@ornery/ui-grid-react 0.1.10 → 1.0.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/dist/index.js CHANGED
@@ -30,2163 +30,209 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- DEFAULT_GRID_LABELS: () => import_ui_grid_core4.DEFAULT_GRID_LABELS,
33
+ DEFAULT_GRID_LABELS: () => import_ui_grid_core.DEFAULT_GRID_LABELS,
34
34
  UiGrid: () => UiGrid,
35
- buildGridTemplateColumns: () => buildGridTemplateColumns,
36
- computeViewportHeightPx: () => computeViewportHeightPx,
37
- computeViewportRows: () => computeViewportRows,
38
- enableReactUiGridWasmEngine: () => enableReactUiGridWasmEngine,
39
- formatPaginationSummary: () => formatPaginationSummary,
35
+ datePickerCell: () => datePickerCell,
40
36
  mountUiGrid: () => mountUiGrid,
41
37
  mountUiGridCustomElement: () => mountUiGridCustomElement,
42
- orderVisibleColumns: () => orderVisibleColumns,
43
- registerReactUiGridWasmEngineFromModule: () => registerReactUiGridWasmEngineFromModule,
44
- resolveBenchmarkIterations: () => resolveBenchmarkIterations,
45
38
  styledCell: () => styledCell,
46
- updateUiGrid: () => updateUiGrid,
47
- useGridState: () => useGridState,
48
- useVirtualScroll: () => useVirtualScroll
39
+ updateUiGrid: () => updateUiGrid
49
40
  });
50
41
  module.exports = __toCommonJS(index_exports);
51
42
 
52
43
  // src/UiGrid.tsx
