@streamscloud/kit 0.14.0 → 0.15.1
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/image/cmp.image-stub.svelte +2 -4
- package/dist/ui/image/cmp.image-stub.svelte.d.ts +1 -1
- package/dist/ui/input/cmp.input.svelte +4 -2
- package/dist/ui/input/cmp.input.svelte.d.ts +2 -1
- package/dist/ui/input/index.d.ts +6 -0
- package/dist/ui/input/types.d.ts +1 -0
- package/dist/ui/page-toolbar/cmp.toolbar-search-input.svelte +26 -3
- package/dist/ui/page-toolbar/cmp.toolbar-search-input.svelte.d.ts +6 -1
- package/dist/ui/select/cmp.multiselect-tree.svelte +2 -3
- package/dist/ui/select/cmp.multiselect-tree.svelte.d.ts +2 -2
- package/dist/ui/select/multiselect-base.svelte +2 -2
- package/dist/ui/select/types.d.ts +4 -4
- package/package.json +1 -1
|
@@ -13,11 +13,11 @@ A placeholder image stub showing a generic image icon, used as a fallback when n
|
|
|
13
13
|
### CSS Custom Properties
|
|
14
14
|
| Property | Description | Default |
|
|
15
15
|
|---|---|---|
|
|
16
|
-
| `--sc-kit--image-stub--color` | Icon
|
|
16
|
+
| `--sc-kit--image-stub--color` | Icon color | `var(--sc-kit--color--text--on-accent)` |
|
|
17
17
|
-->
|
|
18
18
|
|
|
19
19
|
<style>.image-stub {
|
|
20
|
-
--_image-stub--color: var(--sc-kit--image-stub--color, var(--sc-kit--color--
|
|
20
|
+
--_image-stub--color: var(--sc-kit--image-stub--color, var(--sc-kit--color--text--on-accent));
|
|
21
21
|
width: 100%;
|
|
22
22
|
height: 100%;
|
|
23
23
|
z-index: 2;
|
|
@@ -25,6 +25,4 @@ A placeholder image stub showing a generic image icon, used as a fallback when n
|
|
|
25
25
|
justify-content: center;
|
|
26
26
|
align-items: center;
|
|
27
27
|
color: var(--_image-stub--color);
|
|
28
|
-
border: 1px solid var(--_image-stub--color);
|
|
29
|
-
border-radius: 0.25rem;
|
|
30
28
|
}</style>
|
|
@@ -17,7 +17,7 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
17
17
|
* ### CSS Custom Properties
|
|
18
18
|
* | Property | Description | Default |
|
|
19
19
|
* |---|---|---|
|
|
20
|
-
* | `--sc-kit--image-stub--color` | Icon
|
|
20
|
+
* | `--sc-kit--image-stub--color` | Icon color | `var(--sc-kit--color--text--on-accent)` |
|
|
21
21
|
*/
|
|
22
22
|
declare const Cmp: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
23
23
|
[evt: string]: CustomEvent<any>;
|
|
@@ -41,6 +41,7 @@ const handleClear = () => {
|
|
|
41
41
|
handleChange();
|
|
42
42
|
inputEl.focus();
|
|
43
43
|
};
|
|
44
|
+
export const clear = () => handleClear();
|
|
44
45
|
const handlePasswordToggle = () => {
|
|
45
46
|
passwordRevealed = !passwordRevealed;
|
|
46
47
|
inputEl?.focus();
|
|
@@ -109,7 +110,8 @@ const focusInput = () => inputEl?.focus();
|
|
|
109
110
|
oninput={handleInput}
|
|
110
111
|
onchange={handleChange}
|
|
111
112
|
onblur={handleBlur}
|
|
112
|
-
onfocus={() => on?.focus?.()}
|
|
113
|
+
onfocus={() => on?.focus?.()}
|
|
114
|
+
onkeydown={(event) => on?.keydown?.(event)} />
|
|
113
115
|
|
|
114
116
|
{#if suffix}
|
|
115
117
|
<span class="input__suffix">{@render suffix()}</span>
|
|
@@ -141,7 +143,7 @@ Text input field with leading/trailing icon slots, clear button, emoji picker, a
|
|
|
141
143
|
focus underline. Discriminated `type` selects native input mode (`text` / `password` / `email` /
|
|
142
144
|
`search` / `url` / `tel`). Set `inert` for display mode (no focus, no animations), `readonly`
|
|
143
145
|
for non-editable but selectable, `error` for the visual + a11y error state. Imperative
|
|
144
|
-
`focus()` / `select()` exposed via `bind:this`.
|
|
146
|
+
`focus()` / `select()` / `clear()` exposed via `bind:this`.
|
|
145
147
|
|
|
146
148
|
Two snippet slots widen the chrome: `prefix` for a full-height segmented leading addon (see
|
|
147
149
|
`WebsiteInput`), and `suffix` for a free-form trailing addon rendered before any trailing icons
|
|
@@ -4,7 +4,7 @@ import type { InputProps } from './types';
|
|
|
4
4
|
* focus underline. Discriminated `type` selects native input mode (`text` / `password` / `email` /
|
|
5
5
|
* `search` / `url` / `tel`). Set `inert` for display mode (no focus, no animations), `readonly`
|
|
6
6
|
* for non-editable but selectable, `error` for the visual + a11y error state. Imperative
|
|
7
|
-
* `focus()` / `select()` exposed via `bind:this`.
|
|
7
|
+
* `focus()` / `select()` / `clear()` exposed via `bind:this`.
|
|
8
8
|
*
|
|
9
9
|
* Two snippet slots widen the chrome: `prefix` for a full-height segmented leading addon (see
|
|
10
10
|
* `WebsiteInput`), and `suffix` for a free-form trailing addon rendered before any trailing icons
|
|
@@ -33,6 +33,7 @@ import type { InputProps } from './types';
|
|
|
33
33
|
declare const Cmp: import("svelte").Component<InputProps, {
|
|
34
34
|
/** Imperative API exposed via `bind:this` on `<Input>`. */ focus: () => void;
|
|
35
35
|
select: () => void;
|
|
36
|
+
clear: () => void;
|
|
36
37
|
}, "">;
|
|
37
38
|
type Cmp = ReturnType<typeof Cmp>;
|
|
38
39
|
export default Cmp;
|
package/dist/ui/input/index.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export { default as Input } from './cmp.input.svelte';
|
|
2
2
|
export type { InputForwardedProps, InputProps, InputSize, InputType } from './types';
|
|
3
|
+
/** Imperative API exposed via `bind:this={instance}` on `<Input>`. */
|
|
4
|
+
export type InputInstance = {
|
|
5
|
+
focus: () => void;
|
|
6
|
+
select: () => void;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
};
|
package/dist/ui/input/types.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { CONTROL_ICON_SIZE, scaleUp } from '../icon';
|
|
3
3
|
import { Input } from '../input';
|
|
4
4
|
import IconSearch from '@fluentui/svg-icons/icons/search_20_regular.svg?raw';
|
|
5
|
-
const { value, collapsedIconColor, collapsedIconSize, placeholder = '', size = 'sm', debounce = 0, on } = $props();
|
|
5
|
+
const { value, collapsedIconColor, collapsedIconSize, placeholder = '', size = 'sm', debounce = 0, shortcut = false, clearOnEscape = false, on } = $props();
|
|
6
|
+
let inputRef = $state.raw(undefined);
|
|
6
7
|
let focused = $state(false);
|
|
7
8
|
const expanded = $derived(focused || !!value);
|
|
8
9
|
const collapsedSize = $derived(collapsedIconSize ?? scaleUp(CONTROL_ICON_SIZE[size]));
|
|
@@ -10,24 +11,46 @@ const onInput = (v) => {
|
|
|
10
11
|
on?.input?.(v);
|
|
11
12
|
};
|
|
12
13
|
const onInputDebounced = $derived(debounce > 0 ? Utils.debounce(onInput, debounce) : onInput);
|
|
14
|
+
$effect(() => {
|
|
15
|
+
if (!shortcut) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const onShortcut = (event) => {
|
|
19
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
inputRef?.focus();
|
|
22
|
+
inputRef?.select();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
document.addEventListener('keydown', onShortcut);
|
|
26
|
+
return () => document.removeEventListener('keydown', onShortcut);
|
|
27
|
+
});
|
|
28
|
+
const handleKeydown = (event) => {
|
|
29
|
+
if (clearOnEscape && event.key === 'Escape' && !!value) {
|
|
30
|
+
event.stopPropagation();
|
|
31
|
+
inputRef?.clear();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
13
34
|
</script>
|
|
14
35
|
|
|
15
36
|
<div class="toolbar-search-input toolbar-search-input--{size}" class:toolbar-search-input--expanded={expanded}>
|
|
16
37
|
<Input
|
|
38
|
+
bind:this={inputRef}
|
|
17
39
|
value={value}
|
|
18
40
|
size={size}
|
|
19
41
|
placeholder={placeholder}
|
|
20
42
|
icon={{ src: IconSearch, color: expanded ? undefined : (collapsedIconColor ?? 'accent'), size: expanded ? undefined : collapsedSize }}
|
|
21
43
|
clearable
|
|
22
44
|
borderless={!expanded}
|
|
23
|
-
on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false) }} />
|
|
45
|
+
on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false), keydown: handleKeydown }} />
|
|
24
46
|
</div>
|
|
25
47
|
|
|
26
48
|
<!--
|
|
27
49
|
@component
|
|
28
50
|
A collapsible search input for toolbars. Collapsed to an icon-only square at the chosen field height
|
|
29
51
|
when empty + unfocused; expands to the full input width when focused or when a value is present.
|
|
30
|
-
Shares Input's size preset so it lines up with other field-shaped controls.
|
|
52
|
+
Shares Input's size preset so it lines up with other field-shaped controls. Opt into `shortcut`
|
|
53
|
+
for a document-wide Cmd/Ctrl+K focus-and-select, and `clearOnEscape` to clear on Escape.
|
|
31
54
|
|
|
32
55
|
### CSS Custom Properties
|
|
33
56
|
| Property | Description | Default |
|
|
@@ -9,6 +9,10 @@ type Props = {
|
|
|
9
9
|
size?: 'sm' | 'md' | 'lg';
|
|
10
10
|
/** Debounce delay in ms @default 0 */
|
|
11
11
|
debounce?: number;
|
|
12
|
+
/** Bind Cmd/Ctrl+K document-wide to focus the input and select its text. Enable on a single instance per view. @default false */
|
|
13
|
+
shortcut?: boolean;
|
|
14
|
+
/** Clear the value on Escape while focused (swallowing the keystroke); an already-empty input lets Escape bubble. @default false */
|
|
15
|
+
clearOnEscape?: boolean;
|
|
12
16
|
on?: {
|
|
13
17
|
input?: (value: string) => void;
|
|
14
18
|
};
|
|
@@ -16,7 +20,8 @@ type Props = {
|
|
|
16
20
|
/**
|
|
17
21
|
* A collapsible search input for toolbars. Collapsed to an icon-only square at the chosen field height
|
|
18
22
|
* when empty + unfocused; expands to the full input width when focused or when a value is present.
|
|
19
|
-
* Shares Input's size preset so it lines up with other field-shaped controls.
|
|
23
|
+
* Shares Input's size preset so it lines up with other field-shaped controls. Opt into `shortcut`
|
|
24
|
+
* for a document-wide Cmd/Ctrl+K focus-and-select, and `clearOnEscape` to clear on Escape.
|
|
20
25
|
*
|
|
21
26
|
* ### CSS Custom Properties
|
|
22
27
|
* | Property | Description | Default |
|
|
@@ -7,9 +7,8 @@ import { isSelectGroup } from './types';
|
|
|
7
7
|
const { options, value, compare = defaultCompare, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = false, groupHeader = 'toggle-all', selectionMode = 'children-only', selectedDisplay = 'checkbox', canCreate, icon, chevronIcon, optionSnippet, selectionSnippet, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, on } = $props();
|
|
8
8
|
const fuse = $derived(buildFuseIndex(options));
|
|
9
9
|
const loadOptionsShim = (q) => Promise.resolve(runFuseSearch(fuse, q, options));
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
const parentSource = $derived(options.filter(isSelectGroup).reduce((acc, g) => (g.value !== undefined ? [...acc, { label: g.label, value: g.value }] : acc), []));
|
|
10
|
+
// Include flat roots, not only groups — else a childless root can't be picked as a create-parent.
|
|
11
|
+
const parentSource = $derived(options.flatMap((item) => (item.value !== undefined ? [{ label: item.label, value: item.value }] : [])));
|
|
13
12
|
const resolvedValue = $derived.by(() => {
|
|
14
13
|
const out = [];
|
|
15
14
|
for (const v of value) {
|
|
@@ -57,7 +57,7 @@ declare function $$render<T>(): {
|
|
|
57
57
|
selectedDisplay?: "checkmark" | "checkbox" | "highlight";
|
|
58
58
|
/** Equality comparator for `T`. Required when `T` is an object. @default (a, b) => a === b */
|
|
59
59
|
compare?: (a: T, b: T) => boolean;
|
|
60
|
-
/** Enables creatable mode. The predicate validates each query. When
|
|
60
|
+
/** Enables creatable mode. The predicate validates each query. When at least one top-level root has a `value`, the "Create …" UI expands into a section whose parent picker offers those roots (group or flat); otherwise a plain "Create …" row is shown. */
|
|
61
61
|
canCreate?: (query: string) => boolean;
|
|
62
62
|
/** Leading icon — string SVG source, `{ src, color?, size? }` object, or custom snippet. */
|
|
63
63
|
icon?: IconProp;
|
|
@@ -80,7 +80,7 @@ declare function $$render<T>(): {
|
|
|
80
80
|
on?: {
|
|
81
81
|
/** Fires when the user picks/unpicks (and on group toggle-all). Emits the full new selection (array of values). */
|
|
82
82
|
change?: (value: T[]) => void;
|
|
83
|
-
/** Fires when the user confirms the create-with-parent section. `parentValue` is the
|
|
83
|
+
/** Fires when the user confirms the create-with-parent section. `parentValue` is the chosen parent root's `value` from the parent dropdown — undefined when no parent was selected. Return a Promise to keep the spinner up. */
|
|
84
84
|
create?: (payload: {
|
|
85
85
|
query: string;
|
|
86
86
|
parentValue?: T;
|
|
@@ -103,8 +103,8 @@ const isExternalChips = $derived(chipMode === 'external');
|
|
|
103
103
|
const inlineVisible = $derived(isExternalChips || selectionSnippet ? [] : value.slice(0, maxVisible));
|
|
104
104
|
const inlineOverflow = $derived(isExternalChips || selectionSnippet ? 0 : Math.max(0, value.length - maxVisible));
|
|
105
105
|
// Create-with-parent section: shown when canCreate is gated true by core AND the proxy
|
|
106
|
-
// passed a non-empty `parentSource`. The source is the FULL unfiltered
|
|
107
|
-
// parent picker is stable regardless of which
|
|
106
|
+
// passed a non-empty `parentSource`. The source is the FULL unfiltered parent-candidate list
|
|
107
|
+
// so the parent picker is stable regardless of which roots currently survive the listbox filter.
|
|
108
108
|
const parentSourceList = $derived(parentSource ?? []);
|
|
109
109
|
const showCreateSection = $derived(core.canShowCreate && parentSourceList.length > 0);
|
|
110
110
|
let selectedParent = $state.raw(null);
|
|
@@ -156,7 +156,7 @@ export type MultiselectBaseProps<T> = {
|
|
|
156
156
|
* @default 'checkmark'
|
|
157
157
|
*/
|
|
158
158
|
selectedDisplay?: 'checkmark' | 'checkbox' | 'highlight';
|
|
159
|
-
/** Enables creatable mode. The predicate validates each query — only when it returns true does the create UI appear. When
|
|
159
|
+
/** Enables creatable mode. The predicate validates each query — only when it returns true does the create UI appear. When `parentSource` is non-empty, a create-with-parent section replaces the simple "Create …" row. */
|
|
160
160
|
canCreate?: (query: string) => boolean;
|
|
161
161
|
/** Where chips render. `'external'` puts them in a row above the trigger and unlocks `reorderable`. @default 'inline' */
|
|
162
162
|
chipMode?: 'inline' | 'external';
|
|
@@ -190,8 +190,8 @@ export type MultiselectBaseProps<T> = {
|
|
|
190
190
|
}]>;
|
|
191
191
|
/**
|
|
192
192
|
* Enables the create-with-parent section (shown above the listbox when `canCreate` gates true).
|
|
193
|
-
* Receives the FULL
|
|
194
|
-
*
|
|
193
|
+
* Receives the FULL parent-candidate list independent of current filter — so the parent picker offers
|
|
194
|
+
* every candidate regardless of what's currently visible in the listbox. When undefined or empty, a
|
|
195
195
|
* single "Create …" row is shown instead.
|
|
196
196
|
*/
|
|
197
197
|
parentSource?: SelectOption<T>[];
|
|
@@ -204,7 +204,7 @@ export type MultiselectBaseProps<T> = {
|
|
|
204
204
|
on?: {
|
|
205
205
|
/** Fires when the user picks/unpicks/reorders. Emits the full new selection. */
|
|
206
206
|
change?: (value: SelectOption<T>[]) => void;
|
|
207
|
-
/** Fires when the user activates "Create …". When `parentValue` is present, the user picked it via the create-with-parent section
|
|
207
|
+
/** Fires when the user activates "Create …". When `parentValue` is present, the user picked it via the create-with-parent section. Return a Promise to keep the spinner up until the consumer finishes. */
|
|
208
208
|
create?: (payload: {
|
|
209
209
|
query: string;
|
|
210
210
|
parentValue?: T;
|