@human-kit/svelte-components 1.0.0-alpha.13 → 1.0.0-alpha.14
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/checkbox/root/checkbox-root.svelte +22 -2
- package/dist/checkbox/root/checkbox-root.svelte.d.ts +4 -1
- package/dist/combobox/root/combobox.svelte +1 -0
- package/dist/listbox/item/listbox-item.svelte +13 -0
- package/dist/listbox/root/listbox.svelte +7 -1
- package/dist/table/IMPLEMENTATION_NOTES.md +2 -1
- package/dist/table/PLAN.md +440 -17
- package/dist/table/TODO.md +39 -1
- package/dist/table/cell/table-cell.svelte +86 -79
- package/dist/table/checkbox/table-checkbox-test.svelte +7 -0
- package/dist/table/checkbox/table-checkbox-test.svelte.d.ts +3 -1
- package/dist/table/checkbox/table-checkbox.svelte +55 -30
- package/dist/table/index.d.ts +1 -1
- package/dist/table/root/context.d.ts +16 -1
- package/dist/table/root/context.js +199 -24
- package/dist/table/root/table-root.svelte +30 -0
- package/dist/table/root/table-root.svelte.d.ts +4 -1
- package/dist/table/root/table-test.svelte +29 -0
- package/dist/table/root/table-test.svelte.d.ts +5 -1
- package/dist/table/row/table-row.svelte +44 -67
- package/dist/table/utils/handle-body-keydown.d.ts +13 -0
- package/dist/table/utils/handle-body-keydown.js +67 -0
- package/package.json +1 -1
|
@@ -8,6 +8,9 @@ const TABLE_CELL_KEY = Symbol('table-cell');
|
|
|
8
8
|
export function createTableContext(options = {}) {
|
|
9
9
|
let selectionMode = options.selectionMode ?? 'none';
|
|
10
10
|
let selectionBehavior = options.selectionBehavior ?? 'toggle';
|
|
11
|
+
let disabledBehavior = options.disabledBehavior ?? 'all';
|
|
12
|
+
let disallowEmptySelection = options.disallowEmptySelection ?? false;
|
|
13
|
+
let onRowAction = options.onRowAction;
|
|
11
14
|
let sortDescriptor = options.initialSortDescriptor;
|
|
12
15
|
let focusedCellKey = null;
|
|
13
16
|
let focusedRowTarget = null;
|
|
@@ -35,6 +38,7 @@ export function createTableContext(options = {}) {
|
|
|
35
38
|
let orderedColumnTokensCache = null;
|
|
36
39
|
let visibleOrderedColumnTokensCache = null;
|
|
37
40
|
let columnWidthsCache = null;
|
|
41
|
+
let visibleColumnWidthsCache = null;
|
|
38
42
|
let navigableCellsCache = null;
|
|
39
43
|
let rowsWithCellsCache = null;
|
|
40
44
|
const layoutVersion = writable(0);
|
|
@@ -44,6 +48,7 @@ export function createTableContext(options = {}) {
|
|
|
44
48
|
const widthVersion = writable(0);
|
|
45
49
|
const resizeVersion = writable(0);
|
|
46
50
|
const instanceCounters = new Map();
|
|
51
|
+
const selectionUnavailableDescriptionId = createInstanceToken('selection-unavailable');
|
|
47
52
|
function createInstanceToken(prefix) {
|
|
48
53
|
const nextCount = (instanceCounters.get(prefix) ?? 0) + 1;
|
|
49
54
|
instanceCounters.set(prefix, nextCount);
|
|
@@ -54,6 +59,7 @@ export function createTableContext(options = {}) {
|
|
|
54
59
|
orderedColumnTokensCache = null;
|
|
55
60
|
visibleOrderedColumnTokensCache = null;
|
|
56
61
|
columnWidthsCache = null;
|
|
62
|
+
visibleColumnWidthsCache = null;
|
|
57
63
|
navigableCellsCache = null;
|
|
58
64
|
rowsWithCellsCache = null;
|
|
59
65
|
}
|
|
@@ -81,6 +87,7 @@ export function createTableContext(options = {}) {
|
|
|
81
87
|
}
|
|
82
88
|
function notifyWidth() {
|
|
83
89
|
columnWidthsCache = null;
|
|
90
|
+
visibleColumnWidthsCache = null;
|
|
84
91
|
if (!widthNotifyScheduled) {
|
|
85
92
|
widthNotifyScheduled = true;
|
|
86
93
|
queueMicrotask(() => {
|
|
@@ -300,12 +307,15 @@ export function createTableContext(options = {}) {
|
|
|
300
307
|
return widths;
|
|
301
308
|
}
|
|
302
309
|
function getVisibleColumnWidths() {
|
|
310
|
+
if (visibleColumnWidthsCache)
|
|
311
|
+
return visibleColumnWidthsCache;
|
|
303
312
|
const widths = new Map();
|
|
304
313
|
for (const [columnId, width] of getColumnWidths()) {
|
|
305
314
|
if (isColumnHidden(columnId))
|
|
306
315
|
continue;
|
|
307
316
|
widths.set(columnId, width);
|
|
308
317
|
}
|
|
318
|
+
visibleColumnWidthsCache = widths;
|
|
309
319
|
return widths;
|
|
310
320
|
}
|
|
311
321
|
function getMeasuredHeaderWidth(columnToken) {
|
|
@@ -444,6 +454,33 @@ export function createTableContext(options = {}) {
|
|
|
444
454
|
focusedRowTarget = null;
|
|
445
455
|
notifyFocus();
|
|
446
456
|
}
|
|
457
|
+
function reconcileFocusAfterDisabledStateChange() {
|
|
458
|
+
if (focusedCellKey) {
|
|
459
|
+
const focusedCell = cells.get(focusedCellKey);
|
|
460
|
+
if (focusedCell &&
|
|
461
|
+
focusedCell.section === 'body' &&
|
|
462
|
+
isRowDisabled(rows.get(focusedCell.rowToken)?.id, rows.get(focusedCell.rowToken)?.disabled)) {
|
|
463
|
+
moveFocus('down');
|
|
464
|
+
const nextFocusedCell = cells.get(focusedCellKey ?? '');
|
|
465
|
+
if (nextFocusedCell?.section === 'body' &&
|
|
466
|
+
isRowDisabled(rows.get(nextFocusedCell.rowToken)?.id, rows.get(nextFocusedCell.rowToken)?.disabled)) {
|
|
467
|
+
moveFocus('up');
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (focusedRowTarget) {
|
|
472
|
+
const focusedRow = rows.get(focusedRowTarget.rowToken);
|
|
473
|
+
if (focusedRow && isRowDisabled(focusedRow.id, focusedRow.disabled)) {
|
|
474
|
+
const nextToken = getFocusableBodyRowToken('start');
|
|
475
|
+
if (nextToken) {
|
|
476
|
+
setFocusedRow(nextToken, focusedRowTarget.edge);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
setFocusedRow(null);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
447
484
|
function setHiddenColumns(columnIds) {
|
|
448
485
|
const next = new Set(columnIds ?? []);
|
|
449
486
|
let changed = next.size !== hiddenColumnIds.size;
|
|
@@ -635,19 +672,28 @@ export function createTableContext(options = {}) {
|
|
|
635
672
|
const row = rows.get(token);
|
|
636
673
|
if (!row?.id)
|
|
637
674
|
continue;
|
|
638
|
-
if (
|
|
675
|
+
if (isRowSelectionDisabled(row.id, row.disabled))
|
|
639
676
|
continue;
|
|
640
677
|
rowIds.push(row.id);
|
|
641
678
|
}
|
|
642
679
|
return rowIds;
|
|
643
680
|
}
|
|
644
|
-
function
|
|
681
|
+
function isRowSelectionDisabled(id, localDisabled = false) {
|
|
645
682
|
if (localDisabled)
|
|
646
683
|
return true;
|
|
647
684
|
if (id === undefined)
|
|
648
685
|
return false;
|
|
649
686
|
return disabledKeys.has(id);
|
|
650
687
|
}
|
|
688
|
+
function isRowDisabled(id, localDisabled = false) {
|
|
689
|
+
return disabledBehavior === 'all' && isRowSelectionDisabled(id, localDisabled);
|
|
690
|
+
}
|
|
691
|
+
function isRowActionDisabled(id, localDisabled = false) {
|
|
692
|
+
return disabledBehavior === 'all' && isRowSelectionDisabled(id, localDisabled);
|
|
693
|
+
}
|
|
694
|
+
function isRowActionable(id, localDisabled = false) {
|
|
695
|
+
return Boolean(onRowAction) && id !== undefined && !isRowActionDisabled(id, localDisabled);
|
|
696
|
+
}
|
|
651
697
|
function isRowSelected(id) {
|
|
652
698
|
if (id === undefined)
|
|
653
699
|
return false;
|
|
@@ -919,12 +965,25 @@ export function createTableContext(options = {}) {
|
|
|
919
965
|
return true;
|
|
920
966
|
}
|
|
921
967
|
function setSelectedKeys(next, anchor) {
|
|
968
|
+
const previousSelectedKeys = new Set(selectedKeys);
|
|
922
969
|
selectedKeys =
|
|
923
970
|
selectionMode === 'none'
|
|
924
971
|
? new Set()
|
|
925
972
|
: selectionMode === 'single' && next.size > 1
|
|
926
973
|
? new Set([next.values().next().value])
|
|
927
974
|
: next;
|
|
975
|
+
if (selectionMode !== 'none' && disallowEmptySelection && selectedKeys.size === 0) {
|
|
976
|
+
const fallbackKey = (anchor !== undefined && anchor !== null && !isRowSelectionDisabled(anchor)
|
|
977
|
+
? anchor
|
|
978
|
+
: previousSelectedKeys.values().next().value) ??
|
|
979
|
+
getFocusedRowId() ??
|
|
980
|
+
getOrderedSelectableRowIds()[0];
|
|
981
|
+
if (fallbackKey !== undefined &&
|
|
982
|
+
fallbackKey !== null &&
|
|
983
|
+
!isRowSelectionDisabled(fallbackKey)) {
|
|
984
|
+
selectedKeys = new Set([fallbackKey]);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
928
987
|
const fallbackAnchor = selectedKeys.values().next().value ?? null;
|
|
929
988
|
if (anchor === undefined) {
|
|
930
989
|
selectionAnchorKey = fallbackAnchor;
|
|
@@ -933,18 +992,35 @@ export function createTableContext(options = {}) {
|
|
|
933
992
|
selectionAnchorKey = anchor === null || selectedKeys.has(anchor) ? anchor : fallbackAnchor;
|
|
934
993
|
}
|
|
935
994
|
function replaceSelectionWithRow(id) {
|
|
936
|
-
if (id === undefined ||
|
|
995
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
996
|
+
return;
|
|
997
|
+
const next = new Set([id]);
|
|
998
|
+
if (hasSameSelection(selectedKeys, next)) {
|
|
999
|
+
setSelectedKeys(next, id);
|
|
1000
|
+
notifySelection();
|
|
937
1001
|
return;
|
|
938
|
-
|
|
1002
|
+
}
|
|
1003
|
+
setSelectedKeys(next, id);
|
|
939
1004
|
emitSelectionChange();
|
|
940
1005
|
}
|
|
1006
|
+
function applySelectionChange(next, anchor) {
|
|
1007
|
+
const previousSelection = new Set(selectedKeys);
|
|
1008
|
+
const previousAnchor = selectionAnchorKey;
|
|
1009
|
+
setSelectedKeys(next, anchor);
|
|
1010
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1011
|
+
emitSelectionChange();
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
if (!hasSameSelection(next, selectedKeys) || previousAnchor !== selectionAnchorKey) {
|
|
1015
|
+
notifySelection();
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
941
1018
|
function toggleSelectionForRow(id) {
|
|
942
|
-
if (id === undefined ||
|
|
1019
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
943
1020
|
return;
|
|
944
1021
|
if (selectionMode === 'single') {
|
|
945
1022
|
const wasSelected = selectedKeys.has(id);
|
|
946
|
-
|
|
947
|
-
emitSelectionChange();
|
|
1023
|
+
applySelectionChange(selectionBehavior === 'toggle' && wasSelected ? new Set() : new Set([id]), selectionBehavior === 'toggle' && wasSelected ? null : id);
|
|
948
1024
|
return;
|
|
949
1025
|
}
|
|
950
1026
|
const next = new Set(selectedKeys);
|
|
@@ -954,11 +1030,10 @@ export function createTableContext(options = {}) {
|
|
|
954
1030
|
else {
|
|
955
1031
|
next.add(id);
|
|
956
1032
|
}
|
|
957
|
-
|
|
958
|
-
emitSelectionChange();
|
|
1033
|
+
applySelectionChange(next, id);
|
|
959
1034
|
}
|
|
960
1035
|
function extendSelectionToRow(id, anchorOverride) {
|
|
961
|
-
if (id === undefined ||
|
|
1036
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
962
1037
|
return;
|
|
963
1038
|
if (selectionMode !== 'multiple') {
|
|
964
1039
|
replaceSelectionWithRow(id);
|
|
@@ -979,11 +1054,18 @@ export function createTableContext(options = {}) {
|
|
|
979
1054
|
}
|
|
980
1055
|
const start = Math.min(anchorIndex, targetIndex);
|
|
981
1056
|
const end = Math.max(anchorIndex, targetIndex);
|
|
982
|
-
|
|
983
|
-
emitSelectionChange();
|
|
1057
|
+
applySelectionChange(new Set(orderedIds.slice(start, end + 1)), anchor);
|
|
984
1058
|
}
|
|
985
|
-
function
|
|
986
|
-
if (
|
|
1059
|
+
function performRowAction(id) {
|
|
1060
|
+
if (!onRowAction || id === undefined || isRowActionDisabled(id))
|
|
1061
|
+
return;
|
|
1062
|
+
onRowAction(id);
|
|
1063
|
+
}
|
|
1064
|
+
function hasActiveSelection() {
|
|
1065
|
+
return selectedKeys.size > 0;
|
|
1066
|
+
}
|
|
1067
|
+
function pressRowSelection(id, interaction = {}) {
|
|
1068
|
+
if (selectionMode === 'none' || id === undefined || isRowSelectionDisabled(id))
|
|
987
1069
|
return;
|
|
988
1070
|
if (selectionBehavior === 'replace' && selectionMode === 'multiple') {
|
|
989
1071
|
if (interaction.shiftKey) {
|
|
@@ -999,6 +1081,55 @@ export function createTableContext(options = {}) {
|
|
|
999
1081
|
}
|
|
1000
1082
|
toggleSelectionForRow(id);
|
|
1001
1083
|
}
|
|
1084
|
+
function pressRow(id, source, interaction = {}, localDisabled = false) {
|
|
1085
|
+
if (id === undefined)
|
|
1086
|
+
return;
|
|
1087
|
+
if (isRowDisabled(id, localDisabled))
|
|
1088
|
+
return;
|
|
1089
|
+
if (source === 'keyboard-enter') {
|
|
1090
|
+
if (onRowAction) {
|
|
1091
|
+
performRowAction(id);
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
pressRowSelection(id, interaction);
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
if (source === 'keyboard-space') {
|
|
1098
|
+
if (interaction.shiftKey) {
|
|
1099
|
+
extendSelectionToRow(id);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
if (interaction.ctrlKey || interaction.metaKey) {
|
|
1103
|
+
toggleSelectionForRow(id);
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
toggleRowSelection(id);
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
if (source === 'pointer-double') {
|
|
1110
|
+
if (onRowAction && selectionMode !== 'none' && selectionBehavior === 'replace') {
|
|
1111
|
+
performRowAction(id);
|
|
1112
|
+
}
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
if (!onRowAction) {
|
|
1116
|
+
pressRowSelection(id, interaction);
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
if (selectionMode === 'none') {
|
|
1120
|
+
performRowAction(id);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
if (selectionBehavior === 'replace') {
|
|
1124
|
+
pressRowSelection(id, interaction);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (hasActiveSelection()) {
|
|
1128
|
+
pressRowSelection(id, interaction);
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
performRowAction(id);
|
|
1132
|
+
}
|
|
1002
1133
|
function moveFocus(direction, interaction = {}) {
|
|
1003
1134
|
const rowMap = getRowsWithCells();
|
|
1004
1135
|
const currentCoord = getFocusedCoord();
|
|
@@ -1166,12 +1297,11 @@ export function createTableContext(options = {}) {
|
|
|
1166
1297
|
notifySelection();
|
|
1167
1298
|
}
|
|
1168
1299
|
function toggleRowSelection(id) {
|
|
1169
|
-
if (selectionMode === 'none' || id === undefined ||
|
|
1300
|
+
if (selectionMode === 'none' || id === undefined || isRowSelectionDisabled(id))
|
|
1170
1301
|
return;
|
|
1171
1302
|
if (selectionMode === 'single') {
|
|
1172
1303
|
const wasSelected = selectedKeys.has(id);
|
|
1173
|
-
|
|
1174
|
-
emitSelectionChange();
|
|
1304
|
+
applySelectionChange(wasSelected ? new Set() : new Set([id]), wasSelected ? null : id);
|
|
1175
1305
|
return;
|
|
1176
1306
|
}
|
|
1177
1307
|
const next = new Set(selectedKeys);
|
|
@@ -1181,8 +1311,7 @@ export function createTableContext(options = {}) {
|
|
|
1181
1311
|
else {
|
|
1182
1312
|
next.add(id);
|
|
1183
1313
|
}
|
|
1184
|
-
|
|
1185
|
-
emitSelectionChange();
|
|
1314
|
+
applySelectionChange(next, id);
|
|
1186
1315
|
}
|
|
1187
1316
|
function selectAllRows() {
|
|
1188
1317
|
if (selectionMode !== 'multiple')
|
|
@@ -1190,7 +1319,7 @@ export function createTableContext(options = {}) {
|
|
|
1190
1319
|
const next = new Set();
|
|
1191
1320
|
for (const token of getOrderedRowTokens('body')) {
|
|
1192
1321
|
const row = rows.get(token);
|
|
1193
|
-
if (!row?.id ||
|
|
1322
|
+
if (!row?.id || isRowSelectionDisabled(row.id, row.disabled))
|
|
1194
1323
|
continue;
|
|
1195
1324
|
next.add(row.id);
|
|
1196
1325
|
}
|
|
@@ -1200,14 +1329,21 @@ export function createTableContext(options = {}) {
|
|
|
1200
1329
|
function deselectAllRows() {
|
|
1201
1330
|
if (selectedKeys.size === 0)
|
|
1202
1331
|
return;
|
|
1203
|
-
|
|
1204
|
-
emitSelectionChange();
|
|
1332
|
+
applySelectionChange(new Set(), null);
|
|
1205
1333
|
}
|
|
1206
1334
|
function setSelection(keys) {
|
|
1335
|
+
const previousSelection = new Set(selectedKeys);
|
|
1336
|
+
const previousAnchor = selectionAnchorKey;
|
|
1207
1337
|
const next = new Set(keys);
|
|
1208
1338
|
const preservedAnchor = selectionAnchorKey !== null && next.has(selectionAnchorKey) ? selectionAnchorKey : undefined;
|
|
1209
1339
|
setSelectedKeys(next, preservedAnchor);
|
|
1210
|
-
|
|
1340
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1341
|
+
emitSelectionChange();
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
if (previousAnchor !== selectionAnchorKey) {
|
|
1345
|
+
notifySelection();
|
|
1346
|
+
}
|
|
1211
1347
|
}
|
|
1212
1348
|
function setSelectionMode(mode) {
|
|
1213
1349
|
const previousSelectedKeys = new Set(selectedKeys);
|
|
@@ -1225,6 +1361,23 @@ export function createTableContext(options = {}) {
|
|
|
1225
1361
|
selectionBehavior = behavior;
|
|
1226
1362
|
notifySelection();
|
|
1227
1363
|
}
|
|
1364
|
+
function setDisabledBehavior(behavior) {
|
|
1365
|
+
disabledBehavior = behavior;
|
|
1366
|
+
invalidateLayoutCaches();
|
|
1367
|
+
reconcileFocusAfterDisabledStateChange();
|
|
1368
|
+
notifyLayout();
|
|
1369
|
+
notifySelection();
|
|
1370
|
+
}
|
|
1371
|
+
function setDisallowEmptySelection(disallow) {
|
|
1372
|
+
disallowEmptySelection = disallow;
|
|
1373
|
+
const previousSelection = new Set(selectedKeys);
|
|
1374
|
+
setSelectedKeys(new Set(selectedKeys), selectionAnchorKey);
|
|
1375
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1376
|
+
emitSelectionChange();
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
notifySelection();
|
|
1380
|
+
}
|
|
1228
1381
|
function setDisabledKeys(keys) {
|
|
1229
1382
|
disabledKeys.clear();
|
|
1230
1383
|
if (keys) {
|
|
@@ -1232,6 +1385,13 @@ export function createTableContext(options = {}) {
|
|
|
1232
1385
|
disabledKeys.add(key);
|
|
1233
1386
|
}
|
|
1234
1387
|
}
|
|
1388
|
+
invalidateLayoutCaches();
|
|
1389
|
+
reconcileFocusAfterDisabledStateChange();
|
|
1390
|
+
notifyLayout();
|
|
1391
|
+
notifySelection();
|
|
1392
|
+
}
|
|
1393
|
+
function setRowActionHandler(handler) {
|
|
1394
|
+
onRowAction = handler;
|
|
1235
1395
|
notifySelection();
|
|
1236
1396
|
}
|
|
1237
1397
|
function setSortDescriptor(descriptor) {
|
|
@@ -1240,7 +1400,7 @@ export function createTableContext(options = {}) {
|
|
|
1240
1400
|
notifySort();
|
|
1241
1401
|
}
|
|
1242
1402
|
function isColumnSortable(columnId) {
|
|
1243
|
-
return
|
|
1403
|
+
return getColumnRegistrationById(columnId)?.allowsSorting ?? false;
|
|
1244
1404
|
}
|
|
1245
1405
|
function toggleSort(columnId) {
|
|
1246
1406
|
if (!isColumnSortable(columnId))
|
|
@@ -1273,6 +1433,15 @@ export function createTableContext(options = {}) {
|
|
|
1273
1433
|
get selectionBehavior() {
|
|
1274
1434
|
return selectionBehavior;
|
|
1275
1435
|
},
|
|
1436
|
+
get disabledBehavior() {
|
|
1437
|
+
return disabledBehavior;
|
|
1438
|
+
},
|
|
1439
|
+
get disallowEmptySelection() {
|
|
1440
|
+
return disallowEmptySelection;
|
|
1441
|
+
},
|
|
1442
|
+
get selectionUnavailableDescriptionId() {
|
|
1443
|
+
return selectionUnavailableDescriptionId;
|
|
1444
|
+
},
|
|
1276
1445
|
disabledKeys,
|
|
1277
1446
|
get focusedCellKey() {
|
|
1278
1447
|
return focusedCellKey;
|
|
@@ -1321,6 +1490,9 @@ export function createTableContext(options = {}) {
|
|
|
1321
1490
|
isRowFocusTarget,
|
|
1322
1491
|
getRowFocusEdge,
|
|
1323
1492
|
isRowDisabled,
|
|
1493
|
+
isRowSelectionDisabled,
|
|
1494
|
+
isRowActionDisabled,
|
|
1495
|
+
isRowActionable,
|
|
1324
1496
|
hasSelectableRows,
|
|
1325
1497
|
getSelectionCheckboxState,
|
|
1326
1498
|
registerCell,
|
|
@@ -1347,7 +1519,10 @@ export function createTableContext(options = {}) {
|
|
|
1347
1519
|
setSelection,
|
|
1348
1520
|
setSelectionMode,
|
|
1349
1521
|
setSelectionBehavior,
|
|
1522
|
+
setDisabledBehavior,
|
|
1523
|
+
setDisallowEmptySelection,
|
|
1350
1524
|
setDisabledKeys,
|
|
1525
|
+
setRowActionHandler,
|
|
1351
1526
|
setSortDescriptor,
|
|
1352
1527
|
toggleSort,
|
|
1353
1528
|
isColumnSortable,
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
import {
|
|
18
18
|
createTableContext,
|
|
19
19
|
setTableContext,
|
|
20
|
+
type TableDisabledBehavior,
|
|
21
|
+
type TableRowActionHandler,
|
|
20
22
|
type TableContext,
|
|
21
23
|
type TableSelectionBehavior,
|
|
22
24
|
type TableSelectionKey,
|
|
@@ -31,6 +33,8 @@
|
|
|
31
33
|
type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
|
|
32
34
|
selectionMode?: TableSelectionMode;
|
|
33
35
|
selectionBehavior?: TableSelectionBehavior;
|
|
36
|
+
disabledBehavior?: TableDisabledBehavior;
|
|
37
|
+
disallowEmptySelection?: boolean;
|
|
34
38
|
hiddenColumns?: Iterable<string>;
|
|
35
39
|
defaultHiddenColumns?: Iterable<string>;
|
|
36
40
|
selectedKeys?: Iterable<TableSelectionKey>;
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
columnWidths?: Map<string, number>;
|
|
41
45
|
defaultColumnWidths?: Iterable<readonly [string, number]>;
|
|
42
46
|
disabledKeys?: Iterable<TableSelectionKey>;
|
|
47
|
+
onRowAction?: TableRowActionHandler;
|
|
43
48
|
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
44
49
|
onSortChange?: (descriptor: TableSortDescriptor | undefined) => void;
|
|
45
50
|
onColumnWidthsChange?: (widths: Map<string, number>) => void;
|
|
@@ -55,6 +60,8 @@
|
|
|
55
60
|
let {
|
|
56
61
|
selectionMode = 'none',
|
|
57
62
|
selectionBehavior = 'toggle',
|
|
63
|
+
disabledBehavior = 'all',
|
|
64
|
+
disallowEmptySelection = false,
|
|
58
65
|
hiddenColumns = $bindable(),
|
|
59
66
|
defaultHiddenColumns,
|
|
60
67
|
selectedKeys = $bindable(),
|
|
@@ -66,6 +73,7 @@
|
|
|
66
73
|
'aria-label': ariaLabel,
|
|
67
74
|
'aria-labelledby': ariaLabelledby,
|
|
68
75
|
disabledKeys,
|
|
76
|
+
onRowAction,
|
|
69
77
|
onSelectionChange,
|
|
70
78
|
onSortChange,
|
|
71
79
|
onColumnWidthsChange,
|
|
@@ -94,11 +102,14 @@
|
|
|
94
102
|
createTableContext({
|
|
95
103
|
selectionMode: (() => selectionMode)(),
|
|
96
104
|
selectionBehavior: (() => selectionBehavior)(),
|
|
105
|
+
disabledBehavior: (() => disabledBehavior)(),
|
|
106
|
+
disallowEmptySelection: (() => disallowEmptySelection)(),
|
|
97
107
|
initialHiddenColumns: (() => hiddenColumns ?? defaultHiddenColumns)(),
|
|
98
108
|
initialSelectedKeys: (() => selectedKeys ?? defaultSelectedKeys)(),
|
|
99
109
|
initialSortDescriptor: (() => sortDescriptor ?? defaultSortDescriptor)(),
|
|
100
110
|
initialColumnWidths: (() => columnWidths ?? defaultColumnWidths)(),
|
|
101
111
|
disabledKeys: (() => disabledKeys)(),
|
|
112
|
+
onRowAction: (() => onRowAction)(),
|
|
102
113
|
onHiddenColumnsChange: (columnIds) => {
|
|
103
114
|
pendingControlledHiddenColumns = [...columnIds];
|
|
104
115
|
hiddenColumns = [...columnIds];
|
|
@@ -270,10 +281,22 @@
|
|
|
270
281
|
ctx.setSelectionBehavior(selectionBehavior);
|
|
271
282
|
});
|
|
272
283
|
|
|
284
|
+
$effect(() => {
|
|
285
|
+
ctx.setDisabledBehavior(disabledBehavior);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
$effect(() => {
|
|
289
|
+
ctx.setDisallowEmptySelection(disallowEmptySelection);
|
|
290
|
+
});
|
|
291
|
+
|
|
273
292
|
$effect(() => {
|
|
274
293
|
ctx.setDisabledKeys(disabledKeys);
|
|
275
294
|
});
|
|
276
295
|
|
|
296
|
+
$effect(() => {
|
|
297
|
+
ctx.setRowActionHandler(onRowAction);
|
|
298
|
+
});
|
|
299
|
+
|
|
277
300
|
$effect(() => {
|
|
278
301
|
if (selectedKeys !== undefined) {
|
|
279
302
|
const nextSelection = parseSelection(selectedKeys);
|
|
@@ -388,6 +411,7 @@
|
|
|
388
411
|
aria-multiselectable={selectionMode === 'multiple' ? true : undefined}
|
|
389
412
|
data-selection-mode={selectionMode}
|
|
390
413
|
data-selection-behavior={selectionBehavior}
|
|
414
|
+
data-disabled-behavior={disabledBehavior}
|
|
391
415
|
data-focus-within={focusWithin || undefined}
|
|
392
416
|
data-focus-visible={focusVisible || undefined}
|
|
393
417
|
onfocusin={handleFocusIn}
|
|
@@ -408,3 +432,9 @@
|
|
|
408
432
|
style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;"
|
|
409
433
|
>{sortAnnouncement}</span
|
|
410
434
|
>
|
|
435
|
+
|
|
436
|
+
<span
|
|
437
|
+
id={ctx.selectionUnavailableDescriptionId}
|
|
438
|
+
style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;"
|
|
439
|
+
>Selection unavailable for this row.</span
|
|
440
|
+
>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import { type TableContext, type TableSelectionBehavior, type TableSelectionKey, type TableSelectionMode, type TableSortDescriptor } from './context';
|
|
3
|
+
import { type TableDisabledBehavior, type TableRowActionHandler, type TableContext, type TableSelectionBehavior, type TableSelectionKey, type TableSelectionMode, type TableSortDescriptor } from './context';
|
|
4
4
|
type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
|
|
5
5
|
selectionMode?: TableSelectionMode;
|
|
6
6
|
selectionBehavior?: TableSelectionBehavior;
|
|
7
|
+
disabledBehavior?: TableDisabledBehavior;
|
|
8
|
+
disallowEmptySelection?: boolean;
|
|
7
9
|
hiddenColumns?: Iterable<string>;
|
|
8
10
|
defaultHiddenColumns?: Iterable<string>;
|
|
9
11
|
selectedKeys?: Iterable<TableSelectionKey>;
|
|
@@ -13,6 +15,7 @@ type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
|
|
|
13
15
|
columnWidths?: Map<string, number>;
|
|
14
16
|
defaultColumnWidths?: Iterable<readonly [string, number]>;
|
|
15
17
|
disabledKeys?: Iterable<TableSelectionKey>;
|
|
18
|
+
onRowAction?: TableRowActionHandler;
|
|
16
19
|
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
17
20
|
onSortChange?: (descriptor: TableSortDescriptor | undefined) => void;
|
|
18
21
|
onColumnWidthsChange?: (widths: Map<string, number>) => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Table } from '../index';
|
|
3
3
|
import type {
|
|
4
|
+
TableDisabledBehavior,
|
|
4
5
|
TableSelectionBehavior,
|
|
5
6
|
TableSelectionKey,
|
|
6
7
|
TableSelectionMode,
|
|
@@ -25,11 +26,15 @@
|
|
|
25
26
|
ariaLabelledby?: string;
|
|
26
27
|
selectionMode?: TableSelectionMode;
|
|
27
28
|
selectionBehavior?: TableSelectionBehavior;
|
|
29
|
+
disabledBehavior?: TableDisabledBehavior;
|
|
30
|
+
disallowEmptySelection?: boolean;
|
|
28
31
|
hiddenColumns?: string[];
|
|
29
32
|
defaultHiddenColumns?: string[];
|
|
30
33
|
disabledKeys?: Iterable<TableSelectionKey>;
|
|
31
34
|
initialSelectedKeys?: Iterable<TableSelectionKey>;
|
|
32
35
|
initialSortDescriptor?: TableSortDescriptor;
|
|
36
|
+
onRowAction?: (id: TableSelectionKey) => void;
|
|
37
|
+
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
33
38
|
showSelectionModeToggle?: boolean;
|
|
34
39
|
showSingleSelectionModeToggle?: boolean;
|
|
35
40
|
showSortClearButton?: boolean;
|
|
@@ -42,11 +47,15 @@
|
|
|
42
47
|
ariaLabelledby,
|
|
43
48
|
selectionMode = $bindable<TableSelectionMode>('multiple'),
|
|
44
49
|
selectionBehavior = 'toggle',
|
|
50
|
+
disabledBehavior = 'all',
|
|
51
|
+
disallowEmptySelection = false,
|
|
45
52
|
hiddenColumns = $bindable<string[] | undefined>(),
|
|
46
53
|
defaultHiddenColumns,
|
|
47
54
|
disabledKeys,
|
|
48
55
|
initialSelectedKeys,
|
|
49
56
|
initialSortDescriptor,
|
|
57
|
+
onRowAction,
|
|
58
|
+
onSelectionChange,
|
|
50
59
|
showSelectionModeToggle = false,
|
|
51
60
|
showSingleSelectionModeToggle = false,
|
|
52
61
|
showSortClearButton = false,
|
|
@@ -59,6 +68,8 @@
|
|
|
59
68
|
let currentSortDescriptor = $state<TableSortDescriptor | undefined>(
|
|
60
69
|
(() => initialSortDescriptor)()
|
|
61
70
|
);
|
|
71
|
+
let rowActionLog = $state<string[]>([]);
|
|
72
|
+
let eventLog = $state<string[]>([]);
|
|
62
73
|
|
|
63
74
|
const renderedRows = $derived.by(() => {
|
|
64
75
|
const nextRows = [...rows];
|
|
@@ -71,6 +82,18 @@
|
|
|
71
82
|
return String(left).localeCompare(String(right)) * direction;
|
|
72
83
|
});
|
|
73
84
|
});
|
|
85
|
+
|
|
86
|
+
function handleSelectionChange(keys: Set<TableSelectionKey>) {
|
|
87
|
+
currentSelectedKeys = new Set(keys);
|
|
88
|
+
eventLog = [...eventLog, `selection:${JSON.stringify([...keys])}`];
|
|
89
|
+
onSelectionChange?.(new Set(keys));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function handleRowAction(id: TableSelectionKey) {
|
|
93
|
+
rowActionLog = [...rowActionLog, String(id)];
|
|
94
|
+
eventLog = [...eventLog, `action:${String(id)}`];
|
|
95
|
+
onRowAction?.(id);
|
|
96
|
+
}
|
|
74
97
|
</script>
|
|
75
98
|
|
|
76
99
|
<Table.Root
|
|
@@ -78,11 +101,15 @@
|
|
|
78
101
|
aria-labelledby={ariaLabelledby}
|
|
79
102
|
{selectionMode}
|
|
80
103
|
{selectionBehavior}
|
|
104
|
+
{disabledBehavior}
|
|
105
|
+
{disallowEmptySelection}
|
|
81
106
|
bind:hiddenColumns
|
|
82
107
|
{defaultHiddenColumns}
|
|
83
108
|
bind:selectedKeys={currentSelectedKeys}
|
|
84
109
|
bind:sortDescriptor={currentSortDescriptor}
|
|
85
110
|
{disabledKeys}
|
|
111
|
+
onRowAction={handleRowAction}
|
|
112
|
+
onSelectionChange={handleSelectionChange}
|
|
86
113
|
class="table-root"
|
|
87
114
|
>
|
|
88
115
|
<Table.Header>
|
|
@@ -157,6 +184,8 @@
|
|
|
157
184
|
{/if}
|
|
158
185
|
|
|
159
186
|
<output data-testid="selected-keys">{JSON.stringify([...currentSelectedKeys])}</output>
|
|
187
|
+
<output data-testid="row-action-log">{JSON.stringify(rowActionLog)}</output>
|
|
188
|
+
<output data-testid="event-log">{JSON.stringify(eventLog)}</output>
|
|
160
189
|
<output data-testid="sort-descriptor"
|
|
161
190
|
>{currentSortDescriptor
|
|
162
191
|
? `${currentSortDescriptor.column}:${currentSortDescriptor.direction}`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TableSelectionBehavior, TableSelectionKey, TableSelectionMode, TableSortDescriptor } from './context';
|
|
1
|
+
import type { TableDisabledBehavior, TableSelectionBehavior, TableSelectionKey, TableSelectionMode, TableSortDescriptor } from './context';
|
|
2
2
|
type DemoRow = {
|
|
3
3
|
id: string;
|
|
4
4
|
email: string;
|
|
@@ -10,11 +10,15 @@ type TableTestProps = {
|
|
|
10
10
|
ariaLabelledby?: string;
|
|
11
11
|
selectionMode?: TableSelectionMode;
|
|
12
12
|
selectionBehavior?: TableSelectionBehavior;
|
|
13
|
+
disabledBehavior?: TableDisabledBehavior;
|
|
14
|
+
disallowEmptySelection?: boolean;
|
|
13
15
|
hiddenColumns?: string[];
|
|
14
16
|
defaultHiddenColumns?: string[];
|
|
15
17
|
disabledKeys?: Iterable<TableSelectionKey>;
|
|
16
18
|
initialSelectedKeys?: Iterable<TableSelectionKey>;
|
|
17
19
|
initialSortDescriptor?: TableSortDescriptor;
|
|
20
|
+
onRowAction?: (id: TableSelectionKey) => void;
|
|
21
|
+
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
18
22
|
showSelectionModeToggle?: boolean;
|
|
19
23
|
showSingleSelectionModeToggle?: boolean;
|
|
20
24
|
showSortClearButton?: boolean;
|