@youp-grid/react 0.2.2 → 0.2.4
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/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/YoupGrid.js +562 -36
- package/dist/index.d.ts +1 -1
- package/dist/styles.css +156 -2
- package/dist/types.d.ts +52 -0
- package/dist/useYoupGrid.js +9 -1
- package/package.json +17 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Seungyoup Baek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -10,3 +10,18 @@ npm install @youp-grid/core @youp-grid/react
|
|
|
10
10
|
import { YoupGrid } from "@youp-grid/react";
|
|
11
11
|
import "@youp-grid/react/styles.css";
|
|
12
12
|
```
|
|
13
|
+
|
|
14
|
+
## What It Provides
|
|
15
|
+
|
|
16
|
+
- virtualized React grid UI
|
|
17
|
+
- keyboard navigation and inline editing
|
|
18
|
+
- built-in text, number, checkbox, and select editors
|
|
19
|
+
- clipboard paste, fill handle, delete, undo, and redo write paths
|
|
20
|
+
- column menus, resizing, pinning, visibility, density, and row selection UI
|
|
21
|
+
- loading, empty, error, validation, pending, warning, and read-only states
|
|
22
|
+
|
|
23
|
+
The adapter emits changes through callbacks. Applications keep ownership of row data.
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
MIT. See the repository license.
|
package/dist/YoupGrid.js
CHANGED
|
@@ -8,6 +8,7 @@ const DENSITY_ROW_HEIGHTS = {
|
|
|
8
8
|
standard: 38,
|
|
9
9
|
comfortable: 46,
|
|
10
10
|
};
|
|
11
|
+
const ROW_NUMBER_COLUMN_WIDTH = 44;
|
|
11
12
|
const SELECTION_COLUMN_WIDTH = 44;
|
|
12
13
|
const AUTOSIZE_CELL_EXTRA_WIDTH = 8;
|
|
13
14
|
const AUTOSIZE_CELL_BORDER_THRESHOLD = 6;
|
|
@@ -34,8 +35,13 @@ export function YoupGrid(props) {
|
|
|
34
35
|
const [editingCell, setEditingCell] = useState();
|
|
35
36
|
const [columnChooserOpen, setColumnChooserOpen] = useState(false);
|
|
36
37
|
const [columnMenuOpenId, setColumnMenuOpenId] = useState();
|
|
38
|
+
const [cellContextMenu, setCellContextMenu] = useState();
|
|
39
|
+
const [activeTooltipCellKey, setActiveTooltipCellKey] = useState();
|
|
40
|
+
const showRowNumberColumn = props.showRowNumberColumn ?? false;
|
|
37
41
|
const showRowSelectionColumn = props.showRowSelectionColumn ?? false;
|
|
38
42
|
const pinRowSelectionColumn = props.pinRowSelectionColumn ?? false;
|
|
43
|
+
const showCellContextMenu = props.showCellContextMenu ?? false;
|
|
44
|
+
const cellTooltipMode = props.cellTooltip?.mode ?? "native";
|
|
39
45
|
const gridEditable = (props.editable ?? true) && !props.readOnly;
|
|
40
46
|
const displayRows = rowModel.displayRows;
|
|
41
47
|
const virtualRange = useMemo(() => {
|
|
@@ -77,11 +83,14 @@ export function YoupGrid(props) {
|
|
|
77
83
|
const selectedVisibleRowCount = visibleRowIds.filter((rowId) => selectedRowIds.has(rowId)).length;
|
|
78
84
|
const allVisibleRowsSelected = visibleRowIds.length > 0 && selectedVisibleRowCount === visibleRowIds.length;
|
|
79
85
|
const someVisibleRowsSelected = selectedVisibleRowCount > 0 && !allVisibleRowsSelected;
|
|
86
|
+
const rowNumberColumnOffset = showRowNumberColumn ? ROW_NUMBER_COLUMN_WIDTH : 0;
|
|
87
|
+
const selectionColumnOffset = showRowSelectionColumn && pinRowSelectionColumn ? rowNumberColumnOffset : 0;
|
|
88
|
+
const pinnedColumnOffset = rowNumberColumnOffset + (showRowSelectionColumn && pinRowSelectionColumn ? SELECTION_COLUMN_WIDTH : 0);
|
|
80
89
|
const columnLayouts = useMemo(() => {
|
|
81
90
|
return getColumnLayouts(rowModel.visibleColumns, {
|
|
82
|
-
leftOffset:
|
|
91
|
+
leftOffset: pinnedColumnOffset,
|
|
83
92
|
});
|
|
84
|
-
}, [
|
|
93
|
+
}, [pinnedColumnOffset, rowModel.visibleColumns]);
|
|
85
94
|
const visibleColumns = useMemo(() => columnLayouts.map((layout) => layout.column), [columnLayouts]);
|
|
86
95
|
const visibleRowIndexById = useMemo(() => {
|
|
87
96
|
return new Map(rowModel.visibleRows.map((row, index) => [row.id, index]));
|
|
@@ -133,7 +142,7 @@ export function YoupGrid(props) {
|
|
|
133
142
|
};
|
|
134
143
|
const getGridCellMeta = (row, rowIndex, column) => {
|
|
135
144
|
return (props.getCellMeta?.(getCellEditContext(row, rowIndex, column)) ??
|
|
136
|
-
props.cellMeta?.[
|
|
145
|
+
props.cellMeta?.[getCellKey(row.id, column.id)]);
|
|
137
146
|
};
|
|
138
147
|
const createGridCellValueChange = (cell, value) => {
|
|
139
148
|
if (!cell.editable) {
|
|
@@ -167,6 +176,44 @@ export function YoupGrid(props) {
|
|
|
167
176
|
setColumnMenuOpenId(undefined);
|
|
168
177
|
}
|
|
169
178
|
}, [columnMenuOpenId, visibleColumns]);
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
if (!cellContextMenu) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const closeMenu = () => setCellContextMenu(undefined);
|
|
184
|
+
const handleKeyDown = (event) => {
|
|
185
|
+
if (event.key === "Escape") {
|
|
186
|
+
closeMenu();
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
document.addEventListener("click", closeMenu);
|
|
190
|
+
document.addEventListener("contextmenu", closeMenu);
|
|
191
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
192
|
+
return () => {
|
|
193
|
+
document.removeEventListener("click", closeMenu);
|
|
194
|
+
document.removeEventListener("contextmenu", closeMenu);
|
|
195
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
196
|
+
};
|
|
197
|
+
}, [cellContextMenu]);
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
if (cellTooltipMode !== "rich") {
|
|
200
|
+
setActiveTooltipCellKey(undefined);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const cellKey = props.cellTooltip?.autoOpenCellKey;
|
|
204
|
+
if (!cellKey) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
setActiveTooltipCellKey(cellKey);
|
|
208
|
+
const duration = props.cellTooltip?.autoOpenDurationMs ?? 2000;
|
|
209
|
+
if (duration <= 0) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const timeout = window.setTimeout(() => {
|
|
213
|
+
setActiveTooltipCellKey((current) => current === cellKey ? undefined : current);
|
|
214
|
+
}, duration);
|
|
215
|
+
return () => window.clearTimeout(timeout);
|
|
216
|
+
}, [cellTooltipMode, props.cellTooltip?.autoOpenCellKey, props.cellTooltip?.autoOpenDurationMs]);
|
|
170
217
|
useEffect(() => {
|
|
171
218
|
if (!props.infiniteScroll || !props.onRowsEndReached || !infiniteScrollTrigger.shouldLoadMore) {
|
|
172
219
|
return;
|
|
@@ -312,11 +359,207 @@ export function YoupGrid(props) {
|
|
|
312
359
|
const visibleRowIdSet = new Set(visibleRowIds);
|
|
313
360
|
controller.setSelectedRows(currentSelectedRowIds.filter((rowId) => !visibleRowIdSet.has(rowId)));
|
|
314
361
|
};
|
|
362
|
+
const openCellContextMenu = (event, cell) => {
|
|
363
|
+
if (!showCellContextMenu || editingCell) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
event.preventDefault();
|
|
367
|
+
event.stopPropagation();
|
|
368
|
+
const insideSelection = selectionRange
|
|
369
|
+
? isCellInRange(cell.rowIndex, cell.columnIndex, selectionRange)
|
|
370
|
+
: false;
|
|
371
|
+
if (!insideSelection) {
|
|
372
|
+
setSelectionRange(undefined);
|
|
373
|
+
}
|
|
374
|
+
setFocusedRowIndex(cell.rowIndex);
|
|
375
|
+
setFocusedColumnIndex(cell.columnIndex);
|
|
376
|
+
setCellContextMenu({
|
|
377
|
+
rowIndex: cell.rowIndex,
|
|
378
|
+
columnIndex: cell.columnIndex,
|
|
379
|
+
clientX: event.clientX,
|
|
380
|
+
clientY: event.clientY,
|
|
381
|
+
anchor: event.currentTarget,
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
const getCellContextMenuRange = () => {
|
|
385
|
+
if (!cellContextMenu || !selectionRange) {
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
return isCellInRange(cellContextMenu.rowIndex, cellContextMenu.columnIndex, selectionRange)
|
|
389
|
+
? selectionRange
|
|
390
|
+
: undefined;
|
|
391
|
+
};
|
|
392
|
+
const copyCellContextMenuSelection = () => {
|
|
393
|
+
if (!cellContextMenu) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
void writeClipboardText(getGridClipboardText({
|
|
397
|
+
focusedCell: {
|
|
398
|
+
rowIndex: cellContextMenu.rowIndex,
|
|
399
|
+
columnIndex: cellContextMenu.columnIndex,
|
|
400
|
+
},
|
|
401
|
+
selectionRange: getCellContextMenuRange(),
|
|
402
|
+
rows: rowModel.visibleRows,
|
|
403
|
+
columns: visibleColumns,
|
|
404
|
+
})).catch(() => undefined);
|
|
405
|
+
};
|
|
406
|
+
const pasteCellContextMenuSelection = () => {
|
|
407
|
+
if (!cellContextMenu || !gridEditable) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
void readClipboardText()
|
|
411
|
+
.then((text) => {
|
|
412
|
+
applyGridClipboardText({
|
|
413
|
+
text,
|
|
414
|
+
focusedCell: {
|
|
415
|
+
rowIndex: cellContextMenu.rowIndex,
|
|
416
|
+
columnIndex: cellContextMenu.columnIndex,
|
|
417
|
+
},
|
|
418
|
+
selectionRange: getCellContextMenuRange(),
|
|
419
|
+
rows: rowModel.visibleRows,
|
|
420
|
+
columns: visibleColumns,
|
|
421
|
+
canEditCell: canEditGridCell,
|
|
422
|
+
applyCellValueChanges,
|
|
423
|
+
});
|
|
424
|
+
})
|
|
425
|
+
.catch(() => undefined);
|
|
426
|
+
};
|
|
427
|
+
const clearCellContextMenuSelection = () => {
|
|
428
|
+
if (!cellContextMenu || !gridEditable) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
deleteGridCellValues({
|
|
432
|
+
focusedCell: {
|
|
433
|
+
rowIndex: cellContextMenu.rowIndex,
|
|
434
|
+
columnIndex: cellContextMenu.columnIndex,
|
|
435
|
+
},
|
|
436
|
+
selectionRange: getCellContextMenuRange(),
|
|
437
|
+
rows: rowModel.visibleRows,
|
|
438
|
+
columns: visibleColumns,
|
|
439
|
+
canEditCell: canEditGridCell,
|
|
440
|
+
applyCellValueChanges,
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
const selectCellContextMenuRow = () => {
|
|
444
|
+
if (!cellContextMenu) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const row = rowModel.visibleRows[cellContextMenu.rowIndex];
|
|
448
|
+
if (row) {
|
|
449
|
+
controller.setRowSelected(row.id, true);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
const getCellContextMenuTargetRows = () => {
|
|
453
|
+
if (!cellContextMenu) {
|
|
454
|
+
return [];
|
|
455
|
+
}
|
|
456
|
+
const row = rowModel.visibleRows[cellContextMenu.rowIndex];
|
|
457
|
+
if (!row || isRowGroupNode(row)) {
|
|
458
|
+
return [];
|
|
459
|
+
}
|
|
460
|
+
if (selectedRowIds.has(row.id)) {
|
|
461
|
+
return rowModel.visibleRows.filter((visibleRow) => {
|
|
462
|
+
return !isRowGroupNode(visibleRow) && selectedRowIds.has(visibleRow.id);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
return [row];
|
|
466
|
+
};
|
|
467
|
+
const getCellContextMenuDeleteRowCount = () => getCellContextMenuTargetRows().length;
|
|
468
|
+
const insertCellContextMenuRow = (position) => {
|
|
469
|
+
if (!cellContextMenu || !gridEditable || !props.createRow || !props.onRowsChange) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const anchorRow = rowModel.visibleRows[cellContextMenu.rowIndex];
|
|
473
|
+
if (!anchorRow || isRowGroupNode(anchorRow)) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const rowIndex = anchorRow.index + (position === "below" ? 1 : 0);
|
|
477
|
+
const visibleRowIndex = cellContextMenu.rowIndex + (position === "below" ? 1 : 0);
|
|
478
|
+
const row = props.createRow({
|
|
479
|
+
rows: props.rows,
|
|
480
|
+
rowIndex,
|
|
481
|
+
visibleRowIndex,
|
|
482
|
+
position,
|
|
483
|
+
anchorRow: anchorRow.original,
|
|
484
|
+
anchorRowId: anchorRow.id,
|
|
485
|
+
anchorRowIndex: anchorRow.index,
|
|
486
|
+
});
|
|
487
|
+
const rows = [
|
|
488
|
+
...props.rows.slice(0, rowIndex),
|
|
489
|
+
row,
|
|
490
|
+
...props.rows.slice(rowIndex),
|
|
491
|
+
];
|
|
492
|
+
props.onRowsChange({
|
|
493
|
+
rows,
|
|
494
|
+
changes: [{
|
|
495
|
+
type: "insert",
|
|
496
|
+
row,
|
|
497
|
+
rowIndex,
|
|
498
|
+
visibleRowIndex,
|
|
499
|
+
position,
|
|
500
|
+
anchorRow: anchorRow.original,
|
|
501
|
+
anchorRowId: anchorRow.id,
|
|
502
|
+
anchorRowIndex: anchorRow.index,
|
|
503
|
+
}],
|
|
504
|
+
source: "context-menu",
|
|
505
|
+
});
|
|
506
|
+
setSelectionRange(undefined);
|
|
507
|
+
setFocusedRowIndex(visibleRowIndex);
|
|
508
|
+
};
|
|
509
|
+
const deleteCellContextMenuRows = () => {
|
|
510
|
+
if (!gridEditable || !props.onRowsChange) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const targetRows = getCellContextMenuTargetRows();
|
|
514
|
+
if (targetRows.length === 0) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const visibleRowIndexByRowId = new Map();
|
|
518
|
+
rowModel.visibleRows.forEach((row, index) => {
|
|
519
|
+
if (!isRowGroupNode(row)) {
|
|
520
|
+
visibleRowIndexByRowId.set(row.id, index);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
const deleteRowIds = new Set(targetRows.map((row) => row.id));
|
|
524
|
+
const deleteRowIndexes = new Set(targetRows.map((row) => row.index));
|
|
525
|
+
const rows = props.rows.filter((_, index) => !deleteRowIndexes.has(index));
|
|
526
|
+
props.onRowsChange({
|
|
527
|
+
rows,
|
|
528
|
+
changes: targetRows
|
|
529
|
+
.slice()
|
|
530
|
+
.sort((left, right) => left.index - right.index)
|
|
531
|
+
.map((row) => ({
|
|
532
|
+
type: "delete",
|
|
533
|
+
row: row.original,
|
|
534
|
+
rowId: row.id,
|
|
535
|
+
rowIndex: row.index,
|
|
536
|
+
visibleRowIndex: visibleRowIndexByRowId.get(row.id) ?? row.index,
|
|
537
|
+
})),
|
|
538
|
+
source: "context-menu",
|
|
539
|
+
});
|
|
540
|
+
controller.setSelectedRows(currentSelectedRowIds.filter((rowId) => !deleteRowIds.has(rowId)));
|
|
541
|
+
setSelectionRange(undefined);
|
|
542
|
+
setFocusedRowIndex(Math.min(cellContextMenu?.rowIndex ?? 0, Math.max(0, rowModel.visibleRows.length - targetRows.length - 1)));
|
|
543
|
+
};
|
|
544
|
+
const autoSizeCellContextMenuColumn = () => {
|
|
545
|
+
if (!cellContextMenu) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const column = visibleColumns[cellContextMenu.columnIndex];
|
|
549
|
+
if (column) {
|
|
550
|
+
controller.setColumnWidth(column.id, getAutoSizeColumnWidth({
|
|
551
|
+
anchor: cellContextMenu.anchor,
|
|
552
|
+
column,
|
|
553
|
+
rows: rowModel.visibleRows,
|
|
554
|
+
}));
|
|
555
|
+
}
|
|
556
|
+
};
|
|
315
557
|
return createElement("div", {
|
|
316
558
|
className: [
|
|
317
559
|
"youp-grid",
|
|
318
560
|
`youp-grid--density-${density}`,
|
|
319
561
|
!gridEditable ? "youp-grid--read-only" : "",
|
|
562
|
+
showRowNumberColumn ? "youp-grid--row-number-column" : "",
|
|
320
563
|
pinRowSelectionColumn ? "youp-grid--selection-column-pinned" : "",
|
|
321
564
|
props.className,
|
|
322
565
|
].filter(Boolean).join(" "),
|
|
@@ -349,7 +592,7 @@ export function YoupGrid(props) {
|
|
|
349
592
|
className: "youp-grid__viewport",
|
|
350
593
|
role: "grid",
|
|
351
594
|
"aria-rowcount": displayRows.length,
|
|
352
|
-
"aria-colcount": rowModel.visibleColumns.length + (showRowSelectionColumn ? 1 : 0),
|
|
595
|
+
"aria-colcount": rowModel.visibleColumns.length + (showRowNumberColumn ? 1 : 0) + (showRowSelectionColumn ? 1 : 0),
|
|
353
596
|
"aria-busy": loading || undefined,
|
|
354
597
|
"aria-readonly": !gridEditable || undefined,
|
|
355
598
|
onCopy: (event) => {
|
|
@@ -379,14 +622,19 @@ export function YoupGrid(props) {
|
|
|
379
622
|
});
|
|
380
623
|
},
|
|
381
624
|
}, createElement("div", { className: "youp-grid__header", role: "rowgroup", ref: headerRef }, hasHeaderGroups
|
|
382
|
-
? createElement("div", { className: "youp-grid__row youp-grid__row--header-group", role: "row" },
|
|
383
|
-
?
|
|
625
|
+
? createElement("div", { className: "youp-grid__row youp-grid__row--header-group", role: "row" }, showRowNumberColumn
|
|
626
|
+
? renderRowNumberHeaderGroupCell()
|
|
627
|
+
: undefined, showRowSelectionColumn
|
|
628
|
+
? renderSelectionHeaderGroupCell(selectionColumnOffset)
|
|
384
629
|
: undefined, headerGroupLayouts.map((layout) => renderHeaderGroupCell(layout)))
|
|
385
|
-
: undefined, createElement("div", { className: "youp-grid__row youp-grid__row--header", role: "row" },
|
|
630
|
+
: undefined, createElement("div", { className: "youp-grid__row youp-grid__row--header", role: "row" }, showRowNumberColumn
|
|
631
|
+
? renderRowNumberHeaderCell()
|
|
632
|
+
: undefined, showRowSelectionColumn
|
|
386
633
|
? renderSelectionHeaderCell({
|
|
387
634
|
checked: allVisibleRowsSelected,
|
|
388
635
|
indeterminate: someVisibleRowsSelected,
|
|
389
636
|
disabled: visibleRowIds.length === 0,
|
|
637
|
+
leftOffset: selectionColumnOffset,
|
|
390
638
|
toggleSelected: setVisibleRowsSelected,
|
|
391
639
|
})
|
|
392
640
|
: undefined, columnLayouts.map((layout) => {
|
|
@@ -452,7 +700,9 @@ export function YoupGrid(props) {
|
|
|
452
700
|
return renderGroupRow({
|
|
453
701
|
row,
|
|
454
702
|
columns: columnLayouts,
|
|
703
|
+
showRowNumberColumn,
|
|
455
704
|
showSelectionColumn: showRowSelectionColumn,
|
|
705
|
+
selectionColumnOffset,
|
|
456
706
|
rowHeight,
|
|
457
707
|
toggleExpanded: controller.toggleRowGroupExpanded,
|
|
458
708
|
});
|
|
@@ -462,7 +712,9 @@ export function YoupGrid(props) {
|
|
|
462
712
|
row,
|
|
463
713
|
columns: columnLayouts,
|
|
464
714
|
selected: selectedRowIds.has(row.id),
|
|
715
|
+
showRowNumberColumn,
|
|
465
716
|
showSelectionColumn: showRowSelectionColumn,
|
|
717
|
+
selectionColumnOffset,
|
|
466
718
|
displayIndex,
|
|
467
719
|
rowIndex,
|
|
468
720
|
rowHeight,
|
|
@@ -475,10 +727,12 @@ export function YoupGrid(props) {
|
|
|
475
727
|
editingCell,
|
|
476
728
|
editable: gridEditable,
|
|
477
729
|
disabledReason: props.disabledReason,
|
|
730
|
+
treeData: props.treeData ?? false,
|
|
478
731
|
canEditCell: canEditGridCell,
|
|
479
732
|
getCellMeta: getGridCellMeta,
|
|
480
733
|
setRowSelected: (selected) => controller.setRowSelected(row.id, selected),
|
|
481
734
|
setFocusedCell,
|
|
735
|
+
toggleTreeRowExpanded: controller.toggleTreeRowExpanded,
|
|
482
736
|
startFillHandle: (event) => {
|
|
483
737
|
if (!gridEditable) {
|
|
484
738
|
return;
|
|
@@ -524,6 +778,13 @@ export function YoupGrid(props) {
|
|
|
524
778
|
},
|
|
525
779
|
cancelEditing: cancelEditingCell,
|
|
526
780
|
commitEditing: commitEditingValue,
|
|
781
|
+
cellTooltipMode,
|
|
782
|
+
activeTooltipCellKey,
|
|
783
|
+
openCellTooltip: setActiveTooltipCellKey,
|
|
784
|
+
closeCellTooltip: (cellKey) => {
|
|
785
|
+
setActiveTooltipCellKey((current) => current === cellKey ? undefined : current);
|
|
786
|
+
},
|
|
787
|
+
openCellContextMenu: showCellContextMenu ? openCellContextMenu : undefined,
|
|
527
788
|
onRowClick: props.onRowClick,
|
|
528
789
|
onRowDoubleClick: props.onRowDoubleClick,
|
|
529
790
|
onCellKeyDown: (event, cell) => {
|
|
@@ -567,8 +828,27 @@ export function YoupGrid(props) {
|
|
|
567
828
|
enabled: showAggregationFooter,
|
|
568
829
|
aggregation: rowModel.aggregation,
|
|
569
830
|
columns: columnLayouts,
|
|
831
|
+
showRowNumberColumn,
|
|
570
832
|
showSelectionColumn: showRowSelectionColumn,
|
|
571
|
-
|
|
833
|
+
selectionColumnOffset,
|
|
834
|
+
})), renderCellContextMenu({
|
|
835
|
+
state: cellContextMenu,
|
|
836
|
+
editable: gridEditable,
|
|
837
|
+
hasSelectedRows: selectedRowIds.size > 0,
|
|
838
|
+
canInsertRows: gridEditable && Boolean(props.createRow && props.onRowsChange),
|
|
839
|
+
canDeleteRows: gridEditable && Boolean(props.onRowsChange && getCellContextMenuDeleteRowCount() > 0),
|
|
840
|
+
deleteRowLabel: getCellContextMenuDeleteRowCount() > 1 ? "Delete selected rows" : "Delete row",
|
|
841
|
+
copy: copyCellContextMenuSelection,
|
|
842
|
+
paste: pasteCellContextMenuSelection,
|
|
843
|
+
clearContents: clearCellContextMenuSelection,
|
|
844
|
+
selectRow: selectCellContextMenuRow,
|
|
845
|
+
clearRowSelection: () => controller.setSelectedRows([]),
|
|
846
|
+
insertRowAbove: () => insertCellContextMenuRow("above"),
|
|
847
|
+
insertRowBelow: () => insertCellContextMenuRow("below"),
|
|
848
|
+
deleteRows: deleteCellContextMenuRows,
|
|
849
|
+
autoSizeColumn: autoSizeCellContextMenuColumn,
|
|
850
|
+
closeMenu: () => setCellContextMenu(undefined),
|
|
851
|
+
}), renderPagination({
|
|
572
852
|
enabled: props.showPagination ?? true,
|
|
573
853
|
cursorPagination: controller.state.cursorPagination,
|
|
574
854
|
pageCount: rowModel.pageCount,
|
|
@@ -601,7 +881,7 @@ function renderAggregationFooter(context) {
|
|
|
601
881
|
return undefined;
|
|
602
882
|
}
|
|
603
883
|
const aggregationByColumn = groupAggregationByColumn(context.aggregation);
|
|
604
|
-
return createElement("div", { className: "youp-grid__aggregation", role: "rowgroup" }, createElement("div", { className: "youp-grid__row youp-grid__row--aggregation", role: "row" }, context.showSelectionColumn ? renderSelectionAggregationCell() : undefined, context.columns.map((layout) => {
|
|
884
|
+
return createElement("div", { className: "youp-grid__aggregation", role: "rowgroup" }, createElement("div", { className: "youp-grid__row youp-grid__row--aggregation", role: "row" }, context.showRowNumberColumn ? renderRowNumberAggregationCell() : undefined, context.showSelectionColumn ? renderSelectionAggregationCell(context.selectionColumnOffset) : undefined, context.columns.map((layout) => {
|
|
605
885
|
const results = aggregationByColumn.get(layout.column.id) ?? [];
|
|
606
886
|
return createElement("div", {
|
|
607
887
|
key: layout.column.id,
|
|
@@ -611,11 +891,19 @@ function renderAggregationFooter(context) {
|
|
|
611
891
|
}, results.map(formatAggregationResult).join(" · "));
|
|
612
892
|
})));
|
|
613
893
|
}
|
|
614
|
-
function
|
|
894
|
+
function renderRowNumberAggregationCell() {
|
|
895
|
+
return createElement("div", {
|
|
896
|
+
className: "youp-grid__cell youp-grid__row-number-cell youp-grid__row-number-cell--aggregation",
|
|
897
|
+
role: "gridcell",
|
|
898
|
+
style: getRowNumberCellStyle(),
|
|
899
|
+
"aria-hidden": true,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
function renderSelectionAggregationCell(leftOffset) {
|
|
615
903
|
return createElement("div", {
|
|
616
904
|
className: "youp-grid__selection-cell youp-grid__selection-cell--aggregation",
|
|
617
905
|
role: "gridcell",
|
|
618
|
-
style: getSelectionCellStyle(),
|
|
906
|
+
style: getSelectionCellStyle(leftOffset),
|
|
619
907
|
"aria-hidden": true,
|
|
620
908
|
});
|
|
621
909
|
}
|
|
@@ -650,13 +938,31 @@ function renderHeaderGroupCell(layout) {
|
|
|
650
938
|
style: getHeaderGroupStyle(layout),
|
|
651
939
|
}, layout.headerGroup ?? "");
|
|
652
940
|
}
|
|
653
|
-
function
|
|
941
|
+
function renderRowNumberHeaderGroupCell() {
|
|
942
|
+
return createElement("div", {
|
|
943
|
+
key: "__row-number-group",
|
|
944
|
+
className: "youp-grid__cell youp-grid__cell--header-group youp-grid__row-number-cell youp-grid__row-number-cell--header-group",
|
|
945
|
+
role: "columnheader",
|
|
946
|
+
"aria-hidden": true,
|
|
947
|
+
style: getRowNumberCellStyle(),
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
function renderRowNumberHeaderCell() {
|
|
951
|
+
return createElement("div", {
|
|
952
|
+
key: "__row-number",
|
|
953
|
+
className: "youp-grid__cell youp-grid__cell--header youp-grid__row-number-cell youp-grid__row-number-cell--header",
|
|
954
|
+
role: "columnheader",
|
|
955
|
+
"aria-label": "Row number",
|
|
956
|
+
style: getRowNumberCellStyle(),
|
|
957
|
+
}, "#");
|
|
958
|
+
}
|
|
959
|
+
function renderSelectionHeaderGroupCell(leftOffset) {
|
|
654
960
|
return createElement("div", {
|
|
655
961
|
key: "__selection-group",
|
|
656
962
|
className: "youp-grid__cell youp-grid__cell--header-group youp-grid__selection-cell youp-grid__selection-cell--header-group",
|
|
657
963
|
role: "columnheader",
|
|
658
964
|
"aria-hidden": true,
|
|
659
|
-
style: getSelectionCellStyle(),
|
|
965
|
+
style: getSelectionCellStyle(leftOffset),
|
|
660
966
|
});
|
|
661
967
|
}
|
|
662
968
|
function renderSelectionHeaderCell(context) {
|
|
@@ -664,7 +970,7 @@ function renderSelectionHeaderCell(context) {
|
|
|
664
970
|
key: "__selection",
|
|
665
971
|
className: "youp-grid__cell youp-grid__cell--header youp-grid__selection-cell youp-grid__selection-cell--header",
|
|
666
972
|
role: "columnheader",
|
|
667
|
-
style: getSelectionCellStyle(),
|
|
973
|
+
style: getSelectionCellStyle(context.leftOffset),
|
|
668
974
|
}, createElement(SelectionHeaderCheckbox, context));
|
|
669
975
|
}
|
|
670
976
|
function SelectionHeaderCheckbox(context) {
|
|
@@ -811,6 +1117,63 @@ function renderColumnMenuButton(context) {
|
|
|
811
1117
|
},
|
|
812
1118
|
}, context.label);
|
|
813
1119
|
}
|
|
1120
|
+
function renderCellContextMenu(context) {
|
|
1121
|
+
if (!context.state) {
|
|
1122
|
+
return undefined;
|
|
1123
|
+
}
|
|
1124
|
+
const runAction = (action) => {
|
|
1125
|
+
action();
|
|
1126
|
+
context.closeMenu();
|
|
1127
|
+
};
|
|
1128
|
+
return createElement("div", {
|
|
1129
|
+
className: "youp-grid__cell-context-menu",
|
|
1130
|
+
role: "menu",
|
|
1131
|
+
style: {
|
|
1132
|
+
left: context.state.clientX,
|
|
1133
|
+
top: context.state.clientY,
|
|
1134
|
+
},
|
|
1135
|
+
onClick: (event) => {
|
|
1136
|
+
event.stopPropagation();
|
|
1137
|
+
},
|
|
1138
|
+
onContextMenu: (event) => {
|
|
1139
|
+
event.preventDefault();
|
|
1140
|
+
event.stopPropagation();
|
|
1141
|
+
},
|
|
1142
|
+
}, renderColumnMenuButton({
|
|
1143
|
+
label: "Copy",
|
|
1144
|
+
onClick: () => runAction(context.copy),
|
|
1145
|
+
}), renderColumnMenuButton({
|
|
1146
|
+
label: "Paste",
|
|
1147
|
+
disabled: !context.editable,
|
|
1148
|
+
onClick: () => runAction(context.paste),
|
|
1149
|
+
}), renderColumnMenuButton({
|
|
1150
|
+
label: "Clear contents",
|
|
1151
|
+
disabled: !context.editable,
|
|
1152
|
+
onClick: () => runAction(context.clearContents),
|
|
1153
|
+
}), createElement("div", { className: "youp-grid__column-menu-separator", role: "separator" }), renderColumnMenuButton({
|
|
1154
|
+
label: "Select row",
|
|
1155
|
+
onClick: () => runAction(context.selectRow),
|
|
1156
|
+
}), renderColumnMenuButton({
|
|
1157
|
+
label: "Clear row selection",
|
|
1158
|
+
disabled: !context.hasSelectedRows,
|
|
1159
|
+
onClick: () => runAction(context.clearRowSelection),
|
|
1160
|
+
}), createElement("div", { className: "youp-grid__column-menu-separator", role: "separator" }), renderColumnMenuButton({
|
|
1161
|
+
label: "Insert row above",
|
|
1162
|
+
disabled: !context.canInsertRows,
|
|
1163
|
+
onClick: () => runAction(context.insertRowAbove),
|
|
1164
|
+
}), renderColumnMenuButton({
|
|
1165
|
+
label: "Insert row below",
|
|
1166
|
+
disabled: !context.canInsertRows,
|
|
1167
|
+
onClick: () => runAction(context.insertRowBelow),
|
|
1168
|
+
}), renderColumnMenuButton({
|
|
1169
|
+
label: context.deleteRowLabel,
|
|
1170
|
+
disabled: !context.canDeleteRows,
|
|
1171
|
+
onClick: () => runAction(context.deleteRows),
|
|
1172
|
+
}), createElement("div", { className: "youp-grid__column-menu-separator", role: "separator" }), renderColumnMenuButton({
|
|
1173
|
+
label: "Auto-size column",
|
|
1174
|
+
onClick: () => runAction(context.autoSizeColumn),
|
|
1175
|
+
}));
|
|
1176
|
+
}
|
|
814
1177
|
function renderGroupRow(context) {
|
|
815
1178
|
const width = getColumnsWidth(context.columns);
|
|
816
1179
|
return createElement("div", {
|
|
@@ -819,7 +1182,7 @@ function renderGroupRow(context) {
|
|
|
819
1182
|
role: "row",
|
|
820
1183
|
"aria-rowindex": context.row.index + 1,
|
|
821
1184
|
style: { height: context.rowHeight },
|
|
822
|
-
}, context.showSelectionColumn ? renderSelectionGroupCell() : undefined, createElement("div", {
|
|
1185
|
+
}, context.showRowNumberColumn ? renderRowNumberGroupCell() : undefined, context.showSelectionColumn ? renderSelectionGroupCell(context.selectionColumnOffset) : undefined, createElement("div", {
|
|
823
1186
|
className: "youp-grid__cell youp-grid__cell--group",
|
|
824
1187
|
role: "gridcell",
|
|
825
1188
|
"aria-colspan": context.columns.length,
|
|
@@ -835,11 +1198,19 @@ function renderGroupRow(context) {
|
|
|
835
1198
|
onClick: () => context.toggleExpanded(context.row.groupId),
|
|
836
1199
|
}, createElement("span", { className: "youp-grid__group-caret", "aria-hidden": true }, context.row.expanded ? "v" : ">"), createElement("span", { className: "youp-grid__group-label" }, context.row.label), createElement("span", { className: "youp-grid__group-count" }, `${context.row.rowCount} rows`))));
|
|
837
1200
|
}
|
|
838
|
-
function
|
|
1201
|
+
function renderRowNumberGroupCell() {
|
|
1202
|
+
return createElement("div", {
|
|
1203
|
+
className: "youp-grid__cell youp-grid__row-number-cell youp-grid__row-number-cell--group",
|
|
1204
|
+
role: "gridcell",
|
|
1205
|
+
style: getRowNumberCellStyle(),
|
|
1206
|
+
"aria-hidden": true,
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
function renderSelectionGroupCell(leftOffset) {
|
|
839
1210
|
return createElement("div", {
|
|
840
1211
|
className: "youp-grid__selection-cell youp-grid__selection-cell--group",
|
|
841
1212
|
role: "gridcell",
|
|
842
|
-
style: getSelectionCellStyle(),
|
|
1213
|
+
style: getSelectionCellStyle(leftOffset),
|
|
843
1214
|
"aria-hidden": true,
|
|
844
1215
|
});
|
|
845
1216
|
}
|
|
@@ -867,11 +1238,18 @@ function renderRow(context) {
|
|
|
867
1238
|
context.onRowDoubleClick?.(createRowEvent(context, event));
|
|
868
1239
|
}
|
|
869
1240
|
},
|
|
870
|
-
}, context.
|
|
1241
|
+
}, context.showRowNumberColumn
|
|
1242
|
+
? renderRowNumberCell({
|
|
1243
|
+
rowIndex: context.rowIndex,
|
|
1244
|
+
displayIndex: context.displayIndex,
|
|
1245
|
+
})
|
|
1246
|
+
: undefined, context.showSelectionColumn
|
|
871
1247
|
? renderSelectionCell({
|
|
872
1248
|
rowIndex: context.rowIndex,
|
|
873
1249
|
selected: context.selected,
|
|
874
1250
|
setSelected: context.setRowSelected,
|
|
1251
|
+
leftOffset: context.selectionColumnOffset,
|
|
1252
|
+
ariaColIndex: context.showRowNumberColumn ? 2 : 1,
|
|
875
1253
|
})
|
|
876
1254
|
: undefined, context.columns.map((layout, columnIndex) => {
|
|
877
1255
|
const focused = context.focusedCell.rowIndex === context.rowIndex && context.focusedCell.columnIndex === columnIndex;
|
|
@@ -897,7 +1275,7 @@ function renderRow(context) {
|
|
|
897
1275
|
layout,
|
|
898
1276
|
rowIndex: context.rowIndex,
|
|
899
1277
|
columnIndex,
|
|
900
|
-
ariaColumnOffset: context.showSelectionColumn ? 1 : 0,
|
|
1278
|
+
ariaColumnOffset: (context.showRowNumberColumn ? 1 : 0) + (context.showSelectionColumn ? 1 : 0),
|
|
901
1279
|
focused,
|
|
902
1280
|
selected,
|
|
903
1281
|
fillTargeted,
|
|
@@ -906,8 +1284,10 @@ function renderRow(context) {
|
|
|
906
1284
|
editingCell: context.editingCell,
|
|
907
1285
|
editable,
|
|
908
1286
|
disabledReason: context.disabledReason,
|
|
1287
|
+
treeData: context.treeData,
|
|
909
1288
|
meta,
|
|
910
1289
|
setFocusedCell: context.setFocusedCell,
|
|
1290
|
+
toggleTreeRowExpanded: context.toggleTreeRowExpanded,
|
|
911
1291
|
startFillHandle: context.startFillHandle,
|
|
912
1292
|
autoSizeColumn: context.autoSizeColumn,
|
|
913
1293
|
applyCellValue: context.applyCellValue,
|
|
@@ -916,16 +1296,30 @@ function renderRow(context) {
|
|
|
916
1296
|
cancelEditing: context.cancelEditing,
|
|
917
1297
|
commitEditing: context.commitEditing,
|
|
918
1298
|
onKeyDown: context.onCellKeyDown,
|
|
1299
|
+
openContextMenu: context.openCellContextMenu,
|
|
1300
|
+
cellTooltipMode: context.cellTooltipMode,
|
|
1301
|
+
activeTooltipCellKey: context.activeTooltipCellKey,
|
|
1302
|
+
openCellTooltip: context.openCellTooltip,
|
|
1303
|
+
closeCellTooltip: context.closeCellTooltip,
|
|
919
1304
|
renderCell: context.renderCell,
|
|
920
1305
|
});
|
|
921
1306
|
}));
|
|
922
1307
|
}
|
|
1308
|
+
function renderRowNumberCell(context) {
|
|
1309
|
+
return createElement("div", {
|
|
1310
|
+
className: "youp-grid__cell youp-grid__row-number-cell",
|
|
1311
|
+
role: "gridcell",
|
|
1312
|
+
"aria-colindex": 1,
|
|
1313
|
+
"aria-label": `Row ${context.rowIndex + 1}`,
|
|
1314
|
+
style: getRowNumberCellStyle(),
|
|
1315
|
+
}, context.displayIndex + 1);
|
|
1316
|
+
}
|
|
923
1317
|
function renderSelectionCell(context) {
|
|
924
1318
|
return createElement("div", {
|
|
925
1319
|
className: "youp-grid__cell youp-grid__selection-cell",
|
|
926
1320
|
role: "gridcell",
|
|
927
|
-
"aria-colindex":
|
|
928
|
-
style: getSelectionCellStyle(),
|
|
1321
|
+
"aria-colindex": context.ariaColIndex,
|
|
1322
|
+
style: getSelectionCellStyle(context.leftOffset),
|
|
929
1323
|
}, createElement("input", {
|
|
930
1324
|
className: "youp-grid__selection-checkbox",
|
|
931
1325
|
type: "checkbox",
|
|
@@ -960,6 +1354,12 @@ function renderCell(context) {
|
|
|
960
1354
|
const value = column.accessor(context.row.original);
|
|
961
1355
|
const editable = context.editable;
|
|
962
1356
|
const cellAlign = getColumnAlign(column);
|
|
1357
|
+
const cellKey = getCellKey(context.row.id, column.id);
|
|
1358
|
+
const showTreePrefix = context.treeData && context.columnIndex === 0;
|
|
1359
|
+
const hasRichTooltip = context.cellTooltipMode === "rich" && hasTooltipMessage(context.meta);
|
|
1360
|
+
const tooltipId = hasRichTooltip && context.activeTooltipCellKey === cellKey
|
|
1361
|
+
? getCellTooltipId(cellKey)
|
|
1362
|
+
: undefined;
|
|
963
1363
|
const cellContext = {
|
|
964
1364
|
row: context.row,
|
|
965
1365
|
column,
|
|
@@ -968,6 +1368,9 @@ function renderCell(context) {
|
|
|
968
1368
|
focused: context.focused,
|
|
969
1369
|
editable,
|
|
970
1370
|
meta: context.meta,
|
|
1371
|
+
treeDepth: context.row.depth,
|
|
1372
|
+
hasChildren: context.row.hasChildren,
|
|
1373
|
+
expanded: context.row.expanded,
|
|
971
1374
|
};
|
|
972
1375
|
const cellState = {
|
|
973
1376
|
row: context.row,
|
|
@@ -984,8 +1387,16 @@ function renderCell(context) {
|
|
|
984
1387
|
cell: cellState,
|
|
985
1388
|
row: context.row.original,
|
|
986
1389
|
disabledReason: context.disabledReason,
|
|
1390
|
+
cellTooltipMode: context.cellTooltipMode,
|
|
987
1391
|
applyCellValue: context.applyCellValue,
|
|
988
1392
|
});
|
|
1393
|
+
const renderedContent = showTreePrefix && !context.editing
|
|
1394
|
+
? renderTreeCellContent({
|
|
1395
|
+
row: context.row,
|
|
1396
|
+
content: cellContent,
|
|
1397
|
+
toggleExpanded: context.toggleTreeRowExpanded,
|
|
1398
|
+
})
|
|
1399
|
+
: cellContent;
|
|
989
1400
|
return createElement("div", {
|
|
990
1401
|
key: column.id,
|
|
991
1402
|
className: getCellClassName([
|
|
@@ -996,11 +1407,14 @@ function renderCell(context) {
|
|
|
996
1407
|
context.fillTargeted ? "youp-grid__cell--fill-target" : "",
|
|
997
1408
|
context.editing ? "youp-grid__cell--editing" : "",
|
|
998
1409
|
!editable ? "youp-grid__cell--disabled" : "",
|
|
1410
|
+
showTreePrefix ? "youp-grid__cell--tree" : "",
|
|
1411
|
+
tooltipId ? "youp-grid__cell--tooltip-open" : "",
|
|
999
1412
|
context.meta ? `youp-grid__cell--status-${context.meta.status}` : "",
|
|
1000
1413
|
].filter(Boolean).join(" "), context.layout),
|
|
1001
1414
|
role: "gridcell",
|
|
1002
1415
|
tabIndex: context.focused && !context.editing ? 0 : -1,
|
|
1003
|
-
title: getCellTitle(context.meta, context.disabledReason, editable),
|
|
1416
|
+
title: getCellTitle(context.meta, context.disabledReason, editable, context.cellTooltipMode),
|
|
1417
|
+
"aria-describedby": tooltipId,
|
|
1004
1418
|
"aria-colindex": context.columnIndex + context.ariaColumnOffset + 1,
|
|
1005
1419
|
"aria-readonly": !editable || undefined,
|
|
1006
1420
|
"data-youp-row-index": context.rowIndex,
|
|
@@ -1026,6 +1440,34 @@ function renderCell(context) {
|
|
|
1026
1440
|
}
|
|
1027
1441
|
},
|
|
1028
1442
|
onKeyDown: (event) => context.onKeyDown(event, cellState),
|
|
1443
|
+
onContextMenu: context.openContextMenu
|
|
1444
|
+
? (event) => context.openContextMenu?.(event, cellState)
|
|
1445
|
+
: undefined,
|
|
1446
|
+
onMouseEnter: () => {
|
|
1447
|
+
if (hasRichTooltip) {
|
|
1448
|
+
context.openCellTooltip(cellKey);
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
onMouseLeave: () => {
|
|
1452
|
+
if (hasRichTooltip) {
|
|
1453
|
+
context.closeCellTooltip(cellKey);
|
|
1454
|
+
}
|
|
1455
|
+
},
|
|
1456
|
+
onFocus: () => {
|
|
1457
|
+
if (hasRichTooltip) {
|
|
1458
|
+
context.openCellTooltip(cellKey);
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
onBlur: (event) => {
|
|
1462
|
+
if (!hasRichTooltip) {
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
const nextTarget = event.relatedTarget;
|
|
1466
|
+
if (nextTarget && event.currentTarget.contains(nextTarget)) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
context.closeCellTooltip(cellKey);
|
|
1470
|
+
},
|
|
1029
1471
|
}, context.editing
|
|
1030
1472
|
? renderCellEditor({
|
|
1031
1473
|
cell: cellState,
|
|
@@ -1034,7 +1476,7 @@ function renderCell(context) {
|
|
|
1034
1476
|
commitEditing: context.commitEditing,
|
|
1035
1477
|
onKeyDown: context.onKeyDown,
|
|
1036
1478
|
})
|
|
1037
|
-
:
|
|
1479
|
+
: renderedContent, renderCellStatus(context.meta, context.cellTooltipMode), renderCellTooltip(context.meta, tooltipId), !context.editing && context.showFillHandle
|
|
1038
1480
|
? createElement("span", {
|
|
1039
1481
|
className: "youp-grid__fill-handle",
|
|
1040
1482
|
role: "button",
|
|
@@ -1062,7 +1504,7 @@ function renderDefaultCellContent(context) {
|
|
|
1062
1504
|
type: "checkbox",
|
|
1063
1505
|
checked: Boolean(context.cell.value),
|
|
1064
1506
|
disabled: !context.cell.editable,
|
|
1065
|
-
title: getCellTitle(context.cell.meta, context.disabledReason, context.cell.editable),
|
|
1507
|
+
title: getCellTitle(context.cell.meta, context.disabledReason, context.cell.editable, context.cellTooltipMode),
|
|
1066
1508
|
"aria-label": context.cell.column.headerName,
|
|
1067
1509
|
onChange: (event) => {
|
|
1068
1510
|
context.applyCellValue(context.cell, event.currentTarget.checked);
|
|
@@ -1078,7 +1520,37 @@ function renderDefaultCellContent(context) {
|
|
|
1078
1520
|
const text = formatCellValue(context.cell.column, context.row, context.cell.value);
|
|
1079
1521
|
const placeholder = context.cell.column.placeholder;
|
|
1080
1522
|
const hasPlaceholder = text.length === 0 && Boolean(placeholder);
|
|
1081
|
-
return createElement("span", {
|
|
1523
|
+
return createElement("span", {
|
|
1524
|
+
className: [
|
|
1525
|
+
"youp-grid__cell-text",
|
|
1526
|
+
hasPlaceholder ? "youp-grid__cell-placeholder" : "",
|
|
1527
|
+
].filter(Boolean).join(" "),
|
|
1528
|
+
}, hasPlaceholder ? placeholder : text);
|
|
1529
|
+
}
|
|
1530
|
+
function renderTreeCellContent(context) {
|
|
1531
|
+
const depth = Math.max(0, context.row.depth ?? 0);
|
|
1532
|
+
const toggle = context.row.hasChildren
|
|
1533
|
+
? createElement("button", {
|
|
1534
|
+
className: "youp-grid__tree-toggle",
|
|
1535
|
+
type: "button",
|
|
1536
|
+
"aria-label": context.row.expanded ? "Collapse row" : "Expand row",
|
|
1537
|
+
"aria-expanded": context.row.expanded,
|
|
1538
|
+
onClick: (event) => {
|
|
1539
|
+
event.stopPropagation();
|
|
1540
|
+
context.toggleExpanded(context.row.id);
|
|
1541
|
+
},
|
|
1542
|
+
onDoubleClick: (event) => {
|
|
1543
|
+
event.stopPropagation();
|
|
1544
|
+
},
|
|
1545
|
+
onKeyDown: (event) => {
|
|
1546
|
+
event.stopPropagation();
|
|
1547
|
+
},
|
|
1548
|
+
}, createElement("span", { className: "youp-grid__tree-caret", "aria-hidden": true }, context.row.expanded ? "v" : ">"))
|
|
1549
|
+
: createElement("span", { className: "youp-grid__tree-toggle-spacer", "aria-hidden": true });
|
|
1550
|
+
return createElement("span", {
|
|
1551
|
+
className: "youp-grid__cell-tree-content",
|
|
1552
|
+
style: { paddingLeft: depth * 18 },
|
|
1553
|
+
}, toggle, createElement("span", { className: "youp-grid__cell-tree-value" }, context.content));
|
|
1082
1554
|
}
|
|
1083
1555
|
function renderCellEditor(context) {
|
|
1084
1556
|
if (context.cell.column.editor === "select") {
|
|
@@ -1121,16 +1593,26 @@ function renderCellEditor(context) {
|
|
|
1121
1593
|
},
|
|
1122
1594
|
});
|
|
1123
1595
|
}
|
|
1124
|
-
function renderCellStatus(meta) {
|
|
1596
|
+
function renderCellStatus(meta, tooltipMode) {
|
|
1125
1597
|
if (!meta) {
|
|
1126
1598
|
return undefined;
|
|
1127
1599
|
}
|
|
1128
1600
|
return createElement("span", {
|
|
1129
1601
|
className: `youp-grid__cell-status youp-grid__cell-status--${meta.status}`,
|
|
1130
|
-
title: typeof meta.message === "string" ? meta.message : undefined,
|
|
1602
|
+
title: tooltipMode === "native" && typeof meta.message === "string" ? meta.message : undefined,
|
|
1131
1603
|
"aria-hidden": true,
|
|
1132
1604
|
});
|
|
1133
1605
|
}
|
|
1606
|
+
function renderCellTooltip(meta, tooltipId) {
|
|
1607
|
+
if (!tooltipId || !meta?.message) {
|
|
1608
|
+
return undefined;
|
|
1609
|
+
}
|
|
1610
|
+
return createElement("span", {
|
|
1611
|
+
id: tooltipId,
|
|
1612
|
+
className: "youp-grid__cell-tooltip",
|
|
1613
|
+
role: "tooltip",
|
|
1614
|
+
}, meta.message);
|
|
1615
|
+
}
|
|
1134
1616
|
function renderColumnToolbar(context) {
|
|
1135
1617
|
if (!context.showColumnChooser && !context.showCsvExport && !context.showDensityControl) {
|
|
1136
1618
|
return undefined;
|
|
@@ -1300,9 +1782,16 @@ function getHeaderGroupStyle(layout) {
|
|
|
1300
1782
|
}
|
|
1301
1783
|
return style;
|
|
1302
1784
|
}
|
|
1303
|
-
function
|
|
1785
|
+
function getRowNumberCellStyle() {
|
|
1304
1786
|
return {
|
|
1305
1787
|
left: 0,
|
|
1788
|
+
width: ROW_NUMBER_COLUMN_WIDTH,
|
|
1789
|
+
flex: `0 0 ${ROW_NUMBER_COLUMN_WIDTH}px`,
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
function getSelectionCellStyle(leftOffset = 0) {
|
|
1793
|
+
return {
|
|
1794
|
+
left: leftOffset,
|
|
1306
1795
|
width: SELECTION_COLUMN_WIDTH,
|
|
1307
1796
|
flex: `0 0 ${SELECTION_COLUMN_WIDTH}px`,
|
|
1308
1797
|
};
|
|
@@ -1740,22 +2229,38 @@ function commitEditingCell(context) {
|
|
|
1740
2229
|
};
|
|
1741
2230
|
}
|
|
1742
2231
|
function handleGridCopy(context) {
|
|
2232
|
+
context.event.preventDefault();
|
|
2233
|
+
context.event.clipboardData.setData("text/plain", getGridClipboardText(context));
|
|
2234
|
+
}
|
|
2235
|
+
function getGridClipboardText(context) {
|
|
1743
2236
|
const range = context.selectionRange ?? {
|
|
1744
2237
|
anchor: context.focusedCell,
|
|
1745
2238
|
focus: context.focusedCell,
|
|
1746
2239
|
};
|
|
1747
|
-
|
|
2240
|
+
return serializeGridRange({
|
|
1748
2241
|
rows: context.rows,
|
|
1749
2242
|
columns: context.columns,
|
|
1750
2243
|
range,
|
|
1751
2244
|
});
|
|
1752
|
-
context.event.preventDefault();
|
|
1753
|
-
context.event.clipboardData.setData("text/plain", text);
|
|
1754
2245
|
}
|
|
1755
2246
|
function handleGridPaste(context) {
|
|
1756
|
-
const
|
|
2247
|
+
const applied = applyGridClipboardText({
|
|
2248
|
+
text: context.event.clipboardData.getData("text/plain"),
|
|
2249
|
+
focusedCell: context.focusedCell,
|
|
2250
|
+
selectionRange: context.selectionRange,
|
|
2251
|
+
rows: context.rows,
|
|
2252
|
+
columns: context.columns,
|
|
2253
|
+
applyCellValueChanges: context.applyCellValueChanges,
|
|
2254
|
+
canEditCell: context.canEditCell,
|
|
2255
|
+
});
|
|
2256
|
+
if (applied) {
|
|
2257
|
+
context.event.preventDefault();
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
function applyGridClipboardText(context) {
|
|
2261
|
+
const values = parseClipboardText(context.text);
|
|
1757
2262
|
if (values.length === 0) {
|
|
1758
|
-
return;
|
|
2263
|
+
return false;
|
|
1759
2264
|
}
|
|
1760
2265
|
const normalizedRange = context.selectionRange ? normalizeCellRange(context.selectionRange) : undefined;
|
|
1761
2266
|
const startCell = normalizedRange
|
|
@@ -1767,7 +2272,6 @@ function handleGridPaste(context) {
|
|
|
1767
2272
|
const fillRange = normalizedRange && values.length === 1 && values[0]?.length === 1
|
|
1768
2273
|
? normalizedRange
|
|
1769
2274
|
: undefined;
|
|
1770
|
-
context.event.preventDefault();
|
|
1771
2275
|
const changes = [];
|
|
1772
2276
|
for (const cell of getClipboardPasteCells({
|
|
1773
2277
|
values,
|
|
@@ -1797,6 +2301,19 @@ function handleGridPaste(context) {
|
|
|
1797
2301
|
});
|
|
1798
2302
|
}
|
|
1799
2303
|
context.applyCellValueChanges(changes, "paste");
|
|
2304
|
+
return true;
|
|
2305
|
+
}
|
|
2306
|
+
function writeClipboardText(text) {
|
|
2307
|
+
if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
|
|
2308
|
+
return Promise.resolve();
|
|
2309
|
+
}
|
|
2310
|
+
return navigator.clipboard.writeText(text);
|
|
2311
|
+
}
|
|
2312
|
+
function readClipboardText() {
|
|
2313
|
+
if (typeof navigator === "undefined" || !navigator.clipboard?.readText) {
|
|
2314
|
+
return Promise.resolve("");
|
|
2315
|
+
}
|
|
2316
|
+
return navigator.clipboard.readText();
|
|
1800
2317
|
}
|
|
1801
2318
|
function deleteGridCellValues(context) {
|
|
1802
2319
|
const range = normalizeCellRange(context.selectionRange ?? {
|
|
@@ -2020,8 +2537,8 @@ function normalizeEditorOptions(options) {
|
|
|
2020
2537
|
function getEditorOptionValue(option) {
|
|
2021
2538
|
return typeof option === "object" ? option.value : option;
|
|
2022
2539
|
}
|
|
2023
|
-
function getCellTitle(meta, disabledReason, editable) {
|
|
2024
|
-
if (typeof meta?.message === "string") {
|
|
2540
|
+
function getCellTitle(meta, disabledReason, editable, tooltipMode) {
|
|
2541
|
+
if (tooltipMode === "native" && typeof meta?.message === "string") {
|
|
2025
2542
|
return meta.message;
|
|
2026
2543
|
}
|
|
2027
2544
|
if (!editable && typeof disabledReason === "string") {
|
|
@@ -2029,6 +2546,15 @@ function getCellTitle(meta, disabledReason, editable) {
|
|
|
2029
2546
|
}
|
|
2030
2547
|
return undefined;
|
|
2031
2548
|
}
|
|
2549
|
+
function hasTooltipMessage(meta) {
|
|
2550
|
+
return Boolean(meta?.message);
|
|
2551
|
+
}
|
|
2552
|
+
function getCellKey(rowId, columnId) {
|
|
2553
|
+
return `${String(rowId)}:${columnId}`;
|
|
2554
|
+
}
|
|
2555
|
+
function getCellTooltipId(cellKey) {
|
|
2556
|
+
return `youp-grid-cell-tooltip-${cellKey.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
2557
|
+
}
|
|
2032
2558
|
function isTextEditingKey(event) {
|
|
2033
2559
|
if (event.metaKey || event.ctrlKey || event.altKey) {
|
|
2034
2560
|
return false;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { YoupGrid } from "./YoupGrid.ts";
|
|
2
2
|
export { useYoupGrid } from "./useYoupGrid.ts";
|
|
3
|
-
export type { YoupGridCanEditCellContext, YoupGridCellEditCommit, YoupGridCellEditCommitReason, YoupGridCellContext, YoupGridCellMeta, YoupGridCellMetaStatus, YoupGridCellsValueChange, YoupGridCellsValueChangeSource, YoupGridController, YoupGridDensity, YoupGridHeaderContext, YoupGridOptions, YoupGridProps, YoupGridRowEvent, YoupGridRowsEndReachedEvent, YoupGridStateChange, } from "./types.ts";
|
|
3
|
+
export type { YoupGridCanEditCellContext, YoupGridCellEditCommit, YoupGridCellEditCommitReason, YoupGridCellContext, YoupGridCellMeta, YoupGridCellMetaStatus, YoupGridCellTooltipMode, YoupGridCellTooltipOptions, YoupGridCellsValueChange, YoupGridCellsValueChangeSource, YoupGridController, YoupGridCreateRowContext, YoupGridDensity, YoupGridHeaderContext, YoupGridOptions, YoupGridProps, YoupGridRowChange, YoupGridRowDeleteChange, YoupGridRowEvent, YoupGridRowInsertChange, YoupGridRowInsertPosition, YoupGridRowsChange, YoupGridRowsEndReachedEvent, YoupGridRowsChangeSource, YoupGridStateChange, } from "./types.ts";
|
package/dist/styles.css
CHANGED
|
@@ -164,8 +164,8 @@
|
|
|
164
164
|
--youp-grid-header-scroll-left: 0px;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
.youp-grid__header .youp-grid__cell--header:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right),
|
|
168
|
-
.youp-grid__header .youp-grid__cell--header-group:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right) {
|
|
167
|
+
.youp-grid__header .youp-grid__cell--header:not(.youp-grid__row-number-cell):not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right),
|
|
168
|
+
.youp-grid__header .youp-grid__cell--header-group:not(.youp-grid__row-number-cell):not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right) {
|
|
169
169
|
transform: translateX(calc(-1 * var(--youp-grid-header-scroll-left)));
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -215,6 +215,63 @@
|
|
|
215
215
|
background: var(--youp-grid-row-selected);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
.youp-grid__row-number-cell {
|
|
219
|
+
display: grid;
|
|
220
|
+
place-items: center;
|
|
221
|
+
min-width: 44px;
|
|
222
|
+
padding: 0;
|
|
223
|
+
color: var(--youp-grid-muted);
|
|
224
|
+
font-weight: 800;
|
|
225
|
+
text-align: center;
|
|
226
|
+
user-select: none;
|
|
227
|
+
background: #fff;
|
|
228
|
+
position: sticky;
|
|
229
|
+
left: 0;
|
|
230
|
+
z-index: 3;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.youp-grid__cell.youp-grid__row-number-cell {
|
|
234
|
+
min-width: 44px;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.youp-grid__row-number-cell--header,
|
|
238
|
+
.youp-grid__row-number-cell--header-group {
|
|
239
|
+
z-index: 4;
|
|
240
|
+
background: var(--youp-grid-header);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.youp-grid__row-number-cell--header {
|
|
244
|
+
align-content: center;
|
|
245
|
+
overflow: hidden;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.youp-grid__row-number-cell--header-group {
|
|
249
|
+
display: grid;
|
|
250
|
+
padding: 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.youp-grid__row--selected .youp-grid__row-number-cell {
|
|
254
|
+
background: var(--youp-grid-row-selected);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.youp-grid__row:hover .youp-grid__row-number-cell {
|
|
258
|
+
background: var(--youp-grid-row-hover);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.youp-grid__row--selected:hover .youp-grid__row-number-cell {
|
|
262
|
+
background: var(--youp-grid-row-selected);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.youp-grid__row--header:hover .youp-grid__row-number-cell,
|
|
266
|
+
.youp-grid__row--header-group:hover .youp-grid__row-number-cell {
|
|
267
|
+
background: var(--youp-grid-header);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.youp-grid__row--aggregation:hover .youp-grid__row-number-cell,
|
|
271
|
+
.youp-grid__row--group:hover .youp-grid__row-number-cell {
|
|
272
|
+
background: #f8fafc;
|
|
273
|
+
}
|
|
274
|
+
|
|
218
275
|
.youp-grid__selection-cell {
|
|
219
276
|
display: grid;
|
|
220
277
|
place-items: center;
|
|
@@ -355,6 +412,89 @@
|
|
|
355
412
|
color: #94a3b8;
|
|
356
413
|
}
|
|
357
414
|
|
|
415
|
+
.youp-grid__cell-text {
|
|
416
|
+
display: block;
|
|
417
|
+
min-width: 0;
|
|
418
|
+
overflow: hidden;
|
|
419
|
+
text-overflow: ellipsis;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.youp-grid__cell--tree {
|
|
423
|
+
display: flex;
|
|
424
|
+
align-items: center;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.youp-grid__cell-tree-content {
|
|
428
|
+
display: inline-flex;
|
|
429
|
+
min-width: 0;
|
|
430
|
+
align-items: center;
|
|
431
|
+
gap: 4px;
|
|
432
|
+
overflow: hidden;
|
|
433
|
+
text-overflow: ellipsis;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.youp-grid__cell-tree-value {
|
|
437
|
+
min-width: 0;
|
|
438
|
+
overflow: hidden;
|
|
439
|
+
text-overflow: ellipsis;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.youp-grid__tree-toggle,
|
|
443
|
+
.youp-grid__tree-toggle-spacer {
|
|
444
|
+
display: inline-flex;
|
|
445
|
+
flex: 0 0 auto;
|
|
446
|
+
align-items: center;
|
|
447
|
+
justify-content: center;
|
|
448
|
+
width: 18px;
|
|
449
|
+
height: 18px;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.youp-grid__tree-toggle {
|
|
453
|
+
padding: 0;
|
|
454
|
+
border: 0;
|
|
455
|
+
color: var(--youp-grid-muted);
|
|
456
|
+
font: inherit;
|
|
457
|
+
cursor: pointer;
|
|
458
|
+
background: transparent;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.youp-grid__tree-toggle:focus-visible {
|
|
462
|
+
outline: 2px solid #2563eb;
|
|
463
|
+
outline-offset: 1px;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.youp-grid__tree-caret {
|
|
467
|
+
width: 12px;
|
|
468
|
+
line-height: 1;
|
|
469
|
+
text-align: center;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.youp-grid__cell--tooltip-open {
|
|
473
|
+
z-index: 8;
|
|
474
|
+
overflow: visible;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.youp-grid__cell-tooltip {
|
|
478
|
+
position: absolute;
|
|
479
|
+
top: calc(100% + 6px);
|
|
480
|
+
left: var(--youp-grid-cell-inline-padding);
|
|
481
|
+
z-index: 20;
|
|
482
|
+
width: max-content;
|
|
483
|
+
min-width: 120px;
|
|
484
|
+
max-width: 260px;
|
|
485
|
+
padding: 6px 8px;
|
|
486
|
+
border: 1px solid #0f172a;
|
|
487
|
+
border-radius: 6px;
|
|
488
|
+
color: #fff;
|
|
489
|
+
font-size: 12px;
|
|
490
|
+
line-height: 1.4;
|
|
491
|
+
text-align: left;
|
|
492
|
+
white-space: normal;
|
|
493
|
+
pointer-events: none;
|
|
494
|
+
background: #0f172a;
|
|
495
|
+
box-shadow: 0 8px 24px rgb(15 23 42 / 18%);
|
|
496
|
+
}
|
|
497
|
+
|
|
358
498
|
.youp-grid__cell-checkbox {
|
|
359
499
|
width: 16px;
|
|
360
500
|
height: 16px;
|
|
@@ -573,6 +713,7 @@
|
|
|
573
713
|
|
|
574
714
|
.youp-grid__cell--aggregation.youp-grid__cell--pinned-left,
|
|
575
715
|
.youp-grid__cell--aggregation.youp-grid__cell--pinned-right,
|
|
716
|
+
.youp-grid__row-number-cell--aggregation,
|
|
576
717
|
.youp-grid__selection-cell--aggregation {
|
|
577
718
|
background: #f8fafc;
|
|
578
719
|
}
|
|
@@ -585,6 +726,7 @@
|
|
|
585
726
|
background: #f8fafc;
|
|
586
727
|
}
|
|
587
728
|
|
|
729
|
+
.youp-grid__row-number-cell--group,
|
|
588
730
|
.youp-grid__selection-cell--group {
|
|
589
731
|
background: #f8fafc;
|
|
590
732
|
}
|
|
@@ -686,6 +828,18 @@
|
|
|
686
828
|
box-shadow: 0 16px 34px rgba(15, 23, 42, 0.16);
|
|
687
829
|
}
|
|
688
830
|
|
|
831
|
+
.youp-grid__cell-context-menu {
|
|
832
|
+
position: fixed;
|
|
833
|
+
z-index: 40;
|
|
834
|
+
display: grid;
|
|
835
|
+
min-width: 180px;
|
|
836
|
+
padding: 6px;
|
|
837
|
+
border: 1px solid var(--youp-grid-border);
|
|
838
|
+
border-radius: 6px;
|
|
839
|
+
background: #fff;
|
|
840
|
+
box-shadow: 0 16px 34px rgba(15, 23, 42, 0.16);
|
|
841
|
+
}
|
|
842
|
+
|
|
689
843
|
.youp-grid__column-menu-item {
|
|
690
844
|
min-height: 28px;
|
|
691
845
|
padding: 5px 8px;
|
package/dist/types.d.ts
CHANGED
|
@@ -24,11 +24,51 @@ export type YoupGridCellsValueChange<TRow> = {
|
|
|
24
24
|
changes: YoupGridCellValueChange<TRow>[];
|
|
25
25
|
source: YoupGridCellsValueChangeSource;
|
|
26
26
|
};
|
|
27
|
+
export type YoupGridRowsChangeSource = "context-menu";
|
|
28
|
+
export type YoupGridRowInsertPosition = "above" | "below";
|
|
29
|
+
export type YoupGridCreateRowContext<TRow> = {
|
|
30
|
+
rows: readonly TRow[];
|
|
31
|
+
rowIndex: number;
|
|
32
|
+
visibleRowIndex: number;
|
|
33
|
+
position: YoupGridRowInsertPosition;
|
|
34
|
+
anchorRow: TRow;
|
|
35
|
+
anchorRowId: GridRowId;
|
|
36
|
+
anchorRowIndex: number;
|
|
37
|
+
};
|
|
38
|
+
export type YoupGridRowInsertChange<TRow> = {
|
|
39
|
+
type: "insert";
|
|
40
|
+
row: TRow;
|
|
41
|
+
rowIndex: number;
|
|
42
|
+
visibleRowIndex: number;
|
|
43
|
+
position: YoupGridRowInsertPosition;
|
|
44
|
+
anchorRow: TRow;
|
|
45
|
+
anchorRowId: GridRowId;
|
|
46
|
+
anchorRowIndex: number;
|
|
47
|
+
};
|
|
48
|
+
export type YoupGridRowDeleteChange<TRow> = {
|
|
49
|
+
type: "delete";
|
|
50
|
+
row: TRow;
|
|
51
|
+
rowId: GridRowId;
|
|
52
|
+
rowIndex: number;
|
|
53
|
+
visibleRowIndex: number;
|
|
54
|
+
};
|
|
55
|
+
export type YoupGridRowChange<TRow> = YoupGridRowInsertChange<TRow> | YoupGridRowDeleteChange<TRow>;
|
|
56
|
+
export type YoupGridRowsChange<TRow> = {
|
|
57
|
+
rows: TRow[];
|
|
58
|
+
changes: YoupGridRowChange<TRow>[];
|
|
59
|
+
source: YoupGridRowsChangeSource;
|
|
60
|
+
};
|
|
27
61
|
export type YoupGridCellMetaStatus = "loading" | "error" | "warning" | "success";
|
|
28
62
|
export type YoupGridCellMeta = {
|
|
29
63
|
status: YoupGridCellMetaStatus;
|
|
30
64
|
message?: ReactNode;
|
|
31
65
|
};
|
|
66
|
+
export type YoupGridCellTooltipMode = "native" | "rich" | "none";
|
|
67
|
+
export type YoupGridCellTooltipOptions = {
|
|
68
|
+
mode?: YoupGridCellTooltipMode;
|
|
69
|
+
autoOpenCellKey?: string | null;
|
|
70
|
+
autoOpenDurationMs?: number;
|
|
71
|
+
};
|
|
32
72
|
export type YoupGridCanEditCellContext<TRow> = {
|
|
33
73
|
row: TRow;
|
|
34
74
|
rowNode: RowNode<TRow>;
|
|
@@ -61,6 +101,8 @@ export type YoupGridOptions<TRow> = {
|
|
|
61
101
|
defaultState?: GridState;
|
|
62
102
|
onStateChange?: (change: YoupGridStateChange<TRow>) => void;
|
|
63
103
|
getRowId?: (row: TRow, index: number) => GridRowId;
|
|
104
|
+
treeData?: boolean;
|
|
105
|
+
getParentRowId?: (row: TRow, index: number) => GridRowId | null | undefined;
|
|
64
106
|
rowModelType?: GridRowModelType;
|
|
65
107
|
serverRowCount?: number;
|
|
66
108
|
serverFilteredRowCount?: number;
|
|
@@ -101,6 +143,8 @@ export type YoupGridController<TRow> = {
|
|
|
101
143
|
setRowSelected: (rowId: GridRowId, selected: boolean) => void;
|
|
102
144
|
setSelectedRows: (rowIds: readonly GridRowId[]) => void;
|
|
103
145
|
toggleRowSelected: (rowId: GridRowId) => void;
|
|
146
|
+
setTreeExpandedRows: (rowIds: readonly GridRowId[]) => void;
|
|
147
|
+
toggleTreeRowExpanded: (rowId: GridRowId) => void;
|
|
104
148
|
};
|
|
105
149
|
export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
106
150
|
className?: string;
|
|
@@ -117,8 +161,10 @@ export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
|
117
161
|
showFilters?: boolean;
|
|
118
162
|
showAggregationFooter?: boolean;
|
|
119
163
|
showPagination?: boolean;
|
|
164
|
+
showRowNumberColumn?: boolean;
|
|
120
165
|
showRowSelectionColumn?: boolean;
|
|
121
166
|
pinRowSelectionColumn?: boolean;
|
|
167
|
+
showCellContextMenu?: boolean;
|
|
122
168
|
csvFileName?: string;
|
|
123
169
|
density?: YoupGridDensity;
|
|
124
170
|
defaultDensity?: YoupGridDensity;
|
|
@@ -129,11 +175,14 @@ export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
|
129
175
|
errorContent?: ReactNode;
|
|
130
176
|
cellMeta?: Record<string, YoupGridCellMeta | undefined>;
|
|
131
177
|
getCellMeta?: (context: YoupGridCanEditCellContext<TRow>) => YoupGridCellMeta | undefined;
|
|
178
|
+
cellTooltip?: YoupGridCellTooltipOptions;
|
|
132
179
|
renderCell?: (context: YoupGridCellContext<TRow>) => ReactNode;
|
|
133
180
|
renderHeader?: (context: YoupGridHeaderContext<TRow>) => ReactNode;
|
|
134
181
|
onCellValueChange?: (change: YoupGridCellValueChange<TRow>) => void;
|
|
135
182
|
onCellEditCommit?: (commit: YoupGridCellEditCommit<TRow>) => void;
|
|
136
183
|
onCellsValueChange?: (change: YoupGridCellsValueChange<TRow>) => void;
|
|
184
|
+
createRow?: (context: YoupGridCreateRowContext<TRow>) => TRow;
|
|
185
|
+
onRowsChange?: (change: YoupGridRowsChange<TRow>) => void;
|
|
137
186
|
onRowClick?: (event: YoupGridRowEvent<TRow>) => void;
|
|
138
187
|
onRowDoubleClick?: (event: YoupGridRowEvent<TRow>) => void;
|
|
139
188
|
onRowsEndReached?: (event: YoupGridRowsEndReachedEvent<TRow>) => void;
|
|
@@ -147,6 +196,9 @@ export type YoupGridCellContext<TRow> = {
|
|
|
147
196
|
focused: boolean;
|
|
148
197
|
editable: boolean;
|
|
149
198
|
meta?: YoupGridCellMeta;
|
|
199
|
+
treeDepth?: number;
|
|
200
|
+
hasChildren?: boolean;
|
|
201
|
+
expanded?: boolean;
|
|
150
202
|
};
|
|
151
203
|
export type YoupGridHeaderContext<TRow> = {
|
|
152
204
|
column: ResolvedColumnDef<TRow>;
|
package/dist/useYoupGrid.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { acknowledgeRemoteCache as acknowledgeCoreRemoteCache, buildRowModel, cancelRemoteRequest as cancelCoreRemoteRequest, clearFilter as clearCoreFilter, clearSort as clearCoreSort, createGridState, failRemoteRequest as failCoreRemoteRequest, finishRemoteRequest as finishCoreRemoteRequest, invalidateRemoteCache as invalidateCoreRemoteCache, setColumnHidden as setCoreColumnHidden, setColumnPinned as setCoreColumnPinned, setColumnWidth as setCoreColumnWidth, setCursorPage as setCoreCursorPage, setCursorPageSize as setCoreCursorPageSize, setCursorPagination as setCoreCursorPagination, setAggregation as setCoreAggregation, setFilter as setCoreFilter, setPagination, setRemoteCache as setCoreRemoteCache, setRowGrouping as setCoreRowGrouping, setRowSelected as setCoreRowSelected, setSelectedRows as setCoreSelectedRows, setSort as setCoreSort, startRemoteRequest as startCoreRemoteRequest, toggleRowGroupExpanded as toggleCoreRowGroupExpanded, toggleRowSelected as toggleCoreRowSelected, toggleSort as toggleCoreSort, } from "@youp-grid/core";
|
|
1
|
+
import { acknowledgeRemoteCache as acknowledgeCoreRemoteCache, buildRowModel, cancelRemoteRequest as cancelCoreRemoteRequest, clearFilter as clearCoreFilter, clearSort as clearCoreSort, createGridState, failRemoteRequest as failCoreRemoteRequest, finishRemoteRequest as finishCoreRemoteRequest, invalidateRemoteCache as invalidateCoreRemoteCache, setColumnHidden as setCoreColumnHidden, setColumnPinned as setCoreColumnPinned, setColumnWidth as setCoreColumnWidth, setCursorPage as setCoreCursorPage, setCursorPageSize as setCoreCursorPageSize, setCursorPagination as setCoreCursorPagination, setAggregation as setCoreAggregation, setFilter as setCoreFilter, setPagination, setRemoteCache as setCoreRemoteCache, setRowGrouping as setCoreRowGrouping, setRowSelected as setCoreRowSelected, setSelectedRows as setCoreSelectedRows, setSort as setCoreSort, setTreeExpandedRows as setCoreTreeExpandedRows, startRemoteRequest as startCoreRemoteRequest, toggleRowGroupExpanded as toggleCoreRowGroupExpanded, toggleRowSelected as toggleCoreRowSelected, toggleSort as toggleCoreSort, toggleTreeRowExpanded as toggleCoreTreeRowExpanded, } from "@youp-grid/core";
|
|
2
2
|
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
export function useYoupGrid(options) {
|
|
4
4
|
const isControlled = options.state !== undefined;
|
|
@@ -12,6 +12,8 @@ export function useYoupGrid(options) {
|
|
|
12
12
|
columns: options.columns,
|
|
13
13
|
state,
|
|
14
14
|
getRowId: options.getRowId,
|
|
15
|
+
treeData: options.treeData,
|
|
16
|
+
getParentRowId: options.getParentRowId,
|
|
15
17
|
rowModelType: options.rowModelType,
|
|
16
18
|
serverRowCount: options.serverRowCount,
|
|
17
19
|
serverFilteredRowCount: options.serverFilteredRowCount,
|
|
@@ -20,6 +22,8 @@ export function useYoupGrid(options) {
|
|
|
20
22
|
options.rows,
|
|
21
23
|
options.columns,
|
|
22
24
|
options.getRowId,
|
|
25
|
+
options.treeData,
|
|
26
|
+
options.getParentRowId,
|
|
23
27
|
options.rowModelType,
|
|
24
28
|
options.serverRowCount,
|
|
25
29
|
options.serverFilteredRowCount,
|
|
@@ -31,6 +35,8 @@ export function useYoupGrid(options) {
|
|
|
31
35
|
columns: options.columns,
|
|
32
36
|
state: nextState,
|
|
33
37
|
getRowId: options.getRowId,
|
|
38
|
+
treeData: options.treeData,
|
|
39
|
+
getParentRowId: options.getParentRowId,
|
|
34
40
|
rowModelType: options.rowModelType,
|
|
35
41
|
serverRowCount: options.serverRowCount,
|
|
36
42
|
serverFilteredRowCount: options.serverFilteredRowCount,
|
|
@@ -93,5 +99,7 @@ export function useYoupGrid(options) {
|
|
|
93
99
|
setRowSelected: (rowId, selected) => commitState(setCoreRowSelected(state, rowId, selected)),
|
|
94
100
|
setSelectedRows: (rowIds) => commitState(setCoreSelectedRows(state, rowIds)),
|
|
95
101
|
toggleRowSelected: (rowId) => commitState(toggleCoreRowSelected(state, rowId)),
|
|
102
|
+
setTreeExpandedRows: (rowIds) => commitState(setCoreTreeExpandedRows(state, rowIds)),
|
|
103
|
+
toggleTreeRowExpanded: (rowId) => commitState(toggleCoreTreeRowExpanded(state, rowId)),
|
|
96
104
|
};
|
|
97
105
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youp-grid/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "React adapter for Youp Grid.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "SeungyoupBaek",
|
|
5
7
|
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"data-grid",
|
|
10
|
+
"grid",
|
|
11
|
+
"react",
|
|
12
|
+
"typescript",
|
|
13
|
+
"table"
|
|
14
|
+
],
|
|
6
15
|
"main": "./dist/index.js",
|
|
7
16
|
"types": "./dist/index.d.ts",
|
|
8
17
|
"exports": {
|
|
@@ -14,13 +23,18 @@
|
|
|
14
23
|
},
|
|
15
24
|
"files": [
|
|
16
25
|
"dist",
|
|
17
|
-
"README.md"
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
18
28
|
],
|
|
19
29
|
"repository": {
|
|
20
30
|
"type": "git",
|
|
21
31
|
"url": "git+ssh://git@github.com/SeungyoupBaek/youp-grid.git",
|
|
22
32
|
"directory": "packages/react"
|
|
23
33
|
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/SeungyoupBaek/youp-grid/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/SeungyoupBaek/youp-grid/tree/main/packages/react#readme",
|
|
24
38
|
"publishConfig": {
|
|
25
39
|
"access": "public"
|
|
26
40
|
},
|
|
@@ -28,7 +42,7 @@
|
|
|
28
42
|
"build": "tsc -p tsconfig.build.json && cp src/styles.css dist/styles.css"
|
|
29
43
|
},
|
|
30
44
|
"dependencies": {
|
|
31
|
-
"@youp-grid/core": "0.2.
|
|
45
|
+
"@youp-grid/core": "0.2.4"
|
|
32
46
|
},
|
|
33
47
|
"peerDependencies": {
|
|
34
48
|
"react": ">=18.2.0"
|