@streamscloud/kit 0.17.0 → 0.19.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.
Files changed (91) hide show
  1. package/dist/ui/badge/cmp.badge.svelte +4 -0
  2. package/dist/ui/badge/cmp.badge.svelte.d.ts +1 -0
  3. package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte +131 -0
  4. package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte.d.ts +31 -0
  5. package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte +14 -0
  6. package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte.d.ts +19 -0
  7. package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte +19 -0
  8. package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte.d.ts +35 -0
  9. package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte +143 -0
  10. package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte.d.ts +68 -0
  11. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte +71 -0
  12. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte.d.ts +32 -0
  13. package/dist/ui/page-toolbar/cmp.toolbar-option.svelte +189 -0
  14. package/dist/ui/page-toolbar/cmp.toolbar-option.svelte.d.ts +47 -0
  15. package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte +23 -8
  16. package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte.d.ts +14 -6
  17. package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte +46 -0
  18. package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte.d.ts +24 -0
  19. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte +31 -0
  20. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte.d.ts +44 -0
  21. package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte → cmp.toolbar-switch.svelte} +10 -10
  22. package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte.d.ts → cmp.toolbar-switch.svelte.d.ts} +2 -2
  23. package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte +14 -0
  24. package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte.d.ts +19 -0
  25. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte +51 -0
  26. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte.d.ts +27 -0
  27. package/dist/ui/page-toolbar/index.d.ts +12 -7
  28. package/dist/ui/page-toolbar/index.js +11 -6
  29. package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.d.ts +5 -0
  30. package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.js +17 -0
  31. package/dist/ui/page-toolbar/toolbar-filter-select-localization.d.ts +5 -0
  32. package/dist/ui/page-toolbar/toolbar-filter-select-localization.js +20 -0
  33. package/dist/ui/page-toolbar/toolbar-sort-select-localization.d.ts +3 -0
  34. package/dist/ui/page-toolbar/toolbar-sort-select-localization.js +9 -0
  35. package/dist/ui/page-toolbar/toolbar-view-controls-localization.d.ts +5 -0
  36. package/dist/ui/page-toolbar/toolbar-view-controls-localization.js +17 -0
  37. package/dist/ui/page-toolbar/types.d.ts +1 -1
  38. package/dist/ui/select/index.d.ts +1 -0
  39. package/dist/ui/select/index.js +1 -0
  40. package/dist/ui/select/select-listbox.svelte +11 -5
  41. package/dist/ui/select/select-listbox.svelte.d.ts +1 -1
  42. package/dist/ui/table/_table-styles.scss +156 -0
  43. package/dist/ui/table/cmp.table-draggable.svelte +338 -0
  44. package/dist/ui/table/cmp.table-draggable.svelte.d.ts +79 -0
  45. package/dist/ui/table/cmp.table.svelte +96 -265
  46. package/dist/ui/table/cmp.table.svelte.d.ts +16 -8
  47. package/dist/ui/table/index.d.ts +1 -0
  48. package/dist/ui/table/index.js +1 -0
  49. package/dist/ui/table/table-cells/index.d.ts +1 -12
  50. package/dist/ui/table/table-cells/index.js +1 -12
  51. package/dist/ui/table/table-cells/table-cell.svelte +77 -0
  52. package/dist/ui/table/table-cells/{table-select-cell.svelte.d.ts → table-cell.svelte.d.ts} +12 -6
  53. package/dist/ui/table/table-column-models.svelte.d.ts +1 -2
  54. package/dist/ui/table/table-column-models.svelte.js +0 -1
  55. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte +20 -47
  56. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte.d.ts +3 -7
  57. package/dist/ui/table/table-columns-manager/table-columns-manager-localization.d.ts +1 -1
  58. package/dist/ui/table/table-columns-manager/table-columns-manager-localization.js +7 -7
  59. package/dist/ui/table/table-localization.d.ts +0 -2
  60. package/dist/ui/table/table-localization.js +0 -14
  61. package/dist/ui/table/table-model.svelte.d.ts +2 -3
  62. package/dist/ui/table/table-model.svelte.js +5 -35
  63. package/dist/ui/table/table-view.svelte.d.ts +14 -0
  64. package/dist/ui/table/table-view.svelte.js +32 -0
  65. package/dist/ui/table/types.d.ts +5 -28
  66. package/dist/ui/toggle/cmp.toggle.svelte +32 -26
  67. package/dist/ui/toggle/cmp.toggle.svelte.d.ts +2 -0
  68. package/dist/ui/tree/cmp.tree-node-view.svelte +16 -10
  69. package/dist/ui/tree/cmp.tree-node-view.svelte.d.ts +2 -2
  70. package/dist/ui/tree/cmp.tree.svelte +14 -30
  71. package/dist/ui/tree/cmp.tree.svelte.d.ts +5 -5
  72. package/dist/ui/tree/tree-keyboard.svelte.d.ts +9 -0
  73. package/dist/ui/tree/tree-keyboard.svelte.js +107 -0
  74. package/dist/ui/tree/tree-node.svelte.d.ts +7 -3
  75. package/dist/ui/tree/tree-node.svelte.js +32 -16
  76. package/package.json +1 -1
  77. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte +0 -153
  78. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte.d.ts +0 -20
  79. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte +0 -19
  80. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte.d.ts +0 -12
  81. package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte +0 -42
  82. package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte.d.ts +0 -20
  83. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte +0 -57
  84. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte.d.ts +0 -19
  85. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte +0 -16
  86. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte.d.ts +0 -12
  87. package/dist/ui/table/table-cells/table-select-cell.svelte +0 -28
  88. package/dist/ui/table/table-cells/table-text-input-cell.svelte +0 -69
  89. package/dist/ui/table/table-cells/table-text-input-cell.svelte.d.ts +0 -38
  90. package/dist/ui/tree/tree-navigation.svelte.d.ts +0 -14
  91. package/dist/ui/tree/tree-navigation.svelte.js +0 -99
