@streamscloud/kit 0.17.0 → 0.18.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.
- package/dist/ui/badge/cmp.badge.svelte +4 -0
- package/dist/ui/badge/cmp.badge.svelte.d.ts +1 -0
- package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte +131 -0
- package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte.d.ts +31 -0
- package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte +14 -0
- package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte.d.ts +19 -0
- package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte +19 -0
- package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte.d.ts +35 -0
- package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte +143 -0
- package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte.d.ts +68 -0
- package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte +71 -0
- package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte.d.ts +32 -0
- package/dist/ui/page-toolbar/cmp.toolbar-option.svelte +189 -0
- package/dist/ui/page-toolbar/cmp.toolbar-option.svelte.d.ts +47 -0
- package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte +23 -8
- package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte.d.ts +14 -6
- package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte +46 -0
- package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte.d.ts +24 -0
- package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte +31 -0
- package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte.d.ts +44 -0
- package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte → cmp.toolbar-switch.svelte} +10 -10
- package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte.d.ts → cmp.toolbar-switch.svelte.d.ts} +2 -2
- package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte +14 -0
- package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte.d.ts +19 -0
- package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte +51 -0
- package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte.d.ts +27 -0
- package/dist/ui/page-toolbar/index.d.ts +12 -7
- package/dist/ui/page-toolbar/index.js +11 -6
- package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.d.ts +5 -0
- package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.js +17 -0
- package/dist/ui/page-toolbar/toolbar-filter-select-localization.d.ts +5 -0
- package/dist/ui/page-toolbar/toolbar-filter-select-localization.js +20 -0
- package/dist/ui/page-toolbar/toolbar-sort-select-localization.d.ts +3 -0
- package/dist/ui/page-toolbar/toolbar-sort-select-localization.js +9 -0
- package/dist/ui/page-toolbar/toolbar-view-controls-localization.d.ts +5 -0
- package/dist/ui/page-toolbar/toolbar-view-controls-localization.js +17 -0
- package/dist/ui/page-toolbar/types.d.ts +1 -1
- package/dist/ui/select/index.d.ts +1 -0
- package/dist/ui/select/index.js +1 -0
- package/dist/ui/select/select-listbox.svelte +11 -5
- package/dist/ui/select/select-listbox.svelte.d.ts +1 -1
- package/dist/ui/table/_table-styles.scss +156 -0
- package/dist/ui/table/cmp.table-draggable.svelte +338 -0
- package/dist/ui/table/cmp.table-draggable.svelte.d.ts +79 -0
- package/dist/ui/table/cmp.table.svelte +96 -265
- package/dist/ui/table/cmp.table.svelte.d.ts +16 -8
- package/dist/ui/table/index.d.ts +1 -0
- package/dist/ui/table/index.js +1 -0
- package/dist/ui/table/table-cells/index.d.ts +1 -12
- package/dist/ui/table/table-cells/index.js +1 -12
- package/dist/ui/table/table-cells/table-cell.svelte +77 -0
- package/dist/ui/table/table-cells/{table-select-cell.svelte.d.ts → table-cell.svelte.d.ts} +12 -6
- package/dist/ui/table/table-column-models.svelte.d.ts +1 -2
- package/dist/ui/table/table-column-models.svelte.js +0 -1
- package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte +20 -47
- package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte.d.ts +3 -7
- package/dist/ui/table/table-columns-manager/table-columns-manager-localization.d.ts +1 -1
- package/dist/ui/table/table-columns-manager/table-columns-manager-localization.js +7 -7
- package/dist/ui/table/table-localization.d.ts +0 -2
- package/dist/ui/table/table-localization.js +0 -14
- package/dist/ui/table/table-model.svelte.d.ts +2 -3
- package/dist/ui/table/table-model.svelte.js +5 -35
- package/dist/ui/table/table-view.svelte.d.ts +14 -0
- package/dist/ui/table/table-view.svelte.js +32 -0
- package/dist/ui/table/types.d.ts +5 -28
- package/dist/ui/toggle/cmp.toggle.svelte +32 -26
- package/dist/ui/toggle/cmp.toggle.svelte.d.ts +2 -0
- package/dist/ui/tree/cmp.tree-node-view.svelte +7 -2
- package/dist/ui/tree/cmp.tree.svelte +9 -1
- package/dist/ui/tree/cmp.tree.svelte.d.ts +1 -1
- package/dist/ui/tree/tree-navigation.svelte.d.ts +2 -0
- package/dist/ui/tree/tree-navigation.svelte.js +3 -0
- package/package.json +1 -1
- package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte +0 -153
- package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte.d.ts +0 -20
- package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte +0 -19
- package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte.d.ts +0 -12
- package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte +0 -42
- package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte.d.ts +0 -20
- package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte +0 -57
- package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte.d.ts +0 -19
- package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte +0 -16
- package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte.d.ts +0 -12
- package/dist/ui/table/table-cells/table-select-cell.svelte +0 -28
- package/dist/ui/table/table-cells/table-text-input-cell.svelte +0 -69
- package/dist/ui/table/table-cells/table-text-input-cell.svelte.d.ts +0 -38
|
@@ -22,6 +22,7 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
|
|
|
22
22
|
| `--sc-kit--badge--padding-inline` | Horizontal padding | `0.875rem 0.75rem` |
|
|
23
23
|
| `--sc-kit--badge--border-radius` | Corner radius | `var(--sc-kit--radius--pill)` |
|
|
24
24
|
| `--sc-kit--badge--font-size` | Content font size | per size |
|
|
25
|
+
| `--sc-kit--badge--icon-size` | Leading icon size | per size (14 / 16px) |
|
|
25
26
|
| `--sc-kit--badge--font-weight` | Font weight | `var(--sc-kit--font-weight--medium)` |
|
|
26
27
|
| `--sc-kit--badge--gap` | Gap between children | `6px` |
|
|
27
28
|
-->
|
|
@@ -48,6 +49,7 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
|
|
|
48
49
|
display: inline-flex;
|
|
49
50
|
align-items: center;
|
|
50
51
|
flex-shrink: 0;
|
|
52
|
+
--sc-kit--icon--size: var(--_badge--icon-size);
|
|
51
53
|
}
|
|
52
54
|
.badge__content {
|
|
53
55
|
min-width: 0;
|
|
@@ -63,10 +65,12 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
|
|
|
63
65
|
.badge--sm {
|
|
64
66
|
--_badge--height: var(--sc-kit--badge--height, 1.25rem);
|
|
65
67
|
--_badge--font-size: var(--sc-kit--badge--font-size, 0.625rem);
|
|
68
|
+
--_badge--icon-size: var(--sc-kit--badge--icon-size, 0.875rem);
|
|
66
69
|
}
|
|
67
70
|
.badge--md {
|
|
68
71
|
--_badge--height: var(--sc-kit--badge--height, 1.5rem);
|
|
69
72
|
--_badge--font-size: var(--sc-kit--badge--font-size, var(--sc-kit--font-size--xs));
|
|
73
|
+
--_badge--icon-size: var(--sc-kit--badge--icon-size, 1rem);
|
|
70
74
|
}
|
|
71
75
|
.badge--neutral-soft {
|
|
72
76
|
--_badge--color: var(--sc-kit--badge--color, var(--sc-kit--color--text--secondary));
|
|
@@ -26,6 +26,7 @@ type Props = {
|
|
|
26
26
|
* | `--sc-kit--badge--padding-inline` | Horizontal padding | `0.875rem 0.75rem` |
|
|
27
27
|
* | `--sc-kit--badge--border-radius` | Corner radius | `var(--sc-kit--radius--pill)` |
|
|
28
28
|
* | `--sc-kit--badge--font-size` | Content font size | per size |
|
|
29
|
+
* | `--sc-kit--badge--icon-size` | Leading icon size | per size (14 / 16px) |
|
|
29
30
|
* | `--sc-kit--badge--font-weight` | Font weight | `var(--sc-kit--font-weight--medium)` |
|
|
30
31
|
* | `--sc-kit--badge--gap` | Gap between children | `6px` |
|
|
31
32
|
*/
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<script lang="ts">import { Icon } from '../icon';
|
|
2
|
+
import ToolbarDivider from './cmp.toolbar-divider.svelte';
|
|
3
|
+
import ToolbarOption from './cmp.toolbar-option.svelte';
|
|
4
|
+
import ToolbarSectionTitle from './cmp.toolbar-section-title.svelte';
|
|
5
|
+
import { ReorderableCheckboxListLocalization } from './reorderable-checkbox-list-localization';
|
|
6
|
+
import IconReorderDotsVertical from '@fluentui/svg-icons/icons/re_order_dots_vertical_20_regular.svg?raw';
|
|
7
|
+
import { flip } from 'svelte/animate';
|
|
8
|
+
import { dndzone } from 'svelte-dnd-action';
|
|
9
|
+
let { items, title, standard, size = 'md', showClearAll = true, on } = $props();
|
|
10
|
+
const localization = new ReorderableCheckboxListLocalization();
|
|
11
|
+
const reorderableItems = $derived(items.filter((i) => !i.fixed));
|
|
12
|
+
const fixedItems = $derived(items.filter((i) => i.fixed));
|
|
13
|
+
const toReorderable = ({ id, label, enabled }) => ({ id, label, enabled });
|
|
14
|
+
const toFixed = ({ id, label, enabled, fixed }) => ({ id, label, enabled, fixed });
|
|
15
|
+
let dndItems = $state.raw([]);
|
|
16
|
+
$effect(() => {
|
|
17
|
+
dndItems = reorderableItems.map(toReorderable);
|
|
18
|
+
});
|
|
19
|
+
const flipDurationMs = 200;
|
|
20
|
+
const emitChange = (reordered) => {
|
|
21
|
+
on.change([...fixedItems.map(toFixed), ...reordered.map(toReorderable)]);
|
|
22
|
+
};
|
|
23
|
+
const handleConsider = (e) => {
|
|
24
|
+
dndItems = e.detail.items;
|
|
25
|
+
};
|
|
26
|
+
const handleFinalize = (e) => {
|
|
27
|
+
emitChange(e.detail.items);
|
|
28
|
+
};
|
|
29
|
+
const handleToggle = (id, enabled) => {
|
|
30
|
+
emitChange(dndItems.map((i) => (i.id === id ? { ...i, enabled } : i)));
|
|
31
|
+
};
|
|
32
|
+
const handleFixedToggle = (id, enabled) => {
|
|
33
|
+
const updatedFixed = fixedItems.map((item) => toFixed(item.id === id ? { ...item, enabled } : item));
|
|
34
|
+
on.change([...updatedFixed, ...dndItems.map(toReorderable)]);
|
|
35
|
+
};
|
|
36
|
+
const anyEnabled = $derived(items.some((i) => i.enabled));
|
|
37
|
+
const clearAll = () => {
|
|
38
|
+
on.change([...fixedItems.map((item) => toFixed({ ...item, enabled: false })), ...dndItems.map((item) => toReorderable({ ...item, enabled: false }))]);
|
|
39
|
+
};
|
|
40
|
+
const allEnabled = $derived(items.length > 0 && items.every((i) => i.enabled));
|
|
41
|
+
const matchesStandard = $derived(!!standard && items.length === standard.length && items.every((item, idx) => item.id === standard[idx].id && item.enabled === standard[idx].enabled));
|
|
42
|
+
const standardCoversAll = $derived(!!standard && standard.length > 0 && standard.every((i) => i.enabled));
|
|
43
|
+
const selectStandard = () => {
|
|
44
|
+
if (standard) {
|
|
45
|
+
on.change(standard.map((item) => (item.fixed ? toFixed(item) : toReorderable(item))));
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const enableAll = () => {
|
|
49
|
+
on.change([...fixedItems.map((item) => toFixed({ ...item, enabled: true })), ...dndItems.map((item) => toReorderable({ ...item, enabled: true }))]);
|
|
50
|
+
};
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<div class="reorderable-checkbox-list">
|
|
54
|
+
{#if standard}
|
|
55
|
+
<ToolbarOption size={size} selectable={{ selected: matchesStandard, display: 'checkmark' }} on={{ click: selectStandard }}
|
|
56
|
+
>{localization.standard}</ToolbarOption>
|
|
57
|
+
{#if !standardCoversAll}
|
|
58
|
+
<ToolbarOption size={size} selectable={{ selected: allEnabled, display: 'checkmark' }} on={{ click: enableAll }}>{localization.allFields}</ToolbarOption>
|
|
59
|
+
{/if}
|
|
60
|
+
{/if}
|
|
61
|
+
{#if title}
|
|
62
|
+
<ToolbarSectionTitle>{title}</ToolbarSectionTitle>
|
|
63
|
+
{/if}
|
|
64
|
+
{#each fixedItems as item (item.id)}
|
|
65
|
+
<ToolbarOption size={size} selectable={{ selected: item.enabled, display: 'checkbox' }} on={{ click: () => handleFixedToggle(item.id, !item.enabled) }}>
|
|
66
|
+
{#snippet prepend()}
|
|
67
|
+
<span class="reorderable-checkbox-list__handle reorderable-checkbox-list__handle--hidden" aria-hidden="true"
|
|
68
|
+
><Icon src={IconReorderDotsVertical} /></span>
|
|
69
|
+
{/snippet}
|
|
70
|
+
{item.label}
|
|
71
|
+
</ToolbarOption>
|
|
72
|
+
{/each}
|
|
73
|
+
<div
|
|
74
|
+
class="reorderable-checkbox-list__dnd"
|
|
75
|
+
use:dndzone={{ items: dndItems, dropTargetStyle: {}, flipDurationMs, morphDisabled: true }}
|
|
76
|
+
onconsider={handleConsider}
|
|
77
|
+
onfinalize={handleFinalize}>
|
|
78
|
+
{#each dndItems as item (item.id)}
|
|
79
|
+
<div class="reorderable-checkbox-list__item" animate:flip={{ duration: flipDurationMs }}>
|
|
80
|
+
<ToolbarOption size={size} selectable={{ selected: item.enabled, display: 'checkbox' }} on={{ click: () => handleToggle(item.id, !item.enabled) }}>
|
|
81
|
+
{#snippet prepend()}
|
|
82
|
+
<span class="reorderable-checkbox-list__handle"><Icon src={IconReorderDotsVertical} /></span>
|
|
83
|
+
{/snippet}
|
|
84
|
+
{item.label}
|
|
85
|
+
</ToolbarOption>
|
|
86
|
+
</div>
|
|
87
|
+
{/each}
|
|
88
|
+
</div>
|
|
89
|
+
{#if showClearAll && anyEnabled}
|
|
90
|
+
<ToolbarDivider />
|
|
91
|
+
<ToolbarOption size={size} variant="muted" on={{ click: clearAll }}>{localization.clearAll}</ToolbarOption>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!--
|
|
96
|
+
@component
|
|
97
|
+
A reorderable checklist: each row is a draggable `ToolbarOption` checkbox preceded by a left drag handle.
|
|
98
|
+
Clicking a row toggles its `enabled`; dragging reorders. Items flagged `fixed` render above the drag zone
|
|
99
|
+
with a hidden handle (non-reorderable, still toggleable). Pass `title` for a section header, and `standard`
|
|
100
|
+
(a canonical order + enabled reference) to render `Standard` / `All fields` preset rows with auto-detected
|
|
101
|
+
active state. A default `Clear all` footer shows while any item is enabled — set `showClearAll={false}` to
|
|
102
|
+
remove it.
|
|
103
|
+
|
|
104
|
+
### CSS Custom Properties
|
|
105
|
+
| Property | Description | Default |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `--sc-kit--reorderable-checkbox-list--handle--color` | Drag handle icon color | `var(--sc-kit--color--text--muted)` |
|
|
108
|
+
-->
|
|
109
|
+
|
|
110
|
+
<style>.reorderable-checkbox-list {
|
|
111
|
+
--_rcl--handle--color: var(--sc-kit--reorderable-checkbox-list--handle--color, var(--sc-kit--color--text--muted));
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
}
|
|
115
|
+
.reorderable-checkbox-list__dnd {
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
}
|
|
119
|
+
.reorderable-checkbox-list__handle {
|
|
120
|
+
--sc-kit--icon--size: 1rem;
|
|
121
|
+
--sc-kit--icon--color: var(--_rcl--handle--color);
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
cursor: grab;
|
|
125
|
+
}
|
|
126
|
+
.reorderable-checkbox-list__handle:active {
|
|
127
|
+
cursor: grabbing;
|
|
128
|
+
}
|
|
129
|
+
.reorderable-checkbox-list__handle--hidden {
|
|
130
|
+
visibility: hidden;
|
|
131
|
+
}</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReorderableCheckboxItem } from './types';
|
|
2
|
+
type Props = {
|
|
3
|
+
items: ReorderableCheckboxItem[];
|
|
4
|
+
/** Optional section title above the list. */
|
|
5
|
+
title?: string;
|
|
6
|
+
/** Reference `Standard` config (canonical order + enabled). When set, `Standard` / `All fields` preset rows render on top with auto-detected active state. */
|
|
7
|
+
standard?: ReorderableCheckboxItem[];
|
|
8
|
+
/** Row size preset — forwarded to `ToolbarOption`. @default 'md' */
|
|
9
|
+
size?: 'sm' | 'md';
|
|
10
|
+
/** Show the default `Clear all` footer (unchecks every item) while something is enabled. @default true */
|
|
11
|
+
showClearAll?: boolean;
|
|
12
|
+
on: {
|
|
13
|
+
change: (items: ReorderableCheckboxItem[]) => void;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A reorderable checklist: each row is a draggable `ToolbarOption` checkbox preceded by a left drag handle.
|
|
18
|
+
* Clicking a row toggles its `enabled`; dragging reorders. Items flagged `fixed` render above the drag zone
|
|
19
|
+
* with a hidden handle (non-reorderable, still toggleable). Pass `title` for a section header, and `standard`
|
|
20
|
+
* (a canonical order + enabled reference) to render `Standard` / `All fields` preset rows with auto-detected
|
|
21
|
+
* active state. A default `Clear all` footer shows while any item is enabled — set `showClearAll={false}` to
|
|
22
|
+
* remove it.
|
|
23
|
+
*
|
|
24
|
+
* ### CSS Custom Properties
|
|
25
|
+
* | Property | Description | Default |
|
|
26
|
+
* |---|---|---|
|
|
27
|
+
* | `--sc-kit--reorderable-checkbox-list--handle--color` | Drag handle icon color | `var(--sc-kit--color--text--muted)` |
|
|
28
|
+
*/
|
|
29
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
30
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
31
|
+
export default Cmp;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts">import ToolbarOption from './cmp.toolbar-option.svelte';
|
|
2
|
+
const { checked, size = 'md', disabled = false, children, on } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<ToolbarOption size={size} disabled={disabled} selectable={{ selected: checked, display: 'checkbox' }} on={{ click: () => on?.change?.(!checked) }}>
|
|
6
|
+
{@render children()}
|
|
7
|
+
</ToolbarOption>
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
@component
|
|
11
|
+
A checkbox row for toolbar dropdowns — a thin wrapper over `ToolbarOption` with a leading checkbox
|
|
12
|
+
glyph. The whole row is the click target; clicking toggles `checked` through `on.change`. Styling and
|
|
13
|
+
sizing come from `ToolbarOption`.
|
|
14
|
+
-->
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Props = {
|
|
3
|
+
checked: boolean;
|
|
4
|
+
/** Row density — forwarded to `ToolbarOption`. @default 'md' */
|
|
5
|
+
size?: 'sm' | 'md';
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
on?: {
|
|
9
|
+
change?: (value: boolean) => void;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A checkbox row for toolbar dropdowns — a thin wrapper over `ToolbarOption` with a leading checkbox
|
|
14
|
+
* glyph. The whole row is the click target; clicking toggles `checked` through `on.change`. Styling and
|
|
15
|
+
* sizing come from `ToolbarOption`.
|
|
16
|
+
*/
|
|
17
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
19
|
+
export default Cmp;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<div class="toolbar-divider"></div>
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
A thin horizontal separator for toolbar dropdown panels — use between option groups or above a
|
|
6
|
+
footer. Compose it freely inside a `ToolbarFilterSelect` footer snippet.
|
|
7
|
+
|
|
8
|
+
### CSS Custom Properties
|
|
9
|
+
| Property | Description | Default |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `--sc-kit--toolbar-divider--color` | Line color | `var(--sc-kit--color--border)` |
|
|
12
|
+
-->
|
|
13
|
+
|
|
14
|
+
<style>.toolbar-divider {
|
|
15
|
+
flex-shrink: 0;
|
|
16
|
+
block-size: 1px;
|
|
17
|
+
margin: var(--sc-kit--space--1) var(--sc-kit--space--2);
|
|
18
|
+
background: var(--sc-kit--toolbar-divider--color, var(--sc-kit--color--border));
|
|
19
|
+
}</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export default Cmp;
|
|
2
|
+
type Cmp = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A thin horizontal separator for toolbar dropdown panels — use between option groups or above a
|
|
11
|
+
* footer. Compose it freely inside a `ToolbarFilterSelect` footer snippet.
|
|
12
|
+
*
|
|
13
|
+
* ### CSS Custom Properties
|
|
14
|
+
* | Property | Description | Default |
|
|
15
|
+
* |---|---|---|
|
|
16
|
+
* | `--sc-kit--toolbar-divider--color` | Line color | `var(--sc-kit--color--border)` |
|
|
17
|
+
*/
|
|
18
|
+
declare const Cmp: $$__sveltets_2_IsomorphicComponent<{
|
|
19
|
+
[x: string]: never;
|
|
20
|
+
}, {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
}, {}, {}, string>;
|
|
23
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
24
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
25
|
+
$$bindings?: Bindings;
|
|
26
|
+
} & Exports;
|
|
27
|
+
(internal: unknown, props: {
|
|
28
|
+
$$events?: Events;
|
|
29
|
+
$$slots?: Slots;
|
|
30
|
+
}): Exports & {
|
|
31
|
+
$set?: any;
|
|
32
|
+
$on?: any;
|
|
33
|
+
};
|
|
34
|
+
z_$$bindings?: Bindings;
|
|
35
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts" generics="T">import { Button } from '../button';
|
|
2
|
+
import { IconText } from '../icon-text';
|
|
3
|
+
import { Popover } from '../popover';
|
|
4
|
+
import { isSelectGroup } from '../select';
|
|
5
|
+
import ToolbarDivider from './cmp.toolbar-divider.svelte';
|
|
6
|
+
import ToolbarOption from './cmp.toolbar-option.svelte';
|
|
7
|
+
import { ToolbarFilterSelectLocalization } from './toolbar-filter-select-localization';
|
|
8
|
+
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
|
|
9
|
+
const { label, options, value, icon, header, footer, size = 'sm', trigger, borderless = false, optionSize = 'md', single = false, position = 'bottom-start', compare, on } = $props();
|
|
10
|
+
const localization = new ToolbarFilterSelectLocalization();
|
|
11
|
+
const eq = (a, b) => (compare ? compare(a, b) : a === b);
|
|
12
|
+
const isSelected = (candidate) => value.some((selected) => eq(selected, candidate));
|
|
13
|
+
const withValue = (list, candidate) => (list.some((item) => eq(item, candidate)) ? list : [...list, candidate]);
|
|
14
|
+
const without = (list, candidate) => list.filter((item) => !eq(item, candidate));
|
|
15
|
+
const optionDisplay = $derived(single ? 'checkmark' : 'checkbox');
|
|
16
|
+
const leaves = $derived(options.flatMap((item) => (isSelectGroup(item) ? item.options : [item])));
|
|
17
|
+
const selectedLeaves = $derived(leaves.filter((leaf) => isSelected(leaf.value)));
|
|
18
|
+
const summary = $derived.by(() => {
|
|
19
|
+
if (selectedLeaves.length === 0) {
|
|
20
|
+
return label;
|
|
21
|
+
}
|
|
22
|
+
if (selectedLeaves.length === 1) {
|
|
23
|
+
return `${label}: ${selectedLeaves[0].label}`;
|
|
24
|
+
}
|
|
25
|
+
return `${label}: ${localization.selectedCount(selectedLeaves.length)}`;
|
|
26
|
+
});
|
|
27
|
+
const groupSelected = (group) => {
|
|
28
|
+
const selectedCount = group.options.filter((option) => isSelected(option.value)).length;
|
|
29
|
+
if (selectedCount === 0) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return selectedCount === group.options.length ? true : 'indeterminate';
|
|
33
|
+
};
|
|
34
|
+
const emit = (next) => on?.change?.(next);
|
|
35
|
+
const pickSingle = (candidate) => emit(isSelected(candidate) ? [] : [candidate]);
|
|
36
|
+
const toggleOption = (option) => {
|
|
37
|
+
if (single) {
|
|
38
|
+
pickSingle(option.value);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
emit(isSelected(option.value) ? without(value, option.value) : withValue(value, option.value));
|
|
42
|
+
};
|
|
43
|
+
const toggleGroup = (group) => {
|
|
44
|
+
if (single) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const allSelected = group.options.every((option) => isSelected(option.value));
|
|
48
|
+
let next = value;
|
|
49
|
+
for (const option of group.options) {
|
|
50
|
+
next = allSelected ? without(next, option.value) : withValue(next, option.value);
|
|
51
|
+
}
|
|
52
|
+
if (group.value !== undefined) {
|
|
53
|
+
next = allSelected ? without(next, group.value) : withValue(next, group.value);
|
|
54
|
+
}
|
|
55
|
+
emit(next);
|
|
56
|
+
};
|
|
57
|
+
const toggleChild = (group, child) => {
|
|
58
|
+
if (single) {
|
|
59
|
+
pickSingle(child.value);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
let next = isSelected(child.value) ? without(value, child.value) : withValue(value, child.value);
|
|
63
|
+
if (group.value !== undefined) {
|
|
64
|
+
const anyChildSelected = group.options.some((option) => next.some((selected) => eq(selected, option.value)));
|
|
65
|
+
next = anyChildSelected ? withValue(next, group.value) : without(next, group.value);
|
|
66
|
+
}
|
|
67
|
+
emit(next);
|
|
68
|
+
};
|
|
69
|
+
const clearAll = () => emit([]);
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<div class="toolbar-filter-select">
|
|
73
|
+
<Popover position={position} keepOpen aria-label={trigger ? label : undefined} trigger={triggerContent}>
|
|
74
|
+
<div class="filter">
|
|
75
|
+
{#if header}
|
|
76
|
+
{@render header()}
|
|
77
|
+
{/if}
|
|
78
|
+
{#each options as item (isSelectGroup(item) ? item.label : item.value)}
|
|
79
|
+
{#if isSelectGroup(item)}
|
|
80
|
+
<ToolbarOption
|
|
81
|
+
size={optionSize}
|
|
82
|
+
variant="emphasis"
|
|
83
|
+
selectable={{ selected: groupSelected(item), display: optionDisplay }}
|
|
84
|
+
on={{ click: () => toggleGroup(item) }}>{item.label}</ToolbarOption>
|
|
85
|
+
{#each item.options as child (child.value)}
|
|
86
|
+
<ToolbarOption
|
|
87
|
+
size={optionSize}
|
|
88
|
+
indent
|
|
89
|
+
selectable={{ selected: isSelected(child.value), display: optionDisplay }}
|
|
90
|
+
on={{ click: () => toggleChild(item, child) }}>{child.label}</ToolbarOption>
|
|
91
|
+
{/each}
|
|
92
|
+
{:else}
|
|
93
|
+
<ToolbarOption size={optionSize} selectable={{ selected: isSelected(item.value), display: optionDisplay }} on={{ click: () => toggleOption(item) }}
|
|
94
|
+
>{item.label}</ToolbarOption>
|
|
95
|
+
{/if}
|
|
96
|
+
{/each}
|
|
97
|
+
{#if footer}
|
|
98
|
+
{@render footer()}
|
|
99
|
+
{:else if footer !== false && value.length > 0}
|
|
100
|
+
<ToolbarDivider />
|
|
101
|
+
<ToolbarOption size={optionSize} variant="muted" on={{ click: clearAll }}>{single ? localization.clear : localization.clearAll}</ToolbarOption>
|
|
102
|
+
{/if}
|
|
103
|
+
</div>
|
|
104
|
+
</Popover>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{#snippet triggerContent()}
|
|
108
|
+
{#if trigger}
|
|
109
|
+
{@render trigger()}
|
|
110
|
+
{:else}
|
|
111
|
+
<Button type="presentational" variant={borderless ? 'ghost' : 'secondary'} size={size}>
|
|
112
|
+
<IconText icon={icon} secondaryIcon={IconChevronDown} size={size} iconScale="large" trimText>{summary}</IconText>
|
|
113
|
+
</Button>
|
|
114
|
+
{/if}
|
|
115
|
+
{/snippet}
|
|
116
|
+
|
|
117
|
+
<!--
|
|
118
|
+
@component
|
|
119
|
+
A compact toolbar filter dropdown: a secondary-button trigger whose label summarises the selection
|
|
120
|
+
(`Status` → `Status: Draft` → `Status: 2 selected`), and a `ToolbarOption` checklist panel with a
|
|
121
|
+
`Clear all` footer. Multi-select by default; `single` restricts to one (checkmark glyph). `options` is a
|
|
122
|
+
flat `SelectOption[]` or one level of groups (`SelectOptionGroup`) for a tree with a tri-state parent
|
|
123
|
+
row and `children-include-parent` cascade.
|
|
124
|
+
`header` injects content above the list (preset rows, a `ToolbarSectionTitle`, …).
|
|
125
|
+
|
|
126
|
+
### CSS Custom Properties
|
|
127
|
+
| Property | Description | Default |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `--sc-kit--toolbar-filter-select--trigger--max-width` | Trigger max width before the label truncates | `13.75rem` (220px) |
|
|
130
|
+
-->
|
|
131
|
+
|
|
132
|
+
<style>.toolbar-filter-select {
|
|
133
|
+
display: contents;
|
|
134
|
+
--sc-kit--popover--content--padding: var(--sc-kit--space--2);
|
|
135
|
+
--sc-kit--button--max-width: var(--sc-kit--toolbar-filter-select--trigger--max-width, 13.75rem);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.filter {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
gap: 0.125rem;
|
|
142
|
+
min-inline-size: 12.5rem;
|
|
143
|
+
}</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { IconProp } from '../icon';
|
|
2
|
+
import { type SelectItem } from '../select';
|
|
3
|
+
import type { Placement } from '@floating-ui/dom';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
declare function $$render<T>(): {
|
|
6
|
+
props: {
|
|
7
|
+
label: string;
|
|
8
|
+
options: SelectItem<T>[];
|
|
9
|
+
value: T[];
|
|
10
|
+
/** Leading icon on the trigger button. */
|
|
11
|
+
icon?: IconProp;
|
|
12
|
+
/** Content rendered above the options list (e.g. preset rows + a `ToolbarSectionTitle`). */
|
|
13
|
+
header?: Snippet;
|
|
14
|
+
/** Trigger button density. @default 'sm' */
|
|
15
|
+
size?: "sm" | "md";
|
|
16
|
+
/** Custom presentational trigger content — replaces the default summary button. The popover is named by `label` (so an icon-only trigger stays accessible). */
|
|
17
|
+
trigger?: Snippet;
|
|
18
|
+
/** Render the default summary trigger as a borderless (ghost) button instead of secondary. @default false */
|
|
19
|
+
borderless?: boolean;
|
|
20
|
+
/** Option row density. @default 'md' */
|
|
21
|
+
optionSize?: "sm" | "md";
|
|
22
|
+
/** Restrict the selection to a single item — picking one replaces the previous (single-select). @default false */
|
|
23
|
+
single?: boolean;
|
|
24
|
+
/** Footer below the options: a snippet replaces the default `Clear all`; `false` removes it entirely. The default `Clear all` shows only while something is selected. A divider is drawn only when a footer renders. */
|
|
25
|
+
footer?: Snippet | false;
|
|
26
|
+
/** @default 'bottom-start' */
|
|
27
|
+
position?: Placement;
|
|
28
|
+
/** Equality comparator for `T`. Required when `T` is an object. @default (a, b) => a === b */
|
|
29
|
+
compare?: (a: T, b: T) => boolean;
|
|
30
|
+
on?: {
|
|
31
|
+
change?: (value: T[]) => void;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
exports: {};
|
|
35
|
+
bindings: "";
|
|
36
|
+
slots: {};
|
|
37
|
+
events: {};
|
|
38
|
+
};
|
|
39
|
+
declare class __sveltets_Render<T> {
|
|
40
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
41
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
42
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
43
|
+
bindings(): "";
|
|
44
|
+
exports(): {};
|
|
45
|
+
}
|
|
46
|
+
interface $$IsomorphicComponent {
|
|
47
|
+
new <T>(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']>> & {
|
|
48
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
49
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
50
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
51
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A compact toolbar filter dropdown: a secondary-button trigger whose label summarises the selection
|
|
55
|
+
* (`Status` → `Status: Draft` → `Status: 2 selected`), and a `ToolbarOption` checklist panel with a
|
|
56
|
+
* `Clear all` footer. Multi-select by default; `single` restricts to one (checkmark glyph). `options` is a
|
|
57
|
+
* flat `SelectOption[]` or one level of groups (`SelectOptionGroup`) for a tree with a tri-state parent
|
|
58
|
+
* row and `children-include-parent` cascade.
|
|
59
|
+
* `header` injects content above the list (preset rows, a `ToolbarSectionTitle`, …).
|
|
60
|
+
*
|
|
61
|
+
* ### CSS Custom Properties
|
|
62
|
+
* | Property | Description | Default |
|
|
63
|
+
* |---|---|---|
|
|
64
|
+
* | `--sc-kit--toolbar-filter-select--trigger--max-width` | Trigger max width before the label truncates | `13.75rem` (220px) |
|
|
65
|
+
*/
|
|
66
|
+
declare const Cmp: $$IsomorphicComponent;
|
|
67
|
+
type Cmp<T> = InstanceType<typeof Cmp<T>>;
|
|
68
|
+
export default Cmp;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">import { Icon } from '../icon';
|
|
2
|
+
const { icon, 'aria-label': ariaLabel, size = 'sm', active = false, disabled = false, presentational = false, on } = $props();
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
{#if presentational}
|
|
6
|
+
<span class="toolbar-icon-button toolbar-icon-button--{size}" class:toolbar-icon-button--active={active}>
|
|
7
|
+
<Icon src={icon} size="md" />
|
|
8
|
+
</span>
|
|
9
|
+
{:else}
|
|
10
|
+
<button
|
|
11
|
+
type="button"
|
|
12
|
+
class="toolbar-icon-button toolbar-icon-button--{size}"
|
|
13
|
+
class:toolbar-icon-button--active={active}
|
|
14
|
+
disabled={disabled}
|
|
15
|
+
aria-label={ariaLabel}
|
|
16
|
+
aria-pressed={active}
|
|
17
|
+
onclick={() => on?.click?.()}>
|
|
18
|
+
<Icon src={icon} size="md" />
|
|
19
|
+
</button>
|
|
20
|
+
{/if}
|
|
21
|
+
|
|
22
|
+
<!--
|
|
23
|
+
@component
|
|
24
|
+
A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 20px glyph). Background appears on
|
|
25
|
+
hover only; `active` tints the glyph with the accent color (no background). Pass `presentational` to render
|
|
26
|
+
a non-interactive `<span>` for use inside a wrapper that owns the click + semantics (e.g. a Popover trigger).
|
|
27
|
+
Shared by `ToolbarViewControls` and the `ToolbarFilterSelect` icon trigger so they stay visually identical.
|
|
28
|
+
|
|
29
|
+
### CSS Custom Properties
|
|
30
|
+
| Property | Description | Default |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `--sc-kit--toolbar-icon-button--color` | Idle glyph color | `var(--sc-kit--color--text--muted)` |
|
|
33
|
+
| `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--accent)` |
|
|
34
|
+
| `--sc-kit--toolbar-icon-button--background--hover` | Hover background | `var(--sc-kit--color--bg--hover)` |
|
|
35
|
+
-->
|
|
36
|
+
|
|
37
|
+
<style>.toolbar-icon-button {
|
|
38
|
+
--_tib--color: var(--sc-kit--toolbar-icon-button--color, var(--sc-kit--color--text--muted));
|
|
39
|
+
--_tib--color-active: var(--sc-kit--toolbar-icon-button--color--active, var(--sc-kit--color--accent));
|
|
40
|
+
--_tib--background-hover: var(--sc-kit--toolbar-icon-button--background--hover, var(--sc-kit--color--bg--hover));
|
|
41
|
+
--_tib--size: var(--_tib--size-height);
|
|
42
|
+
--sc-kit--icon--color: var(--_tib--color);
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
inline-size: var(--_tib--size);
|
|
48
|
+
block-size: var(--_tib--size);
|
|
49
|
+
padding: 0;
|
|
50
|
+
border: 0;
|
|
51
|
+
background: transparent;
|
|
52
|
+
border-radius: var(--sc-kit--field--border-radius--sm);
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
transition: background-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), color var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
55
|
+
}
|
|
56
|
+
.toolbar-icon-button--sm {
|
|
57
|
+
--_tib--size-height: var(--sc-kit--field--height--sm);
|
|
58
|
+
}
|
|
59
|
+
.toolbar-icon-button--md {
|
|
60
|
+
--_tib--size-height: var(--sc-kit--field--height--md);
|
|
61
|
+
}
|
|
62
|
+
.toolbar-icon-button:hover {
|
|
63
|
+
background: var(--_tib--background-hover);
|
|
64
|
+
}
|
|
65
|
+
.toolbar-icon-button--active {
|
|
66
|
+
--sc-kit--icon--color: var(--_tib--color-active);
|
|
67
|
+
}
|
|
68
|
+
.toolbar-icon-button:disabled {
|
|
69
|
+
cursor: default;
|
|
70
|
+
opacity: 0.5;
|
|
71
|
+
}</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
/** Glyph — a string SVG source. */
|
|
3
|
+
icon: string;
|
|
4
|
+
/** Accessible name. Required for the interactive button; omit for `presentational` (the wrapper owns the name). */
|
|
5
|
+
'aria-label'?: string;
|
|
6
|
+
/** Button size — sm = 28px, md = 32px. @default 'sm' */
|
|
7
|
+
size?: 'sm' | 'md';
|
|
8
|
+
/** Selected state — tints the glyph with the accent color (no background). */
|
|
9
|
+
active?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Render a non-interactive `<span>` for embedding inside another interactive wrapper (e.g. a Popover trigger). @default false */
|
|
12
|
+
presentational?: boolean;
|
|
13
|
+
on?: {
|
|
14
|
+
click?: () => void;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* A flat, square toolbar icon button (28px at `sm`, 32px at `md`, with a 20px glyph). Background appears on
|
|
19
|
+
* hover only; `active` tints the glyph with the accent color (no background). Pass `presentational` to render
|
|
20
|
+
* a non-interactive `<span>` for use inside a wrapper that owns the click + semantics (e.g. a Popover trigger).
|
|
21
|
+
* Shared by `ToolbarViewControls` and the `ToolbarFilterSelect` icon trigger so they stay visually identical.
|
|
22
|
+
*
|
|
23
|
+
* ### CSS Custom Properties
|
|
24
|
+
* | Property | Description | Default |
|
|
25
|
+
* |---|---|---|
|
|
26
|
+
* | `--sc-kit--toolbar-icon-button--color` | Idle glyph color | `var(--sc-kit--color--text--muted)` |
|
|
27
|
+
* | `--sc-kit--toolbar-icon-button--color--active` | Active glyph color | `var(--sc-kit--color--accent)` |
|
|
28
|
+
* | `--sc-kit--toolbar-icon-button--background--hover` | Hover background | `var(--sc-kit--color--bg--hover)` |
|
|
29
|
+
*/
|
|
30
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
31
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
32
|
+
export default Cmp;
|