@opencorestack/opengridx 3.5.1 → 3.7.0

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 (114) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +2 -0
  3. package/dist/ai.cjs +4 -2
  4. package/dist/ai.cjs.map +1 -1
  5. package/dist/ai.d.ts +2 -2
  6. package/dist/ai.es.js +4 -2
  7. package/dist/ai.es.js.map +1 -1
  8. package/dist/index.d.ts +62 -0
  9. package/dist/opengridx.css +1 -1
  10. package/dist/opengridx.es.js +9643 -9024
  11. package/dist/opengridx.es.js.map +1 -1
  12. package/dist/opengridx.umd.js +16 -16
  13. package/dist/opengridx.umd.js.map +1 -1
  14. package/docs/API_REFERENCE.md +17 -3
  15. package/docs/README.md +2 -0
  16. package/docs/architecture/datagrid-orchestration.md +46 -29
  17. package/docs/architecture/grid-row-meta.md +1 -1
  18. package/docs/customization/slots-api.md +1 -1
  19. package/docs/customization/theming.md +43 -0
  20. package/docs/features/ai-toolkit.md +2 -2
  21. package/docs/features/export-guide.md +2 -0
  22. package/docs/features/header-filters.md +34 -0
  23. package/docs/features/keyboard-navigation.md +2 -0
  24. package/docs/features/nextjs.md +241 -0
  25. package/docs/features/pdf-export.md +2 -0
  26. package/docs/features/pinning.md +2 -0
  27. package/docs/features/rtl.md +58 -0
  28. package/docs/features/virtualization.md +16 -2
  29. package/docs/performance.md +89 -119
  30. package/docs/roadmap.md +4 -2
  31. package/lib/ai/promptHandler.ts +12 -8
  32. package/lib/ai/validate.ts +5 -2
  33. package/lib/components/AiAssistant/GridAiAssistantPanel.css +4 -2
  34. package/lib/components/Cell/Cell.css +31 -9
  35. package/lib/components/Cell/Cell.tsx +2 -2
  36. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +4 -4
  37. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +3 -3
  38. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +18 -2
  39. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +3 -1
  40. package/lib/components/DataGrid/DataGrid.css +19 -13
  41. package/lib/components/DataGrid/DataGrid.tsx +163 -670
  42. package/lib/components/DataGrid/GridAggregationFooter.tsx +3 -3
  43. package/lib/components/DataGrid/GridListView.tsx +3 -1
  44. package/lib/components/DataGrid/GridRoot.tsx +239 -0
  45. package/lib/components/DataGrid/GridViewport.tsx +314 -0
  46. package/lib/components/FilterPanel/FilterPanel.css +9 -8
  47. package/lib/components/Header/ColumnMenu.css +5 -4
  48. package/lib/components/Header/ColumnMenu.tsx +14 -6
  49. package/lib/components/Header/Header.css +23 -14
  50. package/lib/components/Header/Header.tsx +16 -9
  51. package/lib/components/Header/headerColumnStyle.ts +3 -2
  52. package/lib/components/HeaderFilter/HeaderFilter.css +9 -3
  53. package/lib/components/HeaderFilter/HeaderFilterCell.tsx +21 -18
  54. package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +5 -4
  55. package/lib/components/HeaderFilter/HeaderFilterRow.tsx +9 -3
  56. package/lib/components/ListView/ListViewRow.tsx +1 -1
  57. package/lib/components/Pagination/Pagination.css +5 -1
  58. package/lib/components/Pagination/Pagination.tsx +4 -4
  59. package/lib/components/Row/Row.css +2 -2
  60. package/lib/components/Row/Row.tsx +3 -3
  61. package/lib/components/SkeletonRow/SkeletonRow.tsx +2 -2
  62. package/lib/components/Toolbar/GridToolbar.css +8 -7
  63. package/lib/components/Toolbar/GridToolbar.tsx +8 -28
  64. package/lib/components/Toolbar/PivotPanel.css +3 -3
  65. package/lib/components/Toolbar/PivotPanel.tsx +4 -7
  66. package/lib/components/ui/ExpandIcon.css +13 -0
  67. package/lib/components/ui/ExpandIcon.tsx +2 -4
  68. package/lib/hooks/core/useGridCellSelection.ts +20 -5
  69. package/lib/hooks/core/useGridColumns.tsx +2 -2
  70. package/lib/hooks/core/useGridDevWarnings.ts +3 -1
  71. package/lib/hooks/core/useGridEditPipeline.ts +55 -0
  72. package/lib/hooks/core/useGridKeyboardNavigation.ts +7 -4
  73. package/lib/hooks/core/useGridRangeEditing.ts +129 -0
  74. package/lib/hooks/core/useGridRenderWindow.ts +66 -0
  75. package/lib/hooks/core/useGridScrollSync.ts +28 -5
  76. package/lib/hooks/core/useGridScrollViewport.ts +42 -0
  77. package/lib/hooks/core/useGridSelectionAndStateApi.ts +61 -0
  78. package/lib/hooks/core/useGridToolbarStack.ts +49 -0
  79. package/lib/hooks/core/useGridViewApis.ts +46 -0
  80. package/lib/hooks/core/useLayout.ts +13 -6
  81. package/lib/hooks/useRowGrouping.ts +9 -9
  82. package/lib/styles/base/variables.css +12 -0
  83. package/lib/theme/DataGridThemeProvider.tsx +15 -0
  84. package/lib/theme/__baseline__/default-theme.darwin.chromium.json +1503 -0
  85. package/lib/theme/__baseline__/default-theme.darwin.firefox.json +1503 -0
  86. package/lib/theme/__baseline__/default-theme.darwin.webkit.json +1503 -0
  87. package/lib/theme/types.ts +31 -0
  88. package/lib/types/ai.ts +109 -0
  89. package/lib/types/api.ts +169 -0
  90. package/lib/types/columns.ts +341 -0
  91. package/lib/types/dataSource.ts +40 -0
  92. package/lib/types/editing.ts +77 -0
  93. package/lib/types/export.ts +164 -0
  94. package/lib/types/filtering.ts +52 -0
  95. package/lib/types/grouping.ts +27 -0
  96. package/lib/types/index.ts +18 -1672
  97. package/lib/types/locale.ts +51 -0
  98. package/lib/types/props.ts +405 -0
  99. package/lib/types/rows.ts +132 -0
  100. package/lib/types/selection.ts +66 -0
  101. package/lib/types/slots.ts +56 -0
  102. package/lib/types/sorting.ts +25 -0
  103. package/lib/types/state.ts +35 -0
  104. package/lib/utils/aggregation/index.ts +56 -1
  105. package/lib/utils/direction.ts +52 -0
  106. package/lib/utils/export/exportToExcelAdvanced.ts +9 -2
  107. package/lib/utils/export/exportToPdf.ts +2 -1
  108. package/lib/utils/filtering/index.ts +58 -6
  109. package/lib/utils/headerFilterLocale.ts +37 -0
  110. package/lib/utils/scroll/index.ts +5 -3
  111. package/lib/utils/sorting/index.ts +141 -26
  112. package/lib/utils/values.ts +10 -6
  113. package/llms.txt +4 -2
  114. package/package.json +4 -2