53
- var import_react3 = __toESM(require("react"));
54
-
55
- // src/useGridState.ts
56
- var import_react = require("react");
57
-
58
- // src/gridStateMath.ts
59
- var import_ui_grid_core = require("@ornery/ui-grid-core");
60
- function orderVisibleColumns(columns, order) {
61
- return [...columns].filter((column) => column.visible !== false).sort((left, right) => order.indexOf(left.name) - order.indexOf(right.name));
62
- }
63
- function buildGridTemplateColumns(columns) {
64
- return columns.map((column) => (0, import_ui_grid_core.gridColumnWidth)(column)).join(" ");
65
- }
66
- function resolveBenchmarkIterations(iterations, configuredIterations) {
67
- return Math.max(1, iterations ?? configuredIterations ?? 25);
68
- }
69
- function formatPaginationSummary(totalItems, firstRowIndex, lastRowIndex) {
70
- if (totalItems === 0) {
71
- return "0-0 of 0";
72
- }
73
- return `${firstRowIndex + 1}-${lastRowIndex + 1} of ${totalItems}`;
74
- }
75
- function computeViewportHeightPx(viewportHeight, autoViewportHeight) {
76
- return `${viewportHeight ?? autoViewportHeight ?? 560}px`;
77
- }
78
- function computeViewportRows(viewportHeight, rowHeight) {
79
- return Math.max(1, Math.ceil((viewportHeight ?? 560) / (rowHeight ?? 44)));
80
- }
81
-
82
- // src/useGridState.ts
83
- var import_ui_grid_core2 = require("@ornery/ui-grid-core");
84
- function escapeCssSelectorValue(value) {
85
- const nativeEscape = globalThis.CSS?.escape;
86
- if (typeof nativeEscape === "function") {
87
- return nativeEscape(value);
88
- }
89
- let output = "";
90
- for (let index = 0; index < value.length; index += 1) {
91
- const codePoint = value.charCodeAt(index);
92
- const character = value.charAt(index);
93
- if (codePoint === 0) {
94
- output += "\uFFFD";
95
- continue;
96
- }
97
- const isControlCharacter = codePoint >= 1 && codePoint <= 31 || codePoint === 127;
98
- const startsWithDigit = index === 0 && codePoint >= 48 && codePoint <= 57;
99
- const secondCharDigitAfterHyphen = index === 1 && codePoint >= 48 && codePoint <= 57 && value.charCodeAt(0) === 45;
100
- if (isControlCharacter || startsWithDigit || secondCharDigitAfterHyphen) {
101
- output += `\\${codePoint.toString(16)} `;
102
- continue;
103
- }
104
- if (index === 0 && value.length === 1 && codePoint === 45) {
105
- output += `\\${character}`;
106
- continue;
107
- }
108
- const isSafeCharacter = codePoint >= 128 || codePoint === 45 || codePoint === 95 || codePoint >= 48 && codePoint <= 57 || codePoint >= 65 && codePoint <= 90 || codePoint >= 97 && codePoint <= 122;
109
- output += isSafeCharacter ? character : `\\${character}`;
110
- }
111
- return output;
112
- }
113
- function useGridState(options, onRegisterApi) {
114
- const [activeFilters, setActiveFilters] = (0, import_react.useState)({});
115
- const [groupByColumns, setGroupByColumns] = (0, import_react.useState)([]);
116
- const [collapsedGroups, setCollapsedGroups] = (0, import_react.useState)({});
117
- const [columnOrder, setColumnOrder] = (0, import_react.useState)([]);
118
- const [hiddenRowReasons, setHiddenRowReasons] = (0, import_react.useState)({});
119
- const [sortState, setSortState] = (0, import_react.useState)({
120
- columnName: null,
121
- direction: import_ui_grid_core2.SORT_DIRECTIONS.none
122
- });
123
- const [focusedCell, setFocusedCell] = (0, import_react.useState)(null);
124
- const [editingCell, setEditingCell] = (0, import_react.useState)(null);
125
- const [editingValue, setEditingValue] = (0, import_react.useState)("");
126
- const [expandedRows, setExpandedRows] = (0, import_react.useState)({});
127
- const [expandedTreeRows, setExpandedTreeRows] = (0, import_react.useState)({});
128
- const [currentPage, setCurrentPage] = (0, import_react.useState)(1);
129
- const [pageSize, setPageSize] = (0, import_react.useState)(0);
130
- const [benchmarkResult, setBenchmarkResult] = (0, import_react.useState)(null);
131
- const [infiniteScrollState, setInfiniteScrollState] = (0, import_react.useState)({
132
- scrollUp: false,
133
- scrollDown: true,
134
- dataLoading: false,
135
- previousVisibleRows: 0
136
- });
137
- const [autoViewportHeight, setAutoViewportHeight] = (0, import_react.useState)(null);
138
- const [pinnedColumns, setPinnedColumns] = (0, import_react.useState)({});
139
- const [columnWidthOverrides, setColumnWidthOverrides] = (0, import_react.useState)({});
140
- const gridContainerRef = (0, import_react.useRef)(null);
141
- const initializedGridIdRef = (0, import_react.useRef)(null);
142
- const lastCanvasHeightRef = (0, import_react.useRef)(0);
143
- const lastGridHeightRef = (0, import_react.useRef)(0);
144
- const lastGridWidthRef = (0, import_react.useRef)(0);
145
- const scrollEndHandleRef = (0, import_react.useRef)(void 0);
146
- const scrollingRef = (0, import_react.useRef)(false);
147
- const editorFocusTokenRef = (0, import_react.useRef)(0);
148
- const renderedCellFocusTokenRef = (0, import_react.useRef)(0);
149
- const activeFiltersRef = (0, import_react.useRef)(activeFilters);
150
- activeFiltersRef.current = activeFilters;
151
- const groupByColumnsRef = (0, import_react.useRef)(groupByColumns);
152
- groupByColumnsRef.current = groupByColumns;
153
- const collapsedGroupsRef = (0, import_react.useRef)(collapsedGroups);
154
- collapsedGroupsRef.current = collapsedGroups;
155
- const columnOrderRef = (0, import_react.useRef)(columnOrder);
156
- columnOrderRef.current = columnOrder;
157
- const hiddenRowReasonsRef = (0, import_react.useRef)(hiddenRowReasons);
158
- hiddenRowReasonsRef.current = hiddenRowReasons;
159
- const sortStateRef = (0, import_react.useRef)(sortState);
160
- sortStateRef.current = sortState;
161
- const focusedCellRef = (0, import_react.useRef)(focusedCell);
162
- focusedCellRef.current = focusedCell;
163
- const editingCellRef = (0, import_react.useRef)(editingCell);
164
- editingCellRef.current = editingCell;
165
- const editingValueRef = (0, import_react.useRef)(editingValue);
166
- editingValueRef.current = editingValue;
167
- const expandedRowsRef = (0, import_react.useRef)(expandedRows);
168
- expandedRowsRef.current = expandedRows;
169
- const expandedTreeRowsRef = (0, import_react.useRef)(expandedTreeRows);
170
- expandedTreeRowsRef.current = expandedTreeRows;
171
- const pinnedColumnsRef = (0, import_react.useRef)(pinnedColumns);
172
- pinnedColumnsRef.current = pinnedColumns;
173
- const currentPageRef = (0, import_react.useRef)(currentPage);
174
- currentPageRef.current = currentPage;
175
- const pageSizeRef = (0, import_react.useRef)(pageSize);
176
- pageSizeRef.current = pageSize;
177
- const setEditingCellState = (0, import_react.useCallback)((nextEditingCell) => {
178
- editingCellRef.current = nextEditingCell;
179
- setEditingCell(nextEditingCell);
180
- }, []);
181
- const setEditingValueState = (0, import_react.useCallback)((nextEditingValue) => {
182
- editingValueRef.current = nextEditingValue;
183
- setEditingValue(nextEditingValue);
184
- }, []);
185
- const infiniteScrollStateRef = (0, import_react.useRef)(infiniteScrollState);
186
- infiniteScrollStateRef.current = infiniteScrollState;
187
- const optionsRef = (0, import_react.useRef)(options);
44
+ var import_react = __toESM(require("react"));
45
+ var import_react_dom = require("react-dom");
46
+ var import_ui_grid_vanilla = require("@ornery/ui-grid-vanilla");
47
+ var import_jsx_runtime = require("react/jsx-runtime");
48
+ var TAG_NAME = "ui-grid-element";
49
+ var definePromise = null;
50
+ function UiGrid({ options, onRegisterApi, cellRenderers, className }) {
51
+ const containerRef = import_react.default.useRef(null);
52
+ const elementRef = import_react.default.useRef(null);
53
+ const [slots, setSlots] = import_react.default.useState(/* @__PURE__ */ new Map());
54
+ const cellRenderersRef = import_react.default.useRef(cellRenderers);
55
+ cellRenderersRef.current = cellRenderers;
56
+ const onRegisterApiRef = import_react.default.useRef(onRegisterApi);
57
+ onRegisterApiRef.current = onRegisterApi;
58
+ const optionsRef = import_react.default.useRef(options);
188
59
  optionsRef.current = options;
189
- const rowSize = options.rowHeight ?? 44;
190
- const visibleColumns = (0, import_react.useMemo)(() => {
191
- const orderedColumns = orderVisibleColumns(options.columnDefs, columnOrder);
192
- const applyWidthOverrides = (columns) => columns.map((col) => {
193
- const override = columnWidthOverrides[col.name];
194
- return override == null ? col : { ...col, width: override };
195
- });
196
- const pinnedEntries = Object.entries(pinnedColumns);
197
- if (pinnedEntries.length === 0) {
198
- return applyWidthOverrides(orderedColumns);
199
- }
200
- const columnByName = new Map(orderedColumns.map((column) => [column.name, column]));
201
- const pinnedLeft = pinnedEntries.filter(([, direction]) => direction === "left").map(([columnName]) => columnByName.get(columnName)).filter((column) => column !== void 0);
202
- const pinnedRight = pinnedEntries.filter(([, direction]) => direction === "right").map(([columnName]) => columnByName.get(columnName)).filter((column) => column !== void 0);
203
- const centerColumns = orderedColumns.filter(
204
- (column) => pinnedColumns[column.name] === void 0
205
- );
206
- return applyWidthOverrides([...pinnedLeft, ...centerColumns, ...pinnedRight]);
207
- }, [options.columnDefs, columnOrder, pinnedColumns, columnWidthOverrides]);
208
- const visibleColumnsRef = (0, import_react.useRef)(visibleColumns);
209
- visibleColumnsRef.current = visibleColumns;
210
- const pipeline = (0, import_react.useMemo)(() => {
211
- return import_ui_grid_core2.defaultGridEngine.buildPipeline({
212
- options,
213
- columns: visibleColumns,
214
- activeFilters,
215
- sortState,
216
- groupByColumns,
217
- collapsedGroups,
218
- hiddenRowReasons,
219
- expandedRows,
220
- expandedTreeRows,
221
- currentPage,
222
- pageSize,
223
- rowSize
224
- });
225
- }, [
226
- options,
227
- visibleColumns,
228
- activeFilters,
229
- sortState,
230
- groupByColumns,
231
- collapsedGroups,
232
- hiddenRowReasons,
233
- expandedRows,
234
- expandedTreeRows,
235
- currentPage,
236
- pageSize,
237
- rowSize
238
- ]);
239
- const pipelineRef = (0, import_react.useRef)(pipeline);
240
- pipelineRef.current = pipeline;
241
- const labels = (0, import_react.useMemo)(() => (0, import_ui_grid_core2.resolveGridLabels)(options.labels), [options.labels]);
242
- const gridTemplateColumns = (0, import_react.useMemo)(
243
- () => buildGridTemplateColumns(visibleColumns),
244
- [visibleColumns]
245
- );
246
- const isPinningEnabledFn = (0, import_react.useCallback)(() => {
247
- return (0, import_ui_grid_core2.isPinningEnabled)(optionsRef.current);
248
- }, []);
249
- const isColumnPinnableFn = (0, import_react.useCallback)((column) => {
250
- return (0, import_ui_grid_core2.isColumnPinnable)(optionsRef.current, column);
251
- }, []);
252
- const isPinnedFn = (0, import_react.useCallback)((column) => {
253
- return pinnedColumnsRef.current[column.name] !== void 0;
254
- }, []);
255
- const pinnedOffsetFn = (0, import_react.useCallback)((column) => {
256
- return (0, import_ui_grid_core2.computePinnedOffset)(visibleColumnsRef.current, pinnedColumnsRef.current, column);
257
- }, []);
258
- const resolveRowId = (0, import_react.useCallback)((row) => {
259
- return (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
260
- }, []);
261
- const buildRowsFromData = (0, import_react.useCallback)((data) => {
262
- return (0, import_ui_grid_core2.buildGridRows)(
263
- { ...optionsRef.current, data },
264
- optionsRef.current.rowHeight ?? 44,
265
- hiddenRowReasonsRef.current,
266
- expandedRowsRef.current
267
- );
268
- }, []);
269
- const findRowById = (0, import_react.useCallback)(
270
- (rowId) => {
271
- return (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), rowId);
272
- },
273
- [buildRowsFromData]
274
- );
275
- const canExpandRowsFn = (0, import_react.useCallback)(() => {
276
- return import_ui_grid_core2.FEATURE_EXPANDABLE && (0, import_ui_grid_core2.canGridExpandRows)(optionsRef.current);
277
- }, []);
278
- const effectivePageSizeFn = (0, import_react.useCallback)((totalItems) => {
279
- return (0, import_ui_grid_core2.getEffectivePageSize)(optionsRef.current, pageSizeRef.current, totalItems);
280
- }, []);
281
- const getCurrentPageValueFn = (0, import_react.useCallback)((totalItems) => {
282
- const ti = totalItems ?? pipelineRef.current.totalItems;
283
- return (0, import_ui_grid_core2.getCurrentPageValue)(
284
- optionsRef.current,
285
- currentPageRef.current,
286
- ti,
287
- pageSizeRef.current
288
- );
289
- }, []);
290
- const getTotalPagesValueFn = (0, import_react.useCallback)((totalItems) => {
291
- const ti = totalItems ?? pipelineRef.current.totalItems;
292
- return (0, import_ui_grid_core2.getTotalPagesValue)(optionsRef.current, ti, pageSizeRef.current);
293
- }, []);
294
- const getFirstRowIndexValueFn = (0, import_react.useCallback)((totalItems) => {
295
- const ti = totalItems ?? pipelineRef.current.totalItems;
296
- return (0, import_ui_grid_core2.getFirstRowIndexValue)(
297
- optionsRef.current,
298
- currentPageRef.current,
299
- ti,
300
- pageSizeRef.current
301
- );
302
- }, []);
303
- const getLastRowIndexValueFn = (0, import_react.useCallback)((totalItems) => {
304
- const ti = totalItems ?? pipelineRef.current.totalItems;
305
- return (0, import_ui_grid_core2.getLastRowIndexValue)(
306
- optionsRef.current,
307
- currentPageRef.current,
308
- ti,
309
- pageSizeRef.current
310
- );
311
- }, []);
312
- const isCellEditable = (0, import_react.useCallback)(
313
- (row, column, triggerEvent) => {
314
- if (!import_ui_grid_core2.FEATURE_CELL_EDIT) return false;
315
- const editable = column.enableCellEdit ?? optionsRef.current.enableCellEdit ?? false;
316
- if (!editable) return false;
317
- const condition = column.cellEditableCondition ?? optionsRef.current.cellEditableCondition ?? true;
318
- if (typeof condition === "boolean") return condition;
319
- const context = {
320
- row: row.entity,
321
- column,
322
- rowIndex: row.index,
323
- triggerEvent
324
- };
325
- return condition(context);
326
- },
327
- []
328
- );
329
- const shouldEditOnFocusFn = (0, import_react.useCallback)((column) => {
330
- return column.enableCellEditOnFocus ?? optionsRef.current.enableCellEditOnFocus ?? false;
331
- }, []);
332
- const focusRenderedCell = (0, import_react.useCallback)((position) => {
333
- const focusToken = ++renderedCellFocusTokenRef.current;
334
- const selector = `.body-cell[data-row-id="${escapeCssSelectorValue(position.rowId)}"][data-col-name="${escapeCssSelectorValue(position.columnName)}"]`;
335
- const doFocus = (retry = true) => {
336
- if (focusToken !== renderedCellFocusTokenRef.current) return;
337
- const container = gridContainerRef.current;
338
- if (!container) return;
339
- const target = container.querySelector(selector);
340
- if (!target) {
341
- if (retry) requestAnimationFrame(() => doFocus(false));
342
- return;
343
- }
344
- target.focus({ preventScroll: true });
345
- if (retry && container.ownerDocument.activeElement !== target) {
346
- requestAnimationFrame(() => doFocus(false));
60
+ const currentSlotColumnsRef = import_react.default.useRef([]);
61
+ import_react.default.useEffect(() => {
62
+ const container = containerRef.current;
63
+ if (!container) return;
64
+ let el = null;
65
+ let disposed = false;
66
+ const mount = async () => {
67
+ if (!definePromise) {
68
+ definePromise = (0, import_ui_grid_vanilla.defineStandaloneUiGridElement)(TAG_NAME);
347
69
  }
70
+ await definePromise;
71
+ if (disposed) return;
72
+ el = document.createElement(TAG_NAME);
73
+ el.style.display = "block";
74
+ el.style.height = "100%";
75
+ el.style.minHeight = "0";
76
+ elementRef.current = el;
77
+ container.appendChild(el);
78
+ el.addEventListener("cellSlotsChanged", handleCellSlotsChanged);
79
+ applyOptions(el, optionsRef.current);
348
80
  };
349
- doFocus(true);
350
- queueMicrotask(() => doFocus(true));
351
- }, []);
352
- const focusEditorInput = (0, import_react.useCallback)((focusToken) => {
353
- if (focusToken !== editorFocusTokenRef.current) return;
354
- const ec = editingCellRef.current;
355
- if (!ec) return;
356
- const selector = `.cell-editor[data-row-id="${escapeCssSelectorValue(ec.rowId)}"][data-col-name="${escapeCssSelectorValue(ec.columnName)}"]`;
357
- const doFocus = (retry = true) => {
358
- if (focusToken !== editorFocusTokenRef.current) return;
359
- const currentEc = editingCellRef.current;
360
- if (!currentEc || currentEc.rowId !== ec.rowId || currentEc.columnName !== ec.columnName)
361
- return;
362
- const container = gridContainerRef.current;
363
- if (!container) return;
364
- const input = container.querySelector(selector);
365
- if (!input) {
366
- if (retry) requestAnimationFrame(() => doFocus(false));
367
- return;
81
+ void mount();
82
+ return () => {
83
+ disposed = true;
84
+ if (el) {
85
+ el.removeEventListener("cellSlotsChanged", handleCellSlotsChanged);
86
+ el.remove();
87
+ elementRef.current = null;
368
88
  }
369
- input.focus();
370
- input.select();
89
+ setSlots(/* @__PURE__ */ new Map());
371
90
  };
372
- doFocus(true);
373
91
  }, []);
374
- const gridApiRef = (0, import_react.useRef)(null);
375
- if (!gridApiRef.current) {
376
- const bindings = {
377
- refresh: () => setActiveFilters((current) => ({ ...current })),
378
- getVisibleRows: () => pipelineRef.current.visibleRows,
379
- setRowInvisible: (row, reason = "user") => {
380
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
381
- setHiddenRowReasons((current) => (0, import_ui_grid_core2.addGridRowInvisibleReason)(current, rowId, reason));
382
- },
383
- clearRowInvisible: (row, reason = "user") => {
384
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
385
- setHiddenRowReasons((current) => (0, import_ui_grid_core2.clearGridRowInvisibleReason)(current, rowId, reason));
386
- },
387
- setFilter: (columnName, value) => {
388
- setActiveFilters((current) => {
389
- const next = { ...current, [columnName]: value };
390
- activeFiltersRef.current = next;
391
- queueMicrotask(() => gridApiRef.current.core.raise.filterChanged(next));
392
- return next;
393
- });
394
- },
395
- clearAllFilters: () => {
396
- const nextFilters = {};
397
- activeFiltersRef.current = nextFilters;
398
- setActiveFilters(nextFilters);
399
- queueMicrotask(() => gridApiRef.current.core.raise.filterChanged(nextFilters));
400
- },
401
- sortColumn: (columnName, direction) => {
402
- (0, import_ui_grid_core2.sortGridColumnCommand)(gridApiRef.current, (s) => setSortState(s), columnName, direction);
403
- },
404
- moveColumn: (fromIndex, toIndex) => {
405
- (0, import_ui_grid_core2.moveGridColumnCommand)(
406
- gridApiRef.current,
407
- import_ui_grid_core2.FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
408
- (updater) => setColumnOrder((current) => updater(current)),
409
- fromIndex,
410
- toIndex
411
- );
412
- },
413
- toggleGrouping: (columnName) => {
414
- if (!(import_ui_grid_core2.FEATURE_GROUPING && (0, import_ui_grid_core2.isGridGroupingEnabled)(optionsRef.current))) return;
415
- const current = groupByColumnsRef.current;
416
- const next = current.includes(columnName) ? current.filter((n) => n !== columnName) : [...current, columnName];
417
- groupByColumnsRef.current = next;
418
- setGroupByColumns(next);
419
- gridApiRef.current.core.raise.groupingChanged(next);
420
- },
421
- clearGrouping: () => {
422
- (0, import_ui_grid_core2.clearGridGroupingCommand)(
423
- gridApiRef.current,
424
- (grouping) => setGroupByColumns(grouping),
425
- false
426
- );
427
- },
428
- benchmark: (iterations) => {
429
- return runBenchmarkFn(iterations);
430
- },
431
- exportCsv: () => {
432
- exportCsvFn();
433
- },
434
- paginationGetPage: () => getCurrentPageValueFn(),
435
- paginationGetTotalPages: () => getTotalPagesValueFn(),
436
- paginationGetFirstRowIndex: () => getFirstRowIndexValueFn(),
437
- paginationGetLastRowIndex: () => getLastRowIndexValueFn(),
438
- paginationNextPage: () => seekPageFn(getCurrentPageValueFn() + 1),
439
- paginationPreviousPage: () => seekPageFn(getCurrentPageValueFn() - 1),
440
- paginationSeek: (page) => seekPageFn(page),
441
- paginationSetPageSize: (ps) => setPaginationPageSizeFn(ps),
442
- toggleRowExpansion: (row) => toggleRowExpansionByRefFn(row),
443
- expandAllRows: () => expandAllRowsFn(),
444
- collapseAllRows: () => {
445
- (0, import_ui_grid_core2.collapseAllGridRowsCommand)((e) => setExpandedRows(e));
446
- },
447
- toggleAllRows: () => toggleAllRowsFn(),
448
- treeExpandAllRows: () => {
449
- (0, import_ui_grid_core2.expandAllGridTreeRowsCommand)(
450
- (data) => buildRowsFromData(data),
451
- optionsRef.current.data,
452
- (e) => setExpandedTreeRows(e)
453
- );
454
- },
455
- treeCollapseAllRows: () => {
456
- (0, import_ui_grid_core2.collapseAllGridTreeRowsCommand)((e) => setExpandedTreeRows(e));
457
- },
458
- treeToggleRow: (row) => toggleTreeRowByRefFn(row),
459
- treeExpandRow: (row) => expandTreeRowByRefFn(row),
460
- treeCollapseRow: (row) => collapseTreeRowByRefFn(row),
461
- treeGetRowChildren: (row) => {
462
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
463
- return buildRowsFromData(optionsRef.current.data).filter((r) => r.parentId === rowId);
464
- },
465
- treeGetState: () => expandedTreeRowsRef.current,
466
- treeSetState: (state) => setExpandedTreeRows({ ...state }),
467
- infiniteScrollDataLoaded: (scrollUp, scrollDown) => {
468
- return (0, import_ui_grid_core2.completeGridInfiniteScrollDataLoadCommand)(
469
- infiniteScrollStateRef.current,
470
- (s) => setInfiniteScrollState(s),
471
- scrollUp ?? infiniteScrollStateRef.current.scrollUp,
472
- scrollDown ?? infiniteScrollStateRef.current.scrollDown
473
- );
474
- },
475
- infiniteScrollReset: (scrollUp, scrollDown) => {
476
- (0, import_ui_grid_core2.resetGridInfiniteScrollCommand)(
477
- (s) => setInfiniteScrollState(s),
478
- scrollUp ?? infiniteScrollStateRef.current.scrollUp,
479
- scrollDown ?? infiniteScrollStateRef.current.scrollDown
480
- );
481
- },
482
- infiniteScrollSaveScrollPercentage: () => {
483
- (0, import_ui_grid_core2.saveGridInfiniteScrollPercentageCommand)(
484
- infiniteScrollStateRef.current,
485
- pipelineRef.current.visibleRows.length,
486
- (s) => setInfiniteScrollState(s)
487
- );
488
- },
489
- infiniteScrollDataRemovedTop: (scrollUp, scrollDown) => {
490
- (0, import_ui_grid_core2.resetGridInfiniteScrollCommand)(
491
- (s) => setInfiniteScrollState(s),
492
- scrollUp ?? infiniteScrollStateRef.current.scrollUp,
493
- scrollDown ?? infiniteScrollStateRef.current.scrollDown
494
- );
495
- },
496
- infiniteScrollDataRemovedBottom: (scrollUp, scrollDown) => {
497
- (0, import_ui_grid_core2.resetGridInfiniteScrollCommand)(
498
- (s) => setInfiniteScrollState(s),
499
- scrollUp ?? infiniteScrollStateRef.current.scrollUp,
500
- scrollDown ?? infiniteScrollStateRef.current.scrollDown
501
- );
502
- },
503
- infiniteScrollSetDirections: (scrollUp, scrollDown) => {
504
- (0, import_ui_grid_core2.setGridInfiniteScrollDirectionsCommand)(
505
- infiniteScrollStateRef.current,
506
- (s) => setInfiniteScrollState(s),
507
- scrollUp,
508
- scrollDown
509
- );
510
- },
511
- saveState: () => {
512
- return (0, import_ui_grid_core2.buildGridSavedState)({
513
- columnOrder: columnOrderRef.current,
514
- activeFilters: activeFiltersRef.current,
515
- sortState: sortStateRef.current,
516
- groupByColumns: groupByColumnsRef.current,
517
- currentPage: currentPageRef.current,
518
- pageSize: pageSizeRef.current,
519
- totalItems: pipelineRef.current.totalItems,
520
- expandedRows: expandedRowsRef.current,
521
- expandedTreeRows: expandedTreeRowsRef.current,
522
- pinnedColumns: pinnedColumnsRef.current
523
- });
524
- },
525
- restoreState: (state) => {
526
- (0, import_ui_grid_core2.restoreGridStateCommand)(gridApiRef.current, state, {
527
- setColumnOrder: (order) => setColumnOrder(order),
528
- setActiveFilters: (filters) => setActiveFilters(filters),
529
- setSortState: (s) => setSortState(s),
530
- setGroupByColumns: (grouping) => setGroupByColumns(grouping),
531
- setCurrentPage: (page) => setCurrentPage(page),
532
- setPageSize: (ps) => setPageSize(ps),
533
- setExpandedRows: (e) => setExpandedRows(e),
534
- setExpandedTreeRows: (e) => setExpandedTreeRows(e),
535
- setPinnedColumns: (p) => setPinnedColumns(p),
536
- getEffectivePageSize: () => effectivePageSizeFn(pipelineRef.current.totalItems)
92
+ import_react.default.useEffect(() => {
93
+ const el = elementRef.current;
94
+ if (!el) return;
95
+ applyOptions(el, options);
96
+ }, [options]);
97
+ import_react.default.useEffect(() => {
98
+ if (slots.size === 0 || !options.data) return;
99
+ const dataById = /* @__PURE__ */ new Map();
100
+ for (const row of options.data) {
101
+ const id = String(row["id"] ?? "");
102
+ if (id) dataById.set(id, row);
103
+ }
104
+ let changed = false;
105
+ const nextSlots = new Map(slots);
106
+ for (const [key, entry] of nextSlots) {
107
+ const row = dataById.get(entry.rowId);
108
+ if (!row) continue;
109
+ const col = options.columnDefs?.find((c) => c.name === entry.columnName);
110
+ const value = col?.field ? getNestedValue(row, col.field) : row[entry.columnName];
111
+ if (entry.context.value !== value || entry.context.row !== row) {
112
+ nextSlots.set(key, {
113
+ ...entry,
114
+ context: { ...entry.context, $implicit: value, value, row }
537
115
  });
538
- },
539
- beginCellEdit: (row, columnName, triggerEvent) => {
540
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
541
- const gridRow = (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), rowId);
542
- const column = visibleColumnsRef.current.find((c) => c.name === columnName);
543
- if (!gridRow || !column || !isCellEditable(gridRow, column, triggerEvent)) return;
544
- startCellEditFn(gridRow, column, triggerEvent);
545
- },
546
- endCellEdit: () => commitCellEditFn(),
547
- cancelCellEdit: () => cancelCellEditFn(),
548
- getEditingCell: () => editingCellRef.current,
549
- pinColumn: (columnName, direction) => {
550
- (0, import_ui_grid_core2.pinGridColumnCommand)(
551
- gridApiRef.current,
552
- isPinningEnabledFn(),
553
- (v) => setPinnedColumns(v),
554
- () => pinnedColumnsRef.current,
555
- columnName,
556
- direction
557
- );
116
+ changed = true;
558
117
  }
559
- };
560
- gridApiRef.current = (0, import_ui_grid_core2.createGridApi)(bindings);
561
- }
562
- const gridApi = gridApiRef.current;
563
- const seekPageFn = (0, import_react.useCallback)(
564
- (page) => {
565
- (0, import_ui_grid_core2.seekGridPaginationCommand)(
566
- gridApiRef.current,
567
- (nextPage) => setCurrentPage(nextPage),
568
- () => getTotalPagesValueFn(),
569
- () => effectivePageSizeFn(pipelineRef.current.totalItems),
570
- page
571
- );
572
- },
573
- [getTotalPagesValueFn, effectivePageSizeFn]
574
- );
575
- const togglePinFn = (0, import_react.useCallback)((column) => {
576
- const current = pinnedColumnsRef.current[column.name];
577
- const next = current === "left" ? "right" : current === "right" ? "none" : "left";
578
- (0, import_ui_grid_core2.pinGridColumnCommand)(
579
- gridApiRef.current,
580
- isPinningEnabledFn(),
581
- (v) => setPinnedColumns(v),
582
- () => pinnedColumnsRef.current,
583
- column.name,
584
- next
585
- );
586
- }, []);
587
- const setPaginationPageSizeFn = (0, import_react.useCallback)((ps) => {
588
- (0, import_ui_grid_core2.setGridPaginationPageSizeCommand)(
589
- gridApiRef.current,
590
- (nextPageSize) => setPageSize(nextPageSize),
591
- (nextPage) => setCurrentPage(nextPage),
592
- ps
593
- );
594
- }, []);
595
- const toggleRowExpansionByRefFn = (0, import_react.useCallback)(
596
- (row) => {
597
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
598
- (0, import_ui_grid_core2.toggleGridRowExpansionCommand)(
599
- gridApiRef.current,
600
- import_ui_grid_core2.FEATURE_EXPANDABLE && (0, import_ui_grid_core2.canGridExpandRows)(optionsRef.current),
601
- expandedRowsRef.current,
602
- rowId,
603
- (e) => setExpandedRows(e),
604
- (resolvedRowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), resolvedRowId)
605
- );
606
- },
607
- [buildRowsFromData]
608
- );
609
- const expandAllRowsFn = (0, import_react.useCallback)(() => {
610
- if (!(0, import_ui_grid_core2.canGridExpandRows)(optionsRef.current)) return;
611
- (0, import_ui_grid_core2.expandAllGridRowsCommand)(
612
- (data) => buildRowsFromData(data),
613
- optionsRef.current.data,
614
- (e) => setExpandedRows(e)
615
- );
616
- }, [buildRowsFromData]);
617
- const toggleAllRowsFn = (0, import_react.useCallback)(() => {
618
- const allExpanded = (0, import_ui_grid_core2.areAllGridRowsExpanded)(
619
- buildRowsFromData(optionsRef.current.data),
620
- expandedRowsRef.current
621
- );
622
- if (allExpanded) {
623
- (0, import_ui_grid_core2.collapseAllGridRowsCommand)((e) => setExpandedRows(e));
624
- } else {
625
- expandAllRowsFn();
626
118
  }
627
- }, [buildRowsFromData, expandAllRowsFn]);
628
- const toggleTreeRowByRefFn = (0, import_react.useCallback)(
629
- (row) => {
630
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
631
- (0, import_ui_grid_core2.toggleGridTreeRowCommand)(
632
- gridApiRef.current,
633
- expandedTreeRowsRef.current,
634
- rowId,
635
- (e) => setExpandedTreeRows(e),
636
- (resolvedRowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), resolvedRowId)
637
- );
638
- },
639
- [buildRowsFromData]
640
- );
641
- const expandTreeRowByRefFn = (0, import_react.useCallback)(
642
- (row) => {
643
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
644
- (0, import_ui_grid_core2.setGridTreeRowExpandedCommand)(
645
- gridApiRef.current,
646
- expandedTreeRowsRef.current,
647
- rowId,
648
- true,
649
- (e) => setExpandedTreeRows(e),
650
- (resolvedRowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), resolvedRowId)
651
- );
652
- },
653
- [buildRowsFromData]
654
- );
655
- const collapseTreeRowByRefFn = (0, import_react.useCallback)(
656
- (row) => {
657
- const rowId = (0, import_ui_grid_core2.resolveGridRowId)(optionsRef.current, row);
658
- (0, import_ui_grid_core2.setGridTreeRowExpandedCommand)(
659
- gridApiRef.current,
660
- expandedTreeRowsRef.current,
661
- rowId,
662
- false,
663
- (e) => setExpandedTreeRows(e),
664
- (resolvedRowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), resolvedRowId)
665
- );
666
- },
667
- [buildRowsFromData]
668
- );
669
- const startCellEditFn = (0, import_react.useCallback)(
670
- (row, column, triggerEvent, initialValue) => {
671
- const currentValue = (0, import_ui_grid_core2.getCellValue)(row.entity, column);
672
- const focusToken = ++editorFocusTokenRef.current;
673
- const ec = (0, import_ui_grid_core2.beginGridCellEditCommand)(
674
- gridApiRef.current,
675
- {
676
- setFocusedCell: (fc) => setFocusedCell(fc),
677
- setEditingCell: setEditingCellState,
678
- setEditingValue: setEditingValueState
679
- },
680
- row,
681
- column,
682
- currentValue,
683
- triggerEvent,
684
- initialValue
685
- );
686
- if (ec) {
687
- queueMicrotask(() => focusEditorInput(focusToken));
688
- }
689
- },
690
- [focusEditorInput, setEditingCellState, setEditingValueState]
691
- );
692
- const commitCellEditFn = (0, import_react.useCallback)(
693
- (direction, restoreFocus = true) => {
694
- const result = (0, import_ui_grid_core2.commitGridCellEditCommand)(gridApiRef.current, {
695
- getEditingCell: () => editingCellRef.current,
696
- getEditingValue: () => editingValueRef.current,
697
- setEditingCell: setEditingCellState,
698
- setEditingValue: setEditingValueState,
699
- findRowById: (rowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), rowId),
700
- findColumnByName: (columnName) => visibleColumnsRef.current.find((c) => c.name === columnName),
701
- parseEditedValue: (column, value, oldValue) => (0, import_ui_grid_core2.parseGridEditedValue)(column, value, oldValue),
702
- setCellValue: (rowEntity, column, value) => {
703
- const fieldPath = column.editModelField ?? column.field ?? column.name;
704
- (0, import_ui_grid_core2.setPathValue)(rowEntity, fieldPath, value);
119
+ if (changed) setSlots(nextSlots);
120
+ }, [options.data]);
121
+ function applyOptions(el, opts) {
122
+ const renderers2 = cellRenderersRef.current;
123
+ const cellSlotColumns = [];
124
+ if (renderers2 && opts.columnDefs) {
125
+ for (const col of opts.columnDefs) {
126
+ if (renderers2[col.name]) {
127
+ cellSlotColumns.push(col.name);
705
128
  }
706
- });
707
- if (!result.committed || !result.row || !result.column || !result.focusTarget) return;
708
- editorFocusTokenRef.current += 1;
709
- if (direction) {
710
- const moved = moveFocusFn(result.row, result.column, direction);
711
- if (!moved) focusRenderedCell(result.focusTarget);
712
- } else if (restoreFocus) {
713
- focusRenderedCell(result.focusTarget);
714
129
  }
715
- },
716
- [buildRowsFromData, focusRenderedCell, setEditingCellState, setEditingValueState]
717
- );
718
- const cancelCellEditFn = (0, import_react.useCallback)(() => {
719
- const hadEditingCell = editingCellRef.current !== null;
720
- const result = (0, import_ui_grid_core2.cancelGridCellEditCommand)(gridApiRef.current, {
721
- getEditingCell: () => editingCellRef.current,
722
- setEditingCell: setEditingCellState,
723
- setEditingValue: setEditingValueState,
724
- findRowById: (rowId) => (0, import_ui_grid_core2.findGridRowById)(buildRowsFromData(optionsRef.current.data), rowId),
725
- findColumnByName: (columnName) => visibleColumnsRef.current.find((c) => c.name === columnName)
726
- });
727
- if (!hadEditingCell) return;
728
- editorFocusTokenRef.current += 1;
729
- if (result.focusTarget) focusRenderedCell(result.focusTarget);
730
- }, [buildRowsFromData, focusRenderedCell, setEditingCellState, setEditingValueState]);
731
- const moveFocusFn = (0, import_react.useCallback)(
732
- (row, column, direction, triggerEvent) => {
733
- const nextCell = (0, import_ui_grid_core2.findNextGridCell)({
734
- rows: pipelineRef.current.displayItems.filter((item) => item.kind === "row").map((item) => item.row),
735
- columns: visibleColumnsRef.current,
736
- rowId: row.id,
737
- columnName: column.name,
738
- direction
739
- });
740
- if (!nextCell) return false;
741
- setFocusedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
742
- focusRenderedCell({ rowId: nextCell.row.id, columnName: nextCell.column.name });
743
- if (shouldEditOnFocusFn(nextCell.column) && isCellEditable(nextCell.row, nextCell.column, triggerEvent)) {
744
- startCellEditFn(nextCell.row, nextCell.column, triggerEvent);
745
- }
746
- return true;
747
- },
748
- [focusRenderedCell, isCellEditable, shouldEditOnFocusFn, startCellEditFn]
749
- );
750
- const runBenchmarkFn = (0, import_react.useCallback)((iterations) => {
751
- const safeIterations = resolveBenchmarkIterations(
752
- iterations,
753
- optionsRef.current.benchmark?.iterations
754
- );
755
- const startedAt = performance.now();
756
- let lastResult = import_ui_grid_core2.defaultGridEngine.buildPipeline({
757
- options: optionsRef.current,
758
- columns: visibleColumnsRef.current,
759
- activeFilters: activeFiltersRef.current,
760
- sortState: sortStateRef.current,
761
- groupByColumns: groupByColumnsRef.current,
762
- collapsedGroups: collapsedGroupsRef.current,
763
- hiddenRowReasons: hiddenRowReasonsRef.current,
764
- expandedRows: expandedRowsRef.current,
765
- expandedTreeRows: expandedTreeRowsRef.current,
766
- currentPage: currentPageRef.current,
767
- pageSize: pageSizeRef.current,
768
- rowSize: optionsRef.current.rowHeight ?? 44
769
- });
770
- for (let i = 1; i < safeIterations; i++) {
771
- lastResult = import_ui_grid_core2.defaultGridEngine.buildPipeline({
772
- options: optionsRef.current,
773
- columns: visibleColumnsRef.current,
774
- activeFilters: activeFiltersRef.current,
775
- sortState: sortStateRef.current,
776
- groupByColumns: groupByColumnsRef.current,
777
- collapsedGroups: collapsedGroupsRef.current,
778
- hiddenRowReasons: hiddenRowReasonsRef.current,
779
- expandedRows: expandedRowsRef.current,
780
- expandedTreeRows: expandedTreeRowsRef.current,
781
- currentPage: currentPageRef.current,
782
- pageSize: pageSizeRef.current,
783
- rowSize: optionsRef.current.rowHeight ?? 44
784
- });
785
- }
786
- const totalMs = performance.now() - startedAt;
787
- const result = {
788
- iterations: safeIterations,
789
- totalMs,
790
- averageMs: totalMs / safeIterations,
791
- visibleRows: lastResult.visibleRows.length,
792
- renderedItems: lastResult.displayItems.length
793
- };
794
- setBenchmarkResult(result);
795
- (0, import_ui_grid_core2.raiseGridBenchmarkComplete)(gridApiRef.current, result);
796
- return result;
797
- }, []);
798
- const exportCsvFn = (0, import_react.useCallback)(() => {
799
- if (!import_ui_grid_core2.FEATURE_CSV_EXPORT) return;
800
- const columns = visibleColumnsRef.current;
801
- const csv = (0, import_ui_grid_core2.exportCsvRows)(columns, pipelineRef.current.visibleRows);
802
- (0, import_ui_grid_core2.downloadGridCsvFile)(csv, `${(0, import_ui_grid_core2.sanitizeDownloadFilename)(optionsRef.current.id)}.csv`);
803
- }, []);
804
- (0, import_react.useEffect)(() => {
805
- if (initializedGridIdRef.current === options.id) return;
806
- initializedGridIdRef.current = options.id;
807
- setActiveFilters({});
808
- setHiddenRowReasons({});
809
- setCollapsedGroups({});
810
- setFocusedCell(null);
811
- setEditingCellState(null);
812
- setEditingValueState("");
813
- setExpandedRows({});
814
- setExpandedTreeRows({});
815
- setColumnOrder(options.columnDefs.map((column) => column.name));
816
- setGroupByColumns(options.grouping?.groupBy ?? []);
817
- setPinnedColumns((0, import_ui_grid_core2.buildInitialPinnedState)(options.columnDefs));
818
- setCurrentPage(options.paginationCurrentPage ?? 1);
819
- setPageSize((0, import_ui_grid_core2.getEffectivePageSize)(options, 0, options.data.length));
820
- setInfiniteScrollState({
821
- scrollUp: options.infiniteScrollUp === true,
822
- scrollDown: options.infiniteScrollDown !== false,
823
- dataLoading: false,
824
- previousVisibleRows: 0
825
- });
826
- const initialSort = options.columnDefs.find(
827
- (column) => column.sort?.direction && !column.sort.ignoreSort
828
- );
829
- setSortState({
830
- columnName: initialSort?.name ?? null,
831
- direction: initialSort?.sort?.direction ?? import_ui_grid_core2.SORT_DIRECTIONS.none
832
- });
833
- onRegisterApi?.(gridApi);
834
- (0, import_ui_grid_core2.raiseGridRenderingComplete)(gridApi);
835
- }, [options.id]);
836
- (0, import_react.useEffect)(() => {
837
- (0, import_ui_grid_core2.raiseGridRowsRendered)(gridApi, pipeline.visibleRows);
838
- (0, import_ui_grid_core2.raiseGridRowsVisibleChanged)(gridApi, pipeline.visibleRows);
839
- const newHeight = pipeline.displayItems.length * rowSize;
840
- if (newHeight !== lastCanvasHeightRef.current) {
841
- (0, import_ui_grid_core2.raiseGridCanvasHeightChanged)(gridApi, lastCanvasHeightRef.current, newHeight);
842
- lastCanvasHeightRef.current = newHeight;
843
130
  }
844
- }, [pipeline, gridApi, rowSize]);
845
- (0, import_react.useEffect)(() => {
846
- if (!import_ui_grid_core2.FEATURE_AUTO_RESIZE) return;
847
- const container = gridContainerRef.current;
848
- if (!container) return;
849
- const observer = (0, import_ui_grid_core2.observeGridHostSize)(container, ({ height: nextHeight, width: nextWidth }) => {
850
- if (nextHeight === lastGridHeightRef.current && nextWidth === lastGridWidthRef.current)
851
- return;
852
- (0, import_ui_grid_core2.raiseGridDimensionChanged)(
853
- gridApi,
854
- lastGridHeightRef.current,
855
- lastGridWidthRef.current,
856
- nextHeight,
857
- nextWidth
858
- );
859
- lastGridHeightRef.current = nextHeight;
860
- lastGridWidthRef.current = nextWidth;
861
- if (!options.viewportHeight && nextHeight > 0) {
862
- setAutoViewportHeight(nextHeight);
863
- }
864
- });
865
- if (!observer) return;
866
- return () => observer.disconnect();
867
- }, [options.enableAutoResize, options.viewportHeight, gridApi]);
868
- const totalRows = pipeline.totalItems;
869
- const visibleRowCount = pipeline.visibleRows.length;
870
- const displayItems = pipeline.displayItems;
871
- const virtualizationEnabled = pipeline.virtualizationEnabled;
872
- const pipelineMsVal = pipeline.pipelineMs;
873
- const paginationCurrentPage = getCurrentPageValueFn();
874
- const paginationTotalPages = getTotalPagesValueFn();
875
- const paginationSelectedPageSize = effectivePageSizeFn(pipeline.totalItems);
876
- const viewportHeightPx = computeViewportHeightPx(options.viewportHeight, autoViewportHeight);
877
- const headerLabelFn = (0, import_react.useCallback)((column) => (0, import_ui_grid_core2.headerLabel)(column), []);
878
- const isGroupItemFn = (0, import_react.useCallback)(
879
- (item) => item.kind === "group",
880
- []
881
- );
882
- const isExpandableItemFn = (0, import_react.useCallback)(
883
- (item) => item.kind === "expandable",
884
- []
885
- );
886
- const isRowItemFn = (0, import_react.useCallback)((item) => item.kind === "row", []);
887
- const isOddStripedRowFn = (0, import_react.useCallback)(
888
- (item) => item.kind === "row" && item.visibleIndex % 2 === 0,
889
- []
890
- );
891
- const sortDirectionFn = (0, import_react.useCallback)((column) => {
892
- return sortStateRef.current.columnName === column.name ? sortStateRef.current.direction : import_ui_grid_core2.SORT_DIRECTIONS.none;
893
- }, []);
894
- const sortButtonLabelFn = (0, import_react.useCallback)(
895
- (column) => {
896
- return (0, import_ui_grid_core2.gridSortButtonLabel)(sortDirectionFn(column), labels);
897
- },
898
- [labels, sortDirectionFn]
899
- );
900
- const sortAriaSortFn = (0, import_react.useCallback)(
901
- (column) => {
902
- return (0, import_ui_grid_core2.gridSortAriaSort)(sortDirectionFn(column));
903
- },
904
- [sortDirectionFn]
905
- );
906
- const groupingButtonLabelFn = (0, import_react.useCallback)(
907
- (column) => {
908
- return (0, import_ui_grid_core2.gridGroupingButtonLabel)(
909
- (0, import_ui_grid_core2.isGridColumnGrouped)(groupByColumnsRef.current, column),
910
- labels
911
- );
912
- },
913
- [labels]
914
- );
915
- const filterValueFn = (0, import_react.useCallback)((columnName) => {
916
- return activeFiltersRef.current[columnName] ?? "";
917
- }, []);
918
- const filterPlaceholderFn = (0, import_react.useCallback)(
919
- (column) => {
920
- return (0, import_ui_grid_core2.gridFilterPlaceholder)((0, import_ui_grid_core2.isGridColumnFilterable)(optionsRef.current, column), labels);
921
- },
922
- [labels]
923
- );
924
- const isFilterInputDisabledFn = (0, import_react.useCallback)((column) => {
925
- return !(0, import_ui_grid_core2.isGridColumnFilterable)(optionsRef.current, column);
926
- }, []);
927
- const groupDisclosureLabelFn = (0, import_react.useCallback)(
928
- (item) => {
929
- return (0, import_ui_grid_core2.gridGroupDisclosureLabel)(item.collapsed, labels);
930
- },
931
- [labels]
932
- );
933
- const cellContextFn = (0, import_react.useCallback)(
934
- (row, column) => {
935
- return (0, import_ui_grid_core2.buildGridCellContext)(row, column);
936
- },
937
- []
938
- );
939
- const displayValueFn = (0, import_react.useCallback)(
940
- (row, column) => {
941
- return (0, import_ui_grid_core2.formatGridCellDisplayValue)(cellContextFn(row, column));
942
- },
943
- [cellContextFn]
944
- );
945
- const isFocusedCellFn = (0, import_react.useCallback)((row, column) => {
946
- return (0, import_ui_grid_core2.isGridCellPosition)(focusedCellRef.current, row.id, column.name);
947
- }, []);
948
- const isFocusedRowFn = (0, import_react.useCallback)((row) => {
949
- return focusedCellRef.current?.rowId === row.id || editingCellRef.current?.rowId === row.id;
950
- }, []);
951
- const isEditingCellFn = (0, import_react.useCallback)((row, column) => {
952
- return (0, import_ui_grid_core2.isGridCellPosition)(editingCellRef.current, row.id, column.name);
953
- }, []);
954
- const editorInputTypeFn = (0, import_react.useCallback)((column) => {
955
- return (0, import_ui_grid_core2.gridEditorInputType)(column);
956
- }, []);
957
- const expandedContextFn = (0, import_react.useCallback)(
958
- (row) => {
959
- return {
960
- $implicit: row.entity,
961
- row: row.entity,
962
- rowIndex: row.index,
963
- expanded: true,
964
- ...optionsRef.current.expandableRowScope ?? {}
965
- };
966
- },
967
- []
968
- );
969
- const columnWidthFn = (0, import_react.useCallback)((column) => (0, import_ui_grid_core2.gridColumnWidth)(column), []);
970
- const isColumnSortableFn = (0, import_react.useCallback)((column) => {
971
- return (0, import_ui_grid_core2.isGridColumnSortable)(optionsRef.current, column);
972
- }, []);
973
- const isColumnFilterableFn = (0, import_react.useCallback)((column) => {
974
- return (0, import_ui_grid_core2.isGridColumnFilterable)(optionsRef.current, column);
975
- }, []);
976
- const cellIndentFn = (0, import_react.useCallback)((row, column) => {
977
- return (0, import_ui_grid_core2.gridCellIndent)(optionsRef.current, visibleColumnsRef.current, row, column);
978
- }, []);
979
- const treeToggleLabelFn = (0, import_react.useCallback)(
980
- (row) => {
981
- return (0, import_ui_grid_core2.gridTreeToggleLabelForRow)(expandedTreeRowsRef.current, row, labels);
982
- },
983
- [labels]
984
- );
985
- const isTreeRowExpandedFn = (0, import_react.useCallback)((row) => {
986
- return (0, import_ui_grid_core2.isGridTreeRowExpanded)(expandedTreeRowsRef.current, row);
987
- }, []);
988
- const expandToggleLabelFn = (0, import_react.useCallback)(
989
- (row) => {
990
- return (0, import_ui_grid_core2.gridExpandToggleLabelForRow)(row, labels);
991
- },
992
- [labels]
993
- );
994
- const isGroupedFn = (0, import_react.useCallback)((column) => {
995
- return (0, import_ui_grid_core2.isGridColumnGrouped)(groupByColumnsRef.current, column);
996
- }, []);
997
- const showTreeToggleFn = (0, import_react.useCallback)((row, column) => {
998
- return (0, import_ui_grid_core2.shouldShowGridTreeToggle)(optionsRef.current, visibleColumnsRef.current, row, column);
999
- }, []);
1000
- const showExpandToggleFn = (0, import_react.useCallback)((row, column) => {
1001
- return (0, import_ui_grid_core2.shouldShowGridExpandToggle)(optionsRef.current, visibleColumnsRef.current, column);
1002
- }, []);
1003
- const showPaginationControlsFn = (0, import_react.useCallback)(() => {
1004
- return import_ui_grid_core2.FEATURE_PAGINATION && (0, import_ui_grid_core2.shouldShowGridPaginationControls)(optionsRef.current);
1005
- }, []);
1006
- const paginationSummaryFn = (0, import_react.useCallback)(() => {
1007
- const ti = pipelineRef.current.totalItems;
1008
- return formatPaginationSummary(ti, getFirstRowIndexValueFn(ti), getLastRowIndexValueFn(ti));
1009
- }, [getFirstRowIndexValueFn, getLastRowIndexValueFn]);
1010
- const pageSizeOptionsFn = (0, import_react.useCallback)(() => {
1011
- return optionsRef.current.paginationPageSizes ?? [];
1012
- }, []);
1013
- const isGroupingEnabledFn = (0, import_react.useCallback)(() => {
1014
- return import_ui_grid_core2.FEATURE_GROUPING && (0, import_ui_grid_core2.isGridGroupingEnabled)(optionsRef.current);
1015
- }, []);
1016
- const isFilteringEnabledFn = (0, import_react.useCallback)(() => {
1017
- return import_ui_grid_core2.FEATURE_FILTERING && (0, import_ui_grid_core2.isGridFilteringEnabled)(optionsRef.current);
1018
- }, []);
1019
- const toggleSortFn = (0, import_react.useCallback)((column) => {
1020
- if (!import_ui_grid_core2.FEATURE_SORTING || !(0, import_ui_grid_core2.isGridColumnSortable)(optionsRef.current, column)) return;
1021
- const currentDirection = sortStateRef.current.columnName === column.name ? sortStateRef.current.direction : import_ui_grid_core2.SORT_DIRECTIONS.none;
1022
- const nextDirection = currentDirection === import_ui_grid_core2.SORT_DIRECTIONS.none ? import_ui_grid_core2.SORT_DIRECTIONS.asc : currentDirection === import_ui_grid_core2.SORT_DIRECTIONS.asc ? import_ui_grid_core2.SORT_DIRECTIONS.desc : import_ui_grid_core2.SORT_DIRECTIONS.none;
1023
- (0, import_ui_grid_core2.applyGridSortStateCommand)(gridApiRef.current, (state) => setSortState(state), {
1024
- columnName: nextDirection === import_ui_grid_core2.SORT_DIRECTIONS.none ? null : column.name,
1025
- direction: nextDirection
1026
- });
1027
- }, []);
1028
- const updateFilterFn = (0, import_react.useCallback)((columnName, value) => {
1029
- (0, import_ui_grid_core2.updateGridFilterCommand)(
1030
- gridApiRef.current,
1031
- (updater) => setActiveFilters((current) => updater(current)),
1032
- () => activeFiltersRef.current,
1033
- columnName,
1034
- value
1035
- );
1036
- }, []);
1037
- const clearAllFiltersFn = (0, import_react.useCallback)(() => {
1038
- (0, import_ui_grid_core2.clearGridFiltersCommand)(gridApiRef.current, (filters) => setActiveFilters(filters));
1039
- }, []);
1040
- const toggleGroupingFn = (0, import_react.useCallback)((column, event) => {
1041
- event?.stopPropagation();
1042
- if (!(import_ui_grid_core2.FEATURE_GROUPING && (0, import_ui_grid_core2.isGridGroupingEnabled)(optionsRef.current))) return;
1043
- const current = groupByColumnsRef.current;
1044
- const next = current.includes(column.name) ? current.filter((n) => n !== column.name) : [...current, column.name];
1045
- groupByColumnsRef.current = next;
1046
- setGroupByColumns(next);
1047
- gridApiRef.current.core.raise.groupingChanged(next);
1048
- }, []);
1049
- const toggleGroupFn = (0, import_react.useCallback)((item) => {
1050
- setCollapsedGroups((current) => ({
1051
- ...current,
1052
- [item.id]: !current[item.id]
1053
- }));
1054
- }, []);
1055
- const focusCellFn = (0, import_react.useCallback)(
1056
- (row, column, triggerEvent) => {
1057
- const nextFocusResult = (0, import_ui_grid_core2.buildGridFocusCellResult)({
1058
- currentFocusedCell: focusedCellRef.current,
1059
- currentEditingCell: editingCellRef.current,
1060
- rowId: row.id,
1061
- columnName: column.name,
1062
- shouldEditOnFocus: shouldEditOnFocusFn(column),
1063
- isCellEditable: isCellEditable(row, column, triggerEvent)
1064
- });
1065
- setFocusedCell(nextFocusResult.focusedCell);
1066
- if (nextFocusResult.shouldBeginEdit) {
1067
- startCellEditFn(row, column, triggerEvent);
1068
- }
1069
- },
1070
- [isCellEditable, shouldEditOnFocusFn, startCellEditFn]
1071
- );
1072
- const handleCellKeyDownFn = (0, import_react.useCallback)(
1073
- (row, column, event) => {
1074
- if ((0, import_ui_grid_core2.isGridNavigationKey)(event.key)) {
1075
- setFocusedCell({ rowId: row.id, columnName: column.name });
1076
- } else {
1077
- focusCellFn(row, column, event.nativeEvent);
1078
- }
1079
- switch (event.key) {
1080
- case "ArrowLeft":
1081
- event.preventDefault();
1082
- event.stopPropagation();
1083
- moveFocusFn(row, column, "left", event.nativeEvent);
1084
- return;
1085
- case "ArrowRight":
1086
- event.preventDefault();
1087
- event.stopPropagation();
1088
- moveFocusFn(row, column, "right", event.nativeEvent);
1089
- return;
1090
- case "ArrowUp":
1091
- event.preventDefault();
1092
- event.stopPropagation();
1093
- moveFocusFn(row, column, "up", event.nativeEvent);
1094
- return;
1095
- case "ArrowDown":
1096
- event.preventDefault();
1097
- event.stopPropagation();
1098
- moveFocusFn(row, column, "down", event.nativeEvent);
1099
- return;
1100
- case "Tab":
1101
- event.preventDefault();
1102
- event.stopPropagation();
1103
- moveFocusFn(row, column, event.shiftKey ? "left" : "right", event.nativeEvent);
1104
- return;
1105
- case "Enter":
1106
- event.preventDefault();
1107
- event.stopPropagation();
1108
- moveFocusFn(row, column, event.shiftKey ? "up" : "down", event.nativeEvent);
1109
- return;
1110
- case "F2":
1111
- event.preventDefault();
1112
- event.stopPropagation();
1113
- if (isCellEditable(row, column, event.nativeEvent)) {
1114
- startCellEditFn(row, column, event.nativeEvent);
1115
- }
1116
- return;
1117
- case "Backspace":
1118
- case "Delete":
1119
- if (isCellEditable(row, column, event.nativeEvent)) {
1120
- event.preventDefault();
1121
- event.stopPropagation();
1122
- startCellEditFn(row, column, event.nativeEvent, "");
1123
- }
1124
- return;
1125
- default:
1126
- break;
1127
- }
1128
- if ((0, import_ui_grid_core2.isPrintableGridKey)(event.key, event.ctrlKey, event.metaKey, event.altKey) && isCellEditable(row, column, event.nativeEvent)) {
1129
- event.preventDefault();
1130
- event.stopPropagation();
1131
- startCellEditFn(row, column, event.nativeEvent, event.key);
1132
- }
1133
- },
1134
- [focusCellFn, moveFocusFn, isCellEditable, startCellEditFn]
1135
- );
1136
- const handleCellDoubleClickFn = (0, import_react.useCallback)(
1137
- (row, column, event) => {
1138
- focusCellFn(row, column, event.nativeEvent);
1139
- if (isCellEditable(row, column, event.nativeEvent)) {
1140
- startCellEditFn(row, column, event.nativeEvent);
1141
- }
1142
- },
1143
- [focusCellFn, isCellEditable, startCellEditFn]
1144
- );
1145
- const updateEditingValueFn = (0, import_react.useCallback)((value) => {
1146
- setEditingValueState(value);
1147
- }, [setEditingValueState]);
1148
- const handleEditorKeyDownFn = (0, import_react.useCallback)(
1149
- (event) => {
1150
- if (event.key === "Escape") {
1151
- event.preventDefault();
1152
- event.stopPropagation();
1153
- cancelCellEditFn();
1154
- return;
1155
- }
1156
- if (event.key === "Enter") {
1157
- event.preventDefault();
1158
- event.stopPropagation();
1159
- commitCellEditFn(event.shiftKey ? "up" : "down");
1160
- return;
1161
- }
1162
- if (event.key === "Tab") {
1163
- event.preventDefault();
1164
- event.stopPropagation();
1165
- commitCellEditFn(event.shiftKey ? "left" : "right");
1166
- return;
1167
- }
1168
- if (event.key === "ArrowUp" || event.key === "ArrowDown") {
1169
- event.preventDefault();
1170
- event.stopPropagation();
1171
- commitCellEditFn(event.key === "ArrowUp" ? "up" : "down");
1172
- }
1173
- },
1174
- [cancelCellEditFn, commitCellEditFn]
1175
- );
1176
- const handleEditorBlurFn = (0, import_react.useCallback)(
1177
- (event) => {
1178
- const ec = editingCellRef.current;
1179
- const target = event.target;
1180
- if (!ec || !target) return;
1181
- if (target.dataset["rowId"] !== ec.rowId || target.dataset["colName"] !== ec.columnName)
1182
- return;
1183
- commitCellEditFn(void 0, false);
1184
- },
1185
- [commitCellEditFn]
1186
- );
1187
- const toggleRowExpansionFn = (0, import_react.useCallback)(
1188
- (row, event) => {
1189
- event?.stopPropagation();
1190
- toggleRowExpansionByRefFn(row);
1191
- },
1192
- [toggleRowExpansionByRefFn]
1193
- );
1194
- const toggleTreeRowFn = (0, import_react.useCallback)(
1195
- (row, event) => {
1196
- event?.stopPropagation();
1197
- toggleTreeRowByRefFn(row);
1198
- },
1199
- [toggleTreeRowByRefFn]
1200
- );
1201
- const moveColumnFn = (0, import_react.useCallback)((fromIndex, toIndex) => {
1202
- (0, import_ui_grid_core2.moveGridColumnCommand)(
1203
- gridApiRef.current,
1204
- import_ui_grid_core2.FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
1205
- (updater) => setColumnOrder((current) => updater(current)),
1206
- fromIndex,
1207
- toIndex
1208
- );
1209
- }, []);
1210
- const moveVisibleColumnFn = (0, import_react.useCallback)((columnName, targetColumnName) => {
1211
- (0, import_ui_grid_core2.moveGridVisibleColumnCommand)(
1212
- gridApiRef.current,
1213
- import_ui_grid_core2.FEATURE_COLUMN_MOVING && optionsRef.current.enableColumnMoving === true,
1214
- columnOrderRef.current,
1215
- visibleColumnsRef.current.map((column) => column.name),
1216
- columnName,
1217
- targetColumnName,
1218
- (order) => setColumnOrder(order)
1219
- );
1220
- }, []);
1221
- const nextPageFn = (0, import_react.useCallback)(() => {
1222
- seekPageFn(getCurrentPageValueFn() + 1);
1223
- }, [seekPageFn, getCurrentPageValueFn]);
1224
- const previousPageFn = (0, import_react.useCallback)(() => {
1225
- seekPageFn(getCurrentPageValueFn() - 1);
1226
- }, [seekPageFn, getCurrentPageValueFn]);
1227
- const onPageSizeChangeFn = (0, import_react.useCallback)(
1228
- (value) => {
1229
- setPaginationPageSizeFn(Number(value));
1230
- },
1231
- [setPaginationPageSizeFn]
1232
- );
1233
- const canResizeColumnsFn = (0, import_react.useCallback)(() => {
1234
- return optionsRef.current.enableColumnResizing !== false;
1235
- }, []);
1236
- const setColumnWidthOverrideFn = (0, import_react.useCallback)((columnName, widthPx) => {
1237
- const nextWidth = `${Math.max(88, Math.round(widthPx))}px`;
1238
- setColumnWidthOverrides((current) => ({ ...current, [columnName]: nextWidth }));
1239
- }, []);
1240
- const measureAutoColumnWidthFn = (0, import_react.useCallback)((columnName) => {
1241
- const container = gridContainerRef.current;
1242
- if (container == null) return 176;
1243
- const escaped = CSS.escape ? CSS.escape(columnName) : columnName.replace(/([\\".#:[\](){}+~> ])/g, "\\$1");
1244
- const selectors = [
1245
- `.header-cell[data-col-name="${escaped}"]`,
1246
- `.filter-cell[data-col-name="${escaped}"]`,
1247
- `.body-cell[data-col-name="${escaped}"] .cell-shell`
1248
- ];
1249
- let maxWidth = 0;
1250
- for (const selector of selectors) {
1251
- const elements = container.querySelectorAll(selector);
1252
- for (const element of elements) {
1253
- maxWidth = Math.max(maxWidth, element.scrollWidth);
131
+ const wrappedOptions = {
132
+ ...opts,
133
+ onRegisterApi: (api) => {
134
+ onRegisterApiRef.current?.(api);
135
+ opts.onRegisterApi?.(api);
1254
136
  }
1255
- }
1256
- return maxWidth + 12;
1257
- }, []);
1258
- const handleHeaderResizeMouseDownFn = (0, import_react.useCallback)(
1259
- (column, event) => {
1260
- if (!canResizeColumnsFn()) return;
1261
- event.preventDefault();
1262
- event.stopPropagation();
1263
- const headerCell = event.currentTarget.closest(".header-cell");
1264
- if (headerCell == null) return;
1265
- const startX = event.clientX;
1266
- const startWidth = headerCell.getBoundingClientRect().width;
1267
- let lastWidth = startWidth;
1268
- const handleMove = (moveEvent) => {
1269
- lastWidth = Math.max(88, startWidth + (moveEvent.clientX - startX));
1270
- const widthStr = `${Math.round(lastWidth)}px`;
1271
- const newTemplate = buildGridTemplateColumns(
1272
- visibleColumnsRef.current.map(
1273
- (c) => c.name === column.name ? { ...c, width: widthStr } : c
1274
- )
1275
- );
1276
- gridContainerRef.current?.querySelectorAll(".header-grid, .filter-grid, .body-grid").forEach((el) => {
1277
- el.style.gridTemplateColumns = newTemplate;
1278
- });
1279
- };
1280
- const handleUp = () => {
1281
- window.removeEventListener("mousemove", handleMove);
1282
- window.removeEventListener("mouseup", handleUp);
1283
- setColumnWidthOverrideFn(column.name, lastWidth);
1284
- };
1285
- window.addEventListener("mousemove", handleMove);
1286
- window.addEventListener("mouseup", handleUp);
1287
- },
1288
- [canResizeColumnsFn, setColumnWidthOverrideFn]
1289
- );
1290
- const autoSizeColumnFn = (0, import_react.useCallback)(
1291
- (column, event) => {
1292
- if (!canResizeColumnsFn()) return;
1293
- event.preventDefault();
1294
- event.stopPropagation();
1295
- setColumnWidthOverrideFn(column.name, measureAutoColumnWidthFn(column.name));
1296
- },
1297
- [canResizeColumnsFn, setColumnWidthOverrideFn, measureAutoColumnWidthFn]
1298
- );
1299
- const onViewportScrollFn = (0, import_react.useCallback)((startIndex) => {
1300
- if (!scrollingRef.current) {
1301
- scrollingRef.current = true;
1302
- (0, import_ui_grid_core2.raiseGridScrollBegin)(gridApiRef.current);
1303
- }
1304
- if (scrollEndHandleRef.current) {
1305
- window.clearTimeout(scrollEndHandleRef.current);
1306
- }
1307
- scrollEndHandleRef.current = window.setTimeout(() => {
1308
- scrollingRef.current = false;
1309
- (0, import_ui_grid_core2.raiseGridScrollEnd)(gridApiRef.current);
1310
- }, 120);
1311
- const isInfiniteScrollEnabled = import_ui_grid_core2.FEATURE_INFINITE_SCROLL && (optionsRef.current.infiniteScrollRowsFromEnd !== void 0 || optionsRef.current.infiniteScrollUp === true || optionsRef.current.infiniteScrollDown !== void 0);
1312
- (0, import_ui_grid_core2.maybeRequestInfiniteScrollCommand)(gridApiRef.current, {
1313
- enabled: isInfiniteScrollEnabled,
1314
- virtualizationEnabled: pipelineRef.current.virtualizationEnabled,
1315
- state: infiniteScrollStateRef.current,
1316
- startIndex,
1317
- visibleRows: pipelineRef.current.visibleRows.length,
1318
- viewportRows: computeViewportRows(
1319
- optionsRef.current.viewportHeight,
1320
- optionsRef.current.rowHeight
1321
- ),
1322
- threshold: optionsRef.current.infiniteScrollRowsFromEnd ?? 20,
1323
- setState: (state) => setInfiniteScrollState(state)
1324
- });
1325
- }, []);
1326
- return {
1327
- pipeline,
1328
- visibleColumns,
1329
- labels,
1330
- gridTemplateColumns,
1331
- gridApi,
1332
- gridContainerRef,
1333
- activeFilters,
1334
- groupByColumns,
1335
- collapsedGroups,
1336
- sortState,
1337
- focusedCell,
1338
- editingCell,
1339
- editingValue,
1340
- expandedRows,
1341
- expandedTreeRows,
1342
- currentPage,
1343
- pageSize,
1344
- benchmarkResult,
1345
- infiniteScrollState,
1346
- totalRows,
1347
- visibleRowCount,
1348
- displayItems,
1349
- virtualizationEnabled,
1350
- pipelineMs: pipelineMsVal,
1351
- paginationCurrentPage,
1352
- paginationTotalPages,
1353
- paginationSelectedPageSize,
1354
- rowSize,
1355
- viewportHeightPx,
1356
- autoViewportHeight,
1357
- headerLabel: headerLabelFn,
1358
- isGroupItem: isGroupItemFn,
1359
- isExpandableItem: isExpandableItemFn,
1360
- isRowItem: isRowItemFn,
1361
- isOddStripedRow: isOddStripedRowFn,
1362
- sortButtonLabel: sortButtonLabelFn,
1363
- sortAriaSort: sortAriaSortFn,
1364
- sortDirection: sortDirectionFn,
1365
- groupingButtonLabel: groupingButtonLabelFn,
1366
- filterValue: filterValueFn,
1367
- filterPlaceholder: filterPlaceholderFn,
1368
- isFilterInputDisabled: isFilterInputDisabledFn,
1369
- groupDisclosureLabel: groupDisclosureLabelFn,
1370
- displayValue: displayValueFn,
1371
- isFocusedCell: isFocusedCellFn,
1372
- isFocusedRow: isFocusedRowFn,
1373
- isEditingCell: isEditingCellFn,
1374
- editorInputType: editorInputTypeFn,
1375
- cellContext: cellContextFn,
1376
- expandedContext: expandedContextFn,
1377
- columnWidth: columnWidthFn,
1378
- isColumnSortable: isColumnSortableFn,
1379
- isColumnFilterable: isColumnFilterableFn,
1380
- cellIndent: cellIndentFn,
1381
- treeToggleLabel: treeToggleLabelFn,
1382
- isTreeRowExpanded: isTreeRowExpandedFn,
1383
- expandToggleLabel: expandToggleLabelFn,
1384
- isGrouped: isGroupedFn,
1385
- showTreeToggle: showTreeToggleFn,
1386
- showExpandToggle: showExpandToggleFn,
1387
- showPaginationControls: showPaginationControlsFn,
1388
- paginationSummary: paginationSummaryFn,
1389
- pageSizeOptions: pageSizeOptionsFn,
1390
- isCellEditable,
1391
- shouldEditOnFocus: shouldEditOnFocusFn,
1392
- sortingFeature: import_ui_grid_core2.FEATURE_SORTING,
1393
- filteringFeature: import_ui_grid_core2.FEATURE_FILTERING,
1394
- groupingFeature: import_ui_grid_core2.FEATURE_GROUPING,
1395
- paginationFeature: import_ui_grid_core2.FEATURE_PAGINATION,
1396
- cellEditFeature: import_ui_grid_core2.FEATURE_CELL_EDIT,
1397
- expandableFeature: import_ui_grid_core2.FEATURE_EXPANDABLE,
1398
- treeViewFeature: import_ui_grid_core2.FEATURE_TREE_VIEW,
1399
- infiniteScrollFeature: import_ui_grid_core2.FEATURE_INFINITE_SCROLL,
1400
- columnMovingFeature: import_ui_grid_core2.FEATURE_COLUMN_MOVING,
1401
- csvExportFeature: import_ui_grid_core2.FEATURE_CSV_EXPORT,
1402
- isGroupingEnabled: isGroupingEnabledFn,
1403
- isFilteringEnabled: isFilteringEnabledFn,
1404
- toggleSort: toggleSortFn,
1405
- updateFilter: updateFilterFn,
1406
- clearAllFilters: clearAllFiltersFn,
1407
- toggleGrouping: toggleGroupingFn,
1408
- toggleGroup: toggleGroupFn,
1409
- focusCell: focusCellFn,
1410
- handleCellKeyDown: handleCellKeyDownFn,
1411
- handleCellDoubleClick: handleCellDoubleClickFn,
1412
- updateEditingValue: updateEditingValueFn,
1413
- handleEditorKeyDown: handleEditorKeyDownFn,
1414
- handleEditorBlur: handleEditorBlurFn,
1415
- toggleRowExpansion: toggleRowExpansionFn,
1416
- toggleTreeRow: toggleTreeRowFn,
1417
- moveColumn: moveColumnFn,
1418
- moveVisibleColumn: moveVisibleColumnFn,
1419
- canResizeColumns: canResizeColumnsFn,
1420
- handleHeaderResizeMouseDown: handleHeaderResizeMouseDownFn,
1421
- autoSizeColumn: autoSizeColumnFn,
1422
- nextPage: nextPageFn,
1423
- previousPage: previousPageFn,
1424
- onPageSizeChange: onPageSizeChangeFn,
1425
- runBenchmark: runBenchmarkFn,
1426
- exportCsv: exportCsvFn,
1427
- onViewportScroll: onViewportScrollFn,
1428
- // Pinning
1429
- isPinned: isPinnedFn,
1430
- pinnedOffset: pinnedOffsetFn,
1431
- isPinningEnabled: isPinningEnabledFn,
1432
- isColumnPinnable: isColumnPinnableFn,
1433
- togglePin: togglePinFn,
1434
- pinningFeature: import_ui_grid_core2.FEATURE_PINNING
1435
- };
1436
- }
1437
-
1438
- // src/useVirtualScroll.ts
1439
- var import_react2 = require("react");
1440
-
1441
- // src/virtualScrollMath.ts
1442
- function calculateVirtualWindow(request) {
1443
- const overscan = request.overscan ?? 3;
1444
- if (request.itemCount <= 0 || request.itemSize <= 0) {
1445
- return {
1446
- visibleRange: { start: 0, end: 0 },
1447
- totalHeight: Math.max(0, request.itemCount) * Math.max(0, request.itemSize),
1448
- offsetY: 0
1449
137
  };
1450
- }
1451
- const rawStart = Math.floor(request.scrollTop / request.itemSize) - overscan;
1452
- const start = Math.max(0, rawStart);
1453
- const rawEnd = rawStart + Math.ceil(request.viewportHeight / request.itemSize) + 2 * overscan;
1454
- const end = Math.min(request.itemCount, rawEnd);
1455
- return {
1456
- visibleRange: { start, end },
1457
- totalHeight: request.itemCount * request.itemSize,
1458
- offsetY: start * request.itemSize
1459
- };
1460
- }
1461
-
1462
- // src/useVirtualScroll.ts
1463
- function useVirtualScroll(options) {
1464
- const { itemCount, itemSize, viewportHeight, overscan = 3 } = options;
1465
- const [scrollTop, setScrollTop] = (0, import_react2.useState)(0);
1466
- const viewportRef = (0, import_react2.useRef)(null);
1467
- const virtualWindow = calculateVirtualWindow({
1468
- itemCount,
1469
- itemSize,
1470
- viewportHeight,
1471
- overscan,
1472
- scrollTop
1473
- });
1474
- const onScroll = (0, import_react2.useCallback)((event) => {
1475
- setScrollTop(event.currentTarget.scrollTop);
1476
- }, []);
1477
- return {
1478
- visibleRange: virtualWindow.visibleRange,
1479
- totalHeight: virtualWindow.totalHeight,
1480
- offsetY: virtualWindow.offsetY,
1481
- onScroll,
1482
- setScrollTop,
1483
- viewportRef,
1484
- scrollTop
1485
- };
1486
- }
1487
-
1488
- // src/UiGrid.tsx
1489
- var import_jsx_runtime = require("react/jsx-runtime");
1490
- function UiGrid({
1491
- options,
1492
- onRegisterApi,
1493
- cellRenderer,
1494
- headerRenderer,
1495
- expandableRenderer,
1496
- className
1497
- }) {
1498
- const state = useGridState(options, onRegisterApi);
1499
- const {
1500
- pipeline,
1501
- visibleColumns,
1502
- labels,
1503
- gridTemplateColumns,
1504
- gridContainerRef,
1505
- displayItems,
1506
- virtualizationEnabled,
1507
- rowSize,
1508
- editingValue,
1509
- autoViewportHeight,
1510
- sortingFeature,
1511
- filteringFeature,
1512
- groupingFeature,
1513
- paginationFeature,
1514
- cellEditFeature,
1515
- expandableFeature,
1516
- treeViewFeature,
1517
- columnMovingFeature,
1518
- paginationCurrentPage,
1519
- paginationTotalPages,
1520
- paginationSelectedPageSize
1521
- } = state;
1522
- const headerGridRef = import_react3.default.useRef(null);
1523
- const filterGridRef = import_react3.default.useRef(null);
1524
- const [headerStickyHeight, setHeaderStickyHeight] = import_react3.default.useState(0);
1525
- const [filterStickyHeight, setFilterStickyHeight] = import_react3.default.useState(0);
1526
- const stickyChromeHeight = headerStickyHeight + filterStickyHeight;
1527
- const resolvedViewportHeight = options.viewportHeight ?? (autoViewportHeight && autoViewportHeight > 0 ? autoViewportHeight : 560);
1528
- const bodyViewportHeight = Math.max(rowSize, resolvedViewportHeight - stickyChromeHeight);
1529
- const virtualScroll = useVirtualScroll({
1530
- itemCount: displayItems.length,
1531
- itemSize: rowSize,
1532
- viewportHeight: bodyViewportHeight,
1533
- overscan: 3
1534
- });
1535
- const [openPinMenuColumn, setOpenPinMenuColumn] = import_react3.default.useState(null);
1536
- const [draggedColumnName, setDraggedColumnName] = import_react3.default.useState(null);
1537
- const [dropTargetColumnName, setDropTargetColumnName] = import_react3.default.useState(null);
1538
- const scrollContainerHeight = `${resolvedViewportHeight}px`;
1539
- function renderHeaderContent(column) {
1540
- const value = state.headerLabel(column);
1541
- const context = {
1542
- $implicit: value,
1543
- value,
1544
- column
1545
- };
1546
- if (headerRenderer) {
1547
- return headerRenderer(context) ?? value;
1548
- }
1549
- if (column.headerRenderer) {
1550
- return column.headerRenderer(context);
138
+ el.options = wrappedOptions;
139
+ const prev = currentSlotColumnsRef.current;
140
+ const columnsChanged = cellSlotColumns.length !== prev.length || cellSlotColumns.some((name, i) => name !== prev[i]);
141
+ if (columnsChanged) {
142
+ currentSlotColumnsRef.current = cellSlotColumns;
143
+ el.setFrameworkRenderedSlots({ cells: cellSlotColumns });
1551
144
  }
1552
- return value;
1553
145
  }
1554
- const eventPathIncludesClass = import_react3.default.useCallback((event, className2) => {
1555
- const eventPath = typeof event.composedPath === "function" ? event.composedPath() : event.target ? [event.target] : [];
1556
- return eventPath.some((target) => {
1557
- if (!target || typeof target !== "object" || !("classList" in target)) {
1558
- return false;
1559
- }
1560
- const classList = target.classList;
1561
- return classList?.contains(className2) ?? false;
1562
- });
1563
- }, []);
1564
- const isPinMenuOpen = import_react3.default.useCallback(
1565
- (column) => openPinMenuColumn === column.name,
1566
- [openPinMenuColumn]
1567
- );
1568
- const pinButtonLabel = import_react3.default.useCallback(
1569
- (column) => state.isPinned(column) ? labels.unpin : labels.pinColumn,
1570
- [labels, state]
1571
- );
1572
- const onPinTrigger = import_react3.default.useCallback(
1573
- (column, event) => {
1574
- event?.stopPropagation();
1575
- if (state.isPinned(column)) {
1576
- setOpenPinMenuColumn(null);
1577
- state.gridApi.pinning.pinColumn(column.name, "none");
1578
- return;
1579
- }
1580
- setOpenPinMenuColumn((current) => current === column.name ? null : column.name);
1581
- },
1582
- [state]
1583
- );
1584
- const choosePinDirection = import_react3.default.useCallback(
1585
- (column, direction, event) => {
1586
- event?.stopPropagation();
1587
- setOpenPinMenuColumn(null);
1588
- state.gridApi.pinning.pinColumn(column.name, direction);
1589
- },
1590
- [state]
1591
- );
1592
- const handleHeaderDragStart = import_react3.default.useCallback(
1593
- (column, event) => {
1594
- if (!columnMovingFeature) {
1595
- event.preventDefault();
1596
- return;
1597
- }
1598
- setDraggedColumnName(column.name);
1599
- setDropTargetColumnName(null);
1600
- event.dataTransfer.effectAllowed = "move";
1601
- event.dataTransfer.setData("text/plain", column.name);
1602
- },
1603
- [columnMovingFeature]
1604
- );
1605
- const handleHeaderDragOver = import_react3.default.useCallback(
1606
- (column, event) => {
1607
- if (!columnMovingFeature || !draggedColumnName || draggedColumnName === column.name) {
1608
- return;
1609
- }
1610
- event.preventDefault();
1611
- event.dataTransfer.dropEffect = "move";
1612
- setDropTargetColumnName(column.name);
1613
- },
1614
- [columnMovingFeature, draggedColumnName]
1615
- );
1616
- const handleHeaderDrop = import_react3.default.useCallback(
1617
- (column, event) => {
1618
- event.preventDefault();
1619
- if (!columnMovingFeature) {
1620
- return;
146
+ function handleCellSlotsChanged(event) {
147
+ const detail = event.detail;
148
+ const el = elementRef.current;
149
+ if (!el) return;
150
+ setSlots((prev) => {
151
+ const next = new Map(prev);
152
+ for (const slot of detail.removed) {
153
+ const entry = next.get(slot.slotName);
154
+ if (entry) {
155
+ entry.wrapper.remove();
156
+ next.delete(slot.slotName);
157
+ }
1621
158
  }
1622
- const sourceColumnName = draggedColumnName ?? event.dataTransfer.getData("text/plain");
1623
- setDraggedColumnName(null);
1624
- setDropTargetColumnName(null);
1625
- if (!sourceColumnName || sourceColumnName === column.name) {
1626
- return;
159
+ for (const slot of detail.added) {
160
+ const existing = next.get(slot.slotName);
161
+ if (existing) {
162
+ existing.wrapper.remove();
163
+ }
164
+ const wrapper = document.createElement("span");
165
+ wrapper.setAttribute("slot", slot.slotName);
166
+ el.appendChild(wrapper);
167
+ next.set(slot.slotName, {
168
+ slotName: slot.slotName,
169
+ columnName: slot.columnName,
170
+ rowId: slot.rowId,
171
+ context: slot.context,
172
+ wrapper
173
+ });
1627
174
  }
1628
- state.moveVisibleColumn(sourceColumnName, column.name);
1629
- },
1630
- [columnMovingFeature, draggedColumnName, state]
1631
- );
1632
- const handleHeaderDragEnd = import_react3.default.useCallback(() => {
1633
- setDraggedColumnName(null);
1634
- setDropTargetColumnName(null);
1635
- }, []);
1636
- import_react3.default.useLayoutEffect(() => {
1637
- setHeaderStickyHeight(headerGridRef.current?.offsetHeight ?? 0);
1638
- setFilterStickyHeight(filterGridRef.current?.offsetHeight ?? 0);
1639
- }, [visibleColumns, filteringFeature, options.enableFiltering]);
1640
- import_react3.default.useLayoutEffect(() => {
1641
- const headerElement = headerGridRef.current;
1642
- const filterElement = filterGridRef.current;
1643
- if (typeof ResizeObserver === "undefined" || !headerElement && !filterElement) {
1644
- return;
1645
- }
1646
- const observer = new ResizeObserver(() => {
1647
- setHeaderStickyHeight(headerGridRef.current?.offsetHeight ?? 0);
1648
- setFilterStickyHeight(filterGridRef.current?.offsetHeight ?? 0);
175
+ return next;
1649
176
  });
1650
- if (headerElement) {
1651
- observer.observe(headerElement);
1652
- }
1653
- if (filterElement) {
1654
- observer.observe(filterElement);
1655
- }
1656
- return () => observer.disconnect();
1657
- }, []);
1658
- import_react3.default.useEffect(() => {
1659
- if (!openPinMenuColumn) {
1660
- return;
1661
- }
1662
- const handleDocumentClick = (event) => {
1663
- if (eventPathIncludesClass(event, "pin-control")) {
1664
- return;
1665
- }
1666
- setOpenPinMenuColumn(null);
1667
- };
1668
- const handleDocumentEscape = (event) => {
1669
- if (event.key === "Escape") {
1670
- setOpenPinMenuColumn(null);
177
+ }
178
+ const portals = [];
179
+ const renderers = cellRenderers;
180
+ if (renderers) {
181
+ for (const [, entry] of slots) {
182
+ const renderer = renderers[entry.columnName];
183
+ if (renderer) {
184
+ portals.push((0, import_react_dom.createPortal)(renderer(entry.context), entry.wrapper, entry.slotName));
1671
185
  }
1672
- };
1673
- document.addEventListener("click", handleDocumentClick);
1674
- document.addEventListener("keydown", handleDocumentEscape);
1675
- return () => {
1676
- document.removeEventListener("click", handleDocumentClick);
1677
- document.removeEventListener("keydown", handleDocumentEscape);
1678
- };
1679
- }, [eventPathIncludesClass, openPinMenuColumn]);
1680
- const itemsToRender = virtualizationEnabled ? displayItems.slice(virtualScroll.visibleRange.start, virtualScroll.visibleRange.end) : displayItems;
1681
- const onGridTableScroll = (event) => {
1682
- const bodyScrollTop = Math.max(0, event.currentTarget.scrollTop - stickyChromeHeight);
1683
- virtualScroll.setScrollTop(bodyScrollTop);
1684
- const startIndex = Math.floor(bodyScrollTop / rowSize);
1685
- state.onViewportScroll(startIndex);
1686
- };
1687
- function renderDisplayItem(item) {
1688
- if (groupingFeature && state.isGroupItem(item)) {
1689
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1690
- "button",
1691
- {
1692
- type: "button",
1693
- className: "group-row ui-grid-row ui-grid-group-row",
1694
- "data-part": "group-row",
1695
- role: "row",
1696
- "aria-expanded": !item.collapsed,
1697
- style: { gridColumn: "1 / -1", paddingInlineStart: `${item.depth * 1.25 + 1}rem` },
1698
- onClick: () => state.toggleGroup(item),
1699
- children: [
1700
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { children: [
1701
- item.field,
1702
- ": ",
1703
- item.label
1704
- ] }),
1705
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1706
- item.count,
1707
- " ",
1708
- labels.groupRowsSuffix
1709
- ] }),
1710
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1711
- "svg",
1712
- {
1713
- className: "toggle-icon group-disclosure-icon",
1714
- viewBox: "0 0 24 24",
1715
- "aria-hidden": "true",
1716
- focusable: false,
1717
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: item.collapsed ? "M10 7l5 5-5 5z" : "M7 10l5 5 5-5z" })
1718
- }
1719
- ),
1720
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: state.groupDisclosureLabel(item) })
1721
- ]
1722
- },
1723
- item.id
1724
- );
1725
- }
1726
- if (expandableFeature && state.isExpandableItem(item)) {
1727
- const ctx = state.expandedContext(item.row);
1728
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1729
- "div",
1730
- {
1731
- className: "expandable-row ui-grid-row ui-grid-expandable-row",
1732
- "data-part": "expandable-row",
1733
- style: { gridColumn: "1 / -1", minHeight: `${item.row.expandedRowHeight}px` },
1734
- children: expandableRenderer?.(ctx)
1735
- },
1736
- item.id
1737
- );
1738
186
  }
1739
- if (item.kind !== "row") return null;
1740
- const rowItem = item;
1741
- return visibleColumns.map((column) => {
1742
- const pinned = state.isPinned(column);
1743
- const pinOffset = pinned ? state.pinnedOffset(column) : null;
1744
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1745
- "div",
1746
- {
1747
- className: `${cellClassName(rowItem, column)}${pinned ? " is-pinned" : ""}`,
1748
- "data-part": "body-cell",
1749
- role: "gridcell",
1750
- tabIndex: 0,
1751
- "data-row-id": rowItem.row.id,
1752
- "data-col-name": column.name,
1753
- onFocus: () => state.focusCell(rowItem.row, column),
1754
- onClick: () => state.focusCell(rowItem.row, column),
1755
- onDoubleClick: (e) => state.handleCellDoubleClick(rowItem.row, column, e),
1756
- onKeyDown: (e) => state.handleCellKeyDown(rowItem.row, column, e),
1757
- style: {
1758
- position: pinned ? "sticky" : void 0,
1759
- left: pinOffset?.side === "left" ? pinOffset.offset : void 0,
1760
- right: pinOffset?.side === "right" ? pinOffset.offset : void 0,
1761
- zIndex: pinned ? 2 : void 0
1762
- },
1763
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1764
- "div",
1765
- {
1766
- className: "cell-shell",
1767
- style: { paddingInlineStart: state.cellIndent(rowItem.row, column) },
1768
- children: [
1769
- treeViewFeature && state.showTreeToggle(rowItem.row, column) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1770
- "button",
1771
- {
1772
- type: "button",
1773
- className: "row-toggle row-toggle-tree",
1774
- "data-part": "tree-toggle",
1775
- "aria-label": state.treeToggleLabel(rowItem.row),
1776
- "aria-expanded": state.isTreeRowExpanded(rowItem.row),
1777
- onClick: (e) => state.toggleTreeRow(rowItem.row, e),
1778
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1779
- "svg",
1780
- {
1781
- className: "toggle-icon",
1782
- viewBox: "0 0 24 24",
1783
- "aria-hidden": "true",
1784
- focusable: false,
1785
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1786
- "path",
1787
- {
1788
- d: state.isTreeRowExpanded(rowItem.row) ? "M7 10l5 5 5-5z" : "M10 7l5 5-5 5z"
1789
- }
1790
- )
1791
- }
1792
- )
1793
- }
1794
- ),
1795
- expandableFeature && state.showExpandToggle(rowItem.row, column) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1796
- "button",
1797
- {
1798
- type: "button",
1799
- className: "row-toggle row-toggle-expand",
1800
- "data-part": "expand-toggle",
1801
- "aria-label": state.expandToggleLabel(rowItem.row),
1802
- "aria-expanded": rowItem.row.expanded,
1803
- onClick: (e) => state.toggleRowExpansion(rowItem.row, e),
1804
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1805
- "svg",
1806
- {
1807
- className: "toggle-icon",
1808
- viewBox: "0 0 24 24",
1809
- "aria-hidden": "true",
1810
- focusable: false,
1811
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: rowItem.row.expanded ? "M7 10l5 5 5-5z" : "M10 7l5 5-5 5z" })
1812
- }
1813
- )
1814
- }
1815
- ),
1816
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cell-value", children: cellEditFeature && state.isEditingCell(rowItem.row, column) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1817
- "input",
1818
- {
1819
- className: "cell-editor",
1820
- "data-row-id": rowItem.row.id,
1821
- "data-col-name": column.name,
1822
- "aria-label": state.headerLabel(column),
1823
- type: state.editorInputType(column),
1824
- defaultValue: editingValue,
1825
- onChange: (e) => state.updateEditingValue(e.target.value),
1826
- onKeyDown: (e) => state.handleEditorKeyDown(e),
1827
- onBlur: (e) => state.handleEditorBlur(e)
1828
- }
1829
- ) : cellRenderer ? cellRenderer(state.cellContext(rowItem.row, column)) ?? state.displayValue(rowItem.row, column) : state.displayValue(rowItem.row, column) })
1830
- ]
1831
- }
1832
- )
1833
- },
1834
- `${rowItem.row.id}-${column.name}`
1835
- );
1836
- });
1837
- }
1838
- function cellClassName(item, column) {
1839
- const classes = ["body-cell", "ui-grid-cell"];
1840
- if (state.isOddStripedRow(item)) classes.push("body-cell-odd");
1841
- if (column.align === "center") classes.push("align-center");
1842
- if (column.align === "end") classes.push("align-end");
1843
- if (state.isFocusedCell(item.row, column)) classes.push("cell-focused");
1844
- if (state.isFocusedRow(item.row)) classes.push("row-focused");
1845
- if (cellEditFeature && state.isEditingCell(item.row, column)) classes.push("cell-editing");
1846
- return classes.join(" ");
1847
187
  }
