Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "chore: restructure stories, add separate category for flat tree",
"packageName": "@fluentui/react-tree",
"email": "bernardo.sunderhus@gmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export type TreeItemLayoutProps = ComponentProps<Partial<TreeItemLayoutSlots>>;

// @public (undocumented)
export type TreeItemLayoutSlots = {
root: Slot<'div'>;
root: Slot<'span'>;
iconBefore?: Slot<'span'>;
iconAfter?: Slot<'span'>;
aside?: Slot<'span'>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utili
import { TreeItemContextValue } from '../../contexts/treeItemContext';

export type TreeItemLayoutSlots = {
root: Slot<'div'>;
root: Slot<'span'>;
/**
* Icon slot that renders right before main content
*/
Expand All @@ -11,6 +11,9 @@ export type TreeItemLayoutSlots = {
* Icon slot that renders right after main content
*/
iconAfter?: Slot<'span'>;
/**
* slot that render right after main content and iconAfter
*/
aside?: Slot<'span'>;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

exports[`TreeItemLayout renders a default state 1`] = `
<div>
<div
<span
class="fui-TreeItemLayout"
>
Default TreeItemLayout
</div>
</span>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ export const useTreeItemLayout_unstable = (
props: TreeItemLayoutProps,
ref: React.Ref<HTMLElement>,
): TreeItemLayoutState => {
const { iconAfter, iconBefore, aside, as = 'div' } = props;
const { iconAfter, iconBefore, aside, as = 'span' } = props;
const treeItemContext = useTreeItemContext_unstable();

return {
...treeItemContext,
components: {
root: 'div',
root: 'span',
iconBefore: 'span',
iconAfter: 'span',
aside: 'span',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const useRootStyles = makeStyles({
width: '100%',
display: 'flex',
alignItems: 'center',
...typographyStyles.body1,
},
});

Expand Down Expand Up @@ -50,16 +51,13 @@ const useContentStyles = makeStyles({
...shorthands.gap(tokens.spacingVerticalNone, tokens.spacingHorizontalNone),
},
});
const useMainStyles = makeStyles({
base: {
...typographyStyles.body1,
},
});

const useDescriptionStyles = makeStyles({
base: {
...typographyStyles.caption1,
},
});

const useAsideStyles = makeStyles({
base: {
display: 'flex',
Expand All @@ -79,7 +77,6 @@ export const useTreeItemPersonaLayoutStyles_unstable = (
const rootStyles = useRootStyles();
const mediaStyles = useMediaStyles();
const contentStyles = useContentStyles();
const mainStyles = useMainStyles();
const descriptionStyles = useDescriptionStyles();
const asideStyles = useAsideStyles();

Expand All @@ -95,7 +92,7 @@ export const useTreeItemPersonaLayoutStyles_unstable = (
);
}
if (state.main) {
state.main.className = mergeClasses(treeItemPersonaLayoutClassNames.main, mainStyles.base, state.main.className);
state.main.className = mergeClasses(treeItemPersonaLayoutClassNames.main, state.main.className);
}
if (state.description) {
state.description.className = mergeClasses(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ export { DefaultOpenTrees } from './TreeDefaultOpenTrees.stories';
export { Appearance } from './TreeAppearance.stories';
export { Size } from './TreeSize.stories';
export { OpenItemsControlled } from './TreeControllingOpenAndClose.stories';
export { UseFlatTree as useFlatTree } from './useFlatTree.stories';
export { FlattenTree as flattenTree } from './flattenTree.stories';
export { Virtualization } from './Virtualization.stories';

export default {
title: 'Preview Components/Tree/Tree',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
The `TreeItem` component represents a single item in a tree. It can contain child items in the form of another `Tree` component or standalone `TreeItem`. The content and layout of a `TreeItem` can be defined using the `TreeItemLayout` or `TreeItemPersonaLayout` component, which should be used as a direct child of `TreeItem`.

When a `TreeItem` has child items, an expand/collapse control is displayed, allowing the user to show or hide the children.

<!-- Don't allow prettier to collapse code block into single line -->
<!-- prettier-ignore -->
> **⚠️ Preview components are considered unstable:**
>
> ```jsx
>
> import { Tree, TreeItem } from '@fluentui/react-components/unstable';
>
> ```
>
> - Features and APIs may change before final release
> - Please contact us if you intend to use this in your product
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import descriptionMd from './TreeItemDescription.md';
export { Default } from './TreeItemDefault.stories';
export { ExpandCollapseIconOnly } from './TreeItemExpandCollapseIconOnly.stories';
export { ExpandIcon } from './TreeItemExpandIcon.stories';
export { IconBefore } from './TreeItemIconBefore.stories';
export { IconAfter } from './TreeItemIconAfter.stories';
export { Actions } from './TreeItemActions.stories';
export { WithInlineStyle } from './TreeItemWithInlineStyle.stories';
export { AddRemoveTreeItem } from './TreeItemAddRemove.stories';

export default {
title: 'Preview Components/Tree/TreeItem',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import * as React from 'react';
import { Tree, TreeItem, TreeItemLayout, TreeItemPersonaLayout } from '@fluentui/react-tree';
import {
CalendarMonthRegular,
LockClosedRegular,
LinkSquareRegular,
Important16Regular,
MoreHorizontal20Regular,
FlagRegular,
} from '@fluentui/react-icons';
import {
Avatar,
Button,
CounterBadge,
Menu,
MenuItem,
MenuList,
MenuPopover,
MenuTrigger,
Text,
tokens,
} from '@fluentui/react-components';

export const Default = () => {
return (
<Tree aria-label="Tree">
<TreeItem>
<TreeItemLayout
iconBefore={<CalendarMonthRegular />}
iconAfter={
<>
<LockClosedRegular />
<LinkSquareRegular />
</>
}
aside={
<>
<Important16Regular primaryFill="red" />
<CounterBadge count={1} color="danger" size="small" />
</>
}
>
Content
</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 2</TreeItemLayout>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 3</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
<TreeItem
actions={
<>
<Button aria-label="Edit" appearance="subtle" icon={<FlagRegular />} />
<Menu>
<MenuTrigger disableButtonEnhancement>
<Button aria-label="More options" appearance="subtle" icon={<MoreHorizontal20Regular />} />
</MenuTrigger>

<MenuPopover>
<MenuList>
<MenuItem>New </MenuItem>
<MenuItem>New Window</MenuItem>
<MenuItem disabled>Open File</MenuItem>
<MenuItem>Open Folder</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
</>
}
>
<TreeItemLayout
iconBefore={<CalendarMonthRegular />}
iconAfter={
<>
<LockClosedRegular />
<LinkSquareRegular />
</>
}
>
Content
</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 3, item 1</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
</TreeItem>
<TreeItem>
<TreeItemPersonaLayout
aside={
<>
<Text font="numeric" as="span" style={{ whiteSpace: 'nowrap' }}>
00:00 AM
</Text>
<div style={{ display: 'flex', marginLeft: 'auto', gap: tokens.spacingHorizontalXS }}>
<Important16Regular primaryFill="red" />
<CounterBadge count={1} color="danger" size="small" />
</div>
</>
}
description="description"
media={<Avatar />}
>
Content
</TreeItemPersonaLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 3, item 1</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
</TreeItem>
<TreeItem>
<TreeItemPersonaLayout
aside={
<div style={{ display: 'flex', marginLeft: 'auto', gap: tokens.spacingHorizontalXS }}>
<Important16Regular primaryFill="red" />
<CounterBadge count={1} color="danger" size="small" />
</div>
}
media={<Avatar shape="square" />}
>
Content
</TreeItemPersonaLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 3, item 1</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
You can leverage multiple props to customize the appearance of a `TreeItemLayout` component. It includes the use of `iconBefore`, `iconAfter` and `aside` slots that can be combined to present meaningful content.

> ⚠️ `iconBefore`, `iconAfter` and `aside` are marked as `aria-hidden` by default
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import * as React from 'react';
import { Tree, TreeItem, TreeItemLayout } from '@fluentui/react-tree';
import {
Image20Regular,
Important16Regular,
LockClosed20Regular,
SquareMultiple20Regular,
} from '@fluentui/react-icons';
import { CounterBadge } from '@fluentui/react-components';
import story from './TreeItemLayout.md';

export const Layout = () => (
<Tree aria-label="Tree">
<TreeItem aria-description="Private, 1 message">
<TreeItemLayout
iconBefore={<Image20Regular />}
iconAfter={
<>
<LockClosed20Regular />
<SquareMultiple20Regular />
</>
}
aside={
<>
<Important16Regular primaryFill="red" />
<CounterBadge count={1} color="danger" size="small" />
</>
}
>
Content
</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>Tree Item</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 2</TreeItemLayout>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 3</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 2</TreeItemLayout>
</TreeItem>
<TreeItem>
<TreeItemLayout>level 2, item 3</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
<TreeItem aria-description="Private">
<TreeItemLayout
iconBefore={<Image20Regular />}
iconAfter={
<>
<LockClosed20Regular />
<SquareMultiple20Regular />
</>
}
aside={<Important16Regular primaryFill="red" />}
>
Content
</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 2, item 1</TreeItemLayout>
<Tree>
<TreeItem>
<TreeItemLayout>level 3, item 1</TreeItemLayout>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
</TreeItem>
</Tree>
);

Layout.parameters = {
docs: {
description: {
story,
},
},
};
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
The `Tree` component allows for an `aside` prop to be added to individual `TreeItemLayout` or `TreeItemPersonaLayout` layout components. This creates an area on the right side of the `TreeItem` where additional information can be displayed, such as a badge with notification count or an icon indicating importance. When actions are specified using the `actions` prop, they will overlay the `aside` area on hover.

> ⚠️ Aside content is `aria-hidden` by default in both `TreeItemLayout` and `TreeItemPersonaLayout`
Loading