@human-kit/svelte-components 1.0.0-alpha.13 → 1.0.0-alpha.15
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 +445 -33
- package/dist/table/README.md +11 -0
- package/dist/table/TODO.md +40 -2
- package/dist/table/body/README.md +2 -0
- package/dist/table/body/table-body.svelte +1 -7
- package/dist/table/body/table-body.svelte.d.ts +1 -6
- package/dist/table/cell/README.md +2 -0
- package/dist/table/cell/table-cell.svelte +87 -86
- package/dist/table/cell/table-cell.svelte.d.ts +1 -6
- package/dist/table/checkbox/README.md +2 -0
- 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 +56 -52
- package/dist/table/checkbox/table-checkbox.svelte.d.ts +1 -10
- package/dist/table/checkbox-indicator/README.md +2 -0
- package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte +1 -8
- package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte.d.ts +1 -7
- package/dist/table/column/README.md +17 -14
- package/dist/table/column/table-column.svelte +2 -26
- package/dist/table/column/table-column.svelte.d.ts +1 -15
- package/dist/table/column-header-cell/README.md +2 -0
- package/dist/table/column-header-cell/table-column-header-cell.svelte +1 -7
- package/dist/table/column-header-cell/table-column-header-cell.svelte.d.ts +1 -6
- package/dist/table/column-resizer/README.md +2 -1
- package/dist/table/column-resizer/table-column-resizer.svelte +1 -9
- package/dist/table/column-resizer/table-column-resizer.svelte.d.ts +1 -8
- package/dist/table/empty-state/README.md +2 -0
- package/dist/table/empty-state/table-empty-state.svelte +1 -6
- package/dist/table/empty-state/table-empty-state.svelte.d.ts +1 -5
- package/dist/table/footer/README.md +2 -0
- package/dist/table/footer/table-footer.svelte +1 -7
- package/dist/table/footer/table-footer.svelte.d.ts +1 -6
- package/dist/table/header/README.md +2 -0
- package/dist/table/header/table-header.svelte +1 -7
- package/dist/table/header/table-header.svelte.d.ts +1 -6
- package/dist/table/index.d.ts +2 -1
- package/dist/table/root/README.md +31 -21
- package/dist/table/root/context.d.ts +19 -6
- package/dist/table/root/context.js +203 -29
- package/dist/table/root/table-root.svelte +30 -33
- package/dist/table/root/table-root.svelte.d.ts +1 -26
- package/dist/table/root/table-test.svelte +29 -0
- package/dist/table/root/table-test.svelte.d.ts +5 -1
- package/dist/table/row/README.md +2 -0
- package/dist/table/row/table-row.svelte +46 -83
- package/dist/table/row/table-row.svelte.d.ts +1 -10
- package/dist/table/types.d.ts +90 -0
- package/dist/table/types.js +1 -0
- 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(() => {
|
|
@@ -136,7 +143,7 @@ export function createTableContext(options = {}) {
|
|
|
136
143
|
for (const column of columns.values()) {
|
|
137
144
|
if (isColumnHidden(column.id))
|
|
138
145
|
continue;
|
|
139
|
-
if (
|
|
146
|
+
if (columnsWithResizers.has(column.token))
|
|
140
147
|
return true;
|
|
141
148
|
}
|
|
142
149
|
return false;
|
|
@@ -152,11 +159,10 @@ export function createTableContext(options = {}) {
|
|
|
152
159
|
return;
|
|
153
160
|
notifyLayout();
|
|
154
161
|
}
|
|
155
|
-
function
|
|
162
|
+
function sameColumnMetadata(left, right) {
|
|
156
163
|
return (left.token === right.token &&
|
|
157
164
|
left.id === right.id &&
|
|
158
165
|
left.allowsSorting === right.allowsSorting &&
|
|
159
|
-
left.allowsResizing === right.allowsResizing &&
|
|
160
166
|
left.isRowHeader === right.isRowHeader &&
|
|
161
167
|
left.textValue === right.textValue &&
|
|
162
168
|
left.width === right.width &&
|
|
@@ -183,7 +189,7 @@ export function createTableContext(options = {}) {
|
|
|
183
189
|
function registerColumn(column) {
|
|
184
190
|
const existing = columns.get(column.token);
|
|
185
191
|
const alreadyOrdered = columnOrder.includes(column.token);
|
|
186
|
-
if (existing &&
|
|
192
|
+
if (existing && sameColumnMetadata(existing, column) && alreadyOrdered)
|
|
187
193
|
return;
|
|
188
194
|
if (existing && existing.id !== column.id && columnIds.get(existing.id) === column.token) {
|
|
189
195
|
columnIds.delete(existing.id);
|
|
@@ -281,7 +287,7 @@ export function createTableContext(options = {}) {
|
|
|
281
287
|
return false;
|
|
282
288
|
if (isColumnHidden(columnId))
|
|
283
289
|
return false;
|
|
284
|
-
return
|
|
290
|
+
return columnsWithResizers.has(column.token);
|
|
285
291
|
}
|
|
286
292
|
function getColumnWidths() {
|
|
287
293
|
if (columnWidthsCache)
|
|
@@ -300,12 +306,15 @@ export function createTableContext(options = {}) {
|
|
|
300
306
|
return widths;
|
|
301
307
|
}
|
|
302
308
|
function getVisibleColumnWidths() {
|
|
309
|
+
if (visibleColumnWidthsCache)
|
|
310
|
+
return visibleColumnWidthsCache;
|
|
303
311
|
const widths = new Map();
|
|
304
312
|
for (const [columnId, width] of getColumnWidths()) {
|
|
305
313
|
if (isColumnHidden(columnId))
|
|
306
314
|
continue;
|
|
307
315
|
widths.set(columnId, width);
|
|
308
316
|
}
|
|
317
|
+
visibleColumnWidthsCache = widths;
|
|
309
318
|
return widths;
|
|
310
319
|
}
|
|
311
320
|
function getMeasuredHeaderWidth(columnToken) {
|
|
@@ -444,6 +453,33 @@ export function createTableContext(options = {}) {
|
|
|
444
453
|
focusedRowTarget = null;
|
|
445
454
|
notifyFocus();
|
|
446
455
|
}
|
|
456
|
+
function reconcileFocusAfterDisabledStateChange() {
|
|
457
|
+
if (focusedCellKey) {
|
|
458
|
+
const focusedCell = cells.get(focusedCellKey);
|
|
459
|
+
if (focusedCell &&
|
|
460
|
+
focusedCell.section === 'body' &&
|
|
461
|
+
isRowDisabled(rows.get(focusedCell.rowToken)?.id, rows.get(focusedCell.rowToken)?.disabled)) {
|
|
462
|
+
moveFocus('down');
|
|
463
|
+
const nextFocusedCell = cells.get(focusedCellKey ?? '');
|
|
464
|
+
if (nextFocusedCell?.section === 'body' &&
|
|
465
|
+
isRowDisabled(rows.get(nextFocusedCell.rowToken)?.id, rows.get(nextFocusedCell.rowToken)?.disabled)) {
|
|
466
|
+
moveFocus('up');
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (focusedRowTarget) {
|
|
471
|
+
const focusedRow = rows.get(focusedRowTarget.rowToken);
|
|
472
|
+
if (focusedRow && isRowDisabled(focusedRow.id, focusedRow.disabled)) {
|
|
473
|
+
const nextToken = getFocusableBodyRowToken('start');
|
|
474
|
+
if (nextToken) {
|
|
475
|
+
setFocusedRow(nextToken, focusedRowTarget.edge);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
setFocusedRow(null);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
447
483
|
function setHiddenColumns(columnIds) {
|
|
448
484
|
const next = new Set(columnIds ?? []);
|
|
449
485
|
let changed = next.size !== hiddenColumnIds.size;
|
|
@@ -635,19 +671,28 @@ export function createTableContext(options = {}) {
|
|
|
635
671
|
const row = rows.get(token);
|
|
636
672
|
if (!row?.id)
|
|
637
673
|
continue;
|
|
638
|
-
if (
|
|
674
|
+
if (isRowSelectionDisabled(row.id, row.disabled))
|
|
639
675
|
continue;
|
|
640
676
|
rowIds.push(row.id);
|
|
641
677
|
}
|
|
642
678
|
return rowIds;
|
|
643
679
|
}
|
|
644
|
-
function
|
|
680
|
+
function isRowSelectionDisabled(id, localDisabled = false) {
|
|
645
681
|
if (localDisabled)
|
|
646
682
|
return true;
|
|
647
683
|
if (id === undefined)
|
|
648
684
|
return false;
|
|
649
685
|
return disabledKeys.has(id);
|
|
650
686
|
}
|
|
687
|
+
function isRowDisabled(id, localDisabled = false) {
|
|
688
|
+
return disabledBehavior === 'all' && isRowSelectionDisabled(id, localDisabled);
|
|
689
|
+
}
|
|
690
|
+
function isRowActionDisabled(id, localDisabled = false) {
|
|
691
|
+
return disabledBehavior === 'all' && isRowSelectionDisabled(id, localDisabled);
|
|
692
|
+
}
|
|
693
|
+
function isRowActionable(id, localDisabled = false) {
|
|
694
|
+
return Boolean(onRowAction) && id !== undefined && !isRowActionDisabled(id, localDisabled);
|
|
695
|
+
}
|
|
651
696
|
function isRowSelected(id) {
|
|
652
697
|
if (id === undefined)
|
|
653
698
|
return false;
|
|
@@ -919,12 +964,25 @@ export function createTableContext(options = {}) {
|
|
|
919
964
|
return true;
|
|
920
965
|
}
|
|
921
966
|
function setSelectedKeys(next, anchor) {
|
|
967
|
+
const previousSelectedKeys = new Set(selectedKeys);
|
|
922
968
|
selectedKeys =
|
|
923
969
|
selectionMode === 'none'
|
|
924
970
|
? new Set()
|
|
925
971
|
: selectionMode === 'single' && next.size > 1
|
|
926
972
|
? new Set([next.values().next().value])
|
|
927
973
|
: next;
|
|
974
|
+
if (selectionMode !== 'none' && disallowEmptySelection && selectedKeys.size === 0) {
|
|
975
|
+
const fallbackKey = (anchor !== undefined && anchor !== null && !isRowSelectionDisabled(anchor)
|
|
976
|
+
? anchor
|
|
977
|
+
: previousSelectedKeys.values().next().value) ??
|
|
978
|
+
getFocusedRowId() ??
|
|
979
|
+
getOrderedSelectableRowIds()[0];
|
|
980
|
+
if (fallbackKey !== undefined &&
|
|
981
|
+
fallbackKey !== null &&
|
|
982
|
+
!isRowSelectionDisabled(fallbackKey)) {
|
|
983
|
+
selectedKeys = new Set([fallbackKey]);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
928
986
|
const fallbackAnchor = selectedKeys.values().next().value ?? null;
|
|
929
987
|
if (anchor === undefined) {
|
|
930
988
|
selectionAnchorKey = fallbackAnchor;
|
|
@@ -933,18 +991,35 @@ export function createTableContext(options = {}) {
|
|
|
933
991
|
selectionAnchorKey = anchor === null || selectedKeys.has(anchor) ? anchor : fallbackAnchor;
|
|
934
992
|
}
|
|
935
993
|
function replaceSelectionWithRow(id) {
|
|
936
|
-
if (id === undefined ||
|
|
994
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
995
|
+
return;
|
|
996
|
+
const next = new Set([id]);
|
|
997
|
+
if (hasSameSelection(selectedKeys, next)) {
|
|
998
|
+
setSelectedKeys(next, id);
|
|
999
|
+
notifySelection();
|
|
937
1000
|
return;
|
|
938
|
-
|
|
1001
|
+
}
|
|
1002
|
+
setSelectedKeys(next, id);
|
|
939
1003
|
emitSelectionChange();
|
|
940
1004
|
}
|
|
1005
|
+
function applySelectionChange(next, anchor) {
|
|
1006
|
+
const previousSelection = new Set(selectedKeys);
|
|
1007
|
+
const previousAnchor = selectionAnchorKey;
|
|
1008
|
+
setSelectedKeys(next, anchor);
|
|
1009
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1010
|
+
emitSelectionChange();
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
if (!hasSameSelection(next, selectedKeys) || previousAnchor !== selectionAnchorKey) {
|
|
1014
|
+
notifySelection();
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
941
1017
|
function toggleSelectionForRow(id) {
|
|
942
|
-
if (id === undefined ||
|
|
1018
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
943
1019
|
return;
|
|
944
1020
|
if (selectionMode === 'single') {
|
|
945
1021
|
const wasSelected = selectedKeys.has(id);
|
|
946
|
-
|
|
947
|
-
emitSelectionChange();
|
|
1022
|
+
applySelectionChange(selectionBehavior === 'toggle' && wasSelected ? new Set() : new Set([id]), selectionBehavior === 'toggle' && wasSelected ? null : id);
|
|
948
1023
|
return;
|
|
949
1024
|
}
|
|
950
1025
|
const next = new Set(selectedKeys);
|
|
@@ -954,11 +1029,10 @@ export function createTableContext(options = {}) {
|
|
|
954
1029
|
else {
|
|
955
1030
|
next.add(id);
|
|
956
1031
|
}
|
|
957
|
-
|
|
958
|
-
emitSelectionChange();
|
|
1032
|
+
applySelectionChange(next, id);
|
|
959
1033
|
}
|
|
960
1034
|
function extendSelectionToRow(id, anchorOverride) {
|
|
961
|
-
if (id === undefined ||
|
|
1035
|
+
if (id === undefined || isRowSelectionDisabled(id))
|
|
962
1036
|
return;
|
|
963
1037
|
if (selectionMode !== 'multiple') {
|
|
964
1038
|
replaceSelectionWithRow(id);
|
|
@@ -979,11 +1053,18 @@ export function createTableContext(options = {}) {
|
|
|
979
1053
|
}
|
|
980
1054
|
const start = Math.min(anchorIndex, targetIndex);
|
|
981
1055
|
const end = Math.max(anchorIndex, targetIndex);
|
|
982
|
-
|
|
983
|
-
emitSelectionChange();
|
|
1056
|
+
applySelectionChange(new Set(orderedIds.slice(start, end + 1)), anchor);
|
|
984
1057
|
}
|
|
985
|
-
function
|
|
986
|
-
if (
|
|
1058
|
+
function performRowAction(id) {
|
|
1059
|
+
if (!onRowAction || id === undefined || isRowActionDisabled(id))
|
|
1060
|
+
return;
|
|
1061
|
+
onRowAction(id);
|
|
1062
|
+
}
|
|
1063
|
+
function hasActiveSelection() {
|
|
1064
|
+
return selectedKeys.size > 0;
|
|
1065
|
+
}
|
|
1066
|
+
function pressRowSelection(id, interaction = {}) {
|
|
1067
|
+
if (selectionMode === 'none' || id === undefined || isRowSelectionDisabled(id))
|
|
987
1068
|
return;
|
|
988
1069
|
if (selectionBehavior === 'replace' && selectionMode === 'multiple') {
|
|
989
1070
|
if (interaction.shiftKey) {
|
|
@@ -999,6 +1080,55 @@ export function createTableContext(options = {}) {
|
|
|
999
1080
|
}
|
|
1000
1081
|
toggleSelectionForRow(id);
|
|
1001
1082
|
}
|
|
1083
|
+
function pressRow(id, source, interaction = {}, localDisabled = false) {
|
|
1084
|
+
if (id === undefined)
|
|
1085
|
+
return;
|
|
1086
|
+
if (isRowDisabled(id, localDisabled))
|
|
1087
|
+
return;
|
|
1088
|
+
if (source === 'keyboard-enter') {
|
|
1089
|
+
if (onRowAction) {
|
|
1090
|
+
performRowAction(id);
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
pressRowSelection(id, interaction);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
if (source === 'keyboard-space') {
|
|
1097
|
+
if (interaction.shiftKey) {
|
|
1098
|
+
extendSelectionToRow(id);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (interaction.ctrlKey || interaction.metaKey) {
|
|
1102
|
+
toggleSelectionForRow(id);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
toggleRowSelection(id);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
if (source === 'pointer-double') {
|
|
1109
|
+
if (onRowAction && selectionMode !== 'none' && selectionBehavior === 'replace') {
|
|
1110
|
+
performRowAction(id);
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (!onRowAction) {
|
|
1115
|
+
pressRowSelection(id, interaction);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
if (selectionMode === 'none') {
|
|
1119
|
+
performRowAction(id);
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (selectionBehavior === 'replace') {
|
|
1123
|
+
pressRowSelection(id, interaction);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (hasActiveSelection()) {
|
|
1127
|
+
pressRowSelection(id, interaction);
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
performRowAction(id);
|
|
1131
|
+
}
|
|
1002
1132
|
function moveFocus(direction, interaction = {}) {
|
|
1003
1133
|
const rowMap = getRowsWithCells();
|
|
1004
1134
|
const currentCoord = getFocusedCoord();
|
|
@@ -1166,12 +1296,11 @@ export function createTableContext(options = {}) {
|
|
|
1166
1296
|
notifySelection();
|
|
1167
1297
|
}
|
|
1168
1298
|
function toggleRowSelection(id) {
|
|
1169
|
-
if (selectionMode === 'none' || id === undefined ||
|
|
1299
|
+
if (selectionMode === 'none' || id === undefined || isRowSelectionDisabled(id))
|
|
1170
1300
|
return;
|
|
1171
1301
|
if (selectionMode === 'single') {
|
|
1172
1302
|
const wasSelected = selectedKeys.has(id);
|
|
1173
|
-
|
|
1174
|
-
emitSelectionChange();
|
|
1303
|
+
applySelectionChange(wasSelected ? new Set() : new Set([id]), wasSelected ? null : id);
|
|
1175
1304
|
return;
|
|
1176
1305
|
}
|
|
1177
1306
|
const next = new Set(selectedKeys);
|
|
@@ -1181,8 +1310,7 @@ export function createTableContext(options = {}) {
|
|
|
1181
1310
|
else {
|
|
1182
1311
|
next.add(id);
|
|
1183
1312
|
}
|
|
1184
|
-
|
|
1185
|
-
emitSelectionChange();
|
|
1313
|
+
applySelectionChange(next, id);
|
|
1186
1314
|
}
|
|
1187
1315
|
function selectAllRows() {
|
|
1188
1316
|
if (selectionMode !== 'multiple')
|
|
@@ -1190,7 +1318,7 @@ export function createTableContext(options = {}) {
|
|
|
1190
1318
|
const next = new Set();
|
|
1191
1319
|
for (const token of getOrderedRowTokens('body')) {
|
|
1192
1320
|
const row = rows.get(token);
|
|
1193
|
-
if (!row?.id ||
|
|
1321
|
+
if (!row?.id || isRowSelectionDisabled(row.id, row.disabled))
|
|
1194
1322
|
continue;
|
|
1195
1323
|
next.add(row.id);
|
|
1196
1324
|
}
|
|
@@ -1200,14 +1328,21 @@ export function createTableContext(options = {}) {
|
|
|
1200
1328
|
function deselectAllRows() {
|
|
1201
1329
|
if (selectedKeys.size === 0)
|
|
1202
1330
|
return;
|
|
1203
|
-
|
|
1204
|
-
emitSelectionChange();
|
|
1331
|
+
applySelectionChange(new Set(), null);
|
|
1205
1332
|
}
|
|
1206
1333
|
function setSelection(keys) {
|
|
1334
|
+
const previousSelection = new Set(selectedKeys);
|
|
1335
|
+
const previousAnchor = selectionAnchorKey;
|
|
1207
1336
|
const next = new Set(keys);
|
|
1208
1337
|
const preservedAnchor = selectionAnchorKey !== null && next.has(selectionAnchorKey) ? selectionAnchorKey : undefined;
|
|
1209
1338
|
setSelectedKeys(next, preservedAnchor);
|
|
1210
|
-
|
|
1339
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1340
|
+
emitSelectionChange();
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
if (previousAnchor !== selectionAnchorKey) {
|
|
1344
|
+
notifySelection();
|
|
1345
|
+
}
|
|
1211
1346
|
}
|
|
1212
1347
|
function setSelectionMode(mode) {
|
|
1213
1348
|
const previousSelectedKeys = new Set(selectedKeys);
|
|
@@ -1225,6 +1360,23 @@ export function createTableContext(options = {}) {
|
|
|
1225
1360
|
selectionBehavior = behavior;
|
|
1226
1361
|
notifySelection();
|
|
1227
1362
|
}
|
|
1363
|
+
function setDisabledBehavior(behavior) {
|
|
1364
|
+
disabledBehavior = behavior;
|
|
1365
|
+
invalidateLayoutCaches();
|
|
1366
|
+
reconcileFocusAfterDisabledStateChange();
|
|
1367
|
+
notifyLayout();
|
|
1368
|
+
notifySelection();
|
|
1369
|
+
}
|
|
1370
|
+
function setDisallowEmptySelection(disallow) {
|
|
1371
|
+
disallowEmptySelection = disallow;
|
|
1372
|
+
const previousSelection = new Set(selectedKeys);
|
|
1373
|
+
setSelectedKeys(new Set(selectedKeys), selectionAnchorKey);
|
|
1374
|
+
if (!hasSameSelection(previousSelection, selectedKeys)) {
|
|
1375
|
+
emitSelectionChange();
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
notifySelection();
|
|
1379
|
+
}
|
|
1228
1380
|
function setDisabledKeys(keys) {
|
|
1229
1381
|
disabledKeys.clear();
|
|
1230
1382
|
if (keys) {
|
|
@@ -1232,6 +1384,13 @@ export function createTableContext(options = {}) {
|
|
|
1232
1384
|
disabledKeys.add(key);
|
|
1233
1385
|
}
|
|
1234
1386
|
}
|
|
1387
|
+
invalidateLayoutCaches();
|
|
1388
|
+
reconcileFocusAfterDisabledStateChange();
|
|
1389
|
+
notifyLayout();
|
|
1390
|
+
notifySelection();
|
|
1391
|
+
}
|
|
1392
|
+
function setRowActionHandler(handler) {
|
|
1393
|
+
onRowAction = handler;
|
|
1235
1394
|
notifySelection();
|
|
1236
1395
|
}
|
|
1237
1396
|
function setSortDescriptor(descriptor) {
|
|
@@ -1240,7 +1399,7 @@ export function createTableContext(options = {}) {
|
|
|
1240
1399
|
notifySort();
|
|
1241
1400
|
}
|
|
1242
1401
|
function isColumnSortable(columnId) {
|
|
1243
|
-
return
|
|
1402
|
+
return getColumnRegistrationById(columnId)?.allowsSorting ?? false;
|
|
1244
1403
|
}
|
|
1245
1404
|
function toggleSort(columnId) {
|
|
1246
1405
|
if (!isColumnSortable(columnId))
|
|
@@ -1273,6 +1432,15 @@ export function createTableContext(options = {}) {
|
|
|
1273
1432
|
get selectionBehavior() {
|
|
1274
1433
|
return selectionBehavior;
|
|
1275
1434
|
},
|
|
1435
|
+
get disabledBehavior() {
|
|
1436
|
+
return disabledBehavior;
|
|
1437
|
+
},
|
|
1438
|
+
get disallowEmptySelection() {
|
|
1439
|
+
return disallowEmptySelection;
|
|
1440
|
+
},
|
|
1441
|
+
get selectionUnavailableDescriptionId() {
|
|
1442
|
+
return selectionUnavailableDescriptionId;
|
|
1443
|
+
},
|
|
1276
1444
|
disabledKeys,
|
|
1277
1445
|
get focusedCellKey() {
|
|
1278
1446
|
return focusedCellKey;
|
|
@@ -1321,6 +1489,9 @@ export function createTableContext(options = {}) {
|
|
|
1321
1489
|
isRowFocusTarget,
|
|
1322
1490
|
getRowFocusEdge,
|
|
1323
1491
|
isRowDisabled,
|
|
1492
|
+
isRowSelectionDisabled,
|
|
1493
|
+
isRowActionDisabled,
|
|
1494
|
+
isRowActionable,
|
|
1324
1495
|
hasSelectableRows,
|
|
1325
1496
|
getSelectionCheckboxState,
|
|
1326
1497
|
registerCell,
|
|
@@ -1347,7 +1518,10 @@ export function createTableContext(options = {}) {
|
|
|
1347
1518
|
setSelection,
|
|
1348
1519
|
setSelectionMode,
|
|
1349
1520
|
setSelectionBehavior,
|
|
1521
|
+
setDisabledBehavior,
|
|
1522
|
+
setDisallowEmptySelection,
|
|
1350
1523
|
setDisabledKeys,
|
|
1524
|
+
setRowActionHandler,
|
|
1351
1525
|
setSortDescriptor,
|
|
1352
1526
|
toggleSort,
|
|
1353
1527
|
isColumnSortable,
|
|
@@ -12,49 +12,23 @@
|
|
|
12
12
|
|
|
13
13
|
<script lang="ts">
|
|
14
14
|
import { tick } from 'svelte';
|
|
15
|
-
import
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
shouldShowFocusVisible,
|
|
17
|
+
trackInteractionModality
|
|
18
|
+
} from '../../primitives/input-modality';
|
|
19
|
+
import type { TableRootProps } from '../types.js';
|
|
17
20
|
import {
|
|
18
21
|
createTableContext,
|
|
19
22
|
setTableContext,
|
|
20
|
-
type TableContext,
|
|
21
|
-
type TableSelectionBehavior,
|
|
22
23
|
type TableSelectionKey,
|
|
23
|
-
type TableSelectionMode,
|
|
24
24
|
type TableSortDescriptor
|
|
25
25
|
} from './context';
|
|
26
|
-
import {
|
|
27
|
-
shouldShowFocusVisible,
|
|
28
|
-
trackInteractionModality
|
|
29
|
-
} from '../../primitives/input-modality';
|
|
30
|
-
|
|
31
|
-
type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
|
|
32
|
-
selectionMode?: TableSelectionMode;
|
|
33
|
-
selectionBehavior?: TableSelectionBehavior;
|
|
34
|
-
hiddenColumns?: Iterable<string>;
|
|
35
|
-
defaultHiddenColumns?: Iterable<string>;
|
|
36
|
-
selectedKeys?: Iterable<TableSelectionKey>;
|
|
37
|
-
defaultSelectedKeys?: Iterable<TableSelectionKey>;
|
|
38
|
-
sortDescriptor?: TableSortDescriptor;
|
|
39
|
-
defaultSortDescriptor?: TableSortDescriptor;
|
|
40
|
-
columnWidths?: Map<string, number>;
|
|
41
|
-
defaultColumnWidths?: Iterable<readonly [string, number]>;
|
|
42
|
-
disabledKeys?: Iterable<TableSelectionKey>;
|
|
43
|
-
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
44
|
-
onSortChange?: (descriptor: TableSortDescriptor | undefined) => void;
|
|
45
|
-
onColumnWidthsChange?: (widths: Map<string, number>) => void;
|
|
46
|
-
onHiddenColumnsChange?: (columnIds: string[]) => void;
|
|
47
|
-
onColumnResizeStart?: (columnId: string) => void;
|
|
48
|
-
onColumnResizeEnd?: (widths: Map<string, number>) => void;
|
|
49
|
-
children?: Snippet;
|
|
50
|
-
class?: string;
|
|
51
|
-
context?: TableContext;
|
|
52
|
-
element?: HTMLTableElement;
|
|
53
|
-
};
|
|
54
26
|
|
|
55
27
|
let {
|
|
56
28
|
selectionMode = 'none',
|
|
57
29
|
selectionBehavior = 'toggle',
|
|
30
|
+
disabledBehavior = 'all',
|
|
31
|
+
disallowEmptySelection = false,
|
|
58
32
|
hiddenColumns = $bindable(),
|
|
59
33
|
defaultHiddenColumns,
|
|
60
34
|
selectedKeys = $bindable(),
|
|
@@ -66,6 +40,7 @@
|
|
|
66
40
|
'aria-label': ariaLabel,
|
|
67
41
|
'aria-labelledby': ariaLabelledby,
|
|
68
42
|
disabledKeys,
|
|
43
|
+
onRowAction,
|
|
69
44
|
onSelectionChange,
|
|
70
45
|
onSortChange,
|
|
71
46
|
onColumnWidthsChange,
|
|
@@ -94,11 +69,14 @@
|
|
|
94
69
|
createTableContext({
|
|
95
70
|
selectionMode: (() => selectionMode)(),
|
|
96
71
|
selectionBehavior: (() => selectionBehavior)(),
|
|
72
|
+
disabledBehavior: (() => disabledBehavior)(),
|
|
73
|
+
disallowEmptySelection: (() => disallowEmptySelection)(),
|
|
97
74
|
initialHiddenColumns: (() => hiddenColumns ?? defaultHiddenColumns)(),
|
|
98
75
|
initialSelectedKeys: (() => selectedKeys ?? defaultSelectedKeys)(),
|
|
99
76
|
initialSortDescriptor: (() => sortDescriptor ?? defaultSortDescriptor)(),
|
|
100
77
|
initialColumnWidths: (() => columnWidths ?? defaultColumnWidths)(),
|
|
101
78
|
disabledKeys: (() => disabledKeys)(),
|
|
79
|
+
onRowAction: (() => onRowAction)(),
|
|
102
80
|
onHiddenColumnsChange: (columnIds) => {
|
|
103
81
|
pendingControlledHiddenColumns = [...columnIds];
|
|
104
82
|
hiddenColumns = [...columnIds];
|
|
@@ -270,10 +248,22 @@
|
|
|
270
248
|
ctx.setSelectionBehavior(selectionBehavior);
|
|
271
249
|
});
|
|
272
250
|
|
|
251
|
+
$effect(() => {
|
|
252
|
+
ctx.setDisabledBehavior(disabledBehavior);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
$effect(() => {
|
|
256
|
+
ctx.setDisallowEmptySelection(disallowEmptySelection);
|
|
257
|
+
});
|
|
258
|
+
|
|
273
259
|
$effect(() => {
|
|
274
260
|
ctx.setDisabledKeys(disabledKeys);
|
|
275
261
|
});
|
|
276
262
|
|
|
263
|
+
$effect(() => {
|
|
264
|
+
ctx.setRowActionHandler(onRowAction);
|
|
265
|
+
});
|
|
266
|
+
|
|
277
267
|
$effect(() => {
|
|
278
268
|
if (selectedKeys !== undefined) {
|
|
279
269
|
const nextSelection = parseSelection(selectedKeys);
|
|
@@ -388,6 +378,7 @@
|
|
|
388
378
|
aria-multiselectable={selectionMode === 'multiple' ? true : undefined}
|
|
389
379
|
data-selection-mode={selectionMode}
|
|
390
380
|
data-selection-behavior={selectionBehavior}
|
|
381
|
+
data-disabled-behavior={disabledBehavior}
|
|
391
382
|
data-focus-within={focusWithin || undefined}
|
|
392
383
|
data-focus-visible={focusVisible || undefined}
|
|
393
384
|
onfocusin={handleFocusIn}
|
|
@@ -408,3 +399,9 @@
|
|
|
408
399
|
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
400
|
>{sortAnnouncement}</span
|
|
410
401
|
>
|
|
402
|
+
|
|
403
|
+
<span
|
|
404
|
+
id={ctx.selectionUnavailableDescriptionId}
|
|
405
|
+
style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;"
|
|
406
|
+
>Selection unavailable for this row.</span
|
|
407
|
+
>
|
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import { type TableContext, type TableSelectionBehavior, type TableSelectionKey, type TableSelectionMode, type TableSortDescriptor } from './context';
|
|
4
|
-
type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'> & {
|
|
5
|
-
selectionMode?: TableSelectionMode;
|
|
6
|
-
selectionBehavior?: TableSelectionBehavior;
|
|
7
|
-
hiddenColumns?: Iterable<string>;
|
|
8
|
-
defaultHiddenColumns?: Iterable<string>;
|
|
9
|
-
selectedKeys?: Iterable<TableSelectionKey>;
|
|
10
|
-
defaultSelectedKeys?: Iterable<TableSelectionKey>;
|
|
11
|
-
sortDescriptor?: TableSortDescriptor;
|
|
12
|
-
defaultSortDescriptor?: TableSortDescriptor;
|
|
13
|
-
columnWidths?: Map<string, number>;
|
|
14
|
-
defaultColumnWidths?: Iterable<readonly [string, number]>;
|
|
15
|
-
disabledKeys?: Iterable<TableSelectionKey>;
|
|
16
|
-
onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
|
|
17
|
-
onSortChange?: (descriptor: TableSortDescriptor | undefined) => void;
|
|
18
|
-
onColumnWidthsChange?: (widths: Map<string, number>) => void;
|
|
19
|
-
onHiddenColumnsChange?: (columnIds: string[]) => void;
|
|
20
|
-
onColumnResizeStart?: (columnId: string) => void;
|
|
21
|
-
onColumnResizeEnd?: (widths: Map<string, number>) => void;
|
|
22
|
-
children?: Snippet;
|
|
23
|
-
class?: string;
|
|
24
|
-
context?: TableContext;
|
|
25
|
-
element?: HTMLTableElement;
|
|
26
|
-
};
|
|
1
|
+
import type { TableRootProps } from '../types.js';
|
|
27
2
|
declare const TableRoot: import("svelte").Component<TableRootProps, {}, "element" | "context" | "hiddenColumns" | "selectedKeys" | "sortDescriptor" | "columnWidths">;
|
|
28
3
|
type TableRoot = ReturnType<typeof TableRoot>;
|
|
29
4
|
export default TableRoot;
|