lithesome 0.23.6 → 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/README.md +9 -3
- package/dist/components/select/Select.svelte +3 -3
- package/dist/components/select/Select.svelte.d.ts +1 -1
- package/dist/components/select/SelectOption.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 +10 -25
- package/dist/components/select/state.svelte.js +80 -95
- package/dist/types/components/select.d.ts +14 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,10 +9,18 @@ An unstyled component library for Svelte 5.
|
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
+
```bash
|
|
13
|
+
npm i -D lithesome
|
|
14
|
+
```
|
|
15
|
+
|
|
12
16
|
```bash
|
|
13
17
|
pnpm i -D lithesome
|
|
14
18
|
```
|
|
15
19
|
|
|
20
|
+
```bash
|
|
21
|
+
bun add -D lithesome
|
|
22
|
+
```
|
|
23
|
+
|
|
16
24
|
## Usage
|
|
17
25
|
|
|
18
26
|
```svelte
|
|
@@ -21,9 +29,7 @@ pnpm i -D lithesome
|
|
|
21
29
|
</script>
|
|
22
30
|
|
|
23
31
|
<Menu>
|
|
24
|
-
<MenuTrigger>
|
|
25
|
-
<button>Auth</button>
|
|
26
|
-
</MenuTrigger>
|
|
32
|
+
<MenuTrigger>Auth</MenuTrigger>
|
|
27
33
|
<MenuContent>
|
|
28
34
|
<MenuItem>My Profile</MenuItem>
|
|
29
35
|
<MenuItem>Account Settings</MenuItem>
|
|
@@ -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;
|
|
@@ -7,7 +7,7 @@ declare const SelectOption: import("svelte").Component<SelectOptionProps<{
|
|
|
7
7
|
role: string;
|
|
8
8
|
tabindex: number;
|
|
9
9
|
'aria-selected': boolean;
|
|
10
|
-
'data-value':
|
|
10
|
+
'data-value': string;
|
|
11
11
|
'data-label': string;
|
|
12
12
|
}> & Record<string, any>, {}, "label" | "disabled" | "ref" | "value">;
|
|
13
13
|
type SelectOption = ReturnType<typeof SelectOption>;
|
|
@@ -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;
|
|
@@ -2,19 +2,17 @@ import { SvelteMap } from 'svelte/reactivity';
|
|
|
2
2
|
import { Floating } from '../../internals/index.js';
|
|
3
3
|
import type { CalcIndexAction, GetInternalProps, JsonValue } from '../../internals/index.js';
|
|
4
4
|
import type { SelectArrowProps, SelectArrowState, SelectContentProps, SelectContentState, SelectOptionProps, SelectOptionState, SelectProps, SelectState, SelectTriggerProps, SelectTriggerState, SelectValueProps, SelectValueState } from '../../types/index.js';
|
|
5
|
-
interface InternalSelectOption {
|
|
6
|
-
value: JsonValue;
|
|
7
|
-
label: string;
|
|
8
|
-
}
|
|
9
5
|
type RootProps = GetInternalProps<SelectProps>;
|
|
10
6
|
declare class SelectRoot extends Floating {
|
|
11
7
|
$$: RootProps;
|
|
12
8
|
hoveredIndex: number;
|
|
13
|
-
options:
|
|
14
|
-
selectedOptions: InternalSelectOption[];
|
|
9
|
+
options: HTMLElement[];
|
|
15
10
|
sharedIds: SvelteMap<"content" | "trigger", string>;
|
|
16
11
|
mounted: boolean;
|
|
17
|
-
|
|
12
|
+
searchable: boolean;
|
|
13
|
+
serachTerm: string;
|
|
14
|
+
HoveredOption: HTMLElement | undefined;
|
|
15
|
+
SelectedOptions: HTMLElement[];
|
|
18
16
|
constructor(props: RootProps);
|
|
19
17
|
/**
|
|
20
18
|
* Toggle the visible state of the content
|
|
@@ -30,28 +28,20 @@ declare class SelectRoot extends Floating {
|
|
|
30
28
|
*/
|
|
31
29
|
close: () => void;
|
|
32
30
|
/**
|
|
33
|
-
*
|
|
34
|
-
*/
|
|
35
|
-
doneMounting: () => void;
|
|
36
|
-
/**
|
|
37
|
-
* Get the element node of the current hovered option.
|
|
31
|
+
* Get all non-disabled options from the content.
|
|
38
32
|
*/
|
|
39
|
-
|
|
33
|
+
getAvilableOptions: () => Promise<void>;
|
|
40
34
|
/**
|
|
41
35
|
* Get any element by its value inside the contents element.
|
|
42
36
|
* @param value The value to search for.
|
|
43
37
|
*/
|
|
44
38
|
getElementByValue: (value: JsonValue) => HTMLElement | null;
|
|
45
|
-
/**
|
|
46
|
-
* Get either the hovered or first selected option id.
|
|
47
|
-
*/
|
|
48
|
-
getHoveredOrFirstSelectedId: () => Promise<string | undefined>;
|
|
49
39
|
/**
|
|
50
40
|
* Append the option to the parent array, used for keeping track of options.
|
|
51
41
|
* @param value The value of the option. This must be unique.
|
|
52
42
|
* @param label The label of the option. If no label is found, the text content of the node is used.
|
|
53
43
|
*/
|
|
54
|
-
registerOption: (
|
|
44
|
+
registerOption: (option: HTMLElement) => void;
|
|
55
45
|
/**
|
|
56
46
|
* Move the focus to another element based on the action used.
|
|
57
47
|
* @param action The direction in which to travel.
|
|
@@ -61,17 +51,13 @@ declare class SelectRoot extends Floating {
|
|
|
61
51
|
* Sets the hovered option.
|
|
62
52
|
* @param value The unique value of the option.
|
|
63
53
|
*/
|
|
64
|
-
setHovered: (value:
|
|
54
|
+
setHovered: (value: string) => void;
|
|
65
55
|
/**
|
|
66
56
|
* Sets the selected option.
|
|
67
57
|
*
|
|
68
58
|
* Handles if singular or mulitple values.
|
|
69
59
|
*/
|
|
70
60
|
setSelected: () => void;
|
|
71
|
-
/**
|
|
72
|
-
* Sets the trigger label to the selected value, only if it's found in the options array.
|
|
73
|
-
*/
|
|
74
|
-
setInitialSelected: () => Promise<void>;
|
|
75
61
|
state: SelectState;
|
|
76
62
|
}
|
|
77
63
|
type TriggerProps = GetInternalProps<SelectTriggerProps>;
|
|
@@ -140,7 +126,7 @@ declare class SelectOption {
|
|
|
140
126
|
role: string;
|
|
141
127
|
tabindex: number;
|
|
142
128
|
'aria-selected': boolean;
|
|
143
|
-
'data-value':
|
|
129
|
+
'data-value': string;
|
|
144
130
|
'data-label': string;
|
|
145
131
|
};
|
|
146
132
|
state: SelectOptionState;
|
|
@@ -151,7 +137,6 @@ declare class SelectValue {
|
|
|
151
137
|
_root: SelectRoot;
|
|
152
138
|
PlaceholderVisible: boolean;
|
|
153
139
|
constructor(root: SelectRoot, props: ValueProps);
|
|
154
|
-
label: string;
|
|
155
140
|
props: {
|
|
156
141
|
id: string;
|
|
157
142
|
"data-select-value": string;
|
|
@@ -1,30 +1,50 @@
|
|
|
1
|
-
import { tick } from 'svelte';
|
|
1
|
+
import { onMount, tick } from 'svelte';
|
|
2
2
|
import { SvelteMap } from 'svelte/reactivity';
|
|
3
3
|
import { outside } from '../../attachments/outside.js';
|
|
4
4
|
import { portal } from '../../attachments/portal.js';
|
|
5
|
-
import { addEvents, attach, buildContext, calculateIndex, createAttributes, floating, Floating, KEYS, visuallyHidden } from '../../internals/index.js';
|
|
6
|
-
const { attrs, selectors } = createAttributes('select', [
|
|
5
|
+
import { addEvents, attach, buildContext, calculateIndex, createAttributes, floating, Floating, KEYS, removeDisabledElements, visuallyHidden } from '../../internals/index.js';
|
|
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,27 +58,15 @@ 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
63
|
/**
|
|
45
|
-
*
|
|
46
|
-
*/
|
|
47
|
-
doneMounting = () => {
|
|
48
|
-
this.mounted = true;
|
|
49
|
-
this.$$.visible.val = false;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Get the element node of the current hovered option.
|
|
64
|
+
* Get all non-disabled options from the content.
|
|
53
65
|
*/
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
if (option)
|
|
59
|
-
return option;
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
66
|
+
getAvilableOptions = async () => {
|
|
67
|
+
const contentElement = document.querySelector(`#${this.sharedIds.get('content')}`);
|
|
68
|
+
if (contentElement)
|
|
69
|
+
this.options = removeDisabledElements(contentElement.querySelectorAll(selectors.option));
|
|
62
70
|
};
|
|
63
71
|
/**
|
|
64
72
|
* Get any element by its value inside the contents element.
|
|
@@ -67,28 +75,15 @@ class SelectRoot extends Floating {
|
|
|
67
75
|
getElementByValue = (value) => {
|
|
68
76
|
return document.querySelector(`#${this.sharedIds.get('content')} ${selectors.option}[data-value="${value}"]`);
|
|
69
77
|
};
|
|
70
|
-
/**
|
|
71
|
-
* Get either the hovered or first selected option id.
|
|
72
|
-
*/
|
|
73
|
-
getHoveredOrFirstSelectedId = async () => {
|
|
74
|
-
await tick();
|
|
75
|
-
const selectedOption = this.HoveredOption || this.selectedOptions[0];
|
|
76
|
-
if (selectedOption) {
|
|
77
|
-
const option = this.getElementByValue(selectedOption.value);
|
|
78
|
-
if (option)
|
|
79
|
-
return option.id;
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
82
|
-
};
|
|
83
78
|
/**
|
|
84
79
|
* Append the option to the parent array, used for keeping track of options.
|
|
85
80
|
* @param value The value of the option. This must be unique.
|
|
86
81
|
* @param label The label of the option. If no label is found, the text content of the node is used.
|
|
87
82
|
*/
|
|
88
|
-
registerOption = (
|
|
89
|
-
const find = this.options.find((option) => option.value === value);
|
|
83
|
+
registerOption = (option) => {
|
|
84
|
+
const find = this.options.find((option) => option.dataset.value === option.dataset.value);
|
|
90
85
|
if (!find)
|
|
91
|
-
this.options.push(
|
|
86
|
+
this.options.push(option);
|
|
92
87
|
};
|
|
93
88
|
/**
|
|
94
89
|
* Move the focus to another element based on the action used.
|
|
@@ -96,16 +91,15 @@ class SelectRoot extends Floating {
|
|
|
96
91
|
*/
|
|
97
92
|
navigate = (action) => {
|
|
98
93
|
this.hoveredIndex = calculateIndex(action, this.options, this.hoveredIndex);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
element.scrollIntoView({ block: 'nearest' });
|
|
94
|
+
if (this.HoveredOption)
|
|
95
|
+
this.HoveredOption.scrollIntoView({ block: 'nearest' });
|
|
102
96
|
};
|
|
103
97
|
/**
|
|
104
98
|
* Sets the hovered option.
|
|
105
99
|
* @param value The unique value of the option.
|
|
106
100
|
*/
|
|
107
101
|
setHovered = (value) => {
|
|
108
|
-
this.hoveredIndex = this.options.findIndex((el) => el.value === value);
|
|
102
|
+
this.hoveredIndex = this.options.findIndex((el) => el.dataset.value === value);
|
|
109
103
|
};
|
|
110
104
|
/**
|
|
111
105
|
* Sets the selected option.
|
|
@@ -113,38 +107,22 @@ class SelectRoot extends Floating {
|
|
|
113
107
|
* Handles if singular or mulitple values.
|
|
114
108
|
*/
|
|
115
109
|
setSelected = () => {
|
|
116
|
-
if (!this.HoveredOption)
|
|
110
|
+
if (!this.HoveredOption || !this.HoveredOption.dataset.value)
|
|
117
111
|
return;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
else
|
|
123
|
-
this.
|
|
124
|
-
}
|
|
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);
|
|
125
118
|
}
|
|
126
119
|
else {
|
|
127
|
-
this.
|
|
120
|
+
if (this.$$.unselectable.val && this.$$.value.val === newVal)
|
|
121
|
+
this.$$.value.val = '';
|
|
122
|
+
else
|
|
123
|
+
this.$$.value.val = newVal;
|
|
124
|
+
this.close();
|
|
128
125
|
}
|
|
129
|
-
if (!this.$$.multiple.val)
|
|
130
|
-
this.$$.visible.val = false;
|
|
131
|
-
this.$$.value.val = this.$$.multiple.val
|
|
132
|
-
? this.selectedOptions.map((el) => el.value)
|
|
133
|
-
: this.selectedOptions[0].value;
|
|
134
|
-
};
|
|
135
|
-
/**
|
|
136
|
-
* Sets the trigger label to the selected value, only if it's found in the options array.
|
|
137
|
-
*/
|
|
138
|
-
setInitialSelected = async () => {
|
|
139
|
-
await tick();
|
|
140
|
-
const value = this.$$.value.val;
|
|
141
|
-
this.selectedOptions = this.options.filter((el) => {
|
|
142
|
-
if (!Array.isArray(value) && el.value === value)
|
|
143
|
-
return el;
|
|
144
|
-
else if (Array.isArray(value) && value.includes(el.value))
|
|
145
|
-
return el;
|
|
146
|
-
});
|
|
147
|
-
this.doneMounting();
|
|
148
126
|
};
|
|
149
127
|
state = $derived.by(() => ({
|
|
150
128
|
visible: this.$$.visible.val
|
|
@@ -168,18 +146,17 @@ class SelectTrigger {
|
|
|
168
146
|
...attach((node) => {
|
|
169
147
|
this._root.trigger = node;
|
|
170
148
|
// Such a hacky way, but it works :\
|
|
171
|
-
if (this._root.HoveredOption || this._root.
|
|
172
|
-
tick().then(
|
|
149
|
+
if (this._root.HoveredOption || this._root.SelectedOptions[0]) {
|
|
150
|
+
tick().then(() => {
|
|
173
151
|
if (this._root.$$.visible.val) {
|
|
174
|
-
const id =
|
|
152
|
+
const { id } = this._root.HoveredOption || this._root.SelectedOptions[0];
|
|
175
153
|
if (id)
|
|
176
154
|
node.setAttribute('aria-activedescendant', id);
|
|
177
155
|
}
|
|
178
|
-
else {
|
|
179
|
-
node.removeAttribute('aria-activedescendant');
|
|
180
|
-
}
|
|
181
156
|
});
|
|
182
157
|
}
|
|
158
|
+
if (!this._root.$$.visible.val)
|
|
159
|
+
node.removeAttribute('aria-activedescendant');
|
|
183
160
|
return addEvents(node, {
|
|
184
161
|
click: () => {
|
|
185
162
|
if (this._root.$$.disabled.val)
|
|
@@ -203,8 +180,8 @@ class SelectTrigger {
|
|
|
203
180
|
if (key === KEYS.enter) {
|
|
204
181
|
e.preventDefault();
|
|
205
182
|
if (this._root.HoveredOption && this._root.$$.visible.val) {
|
|
206
|
-
this._root.
|
|
207
|
-
if (!this._root.$$.
|
|
183
|
+
this._root.HoveredOption?.click();
|
|
184
|
+
if (!Array.isArray(this._root.$$.value.val))
|
|
208
185
|
this._root.close();
|
|
209
186
|
}
|
|
210
187
|
else {
|
|
@@ -228,6 +205,20 @@ class SelectContent {
|
|
|
228
205
|
this._root = root;
|
|
229
206
|
this.$$ = props;
|
|
230
207
|
this._root.sharedIds.set('content', this.$$.id.val);
|
|
208
|
+
// Get element references but wait for label to be populated.
|
|
209
|
+
$effect(() => {
|
|
210
|
+
if (this._root.$$.visible.val) {
|
|
211
|
+
tick().then(() => {
|
|
212
|
+
this._root.getAvilableOptions();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// Set first selected value as highlighted option
|
|
217
|
+
$effect(() => {
|
|
218
|
+
if (this._root.$$.visible.val && this._root.SelectedOptions.length && !this._root.HoveredOption) {
|
|
219
|
+
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.selected === 'true');
|
|
220
|
+
}
|
|
221
|
+
});
|
|
231
222
|
}
|
|
232
223
|
props = $derived.by(() => ({
|
|
233
224
|
id: this.$$.id.val,
|
|
@@ -273,17 +264,11 @@ class SelectArrow {
|
|
|
273
264
|
class SelectOption {
|
|
274
265
|
$$;
|
|
275
266
|
_root;
|
|
276
|
-
Hovered = $derived.by(() => this._root.HoveredOption?.value === this.$$.value.val);
|
|
277
|
-
Selected = $derived.by(() => !!this._root.
|
|
267
|
+
Hovered = $derived.by(() => this._root.HoveredOption?.dataset.value === this.$$.value.val);
|
|
268
|
+
Selected = $derived.by(() => !!this._root.SelectedOptions.find((el) => el.dataset.value === this.$$.value.val));
|
|
278
269
|
constructor(root, props) {
|
|
279
270
|
this._root = root;
|
|
280
271
|
this.$$ = props;
|
|
281
|
-
$effect(() => {
|
|
282
|
-
if (this.$$.disabled.val)
|
|
283
|
-
return;
|
|
284
|
-
const label = this.$$.label.val || this.$$.ref.val.textContent.trim();
|
|
285
|
-
this._root.registerOption(this.$$.value.val, label);
|
|
286
|
-
});
|
|
287
272
|
}
|
|
288
273
|
props = $derived.by(() => ({
|
|
289
274
|
id: this.$$.id.val,
|
|
@@ -294,11 +279,11 @@ class SelectOption {
|
|
|
294
279
|
tabindex: 0,
|
|
295
280
|
'aria-selected': this.Selected,
|
|
296
281
|
'data-value': this.$$.value.val,
|
|
297
|
-
'data-label': this.$$.label.val,
|
|
282
|
+
'data-label': this.$$.ref.val && !this.$$.label.val ? this.$$.ref.val.textContent.trim() : this.$$.label.val,
|
|
298
283
|
...attach((node) => {
|
|
299
284
|
// Set the hovered index to the active item, if that item is "selected".
|
|
300
285
|
if (this._root.$$.value.val === this.$$.value.val) {
|
|
301
|
-
this._root.hoveredIndex = this._root.options.findIndex((el) => el.value === this.$$.value.val);
|
|
286
|
+
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.value === this.$$.value.val);
|
|
302
287
|
}
|
|
303
288
|
return addEvents(node, {
|
|
304
289
|
click: () => {
|
|
@@ -322,12 +307,11 @@ class SelectOption {
|
|
|
322
307
|
class SelectValue {
|
|
323
308
|
$$;
|
|
324
309
|
_root;
|
|
325
|
-
PlaceholderVisible = $derived.by(() => this._root.
|
|
310
|
+
PlaceholderVisible = $derived.by(() => !this._root.$$.value.val.length);
|
|
326
311
|
constructor(root, props) {
|
|
327
312
|
this._root = root;
|
|
328
313
|
this.$$ = props;
|
|
329
314
|
}
|
|
330
|
-
label = $derived.by(() => this.PlaceholderVisible ? this.$$.placeholder.val : this._root.selectedOptions.map((el) => el.label).join(','));
|
|
331
315
|
props = $derived.by(() => ({
|
|
332
316
|
id: this.$$.id.val,
|
|
333
317
|
[attrs.value]: '',
|
|
@@ -335,7 +319,8 @@ class SelectValue {
|
|
|
335
319
|
}));
|
|
336
320
|
state = $derived.by(() => ({
|
|
337
321
|
visible: this._root.$$.visible.val,
|
|
338
|
-
placeholderVisible: this.PlaceholderVisible
|
|
322
|
+
placeholderVisible: this.PlaceholderVisible,
|
|
323
|
+
selectedLabels: this._root.SelectedOptions.map((el) => el.dataset.label)
|
|
339
324
|
}));
|
|
340
325
|
}
|
|
341
326
|
//
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import type { FloatingContent,
|
|
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
|
/**
|
|
@@ -50,7 +52,7 @@ export interface SelectOptionProps<P = any> extends Props<HTMLButtonElement, P,
|
|
|
50
52
|
/**
|
|
51
53
|
* The value of the option.
|
|
52
54
|
*/
|
|
53
|
-
value:
|
|
55
|
+
value: string;
|
|
54
56
|
/**
|
|
55
57
|
* Disables the option, skipping mouse/keyboard navigation and stopping events from firing.
|
|
56
58
|
*
|
|
@@ -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
|
}
|