1848
- function renderSortIcon(column) {
1849
- const direction = state.sortDirection(column);
1850
- switch (direction) {
1851
- case "asc":
1852
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5l-6 6h4v8h4v-8h4z" }) });
1853
- case "desc":
1854
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 19l6-6h-4V5h-4v8H6z" }) });
1855
- default:
1856
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 6h10v2H7V6Zm0 5h7v2H7v-2Zm0 5h4v2H7v-2Z" }) });
1857
- }
188
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, className, style: { display: "block", height: "100%", minHeight: 0 }, children: portals });
189
+ }
190
+ function getNestedValue(obj, field) {
191
+ const parts = field.split(".");
192
+ let current = obj;
193
+ for (const part of parts) {
194
+ if (current == null || typeof current !== "object") return void 0;
195
+ current = current[part];
1858
196
  }
1859
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `ui-grid-host ${className ?? ""}`, ref: gridContainerRef, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1860
- "section",
1861
- {
1862
- className: "grid-frame ui-grid",
1863
- "data-part": "grid-frame",
1864
- role: "grid",
1865
- "aria-label": options.title ?? "Data grid",
1866
- children: [
1867
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1868
- "div",
1869
- {
1870
- className: "grid-table ui-grid-contents-wrapper",
1871
- "data-part": "grid-table",
1872
- style: virtualizationEnabled ? { height: scrollContainerHeight, overflowY: "auto" } : void 0,
1873
- onScroll: virtualizationEnabled ? onGridTableScroll : void 0,
1874
- children: [
1875
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1876
- "div",
1877
- {
1878
- className: "header-grid ui-grid-header ui-grid-header-canvas",
1879
- "data-part": "header",
1880
- role: "row",
1881
- ref: headerGridRef,
1882
- style: { gridTemplateColumns },
1883
- children: visibleColumns.map((column) => {
1884
- const pinned = state.isPinned(column);
1885
- const pinOffset = pinned ? state.pinnedOffset(column) : null;
1886
- const pinMenuOpen = isPinMenuOpen(column);
1887
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1888
- "div",
1889
- {
1890
- className: `header-cell ui-grid-header-cell${sortingFeature && state.sortDirection(column) !== "none" ? " is-active" : ""}${pinned ? " is-pinned" : ""}${pinMenuOpen ? " is-pin-menu-open" : ""}${draggedColumnName === column.name ? " is-dragging" : ""}${dropTargetColumnName === column.name ? " is-drag-target" : ""}`,
1891
- "data-part": "header-cell",
1892
- "data-col-name": column.name,
1893
- "aria-sort": sortingFeature ? state.sortAriaSort(column) : void 0,
1894
- draggable: columnMovingFeature,
1895
- onDragStart: (event) => handleHeaderDragStart(column, event),
1896
- onDragOver: (event) => handleHeaderDragOver(column, event),
1897
- onDrop: (event) => handleHeaderDrop(column, event),
1898
- onDragEnd: handleHeaderDragEnd,
1899
- onDragLeave: () => {
1900
- if (dropTargetColumnName === column.name) {
1901
- setDropTargetColumnName(null);
1902
- }
1903
- },
1904
- style: {
1905
- position: pinned ? "sticky" : void 0,
1906
- left: pinOffset?.side === "left" ? pinOffset.offset : void 0,
1907
- right: pinOffset?.side === "right" ? pinOffset.offset : void 0,
1908
- zIndex: pinMenuOpen ? 8 : pinned ? 2 : void 0
1909
- },
1910
- children: [
1911
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "header-label", children: renderHeaderContent(column) }),
1912
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "header-actions", children: [
1913
- sortingFeature && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1914
- "button",
1915
- {
1916
- type: "button",
1917
- className: `header-action${!state.isColumnSortable(column) ? " header-action-disabled" : ""}`,
1918
- disabled: !state.isColumnSortable(column),
1919
- "aria-label": state.sortButtonLabel(column),
1920
- title: state.sortButtonLabel(column),
1921
- onClick: () => state.toggleSort(column),
1922
- children: [
1923
- renderSortIcon(column),
1924
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: state.sortButtonLabel(column) })
1925
- ]
1926
- }
1927
- ),
1928
- groupingFeature && state.isGroupingEnabled() && column.enableGrouping !== false && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1929
- "button",
1930
- {
1931
- type: "button",
1932
- className: `chip-action${state.isGrouped(column) ? " chip-action-active" : ""}`,
1933
- "data-part": "group-toggle",
1934
- "aria-label": state.groupingButtonLabel(column),
1935
- title: state.groupingButtonLabel(column),
1936
- onClick: (e) => state.toggleGrouping(column, e),
1937
- children: [
1938
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6h8v4H4V6Zm0 8h8v4H4v-4Zm10-8h6v4h-6V6Zm0 8h6v4h-6v-4Z" }) }),
1939
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: state.groupingButtonLabel(column) })
1940
- ]
1941
- }
1942
- ),
1943
- state.pinningFeature && state.isPinningEnabled() && state.isColumnPinnable(column) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1944
- "div",
1945
- {
1946
- className: `pin-control${pinMenuOpen ? " pin-control-open" : ""}`,
1947
- onClick: (event) => event.stopPropagation(),
1948
- children: [
1949
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1950
- "button",
1951
- {
1952
- type: "button",
1953
- className: `chip-action pin-trigger${pinned || pinMenuOpen ? " chip-action-active" : ""}`,
1954
- "data-part": "pin-toggle",
1955
- "aria-label": pinButtonLabel(column),
1956
- title: pinButtonLabel(column),
1957
- "aria-haspopup": pinned ? void 0 : "menu",
1958
- "aria-expanded": pinned ? void 0 : pinMenuOpen,
1959
- onClick: (event) => onPinTrigger(column, event),
1960
- children: [
1961
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M16 12V4h1V2H7v2h1v8l-2 2v2h5v6l1 1 1-1v-6h5v-2l-2-2z" }) }),
1962
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: pinButtonLabel(column) })
1963
- ]
1964
- }
1965
- ),
1966
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1967
- "div",
1968
- {
1969
- className: "pin-menu",
1970
- "data-part": "pin-menu",
1971
- role: "menu",
1972
- "aria-label": "Pin options",
1973
- "aria-hidden": !pinMenuOpen,
1974
- children: [
1975
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1976
- "button",
1977
- {
1978
- type: "button",
1979
- className: "pin-menu-action",
1980
- "data-part": "pin-left-action",
1981
- role: "menuitem",
1982
- "aria-label": labels.pinLeft,
1983
- title: labels.pinLeft,
1984
- tabIndex: pinMenuOpen ? 0 : -1,
1985
- onClick: (event) => choosePinDirection(column, "left", event),
1986
- children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 6 4 12l6 6v-4h10v-4H10V6z" }) }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: labels.pinLeft })
1989
- ]
1990
- }
1991
- ),
1992
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1993
- "button",
1994
- {
1995
- type: "button",
1996
- className: "pin-menu-action",
1997
- "data-part": "pin-right-action",
1998
- role: "menuitem",
1999
- "aria-label": labels.pinRight,
2000
- title: labels.pinRight,
2001
- tabIndex: pinMenuOpen ? 0 : -1,
2002
- onClick: (event) => choosePinDirection(column, "right", event),
2003
- children: [
2004
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 6v4H4v4h10v4l6-6-6-6z" }) }),
2005
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only ui-grid-sr-only", children: labels.pinRight })
2006
- ]
2007
- }
2008
- )
2009
- ]
2010
- }
2011
- )
2012
- ]
2013
- }
2014
- )
2015
- ] }),
2016
- state.canResizeColumns() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2017
- "button",
2018
- {
2019
- type: "button",
2020
- className: "column-resizer",
2021
- "data-col-name": column.name,
2022
- "aria-label": `Resize ${state.headerLabel(column)} column`,
2023
- title: "Drag to resize, double-click to auto fit",
2024
- onMouseDown: (event) => state.handleHeaderResizeMouseDown(column, event),
2025
- onDoubleClick: (event) => state.autoSizeColumn(column, event)
2026
- }
2027
- )
2028
- ]
2029
- },
2030
- column.name
2031
- );
2032
- })
2033
- }
2034
- ),
2035
- filteringFeature && state.isFilteringEnabled() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2036
- "div",
2037
- {
2038
- className: "filter-grid ui-grid-header",
2039
- "data-part": "filters",
2040
- ref: filterGridRef,
2041
- style: {
2042
- gridTemplateColumns,
2043
- ["--ui-grid-header-sticky-top"]: `${headerStickyHeight}px`
2044
- },
2045
- children: visibleColumns.map((column) => {
2046
- const pinned = state.isPinned(column);
2047
- const pinOffset = pinned ? state.pinnedOffset(column) : null;
2048
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2049
- "label",
2050
- {
2051
- className: `filter-cell ui-grid-filter-container${pinned ? " is-pinned" : ""}`,
2052
- "data-part": "filter-cell",
2053
- style: {
2054
- position: pinned ? "sticky" : void 0,
2055
- left: pinOffset?.side === "left" ? pinOffset.offset : void 0,
2056
- right: pinOffset?.side === "right" ? pinOffset.offset : void 0,
2057
- zIndex: pinned ? 2 : void 0
2058
- },
2059
- children: [
2060
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "sr-only ui-grid-sr-only", children: [
2061
- labels.filterColumn,
2062
- " ",
2063
- state.headerLabel(column)
2064
- ] }),
2065
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2066
- "input",
2067
- {
2068
- className: "ui-grid-filter-input",
2069
- type: "text",
2070
- defaultValue: state.filterValue(column.name),
2071
- placeholder: state.filterPlaceholder(column),
2072
- disabled: state.isFilterInputDisabled(column),
2073
- onChange: (e) => state.updateFilter(column.name, e.target.value)
2074
- }
2075
- )
2076
- ]
2077
- },
2078
- column.name
2079
- );
2080
- })
2081
- }
2082
- ),
2083
- displayItems.length > 0 ? virtualizationEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid-virtual-spacer", style: { height: `${virtualScroll.totalHeight}px` }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2084
- "div",
2085
- {
2086
- className: "body-grid ui-grid-canvas grid-virtual-body",
2087
- "data-part": "body",
2088
- role: "rowgroup",
2089
- style: {
2090
- gridTemplateColumns,
2091
- position: "absolute",
2092
- top: `${virtualScroll.offsetY}px`,
2093
- left: 0
2094
- },
2095
- children: itemsToRender.map(renderDisplayItem)
2096
- }
2097
- ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "body-grid ui-grid-canvas", "data-part": "body", role: "rowgroup", style: { gridTemplateColumns }, children: displayItems.map(renderDisplayItem) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "empty-state ui-grid-no-row-overlay", "data-part": "empty-state", children: [
2098
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: options.emptyMessage ?? labels.emptyHeading }),
2099
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: labels.emptyDescription })
2100
- ] })
2101
- ]
2102
- }
2103
- ),
2104
- paginationFeature && state.showPaginationControls() && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2105
- "footer",
2106
- {
2107
- className: "pagination-bar ui-grid-pagination",
2108
- "data-part": "pagination",
2109
- role: "navigation",
2110
- "aria-label": labels.paginationPage,
2111
- children: [
2112
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: state.paginationSummary() }),
2113
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pagination-controls", children: [
2114
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2115
- "button",
2116
- {
2117
- type: "button",
2118
- className: "action action-secondary pagination-button",
2119
- "aria-label": labels.paginationPrevious,
2120
- disabled: paginationCurrentPage <= 1,
2121
- onClick: () => state.previousPage(),
2122
- children: [
2123
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className: "pagination-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }) }),
2124
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: labels.paginationPrevious })
2125
- ]
2126
- }
2127
- ),
2128
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
2129
- labels.paginationPage,
2130
- " ",
2131
- paginationCurrentPage,
2132
- " ",
2133
- labels.paginationOf,
2134
- " ",
2135
- paginationTotalPages
2136
- ] }),
2137
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
2138
- "button",
2139
- {
2140
- type: "button",
2141
- className: "action action-secondary pagination-button",
2142
- "aria-label": labels.paginationNext,
2143
- disabled: paginationCurrentPage >= paginationTotalPages,
2144
- onClick: () => state.nextPage(),
2145
- children: [
2146
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className: "pagination-icon", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z" }) }),
2147
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: labels.paginationNext })
2148
- ]
2149
- }
2150
- ),
2151
- state.pageSizeOptions().length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "pagination-size", children: [
2152
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: labels.paginationRows }),
2153
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2154
- "select",
2155
- {
2156
- "aria-label": labels.paginationRows,
2157
- value: paginationSelectedPageSize,
2158
- onChange: (e) => state.onPageSizeChange(e.target.value),
2159
- children: state.pageSizeOptions().map((size) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: size, children: size }, size))
2160
- }
2161
- )
2162
- ] })
2163
- ] })
2164
- ]
2165
- }
2166
- )
2167
- ]
2168
- }
2169
- ) });
197
+ return current;
2170
198
  }
