@streamscloud/kit 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/core/local-storage/index.d.ts +1 -0
  2. package/dist/core/local-storage/index.js +1 -0
  3. package/dist/core/local-storage/local-storage-item.d.ts +10 -0
  4. package/dist/core/local-storage/local-storage-item.js +27 -0
  5. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte +160 -0
  6. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte.d.ts +20 -0
  7. package/dist/ui/page-toolbar/cmp.toolbar-button-item.svelte +34 -0
  8. package/dist/ui/page-toolbar/cmp.toolbar-button-item.svelte.d.ts +18 -0
  9. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte +21 -0
  10. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte.d.ts +12 -0
  11. package/dist/ui/page-toolbar/cmp.toolbar-dropdown.svelte +29 -0
  12. package/dist/ui/page-toolbar/cmp.toolbar-dropdown.svelte.d.ts +17 -0
  13. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte +58 -0
  14. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte.d.ts +19 -0
  15. package/dist/ui/page-toolbar/cmp.toolbar-search-input.svelte +49 -0
  16. package/dist/ui/page-toolbar/cmp.toolbar-search-input.svelte.d.ts +20 -0
  17. package/dist/ui/page-toolbar/cmp.toolbar-segmented-control.svelte +40 -0
  18. package/dist/ui/page-toolbar/cmp.toolbar-segmented-control.svelte.d.ts +39 -0
  19. package/dist/ui/page-toolbar/cmp.toolbar-switch-item.svelte +51 -0
  20. package/dist/ui/page-toolbar/cmp.toolbar-switch-item.svelte.d.ts +43 -0
  21. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte +45 -0
  22. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte.d.ts +19 -0
  23. package/dist/ui/page-toolbar/index.d.ts +10 -0
  24. package/dist/ui/page-toolbar/index.js +9 -0
  25. package/dist/ui/page-toolbar/types.d.ts +6 -0
  26. package/dist/ui/page-toolbar/types.js +1 -0
  27. package/dist/ui/segmented-control/cmp.segmented-control.svelte +97 -0
  28. package/dist/ui/segmented-control/cmp.segmented-control.svelte.d.ts +52 -0
  29. package/dist/ui/segmented-control/index.d.ts +1 -0
  30. package/dist/ui/segmented-control/index.js +1 -0
  31. package/dist/ui/table/index.d.ts +1 -1
  32. package/dist/ui/table/table-cells/table-text-cell.svelte +2 -2
  33. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte +73 -36
  34. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte.d.ts +16 -6
  35. package/dist/ui/table/table-model.svelte.d.ts +1 -0
  36. package/dist/ui/table/table-model.svelte.js +3 -0
  37. package/dist/ui/table/types.d.ts +6 -1
  38. package/package.json +13 -1
