@gridkitjs/react 0.4.0 → 0.5.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 +17 -2
- package/dist/index.js +159 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { RowSelectEvent, RowsSelectEvent, RowSelectionChangeEvent, CellSelectEvent as CellSelectEvent$1, CellSelectionChangeEvent as CellSelectionChangeEvent$1, ColumnDefinition as ColumnDefinition$1, ColumnSelectEvent as ColumnSelectEvent$1, ColumnSelectionChangeEvent as ColumnSelectionChangeEvent$1, ColumnsSelectEvent as ColumnsSelectEvent$1, SelectableConfig, SelectionState, CellSelectionState, ColumnSizingState, ColumnOrderState, ColumnSizeDefaults, ColumnResizeEvent, ColumnOrderEvent, ResolvedColumn as ResolvedColumn$1, SelectedCell as SelectedCell$1, SelectedColumn as SelectedColumn$1 } from '@gridkitjs/core';
|
|
3
|
+
import { RowSelectEvent, RowsSelectEvent, RowSelectionChangeEvent, CellSelectEvent as CellSelectEvent$1, CellSelectionChangeEvent as CellSelectionChangeEvent$1, ColumnDefinition as ColumnDefinition$1, ColumnSelectEvent as ColumnSelectEvent$1, ColumnSelectionChangeEvent as ColumnSelectionChangeEvent$1, ColumnsSelectEvent as ColumnsSelectEvent$1, SelectableConfig, SelectionState, CellSelectionState, ColumnSizingState, ColumnOrderState, ColumnSizeDefaults, ColumnResizeEvent, ColumnOrderEvent, ColumnSortState, ColumnSortEvent, FilterState, ResolvedColumn as ResolvedColumn$1, SelectedCell as SelectedCell$1, SelectedColumn as SelectedColumn$1 } from '@gridkitjs/core';
|
|
4
4
|
export { CellSelectionMode, CellSelectionState, CellTemplateContext, ColumnResizeEvent, ColumnSizeDefaults, ColumnSizingState, ResolvedRow, RowSelectEvent, RowSelectionChangeEvent, RowsSelectEvent, SelectableConfig, SelectedCellRef, SelectionMode, SelectionState } from '@gridkitjs/core';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -138,6 +138,21 @@ interface DataGridProps<Row> extends SelectionCallbacks<Row> {
|
|
|
138
138
|
* the order as it was does not call it.
|
|
139
139
|
*/
|
|
140
140
|
onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* Whether columns can be sorted by clicking their header toggle, unless a
|
|
143
|
+
* column says otherwise. Shift-click stacks a column into the sort instead
|
|
144
|
+
* of replacing it.
|
|
145
|
+
*/
|
|
146
|
+
sortableColumns?: boolean | undefined;
|
|
147
|
+
/** The sort to start with, in priority order. Uncontrolled. */
|
|
148
|
+
defaultColumnSort?: ColumnSortState | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Called once when the user changes the sort — a toggle, a stack, or a
|
|
151
|
+
* clear back to "none".
|
|
152
|
+
*/
|
|
153
|
+
onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;
|
|
154
|
+
/** The filter to start with — every applied entry, ANDed together. Uncontrolled. */
|
|
155
|
+
defaultFilter?: FilterState<Row> | undefined;
|
|
141
156
|
/**
|
|
142
157
|
* The grid's accessible name, announced when it takes focus. A grid without
|
|
143
158
|
* one is read only as "grid", which says nothing about which grid.
|
|
@@ -149,6 +164,6 @@ interface DataGridProps<Row> extends SelectionCallbacks<Row> {
|
|
|
149
164
|
*/
|
|
150
165
|
labelledBy?: string | undefined;
|
|
151
166
|
}
|
|
152
|
-
declare function DataGridComponent<Row>({ dataSource, columns, getRowId, borders, hoverable, selectable, defaultRowSelection, defaultColumnSelection, defaultCellSelection, resizableColumns, reorderableColumns, resizeMode, defaultColumnSizing, defaultColumnOrder, columnSizeDefaults, onColumnResize, onColumnOrderChange, label, labelledBy, ...callbacks }: DataGridProps<Row>): react.JSX.Element;
|
|
167
|
+
declare function DataGridComponent<Row>({ dataSource, columns, getRowId, borders, hoverable, selectable, defaultRowSelection, defaultColumnSelection, defaultCellSelection, resizableColumns, reorderableColumns, resizeMode, defaultColumnSizing, defaultColumnOrder, columnSizeDefaults, onColumnResize, onColumnOrderChange, sortableColumns, defaultColumnSort, onColumnSortChange, defaultFilter, label, labelledBy, ...callbacks }: DataGridProps<Row>): react.JSX.Element;
|
|
153
168
|
|
|
154
169
|
export { type CellSelectEvent, type CellSelectionChangeEvent, type ColumnDefinition, type ColumnSelectEvent, type ColumnSelectionChangeEvent, type ColumnsSelectEvent, DataGridComponent, type DataGridProps, type ResizeMode, type ResolvedColumn, type SelectedCell, type SelectedColumn };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
moveColumnBefore,
|
|
8
8
|
resolveColumnWidths,
|
|
9
9
|
resolveRowId,
|
|
10
|
+
resolveShownRows,
|
|
10
11
|
totalColumnWidth
|
|
11
12
|
} from "@gridkitjs/core";
|
|
12
13
|
|
|
@@ -363,10 +364,45 @@ function useGridSelection({
|
|
|
363
364
|
|
|
364
365
|
// src/DataGrid/components/GridHeader.tsx
|
|
365
366
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
367
|
+
function ChevronsUpDownIcon() {
|
|
368
|
+
return /* @__PURE__ */ jsxs(
|
|
369
|
+
"svg",
|
|
370
|
+
{
|
|
371
|
+
viewBox: "0 0 24 24",
|
|
372
|
+
fill: "none",
|
|
373
|
+
stroke: "currentColor",
|
|
374
|
+
strokeWidth: 2,
|
|
375
|
+
strokeLinecap: "round",
|
|
376
|
+
strokeLinejoin: "round",
|
|
377
|
+
"aria-hidden": "true",
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ jsx("path", { d: "m7 15 5 5 5-5" }),
|
|
380
|
+
/* @__PURE__ */ jsx("path", { d: "m7 9 5-5 5 5" })
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
function ChevronUpIcon() {
|
|
386
|
+
return /* @__PURE__ */ jsx(
|
|
387
|
+
"svg",
|
|
388
|
+
{
|
|
389
|
+
viewBox: "0 0 24 24",
|
|
390
|
+
fill: "none",
|
|
391
|
+
stroke: "currentColor",
|
|
392
|
+
strokeWidth: 2,
|
|
393
|
+
strokeLinecap: "round",
|
|
394
|
+
strokeLinejoin: "round",
|
|
395
|
+
"aria-hidden": "true",
|
|
396
|
+
children: /* @__PURE__ */ jsx("path", { d: "m18 15-6-6-6 6" })
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
}
|
|
366
400
|
function GridHeader({
|
|
367
401
|
columns,
|
|
368
402
|
resize,
|
|
369
403
|
drag,
|
|
404
|
+
sort,
|
|
405
|
+
sortableColumns,
|
|
370
406
|
nav,
|
|
371
407
|
selection
|
|
372
408
|
}) {
|
|
@@ -380,9 +416,13 @@ function GridHeader({
|
|
|
380
416
|
const dropBefore = beforeId !== void 0 && beforeId === entry.id;
|
|
381
417
|
const dropAfter = beforeId === null && index === columns.length - 1;
|
|
382
418
|
const selected = selection.selectedColumnIds.has(entry.id);
|
|
419
|
+
const sortable = column.sortable ?? sortableColumns;
|
|
420
|
+
const sortDirection = sort.directionFor(entry.id);
|
|
421
|
+
const sortPriority = sort.priorityFor(entry.id);
|
|
383
422
|
const shortcuts = [
|
|
384
423
|
entry.reorderable ? "Control+ArrowLeft Control+ArrowRight" : "",
|
|
385
|
-
entry.resizable ? "Alt+ArrowLeft Alt+ArrowRight" : ""
|
|
424
|
+
entry.resizable ? "Alt+ArrowLeft Alt+ArrowRight" : "",
|
|
425
|
+
sortable ? "Alt+ArrowUp" : ""
|
|
386
426
|
].filter(Boolean).join(" ");
|
|
387
427
|
return /* @__PURE__ */ jsxs(
|
|
388
428
|
"th",
|
|
@@ -401,7 +441,7 @@ function GridHeader({
|
|
|
401
441
|
if (drag.justDragged()) {
|
|
402
442
|
return;
|
|
403
443
|
}
|
|
404
|
-
if (event.target instanceof Element && event.target.closest(".header-resize-handle") !== null) {
|
|
444
|
+
if (event.target instanceof Element && (event.target.closest(".header-resize-handle") !== null || event.target.closest(".header-sort-toggle") !== null)) {
|
|
405
445
|
return;
|
|
406
446
|
}
|
|
407
447
|
selection.selectColumn(entry.id, intentOf(event));
|
|
@@ -419,6 +459,11 @@ function GridHeader({
|
|
|
419
459
|
resize.nudge(entry, direction * KEYBOARD_STEP);
|
|
420
460
|
return;
|
|
421
461
|
}
|
|
462
|
+
if (event.key === "ArrowUp" && event.altKey && sortable) {
|
|
463
|
+
event.preventDefault();
|
|
464
|
+
sort.toggle(entry, { shiftKey: event.shiftKey });
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
422
467
|
if (event.key === " " || event.key === "Enter") {
|
|
423
468
|
event.preventDefault();
|
|
424
469
|
selection.selectColumn(
|
|
@@ -445,6 +490,9 @@ function GridHeader({
|
|
|
445
490
|
column.headerClassName ?? ""
|
|
446
491
|
].filter(Boolean).join(" "),
|
|
447
492
|
...shortcuts !== "" && { "aria-keyshortcuts": shortcuts },
|
|
493
|
+
...sortable && sortDirection !== null && {
|
|
494
|
+
"aria-sort": sortDirection === "asc" ? "ascending" : "descending"
|
|
495
|
+
},
|
|
448
496
|
...entry.reorderable && {
|
|
449
497
|
onPointerDown: (event) => {
|
|
450
498
|
drag.startDrag(entry, event);
|
|
@@ -452,6 +500,33 @@ function GridHeader({
|
|
|
452
500
|
},
|
|
453
501
|
children: [
|
|
454
502
|
entry.label,
|
|
503
|
+
sortable && /*
|
|
504
|
+
* A pointer affordance only, and hidden from assistive
|
|
505
|
+
* technology like the resize handle: the keyboard equivalent
|
|
506
|
+
* lives on the header itself, under Alt+ArrowUp (plain) /
|
|
507
|
+
* Alt+Shift+ArrowUp (stacking).
|
|
508
|
+
*/
|
|
509
|
+
/* @__PURE__ */ jsxs(
|
|
510
|
+
"span",
|
|
511
|
+
{
|
|
512
|
+
className: [
|
|
513
|
+
"header-sort-toggle",
|
|
514
|
+
sortDirection !== null ? `is-sorted-${sortDirection}` : ""
|
|
515
|
+
].filter(Boolean).join(" "),
|
|
516
|
+
"aria-hidden": "true",
|
|
517
|
+
tabIndex: -1,
|
|
518
|
+
onPointerDown: (event) => {
|
|
519
|
+
event.stopPropagation();
|
|
520
|
+
},
|
|
521
|
+
onClick: (event) => {
|
|
522
|
+
sort.toggle(entry, { shiftKey: event.shiftKey });
|
|
523
|
+
},
|
|
524
|
+
children: [
|
|
525
|
+
sortDirection === null ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronUpIcon, {}),
|
|
526
|
+
sortPriority !== null && sortPriority > 1 && /* @__PURE__ */ jsx("span", { className: "header-sort-priority", children: sortPriority })
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
),
|
|
455
530
|
entry.resizable && /*
|
|
456
531
|
* A pointer affordance only, and hidden from assistive
|
|
457
532
|
* technology accordingly: a focusable handle per column would
|
|
@@ -768,7 +843,7 @@ import {
|
|
|
768
843
|
// src/DataGrid/measureColumnContent.ts
|
|
769
844
|
function measureColumnContent(table, columnId) {
|
|
770
845
|
const cells = table.querySelectorAll(
|
|
771
|
-
`[data-gridkit-column="${CSS.escape(columnId)}"]`
|
|
846
|
+
`td[data-gridkit-column="${CSS.escape(columnId)}"]`
|
|
772
847
|
);
|
|
773
848
|
const range = document.createRange();
|
|
774
849
|
let widest = null;
|
|
@@ -828,16 +903,28 @@ function useColumnResize({
|
|
|
828
903
|
}
|
|
829
904
|
function end() {
|
|
830
905
|
stop();
|
|
831
|
-
|
|
906
|
+
if (width !== session.startWidth) {
|
|
907
|
+
commit(base, session.columnId, width, "end");
|
|
908
|
+
}
|
|
832
909
|
}
|
|
833
910
|
function cancel() {
|
|
834
911
|
stop();
|
|
835
|
-
setSizing(
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
912
|
+
setSizing((current) => {
|
|
913
|
+
const next = Object.fromEntries(
|
|
914
|
+
Object.entries(current).filter(
|
|
915
|
+
([columnId]) => columnId !== session.columnId
|
|
916
|
+
)
|
|
917
|
+
);
|
|
918
|
+
if (session.columnId in base) {
|
|
919
|
+
next[session.columnId] = base[session.columnId];
|
|
920
|
+
}
|
|
921
|
+
onColumnResize?.({
|
|
922
|
+
columnId: session.columnId,
|
|
923
|
+
width: session.startWidth,
|
|
924
|
+
sizing: next,
|
|
925
|
+
phase: "end"
|
|
926
|
+
});
|
|
927
|
+
return next;
|
|
841
928
|
});
|
|
842
929
|
}
|
|
843
930
|
function onKeyDown(keyEvent) {
|
|
@@ -883,6 +970,33 @@ function useColumnResize({
|
|
|
883
970
|
return { activeColumnId, startResize, sizeToContent, nudge };
|
|
884
971
|
}
|
|
885
972
|
|
|
973
|
+
// src/DataGrid/useColumnSort.ts
|
|
974
|
+
import {
|
|
975
|
+
sortDirectionFor,
|
|
976
|
+
sortPriorityFor,
|
|
977
|
+
toggleColumnSort
|
|
978
|
+
} from "@gridkitjs/core";
|
|
979
|
+
function useColumnSort({
|
|
980
|
+
sort,
|
|
981
|
+
setSort,
|
|
982
|
+
onColumnSortChange
|
|
983
|
+
}) {
|
|
984
|
+
function toggle(entry, event) {
|
|
985
|
+
const next = toggleColumnSort(sort, entry.id, { stack: event.shiftKey });
|
|
986
|
+
if (next === sort) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
setSort(next);
|
|
990
|
+
onColumnSortChange?.({ columnId: entry.id, sort: next });
|
|
991
|
+
}
|
|
992
|
+
return {
|
|
993
|
+
sort,
|
|
994
|
+
directionFor: (columnId) => sortDirectionFor(sort, columnId),
|
|
995
|
+
priorityFor: (columnId) => sortPriorityFor(sort, columnId),
|
|
996
|
+
toggle
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
|
|
886
1000
|
// src/DataGrid/useElementWidth.ts
|
|
887
1001
|
import { useLayoutEffect, useState as useState4 } from "react";
|
|
888
1002
|
function useElementWidth(ref, enabled) {
|
|
@@ -924,6 +1038,10 @@ function DataGridComponent({
|
|
|
924
1038
|
columnSizeDefaults,
|
|
925
1039
|
onColumnResize,
|
|
926
1040
|
onColumnOrderChange,
|
|
1041
|
+
sortableColumns = false,
|
|
1042
|
+
defaultColumnSort,
|
|
1043
|
+
onColumnSortChange,
|
|
1044
|
+
defaultFilter,
|
|
927
1045
|
label,
|
|
928
1046
|
labelledBy,
|
|
929
1047
|
...callbacks
|
|
@@ -940,6 +1058,8 @@ function DataGridComponent({
|
|
|
940
1058
|
const [order, setOrder] = useState5(
|
|
941
1059
|
defaultColumnOrder ?? []
|
|
942
1060
|
);
|
|
1061
|
+
const [sort, setSort] = useState5(defaultColumnSort ?? []);
|
|
1062
|
+
const [filter] = useState5(defaultFilter ?? []);
|
|
943
1063
|
const [announcement, setAnnouncement] = useState5("");
|
|
944
1064
|
const [rowSelection, setRowSelection] = useState5(
|
|
945
1065
|
defaultRowSelection ?? []
|
|
@@ -984,6 +1104,10 @@ function DataGridComponent({
|
|
|
984
1104
|
resizableColumns,
|
|
985
1105
|
reorderableColumns
|
|
986
1106
|
]);
|
|
1107
|
+
const shownRows = useMemo2(
|
|
1108
|
+
() => resolveShownRows(rows, filter, sort, resolved),
|
|
1109
|
+
[rows, filter, sort, resolved]
|
|
1110
|
+
);
|
|
987
1111
|
function columnName(columnId) {
|
|
988
1112
|
const entry = resolved.find((candidate) => candidate.id === columnId);
|
|
989
1113
|
if (entry === void 0) {
|
|
@@ -1011,7 +1135,7 @@ function DataGridComponent({
|
|
|
1011
1135
|
});
|
|
1012
1136
|
const nav = useGridNavigation({
|
|
1013
1137
|
tableRef,
|
|
1014
|
-
rowCount:
|
|
1138
|
+
rowCount: shownRows.length,
|
|
1015
1139
|
columnCount: resolved.length
|
|
1016
1140
|
});
|
|
1017
1141
|
const displayedIds = useMemo2(
|
|
@@ -1032,8 +1156,27 @@ function DataGridComponent({
|
|
|
1032
1156
|
nav.focusCell(HEADER_ROW, position);
|
|
1033
1157
|
}
|
|
1034
1158
|
const drag = useColumnDrag({ order: displayedIds, onDrop: handleDrop });
|
|
1159
|
+
function handleColumnSortChange(event) {
|
|
1160
|
+
onColumnSortChange?.(event);
|
|
1161
|
+
const entry = event.sort.find(
|
|
1162
|
+
(candidate) => candidate.columnId === event.columnId
|
|
1163
|
+
);
|
|
1164
|
+
if (entry === void 0) {
|
|
1165
|
+
announce(`${columnName(event.columnId)}, sort cleared`);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
const direction = entry.direction === "asc" ? "ascending" : "descending";
|
|
1169
|
+
announce(
|
|
1170
|
+
event.sort.length > 1 ? `${columnName(event.columnId)} sorted ${direction}, key ${String(event.sort.indexOf(entry) + 1)} of ${String(event.sort.length)}` : `${columnName(event.columnId)} sorted ${direction}`
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
const columnSort = useColumnSort({
|
|
1174
|
+
sort,
|
|
1175
|
+
setSort,
|
|
1176
|
+
onColumnSortChange: handleColumnSortChange
|
|
1177
|
+
});
|
|
1035
1178
|
const selection = useGridSelection({
|
|
1036
|
-
rows,
|
|
1179
|
+
rows: shownRows,
|
|
1037
1180
|
columns: resolved,
|
|
1038
1181
|
selectable,
|
|
1039
1182
|
rowSelection,
|
|
@@ -1052,7 +1195,7 @@ function DataGridComponent({
|
|
|
1052
1195
|
{
|
|
1053
1196
|
ref: tableRef,
|
|
1054
1197
|
role: "grid",
|
|
1055
|
-
"aria-rowcount":
|
|
1198
|
+
"aria-rowcount": shownRows.length + 1,
|
|
1056
1199
|
"aria-colcount": resolved.length,
|
|
1057
1200
|
...multiselectable && { "aria-multiselectable": true },
|
|
1058
1201
|
...labelledBy !== void 0 && { "aria-labelledby": labelledBy },
|
|
@@ -1092,6 +1235,8 @@ function DataGridComponent({
|
|
|
1092
1235
|
columns: resolved,
|
|
1093
1236
|
resize,
|
|
1094
1237
|
drag,
|
|
1238
|
+
sort: columnSort,
|
|
1239
|
+
sortableColumns,
|
|
1095
1240
|
nav,
|
|
1096
1241
|
selection
|
|
1097
1242
|
}
|
|
@@ -1100,7 +1245,7 @@ function DataGridComponent({
|
|
|
1100
1245
|
GridBody,
|
|
1101
1246
|
{
|
|
1102
1247
|
columns: resolved,
|
|
1103
|
-
rows,
|
|
1248
|
+
rows: shownRows,
|
|
1104
1249
|
activeColumnId: resize.activeColumnId,
|
|
1105
1250
|
nav,
|
|
1106
1251
|
selection
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/useGridNavigation.ts","../src/DataGrid/useGridSelection.ts","../src/DataGrid/components/GridRow.tsx","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/useColumnDrag.ts","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useElementWidth.ts"],"sourcesContent":["import { useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n applyColumnOrder,\n defineColumnsFromRows,\n fitColumnsToWidth,\n moveColumnBefore,\n resolveColumnWidths,\n resolveRowId,\n totalColumnWidth,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type ColumnOrderEvent,\n type ColumnOrderState,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n type ResolvedRow,\n type CellSelectionState,\n type SelectableConfig,\n type SelectedCell as CoreSelectedCell,\n type SelectedColumn as CoreSelectedColumn,\n type SelectionState,\n type CellSelectEvent as CoreCellSelectEvent,\n type CellSelectionChangeEvent as CoreCellSelectionChangeEvent,\n type ColumnSelectEvent as CoreColumnSelectEvent,\n type ColumnSelectionChangeEvent as CoreColumnSelectionChangeEvent,\n type ColumnsSelectEvent as CoreColumnsSelectEvent,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport useColumnDrag, { type DropTarget } from \"./useColumnDrag\";\nimport useColumnResize from \"./useColumnResize\";\nimport useElementWidth from \"./useElementWidth\";\nimport useGridNavigation, { HEADER_ROW } from \"./useGridNavigation\";\nimport useGridSelection, { type SelectionCallbacks } from \"./useGridSelection\";\n\n/**\n * A column whose header and cells may render arbitrary React content.\n * @gridkitjs/core stays framework-agnostic and so leaves that output type open;\n * this is the binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\n/**\n * The selection payloads, bound to React's node type for the same reason\n * `ColumnDefinition` is: they carry a resolved column, whose label is whatever\n * a `headerTemplate` returned.\n *\n * The row payloads name no node type at all and so are re-exported from\n * `@gridkitjs/core` as they are.\n */\nexport type SelectedColumn<Row> = CoreSelectedColumn<Row, ReactNode>;\nexport type SelectedCell<Row> = CoreSelectedCell<Row, ReactNode>;\nexport type ColumnSelectEvent<Row> = CoreColumnSelectEvent<Row, ReactNode>;\nexport type ColumnsSelectEvent<Row> = CoreColumnsSelectEvent<Row, ReactNode>;\nexport type ColumnSelectionChangeEvent<Row> = CoreColumnSelectionChangeEvent<\n Row,\n ReactNode\n>;\nexport type CellSelectEvent<Row> = CoreCellSelectEvent<Row, ReactNode>;\nexport type CellSelectionChangeEvent<Row> = CoreCellSelectionChangeEvent<\n Row,\n ReactNode\n>;\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\nexport interface DataGridProps<Row> extends SelectionCallbacks<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n /**\n * A row's stable identity, for state keyed by it. Defaults to the row's\n * position, which is enough for a static grid but ties that state to where a\n * row sits rather than to the row — so anything sorting, filtering or paging\n * its data should give one.\n *\n * Called for every row on every change to `dataSource`, so it should be\n * cheap and stable; an inline arrow is fine, one that re-reads the data is\n * not.\n */\n getRowId?: ((row: Row, index: number) => string) | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /**\n * Which parts of the grid the user may select, and how many of each —\n * `{ rows: \"multiple\", cells: \"single\" }`. A cell addresses one value, so it\n * has no `\"multiple\"`.\n *\n * Off by default, unlike `hoverable`: selection claims the click, which a\n * grid that only displays data should not do. Give `getRowId` alongside it\n * for data that sorts, filters or pages, or a selection follows the position\n * rather than the row.\n */\n selectable?: SelectableConfig | undefined;\n /** Row ids selected to start with, keyed as `getRowId` resolves them. Uncontrolled. */\n defaultRowSelection?: SelectionState | undefined;\n /** Column ids selected to start with. Uncontrolled. */\n defaultColumnSelection?: SelectionState | undefined;\n /** The cell selected to start with. Uncontrolled. */\n defaultCellSelection?: CellSelectionState | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns can be dragged into a new position, unless a column says\n * otherwise. Turning it off leaves an order the user already made in place.\n */\n reorderableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Column ids in the order to start in. Uncontrolled, and partial: ids it\n * omits keep their position among `columns` and follow those it lists.\n */\n defaultColumnOrder?: ColumnOrderState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n /**\n * Called once when the user drops a column somewhere new. A drop that leaves\n * the order as it was does not call it.\n */\n onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;\n /**\n * The grid's accessible name, announced when it takes focus. A grid without\n * one is read only as \"grid\", which says nothing about which grid.\n */\n label?: string | undefined;\n /**\n * The id of an element naming the grid, for a heading already on the page.\n * Takes precedence over `label`, as `aria-labelledby` does.\n */\n labelledBy?: string | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n getRowId,\n borders,\n hoverable,\n selectable,\n defaultRowSelection,\n defaultColumnSelection,\n defaultCellSelection,\n resizableColumns = false,\n reorderableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n defaultColumnOrder,\n columnSizeDefaults,\n onColumnResize,\n onColumnOrderChange,\n label,\n labelledBy,\n ...callbacks\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n const [order, setOrder] = useState<ColumnOrderState>(\n defaultColumnOrder ?? [],\n );\n const [announcement, setAnnouncement] = useState(\"\");\n const [rowSelection, setRowSelection] = useState<SelectionState>(\n defaultRowSelection ?? [],\n );\n const [columnSelection, setColumnSelection] = useState<SelectionState>(\n defaultColumnSelection ?? [],\n );\n const [cellSelection, setCellSelection] = useState<CellSelectionState>(\n defaultCellSelection ?? null,\n );\n\n /**\n * The rows as rendered, each carrying the id everything downstream keys it\n * by. Resolved once here rather than per consumer so a row's id cannot come\n * out differently in two places — the same reason `resolveColumnWidths` runs\n * once ahead of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\n const rows = useMemo<readonly ResolvedRow<Row>[]>(\n () =>\n dataSource?.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n })) ?? [],\n [dataSource, getRowId],\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Ahead of sizing, so everything downstream reads one already-ordered list\n * and no part of the grid has to know a reorder happened.\n */\n const orderedColumns = useMemo(\n () => applyColumnOrder(definedColumns, order),\n [definedColumns, order],\n );\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(orderedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n reorderable: reorderableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n orderedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n reorderableColumns,\n ]);\n\n /**\n * What a column is called in an announcement. `label` carries whatever a\n * `headerTemplate` returned, which need not be text at all, so the field\n * path stands in whenever it is not.\n */\n function columnName(columnId: string): string {\n const entry = resolved.find((candidate) => candidate.id === columnId);\n if (entry === undefined) {\n return columnId;\n }\n return typeof entry.label === \"string\" ? entry.label : entry.column.field;\n }\n\n /**\n * Reports a change no visual cue can carry to a screen reader. Held as state\n * rather than written to the DOM directly so React owns the one element the\n * live region watches.\n */\n function announce(message: string): void {\n setAnnouncement(message);\n }\n\n /**\n * Wrapped rather than announced from the resize hook, which reports the\n * continuous `\"move\"` phase as well — a live region given every frame of a\n * drag says nothing an assistive technology can keep up with.\n */\n function handleColumnResize(event: ColumnResizeEvent): void {\n onColumnResize?.(event);\n if (event.phase === \"end\") {\n announce(\n `${columnName(event.columnId)}, ${String(Math.round(event.width))} pixels wide`,\n );\n }\n }\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize: handleColumnResize,\n });\n\n const nav = useGridNavigation({\n tableRef,\n rowCount: rows.length,\n columnCount: resolved.length,\n });\n\n /**\n * The ids as displayed, which a drop is expressed against — the order state\n * starts empty and may name only some columns, so moving against it directly\n * would have nothing to rearrange.\n */\n const displayedIds = useMemo(\n () => orderedColumns.map((column) => column.id ?? column.field),\n [orderedColumns],\n );\n\n /**\n * The one place a drop is applied. A second drop zone — a grouping bar above\n * the header — turns this into a switch on `target.kind` and touches nothing\n * else.\n */\n function handleDrop(target: DropTarget, movedId: string): void {\n const next = moveColumnBefore(displayedIds, movedId, target.beforeId);\n // `moveColumnBefore` hands back the same reference for a move that changes\n // nothing, so a drop in place neither renders nor reports.\n if (next === displayedIds) {\n return;\n }\n const position = next.indexOf(movedId);\n setOrder(next);\n onColumnOrderChange?.({ columnId: movedId, order: next });\n announce(\n `${columnName(movedId)}, column ${String(position + 1)} of ${String(next.length)}`,\n );\n /**\n * The tab stop travels with the column. React reorders the headers by key,\n * so the browser's focus stays on the moved one by itself — without this\n * the stop would be left on whichever column took its index, and the next\n * arrow key would appear to do nothing.\n */\n nav.focusCell(HEADER_ROW, position);\n }\n\n const drag = useColumnDrag<Row>({ order: displayedIds, onDrop: handleDrop });\n\n const selection = useGridSelection<Row>({\n rows,\n columns: resolved,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n });\n\n const multiselectable =\n selection.rowMode === \"multiple\" || selection.columnMode === \"multiple\";\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n <table\n ref={tableRef}\n /*\n * `role=\"grid\"` rather than the table's own semantics: it is what makes\n * the arrow keys a navigation the grid owns, and later what lets a row\n * report whether it is selected. It obliges the single tab stop\n * `useGridNavigation` keeps.\n */\n role=\"grid\"\n // The header is a row too, and counted from one.\n aria-rowcount={rows.length + 1}\n aria-colcount={resolved.length}\n {...(multiselectable && { \"aria-multiselectable\": true })}\n {...(labelledBy !== undefined && { \"aria-labelledby\": labelledBy })}\n {...(labelledBy === undefined &&\n label !== undefined && { \"aria-label\": label })}\n onKeyDown={(event) => {\n /*\n * The two keys that address the grid rather than a cell, and so are\n * caught here where everything bubbles to rather than in each of\n * them.\n */\n if (event.key === \"Escape\") {\n // A gesture in flight has its own use for Escape — cancelling —\n // and gets it first.\n if (drag.draggedColumnId !== null || resize.activeColumnId !== null)\n return;\n selection.clear();\n return;\n }\n if (\n (event.ctrlKey || event.metaKey) &&\n (event.key === \"a\" || event.key === \"A\")\n ) {\n // Left to the browser unless the grid has something to do with it,\n // so a grid without multiple rows does not swallow select-all.\n if (selection.rowMode !== \"multiple\") return;\n event.preventDefault();\n selection.selectAllRows();\n }\n }}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={[\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n // Hover is on by default and selection off, so one set of classes\n // turns styling off and the other turns it on. The polarity differs\n // because the defaults do.\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n selection.rowMode === false ? \"\" : \"selectable-rows\",\n selection.columnMode === false ? \"\" : \"selectable-columns\",\n selection.cellMode === false ? \"\" : \"selectable-cells\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row>\n columns={resolved}\n resize={resize}\n drag={drag}\n nav={nav}\n selection={selection}\n />\n <GridBody<Row>\n columns={resolved}\n rows={rows}\n activeColumnId={resize.activeColumnId}\n nav={nav}\n selection={selection}\n />\n </table>\n {/*\n * Outside the table, which admits no `div`, and polite so it waits for a\n * pause rather than cutting across what the user is already hearing.\n */}\n <div className=\"gridkit-sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </div>\n </div>\n );\n}\n","import { createPortal } from \"react-dom\";\nimport { KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { ColumnDragApi } from \"../useColumnDrag\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\nimport { HEADER_ROW, type GridNavigationApi } from \"../useGridNavigation\";\nimport { intentOf, type GridSelectionApi } from \"../useGridSelection\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n drag: ColumnDragApi<Row>;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n drag,\n nav,\n selection,\n}: GridHeaderProps<Row>) {\n const { beforeId } = drag.dropTarget ?? {};\n const draggedEntry =\n columns.find((entry) => entry.id === drag.draggedColumnId) ?? null;\n\n return (\n <thead>\n <tr className=\"grid-header\" role=\"row\" aria-rowindex={1}>\n {columns.map((entry, index) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n const dragging = drag.draggedColumnId === entry.id;\n\n /**\n * Drawn on the gap's own edge, so the one gap between two columns is\n * marked once. No guard against the dragged column: the hook reports\n * only gaps that would move it.\n */\n const dropBefore = beforeId !== undefined && beforeId === entry.id;\n const dropAfter = beforeId === null && index === columns.length - 1;\n const selected = selection.selectedColumnIds.has(entry.id);\n\n /**\n * Announced so the keys are discoverable, since neither is a\n * convention a user would try unprompted.\n */\n const shortcuts = [\n entry.reorderable ? \"Control+ArrowLeft Control+ArrowRight\" : \"\",\n entry.resizable ? \"Alt+ArrowLeft Alt+ArrowRight\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <th\n key={entry.id}\n scope=\"col\"\n data-gridkit-column={entry.id}\n aria-colindex={index + 1}\n tabIndex={nav.tabIndexFor(HEADER_ROW, index)}\n {...(selection.columnMode !== false && {\n \"aria-selected\": selected,\n })}\n onFocus={() => {\n nav.focusCell(HEADER_ROW, index);\n }}\n onClick={(event) => {\n /*\n * A drag ends in a click on the header it started from, and a\n * resize in one on the handle inside it. Neither is the press\n * that selects a column, so both are shown the door here —\n * the drag by the distance it travelled, the resize by where\n * it began.\n */\n if (drag.justDragged()) {\n return;\n }\n if (\n event.target instanceof Element &&\n event.target.closest(\".header-resize-handle\") !== null\n ) {\n return;\n }\n selection.selectColumn(entry.id, intentOf(event));\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n const direction = event.key === \"ArrowLeft\" ? -1 : 1;\n\n if (horizontal && event.ctrlKey && entry.reorderable) {\n event.preventDefault();\n drag.moveByKeyboard(entry, direction);\n return;\n }\n if (horizontal && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.nudge(entry, direction * KEYBOARD_STEP);\n return;\n }\n // Space builds a selection up and Enter replaces it, as in the\n // body. Taken either way, or Space scrolls the grid away.\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n selection.selectColumn(\n entry.id,\n intentOf({\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n }),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n className={[\n \"header-cell\",\n entry.reorderable ? \"is-reorderable\" : \"\",\n selected ? \"is-selected\" : \"\",\n resizing ? \"is-resizing\" : \"\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n column.wrap?.header ? \"is-wrapped\" : \"\",\n column.headerClassName ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n {...(shortcuts !== \"\" && { \"aria-keyshortcuts\": shortcuts })}\n {...(entry.reorderable && {\n onPointerDown: (event) => {\n drag.startDrag(entry, event);\n },\n })}\n >\n {entry.label}\n {entry.resizable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology accordingly: a focusable handle per column would\n * put N tab stops inside a widget that is meant to have one.\n * The keyboard resizes from the header itself, under Alt.\n */\n <span\n className=\"header-resize-handle\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n />\n )}\n </th>\n );\n })}\n </tr>\n {/*\n * Portalled to the body, and not only because a `div` cannot sit in a\n * `tr`: inside the viewport the overflow that makes the grid scroll\n * would clip it.\n */}\n {draggedEntry !== null &&\n drag.ghostTransform !== null &&\n createPortal(\n <div\n className=\"gridkit-data-grid header-cell drag-ghost\"\n style={{\n width: draggedEntry.width,\n transform: drag.ghostTransform,\n }}\n aria-hidden=\"true\"\n >\n {draggedEntry.label}\n </div>,\n document.body,\n )}\n </thead>\n );\n}\n","import {\n useEffect,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\n\n/**\n * The header's row index. One coordinate space covers the header and the body\n * so that arrowing up out of the first row reaches the header without a case\n * of its own, and every other move is plain arithmetic.\n */\nexport const HEADER_ROW = -1;\n\n/** Rows a page key moves when the viewport cannot be measured. */\nconst FALLBACK_PAGE = 10;\n\n/** The cell the grid's single tab stop sits on. */\nexport interface GridFocus {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\ninterface UseGridNavigationOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n rowCount: number;\n columnCount: number;\n}\n\nexport interface GridNavigationApi {\n focus: GridFocus;\n /**\n * `0` for the focused cell and `-1` for every other. A grid is one tab stop:\n * tabbing reaches it, and the arrow keys move within it.\n */\n tabIndexFor: (rowIndex: number, columnIndex: number) => 0 | -1;\n /** Moves the tab stop, and the browser's focus with it. */\n focusCell: (rowIndex: number, columnIndex: number) => void;\n /** Handles the navigation keys, leaving every other key to bubble. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n}\n\n/**\n * Holds a coordinate inside the grid, so that a focus surviving a column\n * removal or a shorter page never leaves the grid with no tab stop at all —\n * which is a grid a keyboard cannot reach.\n */\nfunction clampFocus(\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n): GridFocus {\n return {\n rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),\n columnIndex: Math.min(\n Math.max(focus.columnIndex, 0),\n Math.max(columnCount - 1, 0),\n ),\n };\n}\n\n/**\n * The cell at a coordinate, found through the table's own row and cell\n * collections rather than a selector.\n *\n * Ids can hold anything a consumer's data holds, and an attribute selector\n * built from one would have to escape it; positions need no quoting.\n */\nfunction cellAt(table: HTMLTableElement, focus: GridFocus): HTMLElement | null {\n const row =\n focus.rowIndex === HEADER_ROW\n ? (table.tHead?.rows[0] ?? null)\n : (table.tBodies[0]?.rows[focus.rowIndex] ?? null);\n return row?.cells[focus.columnIndex] ?? null;\n}\n\n/**\n * Moves one tab stop around the grid, which is what `role=\"grid\"` obliges:\n * arrow keys travel cell to cell and Tab passes the whole grid by.\n *\n * Separate from selection because focus and selection are different states — a\n * cell is focused while travelling before anything is selected, and every cell\n * of a range is selected without being focused. Navigation also has to work\n * with selection turned off entirely, so it cannot depend on it.\n */\nexport default function useGridNavigation({\n tableRef,\n rowCount,\n columnCount,\n}: UseGridNavigationOptions): GridNavigationApi {\n const [stored, setStored] = useState<GridFocus>({\n rowIndex: HEADER_ROW,\n columnIndex: 0,\n });\n\n /**\n * Clamped on the way out rather than written back, so that a coordinate\n * pushed out of range by a change to the data is restored when the data\n * comes back — and so the effect below cannot chase its own output.\n */\n const focus = clampFocus(stored, rowCount, columnCount);\n\n /**\n * Whether the browser's focus still has to be moved to match. Without it\n * every render would pull focus into the grid, including the first.\n */\n const pending = useRef(false);\n\n useEffect(() => {\n if (!pending.current) {\n return;\n }\n pending.current = false;\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n cellAt(table, { rowIndex: focus.rowIndex, columnIndex: focus.columnIndex })\n // Focusing the cell the browser already sits on is a no-op, which is what\n // makes one method serve both a key press and a cell reporting a click.\n ?.focus();\n }, [tableRef, focus.rowIndex, focus.columnIndex]);\n\n /** How many rows fit the viewport, which is what a page key should move. */\n function pageSize(): number {\n const table = tableRef.current;\n const firstRow = table?.tBodies[0]?.rows[0];\n const viewport = table?.parentElement;\n if (\n firstRow === undefined ||\n viewport === null ||\n viewport === undefined ||\n firstRow.offsetHeight === 0\n ) {\n return FALLBACK_PAGE;\n }\n return Math.max(\n 1,\n Math.floor(viewport.clientHeight / firstRow.offsetHeight),\n );\n }\n\n function focusCell(rowIndex: number, columnIndex: number): void {\n const next = clampFocus({ rowIndex, columnIndex }, rowCount, columnCount);\n if (\n next.rowIndex === focus.rowIndex &&\n next.columnIndex === focus.columnIndex\n ) {\n return;\n }\n pending.current = true;\n setStored(next);\n }\n\n function tabIndexFor(rowIndex: number, columnIndex: number): 0 | -1 {\n return rowIndex === focus.rowIndex && columnIndex === focus.columnIndex\n ? 0\n : -1;\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLElement>): void {\n // Alt on an arrow resizes and Ctrl on one reorders; the header claims both\n // before this runs, and elsewhere they belong to the browser.\n if (event.altKey) {\n return;\n }\n\n const { rowIndex, columnIndex } = focus;\n let next: GridFocus;\n\n switch (event.key) {\n case \"ArrowLeft\":\n if (event.ctrlKey) return;\n next = { rowIndex, columnIndex: columnIndex - 1 };\n break;\n case \"ArrowRight\":\n if (event.ctrlKey) return;\n next = { rowIndex, columnIndex: columnIndex + 1 };\n break;\n case \"ArrowUp\":\n next = { rowIndex: rowIndex - 1, columnIndex };\n break;\n case \"ArrowDown\":\n next = { rowIndex: rowIndex + 1, columnIndex };\n break;\n // Ctrl takes Home and End to the grid's ends rather than the row's, which\n // is the one place Ctrl is navigation rather than reorder.\n case \"Home\":\n next = event.ctrlKey\n ? { rowIndex: HEADER_ROW, columnIndex: 0 }\n : { rowIndex, columnIndex: 0 };\n break;\n case \"End\":\n next = event.ctrlKey\n ? { rowIndex: rowCount - 1, columnIndex: columnCount - 1 }\n : { rowIndex, columnIndex: columnCount - 1 };\n break;\n case \"PageUp\":\n next = { rowIndex: rowIndex - pageSize(), columnIndex };\n break;\n case \"PageDown\":\n next = { rowIndex: rowIndex + pageSize(), columnIndex };\n break;\n default:\n return;\n }\n\n // Taken even when the move lands nowhere: an arrow at the last row would\n // otherwise scroll the page out from under the grid.\n event.preventDefault();\n focusCell(next.rowIndex, next.columnIndex);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the focus they move from.\n return { focus, tabIndexFor, focusCell, onKeyDown };\n}\n","import { useMemo, useRef, type Dispatch, type SetStateAction } from \"react\";\nimport {\n accessDotted,\n clearSelection,\n diffSelection,\n selectAll,\n selectCell,\n selectOnly,\n selectRange,\n toggleCellSelection,\n toggleSelection,\n type CellSelectionMode,\n type CellSelectionState,\n type ResolvedRow,\n type SelectableConfig,\n type SelectedCellRef,\n type SelectionMode,\n type SelectionState,\n type RowSelectEvent,\n type RowSelectionChangeEvent,\n type RowsSelectEvent,\n} from \"@gridkitjs/core\";\nimport type {\n CellSelectEvent,\n CellSelectionChangeEvent,\n ColumnSelectEvent,\n ColumnSelectionChangeEvent,\n ColumnsSelectEvent,\n ResolvedColumn,\n SelectedCell,\n SelectedColumn,\n} from \"./DataGrid\";\n\n/**\n * What an interaction means for the selection, read off its modifiers once at\n * the boundary so that nothing downstream handles a raw event.\n */\nexport type SelectIntent = \"replace\" | \"toggle\" | \"range\";\n\n/** The intent a click or key press carries, by the modifiers held with it. */\nexport function intentOf(event: {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n}): SelectIntent {\n if (event.shiftKey) {\n return \"range\";\n }\n // Cmd on a Mac is Ctrl everywhere else, and both mean the same thing here.\n return event.ctrlKey || event.metaKey ? \"toggle\" : \"replace\";\n}\n\n/**\n * Reported as the user selects. Every one of these is fanned out from a single\n * diff of the transition it describes, so no two can disagree about what one\n * interaction did.\n */\nexport interface SelectionCallbacks<Row> {\n /** Called once per row newly selected. The last call names the last row. */\n onRowSelect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n /** Called once with every row one interaction selected. */\n onRowsSelect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n onRowDeselect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n onRowsDeselect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n /**\n * Called once per change with what it added, what it removed and everything\n * selected after it — the one to persist from.\n */\n onRowSelectionChange?:\n ((event: RowSelectionChangeEvent<Row>) => void) | undefined;\n onColumnSelect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsSelect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnDeselect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsDeselect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnSelectionChange?:\n ((event: ColumnSelectionChangeEvent<Row>) => void) | undefined;\n onCellSelect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellDeselect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellSelectionChange?:\n ((event: CellSelectionChangeEvent<Row>) => void) | undefined;\n}\n\ninterface UseGridSelectionOptions<Row> {\n rows: readonly ResolvedRow<Row>[];\n columns: readonly ResolvedColumn<Row>[];\n selectable: SelectableConfig | undefined;\n rowSelection: SelectionState;\n setRowSelection: Dispatch<SetStateAction<SelectionState>>;\n columnSelection: SelectionState;\n setColumnSelection: Dispatch<SetStateAction<SelectionState>>;\n cellSelection: CellSelectionState;\n setCellSelection: Dispatch<SetStateAction<CellSelectionState>>;\n callbacks: SelectionCallbacks<Row>;\n announce: (message: string) => void;\n}\n\nexport interface GridSelectionApi {\n rowMode: SelectionMode;\n columnMode: SelectionMode;\n cellMode: CellSelectionMode;\n /**\n * Lookups for the render pass. The state itself stays an ordered list, which\n * is what makes the most recent selection its last entry.\n */\n selectedRowIds: ReadonlySet<string>;\n selectedColumnIds: ReadonlySet<string>;\n selectedCell: CellSelectionState;\n selectRow: (rowId: string, intent: SelectIntent) => void;\n selectColumn: (columnId: string, intent: SelectIntent) => void;\n selectCell: (cell: SelectedCellRef, intent: SelectIntent) => void;\n selectAllRows: () => void;\n /** Lets go of every selection at once, as Escape does. */\n clear: () => void;\n}\n\n/**\n * The transform an intent asks for. A function rather than a branch inside\n * each caller, so a row and a column cannot come to mean different things by\n * the same click.\n */\nfunction applyIntent(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string | null,\n id: string,\n intent: SelectIntent,\n mode: SelectionMode,\n): SelectionState {\n switch (intent) {\n case \"toggle\":\n return toggleSelection(selection, id, mode);\n // A range with no anchor yet spans from the id to itself, which is the\n // plain click a first Shift-click may as well be.\n case \"range\":\n return selectRange(selection, orderedIds, anchorId ?? id, id, mode);\n default:\n return selectOnly(selection, id, mode);\n }\n}\n\nfunction countMessage(count: number, noun: string): string {\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1\n ? `1 ${noun} selected`\n : `${String(count)} ${noun}s selected`;\n}\n\n/**\n * Turns an intent against a row, column or cell into the selection it implies,\n * and reports what changed.\n *\n * Holds no state of its own: the three selections live in `DataGrid` beside\n * the sizing and the order, so that a ref exposing them later, or a feature\n * reading them, finds them in one place.\n */\nexport default function useGridSelection<Row>({\n rows,\n columns,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n}: UseGridSelectionOptions<Row>): GridSelectionApi {\n const rowMode = selectable?.rows ?? false;\n const columnMode = selectable?.columns ?? false;\n const cellMode = selectable?.cells ?? false;\n\n const rowsById = useMemo(\n () => new Map(rows.map((entry) => [entry.rowId, entry])),\n [rows],\n );\n const rowIds = useMemo(() => rows.map((entry) => entry.rowId), [rows]);\n const columnIds = useMemo(() => columns.map((entry) => entry.id), [columns]);\n\n const selectedRowIds = useMemo(() => new Set(rowSelection), [rowSelection]);\n const selectedColumnIds = useMemo(\n () => new Set(columnSelection),\n [columnSelection],\n );\n\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n const rowAnchor = useRef<string | null>(null);\n const columnAnchor = useRef<string | null>(null);\n\n /**\n * Ids with no row behind them are dropped rather than reported: a selection\n * outlives a change to the data, so that filtering a row out and back leaves\n * it selected, and only what is on screen can be handed to a callback.\n */\n function resolveRows(ids: readonly string[]): readonly ResolvedRow<Row>[] {\n return ids.map((id) => rowsById.get(id)).filter((row) => row !== undefined);\n }\n\n function resolveColumns(\n ids: readonly string[],\n ): readonly SelectedColumn<Row>[] {\n return ids\n .map((id) => {\n const columnIndex = columns.findIndex((entry) => entry.id === id);\n const column = columns[columnIndex];\n return column === undefined\n ? undefined\n : { columnId: id, column, columnIndex };\n })\n .filter((column) => column !== undefined);\n }\n\n function resolveCell(ref: CellSelectionState): SelectedCell<Row> | null {\n if (ref === null) {\n return null;\n }\n const entry = rowsById.get(ref.rowId);\n const columnIndex = columns.findIndex(\n (candidate) => candidate.id === ref.columnId,\n );\n const column = columns[columnIndex];\n if (entry === undefined || column === undefined) {\n return null;\n }\n return {\n rowId: ref.rowId,\n columnId: ref.columnId,\n row: entry.row,\n column,\n rowIndex: entry.rowIndex,\n columnIndex,\n value: accessDotted(entry.row, column.column.field),\n };\n }\n\n /**\n * Announced only for a change touching more than one member. A single\n * selection is already carried by the focused row's own `aria-selected`, and\n * repeating it here would talk over that.\n */\n function announceCount(changed: number, total: number, noun: string): void {\n if (changed > 1) {\n announce(countMessage(total, noun));\n }\n }\n\n function commitRows(next: SelectionState): void {\n // The unchanged-reference contract the core transforms keep: a click that\n // selects what was already selected neither renders nor reports.\n if (next === rowSelection) {\n return;\n }\n setRowSelection(next);\n\n const { added, removed } = diffSelection(rowSelection, next);\n const addedRows = resolveRows(added);\n const removedRows = resolveRows(removed);\n\n for (const row of addedRows) {\n callbacks.onRowSelect?.({ row, selection: next });\n }\n if (addedRows.length > 0) {\n callbacks.onRowsSelect?.({ rows: addedRows, selection: next });\n }\n for (const row of removedRows) {\n callbacks.onRowDeselect?.({ row, selection: next });\n }\n if (removedRows.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removedRows, selection: next });\n }\n callbacks.onRowSelectionChange?.({\n added: addedRows,\n removed: removedRows,\n selected: resolveRows(next),\n selection: next,\n });\n announceCount(added.length + removed.length, next.length, \"row\");\n }\n\n function commitColumns(next: SelectionState): void {\n if (next === columnSelection) {\n return;\n }\n setColumnSelection(next);\n\n const { added, removed } = diffSelection(columnSelection, next);\n const addedColumns = resolveColumns(added);\n const removedColumns = resolveColumns(removed);\n\n for (const column of addedColumns) {\n callbacks.onColumnSelect?.({ column, selection: next });\n }\n if (addedColumns.length > 0) {\n callbacks.onColumnsSelect?.({ columns: addedColumns, selection: next });\n }\n for (const column of removedColumns) {\n callbacks.onColumnDeselect?.({ column, selection: next });\n }\n if (removedColumns.length > 0) {\n callbacks.onColumnsDeselect?.({\n columns: removedColumns,\n selection: next,\n });\n }\n callbacks.onColumnSelectionChange?.({\n added: addedColumns,\n removed: removedColumns,\n selected: resolveColumns(next),\n selection: next,\n });\n announceCount(added.length + removed.length, next.length, \"column\");\n }\n\n function commitCell(next: CellSelectionState): void {\n if (next === cellSelection) {\n return;\n }\n setCellSelection(next);\n\n // Resolved before and after in one place, so that moving between two cells\n // reports the leaving and the arriving as one change.\n const selected = resolveCell(next);\n const deselected = resolveCell(cellSelection);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: next });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: next });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: next,\n });\n }\n\n function selectRow(rowId: string, intent: SelectIntent): void {\n const next = applyIntent(\n rowSelection,\n rowIds,\n rowAnchor.current,\n rowId,\n intent,\n rowMode,\n );\n if (intent !== \"range\") {\n rowAnchor.current = rowId;\n }\n commitRows(next);\n }\n\n function selectColumn(columnId: string, intent: SelectIntent): void {\n const next = applyIntent(\n columnSelection,\n columnIds,\n columnAnchor.current,\n columnId,\n intent,\n columnMode,\n );\n if (intent !== \"range\") {\n columnAnchor.current = columnId;\n }\n commitColumns(next);\n }\n\n function selectCellAt(cell: SelectedCellRef, intent: SelectIntent): void {\n // A cell holds one value, so a range over cells has nothing to span and\n // reads as the plain click it looks like.\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(cellSelection, cell, cellMode)\n : selectCell(cellSelection, cell, cellMode),\n );\n }\n\n function selectAllRows(): void {\n commitRows(selectAll(rowSelection, rowIds, rowMode));\n }\n\n function clear(): void {\n commitRows(clearSelection(rowSelection));\n commitColumns(clearSelection(columnSelection));\n commitCell(null);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the selections they transform.\n return {\n rowMode,\n columnMode,\n cellMode,\n selectedRowIds,\n selectedColumnIds,\n selectedCell: cellSelection,\n selectRow,\n selectColumn,\n selectCell: selectCellAt,\n selectAllRows,\n clear,\n };\n}\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { memo, type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\n\ninterface GridRowProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rowId: string;\n row: Row;\n rowIndex: number;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n selectedColumnIds: ReadonlySet<string>;\n selected: boolean;\n /** Which of this row's cells is the selected one, if any. */\n selectedColumnId: string | null;\n /** Which of this row's cells holds the grid's tab stop, if any. */\n focusedColumnIndex: number | null;\n rowsSelectable: boolean;\n cellsSelectable: boolean;\n}\n\nfunction GridRowComponent<Row>({\n columns,\n rowId,\n row,\n rowIndex,\n activeColumnId,\n selectedColumnIds,\n selected,\n selectedColumnId,\n focusedColumnIndex,\n rowsSelectable,\n cellsSelectable,\n}: GridRowProps<Row>) {\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them.\n aria-rowindex={rowIndex + 2}\n // Omitted rather than `false` when rows cannot be selected, which would\n // otherwise have every row announce that it is not.\n {...(rowsSelectable && { \"aria-selected\": selected })}\n className={[\"grid-row\", selected ? \"is-selected\" : \"\"]\n .filter(Boolean)\n .join(\" \")}\n >\n {columns.map(({ id, column, alignment }, columnIndex) => {\n // Resolved either way, so a template that only formats the value never\n // has to walk the field path a second time.\n const value = accessDotted(row, column.field);\n const cellSelected = id === selectedColumnId;\n\n return (\n <td\n key={id}\n role=\"gridcell\"\n data-gridkit-column={id}\n aria-colindex={columnIndex + 1}\n tabIndex={columnIndex === focusedColumnIndex ? 0 : -1}\n {...(cellsSelectable && { \"aria-selected\": cellSelected })}\n className={[\n \"grid-cell\",\n id === activeColumnId ? \"is-resizing\" : \"\",\n cellSelected || selectedColumnIds.has(id) ? \"is-selected\" : \"\",\n column.wrap?.cells ? \"is-wrapped\" : \"\",\n column.cellClassName ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ textAlign: alignment }}\n >\n {column.cellTemplate\n ? column.cellTemplate({ value, row, rowIndex, rowId, selected })\n : (value as ReactNode)}\n </td>\n );\n })}\n </tr>\n );\n}\n\n/**\n * Selection lives at the top of the grid, so any change to it re-renders the\n * whole body — without this boundary a click would rebuild every cell of every\n * row rather than the one or two rows that changed.\n *\n * Every prop above is a scalar or already memoised for that reason, and no\n * handler reaches here at all: the body delegates its events, so a row has\n * nothing to compare that changes each render.\n *\n * `memo` erases the type parameter, and the cast puts it back — the standard\n * price of memoising a generic component.\n */\nconst GridRow = memo(GridRowComponent) as typeof GridRowComponent;\n\nexport default GridRow;\n","import type { ResolvedRow } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { GridNavigationApi } from \"../useGridNavigation\";\nimport { intentOf, type GridSelectionApi } from \"../useGridSelection\";\nimport GridRow from \"./GridRow\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rows: readonly ResolvedRow<Row>[];\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\n/** Where a cell sits, read off the table's own indices rather than an attribute. */\ninterface CellPosition {\n rowIndex: number;\n columnIndex: number;\n columnId: string;\n}\n\n/**\n * The cell an event happened in. `closest` is what makes the whole cell the\n * target: a click on a template's own markup resolves to the cell holding it.\n */\nfunction cellFrom(target: EventTarget): CellPosition | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const cell = target.closest(\"td[data-gridkit-column]\");\n const row = cell?.parentElement;\n const columnId = cell?.getAttribute(\"data-gridkit-column\");\n if (\n !(cell instanceof HTMLTableCellElement) ||\n !(row instanceof HTMLTableRowElement) ||\n columnId === null ||\n columnId === undefined\n ) {\n return null;\n }\n return {\n rowIndex: row.sectionRowIndex,\n columnIndex: cell.cellIndex,\n columnId,\n };\n}\n\n/**\n * Events are delegated to the body rather than bound per cell, which is what\n * lets `GridRow` be memoised: a handler rebuilt each render is a prop that\n * changes each render, and one reaching every row would defeat the boundary\n * entirely.\n */\nexport default function GridBody<Row>({\n columns,\n rows,\n activeColumnId,\n nav,\n selection,\n}: GridBodyProps<Row>) {\n const { selectedCell, rowMode, cellMode } = selection;\n\n /** The row and cell an event addresses, resolved once for every handler. */\n function targetOf(\n target: EventTarget,\n ): { position: CellPosition; rowId: string } | null {\n const position = cellFrom(target);\n const entry = position === null ? undefined : rows[position.rowIndex];\n return position === null || entry === undefined\n ? null\n : { position, rowId: entry.rowId };\n }\n\n function select(\n rowId: string,\n columnId: string,\n modifiers: { ctrlKey: boolean; metaKey: boolean; shiftKey: boolean },\n ): void {\n const intent = intentOf(modifiers);\n // Independent of each other: selecting a cell says nothing about its row,\n // so a grid with both on reports both.\n if (rowMode !== false) {\n selection.selectRow(rowId, intent);\n }\n if (cellMode !== false) {\n selection.selectCell({ rowId, columnId }, intent);\n }\n }\n\n return (\n <tbody\n className=\"grid-body\"\n onFocus={(event) => {\n const found = targetOf(event.target);\n if (found === null) return;\n nav.focusCell(found.position.rowIndex, found.position.columnIndex);\n }}\n onClick={(event) => {\n const found = targetOf(event.target);\n if (found === null) return;\n select(found.rowId, found.position.columnId, event);\n }}\n onKeyDown={(event) => {\n // Space builds a selection up and Enter replaces it, matching the\n // Ctrl-click and the plain click they stand in for.\n if (event.key === \" \" || event.key === \"Enter\") {\n const found = targetOf(event.target);\n if (found === null) return;\n // Taken whether or not anything is selectable: Space would otherwise\n // scroll the grid out from under the focused cell.\n event.preventDefault();\n select(found.rowId, found.position.columnId, {\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n });\n return;\n }\n nav.onKeyDown(event);\n }}\n >\n {rows.map(({ rowId, row, rowIndex }) => (\n <GridRow<Row>\n key={rowId}\n columns={columns}\n rowId={rowId}\n row={row}\n rowIndex={rowIndex}\n activeColumnId={activeColumnId}\n selectedColumnIds={selection.selectedColumnIds}\n selected={selection.selectedRowIds.has(rowId)}\n /*\n * Narrowed to this row before it crosses the boundary, so that moving\n * the selected cell re-renders the two rows it moved between rather\n * than all of them.\n */\n selectedColumnId={\n selectedCell?.rowId === rowId ? selectedCell.columnId : null\n }\n focusedColumnIndex={\n nav.focus.rowIndex === rowIndex ? nav.focus.columnIndex : null\n }\n rowsSelectable={rowMode !== false}\n cellsSelectable={cellMode !== false}\n />\n ))}\n </tbody>\n );\n}\n","import {\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport {\n movesColumn,\n resolveDropBefore,\n type ColumnOrderState,\n type DropSide,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\n\n/**\n * How far the pointer travels before a press becomes a drag. Below it the\n * gesture is still a click, which is what leaves the header free to take one.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * Where a drop would land. A union rather than the bare id it holds today, so\n * a second drop zone adds a member instead of reshaping this state.\n */\nexport type DropTarget = { kind: \"column-order\"; beforeId: string | null };\n\ninterface UseColumnDragOptions {\n order: ColumnOrderState;\n onDrop: (target: DropTarget, movedId: string) => void;\n}\n\nexport interface ColumnDragApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: DropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /** Moves a column one place left (`-1`) or right (`1`). */\n moveByKeyboard: (entry: ResolvedColumn<Row>, direction: -1 | 1) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for a\n * header that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all —\n * on a column that cannot be reordered — does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * The header under `(x, y)`. `closest` is what makes the whole cell the drop\n * zone: a hit on the label or the resize handle resolves to its header.\n */\nfunction headerAt(x: number, y: number): Element | null {\n const element = document.elementFromPoint(x, y);\n return element?.closest(\"th[data-gridkit-column]\") ?? null;\n}\n\n/** Which half of `element` `x` falls in. */\nfunction sideOf(element: Element, x: number): DropSide {\n const rect = element.getBoundingClientRect();\n return x < rect.left + rect.width / 2 ? \"before\" : \"after\";\n}\n\n/**\n * Turns a pointer drag over the header into a drop target, leaving `onDrop` to\n * apply it.\n *\n * Pointer events rather than HTML5 drag-and-drop: `dragenter`/`dragleave` fire\n * per descendant, so the header's text and resize handle would each report the\n * target leaving and re-entering as the pointer crossed them.\n */\nexport default function useColumnDrag<Row>({\n order,\n onDrop,\n}: UseColumnDragOptions): ColumnDragApi<Row> {\n const [draggedColumnId, setDraggedColumnId] = useState<string | null>(null);\n const [dropTarget, setDropTarget] = useState<DropTarget | null>(null);\n const [ghostTransform, setGhostTransform] = useState<string | null>(null);\n const dragged = useRef(false);\n\n function justDragged(): boolean {\n const answer = dragged.current;\n dragged.current = false;\n return answer;\n }\n\n function startDrag(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const header = event.currentTarget;\n // Only the horizontal distance opens the drag: columns move along one\n // axis, so vertical travel says nothing about the user's intent.\n const { pointerId, clientX: startX } = event;\n const grabX = startX - header.getBoundingClientRect().left;\n let dragging = false;\n let target: DropTarget | null = null;\n\n /** Keeps the grab offset, so the pointer holds the spot it picked up. */\n function placeGhost(x: number, y: number): void {\n setGhostTransform(`translate(${String(x - grabX)}px, ${String(y)}px)`);\n }\n\n header.setPointerCapture(pointerId);\n\n function move(moveEvent: PointerEvent): void {\n const { clientX, clientY } = moveEvent;\n\n if (!dragging) {\n if (Math.abs(clientX - startX) < DRAG_THRESHOLD) {\n return;\n }\n dragging = true;\n // Latched for the `click` that follows the release, which is the only\n // thing that can tell a drag apart from a press in the same spot.\n dragged.current = true;\n setDraggedColumnId(entry.id);\n }\n\n placeGhost(clientX, clientY);\n\n // Hit-tested rather than read from the event's target, which pointer\n // capture pins to the header the drag opened on.\n const over = headerAt(clientX, clientY);\n const overId = over?.getAttribute(\"data-gridkit-column\");\n\n // The rect is read fresh each move, so a width changed mid-drag cannot\n // leave the midpoint stale.\n const beforeId =\n over && overId\n ? resolveDropBefore(order, overId, sideOf(over, clientX))\n : undefined;\n\n // A gap the column already sits in would promise a move that\n // `moveColumnBefore` then declines to make.\n target =\n beforeId !== undefined && movesColumn(order, entry.id, beforeId)\n ? { kind: \"column-order\", beforeId }\n : null;\n\n setDropTarget(target);\n }\n\n function stop(): void {\n header.removeEventListener(\"pointermove\", move);\n header.removeEventListener(\"pointerup\", end);\n header.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (header.hasPointerCapture(pointerId)) {\n header.releasePointerCapture(pointerId);\n }\n setGhostTransform(null);\n setDraggedColumnId(null);\n setDropTarget(null);\n }\n\n function end(): void {\n const dropped = target;\n stop();\n if (dragging && dropped !== null) {\n onDrop(dropped, entry.id);\n }\n }\n\n /** Escape and a cancelled pointer both leave the order as it was. */\n function cancel(): void {\n target = null;\n stop();\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n header.addEventListener(\"pointermove\", move);\n header.addEventListener(\"pointerup\", end);\n header.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function moveByKeyboard(entry: ResolvedColumn<Row>, direction: -1 | 1): void {\n const index = order.indexOf(entry.id);\n if (index === -1) {\n return;\n }\n\n /**\n * Moving right lands in front of the id two along: the gap immediately\n * after a column is the one it already sits in.\n */\n const targetIndex = direction === -1 ? index - 1 : index + 2;\n if (targetIndex < 0) {\n return;\n }\n\n onDrop(\n { kind: \"column-order\", beforeId: order[targetIndex] ?? null },\n entry.id,\n );\n }\n\n // A new object each render, as `useColumnResize` returns: the handlers close\n // over `order`, and a stable identity would buy nothing.\n return {\n draggedColumnId,\n dropTarget,\n ghostTransform,\n startDrag,\n moveByKeyboard,\n justDragged,\n };\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n handle.setPointerCapture(pointerId);\n setActiveColumnId(session.columnId);\n\n function move(moveEvent: PointerEvent): void {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n }\n\n function stop(): void {\n handle.removeEventListener(\"pointermove\", move);\n handle.removeEventListener(\"pointerup\", end);\n handle.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (handle.hasPointerCapture(pointerId)) {\n handle.releasePointerCapture(pointerId);\n }\n setActiveColumnId(null);\n }\n\n function end(): void {\n stop();\n commit(base, session.columnId, width, \"end\");\n }\n\n /**\n * Escape puts back the state the drag started from, which correctly covers\n * a column that had no stored width at all — merging `startWidth` back in\n * would instead leave it pinned and hidden from auto-fit.\n */\n function cancel(): void {\n stop();\n setSizing(base);\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: base,\n phase: \"end\",\n });\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n handle.addEventListener(\"pointermove\", move);\n handle.addEventListener(\"pointerup\", end);\n handle.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n"],"mappings":"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","names":["useMemo","useRef","useState","useRef","accessDotted","jsx","jsx","useRef","useState","useState","useState","useState","jsx","jsxs","useRef","useState","useMemo"]}
|
|
1
|
+
{"version":3,"sources":["../src/DataGrid/DataGrid.tsx","../src/DataGrid/components/GridHeader.tsx","../src/DataGrid/useGridNavigation.ts","../src/DataGrid/useGridSelection.ts","../src/DataGrid/components/GridRow.tsx","../src/DataGrid/components/GridBody.tsx","../src/DataGrid/useColumnDrag.ts","../src/DataGrid/useColumnResize.ts","../src/DataGrid/measureColumnContent.ts","../src/DataGrid/useColumnSort.ts","../src/DataGrid/useElementWidth.ts"],"sourcesContent":["import { useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n applyColumnOrder,\n defineColumnsFromRows,\n fitColumnsToWidth,\n moveColumnBefore,\n resolveColumnWidths,\n resolveRowId,\n resolveShownRows,\n totalColumnWidth,\n type ColumnDefinition as CoreColumnDefinition,\n type ResolvedColumn as CoreResolvedColumn,\n type ColumnOrderEvent,\n type ColumnOrderState,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n type ColumnSortEvent,\n type ColumnSortState,\n type FilterState,\n type ResolvedRow,\n type CellSelectionState,\n type SelectableConfig,\n type SelectedCell as CoreSelectedCell,\n type SelectedColumn as CoreSelectedColumn,\n type SelectionState,\n type CellSelectEvent as CoreCellSelectEvent,\n type CellSelectionChangeEvent as CoreCellSelectionChangeEvent,\n type ColumnSelectEvent as CoreColumnSelectEvent,\n type ColumnSelectionChangeEvent as CoreColumnSelectionChangeEvent,\n type ColumnsSelectEvent as CoreColumnsSelectEvent,\n} from \"@gridkitjs/core\";\nimport GridHeader from \"./components/GridHeader\";\nimport GridBody from \"./components/GridBody\";\nimport useColumnDrag, { type DropTarget } from \"./useColumnDrag\";\nimport useColumnResize from \"./useColumnResize\";\nimport useColumnSort from \"./useColumnSort\";\nimport useElementWidth from \"./useElementWidth\";\nimport useGridNavigation, { HEADER_ROW } from \"./useGridNavigation\";\nimport useGridSelection, { type SelectionCallbacks } from \"./useGridSelection\";\n\n/**\n * A column whose header and cells may render arbitrary React content.\n * @gridkitjs/core stays framework-agnostic and so leaves that output type open;\n * this is the binding React consumers want, and the one they should import.\n */\nexport type ColumnDefinition<Row> = CoreColumnDefinition<Row, ReactNode>;\n\n/** A column paired with the width it renders at. */\nexport type ResolvedColumn<Row> = CoreResolvedColumn<Row, ReactNode>;\n\n/**\n * The selection payloads, bound to React's node type for the same reason\n * `ColumnDefinition` is: they carry a resolved column, whose label is whatever\n * a `headerTemplate` returned.\n *\n * The row payloads name no node type at all and so are re-exported from\n * `@gridkitjs/core` as they are.\n */\nexport type SelectedColumn<Row> = CoreSelectedColumn<Row, ReactNode>;\nexport type SelectedCell<Row> = CoreSelectedCell<Row, ReactNode>;\nexport type ColumnSelectEvent<Row> = CoreColumnSelectEvent<Row, ReactNode>;\nexport type ColumnsSelectEvent<Row> = CoreColumnsSelectEvent<Row, ReactNode>;\nexport type ColumnSelectionChangeEvent<Row> = CoreColumnSelectionChangeEvent<\n Row,\n ReactNode\n>;\nexport type CellSelectEvent<Row> = CoreCellSelectEvent<Row, ReactNode>;\nexport type CellSelectionChangeEvent<Row> = CoreCellSelectionChangeEvent<\n Row,\n ReactNode\n>;\n\nexport type Borders = \"horizontal\" | \"vertical\" | \"all\" | \"none\";\n\n/**\n * How a column's width relates to the grid's.\n *\n * `\"fit\"` keeps the columns filling the grid: the space a column gives up is\n * handed to the others, and the space it takes comes out of them. `\"fixed\"`\n * lets every column keep its own width, so a resize moves one column and\n * nothing else, and the grid scrolls or leaves a gap accordingly.\n */\nexport type ResizeMode = \"fit\" | \"fixed\";\n\nexport interface HoverableConfig {\n rows?: boolean;\n columns?: boolean;\n cells?: boolean;\n}\n\nexport interface DataGridProps<Row> extends SelectionCallbacks<Row> {\n columns?: readonly ColumnDefinition<Row>[] | undefined;\n dataSource?: readonly Row[] | undefined;\n /**\n * A row's stable identity, for state keyed by it. Defaults to the row's\n * position, which is enough for a static grid but ties that state to where a\n * row sits rather than to the row — so anything sorting, filtering or paging\n * its data should give one.\n *\n * Called for every row on every change to `dataSource`, so it should be\n * cheap and stable; an inline arrow is fine, one that re-reads the data is\n * not.\n */\n getRowId?: ((row: Row, index: number) => string) | undefined;\n borders?: Borders | undefined;\n hoverable?: HoverableConfig | undefined;\n /**\n * Which parts of the grid the user may select, and how many of each —\n * `{ rows: \"multiple\", cells: \"single\" }`. A cell addresses one value, so it\n * has no `\"multiple\"`.\n *\n * Off by default, unlike `hoverable`: selection claims the click, which a\n * grid that only displays data should not do. Give `getRowId` alongside it\n * for data that sorts, filters or pages, or a selection follows the position\n * rather than the row.\n */\n selectable?: SelectableConfig | undefined;\n /** Row ids selected to start with, keyed as `getRowId` resolves them. Uncontrolled. */\n defaultRowSelection?: SelectionState | undefined;\n /** Column ids selected to start with. Uncontrolled. */\n defaultColumnSelection?: SelectionState | undefined;\n /** The cell selected to start with. Uncontrolled. */\n defaultCellSelection?: CellSelectionState | undefined;\n /** Whether columns can be dragged wider, unless a column says otherwise. */\n resizableColumns?: boolean | undefined;\n /**\n * Whether columns can be dragged into a new position, unless a column says\n * otherwise. Turning it off leaves an order the user already made in place.\n */\n reorderableColumns?: boolean | undefined;\n /**\n * Whether columns fill the grid's width or sit at their own. Defaults to\n * `\"fit\"`, under which columns the user has sized keep their width and the\n * rest share what is left.\n */\n resizeMode?: ResizeMode | undefined;\n /** Column widths to start from, keyed by column id. Uncontrolled. */\n defaultColumnSizing?: ColumnSizingState | undefined;\n /**\n * Column ids in the order to start in. Uncontrolled, and partial: ids it\n * omits keep their position among `columns` and follow those it lists.\n */\n defaultColumnOrder?: ColumnOrderState | undefined;\n /**\n * Sizes applied to columns that do not set their own — the width they start\n * at and the bounds they may be resized between. Distinct from\n * `defaultColumnSizing`, which sets specific columns' starting widths.\n */\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n /**\n * Called as the user resizes a column. Fires continuously with\n * `phase: \"move\"` and once on release with `phase: \"end\"` — the latter being\n * the one to persist. Auto-fit does not call it; it reports user intent only.\n */\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n /**\n * Called once when the user drops a column somewhere new. A drop that leaves\n * the order as it was does not call it.\n */\n onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;\n /**\n * Whether columns can be sorted by clicking their header toggle, unless a\n * column says otherwise. Shift-click stacks a column into the sort instead\n * of replacing it.\n */\n sortableColumns?: boolean | undefined;\n /** The sort to start with, in priority order. Uncontrolled. */\n defaultColumnSort?: ColumnSortState | undefined;\n /**\n * Called once when the user changes the sort — a toggle, a stack, or a\n * clear back to \"none\".\n */\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n /** The filter to start with — every applied entry, ANDed together. Uncontrolled. */\n defaultFilter?: FilterState<Row> | undefined;\n /**\n * The grid's accessible name, announced when it takes focus. A grid without\n * one is read only as \"grid\", which says nothing about which grid.\n */\n label?: string | undefined;\n /**\n * The id of an element naming the grid, for a heading already on the page.\n * Takes precedence over `label`, as `aria-labelledby` does.\n */\n labelledBy?: string | undefined;\n}\n\nexport function DataGridComponent<Row>({\n dataSource,\n columns,\n getRowId,\n borders,\n hoverable,\n selectable,\n defaultRowSelection,\n defaultColumnSelection,\n defaultCellSelection,\n resizableColumns = false,\n reorderableColumns = false,\n resizeMode = \"fit\",\n defaultColumnSizing,\n defaultColumnOrder,\n columnSizeDefaults,\n onColumnResize,\n onColumnOrderChange,\n sortableColumns = false,\n defaultColumnSort,\n onColumnSortChange,\n defaultFilter,\n label,\n labelledBy,\n ...callbacks\n}: DataGridProps<Row>) {\n const hoverRows = hoverable?.rows ?? true;\n const hoverColumns = hoverable?.columns ?? true;\n const hoverCells = hoverable?.cells ?? true;\n\n const viewportRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const viewportWidth = useElementWidth(viewportRef, resizeMode === \"fit\");\n const [sizing, setSizing] = useState<ColumnSizingState>(\n defaultColumnSizing ?? {},\n );\n const [order, setOrder] = useState<ColumnOrderState>(\n defaultColumnOrder ?? [],\n );\n const [sort, setSort] = useState<ColumnSortState>(defaultColumnSort ?? []);\n const [filter] = useState<FilterState<Row>>(defaultFilter ?? []);\n const [announcement, setAnnouncement] = useState(\"\");\n const [rowSelection, setRowSelection] = useState<SelectionState>(\n defaultRowSelection ?? [],\n );\n const [columnSelection, setColumnSelection] = useState<SelectionState>(\n defaultColumnSelection ?? [],\n );\n const [cellSelection, setCellSelection] = useState<CellSelectionState>(\n defaultCellSelection ?? null,\n );\n\n /**\n * The rows as rendered, each carrying the id everything downstream keys it\n * by. Resolved once here rather than per consumer so a row's id cannot come\n * out differently in two places — the same reason `resolveColumnWidths` runs\n * once ahead of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\n const rows = useMemo<readonly ResolvedRow<Row>[]>(\n () =>\n dataSource?.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n })) ?? [],\n [dataSource, getRowId],\n );\n\n const definedColumns = useMemo<readonly ColumnDefinition<Row>[]>(() => {\n if (columns && columns.length !== 0) return columns;\n if (dataSource && dataSource.length > 0)\n return defineColumnsFromRows(dataSource);\n return [];\n }, [columns, dataSource]);\n\n /**\n * Ahead of sizing, so everything downstream reads one already-ordered list\n * and no part of the grid has to know a reorder happened.\n */\n const orderedColumns = useMemo(\n () => applyColumnOrder(definedColumns, order),\n [definedColumns, order],\n );\n\n /**\n * Auto-fit is a derivation rather than a write back into `sizing`, so that a\n * `width` set in a column definition is never overwritten and the effect\n * cannot chase its own output. `\"fixed\"` is then simply the absence of it.\n */\n const resolved = useMemo(() => {\n const widths = resolveColumnWidths(orderedColumns, sizing, {\n sizes: columnSizeDefaults,\n resizable: resizableColumns,\n reorderable: reorderableColumns,\n });\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, columnSizeDefaults)\n : widths;\n }, [\n orderedColumns,\n sizing,\n resizeMode,\n viewportWidth,\n columnSizeDefaults,\n resizableColumns,\n reorderableColumns,\n ]);\n\n /**\n * `rows`, filtered then sorted — needs `resolved` for each column's\n * `field` and `type`, so it runs after sizing rather than alongside\n * `rows` itself. Everything downstream that renders or interacts with row\n * order and membership reads this rather than `rows`, so what the user\n * sees, filters, sorts, and clicks all agree.\n */\n const shownRows = useMemo(\n () => resolveShownRows(rows, filter, sort, resolved),\n [rows, filter, sort, resolved],\n );\n\n /**\n * What a column is called in an announcement. `label` carries whatever a\n * `headerTemplate` returned, which need not be text at all, so the field\n * path stands in whenever it is not.\n */\n function columnName(columnId: string): string {\n const entry = resolved.find((candidate) => candidate.id === columnId);\n if (entry === undefined) {\n return columnId;\n }\n return typeof entry.label === \"string\" ? entry.label : entry.column.field;\n }\n\n /**\n * Reports a change no visual cue can carry to a screen reader. Held as state\n * rather than written to the DOM directly so React owns the one element the\n * live region watches.\n */\n function announce(message: string): void {\n setAnnouncement(message);\n }\n\n /**\n * Wrapped rather than announced from the resize hook, which reports the\n * continuous `\"move\"` phase as well — a live region given every frame of a\n * drag says nothing an assistive technology can keep up with.\n */\n function handleColumnResize(event: ColumnResizeEvent): void {\n onColumnResize?.(event);\n if (event.phase === \"end\") {\n announce(\n `${columnName(event.columnId)}, ${String(Math.round(event.width))} pixels wide`,\n );\n }\n }\n\n const resize = useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize: handleColumnResize,\n });\n\n const nav = useGridNavigation({\n tableRef,\n rowCount: shownRows.length,\n columnCount: resolved.length,\n });\n\n /**\n * The ids as displayed, which a drop is expressed against — the order state\n * starts empty and may name only some columns, so moving against it directly\n * would have nothing to rearrange.\n */\n const displayedIds = useMemo(\n () => orderedColumns.map((column) => column.id ?? column.field),\n [orderedColumns],\n );\n\n /**\n * The one place a drop is applied. A second drop zone — a grouping bar above\n * the header — turns this into a switch on `target.kind` and touches nothing\n * else.\n */\n function handleDrop(target: DropTarget, movedId: string): void {\n const next = moveColumnBefore(displayedIds, movedId, target.beforeId);\n // `moveColumnBefore` hands back the same reference for a move that changes\n // nothing, so a drop in place neither renders nor reports.\n if (next === displayedIds) {\n return;\n }\n const position = next.indexOf(movedId);\n setOrder(next);\n onColumnOrderChange?.({ columnId: movedId, order: next });\n announce(\n `${columnName(movedId)}, column ${String(position + 1)} of ${String(next.length)}`,\n );\n /**\n * The tab stop travels with the column. React reorders the headers by key,\n * so the browser's focus stays on the moved one by itself — without this\n * the stop would be left on whichever column took its index, and the next\n * arrow key would appear to do nothing.\n */\n nav.focusCell(HEADER_ROW, position);\n }\n\n const drag = useColumnDrag<Row>({ order: displayedIds, onDrop: handleDrop });\n\n /**\n * Wrapped the same way `handleColumnResize`/`handleDrop` are, so a toggle,\n * a stack, or a clear back to \"none\" each get their own announcement.\n */\n function handleColumnSortChange(event: ColumnSortEvent): void {\n onColumnSortChange?.(event);\n const entry = event.sort.find(\n (candidate) => candidate.columnId === event.columnId,\n );\n if (entry === undefined) {\n announce(`${columnName(event.columnId)}, sort cleared`);\n return;\n }\n const direction = entry.direction === \"asc\" ? \"ascending\" : \"descending\";\n announce(\n event.sort.length > 1\n ? `${columnName(event.columnId)} sorted ${direction}, key ${String(event.sort.indexOf(entry) + 1)} of ${String(event.sort.length)}`\n : `${columnName(event.columnId)} sorted ${direction}`,\n );\n }\n\n const columnSort = useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange: handleColumnSortChange,\n });\n\n const selection = useGridSelection<Row>({\n rows: shownRows,\n columns: resolved,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n });\n\n const multiselectable =\n selection.rowMode === \"multiple\" || selection.columnMode === \"multiple\";\n\n return (\n <div className=\"gridkit-data-grid-viewport\" ref={viewportRef}>\n <table\n ref={tableRef}\n /*\n * `role=\"grid\"` rather than the table's own semantics: it is what makes\n * the arrow keys a navigation the grid owns, and later what lets a row\n * report whether it is selected. It obliges the single tab stop\n * `useGridNavigation` keeps.\n */\n role=\"grid\"\n // The header is a row too, and counted from one.\n aria-rowcount={shownRows.length + 1}\n aria-colcount={resolved.length}\n {...(multiselectable && { \"aria-multiselectable\": true })}\n {...(labelledBy !== undefined && { \"aria-labelledby\": labelledBy })}\n {...(labelledBy === undefined &&\n label !== undefined && { \"aria-label\": label })}\n onKeyDown={(event) => {\n /*\n * The two keys that address the grid rather than a cell, and so are\n * caught here where everything bubbles to rather than in each of\n * them.\n */\n if (event.key === \"Escape\") {\n // A gesture in flight has its own use for Escape — cancelling —\n // and gets it first.\n if (drag.draggedColumnId !== null || resize.activeColumnId !== null)\n return;\n selection.clear();\n return;\n }\n if (\n (event.ctrlKey || event.metaKey) &&\n (event.key === \"a\" || event.key === \"A\")\n ) {\n // Left to the browser unless the grid has something to do with it,\n // so a grid without multiple rows does not swallow select-all.\n if (selection.rowMode !== \"multiple\") return;\n event.preventDefault();\n selection.selectAllRows();\n }\n }}\n // Widths are only honoured exactly when the table is as wide as its\n // columns; at `100%` the fixed layout redistributes the difference.\n style={{ width: totalColumnWidth(resolved) }}\n className={[\n \"gridkit-data-grid\",\n borders ? `borders-${borders}` : \"\",\n // Hover is on by default and selection off, so one set of classes\n // turns styling off and the other turns it on. The polarity differs\n // because the defaults do.\n hoverRows ? \"\" : \"no-hover-rows\",\n hoverColumns ? \"\" : \"no-hover-columns\",\n hoverCells ? \"\" : \"no-hover-cells\",\n selection.rowMode === false ? \"\" : \"selectable-rows\",\n selection.columnMode === false ? \"\" : \"selectable-columns\",\n selection.cellMode === false ? \"\" : \"selectable-cells\",\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <colgroup>\n {resolved.map((entry) => (\n <col key={entry.id} style={{ width: entry.width }} />\n ))}\n </colgroup>\n <GridHeader<Row>\n columns={resolved}\n resize={resize}\n drag={drag}\n sort={columnSort}\n sortableColumns={sortableColumns}\n nav={nav}\n selection={selection}\n />\n <GridBody<Row>\n columns={resolved}\n rows={shownRows}\n activeColumnId={resize.activeColumnId}\n nav={nav}\n selection={selection}\n />\n </table>\n {/*\n * Outside the table, which admits no `div`, and polite so it waits for a\n * pause rather than cutting across what the user is already hearing.\n */}\n <div className=\"gridkit-sr-only\" role=\"status\" aria-live=\"polite\">\n {announcement}\n </div>\n </div>\n );\n}\n","import { createPortal } from \"react-dom\";\nimport { KEYBOARD_STEP } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { ColumnDragApi } from \"../useColumnDrag\";\nimport type { ColumnResizeApi } from \"../useColumnResize\";\nimport type { ColumnSortApi } from \"../useColumnSort\";\nimport { HEADER_ROW, type GridNavigationApi } from \"../useGridNavigation\";\nimport { intentOf, type GridSelectionApi } from \"../useGridSelection\";\n\ninterface GridHeaderProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n resize: ColumnResizeApi<Row>;\n drag: ColumnDragApi<Row>;\n sort: ColumnSortApi<Row>;\n sortableColumns: boolean;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\n/**\n * The two glyphs a sort toggle shows: a neutral hint before a column has a\n * direction, and a single chevron reused for both directions once it does —\n * `theme-tailwind` rotates it 180° for `desc` rather than swapping icons.\n */\nfunction ChevronsUpDownIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m7 15 5 5 5-5\" />\n <path d=\"m7 9 5-5 5 5\" />\n </svg>\n );\n}\n\nfunction ChevronUpIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n );\n}\n\nexport default function GridHeader<Row>({\n columns,\n resize,\n drag,\n sort,\n sortableColumns,\n nav,\n selection,\n}: GridHeaderProps<Row>) {\n const { beforeId } = drag.dropTarget ?? {};\n const draggedEntry =\n columns.find((entry) => entry.id === drag.draggedColumnId) ?? null;\n\n return (\n <thead>\n <tr className=\"grid-header\" role=\"row\" aria-rowindex={1}>\n {columns.map((entry, index) => {\n const { column } = entry;\n const resizing = resize.activeColumnId === entry.id;\n const dragging = drag.draggedColumnId === entry.id;\n\n /**\n * Drawn on the gap's own edge, so the one gap between two columns is\n * marked once. No guard against the dragged column: the hook reports\n * only gaps that would move it.\n */\n const dropBefore = beforeId !== undefined && beforeId === entry.id;\n const dropAfter = beforeId === null && index === columns.length - 1;\n const selected = selection.selectedColumnIds.has(entry.id);\n const sortable = column.sortable ?? sortableColumns;\n const sortDirection = sort.directionFor(entry.id);\n const sortPriority = sort.priorityFor(entry.id);\n\n /**\n * Announced so the keys are discoverable, since neither is a\n * convention a user would try unprompted.\n */\n const shortcuts = [\n entry.reorderable ? \"Control+ArrowLeft Control+ArrowRight\" : \"\",\n entry.resizable ? \"Alt+ArrowLeft Alt+ArrowRight\" : \"\",\n sortable ? \"Alt+ArrowUp\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <th\n key={entry.id}\n scope=\"col\"\n data-gridkit-column={entry.id}\n aria-colindex={index + 1}\n tabIndex={nav.tabIndexFor(HEADER_ROW, index)}\n {...(selection.columnMode !== false && {\n \"aria-selected\": selected,\n })}\n onFocus={() => {\n nav.focusCell(HEADER_ROW, index);\n }}\n onClick={(event) => {\n /*\n * A drag ends in a click on the header it started from, and a\n * resize in one on the handle inside it. Neither is the press\n * that selects a column, so both are shown the door here —\n * the drag by the distance it travelled, the resize by where\n * it began.\n */\n if (drag.justDragged()) {\n return;\n }\n if (\n event.target instanceof Element &&\n (event.target.closest(\".header-resize-handle\") !== null ||\n event.target.closest(\".header-sort-toggle\") !== null)\n ) {\n return;\n }\n selection.selectColumn(entry.id, intentOf(event));\n }}\n onKeyDown={(event) => {\n const horizontal =\n event.key === \"ArrowLeft\" || event.key === \"ArrowRight\";\n const direction = event.key === \"ArrowLeft\" ? -1 : 1;\n\n if (horizontal && event.ctrlKey && entry.reorderable) {\n event.preventDefault();\n drag.moveByKeyboard(entry, direction);\n return;\n }\n if (horizontal && event.altKey && entry.resizable) {\n event.preventDefault();\n resize.nudge(entry, direction * KEYBOARD_STEP);\n return;\n }\n if (event.key === \"ArrowUp\" && event.altKey && sortable) {\n event.preventDefault();\n sort.toggle(entry, { shiftKey: event.shiftKey });\n return;\n }\n // Space builds a selection up and Enter replaces it, as in the\n // body. Taken either way, or Space scrolls the grid away.\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n selection.selectColumn(\n entry.id,\n intentOf({\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n }),\n );\n return;\n }\n nav.onKeyDown(event);\n }}\n className={[\n \"header-cell\",\n entry.reorderable ? \"is-reorderable\" : \"\",\n selected ? \"is-selected\" : \"\",\n resizing ? \"is-resizing\" : \"\",\n dragging ? \"is-dragging\" : \"\",\n dropBefore ? \"is-drop-before\" : \"\",\n dropAfter ? \"is-drop-after\" : \"\",\n column.wrap?.header ? \"is-wrapped\" : \"\",\n column.headerClassName ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n {...(shortcuts !== \"\" && { \"aria-keyshortcuts\": shortcuts })}\n {...(sortable &&\n sortDirection !== null && {\n \"aria-sort\":\n sortDirection === \"asc\" ? \"ascending\" : \"descending\",\n })}\n {...(entry.reorderable && {\n onPointerDown: (event) => {\n drag.startDrag(entry, event);\n },\n })}\n >\n {entry.label}\n {sortable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology like the resize handle: the keyboard equivalent\n * lives on the header itself, under Alt+ArrowUp (plain) /\n * Alt+Shift+ArrowUp (stacking).\n */\n <span\n className={[\n \"header-sort-toggle\",\n sortDirection !== null ? `is-sorted-${sortDirection}` : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n /*\n * Otherwise a reorderable header's own `onPointerDown`\n * sees this bubble up and starts a column drag, whose\n * `setPointerCapture` then redirects the click that\n * follows to the `th` — the same reason `startResize`\n * stops it for the resize handle.\n */\n event.stopPropagation();\n }}\n onClick={(event) => {\n sort.toggle(entry, { shiftKey: event.shiftKey });\n }}\n >\n {sortDirection === null ? (\n <ChevronsUpDownIcon />\n ) : (\n <ChevronUpIcon />\n )}\n {sortPriority !== null && sortPriority > 1 && (\n <span className=\"header-sort-priority\">{sortPriority}</span>\n )}\n </span>\n )}\n {entry.resizable && (\n /*\n * A pointer affordance only, and hidden from assistive\n * technology accordingly: a focusable handle per column would\n * put N tab stops inside a widget that is meant to have one.\n * The keyboard resizes from the header itself, under Alt.\n */\n <span\n className=\"header-resize-handle\"\n aria-hidden=\"true\"\n tabIndex={-1}\n onPointerDown={(event) => {\n resize.startResize(entry, event);\n }}\n onDoubleClick={() => {\n resize.sizeToContent(entry);\n }}\n />\n )}\n </th>\n );\n })}\n </tr>\n {/*\n * Portalled to the body, and not only because a `div` cannot sit in a\n * `tr`: inside the viewport the overflow that makes the grid scroll\n * would clip it.\n */}\n {draggedEntry !== null &&\n drag.ghostTransform !== null &&\n createPortal(\n <div\n className=\"gridkit-data-grid header-cell drag-ghost\"\n style={{\n width: draggedEntry.width,\n transform: drag.ghostTransform,\n }}\n aria-hidden=\"true\"\n >\n {draggedEntry.label}\n </div>,\n document.body,\n )}\n </thead>\n );\n}\n","import {\n useEffect,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\n\n/**\n * The header's row index. One coordinate space covers the header and the body\n * so that arrowing up out of the first row reaches the header without a case\n * of its own, and every other move is plain arithmetic.\n */\nexport const HEADER_ROW = -1;\n\n/** Rows a page key moves when the viewport cannot be measured. */\nconst FALLBACK_PAGE = 10;\n\n/** The cell the grid's single tab stop sits on. */\nexport interface GridFocus {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\ninterface UseGridNavigationOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n rowCount: number;\n columnCount: number;\n}\n\nexport interface GridNavigationApi {\n focus: GridFocus;\n /**\n * `0` for the focused cell and `-1` for every other. A grid is one tab stop:\n * tabbing reaches it, and the arrow keys move within it.\n */\n tabIndexFor: (rowIndex: number, columnIndex: number) => 0 | -1;\n /** Moves the tab stop, and the browser's focus with it. */\n focusCell: (rowIndex: number, columnIndex: number) => void;\n /** Handles the navigation keys, leaving every other key to bubble. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n}\n\n/**\n * Holds a coordinate inside the grid, so that a focus surviving a column\n * removal or a shorter page never leaves the grid with no tab stop at all —\n * which is a grid a keyboard cannot reach.\n */\nfunction clampFocus(\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n): GridFocus {\n return {\n rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),\n columnIndex: Math.min(\n Math.max(focus.columnIndex, 0),\n Math.max(columnCount - 1, 0),\n ),\n };\n}\n\n/**\n * The cell at a coordinate, found through the table's own row and cell\n * collections rather than a selector.\n *\n * Ids can hold anything a consumer's data holds, and an attribute selector\n * built from one would have to escape it; positions need no quoting.\n */\nfunction cellAt(table: HTMLTableElement, focus: GridFocus): HTMLElement | null {\n const row =\n focus.rowIndex === HEADER_ROW\n ? (table.tHead?.rows[0] ?? null)\n : (table.tBodies[0]?.rows[focus.rowIndex] ?? null);\n return row?.cells[focus.columnIndex] ?? null;\n}\n\n/**\n * Moves one tab stop around the grid, which is what `role=\"grid\"` obliges:\n * arrow keys travel cell to cell and Tab passes the whole grid by.\n *\n * Separate from selection because focus and selection are different states — a\n * cell is focused while travelling before anything is selected, and every cell\n * of a range is selected without being focused. Navigation also has to work\n * with selection turned off entirely, so it cannot depend on it.\n */\nexport default function useGridNavigation({\n tableRef,\n rowCount,\n columnCount,\n}: UseGridNavigationOptions): GridNavigationApi {\n const [stored, setStored] = useState<GridFocus>({\n rowIndex: HEADER_ROW,\n columnIndex: 0,\n });\n\n /**\n * Clamped on the way out rather than written back, so that a coordinate\n * pushed out of range by a change to the data is restored when the data\n * comes back — and so the effect below cannot chase its own output.\n */\n const focus = clampFocus(stored, rowCount, columnCount);\n\n /**\n * Whether the browser's focus still has to be moved to match. Without it\n * every render would pull focus into the grid, including the first.\n */\n const pending = useRef(false);\n\n useEffect(() => {\n if (!pending.current) {\n return;\n }\n pending.current = false;\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n cellAt(table, { rowIndex: focus.rowIndex, columnIndex: focus.columnIndex })\n // Focusing the cell the browser already sits on is a no-op, which is what\n // makes one method serve both a key press and a cell reporting a click.\n ?.focus();\n }, [tableRef, focus.rowIndex, focus.columnIndex]);\n\n /** How many rows fit the viewport, which is what a page key should move. */\n function pageSize(): number {\n const table = tableRef.current;\n const firstRow = table?.tBodies[0]?.rows[0];\n const viewport = table?.parentElement;\n if (\n firstRow === undefined ||\n viewport === null ||\n viewport === undefined ||\n firstRow.offsetHeight === 0\n ) {\n return FALLBACK_PAGE;\n }\n return Math.max(\n 1,\n Math.floor(viewport.clientHeight / firstRow.offsetHeight),\n );\n }\n\n function focusCell(rowIndex: number, columnIndex: number): void {\n const next = clampFocus({ rowIndex, columnIndex }, rowCount, columnCount);\n if (\n next.rowIndex === focus.rowIndex &&\n next.columnIndex === focus.columnIndex\n ) {\n return;\n }\n pending.current = true;\n setStored(next);\n }\n\n function tabIndexFor(rowIndex: number, columnIndex: number): 0 | -1 {\n return rowIndex === focus.rowIndex && columnIndex === focus.columnIndex\n ? 0\n : -1;\n }\n\n function onKeyDown(event: ReactKeyboardEvent<HTMLElement>): void {\n // Alt on an arrow resizes and Ctrl on one reorders; the header claims both\n // before this runs, and elsewhere they belong to the browser.\n if (event.altKey) {\n return;\n }\n\n const { rowIndex, columnIndex } = focus;\n let next: GridFocus;\n\n switch (event.key) {\n case \"ArrowLeft\":\n if (event.ctrlKey) return;\n next = { rowIndex, columnIndex: columnIndex - 1 };\n break;\n case \"ArrowRight\":\n if (event.ctrlKey) return;\n next = { rowIndex, columnIndex: columnIndex + 1 };\n break;\n case \"ArrowUp\":\n next = { rowIndex: rowIndex - 1, columnIndex };\n break;\n case \"ArrowDown\":\n next = { rowIndex: rowIndex + 1, columnIndex };\n break;\n // Ctrl takes Home and End to the grid's ends rather than the row's, which\n // is the one place Ctrl is navigation rather than reorder.\n case \"Home\":\n next = event.ctrlKey\n ? { rowIndex: HEADER_ROW, columnIndex: 0 }\n : { rowIndex, columnIndex: 0 };\n break;\n case \"End\":\n next = event.ctrlKey\n ? { rowIndex: rowCount - 1, columnIndex: columnCount - 1 }\n : { rowIndex, columnIndex: columnCount - 1 };\n break;\n case \"PageUp\":\n next = { rowIndex: rowIndex - pageSize(), columnIndex };\n break;\n case \"PageDown\":\n next = { rowIndex: rowIndex + pageSize(), columnIndex };\n break;\n default:\n return;\n }\n\n // Taken even when the move lands nowhere: an arrow at the last row would\n // otherwise scroll the page out from under the grid.\n event.preventDefault();\n focusCell(next.rowIndex, next.columnIndex);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the focus they move from.\n return { focus, tabIndexFor, focusCell, onKeyDown };\n}\n","import { useMemo, useRef, type Dispatch, type SetStateAction } from \"react\";\nimport {\n accessDotted,\n clearSelection,\n diffSelection,\n selectAll,\n selectCell,\n selectOnly,\n selectRange,\n toggleCellSelection,\n toggleSelection,\n type CellSelectionMode,\n type CellSelectionState,\n type ResolvedRow,\n type SelectableConfig,\n type SelectedCellRef,\n type SelectionMode,\n type SelectionState,\n type RowSelectEvent,\n type RowSelectionChangeEvent,\n type RowsSelectEvent,\n} from \"@gridkitjs/core\";\nimport type {\n CellSelectEvent,\n CellSelectionChangeEvent,\n ColumnSelectEvent,\n ColumnSelectionChangeEvent,\n ColumnsSelectEvent,\n ResolvedColumn,\n SelectedCell,\n SelectedColumn,\n} from \"./DataGrid\";\n\n/**\n * What an interaction means for the selection, read off its modifiers once at\n * the boundary so that nothing downstream handles a raw event.\n */\nexport type SelectIntent = \"replace\" | \"toggle\" | \"range\";\n\n/** The intent a click or key press carries, by the modifiers held with it. */\nexport function intentOf(event: {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n}): SelectIntent {\n if (event.shiftKey) {\n return \"range\";\n }\n // Cmd on a Mac is Ctrl everywhere else, and both mean the same thing here.\n return event.ctrlKey || event.metaKey ? \"toggle\" : \"replace\";\n}\n\n/**\n * Reported as the user selects. Every one of these is fanned out from a single\n * diff of the transition it describes, so no two can disagree about what one\n * interaction did.\n */\nexport interface SelectionCallbacks<Row> {\n /** Called once per row newly selected. The last call names the last row. */\n onRowSelect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n /** Called once with every row one interaction selected. */\n onRowsSelect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n onRowDeselect?: ((event: RowSelectEvent<Row>) => void) | undefined;\n onRowsDeselect?: ((event: RowsSelectEvent<Row>) => void) | undefined;\n /**\n * Called once per change with what it added, what it removed and everything\n * selected after it — the one to persist from.\n */\n onRowSelectionChange?:\n ((event: RowSelectionChangeEvent<Row>) => void) | undefined;\n onColumnSelect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsSelect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnDeselect?: ((event: ColumnSelectEvent<Row>) => void) | undefined;\n onColumnsDeselect?: ((event: ColumnsSelectEvent<Row>) => void) | undefined;\n onColumnSelectionChange?:\n ((event: ColumnSelectionChangeEvent<Row>) => void) | undefined;\n onCellSelect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellDeselect?: ((event: CellSelectEvent<Row>) => void) | undefined;\n onCellSelectionChange?:\n ((event: CellSelectionChangeEvent<Row>) => void) | undefined;\n}\n\ninterface UseGridSelectionOptions<Row> {\n rows: readonly ResolvedRow<Row>[];\n columns: readonly ResolvedColumn<Row>[];\n selectable: SelectableConfig | undefined;\n rowSelection: SelectionState;\n setRowSelection: Dispatch<SetStateAction<SelectionState>>;\n columnSelection: SelectionState;\n setColumnSelection: Dispatch<SetStateAction<SelectionState>>;\n cellSelection: CellSelectionState;\n setCellSelection: Dispatch<SetStateAction<CellSelectionState>>;\n callbacks: SelectionCallbacks<Row>;\n announce: (message: string) => void;\n}\n\nexport interface GridSelectionApi {\n rowMode: SelectionMode;\n columnMode: SelectionMode;\n cellMode: CellSelectionMode;\n /**\n * Lookups for the render pass. The state itself stays an ordered list, which\n * is what makes the most recent selection its last entry.\n */\n selectedRowIds: ReadonlySet<string>;\n selectedColumnIds: ReadonlySet<string>;\n selectedCell: CellSelectionState;\n selectRow: (rowId: string, intent: SelectIntent) => void;\n selectColumn: (columnId: string, intent: SelectIntent) => void;\n selectCell: (cell: SelectedCellRef, intent: SelectIntent) => void;\n selectAllRows: () => void;\n /** Lets go of every selection at once, as Escape does. */\n clear: () => void;\n}\n\n/**\n * The transform an intent asks for. A function rather than a branch inside\n * each caller, so a row and a column cannot come to mean different things by\n * the same click.\n */\nfunction applyIntent(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string | null,\n id: string,\n intent: SelectIntent,\n mode: SelectionMode,\n): SelectionState {\n switch (intent) {\n case \"toggle\":\n return toggleSelection(selection, id, mode);\n // A range with no anchor yet spans from the id to itself, which is the\n // plain click a first Shift-click may as well be.\n case \"range\":\n return selectRange(selection, orderedIds, anchorId ?? id, id, mode);\n default:\n return selectOnly(selection, id, mode);\n }\n}\n\nfunction countMessage(count: number, noun: string): string {\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1\n ? `1 ${noun} selected`\n : `${String(count)} ${noun}s selected`;\n}\n\n/**\n * Turns an intent against a row, column or cell into the selection it implies,\n * and reports what changed.\n *\n * Holds no state of its own: the three selections live in `DataGrid` beside\n * the sizing and the order, so that a ref exposing them later, or a feature\n * reading them, finds them in one place.\n */\nexport default function useGridSelection<Row>({\n rows,\n columns,\n selectable,\n rowSelection,\n setRowSelection,\n columnSelection,\n setColumnSelection,\n cellSelection,\n setCellSelection,\n callbacks,\n announce,\n}: UseGridSelectionOptions<Row>): GridSelectionApi {\n const rowMode = selectable?.rows ?? false;\n const columnMode = selectable?.columns ?? false;\n const cellMode = selectable?.cells ?? false;\n\n const rowsById = useMemo(\n () => new Map(rows.map((entry) => [entry.rowId, entry])),\n [rows],\n );\n const rowIds = useMemo(() => rows.map((entry) => entry.rowId), [rows]);\n const columnIds = useMemo(() => columns.map((entry) => entry.id), [columns]);\n\n const selectedRowIds = useMemo(() => new Set(rowSelection), [rowSelection]);\n const selectedColumnIds = useMemo(\n () => new Set(columnSelection),\n [columnSelection],\n );\n\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n const rowAnchor = useRef<string | null>(null);\n const columnAnchor = useRef<string | null>(null);\n\n /**\n * Ids with no row behind them are dropped rather than reported: a selection\n * outlives a change to the data, so that filtering a row out and back leaves\n * it selected, and only what is on screen can be handed to a callback.\n */\n function resolveRows(ids: readonly string[]): readonly ResolvedRow<Row>[] {\n return ids.map((id) => rowsById.get(id)).filter((row) => row !== undefined);\n }\n\n function resolveColumns(\n ids: readonly string[],\n ): readonly SelectedColumn<Row>[] {\n return ids\n .map((id) => {\n const columnIndex = columns.findIndex((entry) => entry.id === id);\n const column = columns[columnIndex];\n return column === undefined\n ? undefined\n : { columnId: id, column, columnIndex };\n })\n .filter((column) => column !== undefined);\n }\n\n function resolveCell(ref: CellSelectionState): SelectedCell<Row> | null {\n if (ref === null) {\n return null;\n }\n const entry = rowsById.get(ref.rowId);\n const columnIndex = columns.findIndex(\n (candidate) => candidate.id === ref.columnId,\n );\n const column = columns[columnIndex];\n if (entry === undefined || column === undefined) {\n return null;\n }\n return {\n rowId: ref.rowId,\n columnId: ref.columnId,\n row: entry.row,\n column,\n rowIndex: entry.rowIndex,\n columnIndex,\n value: accessDotted(entry.row, column.column.field),\n };\n }\n\n /**\n * Announced only for a change touching more than one member. A single\n * selection is already carried by the focused row's own `aria-selected`, and\n * repeating it here would talk over that.\n */\n function announceCount(changed: number, total: number, noun: string): void {\n if (changed > 1) {\n announce(countMessage(total, noun));\n }\n }\n\n function commitRows(next: SelectionState): void {\n // The unchanged-reference contract the core transforms keep: a click that\n // selects what was already selected neither renders nor reports.\n if (next === rowSelection) {\n return;\n }\n setRowSelection(next);\n\n const { added, removed } = diffSelection(rowSelection, next);\n const addedRows = resolveRows(added);\n const removedRows = resolveRows(removed);\n\n for (const row of addedRows) {\n callbacks.onRowSelect?.({ row, selection: next });\n }\n if (addedRows.length > 0) {\n callbacks.onRowsSelect?.({ rows: addedRows, selection: next });\n }\n for (const row of removedRows) {\n callbacks.onRowDeselect?.({ row, selection: next });\n }\n if (removedRows.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removedRows, selection: next });\n }\n callbacks.onRowSelectionChange?.({\n added: addedRows,\n removed: removedRows,\n selected: resolveRows(next),\n selection: next,\n });\n announceCount(added.length + removed.length, next.length, \"row\");\n }\n\n function commitColumns(next: SelectionState): void {\n if (next === columnSelection) {\n return;\n }\n setColumnSelection(next);\n\n const { added, removed } = diffSelection(columnSelection, next);\n const addedColumns = resolveColumns(added);\n const removedColumns = resolveColumns(removed);\n\n for (const column of addedColumns) {\n callbacks.onColumnSelect?.({ column, selection: next });\n }\n if (addedColumns.length > 0) {\n callbacks.onColumnsSelect?.({ columns: addedColumns, selection: next });\n }\n for (const column of removedColumns) {\n callbacks.onColumnDeselect?.({ column, selection: next });\n }\n if (removedColumns.length > 0) {\n callbacks.onColumnsDeselect?.({\n columns: removedColumns,\n selection: next,\n });\n }\n callbacks.onColumnSelectionChange?.({\n added: addedColumns,\n removed: removedColumns,\n selected: resolveColumns(next),\n selection: next,\n });\n announceCount(added.length + removed.length, next.length, \"column\");\n }\n\n function commitCell(next: CellSelectionState): void {\n if (next === cellSelection) {\n return;\n }\n setCellSelection(next);\n\n // Resolved before and after in one place, so that moving between two cells\n // reports the leaving and the arriving as one change.\n const selected = resolveCell(next);\n const deselected = resolveCell(cellSelection);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: next });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: next });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: next,\n });\n }\n\n function selectRow(rowId: string, intent: SelectIntent): void {\n const next = applyIntent(\n rowSelection,\n rowIds,\n rowAnchor.current,\n rowId,\n intent,\n rowMode,\n );\n if (intent !== \"range\") {\n rowAnchor.current = rowId;\n }\n commitRows(next);\n }\n\n function selectColumn(columnId: string, intent: SelectIntent): void {\n const next = applyIntent(\n columnSelection,\n columnIds,\n columnAnchor.current,\n columnId,\n intent,\n columnMode,\n );\n if (intent !== \"range\") {\n columnAnchor.current = columnId;\n }\n commitColumns(next);\n }\n\n function selectCellAt(cell: SelectedCellRef, intent: SelectIntent): void {\n // A cell holds one value, so a range over cells has nothing to span and\n // reads as the plain click it looks like.\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(cellSelection, cell, cellMode)\n : selectCell(cellSelection, cell, cellMode),\n );\n }\n\n function selectAllRows(): void {\n commitRows(selectAll(rowSelection, rowIds, rowMode));\n }\n\n function clear(): void {\n commitRows(clearSelection(rowSelection));\n commitColumns(clearSelection(columnSelection));\n commitCell(null);\n }\n\n // A new object each render, as the other hooks here return: the handlers\n // close over the selections they transform.\n return {\n rowMode,\n columnMode,\n cellMode,\n selectedRowIds,\n selectedColumnIds,\n selectedCell: cellSelection,\n selectRow,\n selectColumn,\n selectCell: selectCellAt,\n selectAllRows,\n clear,\n };\n}\n","import { accessDotted } from \"@gridkitjs/core\";\nimport { memo, type ReactNode } from \"react\";\nimport type { ResolvedColumn } from \"../DataGrid\";\n\ninterface GridRowProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rowId: string;\n row: Row;\n rowIndex: number;\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n selectedColumnIds: ReadonlySet<string>;\n selected: boolean;\n /** Which of this row's cells is the selected one, if any. */\n selectedColumnId: string | null;\n /** Which of this row's cells holds the grid's tab stop, if any. */\n focusedColumnIndex: number | null;\n rowsSelectable: boolean;\n cellsSelectable: boolean;\n}\n\nfunction GridRowComponent<Row>({\n columns,\n rowId,\n row,\n rowIndex,\n activeColumnId,\n selectedColumnIds,\n selected,\n selectedColumnId,\n focusedColumnIndex,\n rowsSelectable,\n cellsSelectable,\n}: GridRowProps<Row>) {\n return (\n <tr\n role=\"row\"\n // Two past the index: rows are counted from one, and the header is the\n // first of them.\n aria-rowindex={rowIndex + 2}\n // Omitted rather than `false` when rows cannot be selected, which would\n // otherwise have every row announce that it is not.\n {...(rowsSelectable && { \"aria-selected\": selected })}\n className={[\"grid-row\", selected ? \"is-selected\" : \"\"]\n .filter(Boolean)\n .join(\" \")}\n >\n {columns.map(({ id, column, alignment }, columnIndex) => {\n // Resolved either way, so a template that only formats the value never\n // has to walk the field path a second time.\n const value = accessDotted(row, column.field);\n const cellSelected = id === selectedColumnId;\n\n return (\n <td\n key={id}\n role=\"gridcell\"\n data-gridkit-column={id}\n aria-colindex={columnIndex + 1}\n tabIndex={columnIndex === focusedColumnIndex ? 0 : -1}\n {...(cellsSelectable && { \"aria-selected\": cellSelected })}\n className={[\n \"grid-cell\",\n id === activeColumnId ? \"is-resizing\" : \"\",\n cellSelected || selectedColumnIds.has(id) ? \"is-selected\" : \"\",\n column.wrap?.cells ? \"is-wrapped\" : \"\",\n column.cellClassName ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ textAlign: alignment }}\n >\n {column.cellTemplate\n ? column.cellTemplate({ value, row, rowIndex, rowId, selected })\n : (value as ReactNode)}\n </td>\n );\n })}\n </tr>\n );\n}\n\n/**\n * Selection lives at the top of the grid, so any change to it re-renders the\n * whole body — without this boundary a click would rebuild every cell of every\n * row rather than the one or two rows that changed.\n *\n * Every prop above is a scalar or already memoised for that reason, and no\n * handler reaches here at all: the body delegates its events, so a row has\n * nothing to compare that changes each render.\n *\n * `memo` erases the type parameter, and the cast puts it back — the standard\n * price of memoising a generic component.\n */\nconst GridRow = memo(GridRowComponent) as typeof GridRowComponent;\n\nexport default GridRow;\n","import type { ResolvedRow } from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"../DataGrid\";\nimport type { GridNavigationApi } from \"../useGridNavigation\";\nimport { intentOf, type GridSelectionApi } from \"../useGridSelection\";\nimport GridRow from \"./GridRow\";\n\ninterface GridBodyProps<Row> {\n columns: readonly ResolvedColumn<Row>[];\n rows: readonly ResolvedRow<Row>[];\n /** The column being resized, so its cells outline with its header. */\n activeColumnId: string | null;\n nav: GridNavigationApi;\n selection: GridSelectionApi;\n}\n\n/** Where a cell sits, read off the table's own indices rather than an attribute. */\ninterface CellPosition {\n rowIndex: number;\n columnIndex: number;\n columnId: string;\n}\n\n/**\n * The cell an event happened in. `closest` is what makes the whole cell the\n * target: a click on a template's own markup resolves to the cell holding it.\n */\nfunction cellFrom(target: EventTarget): CellPosition | null {\n if (!(target instanceof Element)) {\n return null;\n }\n const cell = target.closest(\"td[data-gridkit-column]\");\n const row = cell?.parentElement;\n const columnId = cell?.getAttribute(\"data-gridkit-column\");\n if (\n !(cell instanceof HTMLTableCellElement) ||\n !(row instanceof HTMLTableRowElement) ||\n columnId === null ||\n columnId === undefined\n ) {\n return null;\n }\n return {\n rowIndex: row.sectionRowIndex,\n columnIndex: cell.cellIndex,\n columnId,\n };\n}\n\n/**\n * Events are delegated to the body rather than bound per cell, which is what\n * lets `GridRow` be memoised: a handler rebuilt each render is a prop that\n * changes each render, and one reaching every row would defeat the boundary\n * entirely.\n */\nexport default function GridBody<Row>({\n columns,\n rows,\n activeColumnId,\n nav,\n selection,\n}: GridBodyProps<Row>) {\n const { selectedCell, rowMode, cellMode } = selection;\n\n /** The row and cell an event addresses, resolved once for every handler. */\n function targetOf(\n target: EventTarget,\n ): { position: CellPosition; rowId: string } | null {\n const position = cellFrom(target);\n const entry = position === null ? undefined : rows[position.rowIndex];\n return position === null || entry === undefined\n ? null\n : { position, rowId: entry.rowId };\n }\n\n function select(\n rowId: string,\n columnId: string,\n modifiers: { ctrlKey: boolean; metaKey: boolean; shiftKey: boolean },\n ): void {\n const intent = intentOf(modifiers);\n // Independent of each other: selecting a cell says nothing about its row,\n // so a grid with both on reports both.\n if (rowMode !== false) {\n selection.selectRow(rowId, intent);\n }\n if (cellMode !== false) {\n selection.selectCell({ rowId, columnId }, intent);\n }\n }\n\n return (\n <tbody\n className=\"grid-body\"\n onFocus={(event) => {\n const found = targetOf(event.target);\n if (found === null) return;\n nav.focusCell(found.position.rowIndex, found.position.columnIndex);\n }}\n onClick={(event) => {\n const found = targetOf(event.target);\n if (found === null) return;\n select(found.rowId, found.position.columnId, event);\n }}\n onKeyDown={(event) => {\n // Space builds a selection up and Enter replaces it, matching the\n // Ctrl-click and the plain click they stand in for.\n if (event.key === \" \" || event.key === \"Enter\") {\n const found = targetOf(event.target);\n if (found === null) return;\n // Taken whether or not anything is selectable: Space would otherwise\n // scroll the grid out from under the focused cell.\n event.preventDefault();\n select(found.rowId, found.position.columnId, {\n ctrlKey: event.key === \" \" || event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n });\n return;\n }\n nav.onKeyDown(event);\n }}\n >\n {rows.map(({ rowId, row, rowIndex }) => (\n <GridRow<Row>\n key={rowId}\n columns={columns}\n rowId={rowId}\n row={row}\n rowIndex={rowIndex}\n activeColumnId={activeColumnId}\n selectedColumnIds={selection.selectedColumnIds}\n selected={selection.selectedRowIds.has(rowId)}\n /*\n * Narrowed to this row before it crosses the boundary, so that moving\n * the selected cell re-renders the two rows it moved between rather\n * than all of them.\n */\n selectedColumnId={\n selectedCell?.rowId === rowId ? selectedCell.columnId : null\n }\n focusedColumnIndex={\n nav.focus.rowIndex === rowIndex ? nav.focus.columnIndex : null\n }\n rowsSelectable={rowMode !== false}\n cellsSelectable={cellMode !== false}\n />\n ))}\n </tbody>\n );\n}\n","import {\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport {\n movesColumn,\n resolveDropBefore,\n type ColumnOrderState,\n type DropSide,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\n\n/**\n * How far the pointer travels before a press becomes a drag. Below it the\n * gesture is still a click, which is what leaves the header free to take one.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * Where a drop would land. A union rather than the bare id it holds today, so\n * a second drop zone adds a member instead of reshaping this state.\n */\nexport type DropTarget = { kind: \"column-order\"; beforeId: string | null };\n\ninterface UseColumnDragOptions {\n order: ColumnOrderState;\n onDrop: (target: DropTarget, movedId: string) => void;\n}\n\nexport interface ColumnDragApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n draggedColumnId: string | null;\n /** Where it would land if released now. */\n dropTarget: DropTarget | null;\n /** Where the element trailing the pointer sits, as a CSS `transform`. */\n ghostTransform: string | null;\n startDrag: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n /** Moves a column one place left (`-1`) or right (`1`). */\n moveByKeyboard: (entry: ResolvedColumn<Row>, direction: -1 | 1) => void;\n /**\n * Whether the gesture that just ended was a drag rather than a click, for a\n * header that has something of its own to do with a click.\n *\n * Reading it clears it, so that a press which never opened a drag at all —\n * on a column that cannot be reordered — does not see the last one's answer.\n */\n justDragged: () => boolean;\n}\n\n/**\n * The header under `(x, y)`. `closest` is what makes the whole cell the drop\n * zone: a hit on the label or the resize handle resolves to its header.\n */\nfunction headerAt(x: number, y: number): Element | null {\n const element = document.elementFromPoint(x, y);\n return element?.closest(\"th[data-gridkit-column]\") ?? null;\n}\n\n/** Which half of `element` `x` falls in. */\nfunction sideOf(element: Element, x: number): DropSide {\n const rect = element.getBoundingClientRect();\n return x < rect.left + rect.width / 2 ? \"before\" : \"after\";\n}\n\n/**\n * Turns a pointer drag over the header into a drop target, leaving `onDrop` to\n * apply it.\n *\n * Pointer events rather than HTML5 drag-and-drop: `dragenter`/`dragleave` fire\n * per descendant, so the header's text and resize handle would each report the\n * target leaving and re-entering as the pointer crossed them.\n */\nexport default function useColumnDrag<Row>({\n order,\n onDrop,\n}: UseColumnDragOptions): ColumnDragApi<Row> {\n const [draggedColumnId, setDraggedColumnId] = useState<string | null>(null);\n const [dropTarget, setDropTarget] = useState<DropTarget | null>(null);\n const [ghostTransform, setGhostTransform] = useState<string | null>(null);\n const dragged = useRef(false);\n\n function justDragged(): boolean {\n const answer = dragged.current;\n dragged.current = false;\n return answer;\n }\n\n function startDrag(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const header = event.currentTarget;\n // Only the horizontal distance opens the drag: columns move along one\n // axis, so vertical travel says nothing about the user's intent.\n const { pointerId, clientX: startX } = event;\n const grabX = startX - header.getBoundingClientRect().left;\n let dragging = false;\n let target: DropTarget | null = null;\n\n /** Keeps the grab offset, so the pointer holds the spot it picked up. */\n function placeGhost(x: number, y: number): void {\n setGhostTransform(`translate(${String(x - grabX)}px, ${String(y)}px)`);\n }\n\n header.setPointerCapture(pointerId);\n\n function move(moveEvent: PointerEvent): void {\n const { clientX, clientY } = moveEvent;\n\n if (!dragging) {\n if (Math.abs(clientX - startX) < DRAG_THRESHOLD) {\n return;\n }\n dragging = true;\n // Latched for the `click` that follows the release, which is the only\n // thing that can tell a drag apart from a press in the same spot.\n dragged.current = true;\n setDraggedColumnId(entry.id);\n }\n\n placeGhost(clientX, clientY);\n\n // Hit-tested rather than read from the event's target, which pointer\n // capture pins to the header the drag opened on.\n const over = headerAt(clientX, clientY);\n const overId = over?.getAttribute(\"data-gridkit-column\");\n\n // The rect is read fresh each move, so a width changed mid-drag cannot\n // leave the midpoint stale.\n const beforeId =\n over && overId\n ? resolveDropBefore(order, overId, sideOf(over, clientX))\n : undefined;\n\n // A gap the column already sits in would promise a move that\n // `moveColumnBefore` then declines to make.\n target =\n beforeId !== undefined && movesColumn(order, entry.id, beforeId)\n ? { kind: \"column-order\", beforeId }\n : null;\n\n setDropTarget(target);\n }\n\n function stop(): void {\n header.removeEventListener(\"pointermove\", move);\n header.removeEventListener(\"pointerup\", end);\n header.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (header.hasPointerCapture(pointerId)) {\n header.releasePointerCapture(pointerId);\n }\n setGhostTransform(null);\n setDraggedColumnId(null);\n setDropTarget(null);\n }\n\n function end(): void {\n const dropped = target;\n stop();\n if (dragging && dropped !== null) {\n onDrop(dropped, entry.id);\n }\n }\n\n /** Escape and a cancelled pointer both leave the order as it was. */\n function cancel(): void {\n target = null;\n stop();\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n header.addEventListener(\"pointermove\", move);\n header.addEventListener(\"pointerup\", end);\n header.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function moveByKeyboard(entry: ResolvedColumn<Row>, direction: -1 | 1): void {\n const index = order.indexOf(entry.id);\n if (index === -1) {\n return;\n }\n\n /**\n * Moving right lands in front of the id two along: the gap immediately\n * after a column is the one it already sits in.\n */\n const targetIndex = direction === -1 ? index - 1 : index + 2;\n if (targetIndex < 0) {\n return;\n }\n\n onDrop(\n { kind: \"column-order\", beforeId: order[targetIndex] ?? null },\n entry.id,\n );\n }\n\n // A new object each render, as `useColumnResize` returns: the handlers close\n // over `order`, and a stable identity would buy nothing.\n return {\n draggedColumnId,\n dropTarget,\n ghostTransform,\n startDrag,\n moveByKeyboard,\n justDragged,\n };\n}\n","import {\n useState,\n type Dispatch,\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n type SetStateAction,\n} from \"react\";\nimport {\n applyColumnResize,\n beginColumnResize,\n clampColumnWidth,\n resolveColumnConstraints,\n sizeColumnToContent,\n type ColumnResizeEvent,\n type ColumnSizeDefaults,\n type ColumnSizingState,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\nimport measureColumnContent from \"./measureColumnContent\";\n\ninterface UseColumnResizeOptions {\n tableRef: RefObject<HTMLTableElement | null>;\n sizing: ColumnSizingState;\n setSizing: Dispatch<SetStateAction<ColumnSizingState>>;\n columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;\n}\n\nexport interface ColumnResizeApi<Row> {\n /** The column being dragged, for as long as the drag lasts. */\n activeColumnId: string | null;\n startResize: (\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ) => void;\n sizeToContent: (entry: ResolvedColumn<Row>) => void;\n nudge: (entry: ResolvedColumn<Row>, delta: number) => void;\n}\n\n/**\n * Turns pointer and keyboard input into column widths. Every width it produces\n * comes from `@gridkitjs/core`; this hook only supplies the coordinates.\n */\nexport default function useColumnResize<Row>({\n tableRef,\n sizing,\n setSizing,\n columnSizeDefaults,\n onColumnResize,\n}: UseColumnResizeOptions): ColumnResizeApi<Row> {\n const [activeColumnId, setActiveColumnId] = useState<string | null>(null);\n\n function commit(\n base: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n const next = { ...base, [columnId]: width };\n setSizing(next);\n onColumnResize?.({ columnId, width, sizing: next, phase });\n }\n\n function startResize(\n entry: ResolvedColumn<Row>,\n event: ReactPointerEvent<HTMLElement>,\n ): void {\n const handle = event.currentTarget;\n const { pointerId } = event;\n const session = beginColumnResize(\n entry.column,\n entry.width,\n event.clientX,\n columnSizeDefaults,\n );\n /**\n * Only the dragged column can change while the drag lasts, so the state as\n * it was when the drag opened stays a correct base to merge into — no ref\n * mirror is needed to dodge a stale closure.\n */\n const base = sizing;\n let width = session.startWidth;\n\n // Otherwise the drag selects the header text it started on.\n event.preventDefault();\n event.stopPropagation();\n handle.setPointerCapture(pointerId);\n setActiveColumnId(session.columnId);\n\n function move(moveEvent: PointerEvent): void {\n width = applyColumnResize(session, moveEvent.clientX);\n commit(base, session.columnId, width, \"move\");\n }\n\n function stop(): void {\n handle.removeEventListener(\"pointermove\", move);\n handle.removeEventListener(\"pointerup\", end);\n handle.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"keydown\", onKeyDown);\n if (handle.hasPointerCapture(pointerId)) {\n handle.releasePointerCapture(pointerId);\n }\n setActiveColumnId(null);\n }\n\n function end(): void {\n stop();\n // A click with no intervening `move` — as every double-click's two\n // constituent clicks are — leaves `width` at `startWidth`. Committing\n // that anyway would fire a spurious onColumnResize on every click.\n if (width !== session.startWidth) {\n commit(base, session.columnId, width, \"end\");\n }\n }\n\n /**\n * Escape puts back only the dragged column's pre-drag width, merged into\n * whatever the sizing state is *now* — not the `base` snapshot taken at\n * drag-start — so a different column resized via keyboard while this drag\n * was still open keeps its change instead of being clobbered by a stale\n * restore. A column that had no stored width at all is correctly omitted\n * by deleting the key rather than merging `startWidth` back in, which\n * would otherwise leave it pinned and hidden from auto-fit.\n */\n function cancel(): void {\n stop();\n setSizing((current) => {\n const next = Object.fromEntries(\n Object.entries(current).filter(\n ([columnId]) => columnId !== session.columnId,\n ),\n );\n if (session.columnId in base) {\n next[session.columnId] = base[session.columnId] as number;\n }\n onColumnResize?.({\n columnId: session.columnId,\n width: session.startWidth,\n sizing: next,\n phase: \"end\",\n });\n return next;\n });\n }\n\n function onKeyDown(keyEvent: KeyboardEvent): void {\n if (keyEvent.key === \"Escape\") {\n cancel();\n }\n }\n\n handle.addEventListener(\"pointermove\", move);\n handle.addEventListener(\"pointerup\", end);\n handle.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"keydown\", onKeyDown);\n }\n\n function sizeToContent(entry: ResolvedColumn<Row>): void {\n const table = tableRef.current;\n if (table === null) {\n return;\n }\n\n const measured = measureColumnContent(table, entry.id);\n if (measured === null) {\n return;\n }\n\n commit(\n sizing,\n entry.id,\n sizeColumnToContent(\n measured,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n function nudge(entry: ResolvedColumn<Row>, delta: number): void {\n commit(\n sizing,\n entry.id,\n clampColumnWidth(\n entry.width + delta,\n resolveColumnConstraints(entry.column, columnSizeDefaults),\n ),\n \"end\",\n );\n }\n\n // Deliberately a new object each render: the handlers close over `sizing` to\n // merge into, and a stable identity would need either `sizing` in a\n // `useCallback` dep list (no gain) or the ref mirror avoided above.\n return { activeColumnId, startResize, sizeToContent, nudge };\n}\n","/**\n * The width the widest cell in `columnId` needs to show its content in full,\n * or `null` when the column has no cells.\n *\n * Measured with a `Range` over each cell's contents rather than the cell's own\n * `scrollWidth`. A range shrink-wraps what is actually laid out, so a column\n * far wider than its content reports the content width and can be sized *down*;\n * `scrollWidth` never reports less than the cell it is read from and so can\n * only ever grow a column.\n *\n * Only rendered rows are measured — once paging or virtualisation lands, that\n * means the visible ones.\n */\nexport default function measureColumnContent(\n table: HTMLTableElement,\n columnId: string,\n): number | null {\n const cells = table.querySelectorAll<HTMLElement>(\n `td[data-gridkit-column=\"${CSS.escape(columnId)}\"]`,\n );\n const range = document.createRange();\n let widest: number | null = null;\n\n for (const cell of cells) {\n range.selectNodeContents(cell);\n const style = getComputedStyle(cell);\n // The range covers the content box only, so the cell's own spacing has to\n // be added back or the column would clip by exactly its padding.\n const width =\n range.getBoundingClientRect().width +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth);\n\n if (widest === null || width > widest) {\n widest = width;\n }\n }\n\n return widest;\n}\n","import type { Dispatch, SetStateAction } from \"react\";\nimport {\n sortDirectionFor,\n sortPriorityFor,\n toggleColumnSort,\n type ColumnSortEvent,\n type ColumnSortState,\n type SortDirection,\n} from \"@gridkitjs/core\";\nimport type { ResolvedColumn } from \"./DataGrid\";\n\ninterface UseColumnSortOptions {\n sort: ColumnSortState;\n setSort: Dispatch<SetStateAction<ColumnSortState>>;\n onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;\n}\n\nexport interface ColumnSortApi<Row> {\n sort: ColumnSortState;\n /** This column's direction, or `null` if it takes no part in the sort. */\n directionFor: (columnId: string) => SortDirection | null;\n /**\n * This column's 1-based place in the stack, or `null` outside it. Only\n * meaningful once two or more columns are stacked.\n */\n priorityFor: (columnId: string) => number | null;\n /** Cycles `entry`'s sort. A `shiftKey` stacks it; its absence replaces the stack. */\n toggle: (entry: ResolvedColumn<Row>, event: { shiftKey: boolean }) => void;\n}\n\n/**\n * Turns a click or keypress into a sort. Every transition it produces comes\n * from `@gridkitjs/core`; this hook only supplies the state to transform and\n * reports the result.\n */\nexport default function useColumnSort<Row>({\n sort,\n setSort,\n onColumnSortChange,\n}: UseColumnSortOptions): ColumnSortApi<Row> {\n function toggle(\n entry: ResolvedColumn<Row>,\n event: { shiftKey: boolean },\n ): void {\n const next = toggleColumnSort(sort, entry.id, { stack: event.shiftKey });\n if (next === sort) {\n return;\n }\n setSort(next);\n onColumnSortChange?.({ columnId: entry.id, sort: next });\n }\n\n // A new object each render, as the other hooks here return.\n return {\n sort,\n directionFor: (columnId) => sortDirectionFor(sort, columnId),\n priorityFor: (columnId) => sortPriorityFor(sort, columnId),\n toggle,\n };\n}\n","import { useLayoutEffect, useState, type RefObject } from \"react\";\n\n/**\n * The inner width of `ref`'s element, tracked as it changes.\n *\n * A layout effect rather than an effect so the first measurement lands before\n * paint — otherwise columns show at their natural width for a frame and then\n * visibly jump once auto-fit runs. Server rendering would want the usual\n * isomorphic-layout-effect shim here.\n *\n * Reads `clientWidth` rather than the observer entry's `contentRect` so the\n * first measurement and every later one come from the same, already-rounded,\n * source.\n *\n * @param enabled Whether to observe at all. A caller that does not read the\n * width passes `false` rather than paying a re-render of the whole grid on\n * every frame of a window resize.\n */\nexport default function useElementWidth(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean,\n): number | null {\n const [width, setWidth] = useState<number | null>(null);\n\n useLayoutEffect(() => {\n const element = ref.current;\n if (element === null || !enabled) {\n return undefined;\n }\n\n setWidth(element.clientWidth);\n\n const observer = new ResizeObserver(() => {\n setWidth(element.clientWidth);\n });\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n };\n }, [ref, enabled]);\n\n return width;\n}\n"],"mappings":"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","names":["useMemo","useRef","useState","useRef","accessDotted","jsx","jsx","useRef","useState","useState","useState","useState","jsx","jsxs","useRef","useState","useMemo"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gridkitjs/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React data-grid components built on @gridkitjs/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blagoja Blazhevski",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"react-dom": "^19.0.0"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@gridkitjs/core": "0.
|
|
43
|
+
"@gridkitjs/core": "0.6.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/react": "^19.2.18",
|