@streamscloud/kit 0.9.18 → 0.10.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 +13 -5
- package/dist/ui/badge/cmp.badge.svelte.d.ts +2 -0
- package/dist/ui/button/cmp.button.svelte +2 -2
- package/dist/ui/button/cmp.button.svelte.d.ts +1 -1
- package/dist/ui/select/_select-trigger.scss +6 -1
- package/dist/ui/select/cmp.multiselect-async.svelte.d.ts +1 -1
- package/dist/ui/select/cmp.multiselect-tree.svelte +2 -1
- package/dist/ui/select/cmp.multiselect-tree.svelte.d.ts +2 -0
- package/dist/ui/select/cmp.singleselect-async.svelte +8 -2
- package/dist/ui/select/cmp.singleselect-async.svelte.d.ts +4 -0
- package/dist/ui/select/cmp.singleselect.svelte +6 -3
- package/dist/ui/select/cmp.singleselect.svelte.d.ts +7 -2
- package/dist/ui/select/multiselect-base.svelte +8 -2
- package/dist/ui/select/select-core.svelte.d.ts +2 -0
- package/dist/ui/select/select-core.svelte.js +3 -3
- package/dist/ui/select/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<script lang="ts">const { variant = 'neutral', size = 'md', style = 'soft', children } = $props();
|
|
1
|
+
<script lang="ts">const { variant = 'neutral', size = 'md', style = 'soft', fullWidth = false, children } = $props();
|
|
2
2
|
export {};
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
|
-
<span class="badge badge--{size} badge--{variant}-{style}">
|
|
6
|
-
{@render children()}
|
|
5
|
+
<span class="badge badge--{size} badge--{variant}-{style}" class:badge--full={fullWidth}>
|
|
6
|
+
<span class="badge__content">{@render children()}</span>
|
|
7
7
|
</span>
|
|
8
8
|
|
|
9
9
|
<!--
|
|
@@ -39,10 +39,18 @@ Pill-shaped status indicator. Use `solid` for stronger emphasis, `soft` (default
|
|
|
39
39
|
font-size: var(--_badge--font-size);
|
|
40
40
|
font-weight: var(--_badge--font-weight);
|
|
41
41
|
line-height: 1.4;
|
|
42
|
-
|
|
42
|
+
max-width: 100%;
|
|
43
|
+
}
|
|
44
|
+
.badge__content {
|
|
45
|
+
min-width: 0;
|
|
43
46
|
overflow: hidden;
|
|
44
47
|
text-overflow: ellipsis;
|
|
45
|
-
|
|
48
|
+
white-space: nowrap;
|
|
49
|
+
}
|
|
50
|
+
.badge--full {
|
|
51
|
+
display: flex;
|
|
52
|
+
width: 100%;
|
|
53
|
+
justify-content: center;
|
|
46
54
|
}
|
|
47
55
|
.badge--sm {
|
|
48
56
|
--_badge--padding-block: var(--sc-kit--badge--padding-block, 0.25rem);
|
|
@@ -7,6 +7,8 @@ type Props = {
|
|
|
7
7
|
size?: 'sm' | 'md';
|
|
8
8
|
/** Filled chip vs soft-tinted fill @default 'soft' */
|
|
9
9
|
style?: 'soft' | 'solid';
|
|
10
|
+
/** Stretch to fill the parent's inline axis, centering the content. @default false */
|
|
11
|
+
fullWidth?: boolean;
|
|
10
12
|
children: Snippet;
|
|
11
13
|
};
|
|
12
14
|
/**
|
|
@@ -104,7 +104,7 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
|
|
|
104
104
|
| `--sc-kit--button--font-size` | Label font size | per size |
|
|
105
105
|
| `--sc-kit--button--gap` | Gap between icon and label | per size |
|
|
106
106
|
| `--sc-kit--button--border-radius` | Corner rounding | `var(--sc-kit--radius--md)` |
|
|
107
|
-
| `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--
|
|
107
|
+
| `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--regular)` |
|
|
108
108
|
| `--sc-kit--button--width` | Explicit width | `fit-content` |
|
|
109
109
|
| `--sc-kit--button--min-width` | Minimum width | `0` |
|
|
110
110
|
| `--sc-kit--button--max-width` | Maximum width | `100%` |
|
|
@@ -126,7 +126,7 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
|
|
|
126
126
|
--_btn--min-width: var(--sc-kit--button--min-width, 0);
|
|
127
127
|
--_btn--max-width: var(--sc-kit--button--max-width, 100%);
|
|
128
128
|
--_btn--border-radius: var(--sc-kit--button--border-radius, var(--sc-kit--radius--md));
|
|
129
|
-
--_btn--font-weight: var(--sc-kit--button--font-weight, var(--sc-kit--font-weight--
|
|
129
|
+
--_btn--font-weight: var(--sc-kit--button--font-weight, var(--sc-kit--font-weight--regular));
|
|
130
130
|
box-sizing: border-box;
|
|
131
131
|
display: flex;
|
|
132
132
|
align-items: center;
|
|
@@ -62,7 +62,7 @@ type Props = ButtonModeProps | AnchorModeProps;
|
|
|
62
62
|
* | `--sc-kit--button--font-size` | Label font size | per size |
|
|
63
63
|
* | `--sc-kit--button--gap` | Gap between icon and label | per size |
|
|
64
64
|
* | `--sc-kit--button--border-radius` | Corner rounding | `var(--sc-kit--radius--md)` |
|
|
65
|
-
* | `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--
|
|
65
|
+
* | `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--regular)` |
|
|
66
66
|
* | `--sc-kit--button--width` | Explicit width | `fit-content` |
|
|
67
67
|
* | `--sc-kit--button--min-width` | Minimum width | `0` |
|
|
68
68
|
* | `--sc-kit--button--max-width` | Maximum width | `100%` |
|
|
@@ -130,10 +130,15 @@
|
|
|
130
130
|
width: 0;
|
|
131
131
|
flex: 0;
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
&--no-search {
|
|
135
|
+
caret-color: transparent;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
}
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
&__selection {
|
|
136
|
-
flex: 1;
|
|
141
|
+
flex: 0 1 auto;
|
|
137
142
|
min-width: 0;
|
|
138
143
|
@include mixins.ellipsis;
|
|
139
144
|
}
|
|
@@ -5,7 +5,7 @@ export type MultiselectAsyncInstance = {
|
|
|
5
5
|
};
|
|
6
6
|
import type { MultiselectBaseProps, SelectOption } from './types';
|
|
7
7
|
declare function $$render<T>(): {
|
|
8
|
-
props: Omit<MultiselectBaseProps<T>, "on" | "loadOptions" | "groupHeader" | "selectionMode" | "parentSource"> & {
|
|
8
|
+
props: Omit<MultiselectBaseProps<T>, "on" | "loadOptions" | "searchable" | "groupHeader" | "selectionMode" | "parentSource"> & {
|
|
9
9
|
/** Server-side fetcher. Invoked with an empty query on open (initial page) and again — debounced — on every keystroke. Expected to return a flat list (no groups). */
|
|
10
10
|
loadOptions: (query: string) => Promise<SelectOption<T>[]>;
|
|
11
11
|
on?: {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<script lang="ts" generics="T">import { default as MultiselectBase } from './multiselect-base.svelte';
|
|
5
5
|
import { buildFuseIndex, defaultCompare, runFuseSearch } from './select-internals';
|
|
6
6
|
import { isSelectGroup } from './types';
|
|
7
|
-
const { options, value, compare = defaultCompare, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = 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();
|
|
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
10
|
// Full unfiltered group list — fed to the create-with-parent section's parent picker so it
|
|
@@ -54,6 +54,7 @@ $effect(() => {
|
|
|
54
54
|
placeholder={placeholder}
|
|
55
55
|
disabled={disabled}
|
|
56
56
|
readonly={readonly}
|
|
57
|
+
searchable={searchable}
|
|
57
58
|
inert={inert}
|
|
58
59
|
error={error}
|
|
59
60
|
borderless={borderless}
|
|
@@ -31,6 +31,8 @@ declare function $$render<T>(): {
|
|
|
31
31
|
error?: boolean;
|
|
32
32
|
/** Removes the field border. @default false */
|
|
33
33
|
borderless?: boolean;
|
|
34
|
+
/** When true, typing filters the tree; when false, it is a click/keyboard-only picker. @default false */
|
|
35
|
+
searchable?: boolean;
|
|
34
36
|
/**
|
|
35
37
|
* Group-header behavior:
|
|
36
38
|
* - `'static'` — non-interactive label.
|
|
@@ -9,7 +9,7 @@ import { defaultCompare } from './select-internals';
|
|
|
9
9
|
import { default as SelectListbox } from './select-listbox.svelte';
|
|
10
10
|
import { SingleselectLocalization } from './singleselect-localization';
|
|
11
11
|
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_16_regular.svg?raw';
|
|
12
|
-
const { loadOptions, debounceMs = 400, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, groupHeader = 'static', compare = defaultCompare, canCreate, icon, chevronIcon, optionSnippet, selectionSnippet, listbox, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
12
|
+
const { loadOptions, debounceMs = 400, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = true, groupHeader = 'static', compare = defaultCompare, canCreate, icon, chevronIcon, optionSnippet, selectionSnippet, listbox, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
13
13
|
const localization = new SingleselectLocalization();
|
|
14
14
|
const selectedOption = $derived(mode.value ?? null);
|
|
15
15
|
const selectionLabel = $derived(selectedOption?.label ?? '');
|
|
@@ -22,6 +22,7 @@ const core = createSelectCore({
|
|
|
22
22
|
loadOptions: (q) => loadOptions(q),
|
|
23
23
|
getDebounceMs: () => debounceMs,
|
|
24
24
|
getCompare: () => compare,
|
|
25
|
+
getSearchable: () => searchable,
|
|
25
26
|
getCanCreate: () => canCreate,
|
|
26
27
|
getGroupHeader: () => groupHeader,
|
|
27
28
|
isPicked: (option) => selectedOption !== null && compare(option.value, selectedOption.value),
|
|
@@ -89,6 +90,7 @@ const showClear = $derived(mode.clearable && hasValue && isInteractive && !core.
|
|
|
89
90
|
bind:this={inputEl}
|
|
90
91
|
class="singleselect__input"
|
|
91
92
|
class:singleselect__input--hidden={selectionSnippet && selectedOption && !core.isOpen}
|
|
93
|
+
class:singleselect__input--no-search={!searchable}
|
|
92
94
|
type="text"
|
|
93
95
|
role="combobox"
|
|
94
96
|
aria-haspopup="listbox"
|
|
@@ -290,8 +292,12 @@ background--hover}`.
|
|
|
290
292
|
width: 0;
|
|
291
293
|
flex: 0;
|
|
292
294
|
}
|
|
295
|
+
.singleselect__input--no-search {
|
|
296
|
+
caret-color: transparent;
|
|
297
|
+
cursor: pointer;
|
|
298
|
+
}
|
|
293
299
|
.singleselect__selection {
|
|
294
|
-
flex: 1;
|
|
300
|
+
flex: 0 1 auto;
|
|
295
301
|
min-width: 0;
|
|
296
302
|
text-overflow: ellipsis;
|
|
297
303
|
max-width: 100%;
|
|
@@ -12,6 +12,8 @@ declare function $$render<T>(): {
|
|
|
12
12
|
loadOptions: (query: string) => Promise<SelectItem<T>[]>;
|
|
13
13
|
/** Debounce window for `loadOptions` while typing. @default 400 */
|
|
14
14
|
debounceMs?: number;
|
|
15
|
+
/** Internal — set by the sync `Singleselect` wrapper. Async typeahead is always searchable. @default true */
|
|
16
|
+
searchable?: boolean;
|
|
15
17
|
} & {
|
|
16
18
|
/** Discriminator — `true` enables the X clear button and allows `value` to be `null`. */
|
|
17
19
|
clearable: true;
|
|
@@ -28,6 +30,8 @@ declare function $$render<T>(): {
|
|
|
28
30
|
loadOptions: (query: string) => Promise<SelectItem<T>[]>;
|
|
29
31
|
/** Debounce window for `loadOptions` while typing. @default 400 */
|
|
30
32
|
debounceMs?: number;
|
|
33
|
+
/** Internal — set by the sync `Singleselect` wrapper. Async typeahead is always searchable. @default true */
|
|
34
|
+
searchable?: boolean;
|
|
31
35
|
} & {
|
|
32
36
|
/** Discriminator — `false` removes the X clear button; `value` must always be a non-null `SelectOption<T>`. */
|
|
33
37
|
clearable: false;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<script lang="ts" generics="T">import { default as SingleselectAsync } from './cmp.singleselect-async.svelte';
|
|
5
5
|
import { buildFuseIndex, defaultCompare, runFuseSearch } from './select-internals';
|
|
6
6
|
import { isSelectGroup } from './types';
|
|
7
|
-
const { options, compare = defaultCompare, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, groupHeader = 'static', canCreate, icon, chevronIcon, optionSnippet, selectionSnippet, listbox, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
7
|
+
const { options, compare = defaultCompare, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = true, groupHeader = 'static', canCreate, icon, chevronIcon, optionSnippet, selectionSnippet, listbox, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
8
8
|
const fuse = $derived(buildFuseIndex(options));
|
|
9
9
|
const loadOptionsShim = (q) => Promise.resolve(runFuseSearch(fuse, q, options));
|
|
10
10
|
const resolvedValue = $derived.by(() => {
|
|
@@ -52,6 +52,7 @@ $effect(() => {
|
|
|
52
52
|
inert={inert}
|
|
53
53
|
error={error}
|
|
54
54
|
borderless={borderless}
|
|
55
|
+
searchable={searchable}
|
|
55
56
|
groupHeader={groupHeader}
|
|
56
57
|
canCreate={canCreate}
|
|
57
58
|
icon={icon}
|
|
@@ -84,6 +85,7 @@ $effect(() => {
|
|
|
84
85
|
inert={inert}
|
|
85
86
|
error={error}
|
|
86
87
|
borderless={borderless}
|
|
88
|
+
searchable={searchable}
|
|
87
89
|
groupHeader={groupHeader}
|
|
88
90
|
canCreate={canCreate}
|
|
89
91
|
icon={icon}
|
|
@@ -105,8 +107,9 @@ $effect(() => {
|
|
|
105
107
|
|
|
106
108
|
<!--
|
|
107
109
|
@component
|
|
108
|
-
Singleselect —
|
|
109
|
-
open; typing filters via Fuse fuzzy match
|
|
110
|
+
Singleselect — single-value picker for static options. Searchable by default (click or type
|
|
111
|
+
to open; typing filters via Fuse fuzzy match); pass `searchable={false}` for a click/keyboard-only
|
|
112
|
+
picker with no filter input. Internally proxies to `SingleselectAsync` with a
|
|
110
113
|
synchronous `Promise.resolve` `loadOptions` shim — visual behavior, accessibility, 600ms
|
|
111
114
|
spinner gate and race-prevention are inherited verbatim. `clearable` is a required
|
|
112
115
|
discriminator: `true` allows `null` and shows the X clear button; `false` requires non-null `T`.
|
|
@@ -8,6 +8,8 @@ declare function $$render<T>(): {
|
|
|
8
8
|
props: (SingleselectCommonProps<T> & {
|
|
9
9
|
/** Static option list (or grouped). Fuse filters in-memory on every keystroke — no debounce. */
|
|
10
10
|
options: SelectItem<T>[];
|
|
11
|
+
/** When true, typing filters the options; when false, it is a click/keyboard-only picker. @default true */
|
|
12
|
+
searchable?: boolean;
|
|
11
13
|
} & {
|
|
12
14
|
/** Discriminator — `true` enables the X clear button and allows `value` to be `null`. */
|
|
13
15
|
clearable: true;
|
|
@@ -22,6 +24,8 @@ declare function $$render<T>(): {
|
|
|
22
24
|
}) | (SingleselectCommonProps<T> & {
|
|
23
25
|
/** Static option list (or grouped). Fuse filters in-memory on every keystroke — no debounce. */
|
|
24
26
|
options: SelectItem<T>[];
|
|
27
|
+
/** When true, typing filters the options; when false, it is a click/keyboard-only picker. @default true */
|
|
28
|
+
searchable?: boolean;
|
|
25
29
|
} & {
|
|
26
30
|
/** Discriminator — `false` hides the X button; `value` must always be a non-null `T`. */
|
|
27
31
|
clearable: false;
|
|
@@ -62,8 +66,9 @@ interface $$IsomorphicComponent {
|
|
|
62
66
|
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
63
67
|
}
|
|
64
68
|
/**
|
|
65
|
-
* Singleselect —
|
|
66
|
-
* open; typing filters via Fuse fuzzy match
|
|
69
|
+
* Singleselect — single-value picker for static options. Searchable by default (click or type
|
|
70
|
+
* to open; typing filters via Fuse fuzzy match); pass `searchable={false}` for a click/keyboard-only
|
|
71
|
+
* picker with no filter input. Internally proxies to `SingleselectAsync` with a
|
|
67
72
|
* synchronous `Promise.resolve` `loadOptions` shim — visual behavior, accessibility, 600ms
|
|
68
73
|
* spinner gate and race-prevention are inherited verbatim. `clearable` is a required
|
|
69
74
|
* discriminator: `true` allows `null` and shows the X clear button; `false` requires non-null `T`.
|
|
@@ -13,7 +13,7 @@ import { default as SelectListbox } from './select-listbox.svelte';
|
|
|
13
13
|
import IconCheckmark from '@fluentui/svg-icons/icons/checkmark_16_regular.svg?raw';
|
|
14
14
|
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_16_regular.svg?raw';
|
|
15
15
|
import { dndzone } from 'svelte-dnd-action';
|
|
16
|
-
const { loadOptions, debounceMs = 400, value, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, groupHeader = 'static', compare = defaultCompare, selectionMode = 'children-only', selectedDisplay = 'checkmark', canCreate, chipMode = 'inline', reorderable = false, maxVisible = Infinity, showFullItem = false, chipVariant, showChevron = true, hideSelected = false, icon, chevronIcon, optionSnippet, chipSnippet, selectionSnippet, parentSource, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, on } = $props();
|
|
16
|
+
const { loadOptions, debounceMs = 400, value, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = true, groupHeader = 'static', compare = defaultCompare, selectionMode = 'children-only', selectedDisplay = 'checkmark', canCreate, chipMode = 'inline', reorderable = false, maxVisible = Infinity, showFullItem = false, chipVariant, showChevron = true, hideSelected = false, icon, chevronIcon, optionSnippet, chipSnippet, selectionSnippet, parentSource, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, on } = $props();
|
|
17
17
|
const localization = new MultiselectLocalization();
|
|
18
18
|
const isPicked = (v) => value.some((existing) => compare(existing.value, v));
|
|
19
19
|
const hasValue = $derived(value.length > 0);
|
|
@@ -34,6 +34,7 @@ const core = createSelectCore({
|
|
|
34
34
|
loadOptions: (q) => loadOptions(q),
|
|
35
35
|
getDebounceMs: () => debounceMs,
|
|
36
36
|
getCompare: () => compare,
|
|
37
|
+
getSearchable: () => searchable,
|
|
37
38
|
getCanCreate: () => canCreate,
|
|
38
39
|
getHideCreateRow: () => showCreateSection,
|
|
39
40
|
getGroupHeader: () => groupHeader,
|
|
@@ -215,6 +216,7 @@ const handleDndFinalize = (e) => {
|
|
|
215
216
|
<input
|
|
216
217
|
bind:this={inputEl}
|
|
217
218
|
class="multiselect-trigger__input"
|
|
219
|
+
class:multiselect-trigger__input--no-search={!searchable}
|
|
218
220
|
type="text"
|
|
219
221
|
role="combobox"
|
|
220
222
|
aria-haspopup="listbox"
|
|
@@ -506,8 +508,12 @@ padding-inline, font-size, gap, max-width, remove-color, remove-color--hover}`.
|
|
|
506
508
|
width: 0;
|
|
507
509
|
flex: 0;
|
|
508
510
|
}
|
|
511
|
+
.multiselect-trigger__input--no-search {
|
|
512
|
+
caret-color: transparent;
|
|
513
|
+
cursor: pointer;
|
|
514
|
+
}
|
|
509
515
|
.multiselect-trigger__selection {
|
|
510
|
-
flex: 1;
|
|
516
|
+
flex: 0 1 auto;
|
|
511
517
|
min-width: 0;
|
|
512
518
|
text-overflow: ellipsis;
|
|
513
519
|
max-width: 100%;
|
|
@@ -11,6 +11,8 @@ export type SelectCoreConfig<T> = {
|
|
|
11
11
|
getDebounceMs?: () => number;
|
|
12
12
|
/** Equality comparator for `T`. */
|
|
13
13
|
getCompare: () => (a: T, b: T) => boolean;
|
|
14
|
+
/** When false, typing never enters filtering mode — the popover is a click/keyboard-only picker. @default true */
|
|
15
|
+
getSearchable?: () => boolean;
|
|
14
16
|
/** Optional `canCreate` validator — presence enables creatable mode. */
|
|
15
17
|
getCanCreate: () => ((q: string) => boolean) | undefined;
|
|
16
18
|
/** When true, no `kind:'create'` row is emitted (the host renders its own create UI) — keyboard navigation must not reach a row the listbox doesn't show. @default false */
|
|
@@ -281,7 +281,7 @@ export function createSelectCore(config) {
|
|
|
281
281
|
}
|
|
282
282
|
};
|
|
283
283
|
const handleInput = (e) => {
|
|
284
|
-
if (!config.getInteractive()) {
|
|
284
|
+
if (!config.getInteractive() || config.getSearchable?.() === false) {
|
|
285
285
|
return;
|
|
286
286
|
}
|
|
287
287
|
const target = e.target;
|
|
@@ -327,11 +327,11 @@ export function createSelectCore(config) {
|
|
|
327
327
|
closePopover();
|
|
328
328
|
config.getInputEl()?.focus();
|
|
329
329
|
}
|
|
330
|
-
else if (e.key === 'Backspace' && (!isFiltering || !query)) {
|
|
330
|
+
else if (e.key === 'Backspace' && (!isFiltering || !query) && config.getSearchable?.() !== false) {
|
|
331
331
|
e.preventDefault();
|
|
332
332
|
config.onClear();
|
|
333
333
|
}
|
|
334
|
-
else if (!isFiltering && isPrintableKey(e)) {
|
|
334
|
+
else if (config.getSearchable?.() !== false && !isFiltering && isPrintableKey(e)) {
|
|
335
335
|
e.preventDefault();
|
|
336
336
|
isFiltering = true;
|
|
337
337
|
query = e.key;
|
|
@@ -127,6 +127,8 @@ export type MultiselectBaseProps<T> = {
|
|
|
127
127
|
error?: boolean;
|
|
128
128
|
/** Removes the field border. @default false */
|
|
129
129
|
borderless?: boolean;
|
|
130
|
+
/** When false, typing never enters filtering mode — the input stays the combobox anchor (focus/ARIA/keyboard) but is read-only. A click/keyboard-only picker. @default true */
|
|
131
|
+
searchable?: boolean;
|
|
130
132
|
/**
|
|
131
133
|
* Group-header behavior:
|
|
132
134
|
* - `'static'` — non-interactive label (default).
|