@@ -0,0 +1 @@
1
+ export { LocalStorageItem } from './local-storage-item';
@@ -0,0 +1 @@
1
+ export { LocalStorageItem } from './local-storage-item';
@@ -0,0 +1,10 @@
1
+ export declare class LocalStorageItem<T, TFallback = null> {
2
+ readonly key: string;
3
+ private readonly _fallback;
4
+ private constructor();
5
+ static of: <T_1>(key: string) => LocalStorageItem<T_1>;
6
+ static withDefault: <T_1>(key: string, fallback: T_1) => LocalStorageItem<T_1, T_1>;
7
+ get(): T | TFallback;
8
+ remove(): void;
9
+ set(value: T): void;
10
+ }
@@ -0,0 +1,27 @@
1
+ export class LocalStorageItem {
2
+ key;
3
+ _fallback;
4
+ constructor(key, fallback) {
5
+ this.key = key;
6
+ this._fallback = fallback;
7
+ }
8
+ static of = (key) => {
9
+ return new LocalStorageItem(key, null);
10
+ };
11
+ static withDefault = (key, fallback) => {
12
+ return new LocalStorageItem(key, fallback);
13
+ };
14
+ get() {
15
+ const stringValue = localStorage.getItem(this.key);
16
+ if (!stringValue) {
17
+ return this._fallback;
18
+ }
19
+ return JSON.parse(stringValue);
20
+ }
21
+ remove() {
22
+ localStorage.removeItem(this.key);
23
+ }
24
+ set(value) {
25
+ localStorage.setItem(this.key, JSON.stringify(value));
26
+ }
27
+ }
@@ -0,0 +1,160 @@
1
+ <script lang="ts">import { Icon } from '../icon';
2
+ import { Toggle } from '../toggle';
3
+ import IconReorderDotsVertical from '@fluentui/svg-icons/icons/re_order_dots_vertical_20_regular.svg?raw';
4
+ import { flip } from 'svelte/animate';
5
+ import { dndzone } from 'svelte-dnd-action';
6
+ let { items, on } = $props();
7
+ const reorderableItems = $derived(items.filter((i) => !i.fixed));
8
+ const fixedItems = $derived(items.filter((i) => i.fixed));
9
+ let dndItems = $state.raw([]);
10
+ $effect(() => {
11
+ dndItems = reorderableItems.map(({ id, label, enabled }) => ({ id, label, enabled }));
12
+ });
13
+ const flipDurationMs = 200;
14
+ const emitChange = (reordered) => {
15
+ const merged = [
16
+ ...fixedItems.map(({ id, label, enabled, fixed }) => ({ id, label, enabled, fixed })),
17
+ ...reordered.map(({ id, label, enabled }) => ({ id, label, enabled }))
18
+ ];
19
+ on.change(merged);
20
+ };
21
+ const handleConsider = (e) => {
22
+ dndItems = e.detail.items;
23
+ };
24
+ const handleFinalize = (e) => {
25
+ emitChange(e.detail.items);
26
+ };
27
+ const handleToggle = (id, enabled) => {
28
+ emitChange(dndItems.map((i) => (i.id === id ? { ...i, enabled } : i)));
29
+ };
30
+ const handleFixedToggle = (id, enabled) => {
31
+ const updatedFixed = fixedItems.map(({ id: fId, label, enabled: fEnabled, fixed }) => ({
32
+ id: fId,
33
+ label,
34
+ enabled: fId === id ? enabled : fEnabled,
35
+ fixed
36
+ }));
37
+ on.change([...updatedFixed, ...dndItems.map(({ id, label, enabled }) => ({ id, label, enabled }))]);
38
+ };
39
+ </script>
40
+
41
+ <div class="reorderable-toggle-list">
42
+ {#each fixedItems as item (item.id)}
43
+ <div class="reorderable-toggle-list__item">
44
+ <div class="reorderable-toggle-list__drag-handle reorderable-toggle-list__drag-handle--hidden">
45
+ <Icon src={IconReorderDotsVertical} />
46
+ </div>
47
+ <div class="reorderable-toggle-list__label">
48
+ {item.label}
49
+ </div>
50
+ <div class="reorderable-toggle-list__toggle">
51
+ <Toggle
52
+ isOn={item.enabled}
53
+ on={{
54
+ change: (value) => handleFixedToggle(item.id, value)
55
+ }} />
56
+ </div>
57
+ </div>
58
+ {/each}
59
+ <div
60
+ class="reorderable-toggle-list__dnd"
61
+ use:dndzone={{
62
+ items: dndItems,
63
+ dropTargetStyle: {},
64
+ flipDurationMs,
65
+ morphDisabled: true
66
+ }}
67
+ onconsider={handleConsider}
68
+ onfinalize={handleFinalize}>
69
+ {#each dndItems as item (item.id)}
70
+ <div class="reorderable-toggle-list__item" animate:flip={{ duration: flipDurationMs }}>
71
+ <div class="reorderable-toggle-list__drag-handle">
72
+ <Icon src={IconReorderDotsVertical} />
73
+ </div>
74
+ <div class="reorderable-toggle-list__label">
75
+ {item.label}
76
+ </div>
77
+ <div class="reorderable-toggle-list__toggle">
78
+ <Toggle
79
+ isOn={item.enabled}
80
+ on={{
81
+ change: (value) => handleToggle(item.id, value)
82
+ }} />
83
+ </div>
84
+ </div>
85
+ {/each}
86
+ </div>
87
+ </div>
88
+
89
+ <!--
90
+ @component
91
+ A reorderable list of toggle items with drag-and-drop support. Fixed items appear above the reorderable zone.
92
+
93
+ ### CSS Custom Properties
94
+ | Property | Description | Default |
95
+ |---|---|---|
96
+ | `--sc-kit--reorderable-toggle-list--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
97
+ | `--sc-kit--reorderable-toggle-list--handle--color` | Drag handle icon color | `var(--sc-color--text-secondary, light-dark(neutral-500, neutral-300))` |
98
+ | `--sc-kit--reorderable-toggle-list--handle--background` | Drag handle background | `var(--sc-color--bg-element, light-dark(neutral-50, dark-800))` |
99
+ -->
100
+
101
+ <style>.reorderable-toggle-list {
102
+ --_reorderable-toggle-list--label--color: var(
103
+ --sc-kit--reorderable-toggle-list--label--color,
104
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
105
+ );
106
+ --_reorderable-toggle-list--handle--color: var(
107
+ --sc-kit--reorderable-toggle-list--handle--color,
108
+ var(--sc-color--text-secondary, light-dark(#6b7280, #d1d5db))
109
+ );
110
+ --_reorderable-toggle-list--handle--background: var(
111
+ --sc-kit--reorderable-toggle-list--handle--background,
112
+ var(--sc-color--bg-element, light-dark(#f9fafb, #1e1e1e))
113
+ );
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: 0.75rem;
117
+ }
118
+ .reorderable-toggle-list__dnd {
119
+ display: flex;
120
+ flex-direction: column;
121
+ gap: 0.75rem;
122
+ }
123
+ .reorderable-toggle-list__item {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 0.75rem;
127
+ padding: 0.25rem 0.5rem;
128
+ }
129
+ .reorderable-toggle-list__drag-handle {
130
+ --sc-kit--icon--size: 1rem;
131
+ --sc-kit--icon--color: var(--_reorderable-toggle-list--handle--color);
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ height: 1.375rem;
136
+ padding-inline: 0.1875rem;
137
+ border-radius: 0.3125rem 0 0 0.3125rem;
138
+ cursor: grab;
139
+ background: var(--_reorderable-toggle-list--handle--background);
140
+ }
141
+ .reorderable-toggle-list__drag-handle:active {
142
+ cursor: grabbing;
143
+ }
144
+ .reorderable-toggle-list__drag-handle--hidden {
145
+ visibility: hidden;
146
+ }
147
+ .reorderable-toggle-list__label {
148
+ flex: 1;
149
+ min-width: 0;
150
+ font-size: 0.875rem;
151
+ font-weight: 400;
152
+ line-height: 1.25rem;
153
+ color: var(--_reorderable-toggle-list--label--color);
154
+ }
155
+ .reorderable-toggle-list__toggle {
156
+ flex-shrink: 0;
157
+ margin-left: auto;
158
+ --sc-kit--toggle--switch--height: 1.125rem;
159
+ --sc-kit--toggle--switch--width: 2.3125rem;
160
+ }</style>
@@ -0,0 +1,20 @@
1
+ import type { ReorderableToggleItem } from './types';
2
+ type Props = {
3
+ items: ReorderableToggleItem[];
4
+ on: {
5
+ change: (items: ReorderableToggleItem[]) => void;
6
+ };
7
+ };
8
+ /**
9
+ * A reorderable list of toggle items with drag-and-drop support. Fixed items appear above the reorderable zone.
10
+ *
11
+ * ### CSS Custom Properties
12
+ * | Property | Description | Default |
13
+ * |---|---|---|
14
+ * | `--sc-kit--reorderable-toggle-list--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
15
+ * | `--sc-kit--reorderable-toggle-list--handle--color` | Drag handle icon color | `var(--sc-color--text-secondary, light-dark(neutral-500, neutral-300))` |
16
+ * | `--sc-kit--reorderable-toggle-list--handle--background` | Drag handle background | `var(--sc-color--bg-element, light-dark(neutral-50, dark-800))` |
17
+ */
18
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
19
+ type Cmp = ReturnType<typeof Cmp>;
20
+ export default Cmp;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">const { children, on } = $props();
2
+ export {};
3
+ </script>
4
+
5
+ <button type="button" class="toolbar-button-item" onclick={() => on?.click?.()}>
6
+ {@render children()}
7
+ </button>
8
+
9
+ <!--
10
+ @component
11
+ A simple button item for toolbar panels. Renders children as clickable text.
12
+
13
+ ### CSS Custom Properties
14
+ | Property | Description | Default |
15
+ |---|---|---|
16
+ | `--sc-kit--toolbar-button-item--color` | Text color | `var(--sc-color--text-primary, light-dark(black, white))` |
17
+ -->
18
+
19
+ <style>.toolbar-button-item {
20
+ --_toolbar-button-item--color: var(
21
+ --sc-kit--toolbar-button-item--color,
22
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
23
+ );
24
+ font-size: 0.875rem;
25
+ font-weight: 400;
26
+ line-height: 1.25rem;
27
+ color: var(--_toolbar-button-item--color);
28
+ padding: 0.25rem 0.5rem;
29
+ max-width: 100%;
30
+ text-overflow: ellipsis;
31
+ max-width: 100%;
32
+ white-space: nowrap;
33
+ overflow: hidden;
34
+ }</style>
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ children: Snippet;
4
+ on?: {
5
+ click?: () => void;
6
+ };
7
+ };
8
+ /**
9
+ * A simple button item for toolbar panels. Renders children as clickable text.
10
+ *
11
+ * ### CSS Custom Properties
12
+ * | Property | Description | Default |
13
+ * |---|---|---|
14
+ * | `--sc-kit--toolbar-button-item--color` | Text color | `var(--sc-color--text-primary, light-dark(black, white))` |
15
+ */
16
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
17
+ type Cmp = ReturnType<typeof Cmp>;
18
+ export default Cmp;
@@ -0,0 +1,21 @@
1
+ <script lang="ts">import { Checkbox } from '../checkbox';
2
+ const { checked, children, on } = $props();
3
+ </script>
4
+
5
+ <div class="toolbar-checkbox-item">
6
+ <Checkbox checked={checked} on={{ change: (value) => on?.change?.(value) }}>
7
+ {@render children()}
8
+ </Checkbox>
9
+ </div>
10
+
11
+ <!--
12
+ @component
13
+ A checkbox item for toolbar panels. Wraps the kit Checkbox with toolbar-appropriate sizing.
14
+ -->
15
+
16
+ <style>.toolbar-checkbox-item {
17
+ padding: 0.25rem 0.5rem;
18
+ overflow: hidden;
19
+ --sc-kit--checkbox--gap: 1.25rem;
20
+ --sc-kit--checkbox--icon--size: 1.125rem;
21
+ }</style>
@@ -0,0 +1,12 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ checked: boolean;
4
+ children: Snippet;
5
+ on?: {
6
+ change?: (value: boolean) => void;
7
+ };
8
+ };
9
+ /** A checkbox item for toolbar panels. Wraps the kit Checkbox with toolbar-appropriate sizing. */
10
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
11
+ type Cmp = ReturnType<typeof Cmp>;
12
+ export default Cmp;
@@ -0,0 +1,29 @@
1
+ <script lang="ts">import { Button } from '../button';
2
+ import { Dropdown } from '../dropdown';
3
+ import { IconText } from '../icon-text';
4
+ import ToolbarPanel from './cmp.toolbar-panel.svelte';
5
+ import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
6
+ const { title, triggerLabel, icon, iconColor, position = 'bottom-end', children, footer } = $props();
7
+ </script>
8
+
9
+ <div class="toolbar-dropdown">
10
+ <Dropdown position={position} keepDropdownOpen>
11
+ {#snippet trigger()}
12
+ <Button variant="standard" size="small">
13
+ <IconText icon={icon} iconColor={iconColor} secondaryIcon={IconChevronDown}>{triggerLabel}</IconText>
14
+ </Button>
15
+ {/snippet}
16
+ <ToolbarPanel title={title} footer={footer}>
17
+ {@render children()}
18
+ </ToolbarPanel>
19
+ </Dropdown>
20
+ </div>
21
+
22
+ <!--
23
+ @component
24
+ A toolbar dropdown button. Opens a panel with a title, body content, and optional footer.
25
+ -->
26
+
27
+ <style>.toolbar-dropdown {
28
+ display: contents;
29
+ }</style>
@@ -0,0 +1,17 @@
1
+ import type { DropdownPosition } from '../dropdown';
2
+ import type { IconColor } from '../icon';
3
+ import type { Snippet } from 'svelte';
4
+ type Props = {
5
+ title: string;
6
+ triggerLabel: string;
7
+ icon?: string;
8
+ iconColor?: IconColor;
9
+ /** @default 'bottom-end' */
10
+ position?: DropdownPosition;
11
+ children: Snippet;
12
+ footer?: Snippet;
13
+ };
14
+ /** A toolbar dropdown button. Opens a panel with a title, body content, and optional footer. */
15
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
16
+ type Cmp = ReturnType<typeof Cmp>;
17
+ export default Cmp;
@@ -0,0 +1,58 @@
1
+ <script lang="ts">const { title, children, footer } = $props();
2
+ export {};
3
+ </script>
4
+
5
+ <div class="toolbar-panel">
6
+ <div class="toolbar-panel__title">{title}</div>
7
+ <div class="toolbar-panel__body">
8
+ {@render children()}
9
+ {#if footer}
10
+ <div class="toolbar-panel__divider"></div>
11
+ {@render footer()}
12
+ {/if}
13
+ </div>
14
+ </div>
15
+
16
+ <!--
17
+ @component
18
+ A panel container used inside toolbar dropdowns. Provides a title, body area, and optional footer.
19
+
20
+ ### CSS Custom Properties
21
+ | Property | Description | Default |
22
+ |---|---|---|
23
+ | `--sc-kit--toolbar-panel--width` | Panel width | `21.875rem` |
24
+ | `--sc-kit--toolbar-panel--title--color` | Title text color | `var(--sc-color--text-primary, light-dark(black, white))` |
25
+ | `--sc-kit--toolbar-panel--divider--color` | Divider line color | `var(--sc-color--border-primary, light-dark(neutral-100, dark-800))` |
26
+ -->
27
+
28
+ <style>.toolbar-panel {
29
+ --_toolbar-panel--width: var(--sc-kit--toolbar-panel--width, 21.875rem);
30
+ --_toolbar-panel--title--color: var(
31
+ --sc-kit--toolbar-panel--title--color,
32
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
33
+ );
34
+ --_toolbar-panel--divider--color: var(
35
+ --sc-kit--toolbar-panel--divider--color,
36
+ var(--sc-color--border-primary, light-dark(#f2f2f3, #1e1e1e))
37
+ );
38
+ width: var(--_toolbar-panel--width);
39
+ padding: 1.5rem;
40
+ }
41
+ .toolbar-panel__title {
42
+ font-size: 0.875rem;
43
+ font-weight: 600;
44
+ line-height: 1.25rem;
45
+ color: var(--_toolbar-panel--title--color);
46
+ margin-bottom: 0.5rem;
47
+ }
48
+ .toolbar-panel__body {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 1rem;
52
+ padding-block: 0.5rem;
53
+ }
54
+ .toolbar-panel__divider {
55
+ height: 1px;
56
+ background: var(--_toolbar-panel--divider--color);
57
+ margin: 0.25rem 0.5rem;
58
+ }</style>
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ title: string;
4
+ children: Snippet;
5
+ footer?: Snippet;
6
+ };
7
+ /**
8
+ * A panel container used inside toolbar dropdowns. Provides a title, body area, and optional footer.
9
+ *
10
+ * ### CSS Custom Properties
11
+ * | Property | Description | Default |
12
+ * |---|---|---|
13
+ * | `--sc-kit--toolbar-panel--width` | Panel width | `21.875rem` |
14
+ * | `--sc-kit--toolbar-panel--title--color` | Title text color | `var(--sc-color--text-primary, light-dark(black, white))` |
15
+ * | `--sc-kit--toolbar-panel--divider--color` | Divider line color | `var(--sc-color--border-primary, light-dark(neutral-100, dark-800))` |
16
+ */
17
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
18
+ type Cmp = ReturnType<typeof Cmp>;
19
+ export default Cmp;
@@ -0,0 +1,49 @@
1
+ <script lang="ts">import { Utils } from '../../core/utils';
2
+ import { Icon } from '../icon';
3
+ import { Input } from '../inputs';
4
+ import IconSearch from '@fluentui/svg-icons/icons/search_20_regular.svg?raw';
5
+ const { value, placeholder = 'Search...', debounce = 0, on } = $props();
6
+ let focused = $state(false);
7
+ const expanded = $derived(focused || !!value);
8
+ const onInput = (v) => {
9
+ on?.input?.(v);
10
+ };
11
+ const onInputDebounced = $derived(debounce > 0 ? Utils.debounce(onInput, debounce) : onInput);
12
+ </script>
13
+
14
+ {#snippet searchIcon()}
15
+ <Icon src={IconSearch} />
16
+ {/snippet}
17
+
18
+ <div class="toolbar-search-input" class:toolbar-search-input--expanded={expanded}>
19
+ <Input
20
+ value={value}
21
+ placeholder={placeholder}
22
+ icon={searchIcon}
23
+ clearable
24
+ borderless={!expanded}
25
+ on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false) }} />
26
+ </div>
27
+
28
+ <!--
29
+ @component
30
+ A collapsible search input for toolbars. Expands when focused or when value is present.
31
+
32
+ ### CSS Custom Properties
33
+ | Property | Description | Default |
34
+ |---|---|---|
35
+ | `--sc-kit--toolbar-search-input--width` | Expanded width | `12.5rem` |
36
+ -->
37
+
38
+ <style>.toolbar-search-input {
39
+ --_toolbar-search-input--width: var(--sc-kit--toolbar-search-input--width, 12.5rem);
40
+ --sc-kit--input--root--font-size: 0.875rem;
41
+ --sc-kit--input--width: 1.75rem;
42
+ --sc-kit--input--height: 1.75rem;
43
+ --sc-kit--input--icon--color: var(--sc-color--text-brand, #5a8dec);
44
+ --sc-kit--input--accent-color: transparent;
45
+ }
46
+ .toolbar-search-input--expanded {
47
+ --sc-kit--input--width: var(--_toolbar-search-input--width);
48
+ --sc-kit--input--icon--color: initial;
49
+ }</style>
@@ -0,0 +1,20 @@
1
+ type Props = {
2
+ value: string;
3
+ placeholder?: string;
4
+ /** Debounce delay in ms @default 0 */
5
+ debounce?: number;
6
+ on?: {
7
+ input?: (value: string) => void;
8
+ };
9
+ };
10
+ /**
11
+ * A collapsible search input for toolbars. Expands when focused or when value is present.
12
+ *
13
+ * ### CSS Custom Properties
14
+ * | Property | Description | Default |
15
+ * |---|---|---|
16
+ * | `--sc-kit--toolbar-search-input--width` | Expanded width | `12.5rem` |
17
+ */
18
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
19
+ type Cmp = ReturnType<typeof Cmp>;
20
+ export default Cmp;
@@ -0,0 +1,40 @@
1
+ <script lang="ts" generics="T extends string | number">import { LocalStorageItem } from '../../core/local-storage';
2
+ import { SegmentedControl } from '../segmented-control';
3
+ import { untrack } from 'svelte';
4
+ const { segments, selected, localStorageKey, on } = $props();
5
+ let storage = null;
6
+ // One-time init: load from localStorage
7
+ $effect(() => untrack(() => {
8
+ if (!localStorageKey) {
9
+ return;
10
+ }
11
+ storage = LocalStorageItem.of(localStorageKey);
12
+ const saved = storage.get();
13
+ if (saved !== null && segments.some((s) => s.id === saved)) {
14
+ on?.change?.(saved);
15
+ }
16
+ }));
17
+ const handleChange = (id) => {
18
+ storage?.set(id);
19
+ on?.change?.(id);
20
+ };
21
+ </script>
22
+
23
+ <div class="toolbar-segmented-control">
24
+ <SegmentedControl segments={segments} selected={selected} on={{ change: handleChange }} />
25
+ </div>
26
+
27
+ <!--
28
+ @component
29
+ A segmented control styled for toolbar use with optional localStorage persistence.
30
+ Wraps SegmentedControl with toolbar-specific sizing (28px height, 10px font, 4px radius).
31
+ -->
32
+
33
+ <style>.toolbar-segmented-control {
34
+ --sc-kit--segmented-control--height: 1.75rem;
35
+ --sc-kit--segmented-control--label--font-size: 0.625rem;
36
+ --sc-kit--segmented-control--border-radius: 0.25rem;
37
+ --sc-kit--segmented-control--selected--background: var(--sc-color--bg-menu-active, light-dark(#f1f6fd, #2c2c2c));
38
+ --sc-kit--segmented-control--selected--box-shadow: inset 0px 1.5px 0px 0px rgba(255, 255, 255, 0.3);
39
+ --sc-kit--segmented-control--border-color: var(--sc-color--border-primary, light-dark(#f2f2f3, #1e1e1e));
40
+ }</style>
@@ -0,0 +1,39 @@
1
+ declare function $$render<T extends string | number>(): {
2
+ props: {
3
+ segments: {
4
+ id: T;
5
+ label: string;
6
+ }[];
7
+ selected: T;
8
+ /** localStorage key for persisting selection */
9
+ localStorageKey?: string;
10
+ on?: {
11
+ change?: (id: T) => void;
12
+ };
13
+ };
14
+ exports: {};
15
+ bindings: "";
16
+ slots: {};
17
+ events: {};
18
+ };
19
+ declare class __sveltets_Render<T extends string | number> {
20
+ props(): ReturnType<typeof $$render<T>>['props'];
21
+ events(): ReturnType<typeof $$render<T>>['events'];
22
+ slots(): ReturnType<typeof $$render<T>>['slots'];
23
+ bindings(): "";
24
+ exports(): {};
25
+ }
26
+ interface $$IsomorphicComponent {
27
+ new <T extends string | number>(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']>> & {
28
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
29
+ } & ReturnType<__sveltets_Render<T>['exports']>;
30
+ <T extends string | number>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
31
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
32
+ }
33
+ /**
34
+ * A segmented control styled for toolbar use with optional localStorage persistence.
35
+ * Wraps SegmentedControl with toolbar-specific sizing (28px height, 10px font, 4px radius).
36
+ */
37
+ declare const Cmp: $$IsomorphicComponent;
38
+ type Cmp<T extends string | number> = InstanceType<typeof Cmp<T>>;
39
+ export default Cmp;
@@ -0,0 +1,51 @@
1
+ <script lang="ts" generics="T extends string | number">import { SegmentedControl } from '../segmented-control';
2
+ const { segments, selected, children, on } = $props();
3
+ </script>
4
+
5
+ <div class="toolbar-switch-item">
6
+ <div class="toolbar-switch-item__label">
7
+ {@render children()}
8
+ </div>
9
+ <div class="toolbar-switch-item__switch">
10
+ <SegmentedControl segments={segments} selected={selected} on={{ change: (id) => on?.change?.(id) }} />
11
+ </div>
12
+ </div>
13
+
14
+ <!--
15
+ @component
16
+ A switch item for toolbar panels. Shows a label on the left and a segmented control on the right.
17
+
18
+ ### CSS Custom Properties
19
+ | Property | Description | Default |
20
+ |---|---|---|
21
+ | `--sc-kit--toolbar-switch-item--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
22
+ -->
23
+
24
+ <style>.toolbar-switch-item {
25
+ --_toolbar-switch-item--label--color: var(
26
+ --sc-kit--toolbar-switch-item--label--color,
27
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
28
+ );
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ gap: 0.5rem;
33
+ padding: 0.25rem 0.5rem;
34
+ }
35
+ .toolbar-switch-item__label {
36
+ font-size: 0.875rem;
37
+ font-weight: 400;
38
+ line-height: 1.25rem;
39
+ color: var(--_toolbar-switch-item--label--color);
40
+ min-width: 0;
41
+ text-overflow: ellipsis;
42
+ max-width: 100%;
43
+ white-space: nowrap;
44
+ overflow: hidden;
45
+ }
46
+ .toolbar-switch-item__switch {
47
+ flex-shrink: 0;
48
+ --sc-kit--segmented-control--border-radius: 0.375rem;
49
+ --sc-kit--segmented-control--selected--background: var(--sc-color--bg-brand, #144ab0);
50
+ --sc-kit--segmented-control--selected--color: #ffffff;
51
+ }</style>
@@ -0,0 +1,43 @@
1
+ import type { Snippet } from 'svelte';
2
+ declare function $$render<T extends string | number>(): {
3
+ props: {
4
+ segments: {
5
+ id: T;
6
+ label: string;
7
+ }[];
8
+ selected: T;
9
+ children: Snippet;
10
+ on?: {
11
+ change?: (id: T) => void;
12
+ };
13
+ };
14
+ exports: {};
15
+ bindings: "";
16
+ slots: {};
17
+ events: {};
18
+ };
19
+ declare class __sveltets_Render<T extends string | number> {
20
+ props(): ReturnType<typeof $$render<T>>['props'];
21
+ events(): ReturnType<typeof $$render<T>>['events'];
22
+ slots(): ReturnType<typeof $$render<T>>['slots'];
23
+ bindings(): "";
24
+ exports(): {};
25
+ }
26
+ interface $$IsomorphicComponent {
27
+ new <T extends string | number>(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']>> & {
28
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
29
+ } & ReturnType<__sveltets_Render<T>['exports']>;
30
+ <T extends string | number>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
31
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
32
+ }
33
+ /**
34
+ * A switch item for toolbar panels. Shows a label on the left and a segmented control on the right.
35
+ *
36
+ * ### CSS Custom Properties
37
+ * | Property | Description | Default |
38
+ * |---|---|---|
39
+ * | `--sc-kit--toolbar-switch-item--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
40
+ */
41
+ declare const Cmp: $$IsomorphicComponent;
42
+ type Cmp<T extends string | number> = InstanceType<typeof Cmp<T>>;
43
+ export default Cmp;
@@ -0,0 +1,45 @@
1
+ <script lang="ts">import { Toggle } from '../toggle';
2
+ const { isOn, children, on } = $props();
3
+ </script>
4
+
5
+ <div class="toolbar-toggle-item">
6
+ <div class="toolbar-toggle-item__label">
7
+ {@render children()}
8
+ </div>
9
+ <Toggle isOn={isOn} on={{ change: (value) => on?.change?.(value) }} />
10
+ </div>
11
+
12
+ <!--
13
+ @component
14
+ A toggle item for toolbar panels. Shows a label on the left and a toggle switch on the right.
15
+
16
+ ### CSS Custom Properties
17
+ | Property | Description | Default |
18
+ |---|---|---|
19
+ | `--sc-kit--toolbar-toggle-item--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
20
+ -->
21
+
22
+ <style>.toolbar-toggle-item {
23
+ --_toolbar-toggle-item--label--color: var(
24
+ --sc-kit--toolbar-toggle-item--label--color,
25
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
26
+ );
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: space-between;
30
+ gap: 0.5rem;
31
+ padding: 0.25rem 0.5rem;
32
+ --sc-kit--toggle--switch--height: 1.125rem;
33
+ --sc-kit--toggle--switch--width: 2.3125rem;
34
+ }
35
+ .toolbar-toggle-item__label {
36
+ font-size: 0.875rem;
37
+ font-weight: 400;
38
+ line-height: 1.25rem;
39
+ color: var(--_toolbar-toggle-item--label--color);
40
+ min-width: 0;
41
+ text-overflow: ellipsis;
42
+ max-width: 100%;
43
+ white-space: nowrap;
44
+ overflow: hidden;
45
+ }</style>
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ isOn: boolean;
4
+ children: Snippet;
5
+ on?: {
6
+ change?: (value: boolean) => void;
7
+ };
8
+ };
9
+ /**
10
+ * A toggle item for toolbar panels. Shows a label on the left and a toggle switch on the right.
11
+ *
12
+ * ### CSS Custom Properties
13
+ * | Property | Description | Default |
14
+ * |---|---|---|
15
+ * | `--sc-kit--toolbar-toggle-item--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
16
+ */
17
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
18
+ type Cmp = ReturnType<typeof Cmp>;
19
+ export default Cmp;
@@ -0,0 +1,10 @@
1
+ export { default as ReorderableToggleList } from './cmp.reorderable-toggle-list.svelte';
2
+ export { default as ToolbarButtonItem } from './cmp.toolbar-button-item.svelte';
3
+ export { default as ToolbarCheckboxItem } from './cmp.toolbar-checkbox-item.svelte';
4
+ export { default as ToolbarDropdown } from './cmp.toolbar-dropdown.svelte';
5
+ export { default as ToolbarPanel } from './cmp.toolbar-panel.svelte';
6
+ export { default as ToolbarSearchInput } from './cmp.toolbar-search-input.svelte';
7
+ export { default as ToolbarSegmentedControl } from './cmp.toolbar-segmented-control.svelte';
8
+ export { default as ToolbarSwitchItem } from './cmp.toolbar-switch-item.svelte';
9
+ export { default as ToolbarToggleItem } from './cmp.toolbar-toggle-item.svelte';
10
+ export type { ReorderableToggleItem } from './types';
@@ -0,0 +1,9 @@
1
+ export { default as ReorderableToggleList } from './cmp.reorderable-toggle-list.svelte';
2
+ export { default as ToolbarButtonItem } from './cmp.toolbar-button-item.svelte';
3
+ export { default as ToolbarCheckboxItem } from './cmp.toolbar-checkbox-item.svelte';
4
+ export { default as ToolbarDropdown } from './cmp.toolbar-dropdown.svelte';
5
+ export { default as ToolbarPanel } from './cmp.toolbar-panel.svelte';
6
+ export { default as ToolbarSearchInput } from './cmp.toolbar-search-input.svelte';
7
+ export { default as ToolbarSegmentedControl } from './cmp.toolbar-segmented-control.svelte';
8
+ export { default as ToolbarSwitchItem } from './cmp.toolbar-switch-item.svelte';
9
+ export { default as ToolbarToggleItem } from './cmp.toolbar-toggle-item.svelte';
@@ -0,0 +1,6 @@
1
+ export type ReorderableToggleItem = {
2
+ id: string;
3
+ label: string;
4
+ enabled: boolean;
5
+ fixed?: boolean;
6
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,97 @@
1
+ <script lang="ts" generics="T extends string | number">const { segments, selected, on } = $props();
2
+ </script>
3
+
4
+ <div class="segmented-control">
5
+ {#each segments as segment (segment.id)}
6
+ <button
7
+ type="button"
8
+ class="segmented-control__segment"
9
+ class:segmented-control__segment--selected={selected === segment.id}
10
+ onclick={() => on?.change?.(segment.id)}>
11
+ <span class="segmented-control__label">{segment.label}</span>
12
+ </button>
13
+ {/each}
14
+ </div>
15
+
16
+ <!--
17
+ @component
18
+ A segmented control for switching between a set of options. Each segment is a button with a label.
19
+
20
+ ### CSS Custom Properties
21
+ | Property | Description | Default |
22
+ |---|---|---|
23
+ | `--sc-kit--segmented-control--root--font-size` | Base font size for em-based sizing | `1rem` |
24
+ | `--sc-kit--segmented-control--height` | Height of the control | `1.75em` |
25
+ | `--sc-kit--segmented-control--background` | Background color | `var(--sc-color--bg-button, light-dark(neutral-50, dark-600))` |
26
+ | `--sc-kit--segmented-control--border-color` | Border color | `var(--sc-color--border-primary, light-dark(neutral-100, dark-800))` |
27
+ | `--sc-kit--segmented-control--border-radius` | Border radius | `0.25em` |
28
+ | `--sc-kit--segmented-control--segment--padding-block` | Segment vertical padding | `0.25em` |
29
+ | `--sc-kit--segmented-control--segment--padding-inline` | Segment horizontal padding | `1.125em` |
30
+ | `--sc-kit--segmented-control--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
31
+ | `--sc-kit--segmented-control--label--font-size` | Label font size | `0.625em` |
32
+ | `--sc-kit--segmented-control--selected--background` | Selected segment background | `var(--sc-color--bg-menu-active, light-dark(primary-50, dark-400))` |
33
+ | `--sc-kit--segmented-control--selected--box-shadow` | Selected segment box shadow | `0px 1px 3px rgba(0,0,0,0.1)` |
34
+ | `--sc-kit--segmented-control--selected--color` | Selected segment text color | `var(--sc-color--text-primary, light-dark(black, white))` |
35
+ -->
36
+
37
+ <style>.segmented-control {
38
+ --_segmented-control--root--font-size: var(--sc-kit--segmented-control--root--font-size, 1rem);
39
+ --_segmented-control--height: var(--sc-kit--segmented-control--height, 1.75em);
40
+ --_segmented-control--background: var(
41
+ --sc-kit--segmented-control--background,
42
+ var(--sc-color--bg-button, light-dark(#f9fafb, #242424))
43
+ );
44
+ --_segmented-control--border-color: var(
45
+ --sc-kit--segmented-control--border-color,
46
+ var(--sc-color--border-primary, light-dark(#f2f2f3, #1e1e1e))
47
+ );
48
+ --_segmented-control--border-radius: var(--sc-kit--segmented-control--border-radius, 0.25em);
49
+ --_segmented-control--segment--padding-block: var(--sc-kit--segmented-control--segment--padding-block, 0.25em);
50
+ --_segmented-control--segment--padding-inline: var(--sc-kit--segmented-control--segment--padding-inline, 1.125em);
51
+ --_segmented-control--label--color: var(
52
+ --sc-kit--segmented-control--label--color,
53
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
54
+ );
55
+ --_segmented-control--label--font-size: var(--sc-kit--segmented-control--label--font-size, 0.625em);
56
+ --_segmented-control--selected--background: var(
57
+ --sc-kit--segmented-control--selected--background,
58
+ var(--sc-color--bg-menu-active, light-dark(#f1f6fd, #2c2c2c))
59
+ );
60
+ --_segmented-control--selected--box-shadow: var(
61
+ --sc-kit--segmented-control--selected--box-shadow,
62
+ 0px 1px 3px var(--sc-color--box-shadow, rgba(0, 0, 0, 0.1))
63
+ );
64
+ --_segmented-control--selected--color: var(
65
+ --sc-kit--segmented-control--selected--color,
66
+ var(--sc-color--text-primary, light-dark(#000000, #ffffff))
67
+ );
68
+ display: flex;
69
+ width: 100%;
70
+ font-size: var(--_segmented-control--root--font-size);
71
+ height: var(--_segmented-control--height);
72
+ background: var(--_segmented-control--background);
73
+ border: 1px solid var(--_segmented-control--border-color);
74
+ border-radius: var(--_segmented-control--border-radius);
75
+ gap: 0.0313em;
76
+ overflow: hidden;
77
+ }
78
+ .segmented-control__segment {
79
+ color: var(--_segmented-control--label--color);
80
+ flex: 1;
81
+ display: flex;
82
+ flex-direction: column;
83
+ align-items: center;
84
+ justify-content: center;
85
+ padding: var(--_segmented-control--segment--padding-block) var(--_segmented-control--segment--padding-inline);
86
+ transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1), color 250ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1);
87
+ }
88
+ .segmented-control__segment--selected {
89
+ box-shadow: var(--_segmented-control--selected--box-shadow);
90
+ }
91
+ .segmented-control__segment--selected, .segmented-control__segment:hover {
92
+ background: var(--_segmented-control--selected--background);
93
+ color: var(--_segmented-control--selected--color);
94
+ }
95
+ .segmented-control__label {
96
+ font-size: var(--_segmented-control--label--font-size);
97
+ }</style>
@@ -0,0 +1,52 @@
1
+ declare function $$render<T extends string | number>(): {
2
+ props: {
3
+ segments: {
4
+ id: T;
5
+ label: string;
6
+ }[];
7
+ selected: T;
8
+ on?: {
9
+ change?: (id: T) => void;
10
+ };
11
+ };
12
+ exports: {};
13
+ bindings: "";
14
+ slots: {};
15
+ events: {};
16
+ };
17
+ declare class __sveltets_Render<T extends string | number> {
18
+ props(): ReturnType<typeof $$render<T>>['props'];
19
+ events(): ReturnType<typeof $$render<T>>['events'];
20
+ slots(): ReturnType<typeof $$render<T>>['slots'];
21
+ bindings(): "";
22
+ exports(): {};
23
+ }
24
+ interface $$IsomorphicComponent {
25
+ new <T extends string | number>(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']>> & {
26
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
27
+ } & ReturnType<__sveltets_Render<T>['exports']>;
28
+ <T extends string | number>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
29
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
30
+ }
31
+ /**
32
+ * A segmented control for switching between a set of options. Each segment is a button with a label.
33
+ *
34
+ * ### CSS Custom Properties
35
+ * | Property | Description | Default |
36
+ * |---|---|---|
37
+ * | `--sc-kit--segmented-control--root--font-size` | Base font size for em-based sizing | `1rem` |
38
+ * | `--sc-kit--segmented-control--height` | Height of the control | `1.75em` |
39
+ * | `--sc-kit--segmented-control--background` | Background color | `var(--sc-color--bg-button, light-dark(neutral-50, dark-600))` |
40
+ * | `--sc-kit--segmented-control--border-color` | Border color | `var(--sc-color--border-primary, light-dark(neutral-100, dark-800))` |
41
+ * | `--sc-kit--segmented-control--border-radius` | Border radius | `0.25em` |
42
+ * | `--sc-kit--segmented-control--segment--padding-block` | Segment vertical padding | `0.25em` |
43
+ * | `--sc-kit--segmented-control--segment--padding-inline` | Segment horizontal padding | `1.125em` |
44
+ * | `--sc-kit--segmented-control--label--color` | Label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
45
+ * | `--sc-kit--segmented-control--label--font-size` | Label font size | `0.625em` |
46
+ * | `--sc-kit--segmented-control--selected--background` | Selected segment background | `var(--sc-color--bg-menu-active, light-dark(primary-50, dark-400))` |
47
+ * | `--sc-kit--segmented-control--selected--box-shadow` | Selected segment box shadow | `0px 1px 3px rgba(0,0,0,0.1)` |
48
+ * | `--sc-kit--segmented-control--selected--color` | Selected segment text color | `var(--sc-color--text-primary, light-dark(black, white))` |
49
+ */
50
+ declare const Cmp: $$IsomorphicComponent;
51
+ type Cmp<T extends string | number> = InstanceType<typeof Cmp<T>>;
52
+ export default Cmp;
@@ -0,0 +1 @@
1
+ export { default as SegmentedControl } from './cmp.segmented-control.svelte';
@@ -0,0 +1 @@
1
+ export { default as SegmentedControl } from './cmp.segmented-control.svelte';
@@ -1,7 +1,7 @@
1
1
  export { default as Table } from './cmp.table.svelte';
2
2
  export { default as TableColumnsManager } from './table-columns-manager/cmp.table-columns-manager.svelte';
3
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';
4
+ export type { ColumnsConfig, TableColumnSortDirection, TableColumnType, TableImageColumnFormat, TableItemAction, TableTextColumnFormat, TableOrderByState, PageQuery, IAnyTableColumn } from './types';
5
5
  export type { TableGroupAction } from './table-group-actions/types.svelte';
6
6
  export { TableModel } from './table-model.svelte';
7
7
  export { pickDirectionFromOrderByState, generatePagination } from './service';
@@ -19,14 +19,14 @@ const fmt = (d, options) => new Intl.DateTimeFormat(undefined, options).format(d
19
19
  {#if column.maxLines === 'single-line-no-trim'}
20
20
  <span class="table-text-cell__single-line-no-trim">{HtmlHelper.stripHtml(value)}</span>
21
21
  {:else}
22
- <LineClamp maxLines={column.maxLines || 3}>
22
+ <LineClamp maxLines={column.maxLines || 1}>
23
23
  {@html HtmlHelper.sanitizeHtml(value)}
24
24
  </LineClamp>
25
25
  {/if}
26
26
  {:else if column.maxLines === 'single-line-no-trim'}
27
27
  <span class="table-text-cell__single-line-no-trim">{value}</span>
28
28
  {:else}
29
- <LineClamp maxLines={column.maxLines || 3}>{value}</LineClamp>
29
+ <LineClamp maxLines={column.maxLines || 1}>{value}</LineClamp>
30
30
  {/if}
31
31
  </span>
32
32
 
@@ -1,15 +1,81 @@
1
- <script lang="ts" generics="T extends {id: string}">import { Button } from '../../button';
1
+ <script lang="ts" generics="T extends {id: string}">import { LocalStorageItem } from '../../../core/local-storage';
2
+ import { Button } from '../../button';
2
3
  import { Dropdown } from '../../dropdown';
3
4
  import { IconText } from '../../icon-text';
4
- import { Toggle } from '../../toggle';
5
+ import { ReorderableToggleList } from '../../page-toolbar';
5
6
  import { TableColumnsManagerLocalization } from './table-columns-manager-localization';
6
7
  import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
7
8
  import IconColumnTwo from '@fluentui/svg-icons/icons/text_column_two_20_regular.svg?raw';
8
- let { columns } = $props();
9
+ import { untrack } from 'svelte';
10
+ let { model, localStorageKey, on } = $props();
9
11
  const localization = new TableColumnsManagerLocalization();
12
+ const storage = $derived(localStorageKey ? LocalStorageItem.of(localStorageKey) : null);
13
+ const hideableColumns = $derived(model.columns.filter((c) => c.hideable));
14
+ const items = $derived(hideableColumns.map((col) => ({
15
+ id: String(col.id),
16
+ label: col.title,
17
+ enabled: !col.hidden
18
+ })));
19
+ // Load from localStorage once columns are available
20
+ let initialized = false;
21
+ $effect(() => {
22
+ const columns = hideableColumns;
23
+ if (!storage || columns.length === 0 || initialized) {
24
+ return;
25
+ }
26
+ initialized = true;
27
+ const saved = storage.get();
28
+ if (!saved || !Array.isArray(saved)) {
29
+ return;
30
+ }
31
+ untrack(() => {
32
+ applyConfig(saved);
33
+ });
34
+ });
35
+ /** Apply a columns config. Updates column visibility and order on the model, persists to localStorage. */
36
+ export const applyConfig = (config) => {
37
+ const configMap = new Map(config.map((c) => [c.id, c]));
38
+ for (const col of model.columns) {
39
+ if (col.hideable) {
40
+ const cfg = configMap.get(String(col.id));
41
+ if (cfg) {
42
+ col.hidden = cfg.hidden;
43
+ }
44
+ }
45
+ }
46
+ reorderHideableColumns(config.map((c) => c.id));
47
+ if (storage) {
48
+ storage.set(config);
49
+ }
50
+ };
51
+ const reorderHideableColumns = (orderedIds) => {
52
+ const columns = model.columns;
53
+ const hideable = columns.filter((c) => c.hideable);
54
+ const hideableMap = new Map(hideable.map((c) => [String(c.id), c]));
55
+ const orderedSet = new Set(orderedIds);
56
+ const reordered = [];
57
+ for (const id of orderedIds) {
58
+ const col = hideableMap.get(id);
59
+ if (col) {
60
+ reordered.push(col);
61
+ }
62
+ }
63
+ for (const col of hideable) {
64
+ if (!orderedSet.has(String(col.id))) {
65
+ reordered.push(col);
66
+ }
67
+ }
68
+ let idx = 0;
69
+ model.setResolvedColumns(columns.map((col) => (col.hideable ? reordered[idx++] : col)));
70
+ };
71
+ const handleChange = (updatedItems) => {
72
+ const config = updatedItems.map((i) => ({ id: i.id, hidden: !i.enabled }));
73
+ applyConfig(config);
74
+ on?.change?.(config);
75
+ };
10
76
  </script>
11
77
 
12
- <Dropdown position="bottom-end" keepDropdownOpen>
78
+ <Dropdown position="bottom-start" keepDropdownOpen>
13
79
  {#snippet trigger()}
14
80
  <Button variant="standard" size="small">
15
81
  <IconText icon={IconColumnTwo} iconColor="blue" secondaryIcon={IconChevronDown}>{localization.columns}</IconText>
@@ -18,25 +84,20 @@ const localization = new TableColumnsManagerLocalization();
18
84
  <div class="columns-manager">
19
85
  <div class="columns-manager__title">{localization.selectColumns}</div>
20
86
  <div class="columns-manager__body">
21
- {#each columns.filter((c) => c.hideable) as column (column)}
22
- <div class="columns-manager__item">
23
- <div class="columns-manager__label">{column.title}</div>
24
- <Toggle isOn={!column.hidden} on={{ change: (value) => (column.hidden = !value) }} />
25
- </div>
26
- {/each}
87
+ <ReorderableToggleList items={items} on={{ change: handleChange }} />
27
88
  </div>
28
89
  </div>
29
90
  </Dropdown>
30
91
 
31
92
  <!--
32
93
  @component
33
- Column visibility manager for tables. Shows a dropdown with toggles for each hideable column.
94
+ Column visibility and order manager for tables. Shows a dropdown with a reorderable toggle list for each hideable column.
95
+ Supports optional localStorage persistence of column order and visibility.
34
96
 
35
97
  ### CSS Custom Properties
36
98
  | Property | Description | Default |
37
99
  |---|---|---|
38
100
  | `--sc-kit--table-columns-manager--title--color` | Title text color | `var(--sc-color--text-primary, light-dark(black, white))` |
39
- | `--sc-kit--table-columns-manager--label--color` | Column label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
40
101
  -->
41
102
 
42
103
  <style>.columns-manager {
@@ -44,10 +105,6 @@ Column visibility manager for tables. Shows a dropdown with toggles for each hid
44
105
  --sc-kit--table-columns-manager--title--color,
45
106
  var(--sc-color--text-primary, light-dark(#000000, #ffffff))
46
107
  );
47
- --_columns-manager--label--color: var(
48
- --sc-kit--table-columns-manager--label--color,
49
- var(--sc-color--text-primary, light-dark(#000000, #ffffff))
50
- );
51
108
  width: 21.875rem;
52
109
  padding: 1.5rem;
53
110
  }
@@ -63,24 +120,4 @@ Column visibility manager for tables. Shows a dropdown with toggles for each hid
63
120
  flex-direction: column;
64
121
  gap: 1rem;
65
122
  padding-block: 0.5rem;
66
- }
67
- .columns-manager__item {
68
- display: flex;
69
- align-items: center;
70
- justify-content: space-between;
71
- gap: 0.5rem;
72
- padding: 0.25rem 0.5rem;
73
- --sc-kit--toggle--switch--height: 1.125rem;
74
- --sc-kit--toggle--switch--width: 2.3125rem;
75
- }
76
- .columns-manager__label {
77
- font-size: 0.875rem;
78
- font-weight: 400;
79
- line-height: 1.25rem;
80
- color: var(--_columns-manager--label--color);
81
- min-width: 0;
82
- text-overflow: ellipsis;
83
- max-width: 100%;
84
- white-space: nowrap;
85
- overflow: hidden;
86
123
  }</style>
@@ -1,11 +1,19 @@
1
- import type { ResolvedColumn } from '../table-column-models.svelte';
1
+ import type { TableModel } from '..';
2
+ import type { ColumnsConfig } from '../types';
2
3
  declare function $$render<T extends {
3
4
  id: string;
4
5
  }>(): {
5
6
  props: {
6
- columns: Array<ResolvedColumn<T>>;
7
+ model: TableModel<T>;
8
+ /** localStorage key for persisting column order and visibility */
9
+ localStorageKey?: string;
10
+ on?: {
11
+ change?: (config: ColumnsConfig) => void;
12
+ };
13
+ };
14
+ exports: {
15
+ /** Apply a columns config. Updates column visibility and order on the model, persists to localStorage. */ applyConfig: (config: ColumnsConfig) => void;
7
16
  };
8
- exports: {};
9
17
  bindings: "";
10
18
  slots: {};
11
19
  events: {};
@@ -17,7 +25,9 @@ declare class __sveltets_Render<T extends {
17
25
  events(): ReturnType<typeof $$render<T>>['events'];
18
26
  slots(): ReturnType<typeof $$render<T>>['slots'];
19
27
  bindings(): "";
20
- exports(): {};
28
+ exports(): {
29
+ /** Apply a columns config. Updates column visibility and order on the model, persists to localStorage. */ applyConfig: (config: ColumnsConfig) => void;
30
+ };
21
31
  }
22
32
  interface $$IsomorphicComponent {
23
33
  new <T extends {
@@ -31,13 +41,13 @@ interface $$IsomorphicComponent {
31
41
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
32
42
  }
33
43
  /**
34
- * Column visibility manager for tables. Shows a dropdown with toggles for each hideable column.
44
+ * Column visibility and order manager for tables. Shows a dropdown with a reorderable toggle list for each hideable column.
45
+ * Supports optional localStorage persistence of column order and visibility.
35
46
  *
36
47
  * ### CSS Custom Properties
37
48
  * | Property | Description | Default |
38
49
  * |---|---|---|
39
50
  * | `--sc-kit--table-columns-manager--title--color` | Title text color | `var(--sc-color--text-primary, light-dark(black, white))` |
40
- * | `--sc-kit--table-columns-manager--label--color` | Column label text color | `var(--sc-color--text-primary, light-dark(black, white))` |
41
51
  */
42
52
  declare const Cmp: $$IsomorphicComponent;
43
53
  type Cmp<T extends {
@@ -36,6 +36,7 @@ export declare class TableModel<T extends WithId> {
36
36
  set columns(value: IAnyTableColumn<T>[]);
37
37
  set editingItem(value: T | null);
38
38
  set highlightedItemIds(value: string[]);
39
+ setResolvedColumns: (columns: ResolvedColumn<T>[]) => void;
39
40
  private reconcileColumns;
40
41
  private mapColumn;
41
42
  }
@@ -97,6 +97,9 @@ export class TableModel {
97
97
  set highlightedItemIds(value) {
98
98
  this._highlightedItemIds = value;
99
99
  }
100
+ setResolvedColumns = (columns) => {
101
+ this._columns = columns;
102
+ };
100
103
  reconcileColumns = (newDefs) => {
101
104
  // Save state from current columns
102
105
  const stateMap = new Map();
@@ -44,7 +44,7 @@ export interface ITableByColumn<T> extends ITableColumn<T> {
44
44
  id: string;
45
45
  name: string;
46
46
  handle: string;
47
- image: string;
47
+ image: string | null;
48
48
  }) | null;
49
49
  /** Returns href for the user link. If not provided, no link is rendered. */
50
50
  hrefFactory?: ((by: {
@@ -101,6 +101,7 @@ export interface ITableSelectColumn<T, K extends keyof T> extends ITableColumn<T
101
101
  export interface ITableTextColumn<T> extends ITableColumn<T> {
102
102
  type: 'text';
103
103
  format?: TableTextColumnFormat | null;
104
+ /** @default 1 */
104
105
  maxLines?: number | 'single-line-no-trim' | null;
105
106
  valueFactory?: ((item: T) => string) | null;
106
107
  editorColumn?: IEditorColumn<T> | null;
@@ -141,4 +142,8 @@ export type SelectionSettings<T extends WithId> = {
141
142
  repository?: Repository<T>;
142
143
  };
143
144
  export type TableColumnSortDirection = 'none' | 'asc' | 'desc';
145
+ export type ColumnsConfig = Array<{
146
+ id: string;
147
+ hidden: boolean;
148
+ }>;
144
149
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -53,6 +53,10 @@
53
53
  "types": "./dist/core/i18n/index.d.ts",
54
54
  "svelte": "./dist/core/i18n/index.js"
55
55
  },
56
+ "./core/local-storage": {
57
+ "types": "./dist/core/local-storage/index.d.ts",
58
+ "svelte": "./dist/core/local-storage/index.js"
59
+ },
56
60
  "./core/locale": {
57
61
  "types": "./dist/core/locale/index.d.ts",
58
62
  "svelte": "./dist/core/locale/index.js"
@@ -181,6 +185,10 @@
181
185
  "types": "./dist/ui/media-viewer-dialog/index.d.ts",
182
186
  "svelte": "./dist/ui/media-viewer-dialog/index.js"
183
187
  },
188
+ "./ui/page-toolbar": {
189
+ "types": "./dist/ui/page-toolbar/index.d.ts",
190
+ "svelte": "./dist/ui/page-toolbar/index.js"
191
+ },
184
192
  "./ui/player/buttons": {
185
193
  "types": "./dist/ui/player/buttons/index.d.ts",
186
194
  "svelte": "./dist/ui/player/buttons/index.js"
@@ -213,6 +221,10 @@
213
221
  "types": "./dist/ui/seek-bar/index.d.ts",
214
222
  "svelte": "./dist/ui/seek-bar/index.js"
215
223
  },
224
+ "./ui/segmented-control": {
225
+ "types": "./dist/ui/segmented-control/index.d.ts",
226
+ "svelte": "./dist/ui/segmented-control/index.js"
227
+ },
216
228
  "./ui/selects": {
217
229
  "types": "./dist/ui/selects/index.d.ts",
218
230
  "svelte": "./dist/ui/selects/index.js"