diff --git a/change/@fluentui-react-tree-bbd9207d-d370-4635-b213-bbe2b2d53a24.json b/change/@fluentui-react-tree-bbd9207d-d370-4635-b213-bbe2b2d53a24.json new file mode 100644 index 00000000000000..e92497b67532bc --- /dev/null +++ b/change/@fluentui-react-tree-bbd9207d-d370-4635-b213-bbe2b2d53a24.json @@ -0,0 +1,8 @@ +{ + "type": "patch", + "comment": "Export useTreeItemPersonaLayoutContextValues_unstable and TreeItemPersonaLayoutContextValues from @fluentui/react-tree", + "packageName": "@fluentui/react-tree", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch", + "date": "2026-04-26T20:21:03.202Z" +} diff --git a/packages/react-components/react-headless-components-preview/library/package.json b/packages/react-components/react-headless-components-preview/library/package.json index 9775edbcb1159f..2b47de5a4fab7b 100644 --- a/packages/react-components/react-headless-components-preview/library/package.json +++ b/packages/react-components/react-headless-components-preview/library/package.json @@ -50,6 +50,7 @@ "@fluentui/react-tabs": "^9.11.2", "@fluentui/react-tags": "^9.7.19", "@fluentui/react-textarea": "^9.7.0", + "@fluentui/react-tree": "^9.15.16", "@fluentui/react-toolbar": "^9.7.7", "@fluentui/react-utilities": "^9.26.2", "@swc/helpers": "^0.5.1" diff --git a/packages/react-components/react-headless-components-preview/library/src/Tree.ts b/packages/react-components/react-headless-components-preview/library/src/Tree.ts new file mode 100644 index 00000000000000..50ec8d7b11cac2 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/Tree.ts @@ -0,0 +1,72 @@ +export { Tree, renderTree, useTree, useTreeContextValues } from './components/Tree'; +export type { + TreeSlots, + TreeProps, + TreeState, + TreeContextValues, + TreeCheckedChangeData, + TreeCheckedChangeEvent, + TreeNavigationData_unstable, + TreeNavigationEvent_unstable, + TreeNavigationDataParam, + TreeNavigationMode, + TreeOpenChangeData, + TreeOpenChangeEvent, + TreeSelectionValue, +} from './components/Tree'; + +export { + FlatTree, + renderFlatTree, + useFlatTree, + useFlatTreeContextValues, + useHeadlessFlatTree, +} from './components/Tree/FlatTree'; +export type { + FlatTreeSlots, + FlatTreeProps, + FlatTreeState, + FlatTreeContextValues, + HeadlessFlatTree, + HeadlessFlatTreeItem, + HeadlessFlatTreeItemProps, + HeadlessFlatTreeOptions, +} from './components/Tree/FlatTree'; + +export { FlatTreeItem } from './components/Tree/FlatTreeItem'; +export type { FlatTreeItemProps } from './components/Tree/FlatTreeItem'; + +export { TreeItem, renderTreeItem, useTreeItem, useTreeItemContextValues } from './components/Tree/TreeItem'; +export type { + TreeItemSlots, + TreeItemProps, + TreeItemState, + TreeItemContextValues, + TreeItemType, + TreeItemValue, + TreeItemCSSProperties, + TreeItemOpenChangeData, + TreeItemOpenChangeEvent, +} from './components/Tree/TreeItem'; + +export { TreeItemLayout, renderTreeItemLayout, useTreeItemLayout } from './components/Tree/TreeItemLayout'; +export type { + TreeItemLayoutSlots, + TreeItemLayoutProps, + TreeItemLayoutState, + TreeItemLayoutActionSlotProps, + TreeItemLayoutActionVisibilityChangeData, +} from './components/Tree/TreeItemLayout'; + +export { + TreeItemPersonaLayout, + renderTreeItemPersonaLayout, + useTreeItemPersonaLayout, + useTreeItemPersonaLayoutContextValues, +} from './components/Tree/TreeItemPersonaLayout'; +export type { + TreeItemPersonaLayoutSlots, + TreeItemPersonaLayoutProps, + TreeItemPersonaLayoutState, + TreeItemPersonaLayoutContextValues, +} from './components/Tree/TreeItemPersonaLayout'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.tsx new file mode 100644 index 00000000000000..3e2fd73fe98f4b --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.tsx @@ -0,0 +1,13 @@ +'use client'; +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import type { FlatTreeProps } from './FlatTree.types'; +import { useFlatTree, useFlatTreeContextValues } from './useFlatTree'; +import { renderFlatTree } from './renderFlatTree'; + +export const FlatTree: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useFlatTree(props, ref); + const contextValues = useFlatTreeContextValues(state); + return renderFlatTree(state, contextValues); +}); +FlatTree.displayName = 'FlatTree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.types.ts new file mode 100644 index 00000000000000..210f79cea695da --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/FlatTree.types.ts @@ -0,0 +1,10 @@ +export type { + FlatTreeSlots, + FlatTreeProps, + FlatTreeState, + FlatTreeContextValues, + HeadlessFlatTree, + HeadlessFlatTreeItem, + HeadlessFlatTreeItemProps, + HeadlessFlatTreeOptions, +} from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/index.ts new file mode 100644 index 00000000000000..bc5e76e5c2791d --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/index.ts @@ -0,0 +1,13 @@ +export { FlatTree } from './FlatTree'; +export { renderFlatTree } from './renderFlatTree'; +export { useFlatTree, useFlatTreeContextValues, useHeadlessFlatTree } from './useFlatTree'; +export type { + FlatTreeSlots, + FlatTreeProps, + FlatTreeState, + FlatTreeContextValues, + HeadlessFlatTree, + HeadlessFlatTreeItem, + HeadlessFlatTreeItemProps, + HeadlessFlatTreeOptions, +} from './FlatTree.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/renderFlatTree.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/renderFlatTree.ts new file mode 100644 index 00000000000000..9f91e4ca4b77fc --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/renderFlatTree.ts @@ -0,0 +1,2 @@ +'use client'; +export { renderFlatTree_unstable as renderFlatTree } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/useFlatTree.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/useFlatTree.ts new file mode 100644 index 00000000000000..8ce1f2662206d7 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTree/useFlatTree.ts @@ -0,0 +1,12 @@ +'use client'; +import { + useFlatTree_unstable, + useFlatTreeContextValues_unstable, + useHeadlessFlatTree_unstable, +} from '@fluentui/react-tree'; +import type { FlatTreeState, FlatTreeContextValues } from './FlatTree.types'; +export const useFlatTree = useFlatTree_unstable; +export const useFlatTreeContextValues = useFlatTreeContextValues_unstable as ( + state: FlatTreeState, +) => FlatTreeContextValues; +export const useHeadlessFlatTree = useHeadlessFlatTree_unstable; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.tsx new file mode 100644 index 00000000000000..274fe493f7217b --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.tsx @@ -0,0 +1,2 @@ +'use client'; +export { FlatTreeItem } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.types.ts new file mode 100644 index 00000000000000..6eee3e6a87a376 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/FlatTreeItem.types.ts @@ -0,0 +1 @@ +export type { FlatTreeItemProps } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/index.ts new file mode 100644 index 00000000000000..88ff3a71891f22 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/FlatTreeItem/index.ts @@ -0,0 +1,2 @@ +export { FlatTreeItem } from './FlatTreeItem'; +export type { FlatTreeItemProps } from './FlatTreeItem.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.test.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.test.tsx new file mode 100644 index 00000000000000..6b3d5276ab0c17 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.test.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { Tree } from './Tree'; + +describe('Tree', () => { + it('renders without crashing', () => { + const { container } = render(); + expect(container.firstChild).toBeTruthy(); + }); + + it('applies className', () => { + const { container } = render(); + expect(container.firstChild).toHaveClass('custom'); + }); +}); diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.tsx new file mode 100644 index 00000000000000..dd13ec399db623 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.tsx @@ -0,0 +1,13 @@ +'use client'; +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import type { TreeProps } from './Tree.types'; +import { useTree, useTreeContextValues } from './useTree'; +import { renderTree } from './renderTree'; + +export const Tree: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useTree(props, ref); + const contextValues = useTreeContextValues(state); + return renderTree(state, contextValues); +}); +Tree.displayName = 'Tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.types.ts new file mode 100644 index 00000000000000..0ff4106a8aba1e --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/Tree.types.ts @@ -0,0 +1,15 @@ +export type { + TreeSlots, + TreeProps, + TreeState, + TreeContextValues, + TreeCheckedChangeData, + TreeCheckedChangeEvent, + TreeNavigationData_unstable, + TreeNavigationEvent_unstable, + TreeNavigationDataParam, + TreeNavigationMode, + TreeOpenChangeData, + TreeOpenChangeEvent, + TreeSelectionValue, +} from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.tsx new file mode 100644 index 00000000000000..8dc34d63f50424 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.tsx @@ -0,0 +1,13 @@ +'use client'; +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import type { TreeItemProps } from './TreeItem.types'; +import { useTreeItem, useTreeItemContextValues } from './useTreeItem'; +import { renderTreeItem } from './renderTreeItem'; + +export const TreeItem: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useTreeItem(props, ref); + const contextValues = useTreeItemContextValues(state); + return renderTreeItem(state, contextValues); +}); +TreeItem.displayName = 'TreeItem'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.types.ts new file mode 100644 index 00000000000000..eca98125824ed8 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/TreeItem.types.ts @@ -0,0 +1,11 @@ +export type { + TreeItemSlots, + TreeItemProps, + TreeItemState, + TreeItemContextValues, + TreeItemType, + TreeItemValue, + TreeItemCSSProperties, + TreeItemOpenChangeData, + TreeItemOpenChangeEvent, +} from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/index.ts new file mode 100644 index 00000000000000..3e574756b74cf2 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/index.ts @@ -0,0 +1,14 @@ +export { TreeItem } from './TreeItem'; +export { renderTreeItem } from './renderTreeItem'; +export { useTreeItem, useTreeItemContextValues } from './useTreeItem'; +export type { + TreeItemSlots, + TreeItemProps, + TreeItemState, + TreeItemContextValues, + TreeItemType, + TreeItemValue, + TreeItemCSSProperties, + TreeItemOpenChangeData, + TreeItemOpenChangeEvent, +} from './TreeItem.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/renderTreeItem.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/renderTreeItem.ts new file mode 100644 index 00000000000000..b12c2f98f336b0 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/renderTreeItem.ts @@ -0,0 +1,2 @@ +'use client'; +export { renderTreeItem_unstable as renderTreeItem } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/useTreeItem.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/useTreeItem.ts new file mode 100644 index 00000000000000..90b362596ad8e2 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItem/useTreeItem.ts @@ -0,0 +1,7 @@ +'use client'; +import { useTreeItem_unstable, useTreeItemContextValues_unstable } from '@fluentui/react-tree'; +import type { TreeItemState, TreeItemContextValues } from './TreeItem.types'; +export const useTreeItem = useTreeItem_unstable; +export const useTreeItemContextValues = useTreeItemContextValues_unstable as ( + state: TreeItemState, +) => TreeItemContextValues; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.tsx new file mode 100644 index 00000000000000..b1352b79ed479b --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.tsx @@ -0,0 +1,11 @@ +'use client'; +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import type { TreeItemLayoutProps } from './TreeItemLayout.types'; +import { useTreeItemLayout } from './useTreeItemLayout'; +import { renderTreeItemLayout } from './renderTreeItemLayout'; + +export const TreeItemLayout: ForwardRefComponent = React.forwardRef((props, ref) => { + return renderTreeItemLayout(useTreeItemLayout(props, ref)); +}); +TreeItemLayout.displayName = 'TreeItemLayout'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.types.ts new file mode 100644 index 00000000000000..98bc59cd8bdf53 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/TreeItemLayout.types.ts @@ -0,0 +1,7 @@ +export type { + TreeItemLayoutSlots, + TreeItemLayoutProps, + TreeItemLayoutState, + TreeItemLayoutActionSlotProps, + TreeItemLayoutActionVisibilityChangeData, +} from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/index.ts new file mode 100644 index 00000000000000..7c8b439c5cc6e4 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/index.ts @@ -0,0 +1,10 @@ +export { TreeItemLayout } from './TreeItemLayout'; +export { renderTreeItemLayout } from './renderTreeItemLayout'; +export { useTreeItemLayout } from './useTreeItemLayout'; +export type { + TreeItemLayoutSlots, + TreeItemLayoutProps, + TreeItemLayoutState, + TreeItemLayoutActionSlotProps, + TreeItemLayoutActionVisibilityChangeData, +} from './TreeItemLayout.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/renderTreeItemLayout.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/renderTreeItemLayout.ts new file mode 100644 index 00000000000000..9ba36f448c4a72 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/renderTreeItemLayout.ts @@ -0,0 +1,2 @@ +'use client'; +export { renderTreeItemLayout_unstable as renderTreeItemLayout } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/useTreeItemLayout.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/useTreeItemLayout.ts new file mode 100644 index 00000000000000..aefeb59373a497 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemLayout/useTreeItemLayout.ts @@ -0,0 +1,2 @@ +'use client'; +export { useTreeItemLayout_unstable as useTreeItemLayout } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.tsx b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.tsx new file mode 100644 index 00000000000000..b231e681c4dcc1 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.tsx @@ -0,0 +1,13 @@ +'use client'; +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import type { TreeItemPersonaLayoutProps } from './TreeItemPersonaLayout.types'; +import { useTreeItemPersonaLayout, useTreeItemPersonaLayoutContextValues } from './useTreeItemPersonaLayout'; +import { renderTreeItemPersonaLayout } from './renderTreeItemPersonaLayout'; + +export const TreeItemPersonaLayout: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useTreeItemPersonaLayout(props, ref); + const contextValues = useTreeItemPersonaLayoutContextValues(state); + return renderTreeItemPersonaLayout(state, contextValues); +}); +TreeItemPersonaLayout.displayName = 'TreeItemPersonaLayout'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.types.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.types.ts new file mode 100644 index 00000000000000..e22427ba06acf0 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/TreeItemPersonaLayout.types.ts @@ -0,0 +1,6 @@ +export type { + TreeItemPersonaLayoutSlots, + TreeItemPersonaLayoutProps, + TreeItemPersonaLayoutState, + TreeItemPersonaLayoutContextValues, +} from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/index.ts new file mode 100644 index 00000000000000..3a4cec8080ee55 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/index.ts @@ -0,0 +1,9 @@ +export { TreeItemPersonaLayout } from './TreeItemPersonaLayout'; +export { renderTreeItemPersonaLayout } from './renderTreeItemPersonaLayout'; +export { useTreeItemPersonaLayout, useTreeItemPersonaLayoutContextValues } from './useTreeItemPersonaLayout'; +export type { + TreeItemPersonaLayoutSlots, + TreeItemPersonaLayoutProps, + TreeItemPersonaLayoutState, + TreeItemPersonaLayoutContextValues, +} from './TreeItemPersonaLayout.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/renderTreeItemPersonaLayout.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/renderTreeItemPersonaLayout.ts new file mode 100644 index 00000000000000..d1bca4ab55e610 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/renderTreeItemPersonaLayout.ts @@ -0,0 +1,2 @@ +'use client'; +export { renderTreeItemPersonaLayout_unstable as renderTreeItemPersonaLayout } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/useTreeItemPersonaLayout.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/useTreeItemPersonaLayout.ts new file mode 100644 index 00000000000000..9782f34d12017f --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/TreeItemPersonaLayout/useTreeItemPersonaLayout.ts @@ -0,0 +1,10 @@ +'use client'; +import { + useTreeItemPersonaLayout_unstable, + useTreeItemPersonaLayoutContextValues_unstable, +} from '@fluentui/react-tree'; +import type { TreeItemPersonaLayoutState, TreeItemPersonaLayoutContextValues } from './TreeItemPersonaLayout.types'; +export const useTreeItemPersonaLayout = useTreeItemPersonaLayout_unstable; +export const useTreeItemPersonaLayoutContextValues = useTreeItemPersonaLayoutContextValues_unstable as ( + state: TreeItemPersonaLayoutState, +) => TreeItemPersonaLayoutContextValues; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/index.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/index.ts new file mode 100644 index 00000000000000..b01fb6a21e55e8 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/index.ts @@ -0,0 +1,18 @@ +export { Tree } from './Tree'; +export { renderTree } from './renderTree'; +export { useTree, useTreeContextValues } from './useTree'; +export type { + TreeSlots, + TreeProps, + TreeState, + TreeContextValues, + TreeCheckedChangeData, + TreeCheckedChangeEvent, + TreeNavigationData_unstable, + TreeNavigationEvent_unstable, + TreeNavigationDataParam, + TreeNavigationMode, + TreeOpenChangeData, + TreeOpenChangeEvent, + TreeSelectionValue, +} from './Tree.types'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/renderTree.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/renderTree.ts new file mode 100644 index 00000000000000..c0e94b3845a760 --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/renderTree.ts @@ -0,0 +1,2 @@ +'use client'; +export { renderTree_unstable as renderTree } from '@fluentui/react-tree'; diff --git a/packages/react-components/react-headless-components-preview/library/src/components/Tree/useTree.ts b/packages/react-components/react-headless-components-preview/library/src/components/Tree/useTree.ts new file mode 100644 index 00000000000000..d521a1b39b7cce --- /dev/null +++ b/packages/react-components/react-headless-components-preview/library/src/components/Tree/useTree.ts @@ -0,0 +1,5 @@ +'use client'; +import { useTree_unstable, useTreeContextValues_unstable } from '@fluentui/react-tree'; +import type { TreeState, TreeContextValues } from './Tree.types'; +export const useTree = useTree_unstable; +export const useTreeContextValues = useTreeContextValues_unstable as (state: TreeState) => TreeContextValues; diff --git a/packages/react-components/react-headless-components-preview/library/src/index.ts b/packages/react-components/react-headless-components-preview/library/src/index.ts index 0e55d90452127d..2c81266974b727 100644 --- a/packages/react-components/react-headless-components-preview/library/src/index.ts +++ b/packages/react-components/react-headless-components-preview/library/src/index.ts @@ -282,3 +282,69 @@ export type { ToolbarToggleButtonProps, ToolbarToggleButtonState, } from './Toolbar'; + +export { + Tree, + renderTree, + useTree, + useTreeContextValues, + FlatTree, + renderFlatTree, + useFlatTree, + useFlatTreeContextValues, + useHeadlessFlatTree, + FlatTreeItem, + TreeItem, + renderTreeItem, + useTreeItem, + useTreeItemContextValues, + TreeItemLayout, + renderTreeItemLayout, + useTreeItemLayout, + TreeItemPersonaLayout, + renderTreeItemPersonaLayout, + useTreeItemPersonaLayout, + useTreeItemPersonaLayoutContextValues, +} from './Tree'; +export type { + TreeSlots, + TreeProps, + TreeState, + TreeContextValues, + TreeCheckedChangeData, + TreeCheckedChangeEvent, + TreeNavigationData_unstable, + TreeNavigationEvent_unstable, + TreeNavigationDataParam, + TreeNavigationMode, + TreeOpenChangeData, + TreeOpenChangeEvent, + TreeSelectionValue, + FlatTreeSlots, + FlatTreeProps, + FlatTreeState, + FlatTreeContextValues, + HeadlessFlatTree, + HeadlessFlatTreeItem, + HeadlessFlatTreeItemProps, + HeadlessFlatTreeOptions, + FlatTreeItemProps, + TreeItemSlots, + TreeItemProps, + TreeItemState, + TreeItemContextValues, + TreeItemType, + TreeItemValue, + TreeItemCSSProperties, + TreeItemOpenChangeData, + TreeItemOpenChangeEvent, + TreeItemLayoutSlots, + TreeItemLayoutProps, + TreeItemLayoutState, + TreeItemLayoutActionSlotProps, + TreeItemLayoutActionVisibilityChangeData, + TreeItemPersonaLayoutSlots, + TreeItemPersonaLayoutProps, + TreeItemPersonaLayoutState, + TreeItemPersonaLayoutContextValues, +} from './Tree'; diff --git a/packages/react-components/react-tree/library/etc/react-tree.api.md b/packages/react-components/react-tree/library/etc/react-tree.api.md index 31e4ba8fa97dc3..6c9f576074260d 100644 --- a/packages/react-components/react-tree/library/etc/react-tree.api.md +++ b/packages/react-components/react-tree/library/etc/react-tree.api.md @@ -267,6 +267,11 @@ export type TreeItemPersonaLayoutSlots = Pick; }; +// @public +export type TreeItemPersonaLayoutContextValues = { + avatar: AvatarContextValue; +}; + // @public export type TreeItemPersonaLayoutState = ComponentState & { avatarSize: AvatarSize; @@ -459,6 +464,9 @@ export const useTreeItemLayoutStyles_unstable: (state: TreeItemLayoutState) => T // @public export const useTreeItemPersonaLayout_unstable: (props: TreeItemPersonaLayoutProps, ref: React_2.Ref) => TreeItemPersonaLayoutState; +// @public +export function useTreeItemPersonaLayoutContextValues_unstable(state: TreeItemPersonaLayoutState): TreeItemPersonaLayoutContextValues; + // @public export const useTreeItemPersonaLayoutStyles_unstable: (state: TreeItemPersonaLayoutState) => TreeItemPersonaLayoutState; diff --git a/packages/react-components/react-tree/library/src/components/FlatTree/useFlatTree.test.ts b/packages/react-components/react-tree/library/src/components/FlatTree/useFlatTree.test.ts new file mode 100644 index 00000000000000..393696d054e1fa --- /dev/null +++ b/packages/react-components/react-tree/library/src/components/FlatTree/useFlatTree.test.ts @@ -0,0 +1,84 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { useFlatTree_unstable } from './useFlatTree'; +import { useFlatTreeContextValues_unstable } from './useFlatTreeContextValues'; + +describe('useFlatTree_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns default state with div root element', () => { + const { result } = renderHook(() => useFlatTree_unstable({}, ref)); + + expect(result.current).toMatchObject({ + components: { root: 'div' }, + contextType: 'root', + level: 1, + }); + }); + + it('reflects size prop in state', () => { + const { result } = renderHook(() => useFlatTree_unstable({ size: 'small' }, ref)); + + expect(result.current.size).toBe('small'); + }); + + it('reflects appearance prop in state', () => { + const { result } = renderHook(() => useFlatTree_unstable({ appearance: 'subtle' }, ref)); + + expect(result.current.appearance).toBe('subtle'); + }); + + it('reflects selectionMode prop in state', () => { + const { result } = renderHook(() => useFlatTree_unstable({ selectionMode: 'multiselect' }, ref)); + + expect(result.current.selectionMode).toBe('multiselect'); + }); + + it('defaults navigationMode to tree', () => { + const { result } = renderHook(() => useFlatTree_unstable({}, ref)); + + expect(result.current.navigationMode).toBe('tree'); + }); +}); + +describe('useFlatTreeContextValues_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns tree context with root contextType', () => { + const { result } = renderHook(() => { + const state = useFlatTree_unstable({}, ref); + return useFlatTreeContextValues_unstable(state); + }); + + expect(result.current.tree).toMatchObject({ + contextType: 'root', + level: 1, + }); + }); + + it('reflects selectionMode in tree context', () => { + const { result } = renderHook(() => { + const state = useFlatTree_unstable({ selectionMode: 'single' }, ref); + return useFlatTreeContextValues_unstable(state); + }); + + expect(result.current.tree.selectionMode).toBe('single'); + }); + + it('reflects size in tree context', () => { + const { result } = renderHook(() => { + const state = useFlatTree_unstable({ size: 'small' }, ref); + return useFlatTreeContextValues_unstable(state); + }); + + expect(result.current.tree.size).toBe('small'); + }); +}); diff --git a/packages/react-components/react-tree/library/src/components/Tree/useTree.test.ts b/packages/react-components/react-tree/library/src/components/Tree/useTree.test.ts new file mode 100644 index 00000000000000..87bccb3d6dc218 --- /dev/null +++ b/packages/react-components/react-tree/library/src/components/Tree/useTree.test.ts @@ -0,0 +1,90 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { useTree_unstable } from './useTree'; +import { useTreeContextValues_unstable } from './useTreeContextValues'; + +describe('useTree_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns default state with div root element', () => { + const { result } = renderHook(() => useTree_unstable({}, ref)); + + expect(result.current).toMatchObject({ + components: { root: 'div' }, + contextType: 'root', + level: 1, + }); + }); + + it('reflects size prop in state', () => { + const { result } = renderHook(() => useTree_unstable({ size: 'small' }, ref)); + + expect(result.current.size).toBe('small'); + }); + + it('reflects appearance prop in state', () => { + const { result } = renderHook(() => useTree_unstable({ appearance: 'subtle-alpha' }, ref)); + + expect(result.current.appearance).toBe('subtle-alpha'); + }); + + it('reflects selectionMode prop in state', () => { + const { result } = renderHook(() => useTree_unstable({ selectionMode: 'multiselect' }, ref)); + + expect(result.current.selectionMode).toBe('multiselect'); + }); + + it('defaults navigationMode to tree', () => { + const { result } = renderHook(() => useTree_unstable({}, ref)); + + expect(result.current.navigationMode).toBe('tree'); + }); + + it('reflects navigationMode prop in state', () => { + const { result } = renderHook(() => useTree_unstable({ navigationMode: 'treegrid' }, ref)); + + expect(result.current.navigationMode).toBe('treegrid'); + }); +}); + +describe('useTreeContextValues_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns tree context with root contextType', () => { + const { result } = renderHook(() => { + const state = useTree_unstable({}, ref); + return useTreeContextValues_unstable(state); + }); + + expect(result.current.tree).toMatchObject({ + contextType: 'root', + level: 1, + }); + }); + + it('reflects selectionMode in tree context', () => { + const { result } = renderHook(() => { + const state = useTree_unstable({ selectionMode: 'single' }, ref); + return useTreeContextValues_unstable(state); + }); + + expect(result.current.tree.selectionMode).toBe('single'); + }); + + it('reflects appearance in tree context', () => { + const { result } = renderHook(() => { + const state = useTree_unstable({ appearance: 'transparent' }, ref); + return useTreeContextValues_unstable(state); + }); + + expect(result.current.tree.appearance).toBe('transparent'); + }); +}); diff --git a/packages/react-components/react-tree/library/src/components/TreeItem/useTreeItem.test.tsx b/packages/react-components/react-tree/library/src/components/TreeItem/useTreeItem.test.tsx new file mode 100644 index 00000000000000..7c0035859f91a7 --- /dev/null +++ b/packages/react-components/react-tree/library/src/components/TreeItem/useTreeItem.test.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import { useTreeItem_unstable } from './useTreeItem'; +import { useTreeItemContextValues_unstable } from './useTreeItemContextValues'; + +describe('useTreeItem_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns default state with div root element', () => { + const { result } = renderHook(() => useTreeItem_unstable({ value: 'item-1', itemType: 'leaf' }, ref)); + + expect(result.current).toMatchObject({ + components: { root: 'div' }, + itemType: 'leaf', + value: 'item-1', + }); + }); + + it('reflects branch itemType in state', () => { + const { result } = renderHook(() => useTreeItem_unstable({ value: 'item-1', itemType: 'branch' }, ref)); + + expect(result.current.itemType).toBe('branch'); + }); + + it('reflects value prop in state', () => { + const { result } = renderHook(() => useTreeItem_unstable({ value: 'custom-value', itemType: 'leaf' }, ref)); + + expect(result.current.value).toBe('custom-value'); + }); + + it('defaults open to false for leaf items', () => { + const { result } = renderHook(() => useTreeItem_unstable({ value: 'item-1', itemType: 'leaf' }, ref)); + + expect(result.current.open).toBe(false); + }); +}); + +describe('useTreeItemContextValues_unstable', () => { + let ref: React.RefObject; + + beforeEach(() => { + ref = React.createRef(); + }); + + it('returns treeItem context with value and itemType', () => { + const { result } = renderHook(() => { + const state = useTreeItem_unstable({ value: 'item-1', itemType: 'leaf' }, ref); + return useTreeItemContextValues_unstable(state); + }); + + expect(result.current.treeItem).toMatchObject({ + value: 'item-1', + itemType: 'leaf', + }); + }); + + it('reflects open state in treeItem context', () => { + const { result } = renderHook(() => { + const state = useTreeItem_unstable({ value: 'item-1', itemType: 'branch', open: true }, ref); + return useTreeItemContextValues_unstable(state); + }); + + expect(result.current.treeItem.open).toBe(true); + }); +}); diff --git a/packages/react-components/react-tree/library/src/index.ts b/packages/react-components/react-tree/library/src/index.ts index 114aa2c1627cdc..65e47d69fb2c1f 100644 --- a/packages/react-components/react-tree/library/src/index.ts +++ b/packages/react-components/react-tree/library/src/index.ts @@ -91,11 +91,13 @@ export { renderTreeItemPersonaLayout_unstable, useTreeItemPersonaLayoutStyles_unstable, useTreeItemPersonaLayout_unstable, + useTreeItemPersonaLayoutContextValues_unstable, } from './TreeItemPersonaLayout'; export type { TreeItemPersonaLayoutProps, TreeItemPersonaLayoutSlots, TreeItemPersonaLayoutState, + TreeItemPersonaLayoutContextValues, } from './TreeItemPersonaLayout'; export { flattenTree_unstable } from './utils/flattenTree';