@dashforge/tw 0.8.0-beta → 0.9.0-beta

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 (183) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/COVERAGE.md +63 -0
  3. package/LICENSE +21 -0
  4. package/PERFORMANCE.md +59 -0
  5. package/REFINEMENT-NOTES.md +50 -0
  6. package/dist/index.esm.js +235 -160
  7. package/dist/src/components/DataGrid/DataGrid.d.ts.map +1 -1
  8. package/dist/src/components/DataGrid/filters/ColumnFilters.d.ts.map +1 -1
  9. package/dist/src/components/DataGrid/resize/useColumnResize.d.ts +7 -0
  10. package/dist/src/components/DataGrid/resize/useColumnResize.d.ts.map +1 -1
  11. package/dist/src/components/DataGrid/visibility/ColumnVisibilityMenu.d.ts +44 -0
  12. package/dist/src/components/DataGrid/visibility/ColumnVisibilityMenu.d.ts.map +1 -0
  13. package/dist/src/components/Dialog/Dialog.d.ts.map +1 -1
  14. package/dist/src/components/Table/Table.d.ts.map +1 -1
  15. package/dist/src/components/Table/cells/RenderChip.d.ts.map +1 -1
  16. package/dist/src/components/Table/table.types.d.ts +29 -6
  17. package/dist/src/components/Table/table.types.d.ts.map +1 -1
  18. package/dist/src/components/Typography/typography.variants.d.ts.map +1 -1
  19. package/eslint.config.mjs +16 -1
  20. package/package.json +11 -8
  21. package/src/components/Breadcrumbs/Breadcrumbs.perf.test.tsx +5 -2
  22. package/src/components/DataGrid/DataGrid.perf.test.tsx +114 -0
  23. package/src/components/DataGrid/DataGrid.test.tsx +253 -17
  24. package/src/components/DataGrid/DataGrid.tsx +107 -24
  25. package/src/components/DataGrid/filters/ColumnFilters.test.tsx +330 -0
  26. package/src/components/DataGrid/filters/ColumnFilters.tsx +26 -2
  27. package/src/components/DataGrid/reorder/useColumnReorder.test.ts +95 -3
  28. package/src/components/DataGrid/resize/useColumnResize.test.ts +144 -0
  29. package/src/components/DataGrid/resize/useColumnResize.ts +30 -1
  30. package/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx +186 -0
  31. package/src/components/Dialog/Dialog.tsx +9 -0
  32. package/src/components/Table/Table.perf.test.tsx +81 -0
  33. package/src/components/Table/Table.test.tsx +72 -1
  34. package/src/components/Table/Table.tsx +41 -8
  35. package/src/components/Table/cells/RenderChip.tsx +6 -9
  36. package/src/components/Table/cells/cells.test.tsx +247 -0
  37. package/src/components/Table/table.types.ts +29 -6
  38. package/src/components/Typography/Typography.test.tsx +15 -0
  39. package/src/components/Typography/typography.variants.ts +14 -1
  40. package/test-output/vitest/coverage/base.css +224 -0
  41. package/test-output/vitest/coverage/block-navigation.js +87 -0
  42. package/test-output/vitest/coverage/clover.xml +2418 -0
  43. package/test-output/vitest/coverage/coverage-final.json +89 -0
  44. package/test-output/vitest/coverage/favicon.png +0 -0
  45. package/test-output/vitest/coverage/index.html +746 -0
  46. package/test-output/vitest/coverage/prettify.css +1 -0
  47. package/test-output/vitest/coverage/prettify.js +2 -0
  48. package/test-output/vitest/coverage/sort-arrow-sprite.png +0 -0
  49. package/test-output/vitest/coverage/sorter.js +210 -0
  50. package/test-output/vitest/coverage/src/components/Accordion/Accordion.tsx.html +376 -0
  51. package/test-output/vitest/coverage/src/components/Accordion/accordion.variants.ts.html +181 -0
  52. package/test-output/vitest/coverage/src/components/Accordion/index.html +131 -0
  53. package/test-output/vitest/coverage/src/components/AppShell/AppShell.tsx.html +802 -0
  54. package/test-output/vitest/coverage/src/components/AppShell/appShell.variants.ts.html +247 -0
  55. package/test-output/vitest/coverage/src/components/AppShell/index.html +131 -0
  56. package/test-output/vitest/coverage/src/components/AspectRatio/AspectRatio.tsx.html +304 -0
  57. package/test-output/vitest/coverage/src/components/AspectRatio/index.html +116 -0
  58. package/test-output/vitest/coverage/src/components/Autocomplete/Autocomplete.tsx.html +3292 -0
  59. package/test-output/vitest/coverage/src/components/Autocomplete/autocomplete.variants.ts.html +508 -0
  60. package/test-output/vitest/coverage/src/components/Autocomplete/index.html +131 -0
  61. package/test-output/vitest/coverage/src/components/Box/Box.tsx.html +334 -0
  62. package/test-output/vitest/coverage/src/components/Box/box.variants.ts.html +775 -0
  63. package/test-output/vitest/coverage/src/components/Box/index.html +131 -0
  64. package/test-output/vitest/coverage/src/components/Breadcrumbs/Breadcrumbs.tsx.html +694 -0
  65. package/test-output/vitest/coverage/src/components/Breadcrumbs/breadcrumbs.variants.ts.html +247 -0
  66. package/test-output/vitest/coverage/src/components/Breadcrumbs/index.html +131 -0
  67. package/test-output/vitest/coverage/src/components/Button/Button.tsx.html +535 -0
  68. package/test-output/vitest/coverage/src/components/Button/button.variants.ts.html +562 -0
  69. package/test-output/vitest/coverage/src/components/Button/index.html +131 -0
  70. package/test-output/vitest/coverage/src/components/Checkbox/Checkbox.tsx.html +943 -0
  71. package/test-output/vitest/coverage/src/components/Checkbox/checkbox.variants.ts.html +289 -0
  72. package/test-output/vitest/coverage/src/components/Checkbox/index.html +131 -0
  73. package/test-output/vitest/coverage/src/components/ConfirmDialog/ConfirmDialog.tsx.html +841 -0
  74. package/test-output/vitest/coverage/src/components/ConfirmDialog/confirmDialog.variants.ts.html +313 -0
  75. package/test-output/vitest/coverage/src/components/ConfirmDialog/index.html +131 -0
  76. package/test-output/vitest/coverage/src/components/Container/Container.tsx.html +307 -0
  77. package/test-output/vitest/coverage/src/components/Container/container.variants.ts.html +328 -0
  78. package/test-output/vitest/coverage/src/components/Container/index.html +131 -0
  79. package/test-output/vitest/coverage/src/components/DataGrid/DataGrid.tsx.html +3937 -0
  80. package/test-output/vitest/coverage/src/components/DataGrid/dataGrid.variants.ts.html +541 -0
  81. package/test-output/vitest/coverage/src/components/DataGrid/filters/ColumnFilters.tsx.html +1453 -0
  82. package/test-output/vitest/coverage/src/components/DataGrid/filters/index.html +116 -0
  83. package/test-output/vitest/coverage/src/components/DataGrid/index.html +131 -0
  84. package/test-output/vitest/coverage/src/components/DataGrid/reorder/index.html +116 -0
  85. package/test-output/vitest/coverage/src/components/DataGrid/reorder/useColumnReorder.ts.html +517 -0
  86. package/test-output/vitest/coverage/src/components/DataGrid/resize/index.html +116 -0
  87. package/test-output/vitest/coverage/src/components/DataGrid/resize/useColumnResize.ts.html +490 -0
  88. package/test-output/vitest/coverage/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx.html +592 -0
  89. package/test-output/vitest/coverage/src/components/DataGrid/visibility/index.html +116 -0
  90. package/test-output/vitest/coverage/src/components/DateTimePicker/DateTimePicker.tsx.html +1042 -0
  91. package/test-output/vitest/coverage/src/components/DateTimePicker/dateTimePicker.variants.ts.html +337 -0
  92. package/test-output/vitest/coverage/src/components/DateTimePicker/index.html +131 -0
  93. package/test-output/vitest/coverage/src/components/Dialog/Dialog.tsx.html +391 -0
  94. package/test-output/vitest/coverage/src/components/Dialog/dialog.variants.ts.html +283 -0
  95. package/test-output/vitest/coverage/src/components/Dialog/index.html +131 -0
  96. package/test-output/vitest/coverage/src/components/Divider/Divider.tsx.html +505 -0
  97. package/test-output/vitest/coverage/src/components/Divider/divider.variants.ts.html +433 -0
  98. package/test-output/vitest/coverage/src/components/Divider/index.html +131 -0
  99. package/test-output/vitest/coverage/src/components/Grid/Grid.tsx.html +529 -0
  100. package/test-output/vitest/coverage/src/components/Grid/grid.variants.ts.html +484 -0
  101. package/test-output/vitest/coverage/src/components/Grid/index.html +131 -0
  102. package/test-output/vitest/coverage/src/components/LeftNav/LeftNav.tsx.html +1075 -0
  103. package/test-output/vitest/coverage/src/components/LeftNav/index.html +131 -0
  104. package/test-output/vitest/coverage/src/components/LeftNav/leftNav.variants.ts.html +406 -0
  105. package/test-output/vitest/coverage/src/components/NumberField/NumberField.tsx.html +1048 -0
  106. package/test-output/vitest/coverage/src/components/NumberField/index.html +131 -0
  107. package/test-output/vitest/coverage/src/components/NumberField/numberField.variants.ts.html +367 -0
  108. package/test-output/vitest/coverage/src/components/OTPField/OTPField.tsx.html +835 -0
  109. package/test-output/vitest/coverage/src/components/OTPField/index.html +131 -0
  110. package/test-output/vitest/coverage/src/components/OTPField/otpField.variants.ts.html +301 -0
  111. package/test-output/vitest/coverage/src/components/Pagination/Pagination.tsx.html +916 -0
  112. package/test-output/vitest/coverage/src/components/Pagination/index.html +146 -0
  113. package/test-output/vitest/coverage/src/components/Pagination/pagination.helpers.ts.html +391 -0
  114. package/test-output/vitest/coverage/src/components/Pagination/pagination.variants.ts.html +436 -0
  115. package/test-output/vitest/coverage/src/components/Popover/Popover.tsx.html +250 -0
  116. package/test-output/vitest/coverage/src/components/Popover/index.html +131 -0
  117. package/test-output/vitest/coverage/src/components/Popover/popover.variants.ts.html +157 -0
  118. package/test-output/vitest/coverage/src/components/RadioGroup/RadioGroup.tsx.html +934 -0
  119. package/test-output/vitest/coverage/src/components/RadioGroup/index.html +131 -0
  120. package/test-output/vitest/coverage/src/components/RadioGroup/radioGroup.variants.ts.html +346 -0
  121. package/test-output/vitest/coverage/src/components/Skeleton/Skeleton.tsx.html +232 -0
  122. package/test-output/vitest/coverage/src/components/Skeleton/index.html +131 -0
  123. package/test-output/vitest/coverage/src/components/Skeleton/skeleton.variants.ts.html +346 -0
  124. package/test-output/vitest/coverage/src/components/Snackbar/Snackbar.tsx.html +979 -0
  125. package/test-output/vitest/coverage/src/components/Snackbar/index.html +131 -0
  126. package/test-output/vitest/coverage/src/components/Snackbar/snackbar.variants.ts.html +307 -0
  127. package/test-output/vitest/coverage/src/components/Stack/Stack.tsx.html +430 -0
  128. package/test-output/vitest/coverage/src/components/Stack/index.html +131 -0
  129. package/test-output/vitest/coverage/src/components/Stack/stack.variants.ts.html +325 -0
  130. package/test-output/vitest/coverage/src/components/Switch/Switch.tsx.html +559 -0
  131. package/test-output/vitest/coverage/src/components/Switch/index.html +131 -0
  132. package/test-output/vitest/coverage/src/components/Switch/switch.variants.ts.html +295 -0
  133. package/test-output/vitest/coverage/src/components/Table/Table.tsx.html +2677 -0
  134. package/test-output/vitest/coverage/src/components/Table/cells/RenderButton.tsx.html +154 -0
  135. package/test-output/vitest/coverage/src/components/Table/cells/RenderChip.tsx.html +385 -0
  136. package/test-output/vitest/coverage/src/components/Table/cells/RenderText.tsx.html +196 -0
  137. package/test-output/vitest/coverage/src/components/Table/cells/RenderTwoLine.tsx.html +187 -0
  138. package/test-output/vitest/coverage/src/components/Table/cells/RowActionsMenu.tsx.html +526 -0
  139. package/test-output/vitest/coverage/src/components/Table/cells/index.html +191 -0
  140. package/test-output/vitest/coverage/src/components/Table/cells/index.ts.html +127 -0
  141. package/test-output/vitest/coverage/src/components/Table/index.html +131 -0
  142. package/test-output/vitest/coverage/src/components/Table/table.variants.ts.html +706 -0
  143. package/test-output/vitest/coverage/src/components/Tabs/Tabs.tsx.html +283 -0
  144. package/test-output/vitest/coverage/src/components/Tabs/index.html +131 -0
  145. package/test-output/vitest/coverage/src/components/Tabs/tabs.variants.ts.html +292 -0
  146. package/test-output/vitest/coverage/src/components/TextField/TextField.tsx.html +820 -0
  147. package/test-output/vitest/coverage/src/components/TextField/index.html +131 -0
  148. package/test-output/vitest/coverage/src/components/TextField/textField.variants.ts.html +400 -0
  149. package/test-output/vitest/coverage/src/components/Textarea/Textarea.tsx.html +655 -0
  150. package/test-output/vitest/coverage/src/components/Textarea/index.html +131 -0
  151. package/test-output/vitest/coverage/src/components/Textarea/textarea.variants.ts.html +340 -0
  152. package/test-output/vitest/coverage/src/components/Tooltip/Tooltip.tsx.html +295 -0
  153. package/test-output/vitest/coverage/src/components/Tooltip/index.html +131 -0
  154. package/test-output/vitest/coverage/src/components/Tooltip/tooltip.variants.ts.html +169 -0
  155. package/test-output/vitest/coverage/src/components/TopBar/TopBar.tsx.html +283 -0
  156. package/test-output/vitest/coverage/src/components/TopBar/index.html +131 -0
  157. package/test-output/vitest/coverage/src/components/TopBar/topBar.variants.ts.html +199 -0
  158. package/test-output/vitest/coverage/src/components/Typography/Typography.tsx.html +421 -0
  159. package/test-output/vitest/coverage/src/components/Typography/index.html +131 -0
  160. package/test-output/vitest/coverage/src/components/Typography/typography.variants.ts.html +436 -0
  161. package/test-output/vitest/coverage/src/components/VisuallyHidden/VisuallyHidden.tsx.html +262 -0
  162. package/test-output/vitest/coverage/src/components/VisuallyHidden/index.html +116 -0
  163. package/test-output/vitest/coverage/src/components/_shared/data/getNestedValue.ts.html +181 -0
  164. package/test-output/vitest/coverage/src/components/_shared/data/index.html +236 -0
  165. package/test-output/vitest/coverage/src/components/_shared/data/useColumnAutoDetect.ts.html +385 -0
  166. package/test-output/vitest/coverage/src/components/_shared/data/useControllableState.ts.html +229 -0
  167. package/test-output/vitest/coverage/src/components/_shared/data/useDebouncedValue.ts.html +157 -0
  168. package/test-output/vitest/coverage/src/components/_shared/data/useTableFilter.ts.html +439 -0
  169. package/test-output/vitest/coverage/src/components/_shared/data/useTableSearch.ts.html +283 -0
  170. package/test-output/vitest/coverage/src/components/_shared/data/useTableSelection.ts.html +385 -0
  171. package/test-output/vitest/coverage/src/components/_shared/data/useTableSort.ts.html +508 -0
  172. package/test-output/vitest/coverage/src/components/_shared/data/useVirtualizer.ts.html +682 -0
  173. package/test-output/vitest/coverage/src/components/_shared/index.html +116 -0
  174. package/test-output/vitest/coverage/src/components/_shared/resolveValidationState.ts.html +265 -0
  175. package/test-output/vitest/coverage/src/hooks/index.html +116 -0
  176. package/test-output/vitest/coverage/src/hooks/useAccessState.ts.html +328 -0
  177. package/test-output/vitest/coverage/src/index.html +116 -0
  178. package/test-output/vitest/coverage/src/index.ts.html +1153 -0
  179. package/test-output/vitest/coverage/src/utils/cn.ts.html +172 -0
  180. package/test-output/vitest/coverage/src/utils/index.html +116 -0
  181. package/dist/src/components/DataGrid/visibility/ColumnVisibilityDialog.d.ts +0 -33
  182. package/dist/src/components/DataGrid/visibility/ColumnVisibilityDialog.d.ts.map +0 -1
  183. package/src/components/DataGrid/visibility/ColumnVisibilityDialog.tsx +0 -200