@@ -258,9 +258,9 @@ function CellImpl<R extends GridRowModel = GridRowModel>(props: CellProps<R>) {
258
258
 
259
259
  if (isPinned && pinnedOffset !== undefined) {
260
260
  if (pinnedPosition === 'left') {
261
- style.left = pinnedOffset;
261
+ style.insetInlineStart = pinnedOffset;
262
262
  } else {
263
- style.right = pinnedOffset;
263
+ style.insetInlineEnd = pinnedOffset;
264
264
  }
265
265
  }
266
266
 
@@ -8,7 +8,7 @@
8
8
  display: flex;
9
9
  align-items: stretch;
10
10
  background: var(--ogx-grid-header-background);
11
- border-bottom: 1px solid var(--ogx-grid-border-color);
11
+ border-bottom: var(--ogx-grid-row-divider-width) solid var(--ogx-grid-row-divider-color, var(--ogx-grid-border-color));
12
12
  /* No overflow clipping: it would make the row the scroll container of its sticky (pinned) cells. */
13
13
  flex-shrink: 0;
14
14
  min-height: var(--ogx-header-height, 48px);
@@ -23,15 +23,15 @@
23
23
  box-sizing: border-box;
24
24
  position: relative;
25
25
  overflow: hidden;
26
- /* Same border UI as primary header cells: half-height right divider */
26
+ /* Same border UI as primary header cells: half-height divider on the end edge */
27
27
  }