@@ -1,128 +1,47 @@
1
- <script lang="ts" generics="T extends {id: string}">import { Button } from '../button';
2
- import { DynamicComponent } from '../dynamic-component';
1
+ <script lang="ts" generics="T extends {id: string}">import { DynamicComponent } from '../dynamic-component';
3
2
  import { EmptyState } from '../empty-state';
4
- import { Icon } from '../icon';
5
- import { IconText } from '../icon-text';
6
- import { PopoverItem } from '../popover';
7
- import { TableActionsCell, TableBadgeCell, TableButtonCell, TableByCell, TableCheckboxCell, TableHideableCell, TableIconCell, TableImageCell, TableMoveRowCell, TableCustomCell, TableSelectCell, TableTextCell, TableTextInputCell } from './table-cells';
8
- import { ResolvedColumn } from './table-column-models.svelte';
3
+ import { TableCell, TableHideableCell } from './table-cells';
9
4
  import { TableLocalization } from './table-localization';
10
- import IconReorderDotsHorizontal from '@fluentui/svg-icons/icons/re_order_dots_horizontal_20_regular.svg?raw';
11
- import { untrack } from 'svelte';
12
- import { flip } from 'svelte/animate';
13
- import { dndzone } from 'svelte-dnd-action';
14
- let { model, rowsDraggable = false, showPlaceholder = false, showAlternativeView = false, on, alternativeView, placeholderRow, customNoItemsPlaceholder } = $props();
5
+ import { createTableView, cssWidth } from './table-view.svelte';
6
+ let { model, showPlaceholder = false, showAlternativeView = false, grouping, on, alternativeView, placeholderRow, customNoItemsPlaceholder } = $props();
15
7
  const localization = new TableLocalization();
