@cdx-ui/data-grid 0.3.11 → 0.3.13

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.
Files changed (96) hide show
  1. package/README.md +3 -1
  2. package/coverage.svg +1 -1
  3. package/lib/commonjs/DataGrid.js +490 -81
  4. package/lib/commonjs/DataGrid.js.map +1 -1
  5. package/lib/commonjs/DataGridFilterPanel.js +547 -0
  6. package/lib/commonjs/DataGridFilterPanel.js.map +1 -0
  7. package/lib/commonjs/adapter/columnTypes.js +256 -0
  8. package/lib/commonjs/adapter/columnTypes.js.map +1 -0
  9. package/lib/commonjs/adapter/columns.js +140 -4
  10. package/lib/commonjs/adapter/columns.js.map +1 -1
  11. package/lib/commonjs/adapter/filterOperators.js +422 -0
  12. package/lib/commonjs/adapter/filterOperators.js.map +1 -0
  13. package/lib/commonjs/adapter/pinning.js +105 -0
  14. package/lib/commonjs/adapter/pinning.js.map +1 -0
  15. package/lib/commonjs/adapter/selectColumn.js +11 -0
  16. package/lib/commonjs/adapter/selectColumn.js.map +1 -1
  17. package/lib/commonjs/adapter/treeData.js +195 -0
  18. package/lib/commonjs/adapter/treeData.js.map +1 -0
  19. package/lib/commonjs/index.js +26 -0
  20. package/lib/commonjs/index.js.map +1 -1
  21. package/lib/commonjs/numberCells.js +280 -0
  22. package/lib/commonjs/numberCells.js.map +1 -0
  23. package/lib/commonjs/styles.js +107 -1
  24. package/lib/commonjs/styles.js.map +1 -1
  25. package/lib/commonjs/types.js +39 -1
  26. package/lib/commonjs/types.js.map +1 -1
  27. package/lib/commonjs/useDataGridTable.js +234 -18
  28. package/lib/commonjs/useDataGridTable.js.map +1 -1
  29. package/lib/module/DataGrid.js +497 -88
  30. package/lib/module/DataGrid.js.map +1 -1
  31. package/lib/module/DataGridFilterPanel.js +540 -0
  32. package/lib/module/DataGridFilterPanel.js.map +1 -0
  33. package/lib/module/adapter/columnTypes.js +240 -0
  34. package/lib/module/adapter/columnTypes.js.map +1 -0
  35. package/lib/module/adapter/columns.js +137 -4
  36. package/lib/module/adapter/columns.js.map +1 -1
  37. package/lib/module/adapter/filterOperators.js +406 -0
  38. package/lib/module/adapter/filterOperators.js.map +1 -0
  39. package/lib/module/adapter/pinning.js +94 -0
  40. package/lib/module/adapter/pinning.js.map +1 -0
  41. package/lib/module/adapter/selectColumn.js +11 -1
  42. package/lib/module/adapter/selectColumn.js.map +1 -1
  43. package/lib/module/adapter/treeData.js +187 -0
  44. package/lib/module/adapter/treeData.js.map +1 -0
  45. package/lib/module/index.js +2 -0
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/numberCells.js +275 -0
  48. package/lib/module/numberCells.js.map +1 -0
  49. package/lib/module/styles.js +106 -0
  50. package/lib/module/styles.js.map +1 -1
  51. package/lib/module/types.js +38 -0
  52. package/lib/module/types.js.map +1 -1
  53. package/lib/module/useDataGridTable.js +238 -22
  54. package/lib/module/useDataGridTable.js.map +1 -1
  55. package/lib/typescript/DataGrid.d.ts.map +1 -1
  56. package/lib/typescript/DataGridFilterPanel.d.ts +52 -0
  57. package/lib/typescript/DataGridFilterPanel.d.ts.map +1 -0
  58. package/lib/typescript/adapter/columnTypes.d.ts +32 -0
  59. package/lib/typescript/adapter/columnTypes.d.ts.map +1 -0
  60. package/lib/typescript/adapter/columns.d.ts +14 -5
  61. package/lib/typescript/adapter/columns.d.ts.map +1 -1
  62. package/lib/typescript/adapter/filterOperators.d.ts +43 -0
  63. package/lib/typescript/adapter/filterOperators.d.ts.map +1 -0
  64. package/lib/typescript/adapter/pinning.d.ts +26 -0
  65. package/lib/typescript/adapter/pinning.d.ts.map +1 -0
  66. package/lib/typescript/adapter/selectColumn.d.ts +8 -0
  67. package/lib/typescript/adapter/selectColumn.d.ts.map +1 -1
  68. package/lib/typescript/adapter/treeData.d.ts +36 -0
  69. package/lib/typescript/adapter/treeData.d.ts.map +1 -0
  70. package/lib/typescript/index.d.ts +4 -1
  71. package/lib/typescript/index.d.ts.map +1 -1
  72. package/lib/typescript/numberCells.d.ts +46 -0
  73. package/lib/typescript/numberCells.d.ts.map +1 -0
  74. package/lib/typescript/styles.d.ts +32 -0
  75. package/lib/typescript/styles.d.ts.map +1 -1
  76. package/lib/typescript/types.d.ts +154 -7
  77. package/lib/typescript/types.d.ts.map +1 -1
  78. package/lib/typescript/useDataGridTable.d.ts +40 -4
  79. package/lib/typescript/useDataGridTable.d.ts.map +1 -1
  80. package/package.json +5 -5
  81. package/src/DataGrid.tsx +745 -95
  82. package/src/DataGridFilterPanel.tsx +648 -0
  83. package/src/adapter/columnTypes.ts +327 -0
  84. package/src/adapter/columns.test.ts +75 -1
  85. package/src/adapter/columns.ts +192 -3
  86. package/src/adapter/filterOperators.test.ts +292 -0
  87. package/src/adapter/filterOperators.ts +524 -0
  88. package/src/adapter/pinning.ts +134 -0
  89. package/src/adapter/selectColumn.ts +12 -1
  90. package/src/adapter/treeData.ts +228 -0
  91. package/src/index.ts +19 -0
  92. package/src/numberCells.tsx +379 -0
  93. package/src/styles.ts +131 -0
  94. package/src/types.ts +190 -7
  95. package/src/useDataGridTable.test.ts +69 -0
  96. package/src/useDataGridTable.ts +338 -17
@@ -1,22 +1,29 @@
1
1
  "use strict";
2
2
 
