@streamscloud/kit 0.2.10 → 0.2.11
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/ui/table/cmp.table.svelte +417 -0
- package/dist/ui/table/cmp.table.svelte.d.ts +74 -0
- package/dist/ui/table/index.d.ts +7 -0
- package/dist/ui/table/index.js +5 -0
- package/dist/ui/table/service.d.ts +7 -0
- package/dist/ui/table/service.js +17 -0
- package/dist/ui/table/table-cells/index.d.ts +13 -0
- package/dist/ui/table/table-cells/index.js +13 -0
- package/dist/ui/table/table-cells/table-actions-cell.svelte +53 -0
- package/dist/ui/table/table-cells/table-actions-cell.svelte.d.ts +18 -0
- package/dist/ui/table/table-cells/table-badge-cell.svelte +15 -0
- package/dist/ui/table/table-cells/table-badge-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-button-cell.svelte +20 -0
- package/dist/ui/table/table-cells/table-button-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-by-cell.svelte +105 -0
- package/dist/ui/table/table-cells/table-by-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-checkbox-cell.svelte +21 -0
- package/dist/ui/table/table-cells/table-checkbox-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-custom-cell.svelte +5 -0
- package/dist/ui/table/table-cells/table-custom-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-hideable-cell.svelte +7 -0
- package/dist/ui/table/table-cells/table-hideable-cell.svelte.d.ts +39 -0
- package/dist/ui/table/table-cells/table-icon-cell.svelte +53 -0
- package/dist/ui/table/table-cells/table-icon-cell.svelte.d.ts +48 -0
- package/dist/ui/table/table-cells/table-image-cell.svelte +64 -0
- package/dist/ui/table/table-cells/table-image-cell.svelte.d.ts +39 -0
- package/dist/ui/table/table-cells/table-move-row-cell.svelte +29 -0
- package/dist/ui/table/table-cells/table-move-row-cell.svelte.d.ts +9 -0
- package/dist/ui/table/table-cells/table-select-cell.svelte +22 -0
- package/dist/ui/table/table-cells/table-select-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-cells/table-text-cell.svelte +60 -0
- package/dist/ui/table/table-cells/table-text-cell.svelte.d.ts +47 -0
- package/dist/ui/table/table-cells/table-text-input-cell.svelte +83 -0
- package/dist/ui/table/table-cells/table-text-input-cell.svelte.d.ts +38 -0
- package/dist/ui/table/table-column-models.svelte.d.ts +28 -0
- package/dist/ui/table/table-column-models.svelte.js +57 -0
- package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte +84 -0
- package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte.d.ts +46 -0
- package/dist/ui/table/table-group-actions/cmp.table-group-actions.svelte +54 -0
- package/dist/ui/table/table-group-actions/cmp.table-group-actions.svelte.d.ts +40 -0
- package/dist/ui/table/table-group-actions/types.svelte.d.ts +8 -0
- package/dist/ui/table/table-group-actions/types.svelte.js +1 -0
- package/dist/ui/table/table-headers/index.d.ts +3 -0
- package/dist/ui/table/table-headers/index.js +3 -0
- package/dist/ui/table/table-headers/table-checkbox-header.svelte +18 -0
- package/dist/ui/table/table-headers/table-checkbox-header.svelte.d.ts +41 -0
- package/dist/ui/table/table-headers/table-header-sortable.svelte +92 -0
- package/dist/ui/table/table-headers/table-header-sortable.svelte.d.ts +12 -0
- package/dist/ui/table/table-headers/table-header.svelte +18 -0
- package/dist/ui/table/table-headers/table-header.svelte.d.ts +10 -0
- package/dist/ui/table/table-model.svelte.d.ts +42 -0
- package/dist/ui/table/table-model.svelte.js +207 -0
- package/dist/ui/table/types.d.ts +144 -0
- package/dist/ui/table/types.js +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends {id: string}">import { Button } from '../button';
|
|
2
|
+
import { DropdownItem } from '../dropdown';
|
|
3
|
+
import { DynamicComponent } from '../dynamic-component';
|
|
4
|
+
import { Icon } from '../icon';
|
|
5
|
+
import { IconText } from '../icon-text';
|
|
6
|
+
import { Placeholder } from '../placeholder';
|
|
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';
|
|
9
|
+
import IconReorderDotsHorizontal from '@fluentui/svg-icons/icons/re_order_dots_horizontal_20_regular.svg?raw';
|
|
10
|
+
import { untrack } from 'svelte';
|
|
11
|
+
import { flip } from 'svelte/animate';
|
|
12
|
+
import { dndzone } from 'svelte-dnd-action';
|
|
13
|
+
let { model, rowsDraggable = false, showPlaceholder = false, showAlternativeView = false, on, alternativeView, placeholderRow, customNoItemsPlaceholder } = $props();
|
|
14
|
+
let showNoItemsPlaceholder = $state(false);
|
|
15
|
+
let showNoItemsTimeout = 0;
|
|
16
|
+
let showNoItemsPlaceholderFn = null;
|
|
17
|
+
let hideNoItemsPlaceholderFn = null;
|
|
18
|
+
// One-time setup: selection subscriptions + no-items placeholder logic
|
|
19
|
+
$effect(() => untrack(() => {
|
|
20
|
+
const subscriptions = [
|
|
21
|
+
model.selection.subscribeOnChange((values) => on?.selectionChanged?.(values)),
|
|
22
|
+
model.selection.subscribeOnAdd((values) => on?.itemsSelected?.(values)),
|
|
23
|
+
model.selection.subscribeOnRemove((values) => on?.itemsDeselected?.(values))
|
|
24
|
+
];
|
|
25
|
+
showNoItemsPlaceholderFn = () => {
|
|
26
|
+
showNoItemsTimeout = window.setTimeout(() => {
|
|
27
|
+
showNoItemsPlaceholder = !model.items.length;
|
|
28
|
+
}, 700);
|
|
29
|
+
};
|
|
30
|
+
hideNoItemsPlaceholderFn = () => {
|
|
31
|
+
clearTimeout(showNoItemsTimeout);
|
|
32
|
+
showNoItemsPlaceholder = false;
|
|
33
|
+
};
|
|
34
|
+
return () => {
|
|
35
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
36
|
+
};
|
|
37
|
+
}));
|
|
38
|
+
$effect(() => {
|
|
39
|
+
if (!model.items.length) {
|
|
40
|
+
untrack(() => showNoItemsPlaceholderFn?.());
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
untrack(() => hideNoItemsPlaceholderFn?.());
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
// region Drag and Drop
|
|
47
|
+
const flipDurationMs = 200;
|
|
48
|
+
let tableRef = $state.raw(null);
|
|
49
|
+
const handleConsider = (e) => {
|
|
50
|
+
const { items: newItems } = e.detail;
|
|
51
|
+
model.items = newItems;
|
|
52
|
+
};
|
|
53
|
+
const handleFinalize = (e) => {
|
|
54
|
+
const { items: newItems } = e.detail;
|
|
55
|
+
model.items = newItems;
|
|
56
|
+
on?.itemsReordered?.(newItems);
|
|
57
|
+
};
|
|
58
|
+
const startDrag = (e) => {
|
|
59
|
+
// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
};
|
|
62
|
+
const transformDraggedElement = (draggedRow) => {
|
|
63
|
+
if (!draggedRow) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const referenceColumns = tableRef.querySelector('tbody')?.querySelector('tr')?.querySelectorAll('td') || [];
|
|
67
|
+
const draggedColumns = draggedRow.querySelectorAll('td');
|
|
68
|
+
if (referenceColumns.length !== draggedColumns.length) {
|
|
69
|
+
console.error('not equal count of model.columns withing table rows');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
for (let i = 0, length = referenceColumns.length; i < length; i++) {
|
|
73
|
+
draggedColumns[i].style.width = `${referenceColumns[i].clientWidth}px`;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
// endregion Drag and Drop
|
|
77
|
+
const changeItemPosition = (item, positionChange) => {
|
|
78
|
+
const index = model.items.indexOf(item);
|
|
79
|
+
const newIndex = index + positionChange;
|
|
80
|
+
const newItems = [...model.items];
|
|
81
|
+
newItems.splice(index, 1);
|
|
82
|
+
newItems.splice(newIndex, 0, item);
|
|
83
|
+
model.items = newItems;
|
|
84
|
+
on?.itemsReordered?.(newItems);
|
|
85
|
+
};
|
|
86
|
+
const disableMoveRowCell = (def) => {
|
|
87
|
+
if (!def.disableFactory) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return def.disableFactory();
|
|
91
|
+
};
|
|
92
|
+
const cssWidth = (column) => {
|
|
93
|
+
if (column.fixedCssWidth) {
|
|
94
|
+
return `width: ${column.fixedCssWidth};`;
|
|
95
|
+
}
|
|
96
|
+
return 'width: auto;';
|
|
97
|
+
};
|
|
98
|
+
const anyVisibleItemActions = (item) => {
|
|
99
|
+
return model.itemActions.some((action) => (action.visibilityFactory ? action.visibilityFactory(item) : true));
|
|
100
|
+
};
|
|
101
|
+
const getEditorColumnOrDefault = (column, editMode) => {
|
|
102
|
+
if (!editMode) {
|
|
103
|
+
return column;
|
|
104
|
+
}
|
|
105
|
+
if (column.editorColumn) {
|
|
106
|
+
return column.editorColumn;
|
|
107
|
+
}
|
|
108
|
+
return column;
|
|
109
|
+
};
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<div class="table-container">
|
|
113
|
+
{#if alternativeView && showAlternativeView}
|
|
114
|
+
{#if showPlaceholder || showNoItemsPlaceholder}
|
|
115
|
+
<div class="alternative-view__placeholder">
|
|
116
|
+
{#if showPlaceholder}
|
|
117
|
+
{@render placeholderRow?.()}
|
|
118
|
+
{:else if customNoItemsPlaceholder}
|
|
119
|
+
{@render customNoItemsPlaceholder()}
|
|
120
|
+
{/if}
|
|
121
|
+
</div>
|
|
122
|
+
{:else}
|
|
123
|
+
{@render alternativeView()}
|
|
124
|
+
{/if}
|
|
125
|
+
{:else}
|
|
126
|
+
<table class="table" class:table--sticky-header={model.styles?.stickyHeader === true} bind:this={tableRef}>
|
|
127
|
+
<thead class="table__head">
|
|
128
|
+
<tr>
|
|
129
|
+
{#if rowsDraggable && !model.editingItem}
|
|
130
|
+
<th class="table__th table__drag-handle"> </th>
|
|
131
|
+
{/if}
|
|
132
|
+
{#each model.columns as column (column)}
|
|
133
|
+
<TableHideableCell column={column}>
|
|
134
|
+
<th class="table__th" class:table__th--centered={column.centered} style={cssWidth(column)} title={column.title}>
|
|
135
|
+
<DynamicComponent model={column.headerView} />
|
|
136
|
+
</th>
|
|
137
|
+
</TableHideableCell>
|
|
138
|
+
{/each}
|
|
139
|
+
</tr>
|
|
140
|
+
</thead>
|
|
141
|
+
<tbody
|
|
142
|
+
use:dndzone={{ items: model.items, dragDisabled: !rowsDraggable, flipDurationMs, dropTargetStyle: {}, transformDraggedElement, type: 'table' }}
|
|
143
|
+
onconsider={handleConsider}
|
|
144
|
+
onfinalize={handleFinalize}>
|
|
145
|
+
{#if showPlaceholder || showNoItemsPlaceholder}
|
|
146
|
+
<tr class="table__tr table__tr--placeholder">
|
|
147
|
+
<td colspan={model.columns.length}>
|
|
148
|
+
<div class="table__placeholder">
|
|
149
|
+
{#if showPlaceholder}
|
|
150
|
+
{@render placeholderRow?.()}
|
|
151
|
+
{:else if customNoItemsPlaceholder}
|
|
152
|
+
{@render customNoItemsPlaceholder()}
|
|
153
|
+
{:else}
|
|
154
|
+
<Placeholder imageSrc="/placeholders/default.svg" title="No Items <span>Found</span>" body="No data found. Create one to get started" />
|
|
155
|
+
{/if}
|
|
156
|
+
</div>
|
|
157
|
+
</td>
|
|
158
|
+
</tr>
|
|
159
|
+
{:else}
|
|
160
|
+
{#snippet cell({ item, column, itemIndex }: { item: T; column: ResolvedColumn<T>; itemIndex: Number })}
|
|
161
|
+
{@const editMode = model.editingItem?.id === item.id}
|
|
162
|
+
{@const def = column.def}
|
|
163
|
+
{#if def.type === 'actions'}
|
|
164
|
+
{#if anyVisibleItemActions(item)}
|
|
165
|
+
{#if editMode}
|
|
166
|
+
<div class="table__save-cancel">
|
|
167
|
+
<Button size="small" variant="transparent-success" on={{ click: () => on?.saveChanges?.(item) }}>Save</Button>
|
|
168
|
+
<Button size="small" variant="gray" on={{ click: () => on?.cancelChanges?.() }}>Cancel</Button>
|
|
169
|
+
</div>
|
|
170
|
+
{:else}
|
|
171
|
+
<TableActionsCell dropdownPosition={model.styles?.actionsDropdownTopDirection ? 'top' : 'bottom'}>
|
|
172
|
+
<div class="table__actions">
|
|
173
|
+
{#each model.itemActions as action (action)}
|
|
174
|
+
{#if action.visibilityFactory ? action.visibilityFactory(item) : true}
|
|
175
|
+
<DropdownItem on={{ click: () => action.action(item) }}>
|
|
176
|
+
<IconText icon={action.icon} iconColor={action.color}>
|
|
177
|
+
{action.title}
|
|
178
|
+
</IconText>
|
|
179
|
+
</DropdownItem>
|
|
180
|
+
{/if}
|
|
181
|
+
{/each}
|
|
182
|
+
</div>
|
|
183
|
+
</TableActionsCell>
|
|
184
|
+
{/if}
|
|
185
|
+
{/if}
|
|
186
|
+
{:else if def.type === 'badge'}
|
|
187
|
+
<TableBadgeCell column={def} item={item} />
|
|
188
|
+
{:else if def.type === 'button'}
|
|
189
|
+
<TableButtonCell column={def} item={item} />
|
|
190
|
+
{:else if def.type === 'by'}
|
|
191
|
+
<TableByCell column={def} item={item} />
|
|
192
|
+
{:else if def.type === 'checkbox'}
|
|
193
|
+
<TableCheckboxCell item={item} selection={model.selection} />
|
|
194
|
+
{:else if def.type === 'custom'}
|
|
195
|
+
<TableCustomCell column={def} item={item} />
|
|
196
|
+
{:else if def.type === 'icon'}
|
|
197
|
+
<TableIconCell column={def} item={item} />
|
|
198
|
+
{:else if def.type === 'image'}
|
|
199
|
+
<TableImageCell column={def} item={item} centered={column.centered} />
|
|
200
|
+
{:else if def.type === 'move-row'}
|
|
201
|
+
{#if !editMode}
|
|
202
|
+
<TableMoveRowCell
|
|
203
|
+
on={{
|
|
204
|
+
up: disableMoveRowCell(def) || itemIndex < 1 ? undefined : () => changeItemPosition(item, -1),
|
|
205
|
+
down: disableMoveRowCell(def) || itemIndex >= model.items.length - 1 ? undefined : () => changeItemPosition(item, 1)
|
|
206
|
+
}} />
|
|
207
|
+
{/if}
|
|
208
|
+
{:else if def.type === 'select'}
|
|
209
|
+
<TableSelectCell column={def} item={item} />
|
|
210
|
+
{:else if def.type === 'text'}
|
|
211
|
+
<TableTextCell column={def} item={item} centered={column.centered} />
|
|
212
|
+
{:else if def.type === 'text-input'}
|
|
213
|
+
<TableTextInputCell column={def} item={item}></TableTextInputCell>
|
|
214
|
+
{:else}
|
|
215
|
+
<TableTextCell column={def} item={item} centered={false} />
|
|
216
|
+
{/if}
|
|
217
|
+
{/snippet}
|
|
218
|
+
{#each model.items as item, itemIndex (item)}
|
|
219
|
+
{@const editMode = model.editingItem?.id === item.id}
|
|
220
|
+
<tr
|
|
221
|
+
animate:flip={{ duration: flipDurationMs }}
|
|
222
|
+
class="table__tr"
|
|
223
|
+
id={item.id}
|
|
224
|
+
class:table__tr--highlighted={model.highlightedItemIds.includes(item.id)}>
|
|
225
|
+
{#if rowsDraggable && !model.editingItem}
|
|
226
|
+
<td class="table__td table__drag-handle table__drag-handle--dragging" onmousedown={startDrag} ontouchstart={startDrag}>
|
|
227
|
+
<Icon src={IconReorderDotsHorizontal} />
|
|
228
|
+
</td>
|
|
229
|
+
{/if}
|
|
230
|
+
|
|
231
|
+
{#each model.columns as column (column)}
|
|
232
|
+
<TableHideableCell column={column}>
|
|
233
|
+
<td
|
|
234
|
+
class="table__td"
|
|
235
|
+
class:table__td--centered={column.centered}
|
|
236
|
+
class:table__td--clickable={!!column.onClick && !editMode}
|
|
237
|
+
style={cssWidth(column)}
|
|
238
|
+
onclick={() => !editMode && column.onClick && column.onClick(item)}>
|
|
239
|
+
{@render cell({
|
|
240
|
+
item: editMode && model.editingItem ? model.editingItem : item,
|
|
241
|
+
column: getEditorColumnOrDefault(column, editMode),
|
|
242
|
+
itemIndex
|
|
243
|
+
})}
|
|
244
|
+
</td>
|
|
245
|
+
</TableHideableCell>
|
|
246
|
+
{/each}
|
|
247
|
+
</tr>
|
|
248
|
+
{/each}
|
|
249
|
+
{/if}
|
|
250
|
+
</tbody>
|
|
251
|
+
</table>
|
|
252
|
+
{/if}
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<!--
|
|
256
|
+
@component
|
|
257
|
+
Data table component with support for sorting, selection, drag-and-drop row reordering,
|
|
258
|
+
inline editing, column visibility management, and group actions.
|
|
259
|
+
|
|
260
|
+
### CSS Custom Properties
|
|
261
|
+
| Property | Description | Default |
|
|
262
|
+
|---|---|---|
|
|
263
|
+
| `--sc-kit--table--row--height` | Row height | `3.125em` |
|
|
264
|
+
| `--sc-kit--table--padding-left` | Left padding for first column | `2em` |
|
|
265
|
+
| `--sc-kit--table--padding-right` | Right padding for last column | `3em` |
|
|
266
|
+
| `--sc-kit--table--head--background-color` | Header background | `light-dark(gray-50, dark-800)` |
|
|
267
|
+
| `--sc-kit--table--border-color` | Border color between rows | `light-dark(neutral-100, dark-800)` |
|
|
268
|
+
| `--sc-kit--table--cell--font-size` | Cell font size | `0.875em` |
|
|
269
|
+
| `--sc-kit--table--row--color` | Row background | `transparent` |
|
|
270
|
+
| `--sc-kit--table--row--alternative-color` | Hover/highlighted row background | `light-dark(neutral-100, dark-800)` |
|
|
271
|
+
| `--sc-kit--table-actions-cell--trigger--border-color` | Actions trigger border color | `light-dark(primary-50, primary-900)` |
|
|
272
|
+
| `--sc-kit--table-actions-cell--trigger--icon-color` | Actions trigger icon color | `light-dark(primary-300, primary-400)` |
|
|
273
|
+
| `--sc-kit--table-text-cell--clickable--color` | Clickable text cell color | `light-dark(primary-500, primary-400)` |
|
|
274
|
+
| `--sc-kit--table-icon-cell--tooltip--color` | Icon cell tooltip text color | `white` |
|
|
275
|
+
| `--sc-kit--table-icon-cell--tooltip--background` | Icon cell tooltip background | `black` |
|
|
276
|
+
| `--sc-kit--table-icon-cell--tooltip--opacity` | Icon cell tooltip opacity | `70%` |
|
|
277
|
+
-->
|
|
278
|
+
|
|
279
|
+
<style>.alternative-view__placeholder {
|
|
280
|
+
width: 100%;
|
|
281
|
+
display: flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
justify-content: center;
|
|
284
|
+
font-size: 80%;
|
|
285
|
+
user-select: none;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.table-container {
|
|
289
|
+
--_table--row--height: var(--sc-kit--table--row--height, 3.125em);
|
|
290
|
+
--_table--padding-left: var(--sc-kit--table--padding-left, 2em);
|
|
291
|
+
--_table--padding-right: var(--sc-kit--table--padding-right, 3em);
|
|
292
|
+
--_table--head--height: 2.625em;
|
|
293
|
+
--_table--head--background-color: var(--sc-kit--table--head--background-color, light-dark(#fafafa, #1e1e1e));
|
|
294
|
+
--_table--border-color: var(--sc-kit--table--border-color, light-dark(#f2f2f3, #1e1e1e));
|
|
295
|
+
--_table--cell--font-size: var(--sc-kit--table--cell--font-size, 0.875em);
|
|
296
|
+
--_table--cell--horizontal-padding: 0.75em;
|
|
297
|
+
--_table--row--color: var(--sc-kit--table--row--color, transparent);
|
|
298
|
+
--_table--row--alternative-color: var(--sc-kit--table--row--alternative-color, light-dark(#f2f2f3, #1e1e1e));
|
|
299
|
+
display: flex;
|
|
300
|
+
overflow-x: auto;
|
|
301
|
+
height: 100%;
|
|
302
|
+
--_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, light-dark(#d1d5db, #4b5563));
|
|
303
|
+
--_cross-browser-scrollbar--track-color: var(--scrollbar--track-color, transparent);
|
|
304
|
+
}
|
|
305
|
+
.table-container::-webkit-scrollbar {
|
|
306
|
+
width: 6px;
|
|
307
|
+
height: 6px;
|
|
308
|
+
}
|
|
309
|
+
.table-container::-webkit-scrollbar-track {
|
|
310
|
+
background: var(--_cross-browser-scrollbar--track-color);
|
|
311
|
+
border-radius: 100vw;
|
|
312
|
+
}
|
|
313
|
+
.table-container::-webkit-scrollbar-thumb {
|
|
314
|
+
background: var(--_cross-browser-scrollbar--thumb-color);
|
|
315
|
+
border-radius: 100vw;
|
|
316
|
+
}
|
|
317
|
+
@supports (scrollbar-color: transparent transparent) {
|
|
318
|
+
.table-container {
|
|
319
|
+
scrollbar-color: var(--_cross-browser-scrollbar--thumb-color) var(--_cross-browser-scrollbar--track-color);
|
|
320
|
+
scrollbar-width: thin;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.table {
|
|
325
|
+
width: 100%;
|
|
326
|
+
table-layout: auto;
|
|
327
|
+
height: fit-content;
|
|
328
|
+
}
|
|
329
|
+
.table__head {
|
|
330
|
+
height: var(--_table--head--height);
|
|
331
|
+
max-height: var(--_table--head--height);
|
|
332
|
+
background: var(--_table--head--background-color);
|
|
333
|
+
border-bottom: 1px solid var(--_table--border-color);
|
|
334
|
+
}
|
|
335
|
+
.table__th {
|
|
336
|
+
padding: 0 var(--_table--cell--horizontal-padding);
|
|
337
|
+
text-align: left;
|
|
338
|
+
-webkit-user-drag: none;
|
|
339
|
+
user-select: none;
|
|
340
|
+
}
|
|
341
|
+
.table__th :global([contenteditable]) {
|
|
342
|
+
user-select: text;
|
|
343
|
+
}
|
|
344
|
+
.table__th--centered {
|
|
345
|
+
text-align: center;
|
|
346
|
+
}
|
|
347
|
+
.table__th:first-child {
|
|
348
|
+
padding-left: var(--_table--padding-left);
|
|
349
|
+
}
|
|
350
|
+
.table__th:last-child {
|
|
351
|
+
padding-right: var(--_table--padding-right);
|
|
352
|
+
}
|
|
353
|
+
.table__tr {
|
|
354
|
+
height: var(--_table--row--height);
|
|
355
|
+
max-height: var(--_table--row--height);
|
|
356
|
+
background: var(--_table--row--color);
|
|
357
|
+
}
|
|
358
|
+
.table__tr:hover, .table__tr--highlighted {
|
|
359
|
+
background: var(--_table--row--alternative-color);
|
|
360
|
+
}
|
|
361
|
+
.table__tr:hover :global(.move-row-cell), .table__tr--highlighted :global(.move-row-cell) {
|
|
362
|
+
opacity: 1;
|
|
363
|
+
}
|
|
364
|
+
.table__tr--placeholder {
|
|
365
|
+
background: var(--_table--row--color) !important;
|
|
366
|
+
}
|
|
367
|
+
.table__td {
|
|
368
|
+
padding: 0 var(--_table--cell--horizontal-padding);
|
|
369
|
+
border-bottom: 1px solid var(--_table--border-color);
|
|
370
|
+
}
|
|
371
|
+
.table__td--centered {
|
|
372
|
+
text-align: center;
|
|
373
|
+
}
|
|
374
|
+
.table__td--clickable {
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
}
|
|
377
|
+
.table__td:first-child {
|
|
378
|
+
padding-left: var(--_table--padding-left);
|
|
379
|
+
}
|
|
380
|
+
.table__td:last-child {
|
|
381
|
+
padding-right: var(--_table--padding-right);
|
|
382
|
+
}
|
|
383
|
+
.table__save-cancel {
|
|
384
|
+
display: flex;
|
|
385
|
+
flex-direction: column;
|
|
386
|
+
gap: 0.5em;
|
|
387
|
+
--button--min-width: 4.6875em;
|
|
388
|
+
}
|
|
389
|
+
.table__placeholder {
|
|
390
|
+
display: flex;
|
|
391
|
+
align-items: center;
|
|
392
|
+
justify-content: center;
|
|
393
|
+
font-size: 80%;
|
|
394
|
+
user-select: none;
|
|
395
|
+
}
|
|
396
|
+
.table__actions {
|
|
397
|
+
display: contents;
|
|
398
|
+
--sc-kit--dropdown-item--font-size: 0.875rem;
|
|
399
|
+
--sc-kit--dropdown-item--min-width: 8.75rem;
|
|
400
|
+
--sc-kit--dropdown-item--padding: 0.75rem 1.25rem;
|
|
401
|
+
--sc-kit--icon-text--text--font-size: 0.875rem;
|
|
402
|
+
--sc-kit--icon-text--icon--font-size: 1.125rem;
|
|
403
|
+
}
|
|
404
|
+
.table__drag-handle {
|
|
405
|
+
width: 3.125em;
|
|
406
|
+
cursor: grab;
|
|
407
|
+
--sc-kit--icon--size: 1.5em;
|
|
408
|
+
--sc-kit--icon--stroke-width: 1.1;
|
|
409
|
+
}
|
|
410
|
+
.table__drag-handle--dragging {
|
|
411
|
+
cursor: grabbing;
|
|
412
|
+
}
|
|
413
|
+
.table--sticky-header thead {
|
|
414
|
+
position: sticky;
|
|
415
|
+
top: 0;
|
|
416
|
+
z-index: 1;
|
|
417
|
+
}</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { TableModel } from './table-model.svelte';
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
declare function $$render<T extends {
|
|
4
|
+
id: string;
|
|
5
|
+
}>(): {
|
|
6
|
+
props: {
|
|
7
|
+
model: TableModel<T>;
|
|
8
|
+
rowsDraggable?: boolean;
|
|
9
|
+
showPlaceholder?: boolean;
|
|
10
|
+
showAlternativeView?: boolean;
|
|
11
|
+
on?: {
|
|
12
|
+
selectionChanged?: (e: T[]) => void;
|
|
13
|
+
itemsSelected?: (e: T[]) => void;
|
|
14
|
+
itemsDeselected?: (e: T[]) => void;
|
|
15
|
+
itemsReordered?: (e: T[]) => void;
|
|
16
|
+
saveChanges?: (e: T) => void;
|
|
17
|
+
cancelChanges?: () => void;
|
|
18
|
+
};
|
|
19
|
+
alternativeView?: Snippet;
|
|
20
|
+
placeholderRow?: Snippet;
|
|
21
|
+
customNoItemsPlaceholder?: Snippet;
|
|
22
|
+
};
|
|
23
|
+
exports: {};
|
|
24
|
+
bindings: "";
|
|
25
|
+
slots: {};
|
|
26
|
+
events: {};
|
|
27
|
+
};
|
|
28
|
+
declare class __sveltets_Render<T extends {
|
|
29
|
+
id: string;
|
|
30
|
+
}> {
|
|
31
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
32
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
33
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
34
|
+
bindings(): "";
|
|
35
|
+
exports(): {};
|
|
36
|
+
}
|
|
37
|
+
interface $$IsomorphicComponent {
|
|
38
|
+
new <T extends {
|
|
39
|
+
id: string;
|
|
40
|
+
}>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
41
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
42
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
43
|
+
<T extends {
|
|
44
|
+
id: string;
|
|
45
|
+
}>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
46
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Data table component with support for sorting, selection, drag-and-drop row reordering,
|
|
50
|
+
* inline editing, column visibility management, and group actions.
|
|
51
|
+
*
|
|
52
|
+
* ### CSS Custom Properties
|
|
53
|
+
* | Property | Description | Default |
|
|
54
|
+
* |---|---|---|
|
|
55
|
+
* | `--sc-kit--table--row--height` | Row height | `3.125em` |
|
|
56
|
+
* | `--sc-kit--table--padding-left` | Left padding for first column | `2em` |
|
|
57
|
+
* | `--sc-kit--table--padding-right` | Right padding for last column | `3em` |
|
|
58
|
+
* | `--sc-kit--table--head--background-color` | Header background | `light-dark(gray-50, dark-800)` |
|
|
59
|
+
* | `--sc-kit--table--border-color` | Border color between rows | `light-dark(neutral-100, dark-800)` |
|
|
60
|
+
* | `--sc-kit--table--cell--font-size` | Cell font size | `0.875em` |
|
|
61
|
+
* | `--sc-kit--table--row--color` | Row background | `transparent` |
|
|
62
|
+
* | `--sc-kit--table--row--alternative-color` | Hover/highlighted row background | `light-dark(neutral-100, dark-800)` |
|
|
63
|
+
* | `--sc-kit--table-actions-cell--trigger--border-color` | Actions trigger border color | `light-dark(primary-50, primary-900)` |
|
|
64
|
+
* | `--sc-kit--table-actions-cell--trigger--icon-color` | Actions trigger icon color | `light-dark(primary-300, primary-400)` |
|
|
65
|
+
* | `--sc-kit--table-text-cell--clickable--color` | Clickable text cell color | `light-dark(primary-500, primary-400)` |
|
|
66
|
+
* | `--sc-kit--table-icon-cell--tooltip--color` | Icon cell tooltip text color | `white` |
|
|
67
|
+
* | `--sc-kit--table-icon-cell--tooltip--background` | Icon cell tooltip background | `black` |
|
|
68
|
+
* | `--sc-kit--table-icon-cell--tooltip--opacity` | Icon cell tooltip opacity | `70%` |
|
|
69
|
+
*/
|
|
70
|
+
declare const Cmp: $$IsomorphicComponent;
|
|
71
|
+
type Cmp<T extends {
|
|
72
|
+
id: string;
|
|
73
|
+
}> = InstanceType<typeof Cmp<T>>;
|
|
74
|
+
export default Cmp;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Table } from './cmp.table.svelte';
|
|
2
|
+
export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
|
|
3
|
+
export { default as TableGroupActions } from './table-group-actions/cmp.table-group-actions.svelte';
|
|
4
|
+
export type { TableColumnSortDirection, TableColumnType, TableImageColumnFormat, TableItemAction, TableTextColumnFormat, TableOrderByState, PageQuery, IAnyTableColumn } from './types';
|
|
5
|
+
export type { TableGroupAction } from './table-group-actions/types.svelte';
|
|
6
|
+
export { TableModel } from './table-model.svelte';
|
|
7
|
+
export { pickDirectionFromOrderByState, generatePagination } from './service';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Table } from './cmp.table.svelte';
|
|
2
|
+
export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
|
|
3
|
+
export { default as TableGroupActions } from './table-group-actions/cmp.table-group-actions.svelte';
|
|
4
|
+
export { TableModel } from './table-model.svelte';
|
|
5
|
+
export { pickDirectionFromOrderByState, generatePagination } from './service';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TableColumnSortDirection, TableOrderByState, PageQuery } from './types';
|
|
2
|
+
export declare const pickDirectionFromOrderByState: <TOrder>(orderBy: TOrder, orderByState: TableOrderByState<TOrder>) => TableColumnSortDirection;
|
|
3
|
+
export declare const generatePagination: <TOrder>(data: {
|
|
4
|
+
pageSize: number;
|
|
5
|
+
pageNumber: number;
|
|
6
|
+
orderByState: TableOrderByState<TOrder>;
|
|
7
|
+
}) => PageQuery<TOrder>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const pickDirectionFromOrderByState = (orderBy, orderByState) => {
|
|
2
|
+
if (orderByState.orderBy === orderBy) {
|
|
3
|
+
return orderByState.ascendingOrder ? 'asc' : 'desc';
|
|
4
|
+
}
|
|
5
|
+
return 'none';
|
|
6
|
+
};
|
|
7
|
+
export const generatePagination = (data) => {
|
|
8
|
+
const { pageSize, pageNumber, orderByState } = data;
|
|
9
|
+
const query = {
|
|
10
|
+
perPage: pageSize,
|
|
11
|
+
page: pageNumber,
|
|
12
|
+
fetchTotal: pageNumber === 1,
|
|
13
|
+
orderBy: orderByState.orderBy,
|
|
14
|
+
ascendingOrder: orderByState.ascendingOrder
|
|
15
|
+
};
|
|
16
|
+
return query;
|
|
17
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
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';
|
|
13
|
+
export { default as TableHideableCell } from './table-hideable-cell.svelte';
|
|
@@ -0,0 +1,13 @@
|
|
|
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';
|
|
13
|
+
export { default as TableHideableCell } from './table-hideable-cell.svelte';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">import { Dropdown } from '../../dropdown';
|
|
2
|
+
import { Icon } from '../../icon';
|
|
3
|
+
import IconMoreHorizontal from '@fluentui/svg-icons/icons/more_horizontal_20_regular.svg?raw';
|
|
4
|
+
let { dropdownPosition = 'bottom-end', children } = $props();
|
|
5
|
+
let toggleOpen = $state(null);
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<button type="button" class="table-actions-cell__dropdown-wrapper" onclick={toggleOpen}>
|
|
9
|
+
<span>
|
|
10
|
+
<Dropdown position={dropdownPosition} on={{ mounted: (e) => (toggleOpen = e.toggleOpen) }}>
|
|
11
|
+
{#snippet trigger()}
|
|
12
|
+
<button type="button" class="table-actions-cell__trigger">
|
|
13
|
+
<Icon src={IconMoreHorizontal} />
|
|
14
|
+
</button>
|
|
15
|
+
{/snippet}
|
|
16
|
+
{@render children()}
|
|
17
|
+
</Dropdown>
|
|
18
|
+
</span>
|
|
19
|
+
</button>
|
|
20
|
+
|
|
21
|
+
<!--
|
|
22
|
+
@component
|
|
23
|
+
Actions cell for table rows. Shows a dropdown trigger with a "more" icon.
|
|
24
|
+
|
|
25
|
+
### CSS Custom Properties
|
|
26
|
+
| Property | Description | Default |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `--sc-kit--table-actions-cell--trigger--border-color` | Trigger button border color | `light-dark(primary-50, primary-900)` |
|
|
29
|
+
| `--sc-kit--table-actions-cell--trigger--icon-color` | Trigger icon color | `light-dark(primary-300, primary-400)` |
|
|
30
|
+
-->
|
|
31
|
+
|
|
32
|
+
<style>.table-actions-cell__trigger {
|
|
33
|
+
--_table-actions-cell--trigger--border-color: var(
|
|
34
|
+
--sc-kit--table-actions-cell--trigger--border-color,
|
|
35
|
+
light-dark(#f1f6fd, #0a2557)
|
|
36
|
+
);
|
|
37
|
+
--_table-actions-cell--trigger--icon-color: var(
|
|
38
|
+
--sc-kit--table-actions-cell--trigger--icon-color,
|
|
39
|
+
light-dark(#91b3f3, #5a8dec)
|
|
40
|
+
);
|
|
41
|
+
border: 1px solid var(--_table-actions-cell--trigger--border-color);
|
|
42
|
+
padding: 0.125em 0.25em;
|
|
43
|
+
border-radius: 0.375em;
|
|
44
|
+
--sc-kit--icon--stroke-width: 0.6;
|
|
45
|
+
--sc-kit--icon--color: var(--_table-actions-cell--trigger--icon-color);
|
|
46
|
+
}
|
|
47
|
+
.table-actions-cell__dropdown-wrapper {
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
display: flex;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
align-items: center;
|
|
53
|
+
}</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type DropdownPosition } from '../../dropdown';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
type Props = {
|
|
4
|
+
dropdownPosition?: DropdownPosition;
|
|
5
|
+
children: Snippet;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Actions cell for table rows. Shows a dropdown trigger with a "more" icon.
|
|
9
|
+
*
|
|
10
|
+
* ### CSS Custom Properties
|
|
11
|
+
* | Property | Description | Default |
|
|
12
|
+
* |---|---|---|
|
|
13
|
+
* | `--sc-kit--table-actions-cell--trigger--border-color` | Trigger button border color | `light-dark(primary-50, primary-900)` |
|
|
14
|
+
* | `--sc-kit--table-actions-cell--trigger--icon-color` | Trigger icon color | `light-dark(primary-300, primary-400)` |
|
|
15
|
+
*/
|
|
16
|
+
declare const TableActionsCell: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type TableActionsCell = ReturnType<typeof TableActionsCell>;
|
|
18
|
+
export default TableActionsCell;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends {id: string}">import { Badge } from '../../badge';
|
|
2
|
+
let { item, column } = $props();
|
|
3
|
+
const getValueForColumn = (column, item) => (column.valueFactory ? column.valueFactory(item) : String(item[column.id]));
|
|
4
|
+
const color = $derived(column.colorFactory ? column.colorFactory(item) : 'default');
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
{#if getValueForColumn(column, item) !== null}
|
|
8
|
+
<div class="table-badge-cell">
|
|
9
|
+
<Badge color={color} rounded={column.roundedBadge ?? false}>{getValueForColumn(column, item)}</Badge>
|
|
10
|
+
</div>
|
|
11
|
+
{/if}
|
|
12
|
+
|
|
13
|
+
<style>.table-badge-cell {
|
|
14
|
+
width: 100%;
|
|
15
|
+
}</style>
|