Skip to content

Commit

Permalink
feat: noNativeElements renders table with flex layout (#24913)
Browse files Browse the repository at this point in the history
* feat: Adds `layoutType` prop to Table with flex option

Native `display: table` is great for column alignment and simplifies
column sizing. However, native table layout is not very virtualization
friendly and does cannot handle any non-compliant element in the markup.

For virtualization and other cases that involve non-compliant table
elements in markup, there is a `layoutType` prop with the `native`and
`flex` layouts.

Flex layout is what was used before #24762 with fixes to column
alignment for long content.

* update test and md

* vr tests should test both layout types

* changefiles

* noNativeElements decides layout

* update changefile
  • Loading branch information
ling1726 authored Sep 29, 2022
1 parent 0de548d commit 0bece74
Show file tree
Hide file tree
Showing 23 changed files with 709 additions and 498 deletions.
926 changes: 470 additions & 456 deletions apps/vr-tests-react-components/src/stories/Table.stories.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat: `noNativeElements` renders a flex layout",
"packageName": "@fluentui/react-table",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
16 changes: 6 additions & 10 deletions packages/react-components/react-table/etc/react-table.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export type TableBodySlots = {
};

// @public
export type TableBodyState = ComponentState<TableBodySlots>;
export type TableBodyState = ComponentState<TableBodySlots> & Pick<TableContextValue, 'noNativeElements'>;

// @public
export const TableCell: ForwardRefComponent<TableCellProps>;
Expand Down Expand Up @@ -152,7 +152,7 @@ export type TableCellSlots = {
};

// @public
export type TableCellState = ComponentState<TableCellSlots>;
export type TableCellState = ComponentState<TableCellSlots> & Pick<TableContextValue, 'noNativeElements'>;

// @public (undocumented)
export const tableClassName = "fui-Table";
Expand Down Expand Up @@ -200,9 +200,7 @@ export type TableHeaderCellSlots = {
};

// @public
export type TableHeaderCellState = ComponentState<TableHeaderCellSlots> & {
sortable: boolean;
};
export type TableHeaderCellState = ComponentState<TableHeaderCellSlots> & Pick<TableContextValue, 'noNativeElements' | 'sortable'>;

// @public (undocumented)
export const tableHeaderClassName = "fui-TableHeader";
Expand All @@ -219,7 +217,7 @@ export type TableHeaderSlots = {
};

// @public
export type TableHeaderState = ComponentState<TableHeaderSlots>;
export type TableHeaderState = ComponentState<TableHeaderSlots> & Pick<TableContextValue, 'noNativeElements'>;

// @public
export type TableProps = ComponentProps<TableSlots> & Partial<TableContextValue>;
Expand All @@ -242,9 +240,7 @@ export type TableRowSlots = {
};

// @public
export type TableRowState = ComponentState<TableRowSlots> & {
size: TableState['size'];
};
export type TableRowState = ComponentState<TableRowSlots> & Pick<TableContextValue, 'noNativeElements' | 'size'>;

// @public
export const TableSelectionCell: ForwardRefComponent<TableSelectionCellProps>;
Expand All @@ -265,7 +261,7 @@ export type TableSelectionCellSlots = {
} & Pick<TableCellSlots, 'root'>;

// @public
export type TableSelectionCellState = ComponentState<TableSelectionCellSlots> & Pick<Required<TableSelectionCellProps>, 'type' | 'checked'>;
export type TableSelectionCellState = ComponentState<TableSelectionCellSlots> & Pick<Required<TableSelectionCellProps>, 'type' | 'checked'> & Pick<TableContextValue, 'noNativeElements'>;

// @public (undocumented)
export interface TableSelectionState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ export type TableSlots = {
};

export type TableContextValue = {
/**
* Affects the sizes of all table subcomponents
* @default medium
*/
size: 'small' | 'smaller' | 'medium';

/**
* Render all table elements as divs intead of semantic table elements
* Using divs no longer uses `display: table` layout but `display: flex`
*/
noNativeElements: boolean;

/**
* Whether the table is sortable
*/
sortable: boolean;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,27 @@ export const tableClassNames: SlotClassNames<TableSlots> = {
root: 'fui-Table',
};

const useTableLayoutStyles = makeStyles({
root: {
display: 'table',
verticalAlign: 'middle',
width: '100%',
tableLayout: 'fixed',
},
});

const useFlexLayoutStyles = makeStyles({
root: {
display: 'block',
},
});

/**
* Styles for the root slot
*/
const useStyles = makeStyles({
root: {
verticalAlign: 'middle',
borderCollapse: 'collapse',
width: '100%',
display: 'table',
backgroundColor: tokens.colorNeutralBackground1,
},
});
Expand All @@ -26,7 +38,16 @@ const useStyles = makeStyles({
*/
export const useTableStyles_unstable = (state: TableState): TableState => {
const styles = useStyles();
state.root.className = mergeClasses(tableClassName, styles.root, state.root.className);
const layoutStyles = {
table: useTableLayoutStyles(),
flex: useFlexLayoutStyles(),
};
state.root.className = mergeClasses(
tableClassName,
styles.root,
state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root,
state.root.className,
);

return state;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { TableContextValue } from '../Table/Table.types';

export type TableBodySlots = {
root: Slot<'tbody', 'div'>;
Expand All @@ -12,4 +13,4 @@ export type TableBodyProps = ComponentProps<TableBodySlots>;
/**
* State used in rendering TableBody
*/
export type TableBodyState = ComponentState<TableBodySlots>;
export type TableBodyState = ComponentState<TableBodySlots> & Pick<TableContextValue, 'noNativeElements'>;
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ export const useTableBody_unstable = (props: TableBodyProps, ref: React.Ref<HTML
role: rootComponent === 'div' ? 'rowgroup' : undefined,
...props,
}),
noNativeElements,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { mergeClasses, makeStyles } from '@griffel/react';
import type { TableBodySlots, TableBodyState } from './TableBody.types';
import type { SlotClassNames } from '@fluentui/react-utilities';

const useStyles = makeStyles({
const useTableLayoutStyles = makeStyles({
root: {
display: 'table-row-group',
},
});

const useFlexLayoutStyles = makeStyles({
root: {
display: 'block',
},
});

export const tableBodyClassName = 'fui-TableBody';
export const tableBodyClassNames: SlotClassNames<TableBodySlots> = {
root: 'fui-TableBody',
Expand All @@ -17,8 +23,15 @@ export const tableBodyClassNames: SlotClassNames<TableBodySlots> = {
* Apply styling to the TableBody slots based on the state
*/
export const useTableBodyStyles_unstable = (state: TableBodyState): TableBodyState => {
const styles = useStyles();
state.root.className = mergeClasses(tableBodyClassName, styles.root, state.root.className);
const layoutStyles = {
table: useTableLayoutStyles(),
flex: useFlexLayoutStyles(),
};
state.root.className = mergeClasses(
tableBodyClassName,
state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root,
state.root.className,
);

return state;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { TableContextValue } from '../Table/Table.types';

export type TableCellSlots = {
root: Slot<'td', 'div'>;
Expand All @@ -12,4 +13,4 @@ export type TableCellProps = ComponentProps<TableCellSlots> & {};
/**
* State used in rendering TableCell
*/
export type TableCellState = ComponentState<TableCellSlots>;
export type TableCellState = ComponentState<TableCellSlots> & Pick<TableContextValue, 'noNativeElements'>;
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ export const useTableCell_unstable = (props: TableCellProps, ref: React.Ref<HTML
role: rootComponent === 'div' ? 'cell' : undefined,
...props,
}),
noNativeElements,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,28 @@ export const tableCellClassNames: SlotClassNames<TableCellSlots> = {
root: tableCellClassName,
};

const useTableLayoutStyles = makeStyles({
root: {
display: 'table-cell',
verticalAlign: 'middle',
},
});

const useFlexLayoutStyles = makeStyles({
root: {
display: 'flex',
minWidth: '0px',
alignItems: 'center',
...shorthands.flex(1, 1, '0px'),
},
});

/**
* Styles for the root slot
*/
const useStyles = makeStyles({
root: {
position: 'relative',
verticalAlign: 'middle',
display: 'table-cell',
...shorthands.padding('0px', tokens.spacingHorizontalS),
},
});
Expand All @@ -25,6 +39,15 @@ const useStyles = makeStyles({
*/
export const useTableCellStyles_unstable = (state: TableCellState): TableCellState => {
const styles = useStyles();
state.root.className = mergeClasses(tableCellClassNames.root, styles.root, state.root.className);
const layoutStyles = {
table: useTableLayoutStyles(),
flex: useFlexLayoutStyles(),
};
state.root.className = mergeClasses(
tableCellClassNames.root,
styles.root,
state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root,
state.root.className,
);
return state;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { TableContextValue } from '../Table/Table.types';

export type TableHeaderSlots = {
root: Slot<'thead', 'div'>;
Expand All @@ -12,4 +13,4 @@ export type TableHeaderProps = ComponentProps<TableHeaderSlots> & {};
/**
* State used in rendering TableHeader
*/
export type TableHeaderState = ComponentState<TableHeaderSlots>;
export type TableHeaderState = ComponentState<TableHeaderSlots> & Pick<TableContextValue, 'noNativeElements'>;
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ export const useTableHeader_unstable = (props: TableHeaderProps, ref: React.Ref<
...(sortable && keyboardNavAttr),
...props,
}),
noNativeElements,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,21 @@ export const tableHeaderClassNames: SlotClassNames<TableHeaderSlots> = {
root: 'fui-TableHeader',
};

const useStyles = makeStyles({
const useFlexLayoutStyles = makeStyles({
root: {
display: 'block',
},

roottable: {
display: 'table-row-group',
},

rootFlex: {
display: 'block',
},
});

const useTableLayoutStyles = makeStyles({
root: {
display: 'table-row-group',
},
Expand All @@ -17,8 +31,15 @@ const useStyles = makeStyles({
* Apply styling to the TableHeader slots based on the state
*/
export const useTableHeaderStyles_unstable = (state: TableHeaderState): TableHeaderState => {
const styles = useStyles();
state.root.className = mergeClasses(tableHeaderClassName, styles.root, state.root.className);
const layoutStyles = {
table: useTableLayoutStyles(),
flex: useFlexLayoutStyles(),
};
state.root.className = mergeClasses(
tableHeaderClassName,
state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root,
state.root.className,
);

return state;
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import { ARIAButtonSlotProps } from '@fluentui/react-aria';
import { SortDirection } from '../Table/Table.types';
import { SortDirection, TableContextValue } from '../Table/Table.types';

export type TableHeaderCellSlots = {
root: Slot<'th', 'div'>;
Expand All @@ -23,4 +23,5 @@ export type TableHeaderCellProps = ComponentProps<Partial<TableHeaderCellSlots>>
/**
* State used in rendering TableHeaderCell
*/
export type TableHeaderCellState = ComponentState<TableHeaderCellSlots> & { sortable: boolean };
export type TableHeaderCellState = ComponentState<TableHeaderCellSlots> &
Pick<TableContextValue, 'noNativeElements' | 'sortable'>;
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ export const useTableHeaderCell_unstable = (
},
}),
sortable,
noNativeElements,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,26 @@ export const tableHeaderCellClassNames: SlotClassNames<TableHeaderCellSlots> = {
sortIcon: 'fui-TableHeaderCell__sortIcon',
};

const useTableLayoutStyles = makeStyles({
root: {
display: 'table-cell',
verticalAlign: 'middle',
},
});

const useFlexLayoutStyles = makeStyles({
root: {
display: 'flex',
...shorthands.flex(1, 1, '0px'),
minWidth: '0px',
},
});

/**
* Styles for the root slot
*/
const useStyles = makeStyles({
root: {
display: 'table-cell',
verticalAlign: 'middle',
...shorthands.padding('0px', tokens.spacingHorizontalS),
},

Expand Down Expand Up @@ -60,7 +73,16 @@ const useStyles = makeStyles({
*/
export const useTableHeaderCellStyles_unstable = (state: TableHeaderCellState): TableHeaderCellState => {
const styles = useStyles();
state.root.className = mergeClasses(tableHeaderCellClassNames.root, styles.root, state.root.className);
const layoutStyles = {
table: useTableLayoutStyles(),
flex: useFlexLayoutStyles(),
};
state.root.className = mergeClasses(
tableHeaderCellClassNames.root,
styles.root,
state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root,
state.root.className,
);
state.button.className = mergeClasses(
tableHeaderCellClassNames.button,
styles.resetButton,
Expand Down
Loading

0 comments on commit 0bece74

Please sign in to comment.