3
- import { useMemo } from 'react';
4
- import { Platform, View } from 'react-native';
5
- import { Checkbox, IconButton, Input, Skeleton, Table, TablePagination, Text } from '@cdx-ui/components';
6
- import { KeyboardArrowDown, KeyboardArrowUp, Search } from '@cdx-ui/icons';
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { I18nManager, Platform, View } from 'react-native';
5
+ import { Checkbox, Icon, IconButton, Input, Skeleton, Table, TablePagination, Text } from '@cdx-ui/components';
6
+ import { Check, Close, FilterList, KeyboardArrowDown, KeyboardArrowRight, KeyboardArrowUp, Search } from '@cdx-ui/icons';
7
7
  import { dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
8
8
  import { cn, useControllableState } from '@cdx-ui/utils';
9
- import { normalizeGridAlignment } from './adapter/columns';
10
- import { dataGridBodyVariants, dataGridCellVariants, dataGridEmptyOverlayVariants, dataGridFilterInputVariants, dataGridFooterVariants, dataGridHeadVariants, dataGridHeaderCellInnerVariants, dataGridHeaderLabelVariants, dataGridHeaderVariants, dataGridMainVariants, dataGridOverlayVariants, dataGridPaginationRangeVariants, dataGridPaginationVariants, dataGridRootVariants, dataGridSelectCellVariants, dataGridSelectHeadVariants, dataGridSortButtonVariants, dataGridTableVariants, dataGridToolbarActionsVariants, dataGridToolbarSearchVariants, dataGridToolbarVariants } from './styles';
11
- import { DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAGINATION_MODEL, EMPTY_SELECTION, SELECT_COLUMN_ID } from './types';
9
+ import { normalizePinnedColumns, resolveColumnAlign, resolveColumnHeaderAlign } from './adapter/columns';
10
+ import { DEFAULT_PINNED_COLUMN_WIDTH, DETAIL_PANEL_TOGGLE_WIDTH, SELECT_COLUMN_WIDTH, buildPinnedOffsets, isColumnPinningActive, pinnedCellStyle, pinnedEdgeGuidesImage, pinnedFieldSet, warnPinnedFlexColumns } from './adapter/pinning';
11
+ import { getTypedCellText } from './adapter/columnTypes';
12
+ import { DataGridFilterPanel, useDataGridFilterPanel } from './DataGridFilterPanel';
13
+ import { dataGridBodyVariants, dataGridCellTextVariants, dataGridCellVariants, dataGridDetailPanelCellVariants, dataGridDetailToggleCellVariants, dataGridEmptyOverlayVariants, dataGridFilterInputVariants, dataGridFooterVariants, dataGridHeadVariants, dataGridHeaderCellInnerVariants, dataGridHeaderLabelVariants, dataGridHeaderVariants, dataGridMainVariants, dataGridOverlayVariants, dataGridPaginationRangeVariants, dataGridPaginationVariants, dataGridPinnedEdgeVariants, dataGridPinnedSurfaceVariants, dataGridRootVariants, dataGridSelectCellVariants, dataGridSelectHeadVariants, dataGridSortButtonVariants, dataGridTableVariants, dataGridToolbarActionsVariants, dataGridToolbarSearchVariants, dataGridToolbarVariants, dataGridTreeCellInnerVariants, dataGridTreeContentVariants, dataGridTreeToggleSlotVariants } from './styles';
14
+ import { DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PAGINATION_MODEL, DETAIL_PANEL_TOGGLE_ID, EMPTY_ROW_ID_SET, EMPTY_SELECTION, SELECT_COLUMN_ID } from './types';
12
15
  import { resolveRowId, useDataGridTable } from './useDataGridTable';
13
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
14
17
  const MAX_SKELETON_ROW_COUNT = 10;
18
+ /** Matches the detail panel cell's `px-4`. */
19
+ const DETAIL_PANEL_INSET = 16;
20
+ const TREE_INDENT = 24;
15
21
  const DEFAULT_WEB_COLUMN_WIDTH = 100;
16
- const SELECT_COLUMN_WIDTH = 56;
17
22
  const WEB_TABLE_CONTAINER_STYLE = {
18
23
  overflow: 'visible'
19
24
  };
25
+ // Same token as the pinned cells' `border-stroke-secondary` divider.
26
+ const PINNED_EDGE_COLOR = 'var(--color-stroke-secondary)';
20
27
  function cellStyle(col, webWidth) {
21
28
  if (!col) {
22
29
  return undefined;
@@ -39,36 +46,96 @@ function cellStyle(col, webWidth) {
39
46
  }
40
47
  return Object.keys(style).length > 0 ? style : undefined;
41
48
  }
42
- function webColumnWidths(columns, checkboxSelection) {
43
- const totalFlex = columns.reduce((total, column) => total + Math.max(column.flex ?? 0, 0), 0);
49
+ function effectiveFlex(column, pinned) {
50
+ if (pinned.has(column.field)) {
51
+ return 0;
52
+ }
53
+ return Math.max(column.flex ?? 0, 0);
54
+ }
55
+ function webColumnWidths(columns, leadingWidth, pinned = new Set()) {
56
+ const totalFlex = columns.reduce((total, column) => total + effectiveFlex(column, pinned), 0);
44
57
  const widths = new Map();
45
58
  if (totalFlex === 0) {
46
59
  for (const column of columns) {
47
- if (column.width !== undefined) {
60
+ if (pinned.has(column.field)) {
61
+ widths.set(column.field, Math.max(column.width ?? DEFAULT_PINNED_COLUMN_WIDTH, column.minWidth ?? 0));
62
+ } else if (column.width !== undefined) {
48
63
  widths.set(column.field, column.width);
49
64
  }
50
65
  }
51
66
  return widths;
52
67
  }
53
- const fixedWidth = (checkboxSelection ? SELECT_COLUMN_WIDTH : 0) + columns.reduce((total, column) => {
54
- if ((column.flex ?? 0) > 0) {
68
+ const fixedWidth = leadingWidth + columns.reduce((total, column) => {
69
+ if (effectiveFlex(column, pinned) > 0) {
55
70
  return total;
56
71
  }
57
- return total + Math.max(column.width ?? DEFAULT_WEB_COLUMN_WIDTH, column.minWidth ?? 0);
72
+ const fallback = pinned.has(column.field) ? DEFAULT_PINNED_COLUMN_WIDTH : DEFAULT_WEB_COLUMN_WIDTH;
73
+ return total + Math.max(column.width ?? fallback, column.minWidth ?? 0);
58
74
  }, 0);
59
75
  for (const column of columns) {
60
- if ((column.flex ?? 0) > 0) {
61
- const share = (column.flex ?? 0) / totalFlex;
76
+ const flex = effectiveFlex(column, pinned);
77
+ if (flex > 0) {
78
+ const share = flex / totalFlex;
62
79
  const percentage = share * 100;
63
80
  const fixedShare = fixedWidth * share;
64
81
  const width = `calc(${percentage.toString()}% - ${fixedShare.toString()}px)`;
65
82
  widths.set(column.field, column.minWidth === undefined ? width : `max(${column.minWidth.toString()}px, ${width})`);
66
83
  } else {
67
- widths.set(column.field, Math.max(column.width ?? DEFAULT_WEB_COLUMN_WIDTH, column.minWidth ?? 0));
84
+ const fallback = pinned.has(column.field) ? DEFAULT_PINNED_COLUMN_WIDTH : DEFAULT_WEB_COLUMN_WIDTH;
85
+ widths.set(column.field, Math.max(column.width ?? fallback, column.minWidth ?? 0));
68
86
  }
69
87
  }
70
88
  return widths;
71
89
  }
90
+ function pinMetaFor(columnId, pinning) {
91
+ const startIndex = pinning.start.indexOf(columnId);
92
+ if (startIndex >= 0) {
93
+ return {
94
+ edge: 'start',
95
+ isEdgeDivider: startIndex === pinning.start.length - 1
96
+ };
97
+ }
98
+ const endIndex = pinning.end.indexOf(columnId);
99
+ if (endIndex >= 0) {
100
+ return {
101
+ edge: 'end',
102
+ isEdgeDivider: endIndex === 0
103
+ };
104
+ }
105
+ return {
106
+ edge: false,
107
+ isEdgeDivider: false
108
+ };
109
+ }
110
+ function mergePinnedStyle(base, pin, offsets, columnId, isHeader) {
111
+ if (!pin.edge || offsets == null) {
112
+ return base;
113
+ }
114
+ const offset = pin.edge === 'start' ? offsets.start.get(columnId) ?? 0 : offsets.end.get(columnId) ?? 0;
115
+ return {
116
+ ...base,
117
+ ...pinnedCellStyle(pin.edge, offset, isHeader)
118
+ };
119
+ }
120
+ function pinnedClassName(pin, isHeader) {
121
+ if (!pin.edge) {
122
+ return undefined;
123
+ }
124
+ return cn(dataGridPinnedSurfaceVariants({
125
+ header: isHeader
126
+ }), dataGridPinnedEdgeVariants({
127
+ edge: pin.isEdgeDivider ? pin.edge : 'none'
128
+ }));
129
+ }
130
+ function BooleanCell({
131
+ value
132
+ }) {
133
+ return /*#__PURE__*/_jsx(Icon, {
134
+ as: value ? Check : Close,
135
+ accessibilityLabel: value ? 'Yes' : 'No',
136
+ className: "size-5"
137
+ });
138
+ }
72
139
  function defaultCellContent(value) {
73
140
  if (value == null) {
74
141
  return '';
@@ -88,30 +155,52 @@ function defaultCellContent(value) {
88
155
  }
89
156
  function DefaultLoadingRows({
90
157
  columns,
91
- checkboxSelection,
158
+ leadingColumnIds,
92
159
  rowCount,
93
- columnWidths
160
+ columnWidths,
161
+ orderedColumnIds,
162
+ pinning,
163
+ offsets
94
164
  }) {
165
+ const colByField = new Map(columns.map(column => [column.field, column]));
166
+ const ids = orderedColumnIds ?? [...leadingColumnIds, ...columns.map(column => column.field)];
95
167
  return /*#__PURE__*/_jsx(_Fragment, {
96
168
  children: Array.from({
97
169
  length: rowCount
98
- }, (_, rowIndex) => /*#__PURE__*/_jsxs(Table.Row, {
170
+ }, (_, rowIndex) => /*#__PURE__*/_jsx(Table.Row, {
99
171
  className: "pointer-events-none web:hover:bg-surface-primary",
100
172
  testID: rowIndex === 0 ? 'data-grid-default-loading-rows' : undefined,
101
- children: [checkboxSelection ? /*#__PURE__*/_jsx(Table.Cell, {
102
- align: "center",
103
- className: dataGridSelectCellVariants(),
104
- children: /*#__PURE__*/_jsx(Skeleton, {
105
- className: "size-5"
106
- })
107
- }) : null, columns.map(column => /*#__PURE__*/_jsx(Table.Cell, {
108
- align: normalizeGridAlignment(column.align),
109
- className: dataGridCellVariants(),
110
- style: cellStyle(column, columnWidths.get(column.field)),
111
- children: /*#__PURE__*/_jsx(Skeleton, {
112
- className: "h-4 w-3/5"
113
- })
114
- }, column.field))]
173
+ children: ids.map(columnId => {
174
+ const pin = pinMetaFor(columnId, pinning);
175
+ if (columnId === SELECT_COLUMN_ID) {
176
+ return /*#__PURE__*/_jsx(Table.Cell, {
177
+ align: "center",
178
+ className: cn(dataGridSelectCellVariants(), pinnedClassName(pin, false)),
179
+ style: mergePinnedStyle(undefined, pin, offsets, columnId, false),
180
+ children: /*#__PURE__*/_jsx(Skeleton, {
181
+ className: "size-5"
182
+ })
183
+ }, columnId);
184
+ }
185
+ if (columnId === DETAIL_PANEL_TOGGLE_ID) {
186
+ return /*#__PURE__*/_jsx(Table.Cell, {
187
+ className: cn(dataGridDetailToggleCellVariants(), pinnedClassName(pin, false)),
188
+ style: mergePinnedStyle(undefined, pin, offsets, columnId, false)
189
+ }, columnId);
190
+ }
191
+ const column = colByField.get(columnId);
192
+ if (!column) {
193
+ return null;
194
+ }
195
+ return /*#__PURE__*/_jsx(Table.Cell, {
196
+ align: resolveColumnAlign(column),
197
+ className: cn(dataGridCellVariants(), pinnedClassName(pin, false)),
198
+ style: mergePinnedStyle(cellStyle(column, columnWidths.get(column.field)), pin, offsets, column.field, false),
199
+ children: /*#__PURE__*/_jsx(Skeleton, {
200
+ className: "h-4 w-3/5"
201
+ })
202
+ }, column.field);
203
+ })
115
204
  }, rowIndex))
116
205
  });
117
206
  }
@@ -144,6 +233,8 @@ function DataGridInner(props) {
144
233
  rowCount,
145
234
  showToolbar = false,
146
235
  headerFilters = false,
236
+ pinnedColumns,
237
+ columnVisibilityModel,
147
238
  pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
148
239
  noRowsOverlay,
149
240
  loadingOverlay,
@@ -152,8 +243,49 @@ function DataGridInner(props) {
152
243
  style,
153
244
  label,
154
245
  'aria-label': ariaLabel,
155
- 'aria-labelledby': ariaLabelledBy
246
+ 'aria-labelledby': ariaLabelledBy,
247
+ treeData = false,
248
+ getTreeDataPath,
249
+ groupingColDef,
250
+ defaultGroupingExpansionDepth,
251
+ isGroupExpandedByDefault,
252
+ rowSelectionPropagation,
253
+ getDetailPanelContent
156
254
  } = props;
255
+ const treeActive = treeData && getTreeDataPath !== undefined;
256
+ const isColumnVisible = useCallback(column => columnVisibilityModel?.[column.field] !== false, [columnVisibilityModel]);
257
+ const treeField = treeActive ? columns.find(isColumnVisible)?.field : undefined;
258
+ const gridColumns = useMemo(() => {
259
+ if (treeField === undefined || groupingColDef === undefined) {
260
+ return columns;
261
+ }
262
+ return columns.map(column => column.field === treeField ? {
263
+ ...column,
264
+ ...groupingColDef,
265
+ field: column.field
266
+ } : column);
267
+ }, [columns, groupingColDef, treeField]);
268
+ const visibleColumns = useMemo(() => gridColumns.filter(isColumnVisible), [gridColumns, isColumnVisible]);
269
+ const selectColumn = checkboxSelection && !treeActive;
270
+ const treeCheckbox = checkboxSelection && treeActive;
271
+ const detailPanel = getDetailPanelContent !== undefined;
272
+ const leadingColumnIds = useMemo(() => [...(selectColumn ? [SELECT_COLUMN_ID] : []), ...(detailPanel ? [DETAIL_PANEL_TOGGLE_ID] : [])], [detailPanel, selectColumn]);
273
+ const leadingWidth = (selectColumn ? SELECT_COLUMN_WIDTH : 0) + (detailPanel ? DETAIL_PANEL_TOGGLE_WIDTH : 0);
274
+ const [detailPanelExpandedRowIds, setDetailPanelExpandedRowIds] = useControllableState({
275
+ prop: props.detailPanelExpandedRowIds,
276
+ defaultProp: props.defaultDetailPanelExpandedRowIds ?? EMPTY_ROW_ID_SET,
277
+ onChange: ids => props.onDetailPanelExpandedRowIdsChange?.(new Set(ids))
278
+ });
279
+ const resolvedDetailIds = detailPanelExpandedRowIds ?? EMPTY_ROW_ID_SET;
280
+ const toggleDetailPanel = id => {
281
+ const next = new Set(resolvedDetailIds);
282
+ if (next.has(id)) {
283
+ next.delete(id);
284
+ } else {
285
+ next.add(id);
286
+ }
287
+ setDetailPanelExpandedRowIds(next);
288
+ };
157
289
  const [sortModel, setSortModel] = useControllableState({
158
290
  prop: props.sortModel,
159
291
  defaultProp: props.defaultSortModel ?? [],
@@ -169,6 +301,11 @@ function DataGridInner(props) {
169
301
  defaultProp: props.defaultFilterModel ?? [],
170
302
  onChange: props.onFilterModelChange
171
303
  });
304
+ const [filterLogicOperator, setFilterLogicOperator] = useControllableState({
305
+ prop: props.filterLogicOperator,
306
+ defaultProp: props.defaultFilterLogicOperator ?? 'and',
307
+ onChange: props.onFilterLogicOperatorChange
308
+ });
172
309
  const [quickFilter, setQuickFilter] = useControllableState({
173
310
  prop: props.quickFilter,
174
311
  defaultProp: props.defaultQuickFilter ?? '',
@@ -182,16 +319,29 @@ function DataGridInner(props) {
182
319
  const resolvedSortModel = sortModel ?? [];
183
320
  const resolvedPagination = paginationModel ?? DEFAULT_PAGINATION_MODEL;
184
321
  const resolvedFilterModel = filterModel ?? [];
322
+ const resolvedFilterLogicOperator = filterLogicOperator ?? 'and';
185
323
  const resolvedQuickFilter = quickFilter ?? '';
186
324
  const resolvedSelection = rowSelectionModel ?? EMPTY_SELECTION;
325
+ const knownFields = useMemo(() => new Set(columns.map(column => column.field)), [columns]);
326
+ const columnPinning = useMemo(() => normalizePinnedColumns(pinnedColumns, knownFields, selectColumn, detailPanel), [pinnedColumns, knownFields, selectColumn, detailPanel]);
327
+ const pinningActive = isColumnPinningActive(columnPinning);
328
+ const pinnedFields = useMemo(() => pinnedFieldSet(columnPinning), [columnPinning]);
187
329
  const {
188
330
  table,
189
331
  setQuickFilter: setQuickFilterWithPageReset,
190
- setColumnFilter
332
+ setColumnFilter,
333
+ setFilterModel: setFilterModelWithPageReset,
334
+ tree
191
335
  } = useDataGridTable({
192
336
  rows,
193
- columns,
337
+ columns: gridColumns,
194
338
  getRowId,
339
+ detailPanel,
340
+ treeData: treeActive,
341
+ getTreeDataPath,
342
+ defaultGroupingExpansionDepth,
343
+ isGroupExpandedByDefault,
344
+ rowSelectionPropagation,
195
345
  checkboxSelection,
196
346
  disableColumnSorting,
197
347
  paginationMode,
@@ -204,25 +354,52 @@ function DataGridInner(props) {
204
354
  onPaginationModelChange: model => setPaginationModel(model),
205
355
  filterModel: resolvedFilterModel,
206
356
  onFilterModelChange: model => setFilterModel(model),
357
+ filterLogicOperator: resolvedFilterLogicOperator,
207
358
  quickFilter: resolvedQuickFilter,
208
359
  onQuickFilterChange: value => setQuickFilter(value),
209
360
  rowSelectionModel: resolvedSelection,
210
- onRowSelectionModelChange: model => setRowSelectionModel(model)
361
+ onRowSelectionModelChange: model => setRowSelectionModel(model),
362
+ columnPinning,
363
+ columnVisibility: columnVisibilityModel
211
364
  });
212
365
  const colByField = useMemo(() => {
213
366
  const map = new Map();
214
- for (const col of columns) {
367
+ for (const col of gridColumns) {
215
368
  map.set(col.field, col);
216
369
  }
217
370
  return map;
218
- }, [columns]);
219
- const columnWidths = useMemo(() => webColumnWidths(columns, checkboxSelection), [checkboxSelection, columns]);
220
- const hasFlexColumns = useMemo(() => columns.some(column => (column.flex ?? 0) > 0), [columns]);
371
+ }, [gridColumns]);
372
+ warnPinnedFlexColumns(visibleColumns, pinnedFields);
373
+ const columnWidths = useMemo(() => webColumnWidths(visibleColumns, leadingWidth, pinnedFields), [leadingWidth, visibleColumns, pinnedFields]);
374
+ const hasFlexColumns = useMemo(() => visibleColumns.some(column => effectiveFlex(column, pinnedFields) > 0), [visibleColumns, pinnedFields]);
375
+ const pinnedOffsets = useMemo(() => pinningActive ? buildPinnedOffsets(columnPinning, colByField) : null, [pinningActive, columnPinning, colByField]);
376
+ const orderedLeafColumnIds = useMemo(() => {
377
+ if (!pinningActive) {
378
+ return undefined;
379
+ }
380
+ return [...table.getStartVisibleLeafColumns().map(column => column.id), ...table.getCenterVisibleLeafColumns().map(column => column.id), ...table.getEndVisibleLeafColumns().map(column => column.id)];
381
+ }, [pinningActive, table]);
382
+ const isEmpty = !loading && rows.length === 0;
383
+ const mainScrollStyle = useMemo(() => {
384
+ if (!pinningActive || pinnedOffsets == null) {
385
+ return undefined;
386
+ }
387
+ const guides = Platform.OS === 'web' && !isEmpty ? pinnedEdgeGuidesImage(pinnedOffsets, PINNED_EDGE_COLOR, I18nManager.isRTL) : undefined;
388
+ // Logical scroll-padding keeps focused cells out from under pinned edges (web).
389
+ return {
390
+ scrollPaddingInlineStart: pinnedOffsets.startTotal,
391
+ scrollPaddingInlineEnd: pinnedOffsets.endTotal,
392
+ ...(guides ? {
393
+ backgroundImage: guides,
394
+ backgroundRepeat: 'no-repeat'
395
+ } : {})
396
+ };
397
+ }, [pinningActive, pinnedOffsets, isEmpty]);
221
398
  const visibleRows = table.getRowModel().rows;
222
399
  const pageCount = Math.max(table.getPageCount(), 1);
223
400
  const selectedCount = table.getFilteredSelectedRowModel().rows.length;
224
401
  const filterableCount = table.getFilteredRowModel().rows.length;
225
- const headerSelectState = selectedCount === 0 ? {
402
+ const headerSelectState = tree?.headerSelection ?? (selectedCount === 0 ? {
226
403
  checked: false,
227
404
  indeterminate: false
228
405
  } : selectedCount === filterableCount ? {
@@ -231,16 +408,74 @@ function DataGridInner(props) {
231
408
  } : {
232
409
  checked: false,
233
410
  indeterminate: true
234
- };
411
+ });
412
+ const leafColumnCount = table.getVisibleLeafColumns().length;
235
413
  const accessibleName = ariaLabel ?? label;
236
- const isEmpty = !loading && rows.length === 0;
237
414
  const totalCount = paginationMode === 'server' ? rowCount ?? rows.length : filterableCount;
238
- const filterValueFor = field => resolvedFilterModel.find(item => item.field === field)?.value ?? '';
415
+ const filterValueFor = field => {
416
+ const value = resolvedFilterModel.find(item => item.field === field)?.value;
417
+ return typeof value === 'string' ? value : '';
418
+ };
239
419
  const showToolbarBar = showToolbar || toolbarActions != null;
420
+ const filterPanelColumns = useMemo(() => gridColumns.filter(column => column.filterable !== false), [gridColumns]);
421
+ // Header filter cells and the column menu open the panel through `filterPanel.openForField`.
422
+ const filterPanel = useDataGridFilterPanel({
423
+ columns: filterPanelColumns,
424
+ filterModel: resolvedFilterModel,
425
+ onFilterModelChange: setFilterModel
426
+ });
427
+ const filterPanelOpen = filterPanel.opener !== null && filterPanelColumns.length > 0;
428
+ const filterPanelAnchored = filterPanel.opener?.field !== undefined;
429
+ const filterPanelButtonRef = useRef(null);
430
+ const showFilterPanelButton = showToolbar && filterPanelColumns.length > 0;
431
+ const mainRef = useRef(null);
432
+ const [viewportWidth, setViewportWidth] = useState(undefined);
433
+ useEffect(() => {
434
+ const main = mainRef.current;
435
+ if (Platform.OS !== 'web' || !detailPanel || main === null || typeof ResizeObserver === 'undefined') {
436
+ return undefined;
437
+ }
438
+ const observer = new ResizeObserver(() => setViewportWidth(main.clientWidth));
439
+ observer.observe(main);
440
+ return () => observer.disconnect();
441
+ }, [detailPanel]);
442
+ const detailPanelContentStyle = useMemo(() => viewportWidth === undefined ? undefined : {
443
+ position: 'sticky',
444
+ insetInlineStart: DETAIL_PANEL_INSET,
445
+ width: viewportWidth - DETAIL_PANEL_INSET * 2
446
+ }, [viewportWidth]);
447
+ const rootRef = useRef(null);
448
+ const searchRef = useRef(null);
449
+ const bodyFocusRef = useRef(null);
450
+ useEffect(() => {
451
+ if (Platform.OS !== 'web') {
452
+ return undefined;
453
+ }
454
+ const root = rootRef.current;
455
+ const onFocusIn = event => {
456
+ const target = event.target instanceof Element ? event.target : null;
457
+ bodyFocusRef.current = target !== null && root?.contains(target.closest('tbody')) === true ? target : null;
458
+ };
459
+ document.addEventListener('focusin', onFocusIn);
460
+ return () => document.removeEventListener('focusin', onFocusIn);
461
+ }, []);
462
+ // Only when the focused row control was removed: focus that left the grid stays where it went.
463
+ useEffect(() => {
464
+ const focused = bodyFocusRef.current;
465
+ if (Platform.OS !== 'web' || focused === null || focused.isConnected) {
466
+ return;
467
+ }
468
+ bodyFocusRef.current = null;
469
+ const active = document.activeElement;
470
+ if (active === null || active === document.body) {
471
+ searchRef.current?.focus();
472
+ }
473
+ }, [visibleRows]);
240
474
  return /*#__PURE__*/_jsxs(View, {
475
+ ref: rootRef,
241
476
  className: cn(dataGridRootVariants({
242
477
  autoHeight
243
- }), className),
478
+ }), className, filterPanelOpen && !filterPanelAnchored && 'overflow-visible'),
244
479
  style: style,
245
480
  ...mergeDataAttributes({}, dataAttributes({
246
481
  slot: 'data-grid'
@@ -253,20 +488,50 @@ function DataGridInner(props) {
253
488
  children: [/*#__PURE__*/_jsx(Input.Icon, {
254
489
  as: Search
255
490
  }), /*#__PURE__*/_jsx(Input.Field, {
491
+ ref: searchRef,
256
492
  value: resolvedQuickFilter,
257
493
  onChangeText: setQuickFilterWithPageReset,
258
494
  placeholder: "Search",
259
495
  accessibilityLabel: "Search"
260
496
  })]
497
+ }) : null, showFilterPanelButton ? /*#__PURE__*/_jsx(IconButton, {
498
+ ref: filterPanelButtonRef,
499
+ as: FilterList,
500
+ variant: "ghost",
501
+ color: "neutral",
502
+ size: "small",
503
+ accessibilityLabel: "Filters",
504
+ accessibilityState: {
505
+ expanded: filterPanelOpen
506
+ },
507
+ onPress: () => filterPanel.toggle(filterPanelButtonRef)
261
508
  }) : null, toolbarActions ? /*#__PURE__*/_jsx(View, {
262
509
  className: dataGridToolbarActionsVariants(),
263
510
  children: toolbarActions
264
511
  }) : null]
512
+ }) : null, filterPanelOpen && filterPanel.opener ? /*#__PURE__*/_jsx(DataGridFilterPanel, {
513
+ columns: filterPanelColumns,
514
+ filterModel: resolvedFilterModel,
515
+ onFilterModelChange: setFilterModelWithPageReset,
516
+ logicOperator: resolvedFilterLogicOperator,
517
+ onLogicOperatorChange: operator => {
518
+ setFilterLogicOperator(operator);
519
+ if (resolvedPagination.page !== 0) {
520
+ setPaginationModel({
521
+ ...resolvedPagination,
522
+ page: 0
523
+ });
524
+ }
525
+ },
526
+ onClose: filterPanel.close,
527
+ opener: filterPanel.opener
265
528
  }) : null, /*#__PURE__*/_jsxs(View, {
529
+ ref: mainRef,
266
530
  className: dataGridMainVariants({
267
531
  autoHeight,
268
532
  overlay: isEmpty || loading && loadingOverlay != null
269
533
  }),
534
+ style: mainScrollStyle,
270
535
  children: [/*#__PURE__*/_jsxs(Table, {
271
536
  className: cn(dataGridTableVariants(), Platform.OS === 'web' && hasFlexColumns ? 'table-fixed' : undefined),
272
537
  containerStyle: Platform.OS === 'web' ? WEB_TABLE_CONTAINER_STYLE : undefined,
@@ -278,25 +543,34 @@ function DataGridInner(props) {
278
543
  } : {}),
279
544
  children: [label ? /*#__PURE__*/_jsx(Table.Caption, {
280
545
  children: label
281
- }) : null, Platform.OS === 'web' && hasFlexColumns ? /*#__PURE__*/_jsxs("colgroup", {
282
- children: [checkboxSelection ? /*#__PURE__*/_jsx("col", {
546
+ }) : null, Platform.OS === 'web' && hasFlexColumns ? /*#__PURE__*/_jsx("colgroup", {
547
+ children: (orderedLeafColumnIds ?? [...leadingColumnIds, ...visibleColumns.map(column => column.field)]).map(columnId => columnId === SELECT_COLUMN_ID ? /*#__PURE__*/_jsx("col", {
283
548
  style: {
284
549
  width: SELECT_COLUMN_WIDTH
285
550
  }
286
- }) : null, columns.map(column => /*#__PURE__*/_jsx("col", {
551
+ }, columnId) : columnId === DETAIL_PANEL_TOGGLE_ID ? /*#__PURE__*/_jsx("col", {
552
+ style: {
553
+ width: DETAIL_PANEL_TOGGLE_WIDTH
554
+ }
555
+ }, columnId) : /*#__PURE__*/_jsx("col", {
287
556
  style: {
288
- width: columnWidths.get(column.field),
289
- minWidth: column.minWidth
557
+ width: columnWidths.get(columnId),
558
+ minWidth: colByField.get(columnId)?.minWidth
290
559
  }
291
- }, column.field))]
560
+ }, columnId))
292
561
  }) : null, /*#__PURE__*/_jsxs(Table.Header, {
293
562
  className: dataGridHeaderVariants(),
294
- children: [table.getHeaderGroups().map(headerGroup => /*#__PURE__*/_jsx(Table.Row, {
563
+ children: [(pinningActive ? [{
564
+ id: 'pinned',
565
+ headers: [...table.getStartLeafHeaders(), ...table.getCenterLeafHeaders(), ...table.getEndLeafHeaders()]
566
+ }] : table.getHeaderGroups()).map(headerGroup => /*#__PURE__*/_jsx(Table.Row, {
295
567
  children: headerGroup.headers.map(header => {
568
+ const pin = pinMetaFor(header.column.id, columnPinning);
296
569
  if (header.id === SELECT_COLUMN_ID) {
297
570
  return /*#__PURE__*/_jsx(Table.Head, {
298
571
  align: "center",
299
- className: dataGridSelectHeadVariants(),
572
+ className: cn(dataGridSelectHeadVariants(), pinnedClassName(pin, true)),
573
+ style: mergePinnedStyle(undefined, pin, pinnedOffsets, header.id, true),
300
574
  children: /*#__PURE__*/_jsx(Checkbox, {
301
575
  value: "select-all",
302
576
  isChecked: headerSelectState.checked,
@@ -307,10 +581,17 @@ function DataGridInner(props) {
307
581
  })
308
582
  }, header.id);
309
583
  }
584
+ if (header.id === DETAIL_PANEL_TOGGLE_ID) {
585
+ return /*#__PURE__*/_jsx(Table.Cell, {
586
+ className: cn(dataGridHeadVariants(), dataGridDetailToggleCellVariants(), pinnedClassName(pin, true)),
587
+ style: mergePinnedStyle(undefined, pin, pinnedOffsets, header.id, true)
588
+ }, header.id);
589
+ }
310
590
  const col = colByField.get(header.column.id);
591
+ const isTreeColumn = header.column.id === treeField;
311
592
  const sorted = header.column.getIsSorted();
312
593
  const canSort = !disableColumnSorting && header.column.getCanSort();
313
- const headerAlign = normalizeGridAlignment(col?.headerAlign ?? col?.align);
594
+ const headerAlign = resolveColumnHeaderAlign(col);
314
595
  const headerName = col?.headerName ?? header.column.id;
315
596
  const SortIcon = sorted === 'asc' ? KeyboardArrowUp : KeyboardArrowDown;
316
597
  const sortButton = canSort ? /*#__PURE__*/_jsx(IconButton, {
@@ -328,50 +609,71 @@ function DataGridInner(props) {
328
609
  sorted: sorted !== false
329
610
  })
330
611
  }) : null;
612
+ const headerLabel = /*#__PURE__*/_jsxs(_Fragment, {
613
+ children: [headerAlign === 'end' ? sortButton : null, /*#__PURE__*/_jsx(Text, {
614
+ numberOfLines: 1,
615
+ className: dataGridHeaderLabelVariants(),
616
+ children: col?.renderHeader ? col.renderHeader() : headerName
617
+ }), headerAlign === 'end' ? null : sortButton]
618
+ });
331
619
  return /*#__PURE__*/_jsx(Table.Head, {
332
620
  align: headerAlign,
333
- className: dataGridHeadVariants(),
334
- style: cellStyle(col, columnWidths.get(header.column.id)),
621
+ className: cn(dataGridHeadVariants(), pinnedClassName(pin, true)),
622
+ style: mergePinnedStyle(cellStyle(col, columnWidths.get(header.column.id)), pin, pinnedOffsets, header.column.id, true),
335
623
  ...(Platform.OS === 'web' ? {
336
624
  title: col?.renderHeader ? undefined : headerName,
337
625
  ...(canSort ? {
338
626
  'aria-sort': sorted === 'asc' ? 'ascending' : sorted === 'desc' ? 'descending' : 'none'
339
627
  } : {})
340
628
  } : {}),
341
- children: /*#__PURE__*/_jsxs(View, {
629
+ children: isTreeColumn ? /*#__PURE__*/_jsxs(View, {
630
+ className: dataGridTreeCellInnerVariants(),
631
+ children: [/*#__PURE__*/_jsx(View, {
632
+ className: dataGridTreeToggleSlotVariants()
633
+ }), treeCheckbox ? /*#__PURE__*/_jsx(Checkbox, {
634
+ value: "select-all",
635
+ isChecked: headerSelectState.checked,
636
+ isIndeterminate: headerSelectState.indeterminate,
637
+ onChange: () => tree?.toggleAllRowsSelected(),
638
+ accessibilityLabel: "Select all",
639
+ "aria-label": "Select all"
640
+ }) : null, /*#__PURE__*/_jsx(View, {
641
+ className: cn(dataGridHeaderCellInnerVariants({
642
+ align: headerAlign
643
+ }), 'flex-1'),
644
+ children: headerLabel
645
+ })]
646
+ }) : /*#__PURE__*/_jsx(View, {
342
647
  className: dataGridHeaderCellInnerVariants({
343
648
  align: headerAlign,
344
649
  fitToColumn: Platform.OS === 'web' && columnWidths.has(header.column.id)
345
650
  }),
346
- children: [headerAlign === 'end' ? sortButton : null, /*#__PURE__*/_jsx(Text, {
347
- numberOfLines: 1,
348
- className: dataGridHeaderLabelVariants(),
349
- children: col?.renderHeader ? col.renderHeader() : headerName
350
- }), headerAlign === 'end' ? null : sortButton]
651
+ children: headerLabel
351
652
  })
352
653
  }, header.id);
353
654
  })
354
655
  }, headerGroup.id)), headerFilters ? /*#__PURE__*/_jsx(Table.Row, {
355
- children: table.getAllLeafColumns().map(column => {
356
- if (column.id === SELECT_COLUMN_ID) {
656
+ children: (pinningActive ? [...table.getStartVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns(), ...table.getEndVisibleLeafColumns()] : table.getVisibleLeafColumns()).map(column => {
657
+ const pin = pinMetaFor(column.id, columnPinning);
658
+ if (column.id === SELECT_COLUMN_ID || column.id === DETAIL_PANEL_TOGGLE_ID) {
357
659
  return /*#__PURE__*/_jsx(Table.Cell, {
358
660
  align: "center",
359
- className: dataGridSelectHeadVariants()
661
+ className: cn(dataGridSelectHeadVariants(), column.id === DETAIL_PANEL_TOGGLE_ID && 'w-12 px-2', pinnedClassName(pin, true)),
662
+ style: mergePinnedStyle(undefined, pin, pinnedOffsets, column.id, true)
360
663
  }, column.id);
361
664
  }
362
665
  const col = colByField.get(column.id);
363
- const headerAlign = col?.headerAlign ?? col?.align;
364
666
  if (col?.filterable === false) {
365
667
  return /*#__PURE__*/_jsx(Table.Head, {
366
- align: normalizeGridAlignment(headerAlign),
367
- className: dataGridHeadVariants(),
368
- style: cellStyle(col, columnWidths.get(column.id))
668
+ align: resolveColumnHeaderAlign(col),
669
+ className: cn(dataGridHeadVariants(), pinnedClassName(pin, true)),
670
+ style: mergePinnedStyle(cellStyle(col, columnWidths.get(column.id)), pin, pinnedOffsets, column.id, true)
369
671
  }, column.id);
370
672
  }
371
673
  return /*#__PURE__*/_jsx(Table.Head, {
372
- align: normalizeGridAlignment(headerAlign),
373
- className: dataGridHeadVariants(),
374
- style: cellStyle(col, columnWidths.get(column.id)),
674
+ align: resolveColumnHeaderAlign(col),
675
+ className: cn(dataGridHeadVariants(), pinnedClassName(pin, true)),
676
+ style: mergePinnedStyle(cellStyle(col, columnWidths.get(column.id)), pin, pinnedOffsets, column.id, true),
375
677
  children: /*#__PURE__*/_jsx(Input, {
376
678
  size: "small",
377
679
  className: dataGridFilterInputVariants(),
@@ -388,18 +690,52 @@ function DataGridInner(props) {
388
690
  }), /*#__PURE__*/_jsx(Table.Body, {
389
691
  className: dataGridBodyVariants(),
390
692
  children: loading && loadingOverlay == null ? /*#__PURE__*/_jsx(DefaultLoadingRows, {
391
- columns: columns,
392
- checkboxSelection: checkboxSelection,
693
+ columns: visibleColumns,
694
+ leadingColumnIds: leadingColumnIds,
393
695
  rowCount: Math.min(resolvedPagination.pageSize, MAX_SKELETON_ROW_COUNT),
394
- columnWidths: columnWidths
395
- }) : isEmpty ? null : visibleRows.map(row => {
696
+ columnWidths: columnWidths,
697
+ orderedColumnIds: orderedLeafColumnIds,
698
+ pinning: columnPinning,
699
+ offsets: pinnedOffsets
700
+ }) : isEmpty ? null : visibleRows.flatMap(row => {
396
701
  const rowId = resolveRowId(row.original, getRowId);
397
- return /*#__PURE__*/_jsx(Table.Row, {
398
- children: row.getAllCells().map(cell => {
702
+ const cells = pinningActive ? [...row.getStartVisibleCells(), ...row.getCenterVisibleCells(), ...row.getEndVisibleCells()] : row.getVisibleCells();
703
+ const detailContent = getDetailPanelContent?.({
704
+ id: rowId,
705
+ row: row.original
706
+ });
707
+ const hasDetailPanel = detailContent != null;
708
+ const detailOpen = hasDetailPanel && resolvedDetailIds.has(rowId);
709
+ const treeLabel = treeActive ? [...getTreeDataPath(row.original)].reverse().join(', ') : '';
710
+ const dataRow = /*#__PURE__*/_jsx(Table.Row, {
711
+ className: detailOpen ? 'web:[&>*]:border-b-0' : undefined,
712
+ children: cells.map(cell => {
713
+ const pin = pinMetaFor(cell.column.id, columnPinning);
714
+ if (cell.column.id === DETAIL_PANEL_TOGGLE_ID) {
715
+ return /*#__PURE__*/_jsx(Table.Cell, {
716
+ align: "center",
717
+ className: cn(dataGridDetailToggleCellVariants(), pinnedClassName(pin, false)),
718
+ style: mergePinnedStyle(undefined, pin, pinnedOffsets, cell.column.id, false),
719
+ children: hasDetailPanel ? /*#__PURE__*/_jsx(IconButton, {
720
+ as: detailOpen ? KeyboardArrowDown : KeyboardArrowRight,
721
+ variant: "ghost",
722
+ color: "neutral",
723
+ size: "small",
724
+ iconClassName: detailOpen ? undefined : 'rtl:-scale-x-100',
725
+ accessibilityLabel: `${detailOpen ? 'Collapse' : 'Expand'} row ${String(rowId)}`,
726
+ accessibilityState: {
727
+ expanded: detailOpen
728
+ },
729
+ "aria-expanded": detailOpen,
730
+ onPress: () => toggleDetailPanel(rowId)
731
+ }) : null
732
+ }, cell.id);
733
+ }
399
734
  if (cell.column.id === SELECT_COLUMN_ID) {
400
735
  return /*#__PURE__*/_jsx(Table.Cell, {
401
736
  align: "center",
402
- className: dataGridSelectCellVariants(),
737
+ className: cn(dataGridSelectCellVariants(), pinnedClassName(pin, false)),
738
+ style: mergePinnedStyle(undefined, pin, pinnedOffsets, cell.column.id, false),
403
739
  children: /*#__PURE__*/_jsx(Checkbox, {
404
740
  value: String(rowId),
405
741
  isChecked: row.getIsSelected(),
@@ -417,21 +753,94 @@ function DataGridInner(props) {
417
753
  value,
418
754
  row: row.original,
419
755
  field: col.field,
420
- id: rowId
756
+ id: rowId,
757
+ col
421
758
  });
422
759
  } else if (col?.valueFormatter) {
423
760
  content = col.valueFormatter(value, row.original, col);
761
+ } else if (col?.type === 'boolean' && typeof value === 'boolean') {
762
+ content = /*#__PURE__*/_jsx(BooleanCell, {
763
+ value: value
764
+ });
424
765
  } else {
425
- content = defaultCellContent(value);
766
+ const typedText = getTypedCellText(col, value, row.original);
767
+ content = typedText !== undefined ? typedText : defaultCellContent(value);
768
+ }
769
+ if (tree && cell.column.id === treeField) {
770
+ const canExpand = row.subRows.length > 0;
771
+ const expanded = canExpand && tree.isRowExpanded(row.id);
772
+ const status = tree.selectionStatus(row.id);
773
+ content = /*#__PURE__*/_jsxs(View, {
774
+ className: dataGridTreeCellInnerVariants(),
775
+ style: {
776
+ paddingStart: row.depth * TREE_INDENT
777
+ },
778
+ children: [/*#__PURE__*/_jsx(View, {
779
+ className: dataGridTreeToggleSlotVariants(),
780
+ children: canExpand ? /*#__PURE__*/_jsx(IconButton, {
781
+ as: expanded ? KeyboardArrowDown : KeyboardArrowRight,
782
+ variant: "ghost",
783
+ color: "neutral",
784
+ size: "small",
785
+ iconClassName: expanded ? undefined : 'rtl:-scale-x-100',
786
+ accessibilityLabel: `${expanded ? 'Collapse' : 'Expand'} ${treeLabel}`,
787
+ accessibilityState: {
788
+ expanded
789
+ },
790
+ "aria-expanded": expanded,
791
+ onPress: () => tree.toggleRowExpanded(row.id)
792
+ }) : null
793
+ }), treeCheckbox ? /*#__PURE__*/_jsx(Checkbox, {
794
+ value: String(rowId),
795
+ isChecked: status === 'all',
796
+ isIndeterminate: status === 'some',
797
+ onChange: () => tree.toggleRowSelected(row),
798
+ accessibilityLabel: `Select ${treeLabel}`,
799
+ "aria-label": `Select ${treeLabel}`
800
+ }) : null, /*#__PURE__*/_jsx(View, {
801
+ className: dataGridTreeContentVariants(),
802
+ children: typeof content === 'string' || typeof content === 'number' ? /*#__PURE__*/_jsx(Text, {
803
+ numberOfLines: 1,
804
+ children: content
805
+ }) : content
806
+ })]
807
+ });
426
808
  }
809
+ const align = resolveColumnAlign(col);
810
+ const cellText = !col?.renderCell && (typeof content === 'string' || typeof content === 'number') ? String(content) : undefined;
427
811
  return /*#__PURE__*/_jsx(Table.Cell, {
428
- align: normalizeGridAlignment(col?.align),
429
- className: dataGridCellVariants(),
430
- style: cellStyle(col, columnWidths.get(cell.column.id)),
431
- children: content
812
+ align: align,
813
+ ...(Platform.OS === 'web' && cellText ? {
814
+ title: cellText
815
+ } : {}),
816
+ className: cn(dataGridCellVariants(), pinnedClassName(pin, false)),
817
+ style: mergePinnedStyle(cellStyle(col, columnWidths.get(cell.column.id)), pin, pinnedOffsets, cell.column.id, false),
818
+ children: cellText !== undefined ? /*#__PURE__*/_jsx(Text, {
819
+ numberOfLines: 1,
820
+ className: dataGridCellTextVariants({
821
+ align,
822
+ fitToColumn: Platform.OS === 'web' && columnWidths.has(cell.column.id)
823
+ }),
824
+ children: cellText
825
+ }) : content
432
826
  }, cell.id);
433
827
  })
434
828
  }, row.id);
829
+ if (!detailOpen) {
830
+ return [dataRow];
831
+ }
832
+ return [dataRow, /*#__PURE__*/_jsx(Table.Row, {
833
+ className: "web:hover:bg-transparent",
834
+ testID: `data-grid-detail-panel-${String(rowId)}`,
835
+ children: /*#__PURE__*/_jsx(Table.Cell, {
836
+ colSpan: leafColumnCount,
837
+ className: dataGridDetailPanelCellVariants(),
838
+ children: /*#__PURE__*/_jsx(View, {
839
+ style: detailPanelContentStyle,
840
+ children: detailContent
841
+ })
842
+ })
843
+ }, `${row.id}:detail`)];
435
844
  })
436
845
  })]
437
846
  }), isEmpty ? /*#__PURE__*/_jsx(View, {