Skip to content

Commit

Permalink
refactor: table context selector and stories (microsoft#24136)
Browse files Browse the repository at this point in the history
* refactor: table context selector and stories

Refactor table context to use context selectors, also improve stories to
match how users would generally actually write a table

* fix types

* fix tests

* update stories

* fix size stories
  • Loading branch information
ling1726 authored Jul 29, 2022
1 parent 50b0852 commit ee115c2
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 228 deletions.
1 change: 1 addition & 0 deletions packages/react-components/react-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"@fluentui/react-aria": "^9.0.2",
"@fluentui/react-context-selector": "^9.0.2",
"@fluentui/react-theme": "^9.0.0",
"@fluentui/react-utilities": "^9.0.2",
"@griffel/react": "^1.2.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { TableContextValue } from '../../contexts/types';

export type TableSlots = {
root: Slot<'table', 'div'>;
};

export type TableContextValue = {
size: 'small' | 'smaller' | 'medium';

noNativeElements: boolean;
};

export type TableContextValues = {
table: TableContextValue;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import * as React from 'react';
import { TableContextValue } from '../../contexts/types';
import { TableState } from './Table.types';
import { TableContextValues, TableState } from './Table.types';

export function useTableContextValues_unstable(state: TableState) {
const table = React.useMemo<TableContextValue>(
() => ({
size: state.size,
noNativeElements: state.noNativeElements,
}),
[state.size, state.noNativeElements],
);
export function useTableContextValues_unstable(state: TableState): TableContextValues {
const { size, noNativeElements } = state;

return { table };
return {
table: {
size,
noNativeElements,
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useTableContext } from '../../contexts/tableContext';
* @param ref - reference to root HTMLElement of TableBody
*/
export const useTableBody_unstable = (props: TableBodyProps, ref: React.Ref<HTMLElement>): TableBodyState => {
const { noNativeElements } = useTableContext();
const noNativeElements = useTableContext(ctx => ctx.noNativeElements);
const rootComponent = props.as ?? noNativeElements ? 'div' : 'tbody';

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useTableContext } from '../../contexts/tableContext';
* @param ref - reference to root HTMLElement of TableCell
*/
export const useTableCell_unstable = (props: TableCellProps, ref: React.Ref<HTMLElement>): TableCellState => {
const { noNativeElements } = useTableContext();
const noNativeElements = useTableContext(ctx => ctx.noNativeElements);

const rootComponent = props.as ?? noNativeElements ? 'div' : 'td';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useTableContext } from '../../contexts/tableContext';
* @param ref - reference to root HTMLElement of TableHeader
*/
export const useTableHeader_unstable = (props: TableHeaderProps, ref: React.Ref<HTMLElement>): TableHeaderState => {
const { noNativeElements } = useTableContext();
const noNativeElements = useTableContext(ctx => ctx.noNativeElements);

const rootComponent = props.as ?? noNativeElements ? 'div' : 'thead';
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const useTableHeaderCell_unstable = (
props: TableHeaderCellProps,
ref: React.Ref<HTMLElement>,
): TableHeaderCellState => {
const { noNativeElements } = useTableContext();
const noNativeElements = useTableContext(ctx => ctx.noNativeElements);

const rootComponent = props.as ?? noNativeElements ? 'div' : 'th';
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { TableContextValue } from '../../contexts/types';
import { TableState } from '../Table/Table.types';

export type TableRowSlots = {
root: Slot<'tr', 'div'>;
Expand All @@ -13,4 +13,4 @@ export type TableRowProps = ComponentProps<TableRowSlots> & {};
/**
* State used in rendering TableRow
*/
export type TableRowState = ComponentState<TableRowSlots> & { size: TableContextValue['size'] };
export type TableRowState = ComponentState<TableRowSlots> & { size: TableState['size'] };
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { useTableContext } from '../../contexts/tableContext';
* @param ref - reference to root HTMLElement of TableRow
*/
export const useTableRow_unstable = (props: TableRowProps, ref: React.Ref<HTMLElement>): TableRowState => {
const { size, noNativeElements } = useTableContext();
const noNativeElements = useTableContext(ctx => ctx.noNativeElements);
const size = useTableContext(ctx => ctx.size);
const rootComponent = props.as ?? noNativeElements ? 'div' : 'tr';

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from 'react';
import type { TableContextValue } from './types';
import { createContext, useContextSelector, ContextSelector } from '@fluentui/react-context-selector';
import { TableContextValue } from '../components/Table/Table.types';

const tableContext = React.createContext<TableContextValue | undefined>(undefined);
const tableContext = createContext<TableContextValue | undefined>(undefined);

const tableContextDefaultValue: TableContextValue = {
size: 'medium',
noNativeElements: false,
};

export const TableContextProvider = tableContext.Provider;
export const useTableContext = () => React.useContext(tableContext) ?? tableContextDefaultValue;
export const useTableContext = <T>(selector: ContextSelector<TableContextValue, T>) =>
useContextSelector(tableContext, (ctx = tableContextDefaultValue) => selector(ctx));
5 changes: 0 additions & 5 deletions packages/react-components/react-table/src/contexts/types.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,76 @@ import {
DocumentPdf16Regular as DocumentPdfRegular,
Video16Regular as VideoRegular,
} from '@fluentui/react-icons';
import { Avatar } from '@fluentui/react-avatar';
import { TableBody, TableCell, TableRow, Table } from '../..';
import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components';
import { TableBody, TableCell, TableRow, Table, TableHeader, TableHeaderCell } from '../..';

const items = [
{
file: { label: 'Meeting notes', icon: <DocumentRegular /> },
author: { label: 'Max Mustermann', status: 'available' },
lastUpdated: { label: '7h ago', timestamp: 1 },
lastUpdate: {
label: 'You edited this',
icon: <EditRegular />,
},
},
{
file: { label: 'Thursday presentation', icon: <FolderRegular /> },
author: { label: 'Erika Mustermann', status: 'busy' },
lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular />,
},
},
{
file: { label: 'Training recording', icon: <VideoRegular /> },
author: { label: 'John Doe', status: 'away' },
lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular />,
},
},
{
file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
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: <PeopleRegular />,
},
},
];

const columns = [
{ columnKey: 'file', label: 'File' },
{ columnKey: 'author', label: 'Author' },
{ columnKey: 'lastUpdated', label: 'Last updated' },
{ columnKey: 'lastUpdate', label: 'Last update' },
];

export const Default = () => {
return (
<Table>
<TableHeader>
{columns.map(column => (
<TableHeaderCell key={column.columnKey}>{column.label}</TableHeaderCell>
))}
</TableHeader>
<TableBody>
<TableRow>
<TableCell media={<DocumentRegular />}>Meeting notes</TableCell>
<TableCell media={<Avatar name="Max Mustermann" badge={{ status: 'available' }} />}>Max Mustermann</TableCell>
<TableCell>7h ago</TableCell>
<TableCell media={<EditRegular />}>You edited this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<FolderRegular />}>Thursday presentation</TableCell>
<TableCell media={<Avatar name="Erika Mustermann" badge={{ status: 'away' }} />}>Erika Mustermann</TableCell>
<TableCell>Yesterday at 1:45 PM</TableCell>
<TableCell media={<OpenRegular />}>You recently opened this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<VideoRegular />}>Training recording</TableCell>
<TableCell media={<Avatar name="John Doe" badge={{ status: 'away' }} />}>John Doe</TableCell>
<TableCell>Yesterday at 1:45 PM</TableCell>
<TableCell media={<OpenRegular />}>You recently opened this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<DocumentPdfRegular />}>Purchase order</TableCell>
<TableCell media={<Avatar name="Jane Doe" badge={{ status: 'away' }} />}>Jane Doe</TableCell>
<TableCell>Tue at 9:30 AM</TableCell>
<TableCell media={<PeopleRegular />}>You shared this in a Teams chat</TableCell>
</TableRow>
{items.map(item => (
<TableRow key={item.file.label}>
<TableCell media={item.file.icon}>{item.file.label}</TableCell>
<TableCell
media={<Avatar name={item.author.label} badge={{ status: item.author.status as PresenceBadgeStatus }} />}
>
{item.author.label}
</TableCell>
<TableCell>{item.lastUpdated.label}</TableCell>
<TableCell media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,76 @@ import {
DocumentPdf16Regular as DocumentPdfRegular,
Video16Regular as VideoRegular,
} from '@fluentui/react-icons';
import { Avatar } from '@fluentui/react-avatar';
import { TableCell, TableRow, TableBody, Table } from '../../index';
import { PresenceBadgeStatus, Avatar } from '@fluentui/react-components';
import { TableBody, TableCell, TableRow, Table, TableHeader, TableHeaderCell } from '../..';

const items = [
{
file: { label: 'Meeting notes', icon: <DocumentRegular /> },
author: { label: 'Max Mustermann', status: 'available' },
lastUpdated: { label: '7h ago', timestamp: 1 },
lastUpdate: {
label: 'You edited this',
icon: <EditRegular />,
},
},
{
file: { label: 'Thursday presentation', icon: <FolderRegular /> },
author: { label: 'Erika Mustermann', status: 'busy' },
lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular />,
},
},
{
file: { label: 'Training recording', icon: <VideoRegular /> },
author: { label: 'John Doe', status: 'away' },
lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
lastUpdate: {
label: 'You recently opened this',
icon: <OpenRegular />,
},
},
{
file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
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: <PeopleRegular />,
},
},
];

const columns = [
{ columnKey: 'file', label: 'File' },
{ columnKey: 'author', label: 'Author' },
{ columnKey: 'lastUpdated', label: 'Last updated' },
{ columnKey: 'lastUpdate', label: 'Last update' },
];

export const NonNativeElements = () => {
return (
<Table noNativeElements>
<TableHeader>
{columns.map(column => (
<TableHeaderCell key={column.columnKey}>{column.label}</TableHeaderCell>
))}
</TableHeader>
<TableBody>
<TableRow>
<TableCell media={<DocumentRegular />}>Meeting notes</TableCell>
<TableCell media={<Avatar name="Max Mustermann" badge={{ status: 'available' }} />}>Max Mustermann</TableCell>
<TableCell>7h ago</TableCell>
<TableCell media={<EditRegular />}>You edited this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<FolderRegular />}>Thursday presentation</TableCell>
<TableCell media={<Avatar name="Erika Mustermann" badge={{ status: 'away' }} />}>Erika Mustermann</TableCell>
<TableCell>Yesterday at 1:45 PM</TableCell>
<TableCell media={<OpenRegular />}>You recently opened this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<VideoRegular />}>Training recording</TableCell>
<TableCell media={<Avatar name="John Doe" badge={{ status: 'away' }} />}>John Doe</TableCell>
<TableCell>Yesterday at 1:45 PM</TableCell>
<TableCell media={<OpenRegular />}>You recently opened this</TableCell>
</TableRow>
<TableRow>
<TableCell media={<DocumentPdfRegular />}>Purchase order</TableCell>
<TableCell media={<Avatar name="Jane Doe" badge={{ status: 'away' }} />}>Jane Doe</TableCell>
<TableCell>Tue at 9:30 AM</TableCell>
<TableCell media={<PeopleRegular />}>You shared this in a Teams chat</TableCell>
</TableRow>
{items.map(item => (
<TableRow key={item.file.label}>
<TableCell media={item.file.icon}>{item.file.label}</TableCell>
<TableCell
media={<Avatar name={item.author.label} badge={{ status: item.author.status as PresenceBadgeStatus }} />}
>
{item.author.label}
</TableCell>
<TableCell>{item.lastUpdated.label}</TableCell>
<TableCell media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
Expand Down
Loading

0 comments on commit ee115c2

Please sign in to comment.