lithesome 0.23.6 → 0.23.7
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
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>
|
|
@@ -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>;
|
|
@@ -2,19 +2,15 @@ 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:
|
|
9
|
+
options: HTMLElement[];
|
|
10
|
+
selectedOptions: HTMLElement[];
|
|
15
11
|
sharedIds: SvelteMap<"content" | "trigger", string>;
|
|
16
12
|
mounted: boolean;
|
|
17
|
-
HoveredOption:
|
|
13
|
+
HoveredOption: HTMLElement | undefined;
|
|
18
14
|
constructor(props: RootProps);
|
|
19
15
|
/**
|
|
20
16
|
* Toggle the visible state of the content
|
|
@@ -34,9 +30,9 @@ declare class SelectRoot extends Floating {
|
|
|
34
30
|
*/
|
|
35
31
|
doneMounting: () => void;
|
|
36
32
|
/**
|
|
37
|
-
* Get
|
|
33
|
+
* Get all non-disabled options from the content.
|
|
38
34
|
*/
|
|
39
|
-
|
|
35
|
+
getAvilableOptions: () => Promise<void>;
|
|
40
36
|
/**
|
|
41
37
|
* Get any element by its value inside the contents element.
|
|
42
38
|
* @param value The value to search for.
|
|
@@ -45,13 +41,13 @@ declare class SelectRoot extends Floating {
|
|
|
45
41
|
/**
|
|
46
42
|
* Get either the hovered or first selected option id.
|
|
47
43
|
*/
|
|
48
|
-
getHoveredOrFirstSelectedId: () => Promise<string |
|
|
44
|
+
getHoveredOrFirstSelectedId: () => Promise<string | null>;
|
|
49
45
|
/**
|
|
50
46
|
* Append the option to the parent array, used for keeping track of options.
|
|
51
47
|
* @param value The value of the option. This must be unique.
|
|
52
48
|
* @param label The label of the option. If no label is found, the text content of the node is used.
|
|
53
49
|
*/
|
|
54
|
-
registerOption: (
|
|
50
|
+
registerOption: (option: HTMLElement) => void;
|
|
55
51
|
/**
|
|
56
52
|
* Move the focus to another element based on the action used.
|
|
57
53
|
* @param action The direction in which to travel.
|
|
@@ -61,7 +57,7 @@ declare class SelectRoot extends Floating {
|
|
|
61
57
|
* Sets the hovered option.
|
|
62
58
|
* @param value The unique value of the option.
|
|
63
59
|
*/
|
|
64
|
-
setHovered: (value:
|
|
60
|
+
setHovered: (value: string) => void;
|
|
65
61
|
/**
|
|
66
62
|
* Sets the selected option.
|
|
67
63
|
*
|
|
@@ -131,6 +127,7 @@ declare class SelectOption {
|
|
|
131
127
|
_root: SelectRoot;
|
|
132
128
|
Hovered: boolean;
|
|
133
129
|
Selected: boolean;
|
|
130
|
+
Label: string;
|
|
134
131
|
constructor(root: SelectRoot, props: OptionProps);
|
|
135
132
|
props: {
|
|
136
133
|
id: string;
|
|
@@ -140,7 +137,7 @@ declare class SelectOption {
|
|
|
140
137
|
role: string;
|
|
141
138
|
tabindex: number;
|
|
142
139
|
'aria-selected': boolean;
|
|
143
|
-
'data-value':
|
|
140
|
+
'data-value': string;
|
|
144
141
|
'data-label': string;
|
|
145
142
|
};
|
|
146
143
|
state: SelectOptionState;
|
|
@@ -1,8 +1,8 @@
|
|
|
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';
|
|
5
|
+
import { addEvents, attach, buildContext, calculateIndex, createAttributes, floating, Floating, KEYS, removeDisabledElements, visuallyHidden } from '../../internals/index.js';
|
|
6
6
|
const { attrs, selectors } = createAttributes('select', ['root', 'trigger', 'content', 'arrow', 'option', 'value']);
|
|
7
7
|
class SelectRoot extends Floating {
|
|
8
8
|
$$;
|
|
@@ -49,16 +49,12 @@ class SelectRoot extends Floating {
|
|
|
49
49
|
this.$$.visible.val = false;
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
|
-
* Get
|
|
52
|
+
* Get all non-disabled options from the content.
|
|
53
53
|
*/
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
if (option)
|
|
59
|
-
return option;
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
54
|
+
getAvilableOptions = async () => {
|
|
55
|
+
const contentElement = document.querySelector(`#${this.sharedIds.get('content')}`);
|
|
56
|
+
if (contentElement)
|
|
57
|
+
this.options = removeDisabledElements(contentElement.querySelectorAll(selectors.option));
|
|
62
58
|
};
|
|
63
59
|
/**
|
|
64
60
|
* Get any element by its value inside the contents element.
|
|
@@ -73,22 +69,17 @@ class SelectRoot extends Floating {
|
|
|
73
69
|
getHoveredOrFirstSelectedId = async () => {
|
|
74
70
|
await tick();
|
|
75
71
|
const selectedOption = this.HoveredOption || this.selectedOptions[0];
|
|
76
|
-
|
|
77
|
-
const option = this.getElementByValue(selectedOption.value);
|
|
78
|
-
if (option)
|
|
79
|
-
return option.id;
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
72
|
+
return selectedOption.id || null;
|
|
82
73
|
};
|
|
83
74
|
/**
|
|
84
75
|
* Append the option to the parent array, used for keeping track of options.
|
|
85
76
|
* @param value The value of the option. This must be unique.
|
|
86
77
|
* @param label The label of the option. If no label is found, the text content of the node is used.
|
|
87
78
|
*/
|
|
88
|
-
registerOption = (
|
|
89
|
-
const find = this.options.find((option) => option.value === value);
|
|
79
|
+
registerOption = (option) => {
|
|
80
|
+
const find = this.options.find((option) => option.dataset.value === option.dataset.value);
|
|
90
81
|
if (!find)
|
|
91
|
-
this.options.push(
|
|
82
|
+
this.options.push(option);
|
|
92
83
|
};
|
|
93
84
|
/**
|
|
94
85
|
* Move the focus to another element based on the action used.
|
|
@@ -96,16 +87,15 @@ class SelectRoot extends Floating {
|
|
|
96
87
|
*/
|
|
97
88
|
navigate = (action) => {
|
|
98
89
|
this.hoveredIndex = calculateIndex(action, this.options, this.hoveredIndex);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
element.scrollIntoView({ block: 'nearest' });
|
|
90
|
+
if (this.HoveredOption)
|
|
91
|
+
this.HoveredOption.scrollIntoView({ block: 'nearest' });
|
|
102
92
|
};
|
|
103
93
|
/**
|
|
104
94
|
* Sets the hovered option.
|
|
105
95
|
* @param value The unique value of the option.
|
|
106
96
|
*/
|
|
107
97
|
setHovered = (value) => {
|
|
108
|
-
this.hoveredIndex = this.options.findIndex((el) => el.value === value);
|
|
98
|
+
this.hoveredIndex = this.options.findIndex((el) => el.dataset.value === value);
|
|
109
99
|
};
|
|
110
100
|
/**
|
|
111
101
|
* Sets the selected option.
|
|
@@ -116,8 +106,8 @@ class SelectRoot extends Floating {
|
|
|
116
106
|
if (!this.HoveredOption)
|
|
117
107
|
return;
|
|
118
108
|
if (this.$$.multiple.val) {
|
|
119
|
-
if (this.selectedOptions.find((el) => el.value === this.HoveredOption?.value)) {
|
|
120
|
-
this.selectedOptions = this.selectedOptions.filter((el) => el.value !== this.HoveredOption?.value);
|
|
109
|
+
if (this.selectedOptions.find((el) => el.dataset.value === this.HoveredOption?.dataset.value)) {
|
|
110
|
+
this.selectedOptions = this.selectedOptions.filter((el) => el.dataset.value !== this.HoveredOption?.dataset.value);
|
|
121
111
|
}
|
|
122
112
|
else {
|
|
123
113
|
this.selectedOptions.push(this.HoveredOption);
|
|
@@ -129,8 +119,8 @@ class SelectRoot extends Floating {
|
|
|
129
119
|
if (!this.$$.multiple.val)
|
|
130
120
|
this.$$.visible.val = false;
|
|
131
121
|
this.$$.value.val = this.$$.multiple.val
|
|
132
|
-
? this.selectedOptions.map((el) => el.value)
|
|
133
|
-
: this.selectedOptions[0].value;
|
|
122
|
+
? this.selectedOptions.map((el) => el.dataset.value)
|
|
123
|
+
: this.selectedOptions[0].dataset.value;
|
|
134
124
|
};
|
|
135
125
|
/**
|
|
136
126
|
* Sets the trigger label to the selected value, only if it's found in the options array.
|
|
@@ -139,9 +129,9 @@ class SelectRoot extends Floating {
|
|
|
139
129
|
await tick();
|
|
140
130
|
const value = this.$$.value.val;
|
|
141
131
|
this.selectedOptions = this.options.filter((el) => {
|
|
142
|
-
if (!Array.isArray(value) && el.value === value)
|
|
132
|
+
if (!Array.isArray(value) && el.dataset.value === value)
|
|
143
133
|
return el;
|
|
144
|
-
else if (Array.isArray(value) && value.includes(el.value))
|
|
134
|
+
else if (Array.isArray(value) && value.includes(el.dataset.value))
|
|
145
135
|
return el;
|
|
146
136
|
});
|
|
147
137
|
this.doneMounting();
|
|
@@ -203,7 +193,7 @@ class SelectTrigger {
|
|
|
203
193
|
if (key === KEYS.enter) {
|
|
204
194
|
e.preventDefault();
|
|
205
195
|
if (this._root.HoveredOption && this._root.$$.visible.val) {
|
|
206
|
-
this._root.
|
|
196
|
+
this._root.HoveredOption?.click();
|
|
207
197
|
if (!this._root.$$.multiple.val)
|
|
208
198
|
this._root.close();
|
|
209
199
|
}
|
|
@@ -228,6 +218,17 @@ class SelectContent {
|
|
|
228
218
|
this._root = root;
|
|
229
219
|
this.$$ = props;
|
|
230
220
|
this._root.sharedIds.set('content', this.$$.id.val);
|
|
221
|
+
$effect(() => {
|
|
222
|
+
// Get element references
|
|
223
|
+
if (this._root.$$.visible.val)
|
|
224
|
+
this._root.getAvilableOptions();
|
|
225
|
+
});
|
|
226
|
+
$effect(() => {
|
|
227
|
+
// Set first selected value as highlighted option
|
|
228
|
+
if (this._root.$$.visible.val && this._root.selectedOptions.length && !this._root.HoveredOption) {
|
|
229
|
+
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.selected === 'true');
|
|
230
|
+
}
|
|
231
|
+
});
|
|
231
232
|
}
|
|
232
233
|
props = $derived.by(() => ({
|
|
233
234
|
id: this.$$.id.val,
|
|
@@ -273,17 +274,12 @@ class SelectArrow {
|
|
|
273
274
|
class SelectOption {
|
|
274
275
|
$$;
|
|
275
276
|
_root;
|
|
276
|
-
Hovered = $derived.by(() => this._root.HoveredOption?.value === this.$$.value.val);
|
|
277
|
-
Selected = $derived.by(() => !!this._root.selectedOptions.find((el) => el.value === this.$$.value.val));
|
|
277
|
+
Hovered = $derived.by(() => this._root.HoveredOption?.dataset.value === this.$$.value.val);
|
|
278
|
+
Selected = $derived.by(() => !!this._root.selectedOptions.find((el) => el.dataset.value === this.$$.value.val));
|
|
279
|
+
Label = $derived.by(() => this.$$.label.val);
|
|
278
280
|
constructor(root, props) {
|
|
279
281
|
this._root = root;
|
|
280
282
|
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
283
|
}
|
|
288
284
|
props = $derived.by(() => ({
|
|
289
285
|
id: this.$$.id.val,
|
|
@@ -294,11 +290,14 @@ class SelectOption {
|
|
|
294
290
|
tabindex: 0,
|
|
295
291
|
'aria-selected': this.Selected,
|
|
296
292
|
'data-value': this.$$.value.val,
|
|
297
|
-
'data-label': this
|
|
293
|
+
'data-label': this.Label,
|
|
298
294
|
...attach((node) => {
|
|
295
|
+
if (!this.$$.label.val && this.$$.ref.val) {
|
|
296
|
+
this.Label = this.$$.ref.val.textContent.trim();
|
|
297
|
+
}
|
|
299
298
|
// Set the hovered index to the active item, if that item is "selected".
|
|
300
299
|
if (this._root.$$.value.val === this.$$.value.val) {
|
|
301
|
-
this._root.hoveredIndex = this._root.options.findIndex((el) => el.value === this.$$.value.val);
|
|
300
|
+
this._root.hoveredIndex = this._root.options.findIndex((el) => el.dataset.value === this.$$.value.val);
|
|
302
301
|
}
|
|
303
302
|
return addEvents(node, {
|
|
304
303
|
click: () => {
|
|
@@ -327,7 +326,9 @@ class SelectValue {
|
|
|
327
326
|
this._root = root;
|
|
328
327
|
this.$$ = props;
|
|
329
328
|
}
|
|
330
|
-
label = $derived.by(() => this.PlaceholderVisible
|
|
329
|
+
label = $derived.by(() => this.PlaceholderVisible
|
|
330
|
+
? this.$$.placeholder.val
|
|
331
|
+
: this._root.selectedOptions.map((el) => el.dataset.label).join(','));
|
|
331
332
|
props = $derived.by(() => ({
|
|
332
333
|
id: this.$$.id.val,
|
|
333
334
|
[attrs.value]: '',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FloatingContent,
|
|
2
|
-
export interface SelectProps<V extends
|
|
1
|
+
import type { FloatingContent, Props, PropsNoChildren, PropsNoRender } from '../../internals/index.js';
|
|
2
|
+
export interface SelectProps<V extends string | string[] = any> extends PropsNoRender<SelectState>, FloatingContent {
|
|
3
3
|
/**
|
|
4
4
|
* The currently selected option(s).
|
|
5
5
|
*
|
|
@@ -50,7 +50,7 @@ export interface SelectOptionProps<P = any> extends Props<HTMLButtonElement, P,
|
|
|
50
50
|
/**
|
|
51
51
|
* The value of the option.
|
|
52
52
|
*/
|
|
53
|
-
value:
|
|
53
|
+
value: string;
|
|
54
54
|
/**
|
|
55
55
|
* Disables the option, skipping mouse/keyboard navigation and stopping events from firing.
|
|
56
56
|
*
|