16
- let showNoItemsPlaceholder = $state(false);
17
- let showNoItemsTimeout = 0;
18
- let showNoItemsPlaceholderFn = null;
19
- let hideNoItemsPlaceholderFn = null;
20
- // One-time setup: selection subscriptions + no-items placeholder logic
21
- $effect(() => untrack(() => {
22
- const subscriptions = [
23
- model.selection.subscribeOnChange((values) => on?.selectionChanged?.(values)),
24
- model.selection.subscribeOnAdd((values) => on?.itemsSelected?.(values)),
25
- model.selection.subscribeOnRemove((values) => on?.itemsDeselected?.(values))
26
- ];
27
- showNoItemsPlaceholderFn = () => {
28
- showNoItemsTimeout = window.setTimeout(() => {
29
- showNoItemsPlaceholder = !model.items.length;
30
- }, 700);
31
- };
32
- hideNoItemsPlaceholderFn = () => {
33
- clearTimeout(showNoItemsTimeout);
34
- showNoItemsPlaceholder = false;
35
- };
36
- return () => {
37
- subscriptions.forEach((unsubscribe) => unsubscribe());
38
- };
39
- }));
40
- $effect(() => {
41
- if (!model.items.length) {
42
- untrack(() => showNoItemsPlaceholderFn?.());
8
+ const view = createTableView(() => model, () => on);
9
+ const displayRows = $derived.by(() => {
10
+ const items = model.items;
11
+ const grp = grouping;
12
+ if (!grp) {
13
+ return items.map((item, index) => ({ kind: 'item', item, index }));
43
14
  }
44
- else {
45
- untrack(() => hideNoItemsPlaceholderFn?.());
15
+ const keys = items.map((item) => grp.key(item));
16
+ const out = [];
17
+ let i = 0;
18
+ while (i < items.length) {
19
+ const key = keys[i];
20
+ if (key === null) {
21
+ out.push({ kind: 'item', item: items[i], index: i });
22
+ i += 1;
23
+ continue;
24
+ }
25
+ let j = i + 1;
26
+ while (j < items.length && keys[j] === key) {
27
+ j += 1;
28
+ }
29
+ out.push({ kind: 'group', key, label: grp.label ? grp.label(key, items[i]) : key, count: j - i });
30
+ for (let k = i; k < j; k += 1) {
31
+ out.push({ kind: 'item', item: items[k], index: k });
32
+ }
33
+ i = j;
46
34
  }
35
+ return out;
47
36
  });
48
- // region Drag and Drop
49
- const flipDurationMs = 200;
50
- let tableRef = $state.raw(null);
51
- const handleConsider = (e) => {
52
- const { items: newItems } = e.detail;
53
- model.items = newItems;
54
- };
55
- const handleFinalize = (e) => {
56
- const { items: newItems } = e.detail;
57
- model.items = newItems;
58
- on?.itemsReordered?.(newItems);
59
- };
60
- const startDrag = (e) => {
61
- // preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
62
- e.preventDefault();
63
- };
64
- const transformDraggedElement = (draggedRow) => {
65
- if (!draggedRow) {
66
- return;
67
- }
68
- const referenceRow = tableRef.querySelector('tbody tr:not([data-is-dnd-shadow-item-internal])') ?? tableRef.querySelector('tbody tr');
69
- const referenceColumns = referenceRow?.querySelectorAll('td') ?? [];
70
- const draggedColumns = draggedRow.querySelectorAll('td');
71
- if (!referenceRow || referenceColumns.length !== draggedColumns.length) {
72
- console.error('not equal count of model.columns withing table rows');
73
- return;
74
- }
75
- for (let i = 0, length = referenceColumns.length; i < length; i++) {
76
- draggedColumns[i].style.width = `${referenceColumns[i].clientWidth}px`;
77
- draggedColumns[i].style.height = `${referenceColumns[i].clientHeight}px`;
78
- }
79
- // Clone is reparented to <body>, losing the .table-container --_table--* vars; cells collapse without this.
80
- const cellStyle = window.getComputedStyle(referenceColumns[0]);
81
- draggedRow.style.setProperty('--_table--cell--font-size', cellStyle.fontSize);
82
- draggedRow.style.setProperty('--_table--cell--horizontal-padding', cellStyle.paddingInlineStart);
83
- draggedRow.style.setProperty('--_table--border-color', cellStyle.borderBottomColor);
84
- };
85
- // endregion Drag and Drop
86
- const changeItemPosition = (item, positionChange) => {
87
- const index = model.items.indexOf(item);
88
- const newIndex = index + positionChange;
89
- const newItems = [...model.items];
90
- newItems.splice(index, 1);
91
- newItems.splice(newIndex, 0, item);
92
- model.items = newItems;
93
- on?.itemsReordered?.(newItems);
94
- };
95
- const disableMoveRowCell = (def) => {
96
- if (!def.disableFactory) {
97
- return false;
98
- }
99
- return def.disableFactory();
100
- };
101
- const cssWidth = (column) => {
102
- if (column.fixedCssWidth) {
103
- return `width: ${column.fixedCssWidth};`;
104
- }
105
- return 'width: auto;';
106
- };
107
- const anyVisibleItemActions = (item) => {
108
- return model.itemActions.some((action) => (action.visibilityFactory ? action.visibilityFactory(item) : true));
109
- };
110
- const getEditorColumnOrDefault = (column, editMode) => {
111
- if (!editMode) {
112
- return column;
113
- }
114
- if (column.editorColumn) {
115
- return column.editorColumn;
116
- }
117
- return column;
118
- };
37
+ const visibleColspan = $derived(model.columns.filter((column) => !column.hidden).length);
119
38
  </script>
120
39
 
121
40
  <div
122
41
  class="table-container table-container--{model.styles?.size ?? 'md'} table-container--{model.styles?.variant ?? 'plain'}"
123
42
  class:table-container--zebra={model.styles?.zebra === true}>
124
43
  {#if alternativeView && showAlternativeView}
125
- {#if showPlaceholder || showNoItemsPlaceholder}
44
+ {#if showPlaceholder || view.showNoItemsPlaceholder}
126
45
  <div class="alternative-view__placeholder">
127
46
  {#if showPlaceholder}
128
47
  {@render placeholderRow?.()}
@@ -134,12 +53,9 @@ const getEditorColumnOrDefault = (column, editMode) => {
134
53
  {@render alternativeView()}
135
54
  {/if}
136
55
  {:else}
137
- <table class="table" class:table--sticky-header={model.styles?.stickyHeader === true} bind:this={tableRef}>
56
+ <table class="table" class:table--sticky-header={model.styles?.stickyHeader === true}>
138
57
  <thead class="table__head">
139
58
  <tr>
140
- {#if rowsDraggable && !model.editingItem}
141
- <th class="table__th table__drag-handle">&nbsp;</th>
142
- {/if}
143
59
  {#each model.columns as column (column)}
144
60
  <TableHideableCell column={column}>
145
61
  <th class="table__th" class:table__th--centered={column.centered} style={cssWidth(column)} title={column.title}>
@@ -149,21 +65,10 @@ const getEditorColumnOrDefault = (column, editMode) => {
149
65
  {/each}
150
66
  </tr>
151
67
  </thead>
152
- <tbody
153
- use:dndzone={{
154
- items: model.items,
155
- dragDisabled: !rowsDraggable,
156
- dropFromOthersDisabled: true,
157
- flipDurationMs,
158
- dropTargetStyle: {},
159
- transformDraggedElement,
160
- type: 'table'
161
- }}
162
- onconsider={handleConsider}
163
- onfinalize={handleFinalize}>
164
- {#if showPlaceholder || showNoItemsPlaceholder}
68
+ <tbody>
69
+ {#if showPlaceholder || view.showNoItemsPlaceholder}
165
70
  <tr class="table__tr table__tr--placeholder">
166
- <td colspan={model.columns.length}>
71
+ <td colspan={visibleColspan}>
167
72
  <div class="table__placeholder">
168
73
  {#if showPlaceholder}
169
74
  {@render placeholderRow?.()}
@@ -176,107 +81,45 @@ const getEditorColumnOrDefault = (column, editMode) => {
176
81
  </td>
177
82
  </tr>
178
83
  {:else}
179
- {#snippet cell({ item, column, itemIndex }: { item: T; column: ResolvedColumn<T>; itemIndex: Number })}
180
- {@const editMode = model.editingItem?.id === item.id}
181
- {@const def = column.def}
182
- {#if def.type === 'actions'}
183
- {#if anyVisibleItemActions(item)}
184
- {#if editMode}
185
- <div class="table__save-cancel">
186
- <Button type="button" size="sm" variant="success" on={{ click: () => on?.saveChanges?.(item) }}>{localization.save}</Button>
187
- <Button type="button" size="sm" variant="ghost" on={{ click: () => on?.cancelChanges?.() }}>{localization.cancel}</Button>
188
- </div>
189
- {:else}
190
- <TableActionsCell popoverPosition={model.styles?.actionsPopoverTopDirection ? 'top' : 'bottom'}>
191
- <div class="table__actions">
192
- {#each model.itemActions as action (action)}
193
- {#if action.visibilityFactory ? action.visibilityFactory(item) : true}
194
- <PopoverItem on={{ click: () => action.action(item) }}>
195
- <IconText icon={action.icon} size="md">
196
- {action.title}
197
- </IconText>
198
- </PopoverItem>
199
- {/if}
200
- {/each}
201
- </div>
202
- </TableActionsCell>
203
- {/if}
204
- {/if}
205
- {:else if def.type === 'badge'}
206
- <TableBadgeCell column={def} item={item} />
207
- {:else if def.type === 'button'}
208
- <TableButtonCell column={def} item={item} />
209
- {:else if def.type === 'by'}
210
- <TableByCell column={def} item={item} />
211
- {:else if def.type === 'checkbox'}
212
- <TableCheckboxCell item={item} selection={model.selection} />
213
- {:else if def.type === 'custom'}
214
- <TableCustomCell column={def} item={item} />
215
- {:else if def.type === 'icon'}
216
- <TableIconCell column={def} item={item} />
217
- {:else if def.type === 'image'}
218
- <TableImageCell column={def} item={item} centered={column.centered} />
219
- {:else if def.type === 'move-row'}
220
- {#if !editMode}
221
- <TableMoveRowCell
222
- on={{
223
- up: disableMoveRowCell(def) || itemIndex < 1 ? undefined : () => changeItemPosition(item, -1),
224
- down: disableMoveRowCell(def) || itemIndex >= model.items.length - 1 ? undefined : () => changeItemPosition(item, 1)
225
- }} />
226
- {/if}
227
- {:else if def.type === 'select'}
228
- <TableSelectCell column={def} item={item} />
229
- {:else if def.type === 'snippet'}
230
- {@render def.cell(item)}
231
- {:else if def.type === 'text'}
232
- <TableTextCell column={def} item={item} centered={column.centered} />
233
- {:else if def.type === 'text-input'}
234
- <TableTextInputCell column={def} item={item}></TableTextInputCell>
84
+ {#each displayRows as row (row.kind === 'group' ? 'g:' + row.key : 'i:' + row.item.id)}
85
+ {#if row.kind === 'group'}
86
+ <tr>
87
+ <td class="table__group-header" colspan={visibleColspan}>
88
+ {#if grouping?.header}
89
+ {@render grouping.header({ key: row.key, label: row.label, count: row.count })}
90
+ {:else}
91
+ {row.label}
92
+ {/if}
93
+ </td>
94
+ </tr>
235
95
  {:else}
236
- <TableTextCell column={def} item={item} centered={false} />
96
+ {@const item = row.item}
97
+ {@const itemIndex = row.index}
98
+ {@const isSelected = model.selection.has(item.id)}
99
+ {@const isHighlighted = model.highlightedItemIds.includes(item.id)}
100
+ {@const flushBottom = model.styles?.variant === 'card' && itemIndex === model.items.length - 1}
101
+ {@const zebra = model.styles?.zebra === true && itemIndex % 2 === 1 && !isSelected && !isHighlighted}
102
+ <tr
103
+ class="table__tr"
104
+ id={item.id}
105
+ class:table__tr--selected={isSelected}
106
+ class:table__tr--highlighted={isHighlighted}
107
+ class:table__tr--zebra={zebra}>
108
+ {#each model.columns as column (column)}
109
+ <TableHideableCell column={column}>
110
+ <td
111
+ class="table__td"
112
+ class:table__td--centered={column.centered}
113
+ class:table__td--clickable={!!column.onClick}
114
+ class:table__td--flush={flushBottom}
115
+ style={cssWidth(column)}
116
+ onclick={() => column.onClick && column.onClick(item)}>
117
+ <TableCell model={model} item={item} column={column} itemIndex={itemIndex} on={{ itemsReordered: on?.itemsReordered }} />
118
+ </td>
119
+ </TableHideableCell>
120
+ {/each}
121
+ </tr>
237
122
  {/if}
238
- {/snippet}
239
- {#each model.items as item, itemIndex (item)}
240
- {@const editMode = model.editingItem?.id === item.id}
241
- {@const isSelected = model.selection.has(item.id)}
242
- {@const isHighlighted = model.highlightedItemIds.includes(item.id)}
243
- {@const flushBottom = model.styles?.variant === 'card' && itemIndex === model.items.length - 1}
244
- {@const zebra = model.styles?.zebra === true && itemIndex % 2 === 1 && !isSelected && !isHighlighted}
245
- <tr
246
- animate:flip={{ duration: flipDurationMs }}
247
- class="table__tr"
248
- id={item.id}
249
- class:table__tr--selected={isSelected}
250
- class:table__tr--highlighted={isHighlighted}
251
- class:table__tr--zebra={zebra}>
252
- {#if rowsDraggable && !model.editingItem}
253
- <td
254
- class="table__td table__drag-handle table__drag-handle--dragging"
255
- class:table__td--flush={flushBottom}
256
- onmousedown={startDrag}
257
- ontouchstart={startDrag}>
258
- <Icon src={IconReorderDotsHorizontal} />
259
- </td>
260
- {/if}
261
-
262
- {#each model.columns as column (column)}
263
- <TableHideableCell column={column}>
264
- <td
265
- class="table__td"
266
- class:table__td--centered={column.centered}
267
- class:table__td--clickable={!!column.onClick && !editMode}
268
- class:table__td--flush={flushBottom}
269
- style={cssWidth(column)}
270
- onclick={() => !editMode && column.onClick && column.onClick(item)}>
271
- {@render cell({
272
- item: editMode && model.editingItem ? model.editingItem : item,
273
- column: getEditorColumnOrDefault(column, editMode),
274
- itemIndex
275
- })}
276
- </td>
277
- </TableHideableCell>
278
- {/each}
279
- </tr>
280
123
  {/each}
281
124
  {/if}
282
125
  </tbody>
@@ -286,7 +129,9 @@ const getEditorColumnOrDefault = (column, editMode) => {
286
129
 
287
130
  <!--
288
131
  @component
289
- Data table component with support for sorting, selection, drag-and-drop row reordering, inline editing, column visibility management, and group actions.
132
+ Data table with sorting, selection, column visibility management, optional consumer-driven row grouping
133
+ (`grouping`), and group actions. For drag-and-drop row reordering use `DraggableTable` instead (this static
134
+ variant ships no dnd code).
290
135
 
291
136
  ### TableStyles (via `model.styles`)
292
137
  | Field | Type | Effect |
@@ -312,9 +157,6 @@ Data table component with support for sorting, selection, drag-and-drop row reor
312
157
  | `--sc-kit--table--card--background` | Card variant background | `--sc-kit--color--bg--panel` |
313
158
  | `--sc-kit--table--card--border-color` | Card variant border | `--sc-kit--color--border` |
314
159
  | `--sc-kit--table--card--border-radius` | Card variant radius | `--sc-kit--radius--lg` |
315
- | `--sc-kit--table-actions-cell--trigger--border-color` | Actions trigger border | `--sc-kit--color--accent--soft` |
316
- | `--sc-kit--table-actions-cell--trigger--icon-color` | Actions trigger icon | `--sc-kit--color--accent` |
317
- | `--sc-kit--table-text-cell--clickable--color` | Clickable text cell color | `--sc-kit--color--accent` |
318
160
  -->
319
161
 
320
162
  <style>.alternative-view__placeholder {
@@ -327,10 +169,10 @@ Data table component with support for sorting, selection, drag-and-drop row reor
327
169
  }
328
170
 
329
171
  .table-container {
330
- --_table--row--height: var(--sc-kit--table--row--height);
331
- --_table--cell--font-size: var(--sc-kit--table--cell--font-size);
332
- --_table--cell--horizontal-padding: var(--sc-kit--table--cell--horizontal-padding);
333
- --_table--head--height: var(--sc-kit--table--head--height, var(--_table--row--height));
172
+ --_table--row--height: var(--sc-kit--table--row--height, var(--_table--size-row-height));
173
+ --_table--cell--font-size: var(--sc-kit--table--cell--font-size, var(--_table--size-cell-font-size));
174
+ --_table--cell--horizontal-padding: var(--sc-kit--table--cell--horizontal-padding, var(--_table--size-cell-padding));
175
+ --_table--head--height: var(--sc-kit--table--head--height, var(--_table--size-head-height, var(--_table--row--height)));
334
176
  --_table--head--background-color: var(--sc-kit--table--head--background-color, var(--sc-kit--color--bg--field-alt));
335
177
  --_table--head--color: var(--sc-kit--table--head--color, var(--sc-kit--color--text--secondary));
336
178
  --_table--border-color: var(--sc-kit--table--border-color, var(--sc-kit--color--border));
@@ -367,16 +209,16 @@ Data table component with support for sorting, selection, drag-and-drop row reor
367
209
  }
368
210
  }
369
211
  .table-container--md {
370
- --sc-kit--table--row--height: 2.75rem;
371
- --sc-kit--table--head--height: 2.5rem;
372
- --sc-kit--table--cell--font-size: var(--sc-kit--font-size--md);
373
- --sc-kit--table--cell--horizontal-padding: var(--sc-kit--space--4);
212
+ --_table--size-row-height: 2.75rem;
213
+ --_table--size-head-height: 2.5rem;
214
+ --_table--size-cell-font-size: var(--sc-kit--font-size--md);
215
+ --_table--size-cell-padding: var(--sc-kit--space--4);
374
216
  }
375
217
  .table-container--sm {
376
- --sc-kit--table--row--height: 2.25rem;
377
- --sc-kit--table--head--height: 2rem;
378
- --sc-kit--table--cell--font-size: var(--sc-kit--font-size--sm);
379
- --sc-kit--table--cell--horizontal-padding: var(--sc-kit--space--3);
218
+ --_table--size-row-height: 2.25rem;
219
+ --_table--size-head-height: 2rem;
220
+ --_table--size-cell-font-size: var(--sc-kit--font-size--sm);
221
+ --_table--size-cell-padding: var(--sc-kit--space--3);
380
222
  }
381
223
  .table-container--card {
382
224
  background: var(--_table--card--background);
@@ -452,12 +294,6 @@ Data table component with support for sorting, selection, drag-and-drop row reor
452
294
  .table__td--flush {
453
295
  border-bottom: none;
454
296
  }
455
- .table__save-cancel {
456
- display: flex;
457
- flex-direction: column;
458
- gap: var(--sc-kit--space--2);
459
- --sc-kit--button--min-width: 4.6875rem;
460
- }
461
297
  .table__placeholder {
462
298
  display: flex;
463
299
  align-items: center;
@@ -465,21 +301,16 @@ Data table component with support for sorting, selection, drag-and-drop row reor
465
301
  font-size: 80%;
466
302
  user-select: none;
467
303
  }
468
- .table__actions {
469
- display: contents;
470
- }
471
- .table__drag-handle {
472
- width: 2.25rem;
473
- cursor: grab;
474
- text-align: center;
475
- --sc-kit--icon--size: 1.25rem;
476
- --sc-kit--icon--color: var(--sc-kit--color--text--muted);
477
- }
478
- .table__drag-handle--dragging {
479
- cursor: grabbing;
480
- }
481
304
  .table--sticky-header thead {
482
305
  position: sticky;
483
306
  top: 0;
484
307
  z-index: 1;
308
+ }
309
+
310
+ .table__group-header {
311
+ padding-block: var(--sc-kit--space--6) var(--sc-kit--space--2);
312
+ padding-inline: var(--_table--cell--horizontal-padding);
313
+ font-size: var(--sc-kit--font-size--sm);
314
+ font-weight: var(--sc-kit--font-weight--semibold);
315
+ color: var(--sc-kit--color--text--secondary);
485
316
  }</style>
@@ -1,20 +1,29 @@
1
1
  import type { TableModel } from './table-model.svelte';
2
- import { type Snippet } from 'svelte';
2
+ import type { Snippet } from 'svelte';
3
3
  declare function $$render<T extends {
4
4
  id: string;
5
5
  }>(): {
6
6
  props: {
7
7
  model: TableModel<T>;
8
- rowsDraggable?: boolean;
9
8
  showPlaceholder?: boolean;
10
9
  showAlternativeView?: boolean;
10
+ /** Group consecutive (already-sorted) rows under section headers. `key` returns a group id per item (`null` = ungrouped); a header row renders wherever the key changes between neighbours. */
11
+ grouping?: {
12
+ key: (item: T) => string | null;
13
+ /** Header text — defaults to the group key. */
14
+ label?: (key: string, firstItem: T) => string;
15
+ /** Custom header rendering; receives the group key, resolved label, and row count. */
16
+ header?: Snippet<[{
17
+ key: string;
18
+ label: string;
19
+ count: number;
20
+ }]>;
21
+ };
11
22
  on?: {
12
23
  selectionChanged?: (e: T[]) => void;
13
24
  itemsSelected?: (e: T[]) => void;
14
25
  itemsDeselected?: (e: T[]) => void;
15
26
  itemsReordered?: (e: T[]) => void;
16
- saveChanges?: (e: T) => void;
17
- cancelChanges?: () => void;
18
27
  };
19
28
  alternativeView?: Snippet;
20
29
  placeholderRow?: Snippet;
@@ -46,7 +55,9 @@ interface $$IsomorphicComponent {
46
55
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
47
56
  }
48
57
  /**
49
- * Data table component with support for sorting, selection, drag-and-drop row reordering, inline editing, column visibility management, and group actions.
58
+ * Data table with sorting, selection, column visibility management, optional consumer-driven row grouping
59
+ * (`grouping`), and group actions. For drag-and-drop row reordering use `DraggableTable` instead (this static
60
+ * variant ships no dnd code).
50
61
  *
51
62
  * ### TableStyles (via `model.styles`)
52
63
  * | Field | Type | Effect |
@@ -72,9 +83,6 @@ interface $$IsomorphicComponent {
72
83
  * | `--sc-kit--table--card--background` | Card variant background | `--sc-kit--color--bg--panel` |
73
84
  * | `--sc-kit--table--card--border-color` | Card variant border | `--sc-kit--color--border` |
74
85
  * | `--sc-kit--table--card--border-radius` | Card variant radius | `--sc-kit--radius--lg` |
75
- * | `--sc-kit--table-actions-cell--trigger--border-color` | Actions trigger border | `--sc-kit--color--accent--soft` |
76
- * | `--sc-kit--table-actions-cell--trigger--icon-color` | Actions trigger icon | `--sc-kit--color--accent` |
77
- * | `--sc-kit--table-text-cell--clickable--color` | Clickable text cell color | `--sc-kit--color--accent` |
78
86
  */
79
87
  declare const Cmp: $$IsomorphicComponent;
80
88
  type Cmp<T extends {
@@ -1,4 +1,5 @@
1
1
  export { default as Table } from './cmp.table.svelte';
2
+ export { default as DraggableTable } from './cmp.table-draggable.svelte';
2
3
  export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
3
4
  export { default as TableGroupActions } from './table-group-actions/cmp.table-group-actions.svelte';
4
5
  export type { ColumnsConfig, TableColumnSortDirection, TableColumnType, TableImageColumnFormat, TableItemAction, TableTextColumnFormat, TableOrderByState, PageQuery, IAnyTableColumn } from './types';
@@ -1,4 +1,5 @@
1
1
  export { default as Table } from './cmp.table.svelte';
2
+ export { default as DraggableTable } from './cmp.table-draggable.svelte';
2
3
  export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
3
4
  export { default as TableGroupActions } from './table-group-actions/cmp.table-group-actions.svelte';
4
5
  export { TableModel } from './table-model.svelte';
@@ -1,13 +1,2 @@
1
- export { default as TableActionsCell } from './table-actions-cell.svelte';
2
- export { default as TableBadgeCell } from './table-badge-cell.svelte';
3
- export { default as TableButtonCell } from './table-button-cell.svelte';
4
- export { default as TableByCell } from './table-by-cell.svelte';
5
- export { default as TableCheckboxCell } from './table-checkbox-cell.svelte';
6
- export { default as TableCustomCell } from './table-custom-cell.svelte';
7
- export { default as TableIconCell } from './table-icon-cell.svelte';
8
- export { default as TableImageCell } from './table-image-cell.svelte';
9
- export { default as TableMoveRowCell } from './table-move-row-cell.svelte';
10
- export { default as TableSelectCell } from './table-select-cell.svelte';
11
- export { default as TableTextCell } from './table-text-cell.svelte';
12
- export { default as TableTextInputCell } from './table-text-input-cell.svelte';
1
+ export { default as TableCell } from './table-cell.svelte';
13
2
  export { default as TableHideableCell } from './table-hideable-cell.svelte';
@@ -1,13 +1,2 @@
1
- export { default as TableActionsCell } from './table-actions-cell.svelte';
2
- export { default as TableBadgeCell } from './table-badge-cell.svelte';
3
- export { default as TableButtonCell } from './table-button-cell.svelte';
4
- export { default as TableByCell } from './table-by-cell.svelte';
5
- export { default as TableCheckboxCell } from './table-checkbox-cell.svelte';
6
- export { default as TableCustomCell } from './table-custom-cell.svelte';
7
- export { default as TableIconCell } from './table-icon-cell.svelte';
8
- export { default as TableImageCell } from './table-image-cell.svelte';
9
- export { default as TableMoveRowCell } from './table-move-row-cell.svelte';
10
- export { default as TableSelectCell } from './table-select-cell.svelte';
11
- export { default as TableTextCell } from './table-text-cell.svelte';
12
- export { default as TableTextInputCell } from './table-text-input-cell.svelte';
1
+ export { default as TableCell } from './table-cell.svelte';
13
2
  export { default as TableHideableCell } from './table-hideable-cell.svelte';
@@ -0,0 +1,77 @@
1
+ <script lang="ts" generics="T extends {id: string}">import { IconText } from '../../icon-text';
2
+ import { PopoverItem } from '../../popover';
3
+ import { default as TableActionsCell } from './table-actions-cell.svelte';
4
+ import { default as TableBadgeCell } from './table-badge-cell.svelte';
5
+ import { default as TableButtonCell } from './table-button-cell.svelte';
6
+ import { default as TableByCell } from './table-by-cell.svelte';
7
+ import { default as TableCheckboxCell } from './table-checkbox-cell.svelte';
8
+ import { default as TableCustomCell } from './table-custom-cell.svelte';
9
+ import { default as TableIconCell } from './table-icon-cell.svelte';
10
+ import { default as TableImageCell } from './table-image-cell.svelte';
11
+ import { default as TableMoveRowCell } from './table-move-row-cell.svelte';
12
+ import { default as TableTextCell } from './table-text-cell.svelte';
13
+ const { model, item, column, itemIndex, on } = $props();
14
+ const def = $derived(column.def);
15
+ const visibleActions = $derived(model.itemActions.filter((action) => (action.visibilityFactory ? action.visibilityFactory(item) : true)));
16
+ const disableMoveRowCell = (moveRowDef) => {
17
+ if (!moveRowDef.disableFactory) {
18
+ return false;
19
+ }
20
+ return moveRowDef.disableFactory();
21
+ };
22
+ const changeItemPosition = (target, positionChange) => {
23
+ const index = model.items.indexOf(target);
24
+ const newIndex = index + positionChange;
25
+ const newItems = [...model.items];
26
+ newItems.splice(index, 1);
27
+ newItems.splice(newIndex, 0, target);
28
+ model.reorderItems(newItems);
29
+ on?.itemsReordered?.(newItems);
30
+ };
31
+ </script>
32
+
33
+ {#if def.type === 'actions'}
34
+ {#if visibleActions.length}
35
+ <TableActionsCell popoverPosition={model.styles?.actionsPopoverTopDirection ? 'top' : 'bottom'}>
36
+ <div class="actions">
37
+ {#each visibleActions as action (action)}
38
+ <PopoverItem on={{ click: () => action.action(item) }}>
39
+ <IconText icon={action.icon} size="md">
40
+ {action.title}
41
+ </IconText>
42
+ </PopoverItem>
43
+ {/each}
44
+ </div>
45
+ </TableActionsCell>
46
+ {/if}
47
+ {:else if def.type === 'badge'}
48
+ <TableBadgeCell column={def} item={item} />
49
+ {:else if def.type === 'button'}
50
+ <TableButtonCell column={def} item={item} />
51
+ {:else if def.type === 'by'}
52
+ <TableByCell column={def} item={item} />
53
+ {:else if def.type === 'checkbox'}
54
+ <TableCheckboxCell item={item} selection={model.selection} />
55
+ {:else if def.type === 'custom'}
56
+ <TableCustomCell column={def} item={item} />
57
+ {:else if def.type === 'icon'}
58
+ <TableIconCell column={def} item={item} />
59
+ {:else if def.type === 'image'}
60
+ <TableImageCell column={def} item={item} centered={column.centered} />
61
+ {:else if def.type === 'move-row'}
62
+ <TableMoveRowCell
63
+ on={{
64
+ up: disableMoveRowCell(def) || itemIndex < 1 ? undefined : () => changeItemPosition(item, -1),
65
+ down: disableMoveRowCell(def) || itemIndex >= model.items.length - 1 ? undefined : () => changeItemPosition(item, 1)
66
+ }} />
67
+ {:else if def.type === 'snippet'}
68
+ {@render def.cell(item)}
69
+ {:else if def.type === 'text'}
70
+ <TableTextCell column={def} item={item} centered={column.centered} />
71
+ {:else}
72
+ <TableTextCell column={def} item={item} centered={false} />
73
+ {/if}
74
+
75
+ <style>.actions {
76
+ display: contents;
77
+ }</style>
@@ -1,10 +1,16 @@
1
- import type { ITableSelectColumn } from '../types';
1
+ import type { ResolvedColumn } from '../table-column-models.svelte';
2
+ import type { TableModel } from '../table-model.svelte';
2
3
  declare function $$render<T extends {
3
4
  id: string;
4
5
  }>(): {
5
6
  props: {
7
+ model: TableModel<T>;
6
8
  item: T;
7
- column: ITableSelectColumn<T, keyof T>;
9
+ column: ResolvedColumn<T>;
10
+ itemIndex: number;
11
+ on?: {
12
+ itemsReordered?: (items: T[]) => void;
13
+ };
8
14
  };
9
15
  exports: {};
10
16
  bindings: "";
@@ -31,8 +37,8 @@ interface $$IsomorphicComponent {
31
37
  }>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
32
38
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
33
39
  }
34
- declare const TableSelectCell: $$IsomorphicComponent;
35
- type TableSelectCell<T extends {
40
+ declare const TableCell: $$IsomorphicComponent;
41
+ type TableCell<T extends {
36
42
  id: string;
37
- }> = InstanceType<typeof TableSelectCell<T>>;
38
- export default TableSelectCell;
43
+ }> = InstanceType<typeof TableCell<T>>;
44
+ export default TableCell;