Skip to content

Commit

Permalink
Merge pull request #512 from buildo/table-rows
Browse files Browse the repository at this point in the history
Allow interactive rows on Table
  • Loading branch information
gabro authored Jan 19, 2023
2 parents d4b4c01 + 71689df commit f92d187
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 11 deletions.
5 changes: 5 additions & 0 deletions packages/bento-design-system/src/Table/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TooltipPlacement } from "../Field/FieldProps";
import { IconProps } from "../Icons";
import { IllustrationProps } from "../Illustrations";
import { BentoSprinkles } from "../internal";
import { vars } from "../vars.css";

type CellPaddingConfig = {
paddingX: BentoSprinkles["paddingX"];
Expand All @@ -16,6 +17,10 @@ export type TableConfig = {
hintPlacement: TooltipPlacement;
cellTooltipPlacement: TooltipPlacement;
evenRowsBackgroundColor: BentoSprinkles["background"];
// NOTE(gabro): not using BentoSprinkles["background"] because we only want
// "plain" values to use directly in CSS and not conditional objects like
// { default: ..., hover: ... }
selectedRowBackgroundColor: keyof typeof vars.backgroundColor;
padding: {
header: CellPaddingConfig;
defaultCell: CellPaddingConfig;
Expand Down
36 changes: 30 additions & 6 deletions packages/bento-design-system/src/Table/Table.css.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { style } from "@vanilla-extract/css";
import { createVar, style } from "@vanilla-extract/css";
import { bentoSprinkles } from "../internal";
import { strictRecipe } from "../util/strictRecipe";

export const table = style({
gridAutoRows: "max-content",
Expand Down Expand Up @@ -29,11 +30,34 @@ export const stickyColumnHeader = bentoSprinkles({
top: 0,
});

export const cellContainer = bentoSprinkles({
height: "full",
display: "flex",
flexDirection: "column",
justifyContent: "center",
export const rowContainer = style({
// NOTE(gabro): this allows us to use the entire row as a parent selector,
// for applying a hover effect on all of its children or clicking on row,
// without intrucing a DOM container that would break the grid layout.
display: "contents",
});

export const selectedRowBackgroundColor = createVar();

export const cellContainerRecipe = strictRecipe({
base: bentoSprinkles({
height: "full",
display: "flex",
flexDirection: "column",
justifyContent: "center",
}),
variants: {
interactiveRow: {
true: {
selectors: {
[`${rowContainer}:hover &`]: {
cursor: "pointer",
background: selectedRowBackgroundColor,
},
},
},
},
},
});

export const sectionHeaderContainer = style([
Expand Down
50 changes: 45 additions & 5 deletions packages/bento-design-system/src/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ import {
IconButton,
Tooltip,
FeedbackProps,
vars,
} from "..";
import {
cellContainer,
cellContainerRecipe,
columnHeader,
lastLeftStickyColumn,
rowContainer,
sectionHeader,
sectionHeaderContainer,
selectedRowBackgroundColor,
sortIconContainer,
stickyColumnHeader,
table,
Expand All @@ -42,6 +45,7 @@ import { useLayoutEffect, useMemo, useState, CSSProperties, useEffect } from "re
import { IconHelp, IconInfo } from "../Icons";
import { match, __ } from "ts-pattern";
import { useBentoConfig } from "../BentoConfigContext";
import { assignInlineVars } from "@vanilla-extract/dynamic";

type SortFn<C extends ReadonlyArray<ColumnType<string, {}, any>>> = (
a: Row<RowType<C>>,
Expand Down Expand Up @@ -80,6 +84,7 @@ type Props<C extends ReadonlyArray<ColumnType<string, {}, any>>> = {
initialSorting?: Array<SortingRule<C>>;
stickyHeaders?: boolean;
height?: { custom: string | number };
onRowPress?: (row: Row<RowType<C>>) => void;
} & SortingProps<C>;

/**
Expand Down Expand Up @@ -113,6 +118,7 @@ export function Table<C extends ReadonlyArray<ColumnType<string, {}, any>>>({
initialSorting,
stickyHeaders,
height,
onRowPress,
}: Props<C>) {
const config = useBentoConfig().table;
const customOrderByFn = useMemo(
Expand Down Expand Up @@ -273,7 +279,11 @@ export function Table<C extends ReadonlyArray<ColumnType<string, {}, any>>>({
.map(({ gridWidth = "fit-content" }) => gridWidthStyle(gridWidth))
.join(" ");

function renderCells<D extends Record<string, unknown>>(cells: Array<Cell<D>>, rowIndex: number) {
function renderCells<D extends Record<string, unknown>>(
cells: Array<Cell<D>>,
rowIndex: number,
interactiveRow: boolean
) {
return cells.map((cell, index) => (
<CellContainer
{...cell.getCellProps()}
Expand All @@ -282,6 +292,7 @@ export function Table<C extends ReadonlyArray<ColumnType<string, {}, any>>>({
style={stickyLeftColumnStyle[cell.column.id]}
first={index === 0}
last={(index + 1) % columns.length === 0}
interactiveRow={interactiveRow}
>
{cell.render("Cell")}
</CellContainer>
Expand Down Expand Up @@ -321,18 +332,45 @@ export function Table<C extends ReadonlyArray<ColumnType<string, {}, any>>>({
/>,
...row.leafRows.map((row, index) => {
prepareRow(row);
return renderCells(row.cells, index);
return renderCells(row.cells, index, false);
}),
];
} else {
prepareRow(row);
return [renderCells(row.cells, index)];
return (
<RowContainer key={index} row={row} onPress={onRowPress}>
{renderCells(row.cells, index, onRowPress !== undefined)}
</RowContainer>
);
}
})}
</Box>
);
}

function RowContainer<C extends ReadonlyArray<ColumnType<string, {}, any>>>({
row,
children,
onPress,
}: {
row: Row<RowType<C>>;
onPress: ((row: Row<RowType<C>>) => void) | undefined;
children: Children;
}) {
const config = useBentoConfig().table;
return (
<Box
className={rowContainer}
style={assignInlineVars({
[selectedRowBackgroundColor]: vars.backgroundColor[config.selectedRowBackgroundColor],
})}
onClick={() => onPress?.(row)}
>
{children}
</Box>
);
}

function ColumnHeader<D extends Record<string, unknown>>({
column,
style,
Expand Down Expand Up @@ -484,6 +522,7 @@ function CellContainer({
lastLeftSticky,
first,
last,
interactiveRow,
...props
}: {
children: any;
Expand All @@ -492,14 +531,15 @@ function CellContainer({
lastLeftSticky: boolean;
first: boolean;
last: boolean;
interactiveRow: boolean;
} & TableCellProps) {
const tableConfig = useBentoConfig().table;

return (
<Box className={lastLeftSticky && lastLeftStickyColumn} style={style}>
<Box
background={index % 2 === 0 ? tableConfig.evenRowsBackgroundColor : "backgroundPrimary"}
className={cellContainer}
className={cellContainerRecipe({ interactiveRow })}
paddingLeft={first ? tableConfig.boundaryPadding : undefined}
paddingRight={last ? tableConfig.boundaryPadding : undefined}
{...props}
Expand Down
1 change: 1 addition & 0 deletions packages/bento-design-system/src/util/defaultConfigs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ export const table: TableConfig = {
hintPlacement: "top",
cellTooltipPlacement: "bottom",
evenRowsBackgroundColor: "backgroundSecondary",
selectedRowBackgroundColor: "backgroundInteractiveOverlay",
padding: {
header: { paddingX: 16, paddingY: 8 },
defaultCell: { paddingX: 16, paddingY: 16 },
Expand Down
7 changes: 7 additions & 0 deletions packages/storybook/stories/Components/Table.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,10 @@ export const CustomizedColumns = createStory({
columns: customizedColumns,
data: exampleData,
});

export const InteractiveRow = createStory({
columns: exampleColumns,
data: exampleData,
initialSorting: [{ id: "name" }],
onRowPress: action("onRowPress"),
});

2 comments on commit f92d187

@vercel
Copy link

@vercel vercel bot commented on f92d187 Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f92d187 Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.