diff --git a/packages/bento-design-system/src/Table/Config.ts b/packages/bento-design-system/src/Table/Config.ts index 462484f75..0d12cbc7f 100644 --- a/packages/bento-design-system/src/Table/Config.ts +++ b/packages/bento-design-system/src/Table/Config.ts @@ -13,6 +13,8 @@ export type TableConfig = { emptyIcon: (props: IconProps) => JSX.Element; headerBackgroundColor: BentoSprinkles["background"]; headerForegroundColor: BentoSprinkles["color"]; + footerBackgroundColor: BentoSprinkles["background"]; + footerForegroundColor: BentoSprinkles["color"]; hintPlacement: TooltipPlacement; cellTooltipPlacement: TooltipPlacement; evenRowsBackgroundColor: BentoSprinkles["background"]; @@ -22,6 +24,7 @@ export type TableConfig = { selectedRowBackgroundColor: keyof typeof vars.backgroundColor; padding: { header: CellPaddingConfig; + footer: CellPaddingConfig; defaultCell: CellPaddingConfig; buttonCell: CellPaddingConfig | undefined; buttonLinkCell: CellPaddingConfig | undefined; diff --git a/packages/bento-design-system/src/Table/Table.css.ts b/packages/bento-design-system/src/Table/Table.css.ts index c8027e72c..9441c4a24 100644 --- a/packages/bento-design-system/src/Table/Table.css.ts +++ b/packages/bento-design-system/src/Table/Table.css.ts @@ -1,6 +1,7 @@ import { createVar, style } from "@vanilla-extract/css"; import { bentoSprinkles } from "../internal"; import { strictRecipe } from "../util/strictRecipe"; +import { vars } from "../vars.css"; export const table = style({ gridAutoRows: "max-content", @@ -21,6 +22,18 @@ export const columnHeader = bentoSprinkles({ height: "full", }); +export const columnFooter = style([ + { + boxShadow: `inset 0px 1px 0px ${vars.outlineColor.outlineDecorative}`, + }, + bentoSprinkles({ + display: "flex", + flexDirection: "column", + justifyContent: "center", + height: "full", + }), +]); + export const sortIconContainer = style({ filter: "opacity(80%)", }); @@ -36,6 +49,15 @@ export const stickyColumnHeader = style([ }), ]); +export const stickyColumnFooter = style([ + { + bottom: 0, + }, + bentoSprinkles({ + position: "sticky", + }), +]); + 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, diff --git a/packages/bento-design-system/src/Table/Table.tsx b/packages/bento-design-system/src/Table/Table.tsx index 46fb7741a..d99cc43d0 100644 --- a/packages/bento-design-system/src/Table/Table.tsx +++ b/packages/bento-design-system/src/Table/Table.tsx @@ -31,6 +31,7 @@ import { } from ".."; import { cellContainerRecipe, + columnFooter, columnHeader, lastLeftStickyColumn, rowContainer, @@ -38,6 +39,7 @@ import { sectionHeaderContainer, selectedRowBackgroundColor, sortIconContainer, + stickyColumnFooter, stickyColumnHeader, stickyTopHeight, table, @@ -104,6 +106,7 @@ type Props< noResultsFeedbackSize?: FeedbackProps["size"]; initialSorting?: Array>; stickyHeaders?: boolean; + stickyFooters?: boolean; height?: { custom: string | number }; onRowPress?: (row: Row>) => void; virtualizeRows?: boolean | { estimateRowHeight: (index: number) => number }; @@ -143,6 +146,7 @@ export function Table< onSort, initialSorting, stickyHeaders, + stickyFooters = true, height, onRowPress, virtualizeRows: virtualizeRowsConfig, @@ -417,6 +421,8 @@ export function Table< } }); + const hasFooters = headerGroups.at(-1)?.headers.some((h) => h.Footer); + return ( ( + + ))} ); } @@ -593,6 +618,58 @@ function ColumnHeader>({ ); } +function ColumnFooter>({ + column, + style, + lastLeftSticky, + stickyFooters, + sticky, + first, + last, +}: { + column: ColumnInstance | HeaderGroup; + style: CSSProperties; + lastLeftSticky: boolean; + stickyFooters: boolean; + sticky: boolean; + first: boolean; + last: boolean; +}) { + const config = useBentoConfig().table; + + return ( + + + {column.Footer && ( + + + + + + + + )} + + + ); +} + function SectionHeader({ label, numberOfStickyColumns, diff --git a/packages/bento-design-system/src/Table/tableColumn.tsx b/packages/bento-design-system/src/Table/tableColumn.tsx index 2ae0b3cc2..953462c64 100644 --- a/packages/bento-design-system/src/Table/tableColumn.tsx +++ b/packages/bento-design-system/src/Table/tableColumn.tsx @@ -39,6 +39,7 @@ export function custom>({ sortType, missingValue, width, + footer, ...options }: ColumnOptionsBase & { Cell: (props: CellProps) => Children; @@ -62,6 +63,7 @@ export function custom>({ } }, Header: headerLabel, + Footer: footer, } as Column; if (sortType) { diff --git a/packages/bento-design-system/src/Table/types.ts b/packages/bento-design-system/src/Table/types.ts index ce6409c8e..362115901 100644 --- a/packages/bento-design-system/src/Table/types.ts +++ b/packages/bento-design-system/src/Table/types.ts @@ -15,6 +15,7 @@ declare module "react-table" { sticky?: "left"; gridWidth?: GridWidth; hint?: LocalizedString | { onPress: () => void }; + footer?: string | ((props: { rows: Row[] }) => string); } interface ColumnInstance diff --git a/packages/bento-design-system/src/util/defaultConfigs.tsx b/packages/bento-design-system/src/util/defaultConfigs.tsx index 4bb322f3e..f736d3a20 100644 --- a/packages/bento-design-system/src/util/defaultConfigs.tsx +++ b/packages/bento-design-system/src/util/defaultConfigs.tsx @@ -506,12 +506,15 @@ export const table: TableConfig = { emptyIcon: IconSearch, headerBackgroundColor: "backgroundPrimary", headerForegroundColor: "foregroundPrimary", + footerBackgroundColor: "backgroundPrimary", + footerForegroundColor: "foregroundPrimary", hintPlacement: "top", cellTooltipPlacement: "bottom", evenRowsBackgroundColor: "backgroundSecondary", selectedRowBackgroundColor: "backgroundInteractiveOverlay", padding: { header: { paddingX: 16, paddingY: 8 }, + footer: { paddingX: 16, paddingY: 8 }, defaultCell: { paddingX: 16, paddingY: 16 }, buttonCell: { paddingX: 8, paddingY: 8 }, buttonLinkCell: { paddingX: 8, paddingY: 8 },