28
28
  .ogx-col-group-cell:not(:last-child)::after {
29
29
  content: '';
30
30
  position: absolute;
31
- right: 0;
31
+ inset-inline-end: 0;
32
32
  top: 25%;
33
33
  height: 50%;
34
- width: 1px;
34
+ width: var(--ogx-grid-header-column-divider-width);
35
35
  background-color: var(--ogx-color-gray-300, #cbd5e1);
36
36
  opacity: 0.5;
37
37
  }
@@ -2,7 +2,7 @@
2
2
  position: absolute;
3
3
  top: 0;
4
4
  /* Inside the header cell: the cell clips overflow, so a handle straddling the border lost its outer half. */
5
- right: 0;
5
+ inset-inline-end: 0;
6
6
  width: 8px;
7
7
  height: 100%;
8
8
  cursor: col-resize;
@@ -16,8 +16,8 @@
16
16
  }
17
17
  /* Right-pinned columns grow leftwards: their handle sits on the left edge. */
18
18
  .ogx-column-resize-handle--start {
19
- right: auto;
20
- left: 0;
19
+ inset-inline-end: auto;
20
+ inset-inline-start: 0;
21
21
  justify-content: flex-start;
22
22
  }
23
23
  .ogx-column-resize-handle:focus-visible .ogx-column-resize-handle__line {
@@ -1,5 +1,6 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { clampResizeWidth } from './clampResizeWidth';
3
+ import { isRtl, logicalArrowKey } from '../../utils/direction';
3
4
 
4
5
 
5
6
  export interface ColumnResizeHandleProps {
@@ -23,6 +24,8 @@ interface ActiveResize {
23
24
  pointerId: number;
24
25
  startX: number;
25
26
  startWidth: number;
27
+ /** The grid lays out right to left: the handle's edge grows the column towards the left. */
28
+ rtl: boolean;
26
29
  lastUpdate: number;
27
30
  moved: boolean;
28
31
  }
@@ -53,7 +56,8 @@ export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
53
56
  useEffect(() => () => { activeRef.current = null; }, []);
54
57
 
55
58
  const widthAt = useCallback((active: ActiveResize, clientX: number) => {
56
- const deltaX = clientX - active.startX;
59
+ // Pointer movement towards the column's end edge, in screen pixels.
60
+ const deltaX = (clientX - active.startX) * (active.rtl ? -1 : 1);
57
61
  const raw = active.startWidth + (edge === 'start' ? -deltaX : deltaX);
58
62
  return clampResizeWidth(raw, active.startWidth, minWidth, maxWidth);
59
63
  }, [edge, minWidth, maxWidth]);
@@ -67,6 +71,7 @@ export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
67
71
  startX: event.clientX,
68
72
  // The logical stored width: reliable for pinned, flex, and normal columns.
69
73
  startWidth: currentWidth,
74
+ rtl: isRtl(event.currentTarget),
70
75
  lastUpdate: 0,
71
76
  moved: false,
72
77
  };
@@ -97,6 +102,16 @@ export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
97
102
  if (!active || event.pointerId !== active.pointerId) return;
98
103
  activeRef.current = null;
99
104
  setIsDragging(false);
105
+ // Release explicitly: the implicit release only follows a real pointerup, and a capture left on
106
+ // this handle (a synthetic press on the live mouse pointer, or an interrupted drag) would keep
107
+ // the pointer's later events from reaching the rest of the page.
108
+ if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
109
+ try {
110
+ event.currentTarget.releasePointerCapture(event.pointerId);
111
+ } catch {
112
+ // Already released.
113
+ }
114
+ }
100
115
  if (active.moved || event.clientX !== active.startX) {
101
116
  // The drag may end over the header cell, which would take the synthesized click as a sort.
102
117
  suppressNextClick();
@@ -114,7 +129,8 @@ export function ColumnResizeHandle(props: ColumnResizeHandleProps) {
114
129
  if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
115
130
  event.preventDefault();
116
131
  event.stopPropagation();
117
- const step = (event.shiftKey ? 50 : 10) * (event.key === 'ArrowRight' ? 1 : -1);
132
+ const key = logicalArrowKey(event.key, isRtl(event.currentTarget));
133
+ const step = (event.shiftKey ? 50 : 10) * (key === 'ArrowRight' ? 1 : -1);
118
134
  onResize(field, clampResizeWidth(currentWidth + step, currentWidth, minWidth, maxWidth));
119
135
  }, [field, currentWidth, onResize, onAutosize, minWidth, maxWidth]);