package/dist/index.esm.js CHANGED
@@ -5285,6 +5285,15 @@ const SnackbarContext = /*#__PURE__*/ createContext(null);
5285
5285
  * has set its own color (e.g. `<Box variant="solid" color="primary">`
5286
5286
  * paints white text).
5287
5287
  */ color: {
5288
+ // `inherit` is the explicit escape hatch — use it on a
5289
+ // `<Typography>` inside a coloured surface (e.g.
5290
+ // `<Box variant="solid" color="primary">` paints white text)
5291
+ // so the text picks up the surface colour. It is NO LONGER the
5292
+ // default: a bare `<Typography>` would otherwise inherit the
5293
+ // consuming app's arbitrary root colour (often OS-`prefers-
5294
+ // color-scheme` driven), which diverges from the Dashforge
5295
+ // `data-dash-tw-theme` mode and breaks colour consistency in
5296
+ // dark mode. The default is now `neutral` — see `defaultVariants`.
5288
5297
  inherit: 'text-inherit',
5289
5298
  primary: 'text-primary-700 dark:text-primary-400',
5290
5299
  secondary: 'text-secondary-700 dark:text-secondary-400',
@@ -5337,7 +5346,11 @@ const SnackbarContext = /*#__PURE__*/ createContext(null);
5337
5346
  },