2171
199
 
2172
200
  // src/mountUiGrid.tsx
2173
- var import_react4 = __toESM(require("react"));
201
+ var import_react2 = __toESM(require("react"));
2174
202
  var import_client = require("react-dom/client");
2175
203
  function mountUiGrid(container, props) {
2176
204
  const root = (0, import_client.createRoot)(container);
2177
- root.render(import_react4.default.createElement(UiGrid, props));
205
+ root.render(import_react2.default.createElement(UiGrid, props));
2178
206
  return root;
2179
207
  }
2180
208
  function updateUiGrid(root, props) {
2181
- root.render(import_react4.default.createElement(UiGrid, props));
209
+ root.render(import_react2.default.createElement(UiGrid, props));
2182
210
  }
2183
211
  function styledCell(text, color, extraStyle) {
2184
- return import_react4.default.createElement(
212
+ return import_react2.default.createElement(
2185
213
  "span",
2186
214
  { style: { color, fontVariantNumeric: "tabular-nums", ...extraStyle } },
2187
215
  text
2188
216
  );
2189
217
  }
218
+ function datePickerCell(value, onChange, extraStyle) {
219
+ return import_react2.default.createElement("input", {
220
+ type: "date",
221
+ value: value || "",
222
+ onChange: onChange ? (e) => onChange(e.target.value) : void 0,
223
+ style: {
224
+ font: "inherit",
225
+ fontSize: "0.85rem",
226
+ border: "1px solid color-mix(in srgb, currentColor 20%, transparent)",
227
+ borderRadius: "6px",
228
+ padding: "0.2rem 0.4rem",
229
+ background: "var(--ui-grid-surface, white)",
230
+ color: "inherit",
231
+ cursor: "pointer",
232
+ ...extraStyle
233
+ }
234
+ });
235
+ }
2190
236
 
2191
237
  // src/vanillaAdapter.ts
2192
238
  async function mountUiGridCustomElement(container, mountOptions) {
@@ -2207,44 +253,15 @@ async function mountUiGridCustomElement(container, mountOptions) {
2207
253
  };
2208
254
  }
2209
255
 
2210
- // src/rustWasmGridEngine.ts
2211
- var import_ui_grid_core3 = require("@ornery/ui-grid-core");
2212
- var uiGridWasmModulePath = "../../../dist/ui-grid-wasm-web/ui_grid_wasm.js";
2213
- var uiGridWasmBinaryPath = "/dist/ui-grid-wasm-web/ui_grid_wasm_bg.wasm";
2214
- function registerReactUiGridWasmEngineFromModule(module2) {
2215
- (0, import_ui_grid_core3.registerRustWasmGridEngine)({
2216
- buildPipeline(context) {
2217
- return module2.build_pipeline_js(context);
2218
- }
2219
- });
2220
- }
2221
- async function enableReactUiGridWasmEngine() {
2222
- const module2 = await import(
2223
- /* @vite-ignore */
2224
- uiGridWasmModulePath
2225
- );
2226
- await module2.default(uiGridWasmBinaryPath);
2227
- registerReactUiGridWasmEngineFromModule(module2);
2228
- }
2229
-
2230
256
  // src/index.ts
2231
- var import_ui_grid_core4 = require("@ornery/ui-grid-core");
257
+ var import_ui_grid_core = require("@ornery/ui-grid-core");
2232
258
  // Annotate the CommonJS export names for ESM import in node:
2233
259
  0 && (module.exports = {
2234
260
  DEFAULT_GRID_LABELS,
2235
261
  UiGrid,
2236
- buildGridTemplateColumns,
2237
- computeViewportHeightPx,
2238
- computeViewportRows,
2239
- enableReactUiGridWasmEngine,
2240
- formatPaginationSummary,
262
+ datePickerCell,
2241
263
  mountUiGrid,
2242
264
  mountUiGridCustomElement,
2243
- orderVisibleColumns,
2244
- registerReactUiGridWasmEngineFromModule,
2245
- resolveBenchmarkIterations,
2246
265
  styledCell,
2247
- updateUiGrid,
2248
- useGridState,
2249
- useVirtualScroll
266
+ updateUiGrid
2250
267
  });