diff --git a/change/@fluentui-react-components-7a8583a3-a0c8-4391-9083-d36fa2598973.json b/change/@fluentui-react-components-7a8583a3-a0c8-4391-9083-d36fa2598973.json new file mode 100644 index 00000000000000..5f83e892f15129 --- /dev/null +++ b/change/@fluentui-react-components-7a8583a3-a0c8-4391-9083-d36fa2598973.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: exports `useDataGridContextValues_unstable`", + "packageName": "@fluentui/react-components", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-table-4d29794e-c7a5-4723-8a85-3e5668c2c102.json b/change/@fluentui-react-table-4d29794e-c7a5-4723-8a85-3e5668c2c102.json new file mode 100644 index 00000000000000..acfc2b079995b8 --- /dev/null +++ b/change/@fluentui-react-table-4d29794e-c7a5-4723-8a85-3e5668c2c102.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "feat: exports `useDataGridContextValues_unstable`", + "packageName": "@fluentui/react-table", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-components/etc/react-components.unstable.api.md b/packages/react-components/react-components/etc/react-components.unstable.api.md index 58ea76622cfee9..a9b4d3172608aa 100644 --- a/packages/react-components/react-components/etc/react-components.unstable.api.md +++ b/packages/react-components/react-components/etc/react-components.unstable.api.md @@ -223,6 +223,7 @@ import { useDataGridBody_unstable } from '@fluentui/react-table'; import { useDataGridBodyStyles_unstable } from '@fluentui/react-table'; import { useDataGridCell_unstable } from '@fluentui/react-table'; import { useDataGridCellStyles_unstable } from '@fluentui/react-table'; +import { useDataGridContextValues_unstable } from '@fluentui/react-table'; import { useDataGridHeader_unstable } from '@fluentui/react-table'; import { useDataGridHeaderCell_unstable } from '@fluentui/react-table'; import { useDataGridHeaderCellStyles_unstable } from '@fluentui/react-table'; @@ -713,6 +714,8 @@ export { useDataGridCell_unstable } export { useDataGridCellStyles_unstable } +export { useDataGridContextValues_unstable } + export { useDataGridHeader_unstable } export { useDataGridHeaderCell_unstable } diff --git a/packages/react-components/react-components/src/unstable/index.ts b/packages/react-components/react-components/src/unstable/index.ts index 071aa3890facba..9c23a561df6d09 100644 --- a/packages/react-components/react-components/src/unstable/index.ts +++ b/packages/react-components/react-components/src/unstable/index.ts @@ -139,6 +139,7 @@ export { useDataGridStyles_unstable, useDataGrid_unstable, renderDataGrid_unstable, + useDataGridContextValues_unstable, DataGridHeader, dataGridHeaderClassNames, useDataGridHeaderStyles_unstable, diff --git a/packages/react-components/react-data-grid-react-window/etc/react-data-grid-react-window.api.md b/packages/react-components/react-data-grid-react-window/etc/react-data-grid-react-window.api.md index 00b194abd2edcf..91df62b77636f8 100644 --- a/packages/react-components/react-data-grid-react-window/etc/react-data-grid-react-window.api.md +++ b/packages/react-components/react-data-grid-react-window/etc/react-data-grid-react-window.api.md @@ -7,12 +7,23 @@ /// import type { DataGridBodyProps as DataGridBodyProps_2 } from '@fluentui/react-table'; -import type { DataGridBodySlots as DataGridBodySlots_2 } from '@fluentui/react-table'; -import type { DataGridBodyState as DataGridBodyState_2 } from '@fluentui/react-table'; +import { DataGridCell } from '@fluentui/react-table'; +import { DataGridCellProps } from '@fluentui/react-table'; +import { DataGridHeader } from '@fluentui/react-table'; +import { DataGridHeaderCell } from '@fluentui/react-table'; +import { DataGridHeaderCellProps } from '@fluentui/react-table'; +import { DataGridHeaderProps } from '@fluentui/react-table'; +import { DataGridProps } from '@fluentui/react-table'; +import { DataGridRowProps } from '@fluentui/react-table'; +import { DataGridSelectionCell } from '@fluentui/react-table'; +import { DataGridSelectionCellProps } from '@fluentui/react-table'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import * as React_2 from 'react'; import type { TableRowData } from '@fluentui/react-table'; +// @public (undocumented) +export const DataGrid: ForwardRefComponent; + // @public export const DataGridBody: ForwardRefComponent & ((props: DataGridBodyProps) => JSX.Element); @@ -22,21 +33,31 @@ export type DataGridBodyProps = Omit; + ariaRowIndexStart?: number; }; -// @public (undocumented) -export type DataGridBodySlots = DataGridBodySlots_2; +export { DataGridCell } -// @public -export type DataGridBodyState = Omit & Pick & Pick, 'width'> & { - renderRow: RowRenderFunction; -}; +export { DataGridCellProps } -// @public -export const renderDataGridBody_unstable: (state: DataGridBodyState) => JSX.Element; +export { DataGridHeader } + +export { DataGridHeaderCell } + +export { DataGridHeaderCellProps } + +export { DataGridHeaderProps } + +export { DataGridProps } // @public -export const useDataGridBody_unstable: (props: DataGridBodyProps, ref: React_2.Ref) => DataGridBodyState; +export const DataGridRow: ForwardRefComponent & ((props: DataGridRowProps) => JSX.Element); + +export { DataGridRowProps } + +export { DataGridSelectionCell } + +export { DataGridSelectionCellProps } // (No @packageDocumentation comment for this package) diff --git a/packages/react-components/react-data-grid-react-window/src/DataGrid.ts b/packages/react-components/react-data-grid-react-window/src/DataGrid.ts new file mode 100644 index 00000000000000..f0274f9b91596f --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/DataGrid.ts @@ -0,0 +1 @@ +export * from './components/DataGrid/index'; diff --git a/packages/react-components/react-data-grid-react-window/src/DataGridRow.ts b/packages/react-components/react-data-grid-react-window/src/DataGridRow.ts new file mode 100644 index 00000000000000..dff1abb3f73e23 --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/DataGridRow.ts @@ -0,0 +1 @@ +export * from './components/DataGridRow'; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGrid/DataGrid.tsx b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/DataGrid.tsx new file mode 100644 index 00000000000000..b2daaa21a7941e --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/DataGrid.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { useDataGrid_unstable } from './useDataGrid'; +import { + renderDataGrid_unstable, + useDataGridStyles_unstable, + useDataGridContextValues_unstable, +} from '@fluentui/react-table'; +import type { DataGridProps } from '@fluentui/react-table'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; + +export const DataGrid: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useDataGrid_unstable(props, ref); + + useDataGridStyles_unstable(state); + return renderDataGrid_unstable(state, useDataGridContextValues_unstable(state)); +}); + +DataGrid.displayName = 'DataGrid'; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGrid/index.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/index.ts new file mode 100644 index 00000000000000..0b3589e2b3bc1d --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/index.ts @@ -0,0 +1,2 @@ +export * from './DataGrid'; +export * from './useDataGrid'; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGrid/useDataGrid.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/useDataGrid.ts new file mode 100644 index 00000000000000..c50790787ddad8 --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGrid/useDataGrid.ts @@ -0,0 +1,16 @@ +import * as React from 'react'; +import type { DataGridProps, DataGridState } from '@fluentui/react-table'; +import { useDataGrid_unstable as useBaseState } from '@fluentui/react-table'; + +/** + * Create the state required to render DataGrid. + * + * The returned state can be modified with hooks such as useDataGridStyles_unstable, + * before being passed to renderDataGrid_unstable. + * + * @param props - props from this instance of DataGrid + * @param ref - reference to root HTMLElement of DataGrid + */ +export const useDataGrid_unstable = (props: DataGridProps, ref: React.Ref): DataGridState => { + return useBaseState({ ...props, 'aria-rowcount': props.items.length }, ref); +}; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.test.tsx b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.test.tsx deleted file mode 100644 index 4bc16e449b3b03..00000000000000 --- a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { DataGridBody } from './DataGridBody'; -import { DataGridBodyProps } from './DataGridBody.types'; -import { isConformant } from '../../testing/isConformant'; - -describe('DataGridBody', () => { - isConformant({ - Component: DataGridBody, - displayName: 'DataGridBody', - disabledTests: ['component-has-static-classnames-object'], - requiredProps: { - height: 50, - itemSize: 1000, - }, - }); -}); diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.types.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.types.ts index 227cdb7c96488f..44d0baf65fe88c 100644 --- a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.types.ts +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/DataGridBody.types.ts @@ -34,6 +34,13 @@ export type DataGridBodyProps = Omit; + /** + * All virtualized rows must have the [aria-rowindex](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-rowindex) + * attribute for correct screen reader navigation. The default start index is 2 since we assume that there is only + * one row in the header. If this is not the case, the start index can be reconfigured through this prop. + * @default 2 + */ + ariaRowIndexStart?: number; }; /** @@ -41,6 +48,6 @@ export type DataGridBodyProps = Omit & Pick & - Pick, 'width'> & { + Pick, 'width' | 'ariaRowIndexStart'> & { renderRow: RowRenderFunction; }; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/renderDataGridBody.tsx b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/renderDataGridBody.tsx index bb0b233768b6cf..5d4edd062a76a2 100644 --- a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/renderDataGridBody.tsx +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/renderDataGridBody.tsx @@ -3,6 +3,7 @@ import type { DataGridBodyState, DataGridBodySlots } from './DataGridBody.types' import { FixedSizeList as List, ListChildComponentProps } from 'react-window'; import { getSlots } from '@fluentui/react-utilities'; import { TableRowData, TableRowIdContextProvider } from '@fluentui/react-table'; +import { TableRowIndexContextProvider } from '../../contexts/rowIndexContext'; /** * Render the final JSX of DataGridVirtualizedBody @@ -21,7 +22,11 @@ export const renderDataGridBody_unstable = (state: DataGridBodyState) => { > {({ data, index, style }: ListChildComponentProps) => { const row: TableRowData = data[index]; - return {state.renderRow(row, style)}; + return ( + + {state.renderRow(row, style)} + + ); }} diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/useDataGridBody.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/useDataGridBody.ts index 5f945f12f5b794..04274aa32bb715 100644 --- a/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/useDataGridBody.ts +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridBody/useDataGridBody.ts @@ -12,7 +12,7 @@ import { useDataGridBody_unstable as useDataGridBodyBase_unstable, RowRenderFunc * @param ref - reference to root HTMLElement of DataGridBody */ export const useDataGridBody_unstable = (props: DataGridBodyProps, ref: React.Ref): DataGridBodyState => { - const { height, itemSize, width = '100%', children } = props; + const { height, itemSize, width = '100%', ariaRowIndexStart = 2, children } = props; // cast the row render function to work with unknown args const renderRowWithUnknown = children as RowRenderFunction; @@ -24,5 +24,6 @@ export const useDataGridBody_unstable = (props: DataGridBodyProps, ref: React.Re height, renderRow: children, width, + ariaRowIndexStart, }; }; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/DataGridRow.tsx b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/DataGridRow.tsx new file mode 100644 index 00000000000000..11c6f85063d87c --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/DataGridRow.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { useDataGridRowStyles_unstable, renderDataGridRow_unstable } from '@fluentui/react-table'; +import { useDataGridRow_unstable } from './useDataGridRow'; +import type { DataGridRowProps } from '@fluentui/react-table'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; + +/** + * DataGridRow component + */ +export const DataGridRow: ForwardRefComponent & + ((props: DataGridRowProps) => JSX.Element) = React.forwardRef((props, ref) => { + const state = useDataGridRow_unstable(props, ref); + + useDataGridRowStyles_unstable(state); + return renderDataGridRow_unstable(state); +}) as ForwardRefComponent & ((props: DataGridRowProps) => JSX.Element); + +DataGridRow.displayName = 'DataGridRow'; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/index.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/index.ts new file mode 100644 index 00000000000000..15727b3664100a --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/index.ts @@ -0,0 +1,2 @@ +export * from './DataGridRow'; +export * from './useDataGridRow'; diff --git a/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/useDataGridRow.ts b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/useDataGridRow.ts new file mode 100644 index 00000000000000..b7e73da01d1b7c --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/components/DataGridRow/useDataGridRow.ts @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { DataGridRowProps, DataGridRowState } from '@fluentui/react-table'; +import { useDataGridRow_unstable as useBaseState } from '@fluentui/react-table'; +import { useTableRowIndexContext } from '../../contexts/rowIndexContext'; + +/** + * Create the state required to render DataGridRow. + * + * The returned state can be modified with hooks such as useDataGridRowStyles_unstable, + * before being passed to renderDataGridRow_unstable. + * + * @param props - props from this instance of DataGridRow + * @param ref - reference to root HTMLElement of DataGridRow + */ +export const useDataGridRow_unstable = (props: DataGridRowProps, ref: React.Ref): DataGridRowState => { + const rowIndex = useTableRowIndexContext(); + return useBaseState({ ...props, 'aria-rowindex': rowIndex }, ref); +}; diff --git a/packages/react-components/react-data-grid-react-window/src/contexts/rowIndexContext.ts b/packages/react-components/react-data-grid-react-window/src/contexts/rowIndexContext.ts new file mode 100644 index 00000000000000..6ff39e8372cba0 --- /dev/null +++ b/packages/react-components/react-data-grid-react-window/src/contexts/rowIndexContext.ts @@ -0,0 +1,9 @@ +import * as React from 'react'; + +const rowIndexContext = React.createContext(undefined); + +export const tableRowIndexContextDefaultValue = undefined; + +export const useTableRowIndexContext = () => React.useContext(rowIndexContext) ?? tableRowIndexContextDefaultValue; + +export const TableRowIndexContextProvider = rowIndexContext.Provider; diff --git a/packages/react-components/react-data-grid-react-window/src/index.ts b/packages/react-components/react-data-grid-react-window/src/index.ts index c3328a9b2c49b4..de176daf4b3443 100644 --- a/packages/react-components/react-data-grid-react-window/src/index.ts +++ b/packages/react-components/react-data-grid-react-window/src/index.ts @@ -1,3 +1,16 @@ -export { DataGridBody, useDataGridBody_unstable, renderDataGridBody_unstable } from './DataGridBody'; +export { DataGridBody } from './DataGridBody'; +export { DataGrid } from './DataGrid'; +export { DataGridRow } from './DataGridRow'; -export type { DataGridBodyProps, DataGridBodyState, DataGridBodySlots } from './DataGridBody'; +export { DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridSelectionCell } from '@fluentui/react-table'; + +export type { + DataGridCellProps, + DataGridHeaderCellProps, + DataGridHeaderProps, + DataGridSelectionCellProps, + DataGridRowProps, + DataGridProps, +} from '@fluentui/react-table'; + +export type { DataGridBodyProps } from './DataGridBody'; diff --git a/packages/react-components/react-table/etc/react-table.api.md b/packages/react-components/react-table/etc/react-table.api.md index d23e10b88c72d1..234f8f11403f7e 100644 --- a/packages/react-components/react-table/etc/react-table.api.md +++ b/packages/react-components/react-table/etc/react-table.api.md @@ -545,6 +545,9 @@ export const useDataGridCell_unstable: (props: DataGridCellProps, ref: React_2.R // @public export const useDataGridCellStyles_unstable: (state: DataGridCellState) => DataGridCellState; +// @public (undocumented) +export function useDataGridContextValues_unstable(state: DataGridState): DataGridContextValues; + // @public export const useDataGridHeader_unstable: (props: DataGridHeaderProps, ref: React_2.Ref) => DataGridHeaderState; diff --git a/packages/react-components/react-table/src/components/DataGrid/index.ts b/packages/react-components/react-table/src/components/DataGrid/index.ts index 6906263be7ae7b..f421b8aa7c5534 100644 --- a/packages/react-components/react-table/src/components/DataGrid/index.ts +++ b/packages/react-components/react-table/src/components/DataGrid/index.ts @@ -3,3 +3,4 @@ export * from './DataGrid.types'; export * from './renderDataGrid'; export * from './useDataGrid'; export * from './useDataGridStyles'; +export * from './useDataGridContextValues'; diff --git a/packages/react-components/react-table/src/index.ts b/packages/react-components/react-table/src/index.ts index d162af3a1d39e9..bc387da8b5edc6 100644 --- a/packages/react-components/react-table/src/index.ts +++ b/packages/react-components/react-table/src/index.ts @@ -151,6 +151,7 @@ export { useDataGridStyles_unstable, useDataGrid_unstable, renderDataGrid_unstable, + useDataGridContextValues_unstable, } from './DataGrid'; export type { DataGridProps, diff --git a/packages/react-components/react-table/stories/DataGrid/Virtualization.stories.tsx b/packages/react-components/react-table/stories/DataGrid/Virtualization.stories.tsx index 8f19b8a2785a21..117c799f8e8229 100644 --- a/packages/react-components/react-table/stories/DataGrid/Virtualization.stories.tsx +++ b/packages/react-components/react-table/stories/DataGrid/Virtualization.stories.tsx @@ -9,17 +9,15 @@ import { VideoRegular, } from '@fluentui/react-icons'; import { PresenceBadgeStatus, Avatar, useScrollbarWidth, useFluent } from '@fluentui/react-components'; +import { TableColumnDefinition, createTableColumn, TableCellLayout } from '@fluentui/react-components/unstable'; import { - DataGridRow, + DataGridBody, DataGrid, + DataGridRow, DataGridHeader, - DataGridHeaderCell, DataGridCell, - TableColumnDefinition, - createTableColumn, - TableCellLayout, -} from '@fluentui/react-components/unstable'; -import { DataGridBody } from '@fluentui/react-data-grid-react-window'; + DataGridHeaderCell, +} from '@fluentui/react-data-grid-react-window'; type FileCell = { label: string; @@ -170,3 +168,18 @@ export const Virtualization = () => { ); }; + +Virtualization.parameters = { + docs: { + description: { + story: [ + 'Virtualizating the DataGrid component involves recomposing components to use a virtualized container.', + 'This is already done in the extension package `@fluentui/react-data-grid-react-window` which provides', + 'extended DataGrid components that are powered', + 'by [react-window](https://react-window.vercel.app/#/examples/list/fixed-size).', + '', + 'The example below shows how to use this extension package to virtualize the DataGrid component.', + ].join('\n'), + }, + }, +}; diff --git a/scripts/storybook/src/utils.js b/scripts/storybook/src/utils.js index c1c10f89b71d6c..be565404addf08 100644 --- a/scripts/storybook/src/utils.js +++ b/scripts/storybook/src/utils.js @@ -159,7 +159,7 @@ function _createCodesandboxRule(allPackageInfo = getAllPackageInfo()) { * @returns {import('storybook-addon-export-to-codesandbox').BabelPluginOptions} */ function getCodesandboxBabelOptions() { - return Object.values(allPackageInfo).reduce((acc, cur) => { + const importMappings = Object.values(allPackageInfo).reduce((acc, cur) => { if (isConvergedPackage({ packagePathOrJson: cur.packageJson, projectType: 'library' })) { const isPrerelease = semver.prerelease(cur.packageJson.version) !== null; @@ -170,6 +170,13 @@ function _createCodesandboxRule(allPackageInfo = getAllPackageInfo()) { return acc; }, /** @type import('storybook-addon-export-to-codesandbox').BabelPluginOptions*/ ({})); + + return { + ...importMappings, + '@fluentui/react-data-grid-react-window': { + replace: '@fluentui/react-data-grid-react-window', + }, + }; } }