120
136
 
@@ -2,6 +2,7 @@
2
2
  background: var(--ogx-overlay-background, var(--ogx-color-white));
3
3
  border: var(--ogx-border-width-thin) solid var(--ogx-overlay-border, var(--ogx-border-color));
4
4
  border-radius: var(--ogx-border-radius-sm);
5
+ font-family: var(--ogx-overlay-font-family, inherit);
5
6
  min-width: 250px;
6
7
  max-width: 350px;
7
8
  box-shadow: var(--ogx-shadow-lg);
@@ -120,7 +121,8 @@
120
121
  }
121
122
 
122
123
  .ogx-column-visibility-panel__label {
123
- font-size: var(--ogx-font-size-xs);
124
+ font-size: var(--ogx-overlay-font-size, var(--ogx-font-size-xs));
125
+ font-weight: var(--ogx-overlay-font-weight, inherit);
124
126
  color: var(--ogx-overlay-text, var(--ogx-color-gray-900));
125
127
  user-select: none;
126
128
  cursor: inherit;
@@ -3,8 +3,8 @@
3
3
  flex-direction: column;
4
4
  width: 100%;
5
5
  background: var(--ogx-grid-background);
6
- border: 1px solid var(--ogx-grid-border-color);
7
- border-radius: var(--ogx-border-radius-lg);
6
+ border: var(--ogx-grid-border-width) solid var(--ogx-grid-border-color);
7
+ border-radius: var(--ogx-grid-border-radius, var(--ogx-border-radius-lg));
8
8
  font-family: var(--ogx-font-family);
9
9
  position: relative;
10
10
  box-shadow: var(--ogx-shadow-sm);
@@ -12,12 +12,12 @@
12
12
  overflow: hidden;
13
13
  }
14
14
  .ogx > :first-child {
15
- border-top-left-radius: calc(var(--ogx-border-radius-lg) - 1px);
16
- border-top-right-radius: calc(var(--ogx-border-radius-lg) - 1px);
15
+ border-top-left-radius: max(0px, calc(var(--ogx-grid-border-radius, var(--ogx-border-radius-lg)) - var(--ogx-grid-border-width)));
16
+ border-top-right-radius: max(0px, calc(var(--ogx-grid-border-radius, var(--ogx-border-radius-lg)) - var(--ogx-grid-border-width)));
17
17
  }
