@gridkitjs/react 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +63 -4
- package/dist/index.js +670 -86
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/DataGrid/DataGrid.tsx
|
|
2
2
|
import {
|
|
3
3
|
useImperativeHandle,
|
|
4
|
-
useMemo as
|
|
4
|
+
useMemo as useMemo3,
|
|
5
5
|
useRef as useRef4,
|
|
6
6
|
useState as useState5
|
|
7
7
|
} from "react";
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
applyColumnOrder,
|
|
10
10
|
defineColumnsFromRows,
|
|
11
11
|
fitColumnsToWidth,
|
|
12
|
+
groupRows,
|
|
12
13
|
moveColumnBefore,
|
|
13
14
|
resolveColumnWidths,
|
|
14
15
|
resolveRowId,
|
|
@@ -47,7 +48,11 @@ function tabIndexFor(columnIndex, focusedColumnIndex) {
|
|
|
47
48
|
}
|
|
48
49
|
function cellAt(table, focus) {
|
|
49
50
|
const row = focus.rowIndex === HEADER_ROW ? table.tHead?.rows[0] ?? null : table.tBodies[0]?.rows[focus.rowIndex] ?? null;
|
|
50
|
-
|
|
51
|
+
if (row === null) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const columnIndex = Math.min(focus.columnIndex, row.cells.length - 1);
|
|
55
|
+
return row.cells[columnIndex] ?? null;
|
|
51
56
|
}
|
|
52
57
|
function useGridNavigation({
|
|
53
58
|
tableRef,
|
|
@@ -366,16 +371,26 @@ function ChevronsUpDownIcon() {
|
|
|
366
371
|
function ChevronUpIcon() {
|
|
367
372
|
return /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx("path", { d: "m18 15-6-6-6 6" }) });
|
|
368
373
|
}
|
|
374
|
+
function GroupIcon() {
|
|
375
|
+
return /* @__PURE__ */ jsxs(Icon, { children: [
|
|
376
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
|
|
377
|
+
/* @__PURE__ */ jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
|
|
378
|
+
/* @__PURE__ */ jsx("rect", { x: "8.5", y: "14", width: "7", height: "7", rx: "1" })
|
|
379
|
+
] });
|
|
380
|
+
}
|
|
369
381
|
function GridHeader({
|
|
370
382
|
columns,
|
|
371
383
|
resize,
|
|
372
384
|
drag,
|
|
373
385
|
sort,
|
|
374
386
|
sortableColumns,
|
|
387
|
+
grouping,
|
|
388
|
+
groupableColumns,
|
|
389
|
+
groupToggleIconColumns,
|
|
375
390
|
nav,
|
|
376
391
|
selection
|
|
377
392
|
}) {
|
|
378
|
-
const
|
|
393
|
+
const beforeId = drag.dropTarget?.kind === "column-order" ? drag.dropTarget.beforeId : void 0;
|
|
379
394
|
const draggedEntry = columns.find((entry) => entry.id === drag.draggedColumnId) ?? null;
|
|
380
395
|
return /* @__PURE__ */ jsxs("thead", { children: [
|
|
381
396
|
/* @__PURE__ */ jsx("tr", { className: "grid-header", role: "row", "aria-rowindex": 1, children: columns.map((entry, index) => {
|
|
@@ -388,10 +403,16 @@ function GridHeader({
|
|
|
388
403
|
const sortable = column.sortable ?? sortableColumns;
|
|
389
404
|
const sortDirection = sort.directionFor(entry.id);
|
|
390
405
|
const sortPriority = sort.priorityFor(entry.id);
|
|
406
|
+
const groupable = column.groupable ?? groupableColumns;
|
|
407
|
+
const showGroupToggleIcon = column.groupToggleIcon ?? groupToggleIconColumns;
|
|
408
|
+
const isGrouped = grouping.groupBy.some(
|
|
409
|
+
(level) => level.columnId === entry.id
|
|
410
|
+
);
|
|
391
411
|
const shortcuts = buildKeyShortcuts({
|
|
392
412
|
reorderable: entry.reorderable,
|
|
393
413
|
resizable: entry.resizable,
|
|
394
|
-
sortable
|
|
414
|
+
sortable,
|
|
415
|
+
groupable
|
|
395
416
|
});
|
|
396
417
|
return /* @__PURE__ */ jsxs(
|
|
397
418
|
"th",
|
|
@@ -413,7 +434,7 @@ function GridHeader({
|
|
|
413
434
|
if (drag.justDragged()) {
|
|
414
435
|
return;
|
|
415
436
|
}
|
|
416
|
-
if (event.target instanceof Element && (event.target.closest(".header-resize-handle") !== null || event.target.closest(".header-sort-toggle") !== null)) {
|
|
437
|
+
if (event.target instanceof Element && (event.target.closest(".header-resize-handle") !== null || event.target.closest(".header-sort-toggle") !== null || event.target.closest(".header-group-toggle") !== null)) {
|
|
417
438
|
return;
|
|
418
439
|
}
|
|
419
440
|
selection.selectColumn(entry.id, intentOf(event));
|
|
@@ -441,6 +462,11 @@ function GridHeader({
|
|
|
441
462
|
sort.toggle(entry, { shiftKey: event.shiftKey });
|
|
442
463
|
return;
|
|
443
464
|
}
|
|
465
|
+
if (event.key === "ArrowDown" && event.altKey && groupable) {
|
|
466
|
+
event.preventDefault();
|
|
467
|
+
grouping.toggleGroupBy(entry.id);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
444
470
|
if (event.key === " " || event.key === "Enter") {
|
|
445
471
|
event.preventDefault();
|
|
446
472
|
selection.selectColumn(
|
|
@@ -453,7 +479,11 @@ function GridHeader({
|
|
|
453
479
|
},
|
|
454
480
|
className: classNames(
|
|
455
481
|
"header-cell",
|
|
456
|
-
|
|
482
|
+
// The grab affordance a header showing either drag
|
|
483
|
+
// destination shares — a column dragged only for grouping
|
|
484
|
+
// (`groupByDraggable` without `reorderable`) grabs the same
|
|
485
|
+
// way one dragged only for reordering does.
|
|
486
|
+
entry.reorderable || entry.groupByDraggable ? "is-reorderable" : "",
|
|
457
487
|
selected ? "is-selected" : "",
|
|
458
488
|
resizing ? "is-resizing" : "",
|
|
459
489
|
dragging ? "is-dragging" : "",
|
|
@@ -468,12 +498,40 @@ function GridHeader({
|
|
|
468
498
|
"aria-sort",
|
|
469
499
|
sortDirection === "asc" ? "ascending" : "descending"
|
|
470
500
|
),
|
|
471
|
-
...entry.reorderable && {
|
|
501
|
+
...(entry.reorderable || entry.groupByDraggable) && {
|
|
472
502
|
onPointerDown: (event) => {
|
|
473
503
|
drag.startDrag(entry, event);
|
|
474
504
|
}
|
|
475
505
|
},
|
|
476
506
|
children: [
|
|
507
|
+
groupable && showGroupToggleIcon && /*
|
|
508
|
+
* Inline, before the label, rather than absolutely
|
|
509
|
+
* positioned like the sort toggle and resize handle: those
|
|
510
|
+
* two already share the header's right edge, and a third
|
|
511
|
+
* overlay there would need its own carve-out. Sitting in
|
|
512
|
+
* normal flow costs nothing but a few pixels of label width.
|
|
513
|
+
* A pointer affordance only, same as the other two — the
|
|
514
|
+
* keyboard equivalent is Alt+ArrowDown on the header itself.
|
|
515
|
+
*/
|
|
516
|
+
/* @__PURE__ */ jsx(
|
|
517
|
+
"span",
|
|
518
|
+
{
|
|
519
|
+
className: classNames(
|
|
520
|
+
"header-group-toggle",
|
|
521
|
+
isGrouped ? "is-grouped" : ""
|
|
522
|
+
),
|
|
523
|
+
"aria-hidden": "true",
|
|
524
|
+
tabIndex: -1,
|
|
525
|
+
onPointerDown: (event) => {
|
|
526
|
+
event.stopPropagation();
|
|
527
|
+
},
|
|
528
|
+
onClick: (event) => {
|
|
529
|
+
event.stopPropagation();
|
|
530
|
+
grouping.toggleGroupBy(entry.id);
|
|
531
|
+
},
|
|
532
|
+
children: /* @__PURE__ */ jsx(GroupIcon, {})
|
|
533
|
+
}
|
|
534
|
+
),
|
|
477
535
|
entry.label,
|
|
478
536
|
sortable && /*
|
|
479
537
|
* A pointer affordance only, and hidden from assistive
|
|
@@ -546,12 +604,108 @@ function GridHeader({
|
|
|
546
604
|
}
|
|
547
605
|
|
|
548
606
|
// src/DataGrid/components/GridBody.tsx
|
|
549
|
-
import {
|
|
607
|
+
import { useMemo as useMemo2 } from "react";
|
|
608
|
+
import { groupRowId, intentOf as intentOf2 } from "@gridkitjs/core";
|
|
609
|
+
|
|
610
|
+
// src/DataGrid/components/GridGroupRow.tsx
|
|
611
|
+
import { memo } from "react";
|
|
612
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
613
|
+
function formatGroupValue(value) {
|
|
614
|
+
if (value === null || value === void 0) {
|
|
615
|
+
return "(blank)";
|
|
616
|
+
}
|
|
617
|
+
if (value instanceof Date) {
|
|
618
|
+
return value.toLocaleString();
|
|
619
|
+
}
|
|
620
|
+
switch (typeof value) {
|
|
621
|
+
case "string":
|
|
622
|
+
case "number":
|
|
623
|
+
case "boolean":
|
|
624
|
+
case "bigint":
|
|
625
|
+
case "symbol":
|
|
626
|
+
return String(value);
|
|
627
|
+
case "function":
|
|
628
|
+
return "(function)";
|
|
629
|
+
default:
|
|
630
|
+
return JSON.stringify(value);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function GridGroupRowComponent({
|
|
634
|
+
columnCount,
|
|
635
|
+
groupId,
|
|
636
|
+
level,
|
|
637
|
+
columnLabel,
|
|
638
|
+
value,
|
|
639
|
+
expanded,
|
|
640
|
+
count,
|
|
641
|
+
rowIndex,
|
|
642
|
+
posinset,
|
|
643
|
+
setsize,
|
|
644
|
+
focused
|
|
645
|
+
}) {
|
|
646
|
+
return /* @__PURE__ */ jsx2(
|
|
647
|
+
"tr",
|
|
648
|
+
{
|
|
649
|
+
role: "row",
|
|
650
|
+
"aria-rowindex": rowIndex + 2,
|
|
651
|
+
"aria-level": level + 1,
|
|
652
|
+
"aria-expanded": expanded,
|
|
653
|
+
"aria-setsize": setsize,
|
|
654
|
+
"aria-posinset": posinset,
|
|
655
|
+
"data-gridkit-group": groupId,
|
|
656
|
+
className: classNames(
|
|
657
|
+
"grid-group-row",
|
|
658
|
+
`is-group-level-${String(level)}`
|
|
659
|
+
),
|
|
660
|
+
children: /* @__PURE__ */ jsx2(
|
|
661
|
+
"td",
|
|
662
|
+
{
|
|
663
|
+
role: "gridcell",
|
|
664
|
+
colSpan: columnCount,
|
|
665
|
+
tabIndex: focused ? 0 : -1,
|
|
666
|
+
"aria-keyshortcuts": "Space Enter",
|
|
667
|
+
className: "grid-group-cell",
|
|
668
|
+
children: /* @__PURE__ */ jsxs2(
|
|
669
|
+
"div",
|
|
670
|
+
{
|
|
671
|
+
className: "grid-group-cell-content",
|
|
672
|
+
style: { paddingInlineStart: `${String(level * 1.25 + 0.5)}rem` },
|
|
673
|
+
children: [
|
|
674
|
+
/* @__PURE__ */ jsx2(
|
|
675
|
+
"span",
|
|
676
|
+
{
|
|
677
|
+
className: classNames(
|
|
678
|
+
"group-toggle",
|
|
679
|
+
expanded ? "is-expanded" : "is-collapsed"
|
|
680
|
+
),
|
|
681
|
+
"aria-hidden": "true"
|
|
682
|
+
}
|
|
683
|
+
),
|
|
684
|
+
/* @__PURE__ */ jsxs2("span", { className: "group-label", children: [
|
|
685
|
+
columnLabel,
|
|
686
|
+
": ",
|
|
687
|
+
formatGroupValue(value)
|
|
688
|
+
] }),
|
|
689
|
+
/* @__PURE__ */ jsxs2("span", { className: "group-count", children: [
|
|
690
|
+
"(",
|
|
691
|
+
count,
|
|
692
|
+
")"
|
|
693
|
+
] })
|
|
694
|
+
]
|
|
695
|
+
}
|
|
696
|
+
)
|
|
697
|
+
}
|
|
698
|
+
)
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
var GridGroupRow = memo(GridGroupRowComponent);
|
|
703
|
+
var GridGroupRow_default = GridGroupRow;
|
|
550
704
|
|
|
551
705
|
// src/DataGrid/components/GridRow.tsx
|
|
552
706
|
import { accessDotted } from "@gridkitjs/core";
|
|
553
|
-
import { memo } from "react";
|
|
554
|
-
import { jsx as
|
|
707
|
+
import { memo as memo2 } from "react";
|
|
708
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
555
709
|
function GridRowComponent({
|
|
556
710
|
columns,
|
|
557
711
|
rowId,
|
|
@@ -565,7 +719,7 @@ function GridRowComponent({
|
|
|
565
719
|
rowsSelectable,
|
|
566
720
|
cellsSelectable
|
|
567
721
|
}) {
|
|
568
|
-
return /* @__PURE__ */
|
|
722
|
+
return /* @__PURE__ */ jsx3(
|
|
569
723
|
"tr",
|
|
570
724
|
{
|
|
571
725
|
role: "row",
|
|
@@ -575,7 +729,7 @@ function GridRowComponent({
|
|
|
575
729
|
children: columns.map(({ id, column, alignment }, columnIndex) => {
|
|
576
730
|
const value = accessDotted(row, column.field);
|
|
577
731
|
const cellSelected = id === selectedColumnId;
|
|
578
|
-
return /* @__PURE__ */
|
|
732
|
+
return /* @__PURE__ */ jsx3(
|
|
579
733
|
"td",
|
|
580
734
|
{
|
|
581
735
|
role: "gridcell",
|
|
@@ -600,11 +754,11 @@ function GridRowComponent({
|
|
|
600
754
|
}
|
|
601
755
|
);
|
|
602
756
|
}
|
|
603
|
-
var GridRow =
|
|
757
|
+
var GridRow = memo2(GridRowComponent);
|
|
604
758
|
var GridRow_default = GridRow;
|
|
605
759
|
|
|
606
760
|
// src/DataGrid/components/GridBody.tsx
|
|
607
|
-
import { jsx as
|
|
761
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
608
762
|
function cellFrom(target) {
|
|
609
763
|
if (!(target instanceof Element)) {
|
|
610
764
|
return null;
|
|
@@ -621,18 +775,55 @@ function cellFrom(target) {
|
|
|
621
775
|
columnId
|
|
622
776
|
};
|
|
623
777
|
}
|
|
778
|
+
function groupRowFrom(target) {
|
|
779
|
+
if (!(target instanceof Element)) {
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
const row = target.closest("tr[data-gridkit-group]");
|
|
783
|
+
const groupId = row?.getAttribute("data-gridkit-group");
|
|
784
|
+
if (!(row instanceof HTMLTableRowElement) || groupId === null || groupId === void 0) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
return { rowIndex: row.sectionRowIndex, groupId };
|
|
788
|
+
}
|
|
789
|
+
function groupAriaMeta(rows) {
|
|
790
|
+
const totals = /* @__PURE__ */ new Map();
|
|
791
|
+
for (const entry of rows) {
|
|
792
|
+
if (!("kind" in entry)) continue;
|
|
793
|
+
const parentKey = groupRowId(entry.path.slice(0, -1));
|
|
794
|
+
totals.set(parentKey, (totals.get(parentKey) ?? 0) + 1);
|
|
795
|
+
}
|
|
796
|
+
const seen = /* @__PURE__ */ new Map();
|
|
797
|
+
const meta = /* @__PURE__ */ new Map();
|
|
798
|
+
for (const entry of rows) {
|
|
799
|
+
if (!("kind" in entry)) continue;
|
|
800
|
+
const parentKey = groupRowId(entry.path.slice(0, -1));
|
|
801
|
+
const posinset = (seen.get(parentKey) ?? 0) + 1;
|
|
802
|
+
seen.set(parentKey, posinset);
|
|
803
|
+
meta.set(entry.groupId, {
|
|
804
|
+
posinset,
|
|
805
|
+
setsize: totals.get(parentKey) ?? posinset
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
return meta;
|
|
809
|
+
}
|
|
624
810
|
function GridBody({
|
|
625
811
|
columns,
|
|
626
812
|
rows,
|
|
627
813
|
activeColumnId,
|
|
628
814
|
nav,
|
|
629
|
-
selection
|
|
815
|
+
selection,
|
|
816
|
+
grouping
|
|
630
817
|
}) {
|
|
631
818
|
const { selectedCell, rowMode, cellMode } = selection;
|
|
819
|
+
const ariaMeta = useMemo2(() => groupAriaMeta(rows), [rows]);
|
|
632
820
|
function targetOf(target) {
|
|
633
821
|
const position = cellFrom(target);
|
|
634
822
|
const entry = position === null ? void 0 : rows[position.rowIndex];
|
|
635
|
-
|
|
823
|
+
if (position === null || entry === void 0 || "kind" in entry) {
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
return { position, rowId: entry.rowId };
|
|
636
827
|
}
|
|
637
828
|
function select(rowId, columnId, modifiers) {
|
|
638
829
|
const intent = intentOf2(modifiers);
|
|
@@ -643,21 +834,45 @@ function GridBody({
|
|
|
643
834
|
selection.selectCell({ rowId, columnId }, intent);
|
|
644
835
|
}
|
|
645
836
|
}
|
|
646
|
-
return /* @__PURE__ */
|
|
837
|
+
return /* @__PURE__ */ jsx4(
|
|
647
838
|
"tbody",
|
|
648
839
|
{
|
|
649
840
|
className: "grid-body",
|
|
650
841
|
onFocus: (event) => {
|
|
842
|
+
const group = groupRowFrom(event.target);
|
|
843
|
+
if (group !== null) {
|
|
844
|
+
nav.focusCell(group.rowIndex, 0);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
651
847
|
const found = targetOf(event.target);
|
|
652
848
|
if (found === null) return;
|
|
653
849
|
nav.focusCell(found.position.rowIndex, found.position.columnIndex);
|
|
654
850
|
},
|
|
655
851
|
onClick: (event) => {
|
|
852
|
+
const group = groupRowFrom(event.target);
|
|
853
|
+
if (group !== null) {
|
|
854
|
+
grouping.toggleExpansion(group.groupId);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
656
857
|
const found = targetOf(event.target);
|
|
657
858
|
if (found === null) return;
|
|
658
859
|
select(found.rowId, found.position.columnId, event);
|
|
659
860
|
},
|
|
660
861
|
onKeyDown: (event) => {
|
|
862
|
+
const group = groupRowFrom(event.target);
|
|
863
|
+
if (group !== null) {
|
|
864
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
865
|
+
event.preventDefault();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (event.key === " " || event.key === "Enter") {
|
|
869
|
+
event.preventDefault();
|
|
870
|
+
grouping.toggleExpansion(group.groupId);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
nav.onKeyDown(event);
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
661
876
|
if (event.key === " " || event.key === "Enter") {
|
|
662
877
|
const found = targetOf(event.target);
|
|
663
878
|
if (found === null) return;
|
|
@@ -671,37 +886,60 @@ function GridBody({
|
|
|
671
886
|
}
|
|
672
887
|
nav.onKeyDown(event);
|
|
673
888
|
},
|
|
674
|
-
children: rows.map(
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
889
|
+
children: rows.map(
|
|
890
|
+
(entry) => "kind" in entry ? /* @__PURE__ */ jsx4(
|
|
891
|
+
GridGroupRow_default,
|
|
892
|
+
{
|
|
893
|
+
columnCount: columns.length,
|
|
894
|
+
groupId: entry.groupId,
|
|
895
|
+
level: entry.level,
|
|
896
|
+
columnLabel: columns.find((column) => column.id === entry.columnId)?.label ?? entry.columnId,
|
|
897
|
+
value: entry.value,
|
|
898
|
+
expanded: entry.expanded,
|
|
899
|
+
count: entry.count,
|
|
900
|
+
rowIndex: entry.rowIndex,
|
|
901
|
+
posinset: ariaMeta.get(entry.groupId)?.posinset ?? 1,
|
|
902
|
+
setsize: ariaMeta.get(entry.groupId)?.setsize ?? 1,
|
|
903
|
+
focused: nav.focus.rowIndex === entry.rowIndex
|
|
904
|
+
},
|
|
905
|
+
entry.groupId
|
|
906
|
+
) : /* @__PURE__ */ jsx4(
|
|
907
|
+
GridRow_default,
|
|
908
|
+
{
|
|
909
|
+
columns,
|
|
910
|
+
rowId: entry.rowId,
|
|
911
|
+
row: entry.row,
|
|
912
|
+
rowIndex: entry.rowIndex,
|
|
913
|
+
activeColumnId,
|
|
914
|
+
selectedColumnIds: selection.selectedColumnIds,
|
|
915
|
+
selected: selection.selectedRowIds.has(entry.rowId),
|
|
916
|
+
selectedColumnId: selectedCell?.rowId === entry.rowId ? selectedCell.columnId : null,
|
|
917
|
+
focusedColumnIndex: nav.focus.rowIndex === entry.rowIndex ? nav.focus.columnIndex : null,
|
|
918
|
+
rowsSelectable: rowMode !== false,
|
|
919
|
+
cellsSelectable: cellMode !== false
|
|
920
|
+
},
|
|
921
|
+
entry.rowId
|
|
922
|
+
)
|
|
923
|
+
)
|
|
691
924
|
}
|
|
692
925
|
);
|
|
693
926
|
}
|
|
694
927
|
|
|
695
|
-
// src/DataGrid/
|
|
928
|
+
// src/DataGrid/components/GroupByBar.tsx
|
|
929
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
930
|
+
import { resolveKeyboardDropTarget } from "@gridkitjs/core";
|
|
931
|
+
|
|
932
|
+
// src/DataGrid/groupByDropTarget.ts
|
|
933
|
+
import {
|
|
934
|
+
movesGroupBy,
|
|
935
|
+
resolveDropBefore
|
|
936
|
+
} from "@gridkitjs/core";
|
|
937
|
+
|
|
938
|
+
// src/DataGrid/useDragReorder.ts
|
|
696
939
|
import {
|
|
697
940
|
useRef as useRef3,
|
|
698
941
|
useState as useState2
|
|
699
942
|
} from "react";
|
|
700
|
-
import {
|
|
701
|
-
movesColumn,
|
|
702
|
-
resolveDropBefore,
|
|
703
|
-
resolveKeyboardDropTarget
|
|
704
|
-
} from "@gridkitjs/core";
|
|
705
943
|
|
|
706
944
|
// src/DataGrid/pointerGesture.ts
|
|
707
945
|
function startPointerGesture(element, pointerId, handlers) {
|
|
@@ -737,21 +975,20 @@ function startPointerGesture(element, pointerId, handlers) {
|
|
|
737
975
|
window.addEventListener("keydown", onKeyDown);
|
|
738
976
|
}
|
|
739
977
|
|
|
740
|
-
// src/DataGrid/
|
|
978
|
+
// src/DataGrid/useDragReorder.ts
|
|
741
979
|
var DRAG_THRESHOLD = 4;
|
|
742
|
-
function
|
|
743
|
-
|
|
744
|
-
return element?.closest("th[data-gridkit-column]") ?? null;
|
|
980
|
+
function elementAt(x, y, selector) {
|
|
981
|
+
return document.elementFromPoint(x, y)?.closest(selector) ?? null;
|
|
745
982
|
}
|
|
746
983
|
function sideOf(element, x) {
|
|
747
984
|
const rect = element.getBoundingClientRect();
|
|
748
985
|
return x < rect.left + rect.width / 2 ? "before" : "after";
|
|
749
986
|
}
|
|
750
|
-
function
|
|
751
|
-
|
|
987
|
+
function useDragReorder({
|
|
988
|
+
resolveTarget,
|
|
752
989
|
onDrop
|
|
753
990
|
}) {
|
|
754
|
-
const [
|
|
991
|
+
const [draggedId, setDraggedId] = useState2(null);
|
|
755
992
|
const [dropTarget, setDropTarget] = useState2(null);
|
|
756
993
|
const [ghostTransform, setGhostTransform] = useState2(null);
|
|
757
994
|
const dragged = useRef3(false);
|
|
@@ -760,10 +997,9 @@ function useColumnDrag({
|
|
|
760
997
|
dragged.current = false;
|
|
761
998
|
return answer;
|
|
762
999
|
}
|
|
763
|
-
function startDrag(
|
|
764
|
-
const header = event.currentTarget;
|
|
1000
|
+
function startDrag(id, grabElement, event) {
|
|
765
1001
|
const { pointerId, clientX: startX } = event;
|
|
766
|
-
const grabX = startX -
|
|
1002
|
+
const grabX = startX - grabElement.getBoundingClientRect().left;
|
|
767
1003
|
let dragging = false;
|
|
768
1004
|
let target = null;
|
|
769
1005
|
function placeGhost(x, y) {
|
|
@@ -771,10 +1007,10 @@ function useColumnDrag({
|
|
|
771
1007
|
}
|
|
772
1008
|
function reset() {
|
|
773
1009
|
setGhostTransform(null);
|
|
774
|
-
|
|
1010
|
+
setDraggedId(null);
|
|
775
1011
|
setDropTarget(null);
|
|
776
1012
|
}
|
|
777
|
-
startPointerGesture(
|
|
1013
|
+
startPointerGesture(grabElement, pointerId, {
|
|
778
1014
|
onMove(moveEvent) {
|
|
779
1015
|
const { clientX, clientY } = moveEvent;
|
|
780
1016
|
if (!dragging) {
|
|
@@ -783,20 +1019,17 @@ function useColumnDrag({
|
|
|
783
1019
|
}
|
|
784
1020
|
dragging = true;
|
|
785
1021
|
dragged.current = true;
|
|
786
|
-
|
|
1022
|
+
setDraggedId(id);
|
|
787
1023
|
}
|
|
788
1024
|
placeGhost(clientX, clientY);
|
|
789
|
-
|
|
790
|
-
const overId = over?.getAttribute("data-gridkit-column");
|
|
791
|
-
const beforeId = over && overId ? resolveDropBefore(order, overId, sideOf(over, clientX)) : void 0;
|
|
792
|
-
target = beforeId !== void 0 && movesColumn(order, entry.id, beforeId) ? { kind: "column-order", beforeId } : null;
|
|
1025
|
+
target = resolveTarget(clientX, clientY, id);
|
|
793
1026
|
setDropTarget(target);
|
|
794
1027
|
},
|
|
795
1028
|
onEnd() {
|
|
796
1029
|
const dropped = target;
|
|
797
1030
|
reset();
|
|
798
1031
|
if (dragging && dropped !== null) {
|
|
799
|
-
onDrop(dropped,
|
|
1032
|
+
onDrop(dropped, id);
|
|
800
1033
|
}
|
|
801
1034
|
},
|
|
802
1035
|
// Escape and a cancelled pointer both leave the order as it was.
|
|
@@ -806,20 +1039,214 @@ function useColumnDrag({
|
|
|
806
1039
|
}
|
|
807
1040
|
});
|
|
808
1041
|
}
|
|
1042
|
+
return {
|
|
1043
|
+
draggedId,
|
|
1044
|
+
dropTarget,
|
|
1045
|
+
ghostTransform,
|
|
1046
|
+
startDrag,
|
|
1047
|
+
justDragged
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/DataGrid/groupByDropTarget.ts
|
|
1052
|
+
function resolveGroupByDropTarget(clientX, clientY, movedId, groupBy) {
|
|
1053
|
+
const overBar = elementAt(clientX, clientY, "[data-gridkit-group-by-bar]");
|
|
1054
|
+
if (overBar === null) {
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
const overChip = elementAt(clientX, clientY, "[data-gridkit-group-chip]");
|
|
1058
|
+
const chipId = overChip?.getAttribute("data-gridkit-group-chip");
|
|
1059
|
+
const beforeColumnId = overChip && chipId ? resolveDropBefore(
|
|
1060
|
+
groupBy.map((entry) => entry.columnId),
|
|
1061
|
+
chipId,
|
|
1062
|
+
sideOf(overChip, clientX)
|
|
1063
|
+
) : null;
|
|
1064
|
+
return movesGroupBy(groupBy, movedId, beforeColumnId) ? { kind: "group-by", beforeColumnId } : null;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/DataGrid/useGroupByDrag.ts
|
|
1068
|
+
function useGroupByDrag({
|
|
1069
|
+
groupBy,
|
|
1070
|
+
onDrop
|
|
1071
|
+
}) {
|
|
1072
|
+
const drag = useDragReorder({
|
|
1073
|
+
resolveTarget: (clientX, clientY, movedId) => resolveGroupByDropTarget(clientX, clientY, movedId, groupBy),
|
|
1074
|
+
onDrop: (target, movedId) => {
|
|
1075
|
+
onDrop(movedId, target.beforeColumnId);
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
return {
|
|
1079
|
+
draggedColumnId: drag.draggedId,
|
|
1080
|
+
dropTarget: drag.dropTarget,
|
|
1081
|
+
ghostTransform: drag.ghostTransform,
|
|
1082
|
+
startDrag: (columnId, event) => {
|
|
1083
|
+
drag.startDrag(columnId, event.currentTarget, event);
|
|
1084
|
+
},
|
|
1085
|
+
justDragged: drag.justDragged
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// src/DataGrid/components/GroupByBar.tsx
|
|
1090
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1091
|
+
function GroupByBar({
|
|
1092
|
+
columns,
|
|
1093
|
+
grouping,
|
|
1094
|
+
columnName,
|
|
1095
|
+
headerDragEligible,
|
|
1096
|
+
headerDragBlocked,
|
|
1097
|
+
headerDropTarget
|
|
1098
|
+
}) {
|
|
1099
|
+
const { groupBy } = grouping;
|
|
1100
|
+
const groupByIds = groupBy.map((entry) => entry.columnId);
|
|
1101
|
+
const chipDrag = useGroupByDrag({
|
|
1102
|
+
groupBy,
|
|
1103
|
+
onDrop: (movedId, beforeColumnId) => {
|
|
1104
|
+
grouping.moveGroupBy(movedId, beforeColumnId);
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
const activeDropTarget = chipDrag.dropTarget ?? headerDropTarget;
|
|
1108
|
+
const isDragTarget = chipDrag.draggedColumnId !== null || headerDragEligible;
|
|
1109
|
+
const showPlaceholder = groupBy.length === 0 && columns.some((entry) => entry.groupByDraggable);
|
|
1110
|
+
function labelFor(columnId) {
|
|
1111
|
+
return columns.find((entry) => entry.id === columnId)?.label ?? columnId;
|
|
1112
|
+
}
|
|
1113
|
+
function moveByKeyboard(columnId, direction) {
|
|
1114
|
+
const beforeColumnId = resolveKeyboardDropTarget(
|
|
1115
|
+
groupByIds,
|
|
1116
|
+
columnId,
|
|
1117
|
+
direction
|
|
1118
|
+
);
|
|
1119
|
+
if (beforeColumnId === void 0) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
grouping.moveGroupBy(columnId, beforeColumnId);
|
|
1123
|
+
}
|
|
1124
|
+
return /* @__PURE__ */ jsxs3(
|
|
1125
|
+
"div",
|
|
1126
|
+
{
|
|
1127
|
+
className: classNames(
|
|
1128
|
+
"gridkit-group-by-bar",
|
|
1129
|
+
isDragTarget ? "is-drag-target" : "",
|
|
1130
|
+
headerDragBlocked ? "is-drag-blocked" : ""
|
|
1131
|
+
),
|
|
1132
|
+
"data-gridkit-group-by-bar": "",
|
|
1133
|
+
role: "group",
|
|
1134
|
+
"aria-label": "Grouped by",
|
|
1135
|
+
children: [
|
|
1136
|
+
showPlaceholder && /* @__PURE__ */ jsx5("span", { className: "group-by-bar-placeholder", children: "Drag a column here to group by it" }),
|
|
1137
|
+
groupBy.map((entry, index) => {
|
|
1138
|
+
const dropBefore = activeDropTarget?.beforeColumnId === entry.columnId;
|
|
1139
|
+
const dropAfter = activeDropTarget?.beforeColumnId === null && index === groupBy.length - 1;
|
|
1140
|
+
const dragging = chipDrag.draggedColumnId === entry.columnId;
|
|
1141
|
+
return /* @__PURE__ */ jsxs3(
|
|
1142
|
+
"span",
|
|
1143
|
+
{
|
|
1144
|
+
className: classNames(
|
|
1145
|
+
"group-by-chip",
|
|
1146
|
+
dragging ? "is-dragging" : "",
|
|
1147
|
+
dropBefore ? "is-drop-before" : "",
|
|
1148
|
+
dropAfter ? "is-drop-after" : ""
|
|
1149
|
+
),
|
|
1150
|
+
"data-gridkit-group-chip": entry.columnId,
|
|
1151
|
+
tabIndex: 0,
|
|
1152
|
+
"aria-label": groupBy.length > 1 ? `${columnName(entry.columnId)}, level ${String(index + 1)} of ${String(groupBy.length)}` : columnName(entry.columnId),
|
|
1153
|
+
"aria-keyshortcuts": "Control+ArrowLeft Control+ArrowRight",
|
|
1154
|
+
onPointerDown: (event) => {
|
|
1155
|
+
chipDrag.startDrag(entry.columnId, event);
|
|
1156
|
+
},
|
|
1157
|
+
onKeyDown: (event) => {
|
|
1158
|
+
const horizontal = event.key === "ArrowLeft" || event.key === "ArrowRight";
|
|
1159
|
+
if (horizontal && event.ctrlKey) {
|
|
1160
|
+
event.preventDefault();
|
|
1161
|
+
moveByKeyboard(
|
|
1162
|
+
entry.columnId,
|
|
1163
|
+
event.key === "ArrowLeft" ? -1 : 1
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
},
|
|
1167
|
+
children: [
|
|
1168
|
+
/* @__PURE__ */ jsx5("span", { className: "group-by-chip-label", children: labelFor(entry.columnId) }),
|
|
1169
|
+
/* @__PURE__ */ jsx5(
|
|
1170
|
+
"button",
|
|
1171
|
+
{
|
|
1172
|
+
type: "button",
|
|
1173
|
+
className: "group-by-chip-remove",
|
|
1174
|
+
"aria-label": `Stop grouping by ${columnName(entry.columnId)}`,
|
|
1175
|
+
onPointerDown: (event) => {
|
|
1176
|
+
event.stopPropagation();
|
|
1177
|
+
},
|
|
1178
|
+
onClick: () => {
|
|
1179
|
+
grouping.toggleGroupBy(entry.columnId);
|
|
1180
|
+
},
|
|
1181
|
+
children: "\xD7"
|
|
1182
|
+
}
|
|
1183
|
+
)
|
|
1184
|
+
]
|
|
1185
|
+
},
|
|
1186
|
+
entry.columnId
|
|
1187
|
+
);
|
|
1188
|
+
}),
|
|
1189
|
+
chipDrag.draggedColumnId !== null && chipDrag.ghostTransform !== null && createPortal2(
|
|
1190
|
+
/* @__PURE__ */ jsx5(
|
|
1191
|
+
"span",
|
|
1192
|
+
{
|
|
1193
|
+
className: "group-by-chip drag-ghost",
|
|
1194
|
+
style: { transform: chipDrag.ghostTransform },
|
|
1195
|
+
"aria-hidden": "true",
|
|
1196
|
+
children: labelFor(chipDrag.draggedColumnId)
|
|
1197
|
+
}
|
|
1198
|
+
),
|
|
1199
|
+
document.body
|
|
1200
|
+
)
|
|
1201
|
+
]
|
|
1202
|
+
}
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// src/DataGrid/useColumnDrag.ts
|
|
1207
|
+
import {
|
|
1208
|
+
movesColumn,
|
|
1209
|
+
resolveDropBefore as resolveDropBefore2,
|
|
1210
|
+
resolveKeyboardDropTarget as resolveKeyboardDropTarget2
|
|
1211
|
+
} from "@gridkitjs/core";
|
|
1212
|
+
function useColumnDrag({
|
|
1213
|
+
order,
|
|
1214
|
+
groupBy,
|
|
1215
|
+
groupByDraggableIds,
|
|
1216
|
+
onDrop
|
|
1217
|
+
}) {
|
|
1218
|
+
const drag = useDragReorder({
|
|
1219
|
+
resolveTarget(clientX, clientY, movedId) {
|
|
1220
|
+
const over = elementAt(clientX, clientY, "th[data-gridkit-column]");
|
|
1221
|
+
const overId = over?.getAttribute("data-gridkit-column");
|
|
1222
|
+
const beforeId = over && overId ? resolveDropBefore2(order, overId, sideOf(over, clientX)) : void 0;
|
|
1223
|
+
if (beforeId !== void 0) {
|
|
1224
|
+
return movesColumn(order, movedId, beforeId) ? { kind: "column-order", beforeId } : null;
|
|
1225
|
+
}
|
|
1226
|
+
const alreadyGrouped = groupBy.some(
|
|
1227
|
+
(entry) => entry.columnId === movedId
|
|
1228
|
+
);
|
|
1229
|
+
return groupByDraggableIds.has(movedId) && !alreadyGrouped ? resolveGroupByDropTarget(clientX, clientY, movedId, groupBy) : null;
|
|
1230
|
+
},
|
|
1231
|
+
onDrop
|
|
1232
|
+
});
|
|
1233
|
+
function startDrag(entry, event) {
|
|
1234
|
+
drag.startDrag(entry.id, event.currentTarget, event);
|
|
1235
|
+
}
|
|
809
1236
|
function moveByKeyboard(entry, direction) {
|
|
810
|
-
const beforeId =
|
|
1237
|
+
const beforeId = resolveKeyboardDropTarget2(order, entry.id, direction);
|
|
811
1238
|
if (beforeId === void 0) {
|
|
812
1239
|
return;
|
|
813
1240
|
}
|
|
814
1241
|
onDrop({ kind: "column-order", beforeId }, entry.id);
|
|
815
1242
|
}
|
|
816
1243
|
return {
|
|
817
|
-
draggedColumnId,
|
|
818
|
-
dropTarget,
|
|
819
|
-
ghostTransform,
|
|
1244
|
+
draggedColumnId: drag.draggedId,
|
|
1245
|
+
dropTarget: drag.dropTarget,
|
|
1246
|
+
ghostTransform: drag.ghostTransform,
|
|
820
1247
|
startDrag,
|
|
821
1248
|
moveByKeyboard,
|
|
822
|
-
justDragged
|
|
1249
|
+
justDragged: drag.justDragged
|
|
823
1250
|
};
|
|
824
1251
|
}
|
|
825
1252
|
|
|
@@ -994,8 +1421,62 @@ function useElementWidth(ref, enabled) {
|
|
|
994
1421
|
return width;
|
|
995
1422
|
}
|
|
996
1423
|
|
|
1424
|
+
// src/DataGrid/useRowGrouping.ts
|
|
1425
|
+
import {
|
|
1426
|
+
collapseAllGroups,
|
|
1427
|
+
expandAllGroups,
|
|
1428
|
+
moveGroupByBefore,
|
|
1429
|
+
toggleGroupExpansion
|
|
1430
|
+
} from "@gridkitjs/core";
|
|
1431
|
+
function useRowGrouping({
|
|
1432
|
+
groupBy,
|
|
1433
|
+
setGroupBy,
|
|
1434
|
+
expansion,
|
|
1435
|
+
setExpansion,
|
|
1436
|
+
onGroupByChange,
|
|
1437
|
+
onGroupExpansionChange
|
|
1438
|
+
}) {
|
|
1439
|
+
function commitExpansion(next, groupId) {
|
|
1440
|
+
commitIfChanged(expansion, next, setExpansion, (committed) => {
|
|
1441
|
+
onGroupExpansionChange?.({ groupId, expansion: committed });
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function commitGroupBy(next, columnId) {
|
|
1445
|
+
commitIfChanged(groupBy, next, setGroupBy, (committed) => {
|
|
1446
|
+
onGroupByChange?.({ columnId, groupBy: committed });
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
function toggleGroupBy(columnId) {
|
|
1450
|
+
const isGrouped = groupBy.some((entry) => entry.columnId === columnId);
|
|
1451
|
+
const next = isGrouped ? groupBy.filter((entry) => entry.columnId !== columnId) : [...groupBy, { columnId }];
|
|
1452
|
+
commitGroupBy(next, columnId);
|
|
1453
|
+
}
|
|
1454
|
+
function moveGroupBy(columnId, beforeColumnId) {
|
|
1455
|
+
commitGroupBy(
|
|
1456
|
+
moveGroupByBefore(groupBy, columnId, beforeColumnId),
|
|
1457
|
+
columnId
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
return {
|
|
1461
|
+
groupBy,
|
|
1462
|
+
expansion,
|
|
1463
|
+
isExpanded: (groupId) => !expansion.includes(groupId),
|
|
1464
|
+
toggleExpansion: (groupId) => {
|
|
1465
|
+
commitExpansion(toggleGroupExpansion(expansion, groupId), groupId);
|
|
1466
|
+
},
|
|
1467
|
+
expandAll: () => {
|
|
1468
|
+
commitExpansion(expandAllGroups(expansion), null);
|
|
1469
|
+
},
|
|
1470
|
+
collapseAll: (rows) => {
|
|
1471
|
+
commitExpansion(collapseAllGroups(rows), null);
|
|
1472
|
+
},
|
|
1473
|
+
toggleGroupBy,
|
|
1474
|
+
moveGroupBy
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
|
|
997
1478
|
// src/DataGrid/DataGrid.tsx
|
|
998
|
-
import { jsx as
|
|
1479
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
999
1480
|
function DataGridComponent({
|
|
1000
1481
|
dataSource,
|
|
1001
1482
|
columns,
|
|
@@ -1017,6 +1498,14 @@ function DataGridComponent({
|
|
|
1017
1498
|
sortableColumns = false,
|
|
1018
1499
|
defaultColumnSort,
|
|
1019
1500
|
onColumnSortChange,
|
|
1501
|
+
groupableColumns = false,
|
|
1502
|
+
groupToggleIconColumns = true,
|
|
1503
|
+
groupByDraggableColumns = false,
|
|
1504
|
+
groupByBarVisibility = "auto",
|
|
1505
|
+
defaultGroupBy,
|
|
1506
|
+
onGroupByChange,
|
|
1507
|
+
defaultGroupExpansion,
|
|
1508
|
+
onGroupExpansionChange,
|
|
1020
1509
|
defaultFilter,
|
|
1021
1510
|
label,
|
|
1022
1511
|
labelledBy,
|
|
@@ -1036,6 +1525,10 @@ function DataGridComponent({
|
|
|
1036
1525
|
defaultColumnOrder ?? []
|
|
1037
1526
|
);
|
|
1038
1527
|
const [sort, setSort] = useState5(defaultColumnSort ?? []);
|
|
1528
|
+
const [groupBy, setGroupBy] = useState5(defaultGroupBy ?? []);
|
|
1529
|
+
const [expansion, setExpansion] = useState5(
|
|
1530
|
+
defaultGroupExpansion ?? []
|
|
1531
|
+
);
|
|
1039
1532
|
const [filter] = useState5(defaultFilter ?? []);
|
|
1040
1533
|
const [announcement, setAnnouncement] = useState5("");
|
|
1041
1534
|
const [rowSelection, setRowSelection] = useState5(
|
|
@@ -1047,7 +1540,7 @@ function DataGridComponent({
|
|
|
1047
1540
|
const [cellSelection, setCellSelection] = useState5(
|
|
1048
1541
|
defaultCellSelection ?? null
|
|
1049
1542
|
);
|
|
1050
|
-
const rows =
|
|
1543
|
+
const rows = useMemo3(
|
|
1051
1544
|
() => dataSource?.map((row, rowIndex) => ({
|
|
1052
1545
|
rowId: resolveRowId(row, rowIndex, getRowId),
|
|
1053
1546
|
row,
|
|
@@ -1055,21 +1548,22 @@ function DataGridComponent({
|
|
|
1055
1548
|
})) ?? [],
|
|
1056
1549
|
[dataSource, getRowId]
|
|
1057
1550
|
);
|
|
1058
|
-
const definedColumns =
|
|
1551
|
+
const definedColumns = useMemo3(() => {
|
|
1059
1552
|
if (columns && columns.length !== 0) return columns;
|
|
1060
1553
|
if (dataSource && dataSource.length > 0)
|
|
1061
1554
|
return defineColumnsFromRows(dataSource);
|
|
1062
1555
|
return [];
|
|
1063
1556
|
}, [columns, dataSource]);
|
|
1064
|
-
const orderedColumns =
|
|
1557
|
+
const orderedColumns = useMemo3(
|
|
1065
1558
|
() => applyColumnOrder(definedColumns, order),
|
|
1066
1559
|
[definedColumns, order]
|
|
1067
1560
|
);
|
|
1068
|
-
const resolved =
|
|
1561
|
+
const resolved = useMemo3(() => {
|
|
1069
1562
|
const widths = resolveColumnWidths(orderedColumns, sizing, {
|
|
1070
1563
|
sizes: columnSizeDefaults,
|
|
1071
1564
|
resizable: resizableColumns,
|
|
1072
|
-
reorderable: reorderableColumns
|
|
1565
|
+
reorderable: reorderableColumns,
|
|
1566
|
+
groupByDraggable: groupByDraggableColumns
|
|
1073
1567
|
});
|
|
1074
1568
|
return resizeMode === "fit" && viewportWidth !== null ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults) : widths;
|
|
1075
1569
|
}, [
|
|
@@ -1079,12 +1573,23 @@ function DataGridComponent({
|
|
|
1079
1573
|
viewportWidth,
|
|
1080
1574
|
columnSizeDefaults,
|
|
1081
1575
|
resizableColumns,
|
|
1082
|
-
reorderableColumns
|
|
1576
|
+
reorderableColumns,
|
|
1577
|
+
groupByDraggableColumns
|
|
1083
1578
|
]);
|
|
1084
|
-
const shownRows =
|
|
1579
|
+
const shownRows = useMemo3(
|
|
1085
1580
|
() => resolveShownRows(rows, filter, sort, resolved),
|
|
1086
1581
|
[rows, filter, sort, resolved]
|
|
1087
1582
|
);
|
|
1583
|
+
const displayRows = useMemo3(
|
|
1584
|
+
() => groupRows(shownRows, groupBy, expansion, resolved),
|
|
1585
|
+
[shownRows, groupBy, expansion, resolved]
|
|
1586
|
+
);
|
|
1587
|
+
const displayDataRows = useMemo3(
|
|
1588
|
+
() => groupBy.length === 0 ? shownRows : displayRows.filter(
|
|
1589
|
+
(entry) => !("kind" in entry)
|
|
1590
|
+
),
|
|
1591
|
+
[displayRows, groupBy.length, shownRows]
|
|
1592
|
+
);
|
|
1088
1593
|
function columnName(columnId) {
|
|
1089
1594
|
const entry = resolved.find((candidate) => candidate.id === columnId);
|
|
1090
1595
|
if (entry === void 0) {
|
|
@@ -1110,16 +1615,62 @@ function DataGridComponent({
|
|
|
1110
1615
|
columnSizeDefaults,
|
|
1111
1616
|
onColumnResize: handleColumnResize
|
|
1112
1617
|
});
|
|
1618
|
+
function handleGroupByChange(event) {
|
|
1619
|
+
onGroupByChange?.(event);
|
|
1620
|
+
const entry = event.groupBy.find(
|
|
1621
|
+
(candidate) => candidate.columnId === event.columnId
|
|
1622
|
+
);
|
|
1623
|
+
if (entry === void 0) {
|
|
1624
|
+
announce(`${columnName(event.columnId)}, grouping removed`);
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
announce(
|
|
1628
|
+
event.groupBy.length > 1 ? `Grouped by ${columnName(event.columnId)}, level ${String(event.groupBy.indexOf(entry) + 1)} of ${String(event.groupBy.length)}` : `Grouped by ${columnName(event.columnId)}`
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
function handleGroupExpansionChange(event) {
|
|
1632
|
+
onGroupExpansionChange?.(event);
|
|
1633
|
+
if (event.groupId === null) {
|
|
1634
|
+
announce(
|
|
1635
|
+
event.expansion.length === 0 ? "All groups expanded" : "All groups collapsed"
|
|
1636
|
+
);
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
announce(
|
|
1640
|
+
event.expansion.includes(event.groupId) ? "Group collapsed" : "Group expanded"
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
const grouping = useRowGrouping({
|
|
1644
|
+
groupBy,
|
|
1645
|
+
setGroupBy,
|
|
1646
|
+
expansion,
|
|
1647
|
+
setExpansion,
|
|
1648
|
+
onGroupByChange: handleGroupByChange,
|
|
1649
|
+
onGroupExpansionChange: handleGroupExpansionChange
|
|
1650
|
+
});
|
|
1113
1651
|
const nav = useGridNavigation({
|
|
1114
1652
|
tableRef,
|
|
1115
|
-
|
|
1653
|
+
// Group headers are addressable rows too — the whole point of the flat
|
|
1654
|
+
// `DisplayRow[]` shape is that they share one position space with data
|
|
1655
|
+
// rows, so navigation counts them the same way.
|
|
1656
|
+
rowCount: displayRows.length,
|
|
1116
1657
|
columnCount: resolved.length
|
|
1117
1658
|
});
|
|
1118
|
-
const displayedIds =
|
|
1659
|
+
const displayedIds = useMemo3(
|
|
1119
1660
|
() => orderedColumns.map((column) => column.id ?? column.field),
|
|
1120
1661
|
[orderedColumns]
|
|
1121
1662
|
);
|
|
1663
|
+
const groupByDraggableIds = useMemo3(
|
|
1664
|
+
() => new Set(
|
|
1665
|
+
resolved.filter((entry) => entry.groupByDraggable).map((entry) => entry.id)
|
|
1666
|
+
),
|
|
1667
|
+
[resolved]
|
|
1668
|
+
);
|
|
1122
1669
|
function handleDrop(target, movedId) {
|
|
1670
|
+
if (target.kind === "group-by") {
|
|
1671
|
+
grouping.moveGroupBy(movedId, target.beforeColumnId);
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1123
1674
|
const next = moveColumnBefore(displayedIds, movedId, target.beforeId);
|
|
1124
1675
|
if (next === displayedIds) {
|
|
1125
1676
|
return;
|
|
@@ -1132,7 +1683,16 @@ function DataGridComponent({
|
|
|
1132
1683
|
);
|
|
1133
1684
|
nav.focusCell(HEADER_ROW, position);
|
|
1134
1685
|
}
|
|
1135
|
-
const drag = useColumnDrag({
|
|
1686
|
+
const drag = useColumnDrag({
|
|
1687
|
+
order: displayedIds,
|
|
1688
|
+
groupBy,
|
|
1689
|
+
groupByDraggableIds,
|
|
1690
|
+
onDrop: handleDrop
|
|
1691
|
+
});
|
|
1692
|
+
const draggedColumnAlreadyGrouped = drag.draggedColumnId !== null && groupBy.some((entry) => entry.columnId === drag.draggedColumnId);
|
|
1693
|
+
const dragEligibleForGroupBy = drag.draggedColumnId !== null && groupByDraggableIds.has(drag.draggedColumnId) && !draggedColumnAlreadyGrouped;
|
|
1694
|
+
const showGroupByBar = groupByBarVisibility === "always" || groupByBarVisibility === "auto" && (groupBy.length > 0 || dragEligibleForGroupBy);
|
|
1695
|
+
const headerGroupByDropTarget = drag.dropTarget?.kind === "group-by" ? drag.dropTarget : null;
|
|
1136
1696
|
function handleColumnSortChange(event) {
|
|
1137
1697
|
onColumnSortChange?.(event);
|
|
1138
1698
|
const entry = event.sort.find(
|
|
@@ -1153,7 +1713,7 @@ function DataGridComponent({
|
|
|
1153
1713
|
onColumnSortChange: handleColumnSortChange
|
|
1154
1714
|
});
|
|
1155
1715
|
const selection = useGridSelection({
|
|
1156
|
-
rows:
|
|
1716
|
+
rows: displayDataRows,
|
|
1157
1717
|
columns: resolved,
|
|
1158
1718
|
selectable,
|
|
1159
1719
|
rowSelection,
|
|
@@ -1175,10 +1735,13 @@ function DataGridComponent({
|
|
|
1175
1735
|
return tableRef.current;
|
|
1176
1736
|
},
|
|
1177
1737
|
getRows: () => shownRows,
|
|
1738
|
+
getDisplayRows: () => displayRows,
|
|
1178
1739
|
getColumns: () => resolved,
|
|
1179
1740
|
getColumnSizing: () => sizing,
|
|
1180
1741
|
getColumnOrder: () => order,
|
|
1181
1742
|
getColumnSort: () => sort,
|
|
1743
|
+
getGroupBy: () => groupBy,
|
|
1744
|
+
getGroupExpansion: () => expansion,
|
|
1182
1745
|
getRowSelection: () => rowSelection,
|
|
1183
1746
|
getColumnSelection: () => columnSelection,
|
|
1184
1747
|
getCellSelection: () => cellSelection,
|
|
@@ -1186,8 +1749,14 @@ function DataGridComponent({
|
|
|
1186
1749
|
focusCell: nav.focusCell,
|
|
1187
1750
|
clearSelection: selection.clear,
|
|
1188
1751
|
selectAllRows: selection.selectAllRows,
|
|
1752
|
+
expandAllGroups: grouping.expandAll,
|
|
1753
|
+
collapseAllGroups: () => {
|
|
1754
|
+
grouping.collapseAll(displayRows);
|
|
1755
|
+
},
|
|
1189
1756
|
scrollToRow: (rowId, options) => {
|
|
1190
|
-
const index =
|
|
1757
|
+
const index = displayRows.findIndex(
|
|
1758
|
+
(entry) => !("kind" in entry) && entry.rowId === rowId
|
|
1759
|
+
);
|
|
1191
1760
|
if (index === -1) return;
|
|
1192
1761
|
tableRef.current?.tBodies[0]?.rows[index]?.scrollIntoView(options);
|
|
1193
1762
|
},
|
|
@@ -1199,13 +1768,24 @@ function DataGridComponent({
|
|
|
1199
1768
|
cell?.scrollIntoView(options);
|
|
1200
1769
|
}
|
|
1201
1770
|
}));
|
|
1202
|
-
return /* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */
|
|
1771
|
+
return /* @__PURE__ */ jsxs4("div", { className: "gridkit-data-grid-viewport", ref: viewportRef, children: [
|
|
1772
|
+
showGroupByBar && /* @__PURE__ */ jsx6(
|
|
1773
|
+
GroupByBar,
|
|
1774
|
+
{
|
|
1775
|
+
columns: resolved,
|
|
1776
|
+
grouping,
|
|
1777
|
+
columnName,
|
|
1778
|
+
headerDragEligible: dragEligibleForGroupBy,
|
|
1779
|
+
headerDragBlocked: draggedColumnAlreadyGrouped,
|
|
1780
|
+
headerDropTarget: headerGroupByDropTarget
|
|
1781
|
+
}
|
|
1782
|
+
),
|
|
1783
|
+
/* @__PURE__ */ jsxs4(
|
|
1204
1784
|
"table",
|
|
1205
1785
|
{
|
|
1206
1786
|
ref: tableRef,
|
|
1207
|
-
role: "grid",
|
|
1208
|
-
"aria-rowcount":
|
|
1787
|
+
role: groupBy.length > 0 ? "treegrid" : "grid",
|
|
1788
|
+
"aria-rowcount": displayRows.length + 1,
|
|
1209
1789
|
"aria-colcount": resolved.length,
|
|
1210
1790
|
...ariaAttr(multiselectable, "aria-multiselectable", true),
|
|
1211
1791
|
...ariaAttr(labelledBy !== void 0, "aria-labelledby", labelledBy),
|
|
@@ -1242,8 +1822,8 @@ function DataGridComponent({
|
|
|
1242
1822
|
selection.cellMode === false ? "" : "selectable-cells"
|
|
1243
1823
|
),
|
|
1244
1824
|
children: [
|
|
1245
|
-
/* @__PURE__ */
|
|
1246
|
-
/* @__PURE__ */
|
|
1825
|
+
/* @__PURE__ */ jsx6("colgroup", { children: resolved.map((entry) => /* @__PURE__ */ jsx6("col", { style: { width: entry.width } }, entry.id)) }),
|
|
1826
|
+
/* @__PURE__ */ jsx6(
|
|
1247
1827
|
GridHeader,
|
|
1248
1828
|
{
|
|
1249
1829
|
columns: resolved,
|
|
@@ -1251,24 +1831,28 @@ function DataGridComponent({
|
|
|
1251
1831
|
drag,
|
|
1252
1832
|
sort: columnSort,
|
|
1253
1833
|
sortableColumns,
|
|
1834
|
+
grouping,
|
|
1835
|
+
groupableColumns,
|
|
1836
|
+
groupToggleIconColumns,
|
|
1254
1837
|
nav,
|
|
1255
1838
|
selection
|
|
1256
1839
|
}
|
|
1257
1840
|
),
|
|
1258
|
-
/* @__PURE__ */
|
|
1841
|
+
/* @__PURE__ */ jsx6(
|
|
1259
1842
|
GridBody,
|
|
1260
1843
|
{
|
|
1261
1844
|
columns: resolved,
|
|
1262
|
-
rows:
|
|
1845
|
+
rows: displayRows,
|
|
1263
1846
|
activeColumnId: resize.activeColumnId,
|
|
1264
1847
|
nav,
|
|
1265
|
-
selection
|
|
1848
|
+
selection,
|
|
1849
|
+
grouping
|
|
1266
1850
|
}
|
|
1267
1851
|
)
|
|
1268
1852
|
]
|
|
1269
1853
|
}
|
|
1270
1854
|
),
|
|
1271
|
-
/* @__PURE__ */
|
|
1855
|
+
/* @__PURE__ */ jsx6("div", { className: "gridkit-sr-only", role: "status", "aria-live": "polite", children: announcement })
|
|
1272
1856
|
] });
|
|
1273
1857
|
}
|
|
1274
1858
|
export {
|