5338
5347
  defaultVariants: {
5339
5348
  variant: 'body1',
5340
- color: 'inherit',
5349
+ // `neutral` (not `inherit`): a bare `<Typography>` emits
5350
+ // `text-neutral-900`, which auto-inverts via the dashforgePreset()
5351
+ // CSS-var swap and follows the Dashforge mode. Pass
5352
+ // `color="inherit"` explicitly inside a coloured surface.
5353
+ color: 'neutral',
5341
5354
  align: 'left'
5342
5355
  }
5343
5356
  });
@@ -6915,8 +6928,11 @@ VisuallyHidden.displayName = 'VisuallyHidden';
6915
6928
  jsx(RadixDialog.Overlay, {
6916
6929
  className: cn(v.overlay(), slotProps == null ? void 0 : (_slotProps_overlay = slotProps.overlay) == null ? void 0 : _slotProps_overlay.className)
6917
6930
  }),
6918
- jsxs(RadixDialog.Content, {
6919
- className: cn(v.content(), sx, slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
6931
+ jsxs(RadixDialog.Content, _extends({
6932
+ className: cn(v.content(), sx, slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className)
6933
+ }, description == null ? {
6934
+ 'aria-describedby': undefined
6935
+ } : {}, {
6920
6936
  onPointerDownOutside: (event)=>{
6921
6937
  if (disableBackdropClose) event.preventDefault();
6922
6938
  },
@@ -6955,7 +6971,7 @@ VisuallyHidden.displayName = 'VisuallyHidden';
6955
6971
  })
6956
6972
  })
6957
6973
  ]
6958
- })
6974
+ }))
6959
6975
  ]
6960
6976
  })
6961
6977
  });
