From acc4c3180cc79e287e5c6176f6e73c4acd80a13c Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Fri, 25 Nov 2022 10:57:17 +0100 Subject: [PATCH] docs: Add examples for DataGrid Adds usages examples scenarios and props --- .../DataGrid/KeyboardNavigation.stories.tsx | 169 ++++++++++++++++ .../DataGrid/MultipleSelect.stories.tsx | 177 +++++++++++++++++ .../MultipleSelectControlled.stories.tsx | 185 ++++++++++++++++++ .../DataGrid/SelectionAppearance.stories.tsx | 178 +++++++++++++++++ .../stories/DataGrid/SingleSelect.stories.tsx | 177 +++++++++++++++++ .../SingleSelectControlled.stories.tsx | 185 ++++++++++++++++++ .../stories/DataGrid/Sort.stories.tsx | 172 ++++++++++++++++ .../DataGrid/SortControlled.stories.tsx | 183 +++++++++++++++++ .../DataGrid/SubtleSelection.stories.tsx | 178 +++++++++++++++++ .../stories/DataGrid/index.stories.tsx | 9 + 10 files changed, 1613 insertions(+) create mode 100644 packages/react-components/react-table/stories/DataGrid/KeyboardNavigation.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/MultipleSelect.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/MultipleSelectControlled.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/SelectionAppearance.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/SingleSelect.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/SingleSelectControlled.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/Sort.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/SortControlled.stories.tsx create mode 100644 packages/react-components/react-table/stories/DataGrid/SubtleSelection.stories.tsx diff --git a/packages/react-components/react-table/stories/DataGrid/KeyboardNavigation.stories.tsx b/packages/react-components/react-table/stories/DataGrid/KeyboardNavigation.stories.tsx new file mode 100644 index 0000000000000..71fcead973928 --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/KeyboardNavigation.stories.tsx @@ -0,0 +1,169 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const KeyboardNavigation = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/MultipleSelect.stories.tsx b/packages/react-components/react-table/stories/DataGrid/MultipleSelect.stories.tsx new file mode 100644 index 0000000000000..a266a08035e8d --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/MultipleSelect.stories.tsx @@ -0,0 +1,177 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const MultipleSelect = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const defaultSelectedItems = React.useMemo(() => new Set([1]), []); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/MultipleSelectControlled.stories.tsx b/packages/react-components/react-table/stories/DataGrid/MultipleSelectControlled.stories.tsx new file mode 100644 index 0000000000000..a5160328cc8bc --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/MultipleSelectControlled.stories.tsx @@ -0,0 +1,185 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, + RowId, + DataGridProps, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const MultipleSelectControlled = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const [selectedRows, setSelectedRows] = React.useState( + new Set([1]), + ); + const onSelectionChange: DataGridProps['onSelectionChange'] = (e, data) => { + setSelectedRows(data.selectedItems); + }; + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/SelectionAppearance.stories.tsx b/packages/react-components/react-table/stories/DataGrid/SelectionAppearance.stories.tsx new file mode 100644 index 0000000000000..461413367aeae --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/SelectionAppearance.stories.tsx @@ -0,0 +1,178 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const SelectionAppearance = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const defaultSelectedItems = React.useMemo(() => new Set([1]), []); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/SingleSelect.stories.tsx b/packages/react-components/react-table/stories/DataGrid/SingleSelect.stories.tsx new file mode 100644 index 0000000000000..2f8c90ed66796 --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/SingleSelect.stories.tsx @@ -0,0 +1,177 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const SingleSelect = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const defaultSelectedItems = React.useMemo(() => new Set([1]), []); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/SingleSelectControlled.stories.tsx b/packages/react-components/react-table/stories/DataGrid/SingleSelectControlled.stories.tsx new file mode 100644 index 0000000000000..f556b697106f0 --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/SingleSelectControlled.stories.tsx @@ -0,0 +1,185 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, + RowId, + DataGridProps, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const SingleSelectControlled = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const [selectedRows, setSelectedRows] = React.useState( + new Set([1]), + ); + const onSelectionChange: DataGridProps['onSelectionChange'] = (e, data) => { + setSelectedRows(data.selectedItems); + }; + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/Sort.stories.tsx b/packages/react-components/react-table/stories/DataGrid/Sort.stories.tsx new file mode 100644 index 0000000000000..2b3423cda5d7c --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/Sort.stories.tsx @@ -0,0 +1,172 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; +import { SortState } from '../../src/hooks/types'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const Sort = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const defaultSortState = React.useMemo(() => ({ sortColumn: 'file', sortDirection: 'ascending' }), []); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/SortControlled.stories.tsx b/packages/react-components/react-table/stories/DataGrid/SortControlled.stories.tsx new file mode 100644 index 0000000000000..d4d53508ef1dd --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/SortControlled.stories.tsx @@ -0,0 +1,183 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, + DataGridProps, +} from '@fluentui/react-table'; +import { SortState } from '../../src/hooks/types'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const SortControlled = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const [sortState, setSortState] = React.useState({ sortColumn: 'file', sortDirection: 'ascending' }); + const onSortChange: DataGridProps['onSortChange'] = (e, nextSortState) => { + setSortState(nextSortState); + }; + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/SubtleSelection.stories.tsx b/packages/react-components/react-table/stories/DataGrid/SubtleSelection.stories.tsx new file mode 100644 index 0000000000000..045ab6d60cd57 --- /dev/null +++ b/packages/react-components/react-table/stories/DataGrid/SubtleSelection.stories.tsx @@ -0,0 +1,178 @@ +import * as React from 'react'; +import { + FolderRegular, + EditRegular, + OpenRegular, + DocumentRegular, + PeopleRegular, + DocumentPdfRegular, + VideoRegular, +} from '@fluentui/react-icons'; +import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components'; +import { TableCellLayout } from '@fluentui/react-components/unstable'; +import { + DataGridBody, + DataGridRow, + DataGrid, + DataGridHeader, + DataGridHeaderCell, + DataGridCell, + ColumnDefinition, + RowState, + createColumn, +} from '@fluentui/react-table'; + +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ + { + file: { label: 'Meeting notes', icon: }, + author: { label: 'Max Mustermann', status: 'available' }, + lastUpdated: { label: '7h ago', timestamp: 1 }, + lastUpdate: { + label: 'You edited this', + icon: , + }, + }, + { + file: { label: 'Thursday presentation', icon: }, + author: { label: 'Erika Mustermann', status: 'busy' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Training recording', icon: }, + author: { label: 'John Doe', status: 'away' }, + lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 }, + lastUpdate: { + label: 'You recently opened this', + icon: , + }, + }, + { + file: { label: 'Purchase order', icon: }, + author: { label: 'Jane Doe', status: 'offline' }, + lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 }, + lastUpdate: { + label: 'You shared this in a Teams chat', + icon: , + }, + }, +]; + +export const SubtleSelection = () => { + const columns: ColumnDefinition[] = React.useMemo( + () => [ + createColumn({ + columnId: 'file', + compare: (a, b) => { + return a.file.label.localeCompare(b.file.label); + }, + renderHeaderCell: () => { + return 'File'; + }, + renderCell: item => { + return {item.file.label}; + }, + }), + createColumn({ + columnId: 'author', + compare: (a, b) => { + return a.author.label.localeCompare(b.author.label); + }, + renderHeaderCell: () => { + return 'Author'; + }, + renderCell: item => { + return ( + }> + {item.author.label} + + ); + }, + }), + createColumn({ + columnId: 'lastUpdated', + compare: (a, b) => { + return a.lastUpdated.timestamp - b.lastUpdated.timestamp; + }, + renderHeaderCell: () => { + return 'Last updated'; + }, + + renderCell: item => { + return item.lastUpdated.label; + }, + }), + createColumn({ + columnId: 'lastUpdate', + compare: (a, b) => { + return a.lastUpdate.label.localeCompare(b.lastUpdate.label); + }, + renderHeaderCell: () => { + return 'Last update'; + }, + renderCell: item => { + return {item.lastUpdate.label}; + }, + }), + ], + [], + ); + + const defaultSelectedItems = React.useMemo(() => new Set([1]), []); + + return ( + + + + {({ renderHeaderCell }: ColumnDefinition) => ( + {renderHeaderCell()} + )} + + + + {({ item, rowId }: RowState) => ( + + {({ renderCell }: ColumnDefinition) => {renderCell(item)}} + + )} + + + ); +}; diff --git a/packages/react-components/react-table/stories/DataGrid/index.stories.tsx b/packages/react-components/react-table/stories/DataGrid/index.stories.tsx index f9a915dec8dfb..28479914e313f 100644 --- a/packages/react-components/react-table/stories/DataGrid/index.stories.tsx +++ b/packages/react-components/react-table/stories/DataGrid/index.stories.tsx @@ -1,6 +1,15 @@ import { DataGrid } from '../../src/components/DataGrid/DataGrid'; export { Default } from './Default.stories'; +export { KeyboardNavigation } from './KeyboardNavigation.stories'; +export { Sort } from './Sort.stories'; +export { SortControlled } from './SortControlled.stories'; +export { MultipleSelect } from './MultipleSelect.stories'; +export { MultipleSelectControlled } from './MultipleSelectControlled.stories'; +export { SingleSelect } from './SingleSelect.stories'; +export { SingleSelectControlled } from './SingleSelectControlled.stories'; +export { SubtleSelection } from './SubtleSelection.stories'; +export { SelectionAppearance } from './SelectionAppearance.stories'; export default { title: 'Preview Components/DataGrid', component: DataGrid,