lithesome 0.23.7 → 0.24.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/components/select/Select.svelte +3 -3
- package/dist/components/select/Select.svelte.d.ts +1 -1
- package/dist/components/select/SelectValue.svelte +6 -4
- package/dist/components/select/SelectValue.svelte.d.ts +5 -2
- package/dist/components/select/state.svelte.d.ts +3 -15
- package/dist/components/select/state.svelte.js +58 -74
- package/dist/types/components/select.d.ts +13 -7
- package/package.json +1 -1
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
disabled = $bindable(false),
|
|
15
15
|
portalTarget = 'body',
|
|
16
16
|
floatingConfig = {},
|
|
17
|
-
value = $bindable(),
|
|
18
|
-
|
|
17
|
+
value = $bindable(null!),
|
|
18
|
+
unselectable = false,
|
|
19
19
|
onValueChanged
|
|
20
20
|
}: SelectProps = $props();
|
|
21
21
|
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
),
|
|
41
41
|
portalTarget: stateValue(() => portalTarget),
|
|
42
42
|
floatingConfig: stateValue(() => floatingConfig),
|
|
43
|
-
|
|
43
|
+
unselectable: stateValue(() => unselectable)
|
|
44
44
|
});
|
|
45
45
|
</script>
|
|
46
46
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SelectProps } from '../../types/index.js';
|
|
2
|
-
declare const Select: import("svelte").Component<SelectProps
|
|
2
|
+
declare const Select: import("svelte").Component<SelectProps, {}, "disabled" | "visible" | "value">;
|
|
3
3
|
type Select = ReturnType<typeof Select>;
|
|
4
4
|
export default Select;
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
let {
|
|
10
10
|
id = parseId(uid),
|
|
11
11
|
ref = $bindable(),
|
|
12
|
-
placeholder = $bindable(''),
|
|
12
|
+
placeholder = $bindable('Select an option...'),
|
|
13
|
+
children,
|
|
14
|
+
custom,
|
|
13
15
|
...props
|
|
14
|
-
}: SelectValueProps & Record<string, any> = $props();
|
|
16
|
+
}: SelectValueProps<typeof ctx.props> & Record<string, any> = $props();
|
|
15
17
|
|
|
16
18
|
let ctx = useSelectValue({
|
|
17
19
|
id: stateValue(() => id),
|
|
@@ -20,6 +22,6 @@
|
|
|
20
22
|
});
|
|
21
23
|
</script>
|
|
22
24
|
|
|
23
|
-
<Element bind:ref {ctx} {...props} as="span">
|
|
24
|
-
{ctx.
|
|
25
|
+
<Element bind:ref {custom} {ctx} {...props} as="span">
|
|
26
|
+
{ctx.state.placeholderVisible ? placeholder : ctx.state.selectedLabels.join(', ')}
|
|
25
27
|
</Element>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { SelectValueProps } from '../../types/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
declare const SelectValue: import("svelte").Component<SelectValueProps<{
|
|
3
|
+
id: string;
|
|
4
|
+
"data-select-value": string;
|
|
5
|
+
'data-placeholder': true | undefined;
|
|
6
|
+
}> & Record<string, any>, {}, "ref" | "placeholder">;
|
|
4
7
|
type SelectValue = ReturnType<typeof SelectValue>;
|
|
5
8
|
export default SelectValue;
|
|
@@ -7,10 +7,12 @@ declare class SelectRoot extends Floating {
|
|
|
7
7
|
$$: RootProps;
|
|
8
8
|
hoveredIndex: number;
|
|
9
9
|
options: HTMLElement[];
|
|
10
|
-
selectedOptions: HTMLElement[];
|
|
11
10
|
sharedIds: SvelteMap<"content" | "trigger", string>;
|
|
12
11
|
mounted: boolean;
|
|
12
|
+
searchable: boolean;
|
|
13
|
+
serachTerm: string;
|
|
13
14
|
HoveredOption: HTMLElement | undefined;
|
|
15
|
+
SelectedOptions: HTMLElement[];
|
|
14
16
|
constructor(props: RootProps);
|
|
15
17
|
/**
|
|
16
18
|
* Toggle the visible state of the content
|
|
@@ -25,10 +27,6 @@ declare class SelectRoot extends Floating {
|
|
|
25
27
|
* and reset variables to reduce duplicate entries.
|
|
26
28
|
*/
|
|
27
29
|
close: () => void;
|
|
28
|
-
/**
|
|
29
|
-
* Tells the components that checks have been completed, render as normal.
|
|
30
|
-
*/
|
|
31
|
-
doneMounting: () => void;
|
|
32
30
|
/**
|
|
33
31
|
* Get all non-disabled options from the content.
|
|
34
32
|
*/
|
|
@@ -38,10 +36,6 @@ declare class SelectRoot extends Floating {
|
|
|
38
36
|
* @param value The value to search for.
|
|
39
37
|
*/
|
|
40
38
|
getElementByValue: (value: JsonValue) => HTMLElement | null;
|
|
41
|
-
/**
|
|
42
|
-
* Get either the hovered or first selected option id.
|
|
43
|
-
*/
|
|
44
|
-
getHoveredOrFirstSelectedId: () => Promise<string | null>;
|
|
45
39
|
/**
|
|
46
40
|
* Append the option to the parent array, used for keeping track of options.
|
|
47
41
|
* @param value The value of the option. This must be unique.
|
|
@@ -64,10 +58,6 @@ declare class SelectRoot extends Floating {
|
|
|
64
58
|
* Handles if singular or mulitple values.
|
|
65
59
|
*/
|
|
66
60
|
setSelected: () => void;
|
|
67
|
-
/**
|
|
68
|
-
* Sets the trigger label to the selected value, only if it's found in the options array.
|
|
69
|
-
*/
|
|
70
|
-
setInitialSelected: () => Promise<void>;
|
|
71
61
|
state: SelectState;
|
|
72
62
|
}
|
|
73
63
|
type TriggerProps = GetInternalProps<SelectTriggerProps>;
|
|
@@ -127,7 +117,6 @@ declare class SelectOption {
|
|
|
127
117
|
_root: SelectRoot;
|
|
128
118
|
Hovered: boolean;
|
|
129
119
|
Selected: boolean;
|
|
130
|
-
Label: string;
|
|
131
120
|
constructor(root: SelectRoot, props: OptionProps);
|
|
132
121
|
props: {
|
|
133
122
|
id: string;
|
|
@@ -148,7 +137,6 @@ declare class SelectValue {
|
|
|
148
137
|
_root: SelectRoot;
|
|
149
138
|
PlaceholderVisible: boolean;
|
|
150
139
|
constructor(root: SelectRoot, props: ValueProps);
|
|
151
|
-
label: string;
|
|
152
140
|
props: {
|
|
153
141
|
id: string;
|
|
154
142
|
"data-select-value": string;
|
|
@@ -3,28 +3,48 @@ import { SvelteMap } from 'svelte/reactivity';
|
|
|
3
3
|
import { outside } from '../../attachments/outside.js';
|
|
4
4
|
import { portal } from '../../attachments/portal.js';
|
|
5
5
|
import { addEvents, attach, buildContext, calculateIndex, createAttributes, floating, Floating, KEYS, removeDisabledElements, visuallyHidden } from '../../internals/index.js';
|
|
6
|
-
const { attrs, selectors } = createAttributes('select', [
|
|
6
|
+
const { attrs, selectors } = createAttributes('select', [
|
|
7
|
+
'root',
|
|
8
|
+
'trigger',
|
|
9
|
+
'content',
|
|
10
|
+
'arrow',
|
|
11
|
+
'option',
|
|
12
|
+
'value',
|
|
13
|
+
'search'
|
|
14
|
+
]);
|
|
7
15
|
class SelectRoot extends Floating {
|
|
8
16
|
$$;
|
|
9
17
|
hoveredIndex = $state(-1);
|
|
10
18
|
options = $state([]);
|
|
11
|
-
selectedOptions = $state([]);
|
|
12
19
|
sharedIds = new SvelteMap();
|
|
13
20
|
mounted = $state(false);
|
|
21
|
+
searchable = $state(false);
|
|
22
|
+
serachTerm = $state('');
|
|
14
23
|
HoveredOption = $derived.by(() => this.options[this.hoveredIndex] || undefined);
|
|
24
|
+
SelectedOptions = $derived(this.options.filter((opt) => {
|
|
25
|
+
if (!opt.dataset.value)
|
|
26
|
+
return false;
|
|
27
|
+
return Array.isArray(this.$$.value.val)
|
|
28
|
+
? this.$$.value.val.includes(opt.dataset.value)
|
|
29
|
+
: this.$$.value.val === opt.dataset.value;
|
|
30
|
+
}));
|
|
15
31
|
constructor(props) {
|
|
16
32
|
super();
|
|
17
33
|
this.$$ = props;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
34
|
+
onMount(async () => {
|
|
35
|
+
await tick();
|
|
36
|
+
this.mounted = true;
|
|
37
|
+
this.$$.visible.val = false;
|
|
38
|
+
});
|
|
22
39
|
}
|
|
23
40
|
/**
|
|
24
41
|
* Toggle the visible state of the content
|
|
25
42
|
*/
|
|
26
43
|
toggle = () => {
|
|
27
|
-
|
|
44
|
+
if (this.$$.visible.val)
|
|
45
|
+
this.close();
|
|
46
|
+
else
|
|
47
|
+
this.open();
|
|
28
48
|
};
|
|
29
49
|
/**
|
|
30
50
|
* Set the visible state of the content to true
|
|
@@ -38,16 +58,8 @@ class SelectRoot extends Floating {
|
|
|
38
58
|
*/
|
|
39
59
|
close = () => {
|
|
40
60
|
this.$$.visible.val = false;
|
|
41
|
-
this.options = [];
|
|
42
61
|
this.hoveredIndex = -1;
|
|
43
62
|
};
|
|
44
|
-
/**
|
|
45
|
-
* Tells the components that checks have been completed, render as normal.
|
|
46
|
-
*/
|
|
47
|
-
doneMounting = () => {
|
|
48
|
-
this.mounted = true;
|
|
49
|
-
this.$$.visible.val = false;
|
|
50
|
-
};
|
|
51
63
|
/**
|
|
52
64
|
* Get all non-disabled options from the content.
|
|
53
65
|
*/
|
|
@@ -63,14 +75,6 @@ class SelectRoot extends Floating {
|
|
|
63
75
|
getElementByValue = (value) => {
|
|
64
76
|
return document.querySelector(`#${this.sharedIds.get('content')} ${selectors.option}[data-value="${value}"]`);
|
|
65
77
|
};
|
|
66
|
-
/**
|
|
67
|
-
* Get either the hovered or first selected option id.
|
|
68
|
-
*/
|
|
69
|
-
getHoveredOrFirstSelectedId = async () => {
|
|
70
|
-
await tick();
|
|
71
|
-
const selectedOption = this.HoveredOption || this.selectedOptions[0];
|
|
72
|
-
return selectedOption.id || null;
|
|
73
|
-
};
|
|
74
78
|
/**
|
|
75
79
|
* Append the option to the parent array, used for keeping track of options.
|
|
76
80
|
* @param value The value of the option. This must be unique.
|
|
@@ -103,38 +107,22 @@ class SelectRoot extends Floating {
|
|
|
103
107
|
* Handles if singular or mulitple values.
|
|
104
108
|
*/
|
|
105
109
|
setSelected = () => {
|
|
106
|
-
if (!this.HoveredOption)
|
|
110
|
+
if (!this.HoveredOption || !this.HoveredOption.dataset.value)
|
|
107
111
|
return;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
else
|
|
113
|
-
this.
|
|
114
|
-
}
|
|
112
|
+
const newVal = this.HoveredOption.dataset.value;
|
|
113
|
+
if (Array.isArray(this.$$.value.val)) {
|
|
114
|
+
if (this.$$.value.val.includes(newVal))
|
|
115
|
+
this.$$.value.val = this.$$.value.val.filter((el) => el !== newVal);
|
|
116
|
+
else
|
|
117
|
+
this.$$.value.val.push(newVal);
|
|
115
118
|
}
|
|
116
119
|
else {
|
|
117
|
-
this.
|
|
120
|
+
if (this.$$.unselectable.val && this.$$.value.val === newVal)
|
|
121
|
+
this.$$.value.val = '';
|
|
122
|
+
else
|
|
123
|
+
this.$$.value.val = newVal;
|
|
124
|
+
this.close();
|
|
118
125
|
}
|
|
119
|
-
if (!this.$$.multiple.val)
|
|
120
|
-
this.$$.visible.val = false;
|
|
121
|
-
this.$$.value.val = this.$$.multiple.val
|
|
122
|
-
? this.selectedOptions.map((el) => el.dataset.value)
|
|
123
|
-
: this.selectedOptions[0].dataset.value;
|
|
124
|
-
};
|
|
125
|
-
/**
|
|
126
|
-
* Sets the trigger label to the selected value, only if it's found in the options array.
|
|
127
|
-
*/
|
|
128
|
-
setInitialSelected = async () => {
|
|
129
|
-
await tick();
|
|
130
|
-
const value = this.$$.value.val;
|
|
131
|
-
this.selectedOptions = this.options.filter((el) => {
|
|
132
|
-
if (!Array.isArray(value) && el.dataset.value === value)
|
|
133
|
-
return el;
|
|
134
|
-
else if (Array.isArray(value) && value.includes(el.dataset.value))
|
|
135
|
-
return el;
|
|
136
|
-
});
|
|
137
|
-
this.doneMounting();
|
|
138
126
|
};
|
|
139
127
|
state = $derived.by(() => ({
|
|
140
128
|
visible: this.$$.visible.val
|
|
@@ -158,18 +146,17 @@ class SelectTrigger {
|
|
|
158
146
|
...attach((node) => {
|
|
159
147
|
this._root.trigger = node;
|
|
160
148
|
// Such a hacky way, but it works :\
|
|
161
|
-
if (this._root.HoveredOption || this._root.
|
|
162
|
-
tick().then(
|
|
149
|
+
if (this._root.HoveredOption || this._root.SelectedOptions[0]) {
|
|
150
|
+
tick().then(() => {
|
|
163
151
|
if (this._root.$$.visible.val) {
|
|
164
|
-
const id =
|
|
152
|
+
const { id } = this._root.HoveredOption || this._root.SelectedOptions[0];
|
|
165
153
|
if (id)
|
|
166
154
|
node.setAttribute('aria-activedescendant', id);
|
|
167
155
|
}
|
|
168
|
-
else {
|
|
169
|
-
node.removeAttribute('aria-activedescendant');
|
|
170
|
-
}
|
|
171
156
|
});
|
|
172
157
|
}
|
|
158
|
+
if (!this._root.$$.visible.val)
|
|
159
|
+
node.removeAttribute('aria-activedescendant');
|
|
173
160
|
return addEvents(node, {
|
|
174
161
|
click: () => {
|
|
175
162
|
if (this._root.$$.disabled.val)
|
|
@@ -194,7 +181,7 @@ class SelectTrigger {
|
|
|
194
181
|
e.preventDefault();
|
|
195
182
|
if (this._root.HoveredOption && this._root.$$.visible.val) {
|
|
196
183
|
this._root.HoveredOption?.click();
|
|
197
|
-
if (!this._root.$$.
|
|
184
|
+
if (!Array.isArray(this._root.$$.value.val))
|
|
198
185
|
this._root.close();
|
|
199
186
|
}
|
|
200
187
|
else {
|
|
@@ -218,14 +205,17 @@ class SelectContent {
|
|
|
218
205
|
this._root = root;
|
|
219
206
|
this.$$ = props;
|
|
220
207
|
this._root.sharedIds.set('content', this.$$.id.val);
|
|
208
|
+
// Get element references but wait for label to be populated.
|
|
221
209
|
$effect(() => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
210
|
+
if (this._root.$$.visible.val) {
|
|
211
|
+
tick().then(() => {
|
|
212
|
+
this._root.getAvilableOptions();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
225
215
|
});
|
|
216
|
+
// Set first selected value as highlighted option
|
|
226
217
|
$effect(() => {
|
|
227
|
-
|
|
228
|
-
if (this._root.$$.visible.val && this._root.selectedOptions.length && !this._root.HoveredOption) {
|
|
218
|
+
if (this._root.$$.visible.val && this._root.SelectedOptions.length && !this._root.HoveredOption) {
|
|
229
219
|
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.selected === 'true');
|
|
230
220
|
}
|
|
231
221
|
});
|
|
@@ -275,8 +265,7 @@ class SelectOption {
|
|
|
275
265
|
$$;
|
|
276
266
|
_root;
|
|
277
267
|
Hovered = $derived.by(() => this._root.HoveredOption?.dataset.value === this.$$.value.val);
|
|
278
|
-
Selected = $derived.by(() => !!this._root.
|
|
279
|
-
Label = $derived.by(() => this.$$.label.val);
|
|
268
|
+
Selected = $derived.by(() => !!this._root.SelectedOptions.find((el) => el.dataset.value === this.$$.value.val));
|
|
280
269
|
constructor(root, props) {
|
|
281
270
|
this._root = root;
|
|
282
271
|
this.$$ = props;
|
|
@@ -290,11 +279,8 @@ class SelectOption {
|
|
|
290
279
|
tabindex: 0,
|
|
291
280
|
'aria-selected': this.Selected,
|
|
292
281
|
'data-value': this.$$.value.val,
|
|
293
|
-
'data-label': this.
|
|
282
|
+
'data-label': this.$$.ref.val && !this.$$.label.val ? this.$$.ref.val.textContent.trim() : this.$$.label.val,
|
|
294
283
|
...attach((node) => {
|
|
295
|
-
if (!this.$$.label.val && this.$$.ref.val) {
|
|
296
|
-
this.Label = this.$$.ref.val.textContent.trim();
|
|
297
|
-
}
|
|
298
284
|
// Set the hovered index to the active item, if that item is "selected".
|
|
299
285
|
if (this._root.$$.value.val === this.$$.value.val) {
|
|
300
286
|
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.value === this.$$.value.val);
|
|
@@ -321,14 +307,11 @@ class SelectOption {
|
|
|
321
307
|
class SelectValue {
|
|
322
308
|
$$;
|
|
323
309
|
_root;
|
|
324
|
-
PlaceholderVisible = $derived.by(() => this._root.
|
|
310
|
+
PlaceholderVisible = $derived.by(() => !this._root.$$.value.val.length);
|
|
325
311
|
constructor(root, props) {
|
|
326
312
|
this._root = root;
|
|
327
313
|
this.$$ = props;
|
|
328
314
|
}
|
|
329
|
-
label = $derived.by(() => this.PlaceholderVisible
|
|
330
|
-
? this.$$.placeholder.val
|
|
331
|
-
: this._root.selectedOptions.map((el) => el.dataset.label).join(','));
|
|
332
315
|
props = $derived.by(() => ({
|
|
333
316
|
id: this.$$.id.val,
|
|
334
317
|
[attrs.value]: '',
|
|
@@ -336,7 +319,8 @@ class SelectValue {
|
|
|
336
319
|
}));
|
|
337
320
|
state = $derived.by(() => ({
|
|
338
321
|
visible: this._root.$$.visible.val,
|
|
339
|
-
placeholderVisible: this.PlaceholderVisible
|
|
322
|
+
placeholderVisible: this.PlaceholderVisible,
|
|
323
|
+
selectedLabels: this._root.SelectedOptions.map((el) => el.dataset.label)
|
|
340
324
|
}));
|
|
341
325
|
}
|
|
342
326
|
//
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import type { FloatingContent, Props,
|
|
2
|
-
export interface SelectProps
|
|
1
|
+
import type { FloatingContent, Props, PropsNoRender } from '../../internals/index.js';
|
|
2
|
+
export interface SelectProps extends PropsNoRender<SelectState>, FloatingContent {
|
|
3
3
|
/**
|
|
4
4
|
* The currently selected option(s).
|
|
5
5
|
*
|
|
6
6
|
* ### `$bindable`
|
|
7
7
|
*/
|
|
8
|
-
value?:
|
|
8
|
+
value?: string | string[];
|
|
9
9
|
/**
|
|
10
|
-
* Allows
|
|
10
|
+
* Allows a non-array value to be unselected.
|
|
11
|
+
*
|
|
12
|
+
* @default false
|
|
11
13
|
*/
|
|
12
|
-
|
|
14
|
+
unselectable?: boolean;
|
|
13
15
|
/**
|
|
14
16
|
* Fires whenever the `value` prop changes.
|
|
15
17
|
* @param value The new value
|
|
16
18
|
*/
|
|
17
|
-
onValueChanged?: (value:
|
|
19
|
+
onValueChanged?: (value: string | string[]) => void;
|
|
18
20
|
}
|
|
19
21
|
export interface SelectState {
|
|
20
22
|
/**
|
|
@@ -74,7 +76,7 @@ export interface SelectOptionState {
|
|
|
74
76
|
*/
|
|
75
77
|
selected: boolean;
|
|
76
78
|
}
|
|
77
|
-
export interface SelectValueProps extends
|
|
79
|
+
export interface SelectValueProps<P = any> extends Props<HTMLSpanElement, P, SelectValueState> {
|
|
78
80
|
/**
|
|
79
81
|
* The value displayed when no option(s) is selected.
|
|
80
82
|
*/
|
|
@@ -89,4 +91,8 @@ export interface SelectValueState {
|
|
|
89
91
|
* True if no options are selected.
|
|
90
92
|
*/
|
|
91
93
|
placeholderVisible: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* The currently selected options.
|
|
96
|
+
*/
|
|
97
|
+
selectedLabels: string[];
|
|
92
98
|
}
|