@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.
- package/CHANGELOG.md +53 -0
- package/README.md +2 -0
- package/dist/ai.cjs +4 -2
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.es.js +4 -2
- package/dist/ai.es.js.map +1 -1
- package/dist/index.d.ts +62 -0
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +9643 -9024
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +16 -16
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +17 -3
- package/docs/README.md +2 -0
- package/docs/architecture/datagrid-orchestration.md +46 -29
- package/docs/architecture/grid-row-meta.md +1 -1
- package/docs/customization/slots-api.md +1 -1
- package/docs/customization/theming.md +43 -0
- package/docs/features/ai-toolkit.md +2 -2
- package/docs/features/export-guide.md +2 -0
- package/docs/features/header-filters.md +34 -0
- package/docs/features/keyboard-navigation.md +2 -0
- package/docs/features/nextjs.md +241 -0
- package/docs/features/pdf-export.md +2 -0
- package/docs/features/pinning.md +2 -0
- package/docs/features/rtl.md +58 -0
- package/docs/features/virtualization.md +16 -2
- package/docs/performance.md +89 -119
- package/docs/roadmap.md +4 -2
- package/lib/ai/promptHandler.ts +12 -8
- package/lib/ai/validate.ts +5 -2
- package/lib/components/AiAssistant/GridAiAssistantPanel.css +4 -2
- package/lib/components/Cell/Cell.css +31 -9
- package/lib/components/Cell/Cell.tsx +2 -2
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +4 -4
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +3 -3
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +18 -2
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +3 -1
- package/lib/components/DataGrid/DataGrid.css +19 -13
- package/lib/components/DataGrid/DataGrid.tsx +163 -670
- package/lib/components/DataGrid/GridAggregationFooter.tsx +3 -3
- package/lib/components/DataGrid/GridListView.tsx +3 -1
- package/lib/components/DataGrid/GridRoot.tsx +239 -0
- package/lib/components/DataGrid/GridViewport.tsx +314 -0
- package/lib/components/FilterPanel/FilterPanel.css +9 -8
- package/lib/components/Header/ColumnMenu.css +5 -4
- package/lib/components/Header/ColumnMenu.tsx +14 -6
- package/lib/components/Header/Header.css +23 -14
- package/lib/components/Header/Header.tsx +16 -9
- package/lib/components/Header/headerColumnStyle.ts +3 -2
- package/lib/components/HeaderFilter/HeaderFilter.css +9 -3
- package/lib/components/HeaderFilter/HeaderFilterCell.tsx +21 -18
- package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +5 -4
- package/lib/components/HeaderFilter/HeaderFilterRow.tsx +9 -3
- package/lib/components/ListView/ListViewRow.tsx +1 -1
- package/lib/components/Pagination/Pagination.css +5 -1
- package/lib/components/Pagination/Pagination.tsx +4 -4
- package/lib/components/Row/Row.css +2 -2
- package/lib/components/Row/Row.tsx +3 -3
- package/lib/components/SkeletonRow/SkeletonRow.tsx +2 -2
- package/lib/components/Toolbar/GridToolbar.css +8 -7
- package/lib/components/Toolbar/GridToolbar.tsx +8 -28
- package/lib/components/Toolbar/PivotPanel.css +3 -3
- package/lib/components/Toolbar/PivotPanel.tsx +4 -7
- package/lib/components/ui/ExpandIcon.css +13 -0
- package/lib/components/ui/ExpandIcon.tsx +2 -4
- package/lib/hooks/core/useGridCellSelection.ts +20 -5
- package/lib/hooks/core/useGridColumns.tsx +2 -2
- package/lib/hooks/core/useGridDevWarnings.ts +3 -1
- package/lib/hooks/core/useGridEditPipeline.ts +55 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +7 -4
- package/lib/hooks/core/useGridRangeEditing.ts +129 -0
- package/lib/hooks/core/useGridRenderWindow.ts +66 -0
- package/lib/hooks/core/useGridScrollSync.ts +28 -5
- package/lib/hooks/core/useGridScrollViewport.ts +42 -0
- package/lib/hooks/core/useGridSelectionAndStateApi.ts +61 -0
- package/lib/hooks/core/useGridToolbarStack.ts +49 -0
- package/lib/hooks/core/useGridViewApis.ts +46 -0
- package/lib/hooks/core/useLayout.ts +13 -6
- package/lib/hooks/useRowGrouping.ts +9 -9
- package/lib/styles/base/variables.css +12 -0
- package/lib/theme/DataGridThemeProvider.tsx +15 -0
- package/lib/theme/__baseline__/default-theme.darwin.chromium.json +1503 -0
- package/lib/theme/__baseline__/default-theme.darwin.firefox.json +1503 -0
- package/lib/theme/__baseline__/default-theme.darwin.webkit.json +1503 -0
- package/lib/theme/types.ts +31 -0
- package/lib/types/ai.ts +109 -0
- package/lib/types/api.ts +169 -0
- package/lib/types/columns.ts +341 -0
- package/lib/types/dataSource.ts +40 -0
- package/lib/types/editing.ts +77 -0
- package/lib/types/export.ts +164 -0
- package/lib/types/filtering.ts +52 -0
- package/lib/types/grouping.ts +27 -0
- package/lib/types/index.ts +18 -1672
- package/lib/types/locale.ts +51 -0
- package/lib/types/props.ts +405 -0
- package/lib/types/rows.ts +132 -0
- package/lib/types/selection.ts +66 -0
- package/lib/types/slots.ts +56 -0
- package/lib/types/sorting.ts +25 -0
- package/lib/types/state.ts +35 -0
- package/lib/utils/aggregation/index.ts +56 -1
- package/lib/utils/direction.ts +52 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +9 -2
- package/lib/utils/export/exportToPdf.ts +2 -1
- package/lib/utils/filtering/index.ts +58 -6
- package/lib/utils/headerFilterLocale.ts +37 -0
- package/lib/utils/scroll/index.ts +5 -3
- package/lib/utils/sorting/index.ts +141 -26
- package/lib/utils/values.ts +10 -6
- package/llms.txt +4 -2
- package/package.json +4 -2
|
@@ -2,6 +2,7 @@ import React, { useRef, useEffect, useState } from 'react';
|
|
|
2
2
|
import ReactDOM from 'react-dom';
|
|
3
3
|
import type { GridColDef, GridRowModel, GridSortDirection, GridColumnPinning } from '../../types';
|
|
4
4
|
import { getViewportWidth, getViewportHeight } from '../../utils/viewport';
|
|
5
|
+
import { isRtl } from '../../utils/direction';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
interface ColumnMenuProps {
|
|
@@ -222,6 +223,13 @@ export function ColumnMenu({ colDef, sortModel, onSort, onHide, onPin, pinnedCol
|
|
|
222
223
|
const isPinnedLeft = pinnedColumns?.left?.includes(colDef.field) ?? false;
|
|
223
224
|
const isPinnedRight = pinnedColumns?.right?.includes(colDef.field) ?? false;
|
|
224
225
|
const isUnpinned = !isPinnedLeft && !isPinnedRight;
|
|
226
|
+
// `pinnedColumns.left` / `.right` are the inline start / end: in a right-to-left grid the start
|
|
227
|
+
// is on the right, so the item labelled by screen side pins to the opposite list.
|
|
228
|
+
const rtl = isRtl(anchorEl);
|
|
229
|
+
const screenLeftSide = rtl ? 'right' : 'left';
|
|
230
|
+
const screenRightSide = rtl ? 'left' : 'right';
|
|
231
|
+
const isPinnedScreenLeft = rtl ? isPinnedRight : isPinnedLeft;
|
|
232
|
+
const isPinnedScreenRight = rtl ? isPinnedLeft : isPinnedRight;
|
|
225
233
|
|
|
226
234
|
const colLabel = colDef.headerName || colDef.field;
|
|
227
235
|
|
|
@@ -257,15 +265,15 @@ export function ColumnMenu({ colDef, sortModel, onSort, onHide, onPin, pinnedCol
|
|
|
257
265
|
{canPin && (
|
|
258
266
|
<>
|
|
259
267
|
<div className="ogx-menu-section-label" aria-hidden="true">Pin column</div>
|
|
260
|
-
<button type="button" className={`ogx-menu-item${
|
|
261
|
-
onClick={() => handlePin(
|
|
262
|
-
<span className="ogx-menu-item__indicator" aria-hidden="true">{
|
|
268
|
+
<button type="button" className={`ogx-menu-item${isPinnedScreenLeft ? ' ogx-menu-item--active' : ''}`}
|
|
269
|
+
onClick={() => handlePin(screenLeftSide)} role="menuitemradio" aria-checked={isPinnedScreenLeft} aria-label="Pin to left">
|
|
270
|
+
<span className="ogx-menu-item__indicator" aria-hidden="true">{isPinnedScreenLeft ? <ActiveDotIcon /> : <InactiveDotIcon />}</span>
|
|
263
271
|
<span className="ogx-menu-item__icon" aria-hidden="true"><PinLeftIcon /></span>
|
|
264
272
|
Pin to Left
|
|
265
273
|
</button>
|
|
266
|
-
<button type="button" className={`ogx-menu-item${
|
|
267
|
-
onClick={() => handlePin(
|
|
268
|
-
<span className="ogx-menu-item__indicator" aria-hidden="true">{
|
|
274
|
+
<button type="button" className={`ogx-menu-item${isPinnedScreenRight ? ' ogx-menu-item--active' : ''}`}
|
|
275
|
+
onClick={() => handlePin(screenRightSide)} role="menuitemradio" aria-checked={isPinnedScreenRight} aria-label="Pin to right">
|
|
276
|
+
<span className="ogx-menu-item__indicator" aria-hidden="true">{isPinnedScreenRight ? <ActiveDotIcon /> : <InactiveDotIcon />}</span>
|
|
269
277
|
<span className="ogx-menu-item__icon" aria-hidden="true"><PinRightIcon /></span>
|
|
270
278
|
Pin to Right
|
|
271
279
|
</button>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
display: flex;
|
|
13
13
|
align-items: stretch;
|
|
14
14
|
background: var(--ogx-grid-header-background);
|
|
15
|
-
border-bottom:
|
|
15
|
+
border-bottom: var(--ogx-grid-row-divider-width) solid var(--ogx-grid-row-divider-color, var(--ogx-grid-border-color));
|
|
16
16
|
min-height: var(--ogx-header-height);
|
|
17
17
|
box-shadow: var(--ogx-shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.03));
|
|
18
18
|
}
|
|
@@ -20,15 +20,16 @@
|
|
|
20
20
|
width: 48px;
|
|
21
21
|
min-width: 48px;
|
|
22
22
|
flex-shrink: 0;
|
|
23
|
-
border-
|
|
23
|
+
border-inline-end: 1px solid transparent;
|
|
24
24
|
}
|
|
25
25
|
.ogx__header-cell {
|
|
26
26
|
display: flex;
|
|
27
27
|
align-items: center;
|
|
28
|
-
padding: var(--ogx-grid-cell-padding-y) var(--ogx-grid-cell-padding-x);
|
|
28
|
+
padding: var(--ogx-grid-cell-padding-y) var(--ogx-grid-header-padding-x, var(--ogx-grid-cell-padding-x));
|
|
29
29
|
position: relative;
|
|
30
|
+
font-family: var(--ogx-grid-header-font-family, inherit);
|
|
30
31
|
font-size: var(--ogx-grid-header-font-size);
|
|
31
|
-
font-weight: 600;
|
|
32
|
+
font-weight: var(--ogx-grid-header-font-weight, 600);
|
|
32
33
|
color: var(--ogx-grid-header-text);
|
|
33
34
|
overflow: hidden;
|
|
34
35
|
box-sizing: border-box;
|
|
@@ -39,10 +40,10 @@
|
|
|
39
40
|
.ogx__header-cell:not(:last-child)::after {
|
|
40
41
|
content: '';
|
|
41
42
|
position: absolute;
|
|
42
|
-
|
|
43
|
+
inset-inline-end: 0;
|
|
43
44
|
top: 25%;
|
|
44
45
|
height: 50%;
|
|
45
|
-
width:
|
|
46
|
+
width: var(--ogx-grid-header-column-divider-width);
|
|
46
47
|
background-color: var(--ogx-color-gray-300);
|
|
47
48
|
opacity: 0.5;
|
|
48
49
|
}
|
|
@@ -106,11 +107,11 @@
|
|
|
106
107
|
}
|
|
107
108
|
.ogx__header-cell--align-right .ogx__header-cell-title-wrapper {
|
|
108
109
|
align-items: flex-end;
|
|
109
|
-
text-align:
|
|
110
|
+
text-align: end;
|
|
110
111
|
}
|
|
111
112
|
.ogx__header-cell--align-right .ogx__menu-icon-btn {
|
|
112
|
-
margin-
|
|
113
|
-
margin-
|
|
113
|
+
margin-inline-start: 0;
|
|
114
|
+
margin-inline-end: auto;
|
|
114
115
|
}
|
|
115
116
|
.ogx__header-cell--sortable {
|
|
116
117
|
cursor: pointer;
|
|
@@ -131,7 +132,7 @@
|
|
|
131
132
|
justify-content: center;
|
|
132
133
|
width: 16px;
|
|
133
134
|
height: 16px;
|
|
134
|
-
margin-
|
|
135
|
+
margin-inline-start: 4px;
|
|
135
136
|
flex-shrink: 0;
|
|
136
137
|
font-size: 14px;
|
|
137
138
|
line-height: 1;
|
|
@@ -161,11 +162,19 @@
|
|
|
161
162
|
box-shadow: var(--ogx-grid-pinned-left-shadow, 4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
162
163
|
}
|
|
163
164
|
.ogx__header-cell--pinned-right-first {
|
|
164
|
-
margin-
|
|
165
|
+
margin-inline-start: auto;
|
|
165
166
|
}
|
|
166
167
|
.ogx__header-cell--pinned-right {
|
|
167
168
|
box-shadow: var(--ogx-grid-pinned-right-shadow, -4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
168
169
|
}
|
|
170
|
+
/* Right to left: the start-pinned section is on the right and casts its shadow leftwards, the
|
|
171
|
+
end-pinned one on the left casts it rightwards (the mirrored shadow tokens). */
|
|
172
|
+
.ogx__header-cell--pinned-left:dir(rtl) {
|
|
173
|
+
box-shadow: var(--ogx-grid-pinned-right-shadow, -4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
174
|
+
}
|
|
175
|
+
.ogx__header-cell--pinned-right:dir(rtl) {
|
|
176
|
+
box-shadow: var(--ogx-grid-pinned-left-shadow, 4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
177
|
+
}
|
|
169
178
|
.ogx__header-cell--pinned::after {
|
|
170
179
|
display: none;
|
|
171
180
|
}
|
|
@@ -178,7 +187,7 @@
|
|
|
178
187
|
display: flex;
|
|
179
188
|
align-items: center;
|
|
180
189
|
justify-content: center;
|
|
181
|
-
margin-
|
|
190
|
+
margin-inline-end: 8px;
|
|
182
191
|
color: var(--ogx-color-primary);
|
|
183
192
|
animation: ogx-pulse 1.5s infinite ease-in-out;
|
|
184
193
|
}
|
|
@@ -188,7 +197,7 @@
|
|
|
188
197
|
100% { transform: scale(1); }
|
|
189
198
|
}
|
|
190
199
|
.ogx__header-cell--drag-over {
|
|
191
|
-
border-
|
|
200
|
+
border-inline-start: 2px solid var(--ogx-color-primary) !important;
|
|
192
201
|
background: var(--ogx-color-primary-light);
|
|
193
202
|
}
|
|
194
203
|
/* Show ring on header cells during keyboard navigation */
|
|
@@ -222,7 +231,7 @@
|
|
|
222
231
|
cursor: pointer;
|
|
223
232
|
opacity: 0;
|
|
224
233
|
transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
|
|
225
|
-
margin-
|
|
234
|
+
margin-inline-start: auto;
|
|
226
235
|
}
|
|
227
236
|
.ogx__header-cell:hover .ogx__menu-icon-btn,
|
|
228
237
|
.ogx__header-cell--sorted .ogx__menu-icon-btn {
|
|
@@ -2,7 +2,7 @@ import React, { useId } from 'react';
|
|
|
2
2
|
import { Checkbox } from '../ui/Checkbox';
|
|
3
3
|
import { ColumnResizeHandle } from '../ColumnResizeHandle/ColumnResizeHandle';
|
|
4
4
|
import { clampResizeWidth } from '../ColumnResizeHandle/clampResizeWidth';
|
|
5
|
-
import type { GridColDef, GridRowModel, GridSortDirection, GridColumnPinning, GridAggregationModel, GridColumnGroupingModel, GridFilterModel } from '../../types';
|
|
5
|
+
import type { GridColDef, GridRowModel, GridSortDirection, GridColumnPinning, GridAggregationModel, GridColumnGroupingModel, GridFilterModel, GridLocaleText } from '../../types';
|
|
6
6
|
import { isColumnPinned, calculatePinnedPositions, getPinnedEdgeFields } from '../../utils/pinning';
|
|
7
7
|
import { getRenderedColumnWidth } from '../../utils/columnWidth';
|
|
8
8
|
import { buildColumnGroupRow, getColumnGroupDepth, getColumnGroupPaths } from '../../utils/columnGroups';
|
|
@@ -10,6 +10,7 @@ import { ColumnMenu } from './ColumnMenu';
|
|
|
10
10
|
import { getHeaderLineClamp, shouldWrapHeaderText } from '../../utils/headerWrap';
|
|
11
11
|
import { getHeaderColumnStyle } from './headerColumnStyle';
|
|
12
12
|
import { HeaderFilterRow } from '../HeaderFilter/HeaderFilterRow';
|
|
13
|
+
import { isRtl, logicalArrowKey } from '../../utils/direction';
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
function MenuIcon() {
|
|
@@ -87,6 +88,8 @@ export interface HeaderProps<R extends GridRowModel = GridRowModel> {
|
|
|
87
88
|
onFilterModelChange?: (model: GridFilterModel) => void;
|
|
88
89
|
/** Opens the filter panel; a header filter cell showing "Custom filter" calls it. */
|
|
89
90
|
onOpenFilterPanel?: () => void;
|
|
91
|
+
/** Translations of the header filter row's strings. */
|
|
92
|
+
localeText?: GridLocaleText;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps<R>) {
|
|
@@ -129,6 +132,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
129
132
|
filterModel,
|
|
130
133
|
onFilterModelChange,
|
|
131
134
|
onOpenFilterPanel,
|
|
135
|
+
localeText,
|
|
132
136
|
} = props;
|
|
133
137
|
|
|
134
138
|
const selectAllId = useId();
|
|
@@ -153,7 +157,9 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
153
157
|
event.preventDefault();
|
|
154
158
|
event.stopPropagation();
|
|
155
159
|
const width = getRenderedColumnWidth(colDef, columnWidths);
|
|
156
|
-
|
|
160
|
+
// ArrowRight widens: towards the column's end edge, on the left in a right-to-left grid.
|
|
161
|
+
const key = logicalArrowKey(event.key, isRtl(event.currentTarget));
|
|
162
|
+
const step = (event.shiftKey ? 50 : 10) * (key === 'ArrowRight' ? 1 : -1);
|
|
157
163
|
onColumnResize(colDef.field, clampResizeWidth(width + step, width, colDef.minWidth, colDef.maxWidth));
|
|
158
164
|
return;
|
|
159
165
|
}
|
|
@@ -285,7 +291,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
285
291
|
minWidth: prefixWidth,
|
|
286
292
|
flexShrink: 0,
|
|
287
293
|
position: isPrefixPinned ? 'sticky' : undefined,
|
|
288
|
-
|
|
294
|
+
insetInlineStart: isPrefixPinned ? 0 : undefined,
|
|
289
295
|
}}
|
|
290
296
|
aria-hidden="true"
|
|
291
297
|
/>
|
|
@@ -300,12 +306,12 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
300
306
|
};
|
|
301
307
|
if (cell.pinned === 'left') {
|
|
302
308
|
style.position = 'sticky';
|
|
303
|
-
style.
|
|
309
|
+
style.insetInlineStart = pinnedPositions[cell.fields[0]];
|
|
304
310
|
} else if (cell.pinned === 'right') {
|
|
305
311
|
style.position = 'sticky';
|
|
306
|
-
style.
|
|
312
|
+
style.insetInlineEnd = pinnedPositions[cell.fields[cell.fields.length - 1]];
|
|
307
313
|
// Free space goes before the right-pinned section, as in the column header row.
|
|
308
|
-
if (cells[cellIndex - 1]?.pinned !== 'right') style.
|
|
314
|
+
if (cells[cellIndex - 1]?.pinned !== 'right') style.marginInlineStart = 'auto';
|
|
309
315
|
}
|
|
310
316
|
if (!cell.isGroup) {
|
|
311
317
|
return (
|
|
@@ -351,7 +357,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
351
357
|
minWidth: 48,
|
|
352
358
|
maxWidth: 48,
|
|
353
359
|
position: 'sticky',
|
|
354
|
-
|
|
360
|
+
insetInlineStart: 0,
|
|
355
361
|
}}
|
|
356
362
|
/>
|
|
357
363
|
)}
|
|
@@ -370,7 +376,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
370
376
|
minWidth: 48,
|
|
371
377
|
maxWidth: 48,
|
|
372
378
|
position: pinExpandColumn ? 'sticky' : undefined,
|
|
373
|
-
|
|
379
|
+
insetInlineStart: pinExpandColumn ? (rowReordering ? 48 : 0) : undefined,
|
|
374
380
|
}}
|
|
375
381
|
>
|
|
376
382
|
{ }
|
|
@@ -387,7 +393,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
387
393
|
data-field="__checkbox_col__"
|
|
388
394
|
style={{
|
|
389
395
|
position: pinCheckboxColumn ? 'sticky' : undefined,
|
|
390
|
-
|
|
396
|
+
insetInlineStart: pinCheckboxColumn ? ((rowReordering ? 48 : 0) + (hasDetailPanel && pinExpandColumn ? 48 : 0)) : undefined,
|
|
391
397
|
|
|
392
398
|
}}
|
|
393
399
|
>
|
|
@@ -583,6 +589,7 @@ export function Header<R extends GridRowModel = GridRowModel>(props: HeaderProps
|
|
|
583
589
|
filterModel={filterModel}
|
|
584
590
|
onFilterModelChange={onFilterModelChange}
|
|
585
591
|
onOpenFilterPanel={onOpenFilterPanel}
|
|
592
|
+
localeText={localeText}
|
|
586
593
|
focusedField={focusedCell?.id === null && focusedCell.headerFilter ? focusedCell.field : null}
|
|
587
594
|
/>
|
|
588
595
|
)}
|
|
@@ -21,8 +21,9 @@ export function getHeaderColumnStyle<R extends GridRowModel>(
|
|
|
21
21
|
boxSizing: 'border-box',
|
|
22
22
|
position: pinnedPosition ? 'sticky' : 'relative',
|
|
23
23
|
};
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// Logical sides: `left` pinning sticks to the inline start (the right edge in a right-to-left grid).
|
|
25
|
+
if (pinnedPosition === 'left') style.insetInlineStart = pinnedOffset;
|
|
26
|
+
else if (pinnedPosition === 'right') style.insetInlineEnd = pinnedOffset;
|
|
26
27
|
return style;
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
height: var(--ogx-header-filter-height, 40px);
|
|
8
8
|
min-height: var(--ogx-header-filter-height, 40px);
|
|
9
9
|
background: var(--ogx-grid-header-background);
|
|
10
|
-
border-bottom:
|
|
10
|
+
border-bottom: var(--ogx-grid-row-divider-width) solid var(--ogx-grid-row-divider-color, var(--ogx-grid-border-color));
|
|
11
11
|
}
|
|
12
12
|
.ogx__header-filter-cell {
|
|
13
13
|
display: flex;
|
|
@@ -39,9 +39,15 @@
|
|
|
39
39
|
box-shadow: var(--ogx-grid-pinned-left-shadow, 4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
40
40
|
}
|
|
41
41
|
.ogx__header-filter-cell--pinned-right-first {
|
|
42
|
-
margin-
|
|
42
|
+
margin-inline-start: auto;
|
|
43
43
|
box-shadow: var(--ogx-grid-pinned-right-shadow, -4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
44
44
|
}
|
|
45
|
+
.ogx__header-filter-cell--pinned-left-last:dir(rtl) {
|
|
46
|
+
box-shadow: var(--ogx-grid-pinned-right-shadow, -4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
47
|
+
}
|
|
48
|
+
.ogx__header-filter-cell--pinned-right-first:dir(rtl) {
|
|
49
|
+
box-shadow: var(--ogx-grid-pinned-left-shadow, 4px 0 12px -4px rgba(0, 0, 0, 0.05));
|
|
50
|
+
}
|
|
45
51
|
|
|
46
52
|
/* Operator button: a compact symbol for the current operator; opens the operator menu. */
|
|
47
53
|
.ogx__header-filter-operator {
|
|
@@ -152,7 +158,7 @@
|
|
|
152
158
|
color: var(--ogx-color-primary);
|
|
153
159
|
font: inherit;
|
|
154
160
|
font-style: italic;
|
|
155
|
-
text-align:
|
|
161
|
+
text-align: start;
|
|
156
162
|
}
|
|
157
163
|
button.ogx__header-filter-custom {
|
|
158
164
|
cursor: pointer;
|
|
@@ -3,7 +3,6 @@ import type { GridColDef, GridFilterItem, GridFilterOperator } from '../../types
|
|
|
3
3
|
import { filterValueToInputText, NO_VALUE_OPERATORS } from '../../utils/filtering';
|
|
4
4
|
import {
|
|
5
5
|
HEADER_FILTER_DEBOUNCE_MS,
|
|
6
|
-
HEADER_FILTER_OPERATOR_LABELS,
|
|
7
6
|
HEADER_FILTER_OPERATOR_SYMBOLS,
|
|
8
7
|
buildHeaderFilterItem,
|
|
9
8
|
convertHeaderFilterValue,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
} from '../../utils/headerFilters';
|
|
14
13
|
import { Input } from '../ui/Input';
|
|
15
14
|
import { HeaderFilterOperatorMenu } from './HeaderFilterOperatorMenu';
|
|
15
|
+
import type { HeaderFilterLocale } from '../../utils/headerFilterLocale';
|
|
16
16
|
|
|
17
17
|
export interface HeaderFilterCellProps {
|
|
18
18
|
colDef: GridColDef;
|
|
@@ -25,6 +25,8 @@ export interface HeaderFilterCellProps {
|
|
|
25
25
|
/** Stores (or removes, with null) the cell's own filter item. Must keep its identity. */
|
|
26
26
|
onItemChange: (field: string, item: GridFilterItem | null) => void;
|
|
27
27
|
onOpenFilterPanel?: () => void;
|
|
28
|
+
/** The row's strings (`resolveHeaderFilterLocale`). */
|
|
29
|
+
locale: HeaderFilterLocale;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
interface ValueOption {
|
|
@@ -75,7 +77,7 @@ function ClearIcon() {
|
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
/** One cell of the header filter row: operator button, value control and clear button. */
|
|
78
|
-
export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex, onItemChange, onOpenFilterPanel }: HeaderFilterCellProps) {
|
|
80
|
+
export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex, onItemChange, onOpenFilterPanel, locale }: HeaderFilterCellProps) {
|
|
79
81
|
const label = colDef.headerName || colDef.field;
|
|
80
82
|
const item = state.kind === 'editable' ? state.item : undefined;
|
|
81
83
|
const operator: GridFilterOperator = item?.operator ?? getHeaderFilterDefaultOperator(colDef);
|
|
@@ -242,17 +244,17 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
242
244
|
className="ogx__header-filter-custom"
|
|
243
245
|
tabIndex={-1}
|
|
244
246
|
onClick={onOpenFilterPanel}
|
|
245
|
-
title=
|
|
247
|
+
title={locale.customTooltip}
|
|
246
248
|
>
|
|
247
|
-
|
|
249
|
+
{locale.custom}
|
|
248
250
|
</button>
|
|
249
251
|
) : (
|
|
250
|
-
<span className="ogx__header-filter-custom" title=
|
|
252
|
+
<span className="ogx__header-filter-custom" title={locale.customTooltip}>{locale.custom}</span>
|
|
251
253
|
);
|
|
252
254
|
} else {
|
|
253
255
|
let valueControl: React.ReactNode;
|
|
254
256
|
if (!showsValue) {
|
|
255
|
-
valueControl = <span className="ogx__header-filter-operator-label">{
|
|
257
|
+
valueControl = <span className="ogx__header-filter-operator-label">{locale.operator(operator)}</span>;
|
|
256
258
|
} else if (colDef.type === 'boolean') {
|
|
257
259
|
valueControl = (
|
|
258
260
|
<select
|
|
@@ -261,11 +263,11 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
261
263
|
tabIndex={-1}
|
|
262
264
|
value={item?.value == null || item.value === '' ? '' : String(item.value)}
|
|
263
265
|
onChange={(e) => setValue(e.target.value === '' ? '' : e.target.value === 'true')}
|
|
264
|
-
aria-label={
|
|
266
|
+
aria-label={locale.valueLabel(label)}
|
|
265
267
|
>
|
|
266
|
-
<option value="">
|
|
267
|
-
<option value="true">
|
|
268
|
-
<option value="false">
|
|
268
|
+
<option value="">{locale.any}</option>
|
|
269
|
+
<option value="true">{locale.yes}</option>
|
|
270
|
+
<option value="false">{locale.no}</option>
|
|
269
271
|
</select>
|
|
270
272
|
);
|
|
271
273
|
} else if (usesSelect) {
|
|
@@ -280,9 +282,9 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
280
282
|
const option = valueOptions.find(o => o.key === e.target.value);
|
|
281
283
|
setValue(convertHeaderFilterValue(option ? option.value : '', operator));
|
|
282
284
|
}}
|
|
283
|
-
aria-label={
|
|
285
|
+
aria-label={locale.valueLabel(label)}
|
|
284
286
|
>
|
|
285
|
-
<option value="">
|
|
287
|
+
<option value="">{locale.any}</option>
|
|
286
288
|
{valueOptions.map(o => <option key={o.key} value={o.key}>{o.label}</option>)}
|
|
287
289
|
</select>
|
|
288
290
|
);
|
|
@@ -298,11 +300,11 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
298
300
|
autoComplete="off"
|
|
299
301
|
value={draft ?? filterValueToInputText(item?.value, colDef.type)}
|
|
300
302
|
onChange={(e) => setDraft(e.target.value)}
|
|
301
|
-
aria-label={
|
|
303
|
+
aria-label={locale.valueLabel(label)}
|
|
302
304
|
/>
|
|
303
305
|
);
|
|
304
306
|
}
|
|
305
|
-
const operatorLabel =
|
|
307
|
+
const operatorLabel = locale.operator(operator);
|
|
306
308
|
content = (
|
|
307
309
|
<>
|
|
308
310
|
<button
|
|
@@ -312,7 +314,7 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
312
314
|
tabIndex={-1}
|
|
313
315
|
aria-haspopup="menu"
|
|
314
316
|
aria-expanded={menuAnchor !== null}
|
|
315
|
-
aria-label={
|
|
317
|
+
aria-label={locale.operatorButtonLabel(label, operatorLabel)}
|
|
316
318
|
title={operatorLabel}
|
|
317
319
|
onClick={() => (menuAnchor ? setMenuAnchor(null) : openMenu())}
|
|
318
320
|
>
|
|
@@ -324,8 +326,8 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
324
326
|
type="button"
|
|
325
327
|
className="ogx__header-filter-clear"
|
|
326
328
|
tabIndex={-1}
|
|
327
|
-
aria-label={
|
|
328
|
-
title=
|
|
329
|
+
aria-label={locale.clearLabel(label)}
|
|
330
|
+
title={locale.clearTooltip}
|
|
329
331
|
onClick={() => { clear(); focusCell(); }}
|
|
330
332
|
>
|
|
331
333
|
<ClearIcon />
|
|
@@ -335,6 +337,7 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
335
337
|
<HeaderFilterOperatorMenu
|
|
336
338
|
anchorEl={menuAnchor}
|
|
337
339
|
columnLabel={label}
|
|
340
|
+
locale={locale}
|
|
338
341
|
operators={getHeaderFilterOperators(colDef)}
|
|
339
342
|
current={operator}
|
|
340
343
|
onSelect={selectOperator}
|
|
@@ -358,7 +361,7 @@ export function HeaderFilterCell({ colDef, state, style, className, ariaColIndex
|
|
|
358
361
|
className={classNames}
|
|
359
362
|
style={style}
|
|
360
363
|
role="columnheader"
|
|
361
|
-
aria-label={
|
|
364
|
+
aria-label={locale.cellLabel(label)}
|
|
362
365
|
aria-colindex={ariaColIndex}
|
|
363
366
|
data-field={colDef.field}
|
|
364
367
|
tabIndex={-1}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
2
|
import ReactDOM from 'react-dom';
|
|
3
3
|
import type { GridFilterOperator } from '../../types';
|
|
4
|
-
import {
|
|
4
|
+
import type { HeaderFilterLocale } from '../../utils/headerFilterLocale';
|
|
5
5
|
import { getViewportHeight, getViewportWidth } from '../../utils/viewport';
|
|
6
6
|
|
|
7
7
|
export interface HeaderFilterOperatorMenuProps {
|
|
@@ -13,6 +13,7 @@ export interface HeaderFilterOperatorMenuProps {
|
|
|
13
13
|
onSelect: (operator: GridFilterOperator) => void;
|
|
14
14
|
/** `restoreFocus`: the menu was left from the keyboard or by choosing an item. */
|
|
15
15
|
onClose: (restoreFocus: boolean) => void;
|
|
16
|
+
locale: HeaderFilterLocale;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const HIDDEN_STYLE: React.CSSProperties = { position: 'fixed', zIndex: 1300, top: 0, left: 0, visibility: 'hidden' };
|
|
@@ -21,7 +22,7 @@ const itemsOf = (menu: HTMLElement | null): HTMLElement[] =>
|
|
|
21
22
|
menu ? Array.from(menu.querySelectorAll<HTMLElement>('[role="menuitemradio"]')) : [];
|
|
22
23
|
|
|
23
24
|
/** The operator menu of a header filter cell: a menu of radio items, portalled out of the header. */
|
|
24
|
-
export function HeaderFilterOperatorMenu({ anchorEl, columnLabel, operators, current, onSelect, onClose }: HeaderFilterOperatorMenuProps) {
|
|
25
|
+
export function HeaderFilterOperatorMenu({ anchorEl, columnLabel, operators, current, onSelect, onClose, locale }: HeaderFilterOperatorMenuProps) {
|
|
25
26
|
const menuRef = useRef<HTMLDivElement>(null);
|
|
26
27
|
const [style, setStyle] = useState<React.CSSProperties>(HIDDEN_STYLE);
|
|
27
28
|
|
|
@@ -102,7 +103,7 @@ export function HeaderFilterOperatorMenu({ anchorEl, columnLabel, operators, cur
|
|
|
102
103
|
className="ogx-column-menu ogx__header-filter-menu"
|
|
103
104
|
style={style}
|
|
104
105
|
role="menu"
|
|
105
|
-
aria-label={
|
|
106
|
+
aria-label={locale.operatorMenuLabel(columnLabel)}
|
|
106
107
|
onKeyDown={handleKeyDown}
|
|
107
108
|
>
|
|
108
109
|
{operators.map(op => (
|
|
@@ -115,7 +116,7 @@ export function HeaderFilterOperatorMenu({ anchorEl, columnLabel, operators, cur
|
|
|
115
116
|
className={`ogx-menu-item${op === current ? ' ogx-menu-item--active' : ''}`}
|
|
116
117
|
onClick={() => onSelect(op)}
|
|
117
118
|
>
|
|
118
|
-
{
|
|
119
|
+
{locale.operator(op)}
|
|
119
120
|
</button>
|
|
120
121
|
))}
|
|
121
122
|
</div>,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useCallback, useLayoutEffect, useRef } from 'react';
|
|
2
|
-
import type { GridColDef, GridColumnPinning, GridFilterItem, GridFilterModel } from '../../types';
|
|
2
|
+
import type { GridColDef, GridColumnPinning, GridFilterItem, GridFilterModel, GridLocaleText } from '../../types';
|
|
3
3
|
import { isColumnPinned, SYSTEM_COLUMN_WIDTH } from '../../utils/pinning';
|
|
4
4
|
import { CHECKBOX_FIELD, EXPAND_FIELD, REORDER_FIELD } from '../../utils/focus';
|
|
5
|
+
import { resolveHeaderFilterLocale } from '../../utils/headerFilterLocale';
|
|
5
6
|
import { getHeaderFilterState, hasHeaderFilter, setHeaderFilterItem } from '../../utils/headerFilters';
|
|
6
7
|
import { getHeaderColumnStyle } from '../Header/headerColumnStyle';
|
|
7
8
|
import { HeaderFilterCell } from './HeaderFilterCell';
|
|
@@ -27,6 +28,8 @@ export interface HeaderFilterRowProps {
|
|
|
27
28
|
onOpenFilterPanel?: () => void;
|
|
28
29
|
/** Field of the focused filter cell, or null. */
|
|
29
30
|
focusedField: string | null;
|
|
31
|
+
/** Translations of the row's strings. */
|
|
32
|
+
localeText?: GridLocaleText;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
function SystemFilterCell({ field, ariaColIndex, sticky, left, focused }: {
|
|
@@ -49,7 +52,7 @@ function SystemFilterCell({ field, ariaColIndex, sticky, left, focused }: {
|
|
|
49
52
|
minWidth: SYSTEM_COLUMN_WIDTH,
|
|
50
53
|
maxWidth: SYSTEM_COLUMN_WIDTH,
|
|
51
54
|
position: sticky ? 'sticky' : undefined,
|
|
52
|
-
|
|
55
|
+
insetInlineStart: sticky ? left : undefined,
|
|
53
56
|
}}
|
|
54
57
|
role="columnheader"
|
|
55
58
|
aria-colindex={ariaColIndex}
|
|
@@ -68,7 +71,7 @@ export function HeaderFilterRow(props: HeaderFilterRowProps) {
|
|
|
68
71
|
const {
|
|
69
72
|
columns, columnWidths, pinnedColumns, pinnedPositions, pinnedEdges, rowReordering, hasDetailPanel,
|
|
70
73
|
checkboxSelection, pinExpandColumn, pinCheckboxColumn, columnIndexMap, ariaRowIndex, filterModel,
|
|
71
|
-
onFilterModelChange, onOpenFilterPanel, focusedField,
|
|
74
|
+
onFilterModelChange, onOpenFilterPanel, focusedField, localeText,
|
|
72
75
|
} = props;
|
|
73
76
|
|
|
74
77
|
// Cells commit from timers and unmount cleanups: they read the newest model, and two commits
|
|
@@ -86,6 +89,8 @@ export function HeaderFilterRow(props: HeaderFilterRowProps) {
|
|
|
86
89
|
emit(next);
|
|
87
90
|
}, []);
|
|
88
91
|
|
|
92
|
+
const locale = resolveHeaderFilterLocale(localeText);
|
|
93
|
+
|
|
89
94
|
const reorderColIndex = rowReordering ? 1 : 0;
|
|
90
95
|
const expandColIndex = hasDetailPanel ? reorderColIndex + 1 : reorderColIndex;
|
|
91
96
|
const checkboxColIndex = checkboxSelection ? expandColIndex + 1 : expandColIndex;
|
|
@@ -149,6 +154,7 @@ export function HeaderFilterRow(props: HeaderFilterRowProps) {
|
|
|
149
154
|
ariaColIndex={ariaColIndex}
|
|
150
155
|
onItemChange={handleItemChange}
|
|
151
156
|
onOpenFilterPanel={onOpenFilterPanel}
|
|
157
|
+
locale={locale}
|
|
152
158
|
/>
|
|
153
159
|
);
|
|
154
160
|
})}
|
|
@@ -107,7 +107,7 @@ export function ListViewRow<R extends GridRowModel = GridRowModel>({
|
|
|
107
107
|
// (not a Tab stop: Enter or Alt+Arrow toggle the focused row).
|
|
108
108
|
<div
|
|
109
109
|
className="ogx-list-view__expand"
|
|
110
|
-
style={{
|
|
110
|
+
style={{ paddingInlineStart: (rowMeta.treeDepth ?? 0) * 16 }}
|
|
111
111
|
onClick={(e) => e.stopPropagation()}
|
|
112
112
|
onDoubleClick={(e) => e.stopPropagation()}
|
|
113
113
|
>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
font-size: var(--ogx-font-size-sm);
|
|
10
10
|
color: var(--ogx-grid-row-text);
|
|
11
11
|
min-height: 52px;
|
|
12
|
-
border-radius: 0 0 var(--ogx-border-radius-lg) var(--ogx-border-radius-lg);
|
|
12
|
+
border-radius: 0 0 var(--ogx-grid-border-radius, var(--ogx-border-radius-lg)) var(--ogx-grid-border-radius, var(--ogx-border-radius-lg));
|
|
13
13
|
}
|
|
14
14
|
.ogx-pagination__page-size {
|
|
15
15
|
display: flex;
|
|
@@ -89,3 +89,7 @@
|
|
|
89
89
|
order: 2;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
/* First / previous / next / last arrows point the way the pages run: mirrored right to left. */
|
|
93
|
+
.ogx-pagination__icon:dir(rtl) {
|
|
94
|
+
transform: scaleX(-1);
|
|
95
|
+
}
|
|
@@ -115,7 +115,7 @@ export function Pagination(props: PaginationProps) {
|
|
|
115
115
|
aria-label="Go to first page"
|
|
116
116
|
title="First page"
|
|
117
117
|
>
|
|
118
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
118
|
+
<svg className="ogx-pagination__icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
119
119
|
<path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6zM6 6h2v12H6z" />
|
|
120
120
|
</svg>
|
|
121
121
|
</Button>
|
|
@@ -129,7 +129,7 @@ export function Pagination(props: PaginationProps) {
|
|
|
129
129
|
aria-label="Go to previous page"
|
|
130
130
|
title="Previous page"
|
|
131
131
|
>
|
|
132
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
132
|
+
<svg className="ogx-pagination__icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
133
133
|
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
|
|
134
134
|
</svg>
|
|
135
135
|
</Button>
|
|
@@ -146,7 +146,7 @@ export function Pagination(props: PaginationProps) {
|
|
|
146
146
|
aria-label="Go to next page"
|
|
147
147
|
title="Next page"
|
|
148
148
|
>
|
|
149
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
149
|
+
<svg className="ogx-pagination__icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
150
150
|
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
|
|
151
151
|
</svg>
|
|
152
152
|
</Button>
|
|
@@ -160,7 +160,7 @@ export function Pagination(props: PaginationProps) {
|
|
|
160
160
|
aria-label="Go to last page"
|
|
161
161
|
title="Last page"
|
|
162
162
|
>
|
|
163
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
163
|
+
<svg className="ogx-pagination__icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
164
164
|
<path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6zM16 6h2v12h-2z" />
|
|
165
165
|
</svg>
|
|
166
166
|
</Button>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
.ogx__row {
|
|
2
2
|
display: flex;
|
|
3
3
|
align-items: stretch;
|
|
4
|
-
border-bottom:
|
|
4
|
+
border-bottom: var(--ogx-grid-row-divider-width) solid var(--ogx-grid-row-divider-color, var(--ogx-grid-border-color));
|
|
5
5
|
background: var(--ogx-grid-background);
|
|
6
6
|
position: relative;
|
|
7
7
|
min-height: var(--ogx-row-height);
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
}
|
|
95
95
|
.ogx__row--skeleton {
|
|
96
96
|
pointer-events: none;
|
|
97
|
-
border-bottom:
|
|
97
|
+
border-bottom: var(--ogx-grid-row-divider-width) solid var(--ogx-grid-row-divider-color, var(--ogx-grid-border-color));
|
|
98
98
|
background-color: var(--ogx-grid-background);
|
|
99
99
|
}
|
|
100
100
|
.ogx__row--skeleton .ogx__skeleton-cell {
|
|
@@ -300,7 +300,7 @@ function RowImpl<R extends GridRowModel = GridRowModel>(props: RowProps<R>) {
|
|
|
300
300
|
tabIndex={-1}
|
|
301
301
|
style={{
|
|
302
302
|
position: 'sticky',
|
|
303
|
-
|
|
303
|
+
insetInlineStart: 0,
|
|
304
304
|
zIndex: SYSTEM_CELL_Z_INDEX
|
|
305
305
|
}}
|
|
306
306
|
draggable={!!onDragStart}
|
|
@@ -326,7 +326,7 @@ function RowImpl<R extends GridRowModel = GridRowModel>(props: RowProps<R>) {
|
|
|
326
326
|
data-field="__expand_col__"
|
|
327
327
|
style={{
|
|
328
328
|
position: pinExpandColumn ? 'sticky' : undefined,
|
|
329
|
-
|
|
329
|
+
insetInlineStart: pinExpandColumn ? (rowReordering ? 48 : 0) : undefined,
|
|
330
330
|
zIndex: pinExpandColumn ? SYSTEM_CELL_Z_INDEX : undefined
|
|
331
331
|
}}
|
|
332
332
|
tabIndex={-1}
|
|
@@ -364,7 +364,7 @@ function RowImpl<R extends GridRowModel = GridRowModel>(props: RowProps<R>) {
|
|
|
364
364
|
data-field="__checkbox_col__"
|
|
365
365
|
style={{
|
|
366
366
|
position: pinCheckboxColumn ? 'sticky' : undefined,
|
|
367
|
-
|
|
367
|
+
insetInlineStart: pinCheckboxColumn ? ((rowReordering ? 48 : 0) + (hasDetailPanel && pinExpandColumn ? 48 : 0)) : undefined,
|
|
368
368
|
zIndex: pinCheckboxColumn ? SYSTEM_CELL_Z_INDEX : undefined
|
|
369
369
|
}}
|
|
370
370
|
tabIndex={-1}
|