@@ -8650,6 +8666,7 @@ function inferType(value) {
8650
8666
  const DEFAULT_LABELS$1 = {
8651
8667
  searchPlaceholder: 'Search...',
8652
8668
  noData: 'No data',
8669
+ noResults: 'No matching results',
8653
8670
  loading: 'Loading…',
8654
8671
  ariaSortNone: 'Not sorted. Click to sort ascending.',
8655
8672
  ariaSortAscending: 'Sorted ascending. Click to sort descending.',
@@ -8675,11 +8692,8 @@ const DEFAULT_LABELS$1 = {
8675
8692
  densityComfortable: 'Comfortable',
8676
8693
  densitySpacious: 'Spacious',
8677
8694
  columnsButton: 'Columns',
8678
- columnsTitle: 'Manage columns',
8679
- columnsDescription: 'Show or hide columns. Required columns cannot be toggled.',
8680
- columnsShowAll: 'Show all',
8681
- columnsHideAll: 'Hide all',
8682
- columnsDone: 'Done'
8695
+ columnsTitle: 'Toggle columns',
8696
+ columnsToggleAll: 'Toggle all columns'
8683
8697
  };
8684
8698
  const DEFAULT_GET_ROW_ID = (_row, index)=>String(index);
8685
8699
  /**
@@ -8708,6 +8722,26 @@ const DEFAULT_GET_ROW_ID = (_row, index)=>String(index);
8708
8722
  sortModel: sortModelProp, onSortChange, defaultSortModel, enableSearch = false, searchQuery: searchQueryProp, onSearchQueryChange, searchPlaceholder, searchDebounceMs = 200, filterModel: filterModelProp, onFilterChange, rowSelection = 'none', selectedRowIds: selectedRowIdsProp, onSelectionChange, bulkActions, expandable, rowActions, loading = false, loadingRowCount = 5, emptyState, stickyHeader = true, caption, showCaption = false, access: tableAccess, labels: labelsProp, variant, size, density, sx, slotProps } = props;
8709
8723
  const labels = _extends({}, DEFAULT_LABELS$1, labelsProp);
8710
8724
  const tableAccessState = useAccessState(tableAccess);
8725
+ // Dev-only guard: `getRowId` is optional (positional-index fallback)
8726
+ // but that fallback breaks row identity once rows reorder (sort) or
8727
+ // change presence (search / filter) — selection + expansion state
8728
+ // then jump to the wrong rows. Warn when it's omitted AND a feature
8729
+ // that relies on stable identity is active. Stripped in production.
8730
+ const getRowIdProvided = props.getRowId !== undefined;
8731
+ useEffect(()=>{
8732
+ if (process.env.NODE_ENV === 'production') return;
8733
+ if (getRowIdProvided) return;
8734
+ const identityMatters = rowSelection !== 'none' || expandable != null || enableSearch || cols.some((c)=>Boolean(c.sortable));
8735
+ if (identityMatters) {
8736
+ console.warn('[Dashforge Table] `getRowId` is not set — falling back to the ' + 'positional row index. With sort / search / selection / ' + 'expandable rows active, the index-based key breaks row ' + 'identity when rows reorder. Pass a stable resolver, e.g. ' + '`getRowId={(row) => row.id}`.');
8737
+ }
8738
+ }, [
8739
+ getRowIdProvided,
8740
+ rowSelection,
8741
+ expandable,
8742
+ enableSearch,
8743
+ cols
8744
+ ]);
8711
8745
  // ───── Controllable state machinery ─────
8712
8746
  const [sortModel, setSortModel] = useControllableState({
8713
8747
  controlledValue: sortModelProp,
@@ -8863,7 +8897,9 @@ const DEFAULT_GET_ROW_ID = (_row, index)=>String(index);
8863
8897
  }) : sortedRows.length === 0 ? renderEmptyState$1({
8864
8898
  totalColumnCount,
8865
8899
  emptyState,
8866
- fallback: labels.noData,
8900
+ // Distinguish a genuinely empty dataset from one
8901
+ // emptied by an active search / filter.
8902
+ fallback: rows.length > 0 && (debouncedSearchQuery.trim().length > 0 || filterModel.length > 0) ? labels.noResults : labels.noData,
8867
8903
  cellClass: cn(v.cell(), v.emptyState(), slotProps == null ? void 0 : (_slotProps_emptyState = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState.className)
8868
8904
  }) : sortedRows.map((row, idx)=>{
8869
8905
  var _slotProps_row, _slotProps_cell, _slotProps_cell1, _slotProps_selectionCell, _slotProps_cell2, _slotProps_expandToggleCell, _slotProps_cell3, _slotProps_rowActionsCell, _slotProps_expandedRow;
@@ -9085,6 +9121,10 @@ function handleSortClick$1(col, event, current, setSortModel) {
9085
9121
  }
9086
9122
  function renderLoadingRows$1(args) {
9087
9123
  const { count, visibleCols, showSelectionColumn, showExpandColumn, showRowActionsColumn, rowClass, cellClass } = args;
9124
+ // No explicit row height here (unlike DataGrid's loading rows, which
9125
+ // pin `rowHeight` for the virtualization math): Table is auto-height
9126
+ // by design. Skeleton rows inherit the same density padding via
9127
+ // `cellClass`, so they line up with real rows without a fixed height.
9088
9128
  return Array.from({
9089
9129
  length: count
9090
9130
  }).map((_, i)=>jsxs("tr", {
@@ -9326,15 +9366,12 @@ function SearchIcon$1(props) {
9326
9366
  color: 'secondary',
9327
9367
  class: 'bg-secondary-100 dark:bg-secondary-950 text-secondary-700 dark:text-secondary-300'
9328
9368
  },
9329
- // solid = full bg + light text
9330
- // solid neutral: bg + text both anchored to neutral palette
9331
- // (auto-inverts). `text-white` would not invert and would break
9332
- // contrast in light mode against a `bg-neutral-700` dark bg, so
9333
- // we stick to `text-neutral-50` (light text in light mode, dark
9334
- // in dark — wait, that's wrong too). Actually `text-neutral-50`
9335
- // auto-inverts: light text in light mode (against dark bg) is
9336
- // what we want; in dark mode `bg-neutral-700` becomes light AND
9337
- // `text-neutral-50` becomes dark — contrast preserved.
9369
+ // solid = full bg + contrasting text.
9370
+ // solid neutral: both `bg-neutral-700` and `text-neutral-50` sit
9371
+ // on the neutral palette, so they auto-invert together via the
9372
+ // CSS-var swap — bg/text contrast is preserved in BOTH modes.
9373
+ // (`text-white` is deliberately NOT used here: white does not
9374
+ // auto-invert, which would flip the contrast in dark mode.)
9338
9375
  {
9339
9376
  variant: 'solid',
9340
9377
  color: 'neutral',
@@ -9865,6 +9902,17 @@ function setFilter(model, field, next) {
9865
9902
  next
9866
9903
  ];
9867
9904
  }
9905
+ /**
9906
+ * Shared `onKeyDown` for filter inputs — pressing Enter commits the
9907
+ * filter (equivalent to clicking Apply). Without this the user has to
9908
+ * leave the keyboard and click the button, which reads as broken for
9909
+ * a single-field text filter.
9910
+ */ function onEnterApply(e, apply) {
9911
+ if (e.key === 'Enter') {
9912
+ e.preventDefault();
9913
+ apply();
9914
+ }
9915
+ }
9868
9916
  const DEFAULT_FILTER_LABELS = {
9869
9917
  filterColumn: 'Filter',
9870
9918
  filterApply: 'Apply',
@@ -9950,6 +9998,11 @@ function FilterPanel(props) {
9950
9998
  function TextFilter(props) {
9951
9999
  const { field, current, onCommit, labels } = props;
9952
10000
  const [value, setValue] = useState(typeof (current == null ? void 0 : current.value) === 'string' ? current.value : '');
10001
+ const apply = ()=>onCommit(value.trim() ? {
10002
+ field,
10003
+ op: 'contains',
10004
+ value
10005
+ } : null);
9953
10006
  return jsxs("div", {
9954
10007
  className: "flex flex-col gap-2 min-w-[200px]",
9955
10008
  children: [
@@ -9957,16 +10010,13 @@ function TextFilter(props) {
9957
10010
  type: "text",
9958
10011
  value: value,
9959
10012
  onChange: (e)=>setValue(e.target.value),
10013
+ onKeyDown: (e)=>onEnterApply(e, apply),
9960
10014
  placeholder: "\u2026",
9961
10015
  autoFocus: true,
9962
10016
  className: "rounded-md border border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
9963
10017
  }),
9964
10018
  jsx(FilterActions, {
9965
- onApply: ()=>onCommit(value.trim() ? {
9966
- field,
9967
- op: 'contains',
9968
- value
9969
- } : null),
10019
+ onApply: apply,
9970
10020
  onClear: ()=>{
9971
10021
  setValue('');
9972
10022
  onCommit(null);
@@ -10020,6 +10070,7 @@ function NumberRangeFilter(props) {
10020
10070
  type: "number",
10021
10071
  value: min,
10022
10072
  onChange: (e)=>setMin(e.target.value),
10073
+ onKeyDown: (e)=>onEnterApply(e, apply),
10023
10074
  autoFocus: true,
10024
10075
  className: "rounded-md border border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
10025
10076
  })
@@ -10035,6 +10086,7 @@ function NumberRangeFilter(props) {
10035
10086
  type: "number",
10036
10087
  value: max,
10037
10088
  onChange: (e)=>setMax(e.target.value),
10089
+ onKeyDown: (e)=>onEnterApply(e, apply),
10038
10090
  className: "rounded-md border border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
10039
10091
  })
10040
10092
  ]
@@ -10143,6 +10195,7 @@ function DateRangeFilter(props) {
10143
10195
  type: "date",
10144
10196
  value: from,
10145
10197
  onChange: (e)=>setFrom(e.target.value),
10198
+ onKeyDown: (e)=>onEnterApply(e, apply),
10146
10199
  autoFocus: true,
10147
10200
  className: "rounded-md border border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
10148
10201
  })
@@ -10158,6 +10211,7 @@ function DateRangeFilter(props) {
10158
10211
  type: "date",
10159
10212
  value: to,
10160
10213
  onChange: (e)=>setTo(e.target.value),
10214
+ onKeyDown: (e)=>onEnterApply(e, apply),
10161
10215
  className: "rounded-md border border-neutral-300 bg-neutral-50 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
10162
10216
  })
10163
10217
  ]
@@ -10216,11 +10270,8 @@ function FilterIcon() {
10216
10270
 
10217
10271
  const DEFAULT_VISIBILITY_LABELS = {
10218
10272
  columnsButton: 'Columns',
10219
- columnsTitle: 'Manage columns',
10220
- columnsDescription: 'Show or hide columns. Required columns cannot be toggled.',
10221
- columnsShowAll: 'Show all',
10222
- columnsHideAll: 'Hide all',
10223
- columnsDone: 'Done'
10273
+ columnsTitle: 'Toggle columns',
10274
+ columnsToggleAll: 'Toggle all columns'
10224
10275
  };
10225
10276
  function ColumnVisibilityTrigger(props) {
10226
10277
  const { cols, hiddenColumns, onChange, disabled, labels: labelsProp } = props;
@@ -10230,118 +10281,87 @@ function ColumnVisibilityTrigger(props) {
10230
10281
  // defaults to `true` — a column is hideable unless explicitly opted
10231
10282
  // out with `hideable: false` (structurally required column).
10232
10283
  const hideableCols = cols.filter((c)=>c.hideable !== false);
10233
- return jsxs(Fragment$1, {
10234
- children: [
10235
- jsxs("button", {
10236
- type: "button",
10237
- onClick: ()=>setOpen(true),
10238
- disabled: disabled,
10239
- className: cn('inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md', 'text-sm text-neutral-700 hover:text-neutral-900', 'border border-neutral-300 bg-neutral-50 hover:bg-neutral-100', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500', 'transition-colors motion-reduce:transition-none', 'disabled:opacity-50 disabled:cursor-not-allowed'),
10240
- children: [
10241
- jsx(ColumnsIcon, {}),
10242
- jsx("span", {
10243
- children: labels.columnsButton
10244
- })
10245
- ]
10246
- }),
10247
- jsx(Dialog, {
10248
- open: open,
10249
- onOpenChange: setOpen,
10250
- title: labels.columnsTitle,
10251
- description: labels.columnsDescription,
10252
- size: "sm",
10253
- children: jsx(ColumnVisibilityBody, {
10254
- cols: hideableCols,
10255
- hiddenColumns: hiddenColumns,
10256
- onChange: onChange,
10257
- onDone: ()=>setOpen(false),
10258
- labels: labels
10259
- })
10260
- })
10261
- ]
10262
- });
10263
- }
10264
- // ───── Dialog body ─────
10265
- function ColumnVisibilityBody(props) {
10266
- const { cols, hiddenColumns, onChange, onDone, labels } = props;
10267
- // Local draft so the user can stage changes; commit on Done.
10268
- const [draft, setDraft] = useState(hiddenColumns);
10269
- // Re-sync when the dialog re-opens with a different external state.
10270
- useEffect(()=>{
10271
- setDraft(hiddenColumns);
10272
- }, [
10273
- hiddenColumns
10274
- ]);
10275
10284
  const toggle = (field)=>{
10276
- setDraft((prev)=>prev.includes(field) ? prev.filter((f)=>f !== field) : [
10277
- ...prev,
10278
- field
10279
- ]);
10285
+ onChange(hiddenColumns.includes(field) ? hiddenColumns.filter((f)=>f !== field) : [
10286
+ ...hiddenColumns,
10287
+ field
10288
+ ]);
10280
10289
  };
10281
- const showAll = ()=>setDraft([]);
10282
- const hideAll = ()=>setDraft(cols.map((c)=>c.field));
10283
- return jsxs("div", {
10284
- className: "flex flex-col gap-3",
10285
- children: [
10286
- jsxs("div", {
10287
- className: "flex items-center gap-2 pb-2 border-b border-neutral-200",
10288
- children: [
10289
- jsx("button", {
10290
- type: "button",
10291
- onClick: showAll,
10292
- className: "text-xs text-neutral-600 hover:text-neutral-900 underline-offset-2 hover:underline focus:outline-none focus-visible:underline",
10293
- children: labels.columnsShowAll
10294
- }),
10295
- jsx("span", {
10296
- className: "text-neutral-300",
10297
- children: "\u00B7"
10298
- }),
10299
- jsx("button", {
10300
- type: "button",
10301
- onClick: hideAll,
10302
- className: "text-xs text-neutral-600 hover:text-neutral-900 underline-offset-2 hover:underline focus:outline-none focus-visible:underline",
10303
- children: labels.columnsHideAll
10304
- })
10305
- ]
10306
- }),
10307
- jsx("ul", {
10308
- className: "flex flex-col gap-1.5 max-h-72 overflow-auto",
10309
- children: cols.map((col)=>{
10310
- const field = col.field;
10311
- const hidden = draft.includes(field);
10312
- const header = typeof col.header === 'function' ? col.header() : col.header;
10313
- return jsx("li", {
10314
- children: jsxs("label", {
10315
- className: "flex items-center gap-2 cursor-pointer py-1 px-1 rounded hover:bg-neutral-100",
10316
- children: [
10317
- jsx("input", {
10318
- type: "checkbox",
10319
- checked: !hidden,
10320
- onChange: ()=>toggle(field),
10321
- className: "cursor-pointer"
10322
- }),
10323
- jsx("span", {
10324
- className: "text-sm text-neutral-900",
10325
- children: header
10326
- })
10327
- ]
10290
+ // Tri-state master: checked = every hideable column visible,
10291
+ // unchecked = every one hidden, indeterminate = mixed.
10292
+ const allVisible = hideableCols.every((c)=>!hiddenColumns.includes(c.field));
10293
+ const allHidden = hideableCols.length > 0 && hideableCols.every((c)=>hiddenColumns.includes(c.field));
10294
+ const someHidden = !allVisible && !allHidden;
10295
+ // Standard select-all semantics: when everything is visible the
10296
+ // master hides all; otherwise it shows all.
10297
+ const toggleAll = ()=>{
10298
+ onChange(allVisible ? hideableCols.map((c)=>c.field) : []);
10299
+ };
10300
+ return jsx(Popover, {
10301
+ open: open,
10302
+ onOpenChange: setOpen,
10303
+ side: "bottom",
10304
+ align: "end",
10305
+ content: jsxs("div", {
10306
+ className: "flex flex-col gap-1 min-w-[220px]",
10307
+ children: [
10308
+ jsxs("div", {
10309
+ className: "flex items-center gap-2 px-1 pb-2 mb-1 border-b border-neutral-200",
10310
+ children: [
10311
+ jsx("input", {
10312
+ type: "checkbox",
10313
+ "aria-label": labels.columnsToggleAll,
10314
+ checked: allVisible,
10315
+ ref: (el)=>{
10316
+ if (el) el.indeterminate = someHidden;
10317
+ },
10318
+ onChange: toggleAll,
10319
+ className: "cursor-pointer"
10320
+ }),
10321
+ jsx("span", {
10322
+ className: "text-xs font-semibold text-neutral-700 uppercase tracking-wide",
10323
+ children: labels.columnsTitle
10328
10324
  })
10329
- }, field);
10325
+ ]
10326
+ }),
10327
+ jsx("ul", {
10328
+ className: "flex flex-col gap-0.5 max-h-72 overflow-auto",
10329
+ children: hideableCols.map((col)=>{
10330
+ const field = col.field;
10331
+ const hidden = hiddenColumns.includes(field);
10332
+ const header = typeof col.header === 'function' ? col.header() : col.header;
10333
+ return jsx("li", {
10334
+ children: jsxs("label", {
10335
+ className: "flex items-center gap-2 cursor-pointer py-1 px-1 rounded hover:bg-neutral-100",
10336
+ children: [
10337
+ jsx("input", {
10338
+ type: "checkbox",
10339
+ checked: !hidden,
10340
+ onChange: ()=>toggle(field),
10341
+ className: "cursor-pointer"
10342
+ }),
10343
+ jsx("span", {
10344
+ className: "text-sm text-neutral-900",
10345
+ children: header
10346
+ })
10347
+ ]
10348
+ })
10349
+ }, field);
10350
+ })
10330
10351
  })
10331
- }),
10332
- jsx("div", {
10333
- className: "flex justify-end gap-2 pt-2 border-t border-neutral-200",
10334
- children: jsx("button", {
10335
- type: "button",
10336
- onClick: ()=>{
10337
- onChange(draft);
10338
- onDone();
10339
- },
10340
- className: "text-sm bg-primary-500 text-white rounded-md hover:bg-primary-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 px-3 py-1.5",
10341
- children: labels.columnsDone
10352
+ ]
10353
+ }),
10354
+ children: jsxs("button", {
10355
+ type: "button",
10356
+ disabled: disabled,
10357
+ className: cn('inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md', 'text-sm text-neutral-700 hover:text-neutral-900', 'border border-neutral-300 bg-neutral-50 hover:bg-neutral-100', 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500', 'transition-colors motion-reduce:transition-none', 'disabled:opacity-50 disabled:cursor-not-allowed'),
10358
+ children: [
10359
+ jsx(ColumnsIcon, {}),
10360
+ jsx("span", {
10361
+ children: labels.columnsButton
10342
10362
  })
10343
- })
10344
- ]
10363
+ ]
10364
+ })
10345
10365
  });
10346
10366
  }
10347
10367
  // ───── Icon ─────
@@ -10429,8 +10449,21 @@ function useColumnResize(args) {
10429
10449
  minWidth,
10430
10450
  maxWidth
10431
10451
  ]);
10452
+ const nudge = useCallback((field, currentWidth, delta, clampMin, clampMax)=>{
10453
+ const effectiveMin = Math.max(minWidth, clampMin);
10454
+ const effectiveMax = Math.min(maxWidth, clampMax);
10455
+ const next = clamp(currentWidth + delta, effectiveMin, effectiveMax);
10456
+ onChange(_extends({}, widthsRef.current, {
10457
+ [field]: next
10458
+ }));
10459
+ }, [
10460
+ onChange,
10461
+ minWidth,
10462
+ maxWidth
10463
+ ]);
10432
10464
  return {
10433
- startResize
10465
+ startResize,
10466
+ nudge
10434
10467
  };
10435
10468
  }
10436
10469
  function clamp(n, min, max) {
@@ -10525,6 +10558,7 @@ function arraysEqual(a, b) {
10525
10558
  const DEFAULT_LABELS = {
10526
10559
  searchPlaceholder: 'Search...',
10527
10560
  noData: 'No data',
10561
+ noResults: 'No matching results',
10528
10562
  loading: 'Loading…',
10529
10563
  ariaSortNone: 'Not sorted. Click to sort ascending.',
10530
10564
  ariaSortAscending: 'Sorted ascending. Click to sort descending.',
@@ -10550,11 +10584,8 @@ const DEFAULT_LABELS = {
10550
10584
  densityComfortable: 'Comfortable',
10551
10585
  densitySpacious: 'Spacious',
10552
10586
  columnsButton: 'Columns',
10553
- columnsTitle: 'Manage columns',
10554
- columnsDescription: 'Show or hide columns. Required columns cannot be toggled.',
10555
- columnsShowAll: 'Show all',
10556
- columnsHideAll: 'Hide all',
10557
- columnsDone: 'Done'
10587
+ columnsTitle: 'Toggle columns',
10588
+ columnsToggleAll: 'Toggle all columns'
10558
10589
  };
10559
10590
  /**
10560
10591
  * Dashforge TW `<DataGrid>` — virtualized data table.
@@ -10642,7 +10673,7 @@ const DEFAULT_LABELS = {
10642
10673
  defaultValue: defaultColumnWidths,
10643
10674
  onChange: onColumnWidthsChange
10644
10675
  });
10645
- const { startResize } = useColumnResize({
10676
+ const { startResize, nudge: nudgeColumnWidth } = useColumnResize({
10646
10677
  widths: columnWidths,
10647
10678
  onChange: setColumnWidths
10648
10679
  });
@@ -10659,6 +10690,22 @@ const DEFAULT_LABELS = {
10659
10690
  order: columnOrder,
10660
10691
  onChange: setColumnOrder
10661
10692
  });
10693
+ // Column reorder rides on native HTML5 drag-and-drop, whose
10694
+ // `dragstart` / `drop` events DO NOT fire for touch input. On a
10695
+ // coarse-pointer device the drag would be a dead affordance — so
10696
+ // we detect the primary pointer and gate reorder off there. Mouse
10697
+ // / trackpad / pen (fine pointer) keep the feature. A pointer-event
10698
+ // based reorder that also covers touch is tracked as a follow-up
10699
+ // in REFINEMENT-NOTES.md.
10700
+ const [coarsePointer, setCoarsePointer] = useState(false);
10701
+ useEffect(()=>{
10702
+ if (typeof window === 'undefined' || !window.matchMedia) return;
10703
+ const mq = window.matchMedia('(pointer: coarse)');
10704
+ setCoarsePointer(mq.matches);
10705
+ const onChange = (e)=>setCoarsePointer(e.matches);
10706
+ mq.addEventListener('change', onChange);
10707
+ return ()=>mq.removeEventListener('change', onChange);
10708
+ }, []);
10662
10709
  // Apply the active order to the columns list. Cols not in the
10663
10710
  // order array (e.g. newly-added columns at runtime) are appended
10664
10711
  // in their original position from `cols`.
@@ -10805,7 +10852,7 @@ const DEFAULT_LABELS = {
10805
10852
  ]
10806
10853
  }),
10807
10854
  enableColumnVisibility && jsx(ColumnVisibilityTrigger, {
10808
- cols: cols.filter((c)=>// RBAC-hidden columns are never offered in the dialog.
10855
+ cols: cols.filter((c)=>// RBAC-hidden columns are never offered in the menu.
10809
10856
  !c.access || c.access.onUnauthorized !== 'hide'),
10810
10857
  hiddenColumns: hiddenColumns,
10811
10858
  onChange: setHiddenColumns,
@@ -10813,10 +10860,7 @@ const DEFAULT_LABELS = {
10813
10860
  labels: {
10814
10861
  columnsButton: labels.columnsButton,
10815
10862
  columnsTitle: labels.columnsTitle,
10816
- columnsDescription: labels.columnsDescription,
10817
- columnsShowAll: labels.columnsShowAll,
10818
- columnsHideAll: labels.columnsHideAll,
10819
- columnsDone: labels.columnsDone
10863
+ columnsToggleAll: labels.columnsToggleAll
10820
10864
  }
10821
10865
  })
10822
10866
  ]
@@ -10830,6 +10874,7 @@ const DEFAULT_LABELS = {
10830
10874
  } : undefined,
10831
10875
  children: jsxs("table", {
10832
10876
  className: cn(v.table(), slotProps == null ? void 0 : (_slotProps_table = slotProps.table) == null ? void 0 : _slotProps_table.className),
10877
+ "aria-rowcount": effectiveTotalCount > 0 ? effectiveTotalCount + 1 : -1,
10833
10878
  children: [
10834
10879
  caption != null && jsx("caption", {
10835
10880
  className: cn(!showCaption && 'sr-only', 'py-2 text-sm text-neutral-500'),
@@ -10838,6 +10883,7 @@ const DEFAULT_LABELS = {
10838
10883
  jsx("thead", {
10839
10884
  className: cn(stickyHeader ? v.thead() : 'bg-neutral-50', slotProps == null ? void 0 : (_slotProps_thead = slotProps.thead) == null ? void 0 : _slotProps_thead.className),
10840
10885
  children: jsxs("tr", {
10886
+ "aria-rowindex": 1,
10841
10887
  className: cn(v.headerRow(), slotProps == null ? void 0 : (_slotProps_headerRow = slotProps.headerRow) == null ? void 0 : _slotProps_headerRow.className),
10842
10888
  children: [
10843
10889
  showSelectionColumn && jsx("th", {
@@ -10867,7 +10913,8 @@ const DEFAULT_LABELS = {
10867
10913
  effectiveWidth: resolveColumnWidth(col, columnWidths),
10868
10914
  resizable: enableColumnResize && col.resizable !== false,
10869
10915
  startResize: startResize,
10870
- reorderable: enableColumnReorder && col.reorderable !== false,
10916
+ nudgeColumnWidth: nudgeColumnWidth,
10917
+ reorderable: enableColumnReorder && col.reorderable !== false && !coarsePointer,
10871
10918
  reorderHandlers: reorderHandlers,
10872
10919
  labels: labels,
10873
10920
  className: cn(v.headerCell(), col.sticky === 'left' && v.stickyLeftHeaderCell(), col.sticky === 'right' && v.stickyRightHeaderCell(), slotProps == null ? void 0 : (_slotProps_headerCell = slotProps.headerCell) == null ? void 0 : _slotProps_headerCell.className),
@@ -10896,7 +10943,11 @@ const DEFAULT_LABELS = {
10896
10943
  }) : sortedRows.length === 0 ? renderEmptyState({
10897
10944
  totalColumnCount,
10898
10945
  emptyState,
10899
- fallback: labels.noData,
10946
+ // Distinguish a genuinely empty dataset from one
10947
+ // emptied by an active search / filter (works for
10948
+ // server-side mode too — a query that returns 0
10949
+ // rows still reads as "no matching results").
10950
+ fallback: rows.length > 0 && (debouncedSearchQuery.trim().length > 0 || filterModel.length > 0) ? labels.noResults : labels.noData,
10900
10951
  cellClass: cn(v.cell(), v.emptyState(), slotProps == null ? void 0 : (_slotProps_emptyState = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState.className)
10901
10952
  }) : renderVirtualizedBody({
10902
10953
  vWindow,
@@ -10964,7 +11015,8 @@ const DEFAULT_LABELS = {
10964
11015
  }
10965
11016
  // ───── Header cell ─────
10966
11017
  function HeaderCell(props) {
10967
- const { col, sortModel, onSortClick, inferredType, filterModel, onFilterChange, effectiveWidth, resizable, startResize, reorderable, reorderHandlers, labels, className, buttonClassName, disabled } = props;
11018
+ var _col_minWidth, _col_maxWidth;
11019
+ const { col, sortModel, onSortClick, inferredType, filterModel, onFilterChange, effectiveWidth, resizable, startResize, nudgeColumnWidth, reorderable, reorderHandlers, labels, className, buttonClassName, disabled } = props;
10968
11020
  const align = resolveAlign(col, inferredType);
10969
11021
  const alignClass = align === 'right' ? 'text-right' : align === 'center' ? 'text-center' : 'text-left';
10970
11022
  const sortEntry = sortModel.find((s)=>s.field === col.field);
@@ -10991,20 +11043,42 @@ function HeaderCell(props) {
10991
11043
  onDrop: reorderHandlers.drop(col.field),
10992
11044
  onDragEnd: reorderHandlers.dragEnd
10993
11045
  } : {};
11046
+ // Resize bounds — shared by the pointer-drag and keyboard paths.
11047
+ const resizeMin = (_col_minWidth = col.minWidth) != null ? _col_minWidth : 40;
11048
+ const resizeMax = (_col_maxWidth = col.maxWidth) != null ? _col_maxWidth : 1200;
11049
+ // Keyboard nudge step: 16px, or 64px with Shift held (coarse).
11050
+ const measureWidth = (handle)=>{
11051
+ var _ref;
11052
+ var _handle_parentElement;
11053
+ return (_ref = effectiveWidth != null ? effectiveWidth : (_handle_parentElement = handle.parentElement) == null ? void 0 : _handle_parentElement.getBoundingClientRect().width) != null ? _ref : 120;
11054
+ };
10994
11055
  const resizeHandle = resizable ? jsx("span", {
10995
11056
  role: "separator",
10996
11057
  "aria-orientation": "vertical",
10997
11058
  "aria-label": `Resize ${typeof col.header === 'string' ? col.header : col.field}`,
11059
+ "aria-valuemin": resizeMin,
11060
+ "aria-valuemax": resizeMax,
11061
+ "aria-valuenow": effectiveWidth != null ? effectiveWidth : undefined,
11062
+ // Keyboard-operable: focusable + ArrowLeft/Right resize. WCAG 2.1
11063
+ // keyboard operability — the drag is no longer the only path.
11064
+ tabIndex: disabled ? -1 : 0,
11065
+ // D6 guard: the parent `<th>` is `draggable` when reorderable;
11066
+ // marking the handle non-draggable means grabbing the handle
11067
+ // starts a RESIZE, never a column-reorder drag.
11068
+ draggable: false,
10998
11069
  onPointerDown: (e)=>{
10999
- var _ref, _col_minWidth, _col_maxWidth;
11000
- const handle = e.currentTarget;
11001
- const th = handle.parentElement;
11002
- const startWidth = (_ref = effectiveWidth != null ? effectiveWidth : th == null ? void 0 : th.getBoundingClientRect().width) != null ? _ref : 120;
11003
- const min = (_col_minWidth = col.minWidth) != null ? _col_minWidth : 40;
11004
- const max = (_col_maxWidth = col.maxWidth) != null ? _col_maxWidth : 1200;
11005
- startResize(col.field, startWidth, min, max)(e);
11006
- },
11007
- className: cn('absolute top-0 bottom-0 right-0 w-1.5', 'cursor-col-resize select-none touch-none', 'hover:bg-primary-300 active:bg-primary-400', 'transition-colors motion-reduce:transition-none')
11070
+ const startWidth = measureWidth(e.currentTarget);
11071
+ startResize(col.field, startWidth, resizeMin, resizeMax)(e);
11072
+ },
11073
+ onKeyDown: (e)=>{
11074
+ if (disabled) return;
11075
+ if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
11076
+ e.preventDefault();
11077
+ const step = (e.shiftKey ? 64 : 16) * (e.key === 'ArrowLeft' ? -1 : 1);
11078
+ const current = measureWidth(e.currentTarget);
11079
+ nudgeColumnWidth(col.field, current, step, resizeMin, resizeMax);
11080
+ },
11081
+ className: cn('absolute top-0 bottom-0 right-0 w-1.5', 'cursor-col-resize select-none touch-none', 'hover:bg-primary-300 active:bg-primary-400', 'focus:outline-none focus-visible:bg-primary-400', 'transition-colors motion-reduce:transition-none')
11008
11082
  }) : null;
11009
11083
  const filterType = col.filterable ? resolveFilterType(col, inferredType) : null;
11010
11084
  const filterTrigger = col.filterable && filterType ? jsx(ColumnFilterTrigger, {
@@ -11131,6 +11205,7 @@ function renderVirtualizedBody(args) {
11131
11205
  const rowId = getRowId(row, absoluteIdx);
11132
11206
  const isSelected = selection.isSelected(rowId);
11133
11207
  return jsxs("tr", {
11208
+ "aria-rowindex": absoluteIdx + 2,
11134
11209
  "data-selected": isSelected ? 'true' : 'false',
11135
11210
  "aria-selected": rowSelection !== 'none' ? isSelected : undefined,
11136
11211
  className: classes.row,
@@ -1 +1 @@
1
- {"version":3,"file":"DataGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/DataGrid.tsx"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA6CzD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,kDAohBjE"}
1
+ {"version":3,"file":"DataGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/DataGrid/DataGrid.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA0CzD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,kDA6jBjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnFilters.d.ts","sourceRoot":"","sources":["../../../../../src/components/DataGrid/filters/ColumnFilters.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,gBAAgB,EAChB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAqCpC,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkDlE"}
1
+ {"version":3,"file":"ColumnFilters.d.ts","sourceRoot":"","sources":["../../../../../src/components/DataGrid/filters/ColumnFilters.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,gBAAgB,EAChB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAqDpC,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,cAAc,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkDlE"}