@planningcenter/tapestry 4.4.1-rc.4 → 4.4.1-rc.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,13 +6,14 @@ import type { DataTableColumn } from "./DataTableColumn";
6
6
  import { type ResultNoun } from "./ResultsCount";
7
7
  import { type RowAction } from "./RowActions";
8
8
  import { type TableAction } from "./TableActions";
9
- export type { ResultNoun, RowAction, TableAction };
9
+ import { type DataTableSelection } from "./useDataTableSelection";
10
+ export type { DataTableSelection, ResultNoun, RowAction, TableAction };
10
11
  export type Sort = {
11
12
  column: string;
12
13
  direction: "asc" | "desc";
13
14
  };
14
15
  export type DataTableLoadingState = "error" | "idle" | "loading";
15
- export interface DataTableProps {
16
+ interface DataTableBaseProps {
16
17
  /**
17
18
  * Columns define what data is displayed and how. Pass a stable reference
18
19
  * (e.g. a module constant or memoized value); columns are prepared per array
@@ -97,12 +98,6 @@ export interface DataTableProps {
97
98
  * `getRowLink` is also set, both run and the row navigates.
98
99
  */
99
100
  onRowClick?: (row: unknown) => void;
100
- /**
101
- * Called when the set of selected rows changes. Always receives a plain
102
- * array of row keys — never React Aria's `"all"` sentinel, which is
103
- * resolved to the concrete keys of the loaded rows.
104
- */
105
- onSelectedChange?: (keys: (number | string)[]) => void;
106
101
  /** Callback invoked when the sort state changes. */
107
102
  onSortChange?: (sort: Sort) => void;
108
103
  /**
@@ -132,7 +127,9 @@ export interface DataTableProps {
132
127
  * Overrides the number shown by the `resultNoun` count, which otherwise
133
128
  * uses the length of `data`. Use this when the table renders only part of
134
129
  * the result set — a paginated or virtualized table — so the count reflects
135
- * the whole set. Has no effect unless `resultNoun` is set.
130
+ * the whole set. It also sizes an all-pages selection when
131
+ * `canSelectAllPages` is true, including the count used by table actions.
132
+ * Otherwise, it has no effect unless `resultNoun` is set.
136
133
  */
137
134
  resultCount?: number;
138
135
  /**
@@ -170,24 +167,21 @@ export interface DataTableProps {
170
167
  scrollContainerSelector?: string;
171
168
  /**
172
169
  * Enables row selection via checkboxes, including a "select all" checkbox in
173
- * the header. Without a row action (`onRowClick` or `getRowLink`), pressing
174
- * anywhere in a row toggles the row selection.
170
+ * the header for the loaded page. Without a row action (`onRowClick` or
171
+ * `getRowLink`), pressing anywhere in a row toggles the row selection.
175
172
  */
176
173
  selectable?: boolean;
177
- /** The selected row keys. Keys are the values returned by `getRowId` (or `row.id`, or the row's index). */
178
- selectedKeys?: (number | string)[];
179
174
  /** The current sort state for the table. */
180
175
  sortBy?: Sort;
181
176
  /** Enables a sticky header that tracks an outer scroll container. Progressive enhancement: Relies on `animation-timeline: scroll()`, which isn't supported in all browsers (e.g. Firefox) — the header scrolls with the table body instead of sticking in those cases. */
182
177
  stickyHeader?: boolean;
183
178
  /**
184
- * Table actions rendered as an `IconButton` group directly after the results
185
- * count, above the table. Each entry becomes an icon button whose `callback`
186
- * receives the ids of the currently selected rows. Unlike the original RFC,
187
- * these are not gated on `selectable` actions such as print or export can
188
- * operate without a row selection.
179
+ * The number of disabled rows across the whole result set. Used to size an
180
+ * all-pages selection when disabled rows exist on unloaded pages. Replaces
181
+ * the count inferred from `disabledKeys` rather than adding to it. Values are
182
+ * clamped to the result count, and zero is used as supplied.
189
183
  */
190
- tableActions?: TableAction[];
184
+ totalDisabledCount?: number;
191
185
  /**
192
186
  * The total number of pages in the result set. Setting it renders the page
193
187
  * controls below the table; leaving it unset renders no pagination at all.
@@ -209,6 +203,34 @@ export interface DataTableProps {
209
203
  */
210
204
  visibleColumnNames?: string[];
211
205
  }
206
+ interface DataTableExplicitSelectionProps {
207
+ /** Keeps selection values as arrays of row keys. */
208
+ canSelectAllPages?: false;
209
+ /** Called with the selected row keys whenever selection changes. */
210
+ onSelectedChange?: (keys: (number | string)[]) => void;
211
+ /** The selected row keys. */
212
+ selectedKeys?: (number | string)[];
213
+ /** Table actions whose callbacks receive the selected row keys. */
214
+ tableActions?: TableAction[];
215
+ }
216
+ interface DataTableAllPagesSelectionProps {
217
+ /**
218
+ * Enables tagged selection values that can represent every page plus
219
+ * exclusions. Explicit arrays and the header checkbox remain page-scoped.
220
+ */
221
+ canSelectAllPages: true;
222
+ /** Called with the current explicit or all-pages selection. */
223
+ onSelectedChange?: (selection: DataTableSelection) => void;
224
+ /**
225
+ * The current explicit or all-pages selection. Use
226
+ * `{ keys: "all", excludedKeys: [] }` for every selectable result; a bare
227
+ * `"all"` value is not accepted.
228
+ */
229
+ selectedKeys?: DataTableSelection;
230
+ /** Table actions whose callbacks receive the current selection. */
231
+ tableActions?: TableAction<DataTableSelection>[];
232
+ }
233
+ export type DataTableProps = DataTableBaseProps & (DataTableAllPagesSelectionProps | DataTableExplicitSelectionProps);
212
234
  type AriaTablePropsToOmit = "children" | "slot";
213
235
  type AriaTablePropsToInclude = never;
214
236
  export type DataTableElementProps = CombineAriaPropsWithCustomProps<AriaTableProps, DataTableProps, AriaTablePropsToOmit, AriaTablePropsToInclude>;
@@ -230,7 +252,7 @@ export type DataTableElementProps = CombineAriaPropsWithCustomProps<AriaTablePro
230
252
  * @component
231
253
  */
232
254
  export declare const DataTable: {
233
- ({ className, columns, currentPage, data, disabledKeys, emptyState, errorState, getRowId, getRowLink, hasNextPage, hasPreviousPage, id, loadingState, paginationType, resultCount, resultNoun, scrollContainerRef, scrollContainerSelector, rowActions, selectable, selectedKeys: controlledSelectedKeys, stickyHeader, sortBy, tableActions, totalPages, visibleColumnNames, onNextPageClick, onPageChange, onPreviousPageClick, onRowClick, onSelectedChange, onSortChange, onVisibleColumnNamesChange, ...restProps }: DataTableElementProps): React.JSX.Element;
255
+ ({ className, canSelectAllPages, columns, currentPage, data, disabledKeys, emptyState, errorState, getRowId, getRowLink, hasNextPage, hasPreviousPage, id, loadingState, paginationType, resultCount, resultNoun, scrollContainerRef, scrollContainerSelector, rowActions, selectable, selectedKeys: controlledSelectedKeys, stickyHeader, sortBy, tableActions, totalDisabledCount, totalPages, visibleColumnNames, onNextPageClick, onPageChange, onPreviousPageClick, onRowClick, onSelectedChange, onSortChange, onVisibleColumnNamesChange, ...restProps }: DataTableElementProps): React.JSX.Element;
234
256
  displayName: string;
235
257
  };
236
258
  //# sourceMappingURL=DataTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.tsx"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ import { hasResultsCount, resolveResultNounLabel, ResultsCount } from './Results
12
12
  import { RowActions } from './RowActions.js';
13
13
  import { TableActions } from './TableActions.js';
14
14
  import { useColumnVisibility } from './useColumnVisibility.js';
15
+ import { useDataTableSelection, DataTableSelectionContext } from './useDataTableSelection.js';
15
16
  import { useRowPressBoundary } from './useRowPressBoundary.js';
16
17
  import { ViewSettingsToggle } from './ViewSettingsToggle.js';
17
18
 
@@ -33,7 +34,7 @@ const DEFAULT_ERROR_STATE = "Something went wrong.";
33
34
  *
34
35
  * @component
35
36
  */
36
- const DataTable = ({ className, columns, currentPage = 1, data, disabledKeys, emptyState, errorState, getRowId, getRowLink, hasNextPage = false, hasPreviousPage = false, id, loadingState = "idle", paginationType = "paged", resultCount, resultNoun, scrollContainerRef, scrollContainerSelector = ".content-wrap", rowActions, selectable, selectedKeys: controlledSelectedKeys, stickyHeader, sortBy, tableActions, totalPages, visibleColumnNames, onNextPageClick, onPageChange, onPreviousPageClick, onRowClick, onSelectedChange, onSortChange, onVisibleColumnNamesChange, ...restProps }) => {
37
+ const DataTable = ({ className, canSelectAllPages, columns, currentPage = 1, data, disabledKeys, emptyState, errorState, getRowId, getRowLink, hasNextPage = false, hasPreviousPage = false, id, loadingState = "idle", paginationType = "paged", resultCount, resultNoun, scrollContainerRef, scrollContainerSelector = ".content-wrap", rowActions, selectable, selectedKeys: controlledSelectedKeys, stickyHeader, sortBy, tableActions, totalDisabledCount, totalPages, visibleColumnNames, onNextPageClick, onPageChange, onPreviousPageClick, onRowClick, onSelectedChange, onSortChange, onVisibleColumnNamesChange, ...restProps }) => {
37
38
  const hasRowPressAction = Boolean(onRowClick || getRowLink);
38
39
  const rowsAreInteractive = hasRowPressAction || Boolean(selectable);
39
40
  const combinedClassName = classNames("tds-data-table-grid", className);
@@ -67,32 +68,19 @@ const DataTable = ({ className, columns, currentPage = 1, data, disabledKeys, em
67
68
  visibleColumnNames,
68
69
  });
69
70
  const visiblePreparedColumns = useMemo(() => preparedColumns.filter(({ column }) => isColumnVisible(column)), [preparedColumns, isColumnVisible]);
70
- // Selection is controlled when `selectedKeys` is provided; otherwise it's
71
- // tracked internally so the results count and table actions still reflect it.
72
- const isControlled = controlledSelectedKeys !== undefined;
73
- const [internalSelectedKeys, setInternalSelectedKeys] = useState([]);
74
- const selectedKeys = isControlled
75
- ? controlledSelectedKeys
76
- : internalSelectedKeys;
77
- // React Aria treats a row's own action as primary only while the selection is
78
- // empty: with checkbox selection, once any row is selected the table is in
79
- // selection mode and pressing anywhere in a row toggles its selection instead
80
- // of firing the action. Rows without an action always select on press. The
81
- // row's hover state previews the checkbox's hover state whenever a press would
82
- // select, so this has to track the selection rather than the props alone.
83
- const rowPressSelects = Boolean(selectable) && (!hasRowPressAction || selectedKeys.length > 0);
84
- const selectableProps = useSelectableProps({
71
+ const selectionModel = useDataTableSelection({
72
+ canSelectAllPages,
85
73
  data,
86
74
  disabledKeys,
87
75
  getRowId,
88
- onSelectedChange: (keys) => {
89
- if (!isControlled)
90
- setInternalSelectedKeys(keys);
91
- onSelectedChange?.(keys);
92
- },
76
+ hasRowPressAction,
77
+ onSelectedChange,
78
+ resultCount,
93
79
  selectable,
94
- selectedKeys,
80
+ selectedKeys: controlledSelectedKeys,
81
+ totalDisabledCount,
95
82
  });
83
+ const { headerCheckboxProps, rowPressSelects, selectedCount, tableProps: selectionProps, totalCount, } = selectionModel;
96
84
  // Associate the visible results count with the table so screen readers
97
85
  // announce it as a description of the table. `Table` doesn't support a real
98
86
  // `<caption>` (its children go through a collection builder), so we link the
@@ -126,16 +114,14 @@ const DataTable = ({ className, columns, currentPage = 1, data, disabledKeys, em
126
114
  "tds-data-table--sticky-header": hasScrollContainer,
127
115
  }) },
128
116
  React__default.createElement("div", { className: "tds-data-table-frame" },
129
- showHeader && (React__default.createElement("div", { className: "tds-data-table-frame-header" },
130
- React__default.createElement(ResultsCount, { id: resultsCountId, resultNoun: resultNoun, selectable: selectable, selectedCount: selectedKeys.length,
131
- // An explicit `resultCount` covers the whole result set, which a
132
- // paginated table's `data` doesn't.
133
- totalCount: resultCount ?? data.length }),
134
- hasActions && (React__default.createElement(TableActions, { actions: tableActions, resultNoun: resultNoun, selectedKeys: selectedKeys })),
135
- hasViewSettingsToggle && (React__default.createElement(ViewSettingsToggle, { columns: hideableColumns, onColumnVisibilityChange: onColumnVisibilityChange, visibleColumnNames: visibleHideableColumns })))),
117
+ showHeader && (React__default.createElement(DataTableSelectionContext.Provider, { value: selectionModel },
118
+ React__default.createElement("div", { className: "tds-data-table-frame-header" },
119
+ React__default.createElement(ResultsCount, { id: resultsCountId, resultNoun: resultNoun, selectable: selectable, selectedCount: selectedCount, totalCount: totalCount }),
120
+ hasActions && (React__default.createElement(TableActions, { actions: tableActions, resultNoun: resultNoun })),
121
+ hasViewSettingsToggle && (React__default.createElement(ViewSettingsToggle, { columns: hideableColumns, onColumnVisibilityChange: onColumnVisibilityChange, visibleColumnNames: visibleHideableColumns }))))),
136
122
  React__default.createElement("div", { ref: wrapperRef, className: "tds-data-table-scroll-wrapper" },
137
123
  React__default.createElement("div", { ref: scrollRef, className: "tds-data-table-scroll" },
138
- React__default.createElement(Table, { ...restProps, ...selectableProps, ...(ariaLabel ? { "aria-label": ariaLabel } : {}), ...(describedBy ? { "aria-describedby": describedBy } : {}), ...{ id: tableId }, className: combinedClassName,
124
+ React__default.createElement(Table, { ...restProps, ...selectionProps, ...(ariaLabel ? { "aria-label": ariaLabel } : {}), ...(describedBy ? { "aria-describedby": describedBy } : {}), ...{ id: tableId }, className: combinedClassName,
139
125
  // Pinned rather than exposed as a prop: `disabledKeys` only ever
140
126
  // turns off selection here, leaving the row clickable and
141
127
  // focusable. React Aria defaults this to "all", which would also
@@ -145,8 +131,7 @@ const DataTable = ({ className, columns, currentPage = 1, data, disabledKeys, em
145
131
  onSortChange?.(serializeSort(sort));
146
132
  } },
147
133
  React__default.createElement(TableHeader, { className: "tds-data-table-header" },
148
- selectable && (React__default.createElement(Column, { className: "tds-data-table-column tds-data-table-column--selectable" },
149
- React__default.createElement(Checkbox, { slot: "selection", className: "tds-data-table-selectable-checkbox" }))),
134
+ selectable && (React__default.createElement(Column, { className: "tds-data-table-column tds-data-table-column--selectable" }, headerCheckboxProps ? (React__default.createElement(Checkbox, { ...headerCheckboxProps, "aria-label": "Select all", slot: null, className: "tds-data-table-selectable-checkbox" })) : (React__default.createElement(Checkbox, { slot: "selection", className: "tds-data-table-selectable-checkbox" })))),
150
135
  visiblePreparedColumns.map(({ align, column }, index) => (React__default.createElement(Column, { key: column.name, id: column.name, isRowHeader: index === 0, className: classNames("tds-data-table-column", {
151
136
  [`tds-data-table-column--align-${align}`]: align !== "start",
152
137
  }), allowsSorting: column.sortable },
@@ -207,41 +192,6 @@ function serializeSort(sort) {
207
192
  return { column: sort.column, direction: "desc" };
208
193
  return { column: sort.column, direction: "asc" };
209
194
  }
210
- /**
211
- * Resolves the `<Table>` selection props, driving React Aria's `<Table>` off
212
- * the component's selection state. `onSelectedChange` always receives a plain
213
- * array of keys: React Aria's `"all"` selection sentinel (used for
214
- * infinite-loading collections, which this component doesn't have) is resolved
215
- * to the concrete keys of the currently loaded rows, minus any disabled ones —
216
- * React Aria's own "select all" skips disabled rows, so resolving `"all"` has to
217
- * skip them too.
218
- */
219
- function useSelectableProps({ data, disabledKeys, getRowId, onSelectedChange, selectable, selectedKeys, }) {
220
- const selectedKeysSet = useMemo(() => new Set(selectedKeys), [selectedKeys]);
221
- const { rowKeys, rowOrder } = useMemo(() => {
222
- const rowKeys = data.map((row, index) => getRowKey(row, index, getRowId));
223
- return {
224
- rowKeys,
225
- rowOrder: new Map(rowKeys.map((key, index) => [key, index])),
226
- };
227
- }, [data, getRowId]);
228
- if (!selectable)
229
- return { selectionMode: "none" };
230
- return {
231
- onSelectionChange: (keys) => {
232
- if (keys === "all") {
233
- const disabled = new Set(disabledKeys);
234
- onSelectedChange(rowKeys.filter((key) => !disabled.has(key)));
235
- return;
236
- }
237
- // Keys not found in `rowOrder` (e.g. a previously selected row no longer
238
- // in `data`) sort to the end rather than being dropped.
239
- onSelectedChange(Array.from(keys).sort((a, b) => (rowOrder.get(a) ?? Infinity) - (rowOrder.get(b) ?? Infinity)));
240
- },
241
- selectedKeys: selectedKeysSet,
242
- selectionMode: "multiple",
243
- };
244
- }
245
195
  function useStickyHeader(stickyHeader, scrollContainerRef, scrollContainerSelector) {
246
196
  const wrapperRef = useRef(null);
247
197
  const [hasScrollContainer, setHasScrollContainer] = useState(false);
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { Pagination } from \"@components/internal/pagination\"\nimport Icon from \"@utilities/Icon\"\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, {\n type ReactNode,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport {\n Cell,\n Checkbox,\n Column,\n type Key,\n Row,\n type Selection,\n type SortDescriptor,\n Table,\n TableBody,\n TableHeader,\n type TableProps as AriaTableProps,\n} from \"react-aria-components/Table\"\n\nimport type { DataTableColumn } from \"./DataTableColumn\"\nimport { prepareColumn, type PreparedColumn } from \"./DataTableColumnTypes\"\nimport { getRowKey } from \"./DataTableRow\"\nimport {\n hasResultsCount,\n resolveResultNounLabel,\n type ResultNoun,\n ResultsCount,\n} from \"./ResultsCount\"\nimport { type RowAction, RowActions } from \"./RowActions\"\nimport { type TableAction, TableActions } from \"./TableActions\"\nimport { useColumnVisibility } from \"./useColumnVisibility\"\nimport { useRowPressBoundary } from \"./useRowPressBoundary\"\nimport { ViewSettingsToggle } from \"./ViewSettingsToggle\"\n\nexport type { ResultNoun, RowAction, TableAction }\n\nexport type Sort = { column: string; direction: \"asc\" | \"desc\" }\n\nexport type DataTableLoadingState = \"error\" | \"idle\" | \"loading\"\n\nexport interface DataTableProps {\n /**\n * Columns define what data is displayed and how. Pass a stable reference\n * (e.g. a module constant or memoized value); columns are prepared per array\n * identity, so an inline array rebuilds each column's formatter every render.\n */\n columns: DataTableColumn[]\n /**\n * The 1-indexed current page. Only used by the default `\"paged\"` pagination,\n * where `totalPages` is set, and defaults to `1`.\n */\n currentPage?: number\n /** The array of rows to display. */\n data: unknown[]\n /**\n * Row keys that can't be selected. Keys are the values returned by `getRowId`\n * (or `row.id`, or the row's index) — the same keys used by `selectedKeys`.\n * Only selection is disabled: the row's checkbox renders disabled and \"select\n * all\" skips it, while the row itself stays clickable, navigable, and\n * focusable. Has no effect unless the table is `selectable`.\n */\n disabledKeys?: (number | string)[]\n /** Rendered in place of the table body when there is no data. */\n emptyState?: ReactNode\n /** Rendered in place of the table body when `loadingState` is `\"error\"`. */\n errorState?: ReactNode\n /** Returns a stable identity for each row. Defaults to `row.id`. */\n getRowId?: (row: unknown) => number | string\n /**\n * Returns a URL to navigate to when the row is clicked. Rows with a link\n * render as navigable elements (clickable, keyboard-focusable, and\n * openable in a new tab). Works alongside `onRowClick` and `selectable`.\n */\n getRowLink?: (row: unknown) => string\n /**\n * Whether a page exists after the current one. Only used by\n * `paginationType=\"indexed\"`, which has no page count to derive it from;\n * `false` (the default) disables the Next button.\n */\n hasNextPage?: boolean\n /**\n * Whether a page exists before the current one. Only used by\n * `paginationType=\"indexed\"`, which has no page count to derive it from;\n * `false` (the default) disables the Previous button.\n */\n hasPreviousPage?: boolean\n /**\n * An `id` for the table element. When omitted, a stable generated id is used\n * so the results count can be linked to the table via `aria-describedby`.\n */\n id?: string\n /**\n * Async loading state for the table body.\n * - `\"loading\"`: While `data` is empty, replaces the empty state with a\n * centered spinner.\n * - `\"error\"`: While `data` is empty, replaces the empty state with\n * `errorState` (or a default error message).\n * - `\"idle\"` (default): Normal rendering.\n */\n loadingState?: DataTableLoadingState\n /**\n * Called when the Next button is activated. Only used by\n * `paginationType=\"indexed\"`; load the following page's rows and pass them\n * back in through `data` in response.\n */\n onNextPageClick?: () => void\n /**\n * Called with the 1-indexed page the user navigated to. The table doesn't\n * page `data` itself — pass the rows for the new page back in through `data`\n * (and update `currentPage`) in response. Only used by the default `\"paged\"`\n * pagination; the indexed type has no page number to report.\n */\n onPageChange?: (page: number) => void\n /**\n * Called when the Previous button is activated. Only used by\n * `paginationType=\"indexed\"`; load the preceding page's rows and pass them\n * back in through `data` in response.\n */\n onPreviousPageClick?: () => void\n /**\n * Called with the row when it is clicked. Rows with a click handler render\n * as interactive elements (clickable and keyboard-focusable). When\n * `getRowLink` is also set, both run and the row navigates.\n */\n onRowClick?: (row: unknown) => void\n /**\n * Called when the set of selected rows changes. Always receives a plain\n * array of row keys — never React Aria's `\"all\"` sentinel, which is\n * resolved to the concrete keys of the loaded rows.\n */\n onSelectedChange?: (keys: (number | string)[]) => void\n /** Callback invoked when the sort state changes. */\n onSortChange?: (sort: Sort) => void\n /**\n * Called with the full ordered list of visible column names when the\n * visibility toggle changes. Always-visible columns are included, so the\n * value can be passed straight back as `visibleColumnNames`. Column\n * visibility is controlled, so the table only updates once\n * `visibleColumnNames` changes.\n */\n onVisibleColumnNamesChange?: (visibleColumnNames: string[]) => void\n /**\n * Which shape the page controls take, forwarded to the `Pagination` control's\n * `type`.\n * - `\"paged\"` (the default): a numbered run of pages. Driven by `totalPages`,\n * `currentPage`, and `onPageChange`, and rendered only once `totalPages` is\n * set and greater than `1`.\n * - `\"indexed\"`: a labeled Previous/Next pair, for a result set that can only\n * be stepped through — a cursor-paged API, say, which reports whether a\n * neighboring page exists but not how many there are. Driven by\n * `hasPreviousPage`/`hasNextPage` and `onPreviousPageClick`/\n * `onNextPageClick`; `totalPages` and `currentPage` play no part. With no\n * page count there's no threshold to hide the controls below, so they\n * always render — a single page of results shows both buttons disabled.\n */\n paginationType?: \"indexed\" | \"paged\"\n /**\n * Overrides the number shown by the `resultNoun` count, which otherwise\n * uses the length of `data`. Use this when the table renders only part of\n * the result set — a paginated or virtualized table — so the count reflects\n * the whole set. Has no effect unless `resultNoun` is set.\n */\n resultCount?: number\n /**\n * Displays the number of results (the length of `data`, or `resultCount`\n * when supplied) above the table, followed by a noun that matches the count.\n * Pass a string to use it as the singular noun and append `\"s\"` for the\n * plural (e.g. `\"result\"` → `\"results\"`), or a `[singular, plural]` tuple to\n * supply an irregular plural explicitly (e.g. `[\"person\", \"people\"]`). Pass\n * `true` to use `\"result\"`.\n * When `false` or omitted, no count is rendered. The count is formatted with\n * `Intl.NumberFormat` and the singular form is used only when the count is\n * exactly `1`. When the table is `selectable` and rows are selected, the\n * count instead reflects the selection as `\"{selected} of {total}\"`, e.g.\n * `\"2 of 100\"`, with a visually-hidden suffix naming the noun so assistive\n * tech reads the unambiguous `\"2 of 100 people selected\"`.\n * The count is linked to the table with `aria-describedby` so\n * screen readers announce it as a description of the table. When a string or\n * `[singular, plural]` tuple is provided, the noun also supplies the table's\n * `aria-label` in its plural form (e.g. `\"items\"` or `\"people\"`) unless an\n * `aria-label` is passed directly, which always takes precedence; `true`\n * never provides a label. The same plural noun also names the pagination\n * landmark (e.g. `\"people table pagination\"`), which otherwise falls back to\n * `\"Pagination\"`.\n */\n resultNoun?: ResultNoun\n /**\n * Displays a sticky column to the right that holds row-scoped actions.\n * Renders as a dropdown with 2+ actions or a single button with one. Each\n * action's `onAction` or `getHref` receives the row.\n */\n rowActions?: RowAction[]\n /** Ref to the scroll container the sticky header should track. Takes priority over `scrollContainerSelector`. Only used when `stickyHeader` is true. */\n scrollContainerRef?: React.RefObject<HTMLElement>\n /** CSS selector for the scroll container the sticky header should track. Only used when `stickyHeader` is true. Defaults to \".content-wrap\" */\n scrollContainerSelector?: string\n /**\n * Enables row selection via checkboxes, including a \"select all\" checkbox in\n * the header. Without a row action (`onRowClick` or `getRowLink`), pressing\n * anywhere in a row toggles the row selection.\n */\n selectable?: boolean\n /** The selected row keys. Keys are the values returned by `getRowId` (or `row.id`, or the row's index). */\n selectedKeys?: (number | string)[]\n /** The current sort state for the table. */\n sortBy?: Sort\n /** Enables a sticky header that tracks an outer scroll container. Progressive enhancement: Relies on `animation-timeline: scroll()`, which isn't supported in all browsers (e.g. Firefox) — the header scrolls with the table body instead of sticking in those cases. */\n stickyHeader?: boolean\n /**\n * Table actions rendered as an `IconButton` group directly after the results\n * count, above the table. Each entry becomes an icon button whose `callback`\n * receives the ids of the currently selected rows. Unlike the original RFC,\n * these are not gated on `selectable` — actions such as print or export can\n * operate without a row selection.\n */\n tableActions?: TableAction[]\n /**\n * The total number of pages in the result set. Setting it renders the page\n * controls below the table; leaving it unset renders no pagination at all.\n * A single page has nothing to navigate to, so the controls only render once\n * there are two or more pages. Only used by the default `\"paged\"` pagination\n * — an indexed result set has no page count, which is the reason to reach for\n * `paginationType=\"indexed\"` in the first place.\n *\n * The table displays whatever rows it is given — paging is the caller's job.\n * `data` should hold only the current page's rows, `resultCount` the size of\n * the whole result set, and `onPageChange` should load the next page.\n */\n totalPages?: number\n /**\n * The names of the columns currently visible. Only columns marked `hideable`\n * are affected — every other column stays visible. Omitting this leaves all\n * columns visible. Unknown names are ignored and display order always\n * follows `columns`.\n */\n visibleColumnNames?: string[]\n}\n\nconst DEFAULT_ERROR_STATE = \"Something went wrong.\"\n\ntype AriaTablePropsToOmit = \"children\" | \"slot\"\n\ntype AriaTablePropsToInclude = never\n\nexport type DataTableElementProps = CombineAriaPropsWithCustomProps<\n AriaTableProps,\n DataTableProps,\n AriaTablePropsToOmit,\n AriaTablePropsToInclude\n>\n\n/**\n * A table for displaying tabular data. Built on React Aria's `Table`.\n *\n * Each column declares a `type` that controls how its cell values are\n * formatted: `string`, `number`, `currency`, `date`, `datetime`, `boolean`,\n * `enum`, and `custom`. A column's `render` function always takes precedence\n * over the built-in type formatting.\n *\n * Setting `totalPages` renders page controls below the table; the table itself\n * never slices `data`, so `onPageChange` is where the caller loads the page.\n * `paginationType=\"indexed\"` swaps the numbered run for a labeled\n * Previous/Next pair, for a result set with no known page count.\n *\n * Filtering, presets, and other RFC features are not yet implemented.\n *\n * @component\n */\nexport const DataTable = ({\n className,\n columns,\n currentPage = 1,\n data,\n disabledKeys,\n emptyState,\n errorState,\n getRowId,\n getRowLink,\n hasNextPage = false,\n hasPreviousPage = false,\n id,\n loadingState = \"idle\",\n paginationType = \"paged\",\n resultCount,\n resultNoun,\n scrollContainerRef,\n scrollContainerSelector = \".content-wrap\",\n rowActions,\n selectable,\n selectedKeys: controlledSelectedKeys,\n stickyHeader,\n sortBy,\n tableActions,\n totalPages,\n visibleColumnNames,\n onNextPageClick,\n onPageChange,\n onPreviousPageClick,\n onRowClick,\n onSelectedChange,\n onSortChange,\n onVisibleColumnNamesChange,\n ...restProps\n}: DataTableElementProps) => {\n const hasRowPressAction = Boolean(onRowClick || getRowLink)\n const rowsAreInteractive = hasRowPressAction || Boolean(selectable)\n const combinedClassName = classNames(\"tds-data-table-grid\", className)\n const sortDescriptor = useSortDescriptor(sortBy)\n const { hasScrollContainer, wrapperRef } = useStickyHeader(\n stickyHeader,\n scrollContainerRef,\n scrollContainerSelector\n )\n const scrollRef = useRef<HTMLDivElement>(null)\n // A `Button` or `Link` in a cell keeps its presses to itself, so activating\n // one doesn't also press the row it's in.\n const cellBoundaryProps = useRowPressBoundary(scrollRef, rowsAreInteractive)\n\n // React Aria only invokes `renderEmptyState` when the collection is empty, so\n // the loading spinner and error message only take over the body while `data`\n // is empty; once rows exist they always render.\n const emptyStateContent = getEmptyStateContent({\n emptyState,\n errorState,\n loadingState,\n })\n const renderEmptyState = emptyStateContent\n ? () => emptyStateContent\n : undefined\n\n // Keyed on column names rather than the `columns` array identity so a fresh\n // `columns` literal each render doesn't rebuild every formatter. `columns` is\n // intentionally omitted from the deps.\n const columnKey = columns.map((c) => `${c.name}/${c.type}`).join(\"|\")\n const preparedColumns = useMemo<PreparedColumn[]>(\n () => columns.map(prepareColumn),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [columnKey]\n )\n\n const {\n hideableColumns,\n isColumnVisible,\n onColumnVisibilityChange,\n visibleHideableColumns,\n } = useColumnVisibility({\n columns,\n onVisibleColumnNamesChange,\n visibleColumnNames,\n })\n const visiblePreparedColumns = useMemo(\n () => preparedColumns.filter(({ column }) => isColumnVisible(column)),\n [preparedColumns, isColumnVisible]\n )\n\n // Selection is controlled when `selectedKeys` is provided; otherwise it's\n // tracked internally so the results count and table actions still reflect it.\n const isControlled = controlledSelectedKeys !== undefined\n const [internalSelectedKeys, setInternalSelectedKeys] = useState<\n (number | string)[]\n >([])\n const selectedKeys = isControlled\n ? controlledSelectedKeys\n : internalSelectedKeys\n\n // React Aria treats a row's own action as primary only while the selection is\n // empty: with checkbox selection, once any row is selected the table is in\n // selection mode and pressing anywhere in a row toggles its selection instead\n // of firing the action. Rows without an action always select on press. The\n // row's hover state previews the checkbox's hover state whenever a press would\n // select, so this has to track the selection rather than the props alone.\n const rowPressSelects =\n Boolean(selectable) && (!hasRowPressAction || selectedKeys.length > 0)\n\n const selectableProps = useSelectableProps({\n data,\n disabledKeys,\n getRowId,\n onSelectedChange: (keys) => {\n if (!isControlled) setInternalSelectedKeys(keys)\n onSelectedChange?.(keys)\n },\n selectable,\n selectedKeys,\n })\n\n // Associate the visible results count with the table so screen readers\n // announce it as a description of the table. `Table` doesn't support a real\n // `<caption>` (its children go through a collection builder), so we link the\n // count via `aria-describedby`, merging with any caller-supplied value.\n const stableId = useId()\n const tableId = id || `tds-data-table-${stableId}`\n const resultsCountId = `${tableId}-results-count`\n const describedBy = hasResultsCount(resultNoun)\n ? [restProps[\"aria-describedby\"], resultsCountId].filter(Boolean).join(\" \")\n : restProps[\"aria-describedby\"]\n\n // A caller-supplied `aria-label` always wins; otherwise the results noun\n // provides the table's accessible name so a label is present whenever a noun\n // is given. Array nouns are transformed to their plural form.\n const resultNounLabel = resolveResultNounLabel(resultNoun)\n const ariaLabel = restProps[\"aria-label\"] || resultNounLabel\n const paginationLabel = resultNounLabel\n ? `${resultNounLabel} table pagination`\n : undefined\n\n const hasActions = (tableActions?.length ?? 0) > 0\n const hasViewSettingsToggle = hideableColumns.length > 0\n const showHeader = Boolean(resultNoun || hasActions || hasViewSettingsToggle)\n const hasRowActions = (rowActions?.length ?? 0) > 0\n // A lone page has nothing to navigate to, so the paged controls stay out of\n // the frame entirely rather than rendering a single inert page marker. The\n // indexed type has no page count to measure against — stepping is the only\n // way through the set — so asking for it always renders the controls, and a\n // set that fits on one page shows both buttons disabled.\n const isIndexedPagination = paginationType === \"indexed\"\n const showPagination =\n isIndexedPagination || (totalPages !== undefined && totalPages > 1)\n\n return (\n <div\n className={classNames(\"tds-data-table\", {\n \"tds-data-table--sticky-header\": hasScrollContainer,\n })}\n >\n <div className=\"tds-data-table-frame\">\n {showHeader && (\n <div className=\"tds-data-table-frame-header\">\n <ResultsCount\n id={resultsCountId}\n resultNoun={resultNoun}\n selectable={selectable}\n selectedCount={selectedKeys.length}\n // An explicit `resultCount` covers the whole result set, which a\n // paginated table's `data` doesn't.\n totalCount={resultCount ?? data.length}\n />\n {hasActions && (\n <TableActions\n actions={tableActions!} // Safe to assert non-null here because of `hasActions`\n resultNoun={resultNoun}\n selectedKeys={selectedKeys}\n />\n )}\n {hasViewSettingsToggle && (\n <ViewSettingsToggle\n columns={hideableColumns}\n onColumnVisibilityChange={onColumnVisibilityChange}\n visibleColumnNames={visibleHideableColumns}\n />\n )}\n </div>\n )}\n <div ref={wrapperRef} className=\"tds-data-table-scroll-wrapper\">\n <div ref={scrollRef} className=\"tds-data-table-scroll\">\n <Table\n {...restProps}\n {...selectableProps}\n {...(ariaLabel ? { \"aria-label\": ariaLabel } : {})}\n {...(describedBy ? { \"aria-describedby\": describedBy } : {})}\n // RAC's `Table` forwards `id` to the underlying table element at\n // runtime (via `filterDOMProps({ global: true })`) but omits `id`\n // from its prop types, so spread it through a cast.\n {...({ id: tableId } as Partial<AriaTableProps>)}\n className={combinedClassName}\n // Pinned rather than exposed as a prop: `disabledKeys` only ever\n // turns off selection here, leaving the row clickable and\n // focusable. React Aria defaults this to \"all\", which would also\n // disable `onRowClick`/`getRowLink` and drop the row out of the\n // focus order, so it has to be set explicitly.\n disabledBehavior=\"selection\"\n disabledKeys={disabledKeys}\n sortDescriptor={sortDescriptor}\n onSortChange={(sort) => {\n onSortChange?.(serializeSort(sort))\n }}\n >\n <TableHeader className=\"tds-data-table-header\">\n {/*\n Rendered as a sibling before the `preparedColumns.map` below\n (not folded into it) so the map's `index` still starts at 0\n for the first *data* column — that's what keeps\n `isRowHeader={index === 0}` pointing at the first data\n column instead of this selection column.\n */}\n {selectable && (\n <Column className=\"tds-data-table-column tds-data-table-column--selectable\">\n <Checkbox\n slot=\"selection\"\n className=\"tds-data-table-selectable-checkbox\"\n />\n </Column>\n )}\n {visiblePreparedColumns.map(({ align, column }, index) => (\n <Column\n key={column.name}\n id={column.name}\n isRowHeader={index === 0}\n className={classNames(\"tds-data-table-column\", {\n [`tds-data-table-column--align-${align}`]:\n align !== \"start\",\n })}\n allowsSorting={column.sortable}\n >\n {column.hideLabel ? (\n <span className=\"tds-data-table-column-label--hidden\">\n {column.headerLabel}\n </span>\n ) : (\n column.headerLabel\n )}\n {column.sortable && (\n <Icon\n className=\"tds-data-table-column-icon tds-data-table-column-icon--sort\"\n symbol=\"general#up-caret\"\n aria-hidden={true}\n />\n )}\n </Column>\n ))}\n {hasRowActions && (\n <Column className=\"tds-data-table-column tds-data-table-column--actions\">\n <span className=\"tds-data-table-column-label--hidden\">\n Actions\n </span>\n </Column>\n )}\n </TableHeader>\n <TableBody\n className=\"tds-data-table-body\"\n renderEmptyState={renderEmptyState}\n >\n {data.map((row, rowIndex) => {\n const rowKey = getRowKey(row, rowIndex, getRowId)\n return (\n <Row\n key={rowKey}\n id={rowKey}\n href={getRowLink?.(row)}\n onAction={onRowClick ? () => onRowClick(row) : undefined}\n className={classNames(\"tds-data-table-row\", {\n \"tds-data-table-row--interactive\": rowsAreInteractive,\n \"tds-data-table-row--press-selects\": rowPressSelects,\n })}\n >\n {selectable && (\n <Cell className=\"tds-data-table-cell tds-data-table-cell--selectable\">\n <Checkbox\n slot=\"selection\"\n className=\"tds-data-table-selectable-checkbox\"\n />\n </Cell>\n )}\n {visiblePreparedColumns.map((prepared) => (\n <Cell\n key={prepared.column.name}\n {...cellBoundaryProps}\n data-pii={prepared.column.pii || undefined}\n className={classNames(\"tds-data-table-cell\", {\n [`tds-data-table-cell--align-${prepared.align}`]:\n prepared.align !== \"start\",\n \"tds-data-table-cell--numeric\": prepared.isNumeric,\n })}\n >\n {prepared.renderCell(row)}\n </Cell>\n ))}\n {hasRowActions && (\n <Cell\n {...cellBoundaryProps}\n className=\"tds-data-table-cell tds-data-table-cell--actions\"\n >\n <RowActions\n actions={rowActions!} // Safe to assert non-null here because of `hasRowActions`\n row={row}\n rowKey={rowKey}\n />\n </Cell>\n )}\n </Row>\n )\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n {showPagination && (\n <div className=\"tds-data-table-frame-footer\">\n {/*\n `Pagination`'s two shapes are a discriminated union, so each is\n spelled out in full rather than assembled from one prop bag.\n */}\n {isIndexedPagination ? (\n <Pagination\n aria-label={paginationLabel}\n hasNextPage={hasNextPage}\n hasPreviousPage={hasPreviousPage}\n onNextPageClick={onNextPageClick}\n onPreviousPageClick={onPreviousPageClick}\n type=\"indexed\"\n />\n ) : (\n <Pagination\n aria-label={paginationLabel}\n currentPage={currentPage}\n onPageChange={onPageChange}\n totalPages={totalPages!}\n />\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nDataTable.displayName = \"DataTable\"\n\n/**\n * Resolves the content rendered in the table body's empty-state slot based on\n * `loadingState`, falling back to `emptyState`. Returns `null` when nothing\n * should render (idle with no `emptyState`).\n */\nfunction getEmptyStateContent({\n emptyState,\n errorState,\n loadingState,\n}: {\n emptyState: ReactNode\n errorState: ReactNode\n loadingState: DataTableLoadingState\n}): ReactNode {\n if (loadingState === \"loading\") {\n return (\n <div className=\"tds-data-table-loading\" role=\"status\">\n <span className=\"tds-data-table-cell-label--hidden\">Loading</span>\n <span className=\"tds-data-table-loading-spinner\" aria-hidden=\"true\">\n <LoadingSpinner />\n </span>\n </div>\n )\n }\n\n // Error and empty share the same container; they differ only in content.\n const content =\n loadingState === \"error\" ? (errorState ?? DEFAULT_ERROR_STATE) : emptyState\n if (content == null) return null\n\n return <div className=\"tds-data-table-empty\">{content}</div>\n}\n\nfunction useSortDescriptor(\n sortBy: Sort | undefined\n): SortDescriptor | undefined {\n return useMemo(() => {\n if (!sortBy) return undefined\n return deserializeSort(sortBy)\n }, [sortBy])\n}\n\nfunction deserializeSort(sort: Sort): SortDescriptor {\n if (sort.direction === \"desc\")\n return { column: sort.column, direction: \"descending\" }\n return { column: sort.column, direction: \"ascending\" }\n}\n\nfunction serializeSort(sort: SortDescriptor): Sort {\n if (sort.direction === \"descending\")\n return { column: sort.column as string, direction: \"desc\" }\n return { column: sort.column as string, direction: \"asc\" }\n}\n\n/**\n * Resolves the `<Table>` selection props, driving React Aria's `<Table>` off\n * the component's selection state. `onSelectedChange` always receives a plain\n * array of keys: React Aria's `\"all\"` selection sentinel (used for\n * infinite-loading collections, which this component doesn't have) is resolved\n * to the concrete keys of the currently loaded rows, minus any disabled ones —\n * React Aria's own \"select all\" skips disabled rows, so resolving `\"all\"` has to\n * skip them too.\n */\nfunction useSelectableProps({\n data,\n disabledKeys,\n getRowId,\n onSelectedChange,\n selectable,\n selectedKeys,\n}: {\n data: unknown[]\n disabledKeys: (number | string)[] | undefined\n getRowId: ((row: unknown) => number | string) | undefined\n onSelectedChange: (keys: (number | string)[]) => void\n selectable: boolean | undefined\n selectedKeys: (number | string)[]\n}): Pick<\n AriaTableProps,\n \"onSelectionChange\" | \"selectedKeys\" | \"selectionMode\"\n> {\n const selectedKeysSet = useMemo(\n () => new Set<Key>(selectedKeys),\n [selectedKeys]\n )\n const { rowKeys, rowOrder } = useMemo(() => {\n const rowKeys = data.map((row, index) => getRowKey(row, index, getRowId))\n return {\n rowKeys,\n rowOrder: new Map<Key, number>(rowKeys.map((key, index) => [key, index])),\n }\n }, [data, getRowId])\n\n if (!selectable) return { selectionMode: \"none\" }\n\n return {\n onSelectionChange: (keys: Selection) => {\n if (keys === \"all\") {\n const disabled = new Set<Key>(disabledKeys)\n onSelectedChange(rowKeys.filter((key) => !disabled.has(key)))\n return\n }\n // Keys not found in `rowOrder` (e.g. a previously selected row no longer\n // in `data`) sort to the end rather than being dropped.\n onSelectedChange(\n Array.from(keys).sort(\n (a, b) =>\n (rowOrder.get(a) ?? Infinity) - (rowOrder.get(b) ?? Infinity)\n )\n )\n },\n selectedKeys: selectedKeysSet,\n selectionMode: \"multiple\",\n }\n}\n\nfunction useStickyHeader(\n stickyHeader: boolean | undefined,\n scrollContainerRef: React.RefObject<HTMLElement> | undefined,\n scrollContainerSelector: string | undefined\n) {\n const wrapperRef = useRef<HTMLDivElement>(null)\n const [hasScrollContainer, setHasScrollContainer] = useState(false)\n\n useLayoutEffect(() => {\n setHasScrollContainer(false)\n if (!stickyHeader) return\n if (typeof ResizeObserver === \"undefined\") return\n const wrapper = wrapperRef.current\n if (!wrapper) return\n\n const scrollContainer = getScrollContainer(\n scrollContainerRef,\n scrollContainerSelector,\n wrapper\n )\n if (!scrollContainer) return\n\n setHasScrollContainer(true)\n\n let thead: HTMLElement | null = null\n\n const resizeObserver = new ResizeObserver(() => {\n if (!thead) {\n thead = wrapper.querySelector<HTMLElement>(\".tds-data-table-header\")\n if (!thead) return\n scrollContainer.style.setProperty(\n \"scroll-timeline-name\",\n \"--_sticky-header-scroll\"\n )\n }\n\n const { top: wrapperTop, bottom: wrapperBottom } =\n wrapper.getBoundingClientRect()\n const { top: scrollContainerTop } =\n scrollContainer.getBoundingClientRect()\n // Derive headerTop from the untransformed wrapper to avoid reading the\n // scroll-driven translateY that getBoundingClientRect() includes on thead.\n const headerTop = wrapperTop + wrapper.clientTop\n const start = scrollContainer.scrollTop + (headerTop - scrollContainerTop)\n const max = Math.max(0, wrapperBottom - headerTop - thead.offsetHeight)\n wrapper.style.setProperty(\"--_sticky-header-scroll-start\", `${start}px`)\n wrapper.style.setProperty(\"--_sticky-header-scroll-max\", `${max}px`)\n })\n\n resizeObserver.observe(wrapper)\n resizeObserver.observe(scrollContainer)\n\n return () => {\n resizeObserver.disconnect()\n wrapper.style.removeProperty(\"--_sticky-header-scroll-start\")\n wrapper.style.removeProperty(\"--_sticky-header-scroll-max\")\n }\n }, [stickyHeader, scrollContainerRef, scrollContainerSelector])\n\n return { hasScrollContainer, wrapperRef }\n}\n\nfunction getScrollContainer(\n scrollContainerRef: React.RefObject<HTMLElement> | undefined,\n scrollContainerSelector: string | undefined,\n wrapper: HTMLElement\n): HTMLElement | undefined {\n const element =\n scrollContainerRef?.current ??\n getScrollContainerFromSelector(scrollContainerSelector, wrapper)\n if (element instanceof Window) return\n return element\n}\n\nfunction getScrollContainerFromSelector(\n scrollContainerSelector: string | undefined,\n wrapper: HTMLElement\n): HTMLElement | undefined {\n return scrollContainerSelector\n ? (wrapper.parentElement?.closest<HTMLElement>(scrollContainerSelector) ??\n undefined)\n : undefined\n}\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.js","sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { Pagination } from \"@components/internal/pagination\"\nimport Icon from \"@utilities/Icon\"\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, {\n type ReactNode,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport {\n Cell,\n Checkbox,\n Column,\n Row,\n type SortDescriptor,\n Table,\n TableBody,\n TableHeader,\n type TableProps as AriaTableProps,\n} from \"react-aria-components/Table\"\n\nimport type { DataTableColumn } from \"./DataTableColumn\"\nimport { prepareColumn, type PreparedColumn } from \"./DataTableColumnTypes\"\nimport { getRowKey } from \"./DataTableRow\"\nimport {\n hasResultsCount,\n resolveResultNounLabel,\n type ResultNoun,\n ResultsCount,\n} from \"./ResultsCount\"\nimport { type RowAction, RowActions } from \"./RowActions\"\nimport { type TableAction, TableActions } from \"./TableActions\"\nimport { useColumnVisibility } from \"./useColumnVisibility\"\nimport {\n type DataTableSelection,\n DataTableSelectionContext,\n useDataTableSelection,\n} from \"./useDataTableSelection\"\nimport { useRowPressBoundary } from \"./useRowPressBoundary\"\nimport { ViewSettingsToggle } from \"./ViewSettingsToggle\"\n\nexport type { DataTableSelection, ResultNoun, RowAction, TableAction }\n\nexport type Sort = { column: string; direction: \"asc\" | \"desc\" }\n\nexport type DataTableLoadingState = \"error\" | \"idle\" | \"loading\"\n\ninterface DataTableBaseProps {\n /**\n * Columns define what data is displayed and how. Pass a stable reference\n * (e.g. a module constant or memoized value); columns are prepared per array\n * identity, so an inline array rebuilds each column's formatter every render.\n */\n columns: DataTableColumn[]\n /**\n * The 1-indexed current page. Only used by the default `\"paged\"` pagination,\n * where `totalPages` is set, and defaults to `1`.\n */\n currentPage?: number\n /** The array of rows to display. */\n data: unknown[]\n /**\n * Row keys that can't be selected. Keys are the values returned by `getRowId`\n * (or `row.id`, or the row's index) — the same keys used by `selectedKeys`.\n * Only selection is disabled: the row's checkbox renders disabled and \"select\n * all\" skips it, while the row itself stays clickable, navigable, and\n * focusable. Has no effect unless the table is `selectable`.\n */\n disabledKeys?: (number | string)[]\n /** Rendered in place of the table body when there is no data. */\n emptyState?: ReactNode\n /** Rendered in place of the table body when `loadingState` is `\"error\"`. */\n errorState?: ReactNode\n /** Returns a stable identity for each row. Defaults to `row.id`. */\n getRowId?: (row: unknown) => number | string\n /**\n * Returns a URL to navigate to when the row is clicked. Rows with a link\n * render as navigable elements (clickable, keyboard-focusable, and\n * openable in a new tab). Works alongside `onRowClick` and `selectable`.\n */\n getRowLink?: (row: unknown) => string\n /**\n * Whether a page exists after the current one. Only used by\n * `paginationType=\"indexed\"`, which has no page count to derive it from;\n * `false` (the default) disables the Next button.\n */\n hasNextPage?: boolean\n /**\n * Whether a page exists before the current one. Only used by\n * `paginationType=\"indexed\"`, which has no page count to derive it from;\n * `false` (the default) disables the Previous button.\n */\n hasPreviousPage?: boolean\n /**\n * An `id` for the table element. When omitted, a stable generated id is used\n * so the results count can be linked to the table via `aria-describedby`.\n */\n id?: string\n /**\n * Async loading state for the table body.\n * - `\"loading\"`: While `data` is empty, replaces the empty state with a\n * centered spinner.\n * - `\"error\"`: While `data` is empty, replaces the empty state with\n * `errorState` (or a default error message).\n * - `\"idle\"` (default): Normal rendering.\n */\n loadingState?: DataTableLoadingState\n /**\n * Called when the Next button is activated. Only used by\n * `paginationType=\"indexed\"`; load the following page's rows and pass them\n * back in through `data` in response.\n */\n onNextPageClick?: () => void\n /**\n * Called with the 1-indexed page the user navigated to. The table doesn't\n * page `data` itself — pass the rows for the new page back in through `data`\n * (and update `currentPage`) in response. Only used by the default `\"paged\"`\n * pagination; the indexed type has no page number to report.\n */\n onPageChange?: (page: number) => void\n /**\n * Called when the Previous button is activated. Only used by\n * `paginationType=\"indexed\"`; load the preceding page's rows and pass them\n * back in through `data` in response.\n */\n onPreviousPageClick?: () => void\n /**\n * Called with the row when it is clicked. Rows with a click handler render\n * as interactive elements (clickable and keyboard-focusable). When\n * `getRowLink` is also set, both run and the row navigates.\n */\n onRowClick?: (row: unknown) => void\n /** Callback invoked when the sort state changes. */\n onSortChange?: (sort: Sort) => void\n /**\n * Called with the full ordered list of visible column names when the\n * visibility toggle changes. Always-visible columns are included, so the\n * value can be passed straight back as `visibleColumnNames`. Column\n * visibility is controlled, so the table only updates once\n * `visibleColumnNames` changes.\n */\n onVisibleColumnNamesChange?: (visibleColumnNames: string[]) => void\n /**\n * Which shape the page controls take, forwarded to the `Pagination` control's\n * `type`.\n * - `\"paged\"` (the default): a numbered run of pages. Driven by `totalPages`,\n * `currentPage`, and `onPageChange`, and rendered only once `totalPages` is\n * set and greater than `1`.\n * - `\"indexed\"`: a labeled Previous/Next pair, for a result set that can only\n * be stepped through — a cursor-paged API, say, which reports whether a\n * neighboring page exists but not how many there are. Driven by\n * `hasPreviousPage`/`hasNextPage` and `onPreviousPageClick`/\n * `onNextPageClick`; `totalPages` and `currentPage` play no part. With no\n * page count there's no threshold to hide the controls below, so they\n * always render — a single page of results shows both buttons disabled.\n */\n paginationType?: \"indexed\" | \"paged\"\n /**\n * Overrides the number shown by the `resultNoun` count, which otherwise\n * uses the length of `data`. Use this when the table renders only part of\n * the result set — a paginated or virtualized table — so the count reflects\n * the whole set. It also sizes an all-pages selection when\n * `canSelectAllPages` is true, including the count used by table actions.\n * Otherwise, it has no effect unless `resultNoun` is set.\n */\n resultCount?: number\n /**\n * Displays the number of results (the length of `data`, or `resultCount`\n * when supplied) above the table, followed by a noun that matches the count.\n * Pass a string to use it as the singular noun and append `\"s\"` for the\n * plural (e.g. `\"result\"` → `\"results\"`), or a `[singular, plural]` tuple to\n * supply an irregular plural explicitly (e.g. `[\"person\", \"people\"]`). Pass\n * `true` to use `\"result\"`.\n * When `false` or omitted, no count is rendered. The count is formatted with\n * `Intl.NumberFormat` and the singular form is used only when the count is\n * exactly `1`. When the table is `selectable` and rows are selected, the\n * count instead reflects the selection as `\"{selected} of {total}\"`, e.g.\n * `\"2 of 100\"`, with a visually-hidden suffix naming the noun so assistive\n * tech reads the unambiguous `\"2 of 100 people selected\"`.\n * The count is linked to the table with `aria-describedby` so\n * screen readers announce it as a description of the table. When a string or\n * `[singular, plural]` tuple is provided, the noun also supplies the table's\n * `aria-label` in its plural form (e.g. `\"items\"` or `\"people\"`) unless an\n * `aria-label` is passed directly, which always takes precedence; `true`\n * never provides a label. The same plural noun also names the pagination\n * landmark (e.g. `\"people table pagination\"`), which otherwise falls back to\n * `\"Pagination\"`.\n */\n resultNoun?: ResultNoun\n /**\n * Displays a sticky column to the right that holds row-scoped actions.\n * Renders as a dropdown with 2+ actions or a single button with one. Each\n * action's `onAction` or `getHref` receives the row.\n */\n rowActions?: RowAction[]\n /** Ref to the scroll container the sticky header should track. Takes priority over `scrollContainerSelector`. Only used when `stickyHeader` is true. */\n scrollContainerRef?: React.RefObject<HTMLElement>\n /** CSS selector for the scroll container the sticky header should track. Only used when `stickyHeader` is true. Defaults to \".content-wrap\" */\n scrollContainerSelector?: string\n /**\n * Enables row selection via checkboxes, including a \"select all\" checkbox in\n * the header for the loaded page. Without a row action (`onRowClick` or\n * `getRowLink`), pressing anywhere in a row toggles the row selection.\n */\n selectable?: boolean\n /** The current sort state for the table. */\n sortBy?: Sort\n /** Enables a sticky header that tracks an outer scroll container. Progressive enhancement: Relies on `animation-timeline: scroll()`, which isn't supported in all browsers (e.g. Firefox) — the header scrolls with the table body instead of sticking in those cases. */\n stickyHeader?: boolean\n /**\n * The number of disabled rows across the whole result set. Used to size an\n * all-pages selection when disabled rows exist on unloaded pages. Replaces\n * the count inferred from `disabledKeys` rather than adding to it. Values are\n * clamped to the result count, and zero is used as supplied.\n */\n totalDisabledCount?: number\n /**\n * The total number of pages in the result set. Setting it renders the page\n * controls below the table; leaving it unset renders no pagination at all.\n * A single page has nothing to navigate to, so the controls only render once\n * there are two or more pages. Only used by the default `\"paged\"` pagination\n * — an indexed result set has no page count, which is the reason to reach for\n * `paginationType=\"indexed\"` in the first place.\n *\n * The table displays whatever rows it is given — paging is the caller's job.\n * `data` should hold only the current page's rows, `resultCount` the size of\n * the whole result set, and `onPageChange` should load the next page.\n */\n totalPages?: number\n /**\n * The names of the columns currently visible. Only columns marked `hideable`\n * are affected — every other column stays visible. Omitting this leaves all\n * columns visible. Unknown names are ignored and display order always\n * follows `columns`.\n */\n visibleColumnNames?: string[]\n}\n\ninterface DataTableExplicitSelectionProps {\n /** Keeps selection values as arrays of row keys. */\n canSelectAllPages?: false\n /** Called with the selected row keys whenever selection changes. */\n onSelectedChange?: (keys: (number | string)[]) => void\n /** The selected row keys. */\n selectedKeys?: (number | string)[]\n /** Table actions whose callbacks receive the selected row keys. */\n tableActions?: TableAction[]\n}\n\ninterface DataTableAllPagesSelectionProps {\n /**\n * Enables tagged selection values that can represent every page plus\n * exclusions. Explicit arrays and the header checkbox remain page-scoped.\n */\n canSelectAllPages: true\n /** Called with the current explicit or all-pages selection. */\n onSelectedChange?: (selection: DataTableSelection) => void\n /**\n * The current explicit or all-pages selection. Use\n * `{ keys: \"all\", excludedKeys: [] }` for every selectable result; a bare\n * `\"all\"` value is not accepted.\n */\n selectedKeys?: DataTableSelection\n /** Table actions whose callbacks receive the current selection. */\n tableActions?: TableAction<DataTableSelection>[]\n}\n\nexport type DataTableProps = DataTableBaseProps &\n (DataTableAllPagesSelectionProps | DataTableExplicitSelectionProps)\n\nconst DEFAULT_ERROR_STATE = \"Something went wrong.\"\n\ntype AriaTablePropsToOmit = \"children\" | \"slot\"\n\ntype AriaTablePropsToInclude = never\n\nexport type DataTableElementProps = CombineAriaPropsWithCustomProps<\n AriaTableProps,\n DataTableProps,\n AriaTablePropsToOmit,\n AriaTablePropsToInclude\n>\n\n/**\n * A table for displaying tabular data. Built on React Aria's `Table`.\n *\n * Each column declares a `type` that controls how its cell values are\n * formatted: `string`, `number`, `currency`, `date`, `datetime`, `boolean`,\n * `enum`, and `custom`. A column's `render` function always takes precedence\n * over the built-in type formatting.\n *\n * Setting `totalPages` renders page controls below the table; the table itself\n * never slices `data`, so `onPageChange` is where the caller loads the page.\n * `paginationType=\"indexed\"` swaps the numbered run for a labeled\n * Previous/Next pair, for a result set with no known page count.\n *\n * Filtering, presets, and other RFC features are not yet implemented.\n *\n * @component\n */\nexport const DataTable = ({\n className,\n canSelectAllPages,\n columns,\n currentPage = 1,\n data,\n disabledKeys,\n emptyState,\n errorState,\n getRowId,\n getRowLink,\n hasNextPage = false,\n hasPreviousPage = false,\n id,\n loadingState = \"idle\",\n paginationType = \"paged\",\n resultCount,\n resultNoun,\n scrollContainerRef,\n scrollContainerSelector = \".content-wrap\",\n rowActions,\n selectable,\n selectedKeys: controlledSelectedKeys,\n stickyHeader,\n sortBy,\n tableActions,\n totalDisabledCount,\n totalPages,\n visibleColumnNames,\n onNextPageClick,\n onPageChange,\n onPreviousPageClick,\n onRowClick,\n onSelectedChange,\n onSortChange,\n onVisibleColumnNamesChange,\n ...restProps\n}: DataTableElementProps) => {\n const hasRowPressAction = Boolean(onRowClick || getRowLink)\n const rowsAreInteractive = hasRowPressAction || Boolean(selectable)\n const combinedClassName = classNames(\"tds-data-table-grid\", className)\n const sortDescriptor = useSortDescriptor(sortBy)\n const { hasScrollContainer, wrapperRef } = useStickyHeader(\n stickyHeader,\n scrollContainerRef,\n scrollContainerSelector\n )\n const scrollRef = useRef<HTMLDivElement>(null)\n // A `Button` or `Link` in a cell keeps its presses to itself, so activating\n // one doesn't also press the row it's in.\n const cellBoundaryProps = useRowPressBoundary(scrollRef, rowsAreInteractive)\n\n // React Aria only invokes `renderEmptyState` when the collection is empty, so\n // the loading spinner and error message only take over the body while `data`\n // is empty; once rows exist they always render.\n const emptyStateContent = getEmptyStateContent({\n emptyState,\n errorState,\n loadingState,\n })\n const renderEmptyState = emptyStateContent\n ? () => emptyStateContent\n : undefined\n\n // Keyed on column names rather than the `columns` array identity so a fresh\n // `columns` literal each render doesn't rebuild every formatter. `columns` is\n // intentionally omitted from the deps.\n const columnKey = columns.map((c) => `${c.name}/${c.type}`).join(\"|\")\n const preparedColumns = useMemo<PreparedColumn[]>(\n () => columns.map(prepareColumn),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [columnKey]\n )\n\n const {\n hideableColumns,\n isColumnVisible,\n onColumnVisibilityChange,\n visibleHideableColumns,\n } = useColumnVisibility({\n columns,\n onVisibleColumnNamesChange,\n visibleColumnNames,\n })\n const visiblePreparedColumns = useMemo(\n () => preparedColumns.filter(({ column }) => isColumnVisible(column)),\n [preparedColumns, isColumnVisible]\n )\n\n const selectionModel = useDataTableSelection({\n canSelectAllPages,\n data,\n disabledKeys,\n getRowId,\n hasRowPressAction,\n onSelectedChange,\n resultCount,\n selectable,\n selectedKeys: controlledSelectedKeys,\n totalDisabledCount,\n })\n const {\n headerCheckboxProps,\n rowPressSelects,\n selectedCount,\n tableProps: selectionProps,\n totalCount,\n } = selectionModel\n\n // Associate the visible results count with the table so screen readers\n // announce it as a description of the table. `Table` doesn't support a real\n // `<caption>` (its children go through a collection builder), so we link the\n // count via `aria-describedby`, merging with any caller-supplied value.\n const stableId = useId()\n const tableId = id || `tds-data-table-${stableId}`\n const resultsCountId = `${tableId}-results-count`\n const describedBy = hasResultsCount(resultNoun)\n ? [restProps[\"aria-describedby\"], resultsCountId].filter(Boolean).join(\" \")\n : restProps[\"aria-describedby\"]\n\n // A caller-supplied `aria-label` always wins; otherwise the results noun\n // provides the table's accessible name so a label is present whenever a noun\n // is given. Array nouns are transformed to their plural form.\n const resultNounLabel = resolveResultNounLabel(resultNoun)\n const ariaLabel = restProps[\"aria-label\"] || resultNounLabel\n const paginationLabel = resultNounLabel\n ? `${resultNounLabel} table pagination`\n : undefined\n\n const hasActions = (tableActions?.length ?? 0) > 0\n const hasViewSettingsToggle = hideableColumns.length > 0\n const showHeader = Boolean(resultNoun || hasActions || hasViewSettingsToggle)\n const hasRowActions = (rowActions?.length ?? 0) > 0\n // A lone page has nothing to navigate to, so the paged controls stay out of\n // the frame entirely rather than rendering a single inert page marker. The\n // indexed type has no page count to measure against — stepping is the only\n // way through the set — so asking for it always renders the controls, and a\n // set that fits on one page shows both buttons disabled.\n const isIndexedPagination = paginationType === \"indexed\"\n const showPagination =\n isIndexedPagination || (totalPages !== undefined && totalPages > 1)\n\n return (\n <div\n className={classNames(\"tds-data-table\", {\n \"tds-data-table--sticky-header\": hasScrollContainer,\n })}\n >\n <div className=\"tds-data-table-frame\">\n {showHeader && (\n <DataTableSelectionContext.Provider value={selectionModel}>\n <div className=\"tds-data-table-frame-header\">\n <ResultsCount\n id={resultsCountId}\n resultNoun={resultNoun}\n selectable={selectable}\n selectedCount={selectedCount}\n totalCount={totalCount}\n />\n {hasActions && (\n <TableActions\n actions={tableActions as TableAction<DataTableSelection>[]}\n resultNoun={resultNoun}\n />\n )}\n {hasViewSettingsToggle && (\n <ViewSettingsToggle\n columns={hideableColumns}\n onColumnVisibilityChange={onColumnVisibilityChange}\n visibleColumnNames={visibleHideableColumns}\n />\n )}\n </div>\n </DataTableSelectionContext.Provider>\n )}\n <div ref={wrapperRef} className=\"tds-data-table-scroll-wrapper\">\n <div ref={scrollRef} className=\"tds-data-table-scroll\">\n <Table\n {...restProps}\n {...selectionProps}\n {...(ariaLabel ? { \"aria-label\": ariaLabel } : {})}\n {...(describedBy ? { \"aria-describedby\": describedBy } : {})}\n // RAC's `Table` forwards `id` to the underlying table element at\n // runtime (via `filterDOMProps({ global: true })`) but omits `id`\n // from its prop types, so spread it through a cast.\n {...({ id: tableId } as Partial<AriaTableProps>)}\n className={combinedClassName}\n // Pinned rather than exposed as a prop: `disabledKeys` only ever\n // turns off selection here, leaving the row clickable and\n // focusable. React Aria defaults this to \"all\", which would also\n // disable `onRowClick`/`getRowLink` and drop the row out of the\n // focus order, so it has to be set explicitly.\n disabledBehavior=\"selection\"\n disabledKeys={disabledKeys}\n sortDescriptor={sortDescriptor}\n onSortChange={(sort) => {\n onSortChange?.(serializeSort(sort))\n }}\n >\n <TableHeader className=\"tds-data-table-header\">\n {/*\n Rendered as a sibling before the `preparedColumns.map` below\n (not folded into it) so the map's `index` still starts at 0\n for the first *data* column — that's what keeps\n `isRowHeader={index === 0}` pointing at the first data\n column instead of this selection column.\n */}\n {selectable && (\n <Column className=\"tds-data-table-column tds-data-table-column--selectable\">\n {headerCheckboxProps ? (\n <Checkbox\n {...headerCheckboxProps}\n aria-label=\"Select all\"\n slot={null}\n className=\"tds-data-table-selectable-checkbox\"\n />\n ) : (\n <Checkbox\n slot=\"selection\"\n className=\"tds-data-table-selectable-checkbox\"\n />\n )}\n </Column>\n )}\n {visiblePreparedColumns.map(({ align, column }, index) => (\n <Column\n key={column.name}\n id={column.name}\n isRowHeader={index === 0}\n className={classNames(\"tds-data-table-column\", {\n [`tds-data-table-column--align-${align}`]:\n align !== \"start\",\n })}\n allowsSorting={column.sortable}\n >\n {column.hideLabel ? (\n <span className=\"tds-data-table-column-label--hidden\">\n {column.headerLabel}\n </span>\n ) : (\n column.headerLabel\n )}\n {column.sortable && (\n <Icon\n className=\"tds-data-table-column-icon tds-data-table-column-icon--sort\"\n symbol=\"general#up-caret\"\n aria-hidden={true}\n />\n )}\n </Column>\n ))}\n {hasRowActions && (\n <Column className=\"tds-data-table-column tds-data-table-column--actions\">\n <span className=\"tds-data-table-column-label--hidden\">\n Actions\n </span>\n </Column>\n )}\n </TableHeader>\n <TableBody\n className=\"tds-data-table-body\"\n renderEmptyState={renderEmptyState}\n >\n {data.map((row, rowIndex) => {\n const rowKey = getRowKey(row, rowIndex, getRowId)\n return (\n <Row\n key={rowKey}\n id={rowKey}\n href={getRowLink?.(row)}\n onAction={onRowClick ? () => onRowClick(row) : undefined}\n className={classNames(\"tds-data-table-row\", {\n \"tds-data-table-row--interactive\": rowsAreInteractive,\n \"tds-data-table-row--press-selects\": rowPressSelects,\n })}\n >\n {selectable && (\n <Cell className=\"tds-data-table-cell tds-data-table-cell--selectable\">\n <Checkbox\n slot=\"selection\"\n className=\"tds-data-table-selectable-checkbox\"\n />\n </Cell>\n )}\n {visiblePreparedColumns.map((prepared) => (\n <Cell\n key={prepared.column.name}\n {...cellBoundaryProps}\n data-pii={prepared.column.pii || undefined}\n className={classNames(\"tds-data-table-cell\", {\n [`tds-data-table-cell--align-${prepared.align}`]:\n prepared.align !== \"start\",\n \"tds-data-table-cell--numeric\": prepared.isNumeric,\n })}\n >\n {prepared.renderCell(row)}\n </Cell>\n ))}\n {hasRowActions && (\n <Cell\n {...cellBoundaryProps}\n className=\"tds-data-table-cell tds-data-table-cell--actions\"\n >\n <RowActions\n actions={rowActions!} // Safe to assert non-null here because of `hasRowActions`\n row={row}\n rowKey={rowKey}\n />\n </Cell>\n )}\n </Row>\n )\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n {showPagination && (\n <div className=\"tds-data-table-frame-footer\">\n {/*\n `Pagination`'s two shapes are a discriminated union, so each is\n spelled out in full rather than assembled from one prop bag.\n */}\n {isIndexedPagination ? (\n <Pagination\n aria-label={paginationLabel}\n hasNextPage={hasNextPage}\n hasPreviousPage={hasPreviousPage}\n onNextPageClick={onNextPageClick}\n onPreviousPageClick={onPreviousPageClick}\n type=\"indexed\"\n />\n ) : (\n <Pagination\n aria-label={paginationLabel}\n currentPage={currentPage}\n onPageChange={onPageChange}\n totalPages={totalPages!}\n />\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nDataTable.displayName = \"DataTable\"\n\n/**\n * Resolves the content rendered in the table body's empty-state slot based on\n * `loadingState`, falling back to `emptyState`. Returns `null` when nothing\n * should render (idle with no `emptyState`).\n */\nfunction getEmptyStateContent({\n emptyState,\n errorState,\n loadingState,\n}: {\n emptyState: ReactNode\n errorState: ReactNode\n loadingState: DataTableLoadingState\n}): ReactNode {\n if (loadingState === \"loading\") {\n return (\n <div className=\"tds-data-table-loading\" role=\"status\">\n <span className=\"tds-data-table-cell-label--hidden\">Loading</span>\n <span className=\"tds-data-table-loading-spinner\" aria-hidden=\"true\">\n <LoadingSpinner />\n </span>\n </div>\n )\n }\n\n // Error and empty share the same container; they differ only in content.\n const content =\n loadingState === \"error\" ? (errorState ?? DEFAULT_ERROR_STATE) : emptyState\n if (content == null) return null\n\n return <div className=\"tds-data-table-empty\">{content}</div>\n}\n\nfunction useSortDescriptor(\n sortBy: Sort | undefined\n): SortDescriptor | undefined {\n return useMemo(() => {\n if (!sortBy) return undefined\n return deserializeSort(sortBy)\n }, [sortBy])\n}\n\nfunction deserializeSort(sort: Sort): SortDescriptor {\n if (sort.direction === \"desc\")\n return { column: sort.column, direction: \"descending\" }\n return { column: sort.column, direction: \"ascending\" }\n}\n\nfunction serializeSort(sort: SortDescriptor): Sort {\n if (sort.direction === \"descending\")\n return { column: sort.column as string, direction: \"desc\" }\n return { column: sort.column as string, direction: \"asc\" }\n}\n\nfunction useStickyHeader(\n stickyHeader: boolean | undefined,\n scrollContainerRef: React.RefObject<HTMLElement> | undefined,\n scrollContainerSelector: string | undefined\n) {\n const wrapperRef = useRef<HTMLDivElement>(null)\n const [hasScrollContainer, setHasScrollContainer] = useState(false)\n\n useLayoutEffect(() => {\n setHasScrollContainer(false)\n if (!stickyHeader) return\n if (typeof ResizeObserver === \"undefined\") return\n const wrapper = wrapperRef.current\n if (!wrapper) return\n\n const scrollContainer = getScrollContainer(\n scrollContainerRef,\n scrollContainerSelector,\n wrapper\n )\n if (!scrollContainer) return\n\n setHasScrollContainer(true)\n\n let thead: HTMLElement | null = null\n\n const resizeObserver = new ResizeObserver(() => {\n if (!thead) {\n thead = wrapper.querySelector<HTMLElement>(\".tds-data-table-header\")\n if (!thead) return\n scrollContainer.style.setProperty(\n \"scroll-timeline-name\",\n \"--_sticky-header-scroll\"\n )\n }\n\n const { top: wrapperTop, bottom: wrapperBottom } =\n wrapper.getBoundingClientRect()\n const { top: scrollContainerTop } =\n scrollContainer.getBoundingClientRect()\n // Derive headerTop from the untransformed wrapper to avoid reading the\n // scroll-driven translateY that getBoundingClientRect() includes on thead.\n const headerTop = wrapperTop + wrapper.clientTop\n const start = scrollContainer.scrollTop + (headerTop - scrollContainerTop)\n const max = Math.max(0, wrapperBottom - headerTop - thead.offsetHeight)\n wrapper.style.setProperty(\"--_sticky-header-scroll-start\", `${start}px`)\n wrapper.style.setProperty(\"--_sticky-header-scroll-max\", `${max}px`)\n })\n\n resizeObserver.observe(wrapper)\n resizeObserver.observe(scrollContainer)\n\n return () => {\n resizeObserver.disconnect()\n wrapper.style.removeProperty(\"--_sticky-header-scroll-start\")\n wrapper.style.removeProperty(\"--_sticky-header-scroll-max\")\n }\n }, [stickyHeader, scrollContainerRef, scrollContainerSelector])\n\n return { hasScrollContainer, wrapperRef }\n}\n\nfunction getScrollContainer(\n scrollContainerRef: React.RefObject<HTMLElement> | undefined,\n scrollContainerSelector: string | undefined,\n wrapper: HTMLElement\n): HTMLElement | undefined {\n const element =\n scrollContainerRef?.current ??\n getScrollContainerFromSelector(scrollContainerSelector, wrapper)\n if (element instanceof Window) return\n return element\n}\n\nfunction getScrollContainerFromSelector(\n scrollContainerSelector: string | undefined,\n wrapper: HTMLElement\n): HTMLElement | undefined {\n return scrollContainerSelector\n ? (wrapper.parentElement?.closest<HTMLElement>(scrollContainerSelector) ??\n undefined)\n : undefined\n}\n"],"names":["React"],"mappings":"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"}
@@ -1,14 +1,15 @@
1
1
  import React, { type ReactNode } from "react";
2
2
  import { type ResultNoun } from "./ResultsCount";
3
+ import { type DataTableSelection } from "./useDataTableSelection";
3
4
  /**
4
5
  * A table action rendered as an `IconButton` in the button group above the
5
6
  * table. Replaces the original RFC's `{ buttonProps; callback }` shape with a
6
7
  * narrower, more controllable API so the design can evolve without exposing the
7
8
  * full button surface.
8
9
  */
9
- export type TableAction = {
10
- /** Called with the keys of the currently selected rows when the action is triggered. */
11
- callback?: (selectedKeys: (number | string)[]) => void;
10
+ export type TableAction<SelectionValue extends DataTableSelection = (number | string)[]> = {
11
+ /** Called with the current selection when the action is triggered. */
12
+ callback?: (selection: SelectionValue) => void;
12
13
  /** Whether the action's button is disabled. */
13
14
  disabled?: boolean;
14
15
  /** The icon rendered inside the action's icon button. */
@@ -20,22 +21,20 @@ export type TableAction = {
20
21
  };
21
22
  export interface TableActionsProps {
22
23
  /** The table actions to render as an `IconButton` group. */
23
- actions: TableAction[];
24
+ actions: TableAction<DataTableSelection>[];
24
25
  /**
25
26
  * The noun used to describe the selection in each action's `aria-label`.
26
27
  * See {@link ResultNoun}.
27
28
  */
28
29
  resultNoun?: ResultNoun;
29
- /** The keys of the currently selected rows, passed to each action's `callback`. */
30
- selectedKeys: (number | string)[];
31
30
  }
32
31
  /**
33
32
  * Renders the table actions as an `IconButton` group displayed directly after
34
33
  * the results count, above the table. Each entry becomes an icon button whose
35
- * `callback` receives the keys of the currently selected rows.
34
+ * `callback` receives the current selection.
36
35
  */
37
36
  export declare const TableActions: {
38
- ({ actions, resultNoun, selectedKeys, }: TableActionsProps): React.JSX.Element;
37
+ ({ actions, resultNoun }: TableActionsProps): React.JSX.Element;
39
38
  displayName: string;
40
39
  };
41
40
  //# sourceMappingURL=TableActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TableActions.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/TableActions.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,IAAI,CAAA;IACtD,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yDAAyD;IACzD,IAAI,EAAE,SAAS,CAAA;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;CACrD,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,mFAAmF;IACnF,YAAY,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;CAClC;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY;6CAItB,iBAAiB;;CAsBnB,CAAA"}
1
+ {"version":3,"file":"TableActions.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/TableActions.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAA;AAEhC;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CACrB,cAAc,SAAS,kBAAkB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,IAC7D;IACF,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAA;IAC9C,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yDAAyD;IACzD,IAAI,EAAE,SAAS,CAAA;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;CACrD,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,OAAO,EAAE,WAAW,CAAC,kBAAkB,CAAC,EAAE,CAAA;IAC1C;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY;8BAA6B,iBAAiB;;CAuBtE,CAAA"}
@@ -9,20 +9,22 @@ import { ButtonGroup } from '../button-group/ButtonGroup.js';
9
9
  import { Tooltip } from '../internal/tooltip/Tooltip.js';
10
10
  import React__default from 'react';
11
11
  import { resolveNoun, formatCount } from './ResultsCount.js';
12
+ import { useDataTableSelectionContext } from './useDataTableSelection.js';
12
13
 
13
14
  /**
14
15
  * Renders the table actions as an `IconButton` group displayed directly after
15
16
  * the results count, above the table. Each entry becomes an icon button whose
16
- * `callback` receives the keys of the currently selected rows.
17
+ * `callback` receives the current selection.
17
18
  */
18
- const TableActions = ({ actions, resultNoun, selectedKeys, }) => {
19
+ const TableActions = ({ actions, resultNoun }) => {
20
+ const { selectedCount, selection } = useDataTableSelectionContext();
19
21
  // The count/noun suffix is the same for every table action, so compute it once
20
22
  // here rather than per-button inside the map below.
21
- const countSuffix = getTableActionCountSuffix(selectedKeys.length, resultNoun);
23
+ const countSuffix = getTableActionCountSuffix(selectedCount, resultNoun);
22
24
  return (React__default.createElement(ButtonGroup, { "aria-label": "Table actions" }, actions.map(({ callback, disabled, icon, label, onClick }) => (React__default.createElement(Tooltip, { key: label, content: label, placement: "bottom" },
23
25
  React__default.createElement(IconButton, { "aria-label": `${label}${countSuffix}`, disabled: disabled, icon: icon, onClick: (event) => {
24
26
  onClick?.(event);
25
- callback?.(selectedKeys);
27
+ callback?.(selection);
26
28
  } }))))));
27
29
  };
28
30
  TableActions.displayName = "TableActions";
@@ -1 +1 @@
1
- {"version":3,"file":"TableActions.js","sources":["../../../src/components/DataTable/TableActions.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport { ButtonGroup } from \"@components/button-group\"\nimport { Tooltip } from \"@components/internal/tooltip\"\nimport React, { type ReactNode } from \"react\"\n\nimport { formatCount, resolveNoun, type ResultNoun } from \"./ResultsCount\"\n\n/**\n * A table action rendered as an `IconButton` in the button group above the\n * table. Replaces the original RFC's `{ buttonProps; callback }` shape with a\n * narrower, more controllable API so the design can evolve without exposing the\n * full button surface.\n */\nexport type TableAction = {\n /** Called with the keys of the currently selected rows when the action is triggered. */\n callback?: (selectedKeys: (number | string)[]) => void\n /** Whether the action's button is disabled. */\n disabled?: boolean\n /** The icon rendered inside the action's icon button. */\n icon: ReactNode\n /** Accessible label for the icon-only action button. */\n label: string\n /** Standard click handler, invoked with the click event before `callback`. */\n onClick?: React.MouseEventHandler<HTMLButtonElement>\n}\n\nexport interface TableActionsProps {\n /** The table actions to render as an `IconButton` group. */\n actions: TableAction[]\n /**\n * The noun used to describe the selection in each action's `aria-label`.\n * See {@link ResultNoun}.\n */\n resultNoun?: ResultNoun\n /** The keys of the currently selected rows, passed to each action's `callback`. */\n selectedKeys: (number | string)[]\n}\n\n/**\n * Renders the table actions as an `IconButton` group displayed directly after\n * the results count, above the table. Each entry becomes an icon button whose\n * `callback` receives the keys of the currently selected rows.\n */\nexport const TableActions = ({\n actions,\n resultNoun,\n selectedKeys,\n}: TableActionsProps) => {\n // The count/noun suffix is the same for every table action, so compute it once\n // here rather than per-button inside the map below.\n const countSuffix = getTableActionCountSuffix(selectedKeys.length, resultNoun)\n\n return (\n <ButtonGroup aria-label=\"Table actions\">\n {actions.map(({ callback, disabled, icon, label, onClick }) => (\n <Tooltip key={label} content={label} placement=\"bottom\">\n <IconButton\n aria-label={`${label}${countSuffix}`}\n disabled={disabled}\n icon={icon}\n onClick={(event) => {\n onClick?.(event)\n callback?.(selectedKeys)\n }}\n />\n </Tooltip>\n ))}\n </ButtonGroup>\n )\n}\n\nTableActions.displayName = \"TableActions\"\n\n/**\n * The count/noun suffix appended to each table action's `aria-label` when rows\n * are selected, e.g. `\" (2 selected people)\"` — so `\"Email\"` reads as\n * `\"Email (2 selected people)\"`. Empty when nothing is selected. Falls back to\n * the default `\"result\"` noun when `resultNoun` isn't provided. Shared across\n * every action, so it's computed once rather than per-button.\n */\nfunction getTableActionCountSuffix(\n count: number,\n resultNoun: ResultNoun | undefined\n): string {\n if (!count) return \"\"\n // An absent or `true` noun both default to `\"result\"`/`\"results\"`.\n const noun = resolveNoun(count, resultNoun || true)\n return ` (${formatCount(count)} selected ${noun})`\n}\n"],"names":["React"],"mappings":";;;;;;;;;;;;AAsCA;;;;AAIG;AACI,MAAM,YAAY,GAAG,CAAC,EAC3B,OAAO,EACP,UAAU,EACV,YAAY,GACM,KAAI;;;IAGtB,MAAM,WAAW,GAAG,yBAAyB,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC;AAE9E,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,YAAA,EAAY,eAAe,IACpC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MACxDA,cAAA,CAAA,aAAA,CAAC,OAAO,EAAA,EAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,QAAQ,EAAA;QACrDA,cAAA,CAAA,aAAA,CAAC,UAAU,kBACG,CAAA,EAAG,KAAK,GAAG,WAAW,CAAA,CAAE,EACpC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,CAAC,KAAK,KAAI;AACjB,gBAAA,OAAO,GAAG,KAAK,CAAC;AAChB,gBAAA,QAAQ,GAAG,YAAY,CAAC;AAC1B,YAAA,CAAC,GACD,CACM,CACX,CAAC,CACU;AAElB;AAEA,YAAY,CAAC,WAAW,GAAG,cAAc;AAEzC;;;;;;AAMG;AACH,SAAS,yBAAyB,CAChC,KAAa,EACb,UAAkC,EAAA;AAElC,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,EAAE;;IAErB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;IACnD,OAAO,CAAA,EAAA,EAAK,WAAW,CAAC,KAAK,CAAC,CAAA,UAAA,EAAa,IAAI,GAAG;AACpD;;;;"}
1
+ {"version":3,"file":"TableActions.js","sources":["../../../src/components/DataTable/TableActions.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport { ButtonGroup } from \"@components/button-group\"\nimport { Tooltip } from \"@components/internal/tooltip\"\nimport React, { type ReactNode } from \"react\"\n\nimport { formatCount, resolveNoun, type ResultNoun } from \"./ResultsCount\"\nimport {\n type DataTableSelection,\n useDataTableSelectionContext,\n} from \"./useDataTableSelection\"\n\n/**\n * A table action rendered as an `IconButton` in the button group above the\n * table. Replaces the original RFC's `{ buttonProps; callback }` shape with a\n * narrower, more controllable API so the design can evolve without exposing the\n * full button surface.\n */\nexport type TableAction<\n SelectionValue extends DataTableSelection = (number | string)[],\n> = {\n /** Called with the current selection when the action is triggered. */\n callback?: (selection: SelectionValue) => void\n /** Whether the action's button is disabled. */\n disabled?: boolean\n /** The icon rendered inside the action's icon button. */\n icon: ReactNode\n /** Accessible label for the icon-only action button. */\n label: string\n /** Standard click handler, invoked with the click event before `callback`. */\n onClick?: React.MouseEventHandler<HTMLButtonElement>\n}\n\nexport interface TableActionsProps {\n /** The table actions to render as an `IconButton` group. */\n actions: TableAction<DataTableSelection>[]\n /**\n * The noun used to describe the selection in each action's `aria-label`.\n * See {@link ResultNoun}.\n */\n resultNoun?: ResultNoun\n}\n\n/**\n * Renders the table actions as an `IconButton` group displayed directly after\n * the results count, above the table. Each entry becomes an icon button whose\n * `callback` receives the current selection.\n */\nexport const TableActions = ({ actions, resultNoun }: TableActionsProps) => {\n const { selectedCount, selection } = useDataTableSelectionContext()\n // The count/noun suffix is the same for every table action, so compute it once\n // here rather than per-button inside the map below.\n const countSuffix = getTableActionCountSuffix(selectedCount, resultNoun)\n\n return (\n <ButtonGroup aria-label=\"Table actions\">\n {actions.map(({ callback, disabled, icon, label, onClick }) => (\n <Tooltip key={label} content={label} placement=\"bottom\">\n <IconButton\n aria-label={`${label}${countSuffix}`}\n disabled={disabled}\n icon={icon}\n onClick={(event) => {\n onClick?.(event)\n callback?.(selection)\n }}\n />\n </Tooltip>\n ))}\n </ButtonGroup>\n )\n}\n\nTableActions.displayName = \"TableActions\"\n\n/**\n * The count/noun suffix appended to each table action's `aria-label` when rows\n * are selected, e.g. `\" (2 selected people)\"` — so `\"Email\"` reads as\n * `\"Email (2 selected people)\"`. Empty when nothing is selected. Falls back to\n * the default `\"result\"` noun when `resultNoun` isn't provided. Shared across\n * every action, so it's computed once rather than per-button.\n */\nfunction getTableActionCountSuffix(\n count: number,\n resultNoun: ResultNoun | undefined\n): string {\n if (!count) return \"\"\n // An absent or `true` noun both default to `\"result\"`/`\"results\"`.\n const noun = resolveNoun(count, resultNoun || true)\n return ` (${formatCount(count)} selected ${noun})`\n}\n"],"names":["React"],"mappings":";;;;;;;;;;;;;AA0CA;;;;AAIG;AACI,MAAM,YAAY,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAqB,KAAI;IACzE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,4BAA4B,EAAE;;;IAGnE,MAAM,WAAW,GAAG,yBAAyB,CAAC,aAAa,EAAE,UAAU,CAAC;AAExE,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,YAAA,EAAY,eAAe,IACpC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MACxDA,cAAA,CAAA,aAAA,CAAC,OAAO,EAAA,EAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,QAAQ,EAAA;QACrDA,cAAA,CAAA,aAAA,CAAC,UAAU,kBACG,CAAA,EAAG,KAAK,GAAG,WAAW,CAAA,CAAE,EACpC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,CAAC,KAAK,KAAI;AACjB,gBAAA,OAAO,GAAG,KAAK,CAAC;AAChB,gBAAA,QAAQ,GAAG,SAAS,CAAC;AACvB,YAAA,CAAC,GACD,CACM,CACX,CAAC,CACU;AAElB;AAEA,YAAY,CAAC,WAAW,GAAG,cAAc;AAEzC;;;;;;AAMG;AACH,SAAS,yBAAyB,CAChC,KAAa,EACb,UAAkC,EAAA;AAElC,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,EAAE;;IAErB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;IACnD,OAAO,CAAA,EAAA,EAAK,WAAW,CAAC,KAAK,CAAC,CAAA,UAAA,EAAa,IAAI,GAAG;AACpD;;;;"}
@@ -1,5 +1,5 @@
1
1
  import "./index.css";
2
- export type { DataTableElementProps, DataTableLoadingState, DataTableProps, } from "./DataTable";
2
+ export type { DataTableElementProps, DataTableLoadingState, DataTableProps, DataTableSelection, } from "./DataTable";
3
3
  export { DataTable } from "./DataTable";
4
4
  export type { BooleanColumn, CurrencyColumn, CustomColumn, DataTableColumn, DataTableColumnAlign, DataTableColumnType, DateColumn, DateTimeColumn, EnumColumn, NumberColumn, StringColumn, } from "./DataTableColumn";
5
5
  //# sourceMappingURL=index.d.ts.map