@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.
Files changed (57) hide show
  1. package/dist/checkbox/root/checkbox-root.svelte +22 -2
  2. package/dist/checkbox/root/checkbox-root.svelte.d.ts +4 -1
  3. package/dist/combobox/root/combobox.svelte +1 -0
  4. package/dist/listbox/item/listbox-item.svelte +13 -0
  5. package/dist/listbox/root/listbox.svelte +7 -1
  6. package/dist/table/IMPLEMENTATION_NOTES.md +2 -1
  7. package/dist/table/PLAN.md +445 -33
  8. package/dist/table/README.md +11 -0
  9. package/dist/table/TODO.md +40 -2
  10. package/dist/table/body/README.md +2 -0
  11. package/dist/table/body/table-body.svelte +1 -7
  12. package/dist/table/body/table-body.svelte.d.ts +1 -6
  13. package/dist/table/cell/README.md +2 -0
  14. package/dist/table/cell/table-cell.svelte +87 -86
  15. package/dist/table/cell/table-cell.svelte.d.ts +1 -6
  16. package/dist/table/checkbox/README.md +2 -0
  17. package/dist/table/checkbox/table-checkbox-test.svelte +7 -0
  18. package/dist/table/checkbox/table-checkbox-test.svelte.d.ts +3 -1
  19. package/dist/table/checkbox/table-checkbox.svelte +56 -52
  20. package/dist/table/checkbox/table-checkbox.svelte.d.ts +1 -10
  21. package/dist/table/checkbox-indicator/README.md +2 -0
  22. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte +1 -8
  23. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte.d.ts +1 -7
  24. package/dist/table/column/README.md +17 -14
  25. package/dist/table/column/table-column.svelte +2 -26
  26. package/dist/table/column/table-column.svelte.d.ts +1 -15
  27. package/dist/table/column-header-cell/README.md +2 -0
  28. package/dist/table/column-header-cell/table-column-header-cell.svelte +1 -7
  29. package/dist/table/column-header-cell/table-column-header-cell.svelte.d.ts +1 -6
  30. package/dist/table/column-resizer/README.md +2 -1
  31. package/dist/table/column-resizer/table-column-resizer.svelte +1 -9
  32. package/dist/table/column-resizer/table-column-resizer.svelte.d.ts +1 -8
  33. package/dist/table/empty-state/README.md +2 -0
  34. package/dist/table/empty-state/table-empty-state.svelte +1 -6
  35. package/dist/table/empty-state/table-empty-state.svelte.d.ts +1 -5
  36. package/dist/table/footer/README.md +2 -0
  37. package/dist/table/footer/table-footer.svelte +1 -7
  38. package/dist/table/footer/table-footer.svelte.d.ts +1 -6
  39. package/dist/table/header/README.md +2 -0
  40. package/dist/table/header/table-header.svelte +1 -7
  41. package/dist/table/header/table-header.svelte.d.ts +1 -6
  42. package/dist/table/index.d.ts +2 -1
  43. package/dist/table/root/README.md +31 -21
  44. package/dist/table/root/context.d.ts +19 -6
  45. package/dist/table/root/context.js +203 -29
  46. package/dist/table/root/table-root.svelte +30 -33
  47. package/dist/table/root/table-root.svelte.d.ts +1 -26
  48. package/dist/table/root/table-test.svelte +29 -0
  49. package/dist/table/root/table-test.svelte.d.ts +5 -1
  50. package/dist/table/row/README.md +2 -0
  51. package/dist/table/row/table-row.svelte +46 -83
  52. package/dist/table/row/table-row.svelte.d.ts +1 -10
  53. package/dist/table/types.d.ts +90 -0
  54. package/dist/table/types.js +1 -0
  55. package/dist/table/utils/handle-body-keydown.d.ts +13 -0
  56. package/dist/table/utils/handle-body-keydown.js +67 -0
  57. 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 (column.allowsResizing || columnsWithResizers.has(column.token))
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 sameColumnRegistration(left, right) {
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 && sameColumnRegistration(existing, column) && alreadyOrdered)
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 column.allowsResizing || columnsWithResizers.has(column.token);
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 (disabledKeys.has(row.id) || row.disabled)
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 isRowDisabled(id, localDisabled = false) {
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 || disabledKeys.has(id))
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
- setSelectedKeys(new Set([id]), id);
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 || disabledKeys.has(id))
1018
+ if (id === undefined || isRowSelectionDisabled(id))
943
1019
  return;
944
1020
  if (selectionMode === 'single') {
945
1021
  const wasSelected = selectedKeys.has(id);
946
- setSelectedKeys(selectionBehavior === 'toggle' && wasSelected ? new Set() : new Set([id]), selectionBehavior === 'toggle' && wasSelected ? null : id);
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
- setSelectedKeys(next, id);
958
- emitSelectionChange();
1032
+ applySelectionChange(next, id);
959
1033
  }
960
1034
  function extendSelectionToRow(id, anchorOverride) {
961
- if (id === undefined || disabledKeys.has(id))
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
- setSelectedKeys(new Set(orderedIds.slice(start, end + 1)), anchor);
983
- emitSelectionChange();
1056
+ applySelectionChange(new Set(orderedIds.slice(start, end + 1)), anchor);
984
1057
  }
985
- function pressRow(id, interaction = {}) {
986
- if (selectionMode === 'none' || id === undefined || disabledKeys.has(id))
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 || disabledKeys.has(id))
1299
+ if (selectionMode === 'none' || id === undefined || isRowSelectionDisabled(id))
1170
1300
  return;
1171
1301
  if (selectionMode === 'single') {
1172
1302
  const wasSelected = selectedKeys.has(id);
1173
- setSelectedKeys(wasSelected ? new Set() : new Set([id]), wasSelected ? null : id);
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
- setSelectedKeys(next, id);
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 || disabledKeys.has(row.id) || row.disabled)
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
- setSelectedKeys(new Set(), null);
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
- notifySelection();
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 Array.from(columns.values()).some((column) => column.id === columnId && column.allowsSorting);
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 type { Snippet } from 'svelte';
16
- import type { HTMLAttributes } from 'svelte/elements';
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 { Snippet } from 'svelte';
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;