18
18
  .ogx > :last-child {
19
- border-bottom-left-radius: calc(var(--ogx-border-radius-lg) - 1px);
20
- border-bottom-right-radius: calc(var(--ogx-border-radius-lg) - 1px);
19
+ border-bottom-left-radius: max(0px, calc(var(--ogx-grid-border-radius, var(--ogx-border-radius-lg)) - var(--ogx-grid-border-width)));
20
+ border-bottom-right-radius: max(0px, calc(var(--ogx-grid-border-radius, var(--ogx-border-radius-lg)) - var(--ogx-grid-border-width)));
21
21
  }
22
22
  .ogx:hover {
23
23
  box-shadow: var(--ogx-shadow-md);
@@ -150,7 +150,7 @@
150
150
  min-height: 0;
151
151
  pointer-events: none;
152
152
  z-index: var(--ogx-z-index-modal);
153
- border-radius: var(--ogx-border-radius-lg);
153
+ border-radius: var(--ogx-grid-border-radius, var(--ogx-border-radius-lg));
154
154
  overflow: hidden;
155
155
  }
156
156
  .ogx__loading-overlay--custom {
@@ -243,7 +243,7 @@
243
243
  justify-content: center;
244
244
  overflow: hidden;
245
245
  box-sizing: border-box;
246
- border-right: 1px solid var(--ogx-grid-border-color);
246
+ border-inline-end: var(--ogx-grid-column-divider-width) solid var(--ogx-grid-column-divider-color, var(--ogx-grid-border-color));
247
247
  position: relative;
248
248
  }
249
249
  .ogx__aggregation-cell--pinned-left,
@@ -265,7 +265,7 @@
265
265
  background: var(--ogx-grid-header-background);
266
266
  }
267
267
  .ogx__aggregation-cell--pinned-right {
268
- border-left: 1px solid var(--ogx-grid-border-color);
268
+ border-inline-start: var(--ogx-grid-column-divider-width) solid var(--ogx-grid-column-divider-color, var(--ogx-grid-border-color));
269
269
  }
270
270
  .ogx__aggregation-cell--pinned-left-last {
271
271
  overflow: visible;
@@ -274,26 +274,32 @@
274
274
  content: '';
275
275
  position: absolute;
276
276
  top: 0;
277
- right: -10px;
277
+ inset-inline-end: -10px;
278
278
  bottom: 0;
279
279
  width: 10px;
280
280
  pointer-events: none;
281
281
  box-shadow: inset 10px 0 8px -8px rgba(0, 0, 0, 0.1);
282
282
  }
283
283
  .ogx__aggregation-cell--pinned-right-first {
284
- margin-left: auto;
284
+ margin-inline-start: auto;
285
285
  overflow: visible;
286
286
  }
287
287
  .ogx__aggregation-cell--pinned-right-first::before {
288
288
  content: '';
289
289
  position: absolute;
290
290
  top: 0;
291
- left: -10px;
291
+ inset-inline-start: -10px;
292
292
  bottom: 0;
293
293
  width: 10px;
294
294
  pointer-events: none;
295
295
  box-shadow: inset -10px 0 8px -8px rgba(0, 0, 0, 0.1);
296
296
  }
297
+ .ogx__aggregation-cell--pinned-left-last:dir(rtl)::after {
298
+ box-shadow: inset -10px 0 8px -8px rgba(0, 0, 0, 0.1);
299
+ }
300
+ .ogx__aggregation-cell--pinned-right-first:dir(rtl)::before {
301
+ box-shadow: inset 10px 0 8px -8px rgba(0, 0, 0, 0.1);
302
+ }
297
303
  .ogx__aggregation-label {
298
304
  font-size: 0.7em;
299
305
  text-transform: uppercase;
@@ -321,7 +327,7 @@
321
327
  }
322
328
  .ogx__group-cell-content {
323
329
  font-weight: 500;
324
- text-align: left;
330
+ text-align: start;
325
331
  display: flex;
326
332
  align-items: center;
327
333
  gap: 4px;