svelora 3.0.1 → 3.0.2
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/Accordion/Accordion.svelte +66 -97
- package/dist/Alert/Alert.svelte +39 -64
- package/dist/Alert/Alert.svelte.d.ts +1 -1
- package/dist/Avatar/Avatar.svelte +35 -75
- package/dist/AvatarGroup/AvatarGroup.svelte +38 -55
- package/dist/Badge/Badge.svelte +28 -50
- package/dist/Banner/Banner.svelte +46 -41
- package/dist/Banner/Banner.svelte.d.ts +1 -1
- package/dist/Breadcrumb/Breadcrumb.svelte +32 -26
- package/dist/Button/Button.svelte +70 -138
- package/dist/Calendar/Calendar.svelte +94 -157
- package/dist/Calendar/Calendar.svelte.d.ts +1 -1
- package/dist/Card/Card.svelte +18 -31
- package/dist/Carousel/Carousel.svelte +118 -173
- package/dist/Checkbox/Checkbox.svelte +52 -97
- package/dist/CheckboxGroup/CheckboxGroup.svelte +62 -107
- package/dist/CheckboxGroup/CheckboxGroup.svelte.d.ts +1 -1
- package/dist/Chip/Chip.svelte +22 -34
- package/dist/CodeBlock/CodeBlock.svelte +42 -59
- package/dist/Collapsible/Collapsible.svelte +22 -38
- package/dist/Collapsible/Collapsible.svelte.d.ts +1 -1
- package/dist/Collapsible/CollapsibleTestWrapper.svelte +2 -5
- package/dist/Collapsible/CollapsibleTestWrapper.svelte.d.ts +1 -1
- package/dist/Command/Command.svelte +40 -77
- package/dist/Command/Command.svelte.d.ts +1 -1
- package/dist/Command/CommandTestWrapper.svelte +2 -10
- package/dist/Command/CommandTestWrapper.svelte.d.ts +1 -1
- package/dist/Container/Container.svelte +11 -14
- package/dist/ContextMenu/ContextMenu.svelte +51 -114
- package/dist/ContextMenu/ContextMenu.svelte.d.ts +1 -1
- package/dist/Drawer/Drawer.svelte +72 -110
- package/dist/Drawer/DrawerTriggerTestWrapper.svelte +1 -2
- package/dist/DropdownMenu/DropdownMenu.svelte +63 -124
- package/dist/DropdownMenu/DropdownMenu.svelte.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte +2 -5
- package/dist/Editor/Editor.svelte +441 -576
- package/dist/Editor/Editor.svelte.d.ts +1 -1
- package/dist/Editor/EditorUrlPrompt.svelte +40 -53
- package/dist/Editor/SlashPopup.svelte +12 -24
- package/dist/Empty/Empty.svelte +32 -63
- package/dist/FieldGroup/FieldGroup.svelte +23 -38
- package/dist/FileUpload/FileUpload.svelte +242 -320
- package/dist/FileUpload/FileUpload.svelte.d.ts +1 -1
- package/dist/Fonts/Fonts.svelte +15 -37
- package/dist/Form/Form.svelte +112 -170
- package/dist/FormField/FormField.svelte +102 -135
- package/dist/Icon/Icon.svelte +7 -32
- package/dist/Input/Input.svelte +71 -141
- package/dist/Input/Input.svelte.d.ts +2 -2
- package/dist/Kbd/Kbd.svelte +18 -34
- package/dist/Link/Link.svelte +129 -196
- package/dist/LocaleButton/LocaleButton.svelte +165 -0
- package/dist/LocaleButton/LocaleButton.svelte.d.ts +5 -0
- package/dist/LocaleButton/index.d.ts +2 -0
- package/dist/LocaleButton/index.js +1 -0
- package/dist/LocaleButton/locale-button.types.d.ts +182 -0
- package/dist/LocaleButton/locale-button.types.js +1 -0
- package/dist/LocaleButton/locale-button.variants.d.ts +61 -0
- package/dist/LocaleButton/locale-button.variants.js +34 -0
- package/dist/Modal/Modal.svelte +52 -106
- package/dist/Modal/ModalTriggerTestWrapper.svelte +1 -2
- package/dist/Pagination/Pagination.svelte +48 -92
- package/dist/Pagination/pagination.variants.d.ts +1 -1
- package/dist/PinInput/PinInput.svelte +57 -111
- package/dist/PinInput/PinInput.svelte.d.ts +1 -1
- package/dist/Popover/Popover.svelte +28 -61
- package/dist/Popover/Popover.svelte.d.ts +1 -1
- package/dist/Progress/Progress.svelte +75 -94
- package/dist/RadioGroup/RadioGroup.svelte +54 -99
- package/dist/RadioGroup/RadioGroup.svelte.d.ts +1 -1
- package/dist/Select/Select.svelte +112 -269
- package/dist/Select/Select.svelte.d.ts +1 -1
- package/dist/SelectMenu/SelectMenu.svelte +211 -409
- package/dist/SelectMenu/SelectMenu.svelte.d.ts +1 -1
- package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte +3 -6
- package/dist/Separator/Separator.svelte +29 -44
- package/dist/Skeleton/Skeleton.svelte +11 -23
- package/dist/Slideover/Slideover.svelte +52 -106
- package/dist/Slideover/SlideoverTriggerTestWrapper.svelte +1 -2
- package/dist/Slider/Slider.svelte +48 -84
- package/dist/Slider/Slider.svelte.d.ts +1 -1
- package/dist/Stepper/Stepper.svelte +139 -132
- package/dist/Stepper/Stepper.svelte.d.ts +1 -1
- package/dist/Switch/Switch.svelte +62 -98
- package/dist/Table/Table.svelte +232 -283
- package/dist/Table/table.variants.d.ts +1 -1
- package/dist/Tabs/Tabs.svelte +96 -129
- package/dist/Tabs/Tabs.svelte.d.ts +1 -1
- package/dist/Textarea/Textarea.svelte +90 -173
- package/dist/Textarea/Textarea.svelte.d.ts +1 -1
- package/dist/ThemeModeButton/ThemeModeButton.svelte +16 -38
- package/dist/Timeline/Timeline.svelte +75 -54
- package/dist/Toast/Toaster.svelte +8 -25
- package/dist/Tooltip/Tooltip.svelte +34 -66
- package/dist/Tooltip/Tooltip.svelte.d.ts +1 -1
- package/dist/Tooltip/TooltipTestWrapper.svelte +2 -5
- package/dist/User/User.svelte +33 -49
- package/dist/docs/navigation.js +6 -0
- package/dist/hooks/HookContextProbe.svelte +2 -4
- package/dist/hooks/HookContextProvider.svelte +8 -6
- package/dist/hooks/HookEmitProbe.svelte +8 -11
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/svelora-docs.data.json +4 -2
- package/package.json +16 -8
|
@@ -1,104 +1,59 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { RadioGroupProps } from './radio-group.types.js'
|
|
3
|
-
|
|
4
|
-
export type Props = RadioGroupProps
|
|
1
|
+
<script lang="ts" module>export {};
|
|
5
2
|
</script>
|
|
6
3
|
|
|
7
|
-
<script lang="ts">
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
!formFieldContext
|
|
61
|
-
? undefined
|
|
62
|
-
: hasError
|
|
63
|
-
? `${formFieldContext.ariaId}-error`
|
|
64
|
-
: `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
const slots = $derived(
|
|
68
|
-
radioGroupVariants({
|
|
69
|
-
color: resolvedColor,
|
|
70
|
-
size: resolvedSize,
|
|
71
|
-
variant,
|
|
72
|
-
indicator,
|
|
73
|
-
orientation,
|
|
74
|
-
loading,
|
|
75
|
-
required,
|
|
76
|
-
disabled: isDisabled ? true : undefined
|
|
77
|
-
})
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
const layoutClasses = $derived.by(() => ({
|
|
81
|
-
root: slots.root({ class: [config.slots.root, className, ui?.root] }),
|
|
82
|
-
fieldset: slots.fieldset({ class: [config.slots.fieldset, ui?.fieldset] }),
|
|
83
|
-
legend: slots.legend({ class: [config.slots.legend, ui?.legend] }),
|
|
84
|
-
item: slots.item({ class: [config.slots.item, ui?.item] }),
|
|
85
|
-
container: slots.container({ class: [config.slots.container, ui?.container] }),
|
|
86
|
-
wrapper: slots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] })
|
|
87
|
-
}))
|
|
88
|
-
|
|
89
|
-
const elementClasses = $derived.by(() => ({
|
|
90
|
-
base: slots.base({ class: [config.slots.base, ui?.base] }),
|
|
91
|
-
indicator: slots.indicator({ class: [config.slots.indicator, ui?.indicator] }),
|
|
92
|
-
loadingIcon: slots.loadingIcon({ class: [config.slots.loadingIcon, ui?.loadingIcon] }),
|
|
93
|
-
label: slots.label({ class: [config.slots.label, ui?.label] }),
|
|
94
|
-
description: slots.description({ class: [config.slots.description, ui?.description] })
|
|
95
|
-
}))
|
|
96
|
-
|
|
97
|
-
function handleCardItemClick(e: MouseEvent, btnId: string, itemDisabled: boolean) {
|
|
98
|
-
if (itemDisabled) return
|
|
99
|
-
if ((e.target as Element).closest('button')) return
|
|
100
|
-
document.getElementById(btnId)?.click()
|
|
101
|
-
}
|
|
4
|
+
<script lang="ts">import { Label, RadioGroup, useId } from "bits-ui";
|
|
5
|
+
import { getComponentConfig, iconsDefaults } from "../config.js";
|
|
6
|
+
import { useFormField, useFormFieldEmit } from "../hooks/useFormField.svelte.js";
|
|
7
|
+
import Icon from "../Icon/Icon.svelte";
|
|
8
|
+
import { radioGroupDefaults, radioGroupVariants } from "./radio-group.variants.js";
|
|
9
|
+
const config = getComponentConfig("radioGroup", radioGroupDefaults);
|
|
10
|
+
const icons = getComponentConfig("icons", iconsDefaults);
|
|
11
|
+
let { ref = $bindable(null), value = $bindable(""), onValueChange, items = [], ui, id, name, color = config.defaultVariants.color, size, variant = config.defaultVariants.variant, indicator = config.defaultVariants.indicator, orientation = config.defaultVariants.orientation, disabled = false, required = false, readonly = false, loop = true, loading = false, loadingIcon = icons.loading, legend, legendSlot, labelSlot, descriptionSlot, class: className, ...restProps } = $props();
|
|
12
|
+
const formFieldContext = useFormField();
|
|
13
|
+
const emit = useFormFieldEmit();
|
|
14
|
+
const hasError = $derived(formFieldContext?.error !== undefined && formFieldContext?.error !== false);
|
|
15
|
+
const resolvedSize = $derived(size ?? formFieldContext?.size ?? config.defaultVariants.size);
|
|
16
|
+
const resolvedColor = $derived(hasError ? "error" : color);
|
|
17
|
+
const autoId = useId();
|
|
18
|
+
const resolvedId = $derived(id ?? formFieldContext?.ariaId ?? autoId);
|
|
19
|
+
const resolvedName = $derived(name ?? formFieldContext?.name);
|
|
20
|
+
const isDisabled = $derived(disabled || loading);
|
|
21
|
+
const legendId = $derived(`${resolvedId}-legend`);
|
|
22
|
+
const ariaDescribedBy = $derived(!formFieldContext ? undefined : hasError ? `${formFieldContext.ariaId}-error` : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`);
|
|
23
|
+
const slots = $derived(radioGroupVariants({
|
|
24
|
+
color: resolvedColor,
|
|
25
|
+
size: resolvedSize,
|
|
26
|
+
variant,
|
|
27
|
+
indicator,
|
|
28
|
+
orientation,
|
|
29
|
+
loading,
|
|
30
|
+
required,
|
|
31
|
+
disabled: isDisabled ? true : undefined
|
|
32
|
+
}));
|
|
33
|
+
const layoutClasses = $derived.by(() => ({
|
|
34
|
+
root: slots.root({ class: [
|
|
35
|
+
config.slots.root,
|
|
36
|
+
className,
|
|
37
|
+
ui?.root
|
|
38
|
+
] }),
|
|
39
|
+
fieldset: slots.fieldset({ class: [config.slots.fieldset, ui?.fieldset] }),
|
|
40
|
+
legend: slots.legend({ class: [config.slots.legend, ui?.legend] }),
|
|
41
|
+
item: slots.item({ class: [config.slots.item, ui?.item] }),
|
|
42
|
+
container: slots.container({ class: [config.slots.container, ui?.container] }),
|
|
43
|
+
wrapper: slots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] })
|
|
44
|
+
}));
|
|
45
|
+
const elementClasses = $derived.by(() => ({
|
|
46
|
+
base: slots.base({ class: [config.slots.base, ui?.base] }),
|
|
47
|
+
indicator: slots.indicator({ class: [config.slots.indicator, ui?.indicator] }),
|
|
48
|
+
loadingIcon: slots.loadingIcon({ class: [config.slots.loadingIcon, ui?.loadingIcon] }),
|
|
49
|
+
label: slots.label({ class: [config.slots.label, ui?.label] }),
|
|
50
|
+
description: slots.description({ class: [config.slots.description, ui?.description] })
|
|
51
|
+
}));
|
|
52
|
+
function handleCardItemClick(e, btnId, itemDisabled) {
|
|
53
|
+
if (itemDisabled) return;
|
|
54
|
+
if (e.target.closest("button")) return;
|
|
55
|
+
document.getElementById(btnId)?.click();
|
|
56
|
+
}
|
|
102
57
|
</script>
|
|
103
58
|
|
|
104
59
|
{#snippet itemContent(radioItem: RadioGroupItem)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RadioGroupProps } from './radio-group.types.js';
|
|
2
2
|
export type Props = RadioGroupProps;
|
|
3
3
|
import { RadioGroup } from 'bits-ui';
|
|
4
|
-
declare const RadioGroup: import("svelte").Component<RadioGroupProps, {}, "
|
|
4
|
+
declare const RadioGroup: import("svelte").Component<RadioGroupProps, {}, "ref" | "value">;
|
|
5
5
|
type RadioGroup = ReturnType<typeof RadioGroup>;
|
|
6
6
|
export default RadioGroup;
|
|
@@ -1,274 +1,117 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { SelectItem, SelectItemType, SelectProps } from './select.types.js'
|
|
3
|
-
|
|
4
|
-
export type Props = SelectProps
|
|
1
|
+
<script lang="ts" module>export {};
|
|
5
2
|
</script>
|
|
6
3
|
|
|
7
|
-
<script lang="ts">
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
// ---- Selection (single + multiple) ----
|
|
121
|
-
const selectedValues = $derived(
|
|
122
|
-
multiple
|
|
123
|
-
? Array.isArray(value)
|
|
124
|
-
? (value as string[])
|
|
125
|
-
: []
|
|
126
|
-
: typeof value === 'string' && value !== ''
|
|
127
|
-
? [value]
|
|
128
|
-
: []
|
|
129
|
-
)
|
|
130
|
-
const selectedItems = $derived(
|
|
131
|
-
selectedValues.map((v) => itemsMap.get(v)).filter((i): i is SelectItem => i !== undefined)
|
|
132
|
-
)
|
|
133
|
-
const hasSelection = $derived(selectedValues.length > 0)
|
|
134
|
-
const singleSelectedItem = $derived(multiple ? undefined : selectedItems[0])
|
|
135
|
-
const displayLabel = $derived(
|
|
136
|
-
multiple
|
|
137
|
-
? selectedItems.map((i) => i.label ?? i.value).join(separator)
|
|
138
|
-
: (singleSelectedItem?.label ?? singleSelectedItem?.value ?? '')
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
function removeValue(val: string) {
|
|
142
|
-
if (!multiple) return
|
|
143
|
-
value = selectedValues.filter((v) => v !== val)
|
|
144
|
-
emit.onChange()
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function clearSelection() {
|
|
148
|
-
if (!multiple) return
|
|
149
|
-
value = []
|
|
150
|
-
emit.onChange()
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// ---- Leading / trailing ----
|
|
154
|
-
const displayAvatar = $derived(multiple ? avatar : (singleSelectedItem?.avatar ?? avatar))
|
|
155
|
-
const displayIcon = $derived(
|
|
156
|
-
multiple ? (leadingIcon ?? icon) : (singleSelectedItem?.icon ?? leadingIcon ?? icon)
|
|
157
|
-
)
|
|
158
|
-
const isLeading = $derived(!!leadingSlot || !!displayAvatar || !!displayIcon)
|
|
159
|
-
const leadingIconName = $derived(
|
|
160
|
-
loading && isLeading ? loadingIcon : !displayAvatar ? displayIcon : undefined
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
// ---- bits-ui items for typeahead ----
|
|
164
|
-
const bitsItems = $derived(
|
|
165
|
-
[...itemsMap.values()].map((i) => ({
|
|
166
|
-
value: i.value,
|
|
167
|
-
label: i.label ?? i.value,
|
|
168
|
-
disabled: i.disabled
|
|
169
|
-
}))
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
// ---- Trailing icon ----
|
|
173
|
-
const trailingIconName = $derived(loading && !isLeading ? loadingIcon : trailingIcon)
|
|
174
|
-
const trailingIconClass = $derived(
|
|
175
|
-
`${loading && !isLeading ? 'animate-spin' : 'transition-transform'} ${open && !loading ? 'rotate-180' : ''}`
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
// ---- Variant slots ----
|
|
179
|
-
const variantSlots = $derived(
|
|
180
|
-
selectVariants({
|
|
181
|
-
variant,
|
|
182
|
-
color: resolvedColor,
|
|
183
|
-
size: resolvedSize,
|
|
184
|
-
leading: isLeading,
|
|
185
|
-
trailing: true,
|
|
186
|
-
loading,
|
|
187
|
-
highlight: resolvedHighlight,
|
|
188
|
-
side,
|
|
189
|
-
transition
|
|
190
|
-
})
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
// ---- Trigger classes (root, base, leading, trailing, value, placeholder) ----
|
|
194
|
-
const rootClass = $derived(
|
|
195
|
-
variantSlots.root({
|
|
196
|
-
class: [config.slots.root, fieldGroupClass?.root, className, ui?.root]
|
|
197
|
-
})
|
|
198
|
-
)
|
|
199
|
-
const baseClass = $derived(
|
|
200
|
-
variantSlots.base({
|
|
201
|
-
class: [config.slots.base, fieldGroupClass?.base, ui?.base]
|
|
202
|
-
})
|
|
203
|
-
)
|
|
204
|
-
const leadingClass = $derived(
|
|
205
|
-
variantSlots.leading({ class: [config.slots.leading, ui?.leading] })
|
|
206
|
-
)
|
|
207
|
-
const leadingIconClass = $derived(
|
|
208
|
-
variantSlots.leadingIcon({ class: [config.slots.leadingIcon, ui?.leadingIcon] })
|
|
209
|
-
)
|
|
210
|
-
const leadingAvatarClass = $derived(
|
|
211
|
-
variantSlots.leadingAvatar({ class: [config.slots.leadingAvatar, ui?.leadingAvatar] })
|
|
212
|
-
)
|
|
213
|
-
const leadingAvatarSizeClass = $derived(variantSlots.leadingAvatarSize() as AvatarSize)
|
|
214
|
-
const trailingClass = $derived(
|
|
215
|
-
variantSlots.trailing({ class: [config.slots.trailing, ui?.trailing] })
|
|
216
|
-
)
|
|
217
|
-
const trailingIconBaseClass = $derived(
|
|
218
|
-
variantSlots.trailingIcon({ class: [config.slots.trailingIcon, ui?.trailingIcon] })
|
|
219
|
-
)
|
|
220
|
-
const valueClass = $derived(variantSlots.value({ class: [config.slots.value, ui?.value] }))
|
|
221
|
-
const placeholderClass = $derived(
|
|
222
|
-
variantSlots.placeholder({ class: [config.slots.placeholder, ui?.placeholder] })
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
// ---- Content classes ----
|
|
226
|
-
const contentClass = $derived(
|
|
227
|
-
variantSlots.content({ class: [config.slots.content, ui?.content] })
|
|
228
|
-
)
|
|
229
|
-
const viewportClass = $derived(
|
|
230
|
-
variantSlots.viewport({ class: [config.slots.viewport, ui?.viewport] })
|
|
231
|
-
)
|
|
232
|
-
const groupLabelClass = $derived(
|
|
233
|
-
variantSlots.groupLabel({ class: [config.slots.groupLabel, ui?.groupLabel] })
|
|
234
|
-
)
|
|
235
|
-
const separatorClass = $derived(
|
|
236
|
-
variantSlots.separator({ class: [config.slots.separator, ui?.separator] })
|
|
237
|
-
)
|
|
238
|
-
|
|
239
|
-
// ---- Item classes ----
|
|
240
|
-
const itemClass = $derived(variantSlots.item({ class: [config.slots.item, ui?.item] }))
|
|
241
|
-
const itemIconClass = $derived(
|
|
242
|
-
variantSlots.itemIcon({ class: [config.slots.itemIcon, ui?.itemIcon] })
|
|
243
|
-
)
|
|
244
|
-
const itemAvatarClass = $derived(
|
|
245
|
-
variantSlots.itemAvatar({ class: [config.slots.itemAvatar, ui?.itemAvatar] })
|
|
246
|
-
)
|
|
247
|
-
const itemAvatarSizeClass = $derived(variantSlots.itemAvatarSize() as AvatarSize)
|
|
248
|
-
const itemLabelClass = $derived(
|
|
249
|
-
variantSlots.itemLabel({ class: [config.slots.itemLabel, ui?.itemLabel] })
|
|
250
|
-
)
|
|
251
|
-
const itemDescriptionClass = $derived(
|
|
252
|
-
variantSlots.itemDescription({
|
|
253
|
-
class: [config.slots.itemDescription, ui?.itemDescription]
|
|
254
|
-
})
|
|
255
|
-
)
|
|
256
|
-
const itemIndicatorClass = $derived(
|
|
257
|
-
variantSlots.itemIndicator({ class: [config.slots.itemIndicator, ui?.itemIndicator] })
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
// ---- Type guards ----
|
|
261
|
-
function isSelectItem(item: SelectItemType): item is SelectItem {
|
|
262
|
-
return !('type' in item)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function isSeparator(item: SelectItemType): item is { type: 'separator' } {
|
|
266
|
-
return 'type' in item && item.type === 'separator'
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function isLabel(item: SelectItemType): item is { type: 'label'; label: string } {
|
|
270
|
-
return 'type' in item && item.type === 'label'
|
|
271
|
-
}
|
|
4
|
+
<script lang="ts">import { Select } from "bits-ui";
|
|
5
|
+
import { getContext } from "svelte";
|
|
6
|
+
import Avatar from "../Avatar/Avatar.svelte";
|
|
7
|
+
import { getComponentConfig, iconsDefaults } from "../config.js";
|
|
8
|
+
import { fieldGroupVariantWithRoot } from "../FieldGroup/field-group.variants.js";
|
|
9
|
+
import { useFormField, useFormFieldEmit } from "../hooks/useFormField.svelte.js";
|
|
10
|
+
import Icon from "../Icon/Icon.svelte";
|
|
11
|
+
import { selectDefaults, selectVariants } from "./select.variants.js";
|
|
12
|
+
const config = getComponentConfig("select", selectDefaults);
|
|
13
|
+
const icons = getComponentConfig("icons", iconsDefaults);
|
|
14
|
+
let { ref = $bindable(null), value = $bindable(), open = $bindable(false), onOpenChange, items = [], placeholder, name, required = false, disabled = false, multiple = false, separator = ", ", ui, id, color = config.defaultVariants.color, variant = config.defaultVariants.variant, size, highlight, loading = false, loadingIcon = icons.loading, icon, leadingIcon, trailingIcon = icons.chevronDown, selectedIcon = icons.check, avatar, transition = config.defaultVariants.transition ?? true, portal = true, side = config.defaultVariants.side ?? "bottom", sideOffset = 4, align = "start", alignOffset = 0, avoidCollisions = true, collisionBoundary, collisionPadding = 8, onEscapeKeydown, onInteractOutside, forceMount, loop = true, class: className, leadingSlot, trailingSlot, item: itemSlot, itemLeading, itemLabel: itemLabelSlot, itemTrailing, selected: selectedSlot, content: contentSlot, ...restProps } = $props();
|
|
15
|
+
// ---- Form context ----
|
|
16
|
+
const formFieldContext = useFormField();
|
|
17
|
+
const emit = useFormFieldEmit();
|
|
18
|
+
const fieldGroupContext = getContext("fieldGroup");
|
|
19
|
+
const hasError = $derived(formFieldContext?.error !== undefined && formFieldContext?.error !== false);
|
|
20
|
+
const resolvedSize = $derived(size ?? formFieldContext?.size ?? fieldGroupContext?.size ?? config.defaultVariants.size);
|
|
21
|
+
const resolvedColor = $derived(hasError ? "error" : color);
|
|
22
|
+
const resolvedHighlight = $derived(highlight ?? hasError);
|
|
23
|
+
const fieldGroupClass = $derived(fieldGroupContext ? fieldGroupVariantWithRoot.fieldGroup[fieldGroupContext.orientation ?? "horizontal"] : undefined);
|
|
24
|
+
const resolvedId = $derived(id ?? formFieldContext?.ariaId);
|
|
25
|
+
const resolvedName = $derived(name ?? formFieldContext?.name);
|
|
26
|
+
// ---- ARIA ----
|
|
27
|
+
const ariaDescribedBy = $derived(!formFieldContext ? undefined : hasError ? `${formFieldContext.ariaId}-error` : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`);
|
|
28
|
+
// ---- Items lookup (O(1) via Map) ----
|
|
29
|
+
const itemsMap = $derived(new Map(items.filter((i) => !("type" in i)).map((i) => [i.value, i])));
|
|
30
|
+
// ---- Selection (single + multiple) ----
|
|
31
|
+
const selectedValues = $derived(multiple ? Array.isArray(value) ? value : [] : typeof value === "string" && value !== "" ? [value] : []);
|
|
32
|
+
const selectedItems = $derived(selectedValues.map((v) => itemsMap.get(v)).filter((i) => i !== undefined));
|
|
33
|
+
const hasSelection = $derived(selectedValues.length > 0);
|
|
34
|
+
const singleSelectedItem = $derived(multiple ? undefined : selectedItems[0]);
|
|
35
|
+
const displayLabel = $derived(multiple ? selectedItems.map((i) => i.label ?? i.value).join(separator) : singleSelectedItem?.label ?? singleSelectedItem?.value ?? "");
|
|
36
|
+
function removeValue(val) {
|
|
37
|
+
if (!multiple) return;
|
|
38
|
+
value = selectedValues.filter((v) => v !== val);
|
|
39
|
+
emit.onChange();
|
|
40
|
+
}
|
|
41
|
+
function clearSelection() {
|
|
42
|
+
if (!multiple) return;
|
|
43
|
+
value = [];
|
|
44
|
+
emit.onChange();
|
|
45
|
+
}
|
|
46
|
+
// ---- Leading / trailing ----
|
|
47
|
+
const displayAvatar = $derived(multiple ? avatar : singleSelectedItem?.avatar ?? avatar);
|
|
48
|
+
const displayIcon = $derived(multiple ? leadingIcon ?? icon : singleSelectedItem?.icon ?? leadingIcon ?? icon);
|
|
49
|
+
const isLeading = $derived(!!leadingSlot || !!displayAvatar || !!displayIcon);
|
|
50
|
+
const leadingIconName = $derived(loading && isLeading ? loadingIcon : !displayAvatar ? displayIcon : undefined);
|
|
51
|
+
// ---- bits-ui items for typeahead ----
|
|
52
|
+
const bitsItems = $derived([...itemsMap.values()].map((i) => ({
|
|
53
|
+
value: i.value,
|
|
54
|
+
label: i.label ?? i.value,
|
|
55
|
+
disabled: i.disabled
|
|
56
|
+
})));
|
|
57
|
+
// ---- Trailing icon ----
|
|
58
|
+
const trailingIconName = $derived(loading && !isLeading ? loadingIcon : trailingIcon);
|
|
59
|
+
const trailingIconClass = $derived(`${loading && !isLeading ? "animate-spin" : "transition-transform"} ${open && !loading ? "rotate-180" : ""}`);
|
|
60
|
+
// ---- Variant slots ----
|
|
61
|
+
const variantSlots = $derived(selectVariants({
|
|
62
|
+
variant,
|
|
63
|
+
color: resolvedColor,
|
|
64
|
+
size: resolvedSize,
|
|
65
|
+
leading: isLeading,
|
|
66
|
+
trailing: true,
|
|
67
|
+
loading,
|
|
68
|
+
highlight: resolvedHighlight,
|
|
69
|
+
side,
|
|
70
|
+
transition
|
|
71
|
+
}));
|
|
72
|
+
// ---- Trigger classes (root, base, leading, trailing, value, placeholder) ----
|
|
73
|
+
const rootClass = $derived(variantSlots.root({ class: [
|
|
74
|
+
config.slots.root,
|
|
75
|
+
fieldGroupClass?.root,
|
|
76
|
+
className,
|
|
77
|
+
ui?.root
|
|
78
|
+
] }));
|
|
79
|
+
const baseClass = $derived(variantSlots.base({ class: [
|
|
80
|
+
config.slots.base,
|
|
81
|
+
fieldGroupClass?.base,
|
|
82
|
+
ui?.base
|
|
83
|
+
] }));
|
|
84
|
+
const leadingClass = $derived(variantSlots.leading({ class: [config.slots.leading, ui?.leading] }));
|
|
85
|
+
const leadingIconClass = $derived(variantSlots.leadingIcon({ class: [config.slots.leadingIcon, ui?.leadingIcon] }));
|
|
86
|
+
const leadingAvatarClass = $derived(variantSlots.leadingAvatar({ class: [config.slots.leadingAvatar, ui?.leadingAvatar] }));
|
|
87
|
+
const leadingAvatarSizeClass = $derived(variantSlots.leadingAvatarSize());
|
|
88
|
+
const trailingClass = $derived(variantSlots.trailing({ class: [config.slots.trailing, ui?.trailing] }));
|
|
89
|
+
const trailingIconBaseClass = $derived(variantSlots.trailingIcon({ class: [config.slots.trailingIcon, ui?.trailingIcon] }));
|
|
90
|
+
const valueClass = $derived(variantSlots.value({ class: [config.slots.value, ui?.value] }));
|
|
91
|
+
const placeholderClass = $derived(variantSlots.placeholder({ class: [config.slots.placeholder, ui?.placeholder] }));
|
|
92
|
+
// ---- Content classes ----
|
|
93
|
+
const contentClass = $derived(variantSlots.content({ class: [config.slots.content, ui?.content] }));
|
|
94
|
+
const viewportClass = $derived(variantSlots.viewport({ class: [config.slots.viewport, ui?.viewport] }));
|
|
95
|
+
const groupLabelClass = $derived(variantSlots.groupLabel({ class: [config.slots.groupLabel, ui?.groupLabel] }));
|
|
96
|
+
const separatorClass = $derived(variantSlots.separator({ class: [config.slots.separator, ui?.separator] }));
|
|
97
|
+
// ---- Item classes ----
|
|
98
|
+
const itemClass = $derived(variantSlots.item({ class: [config.slots.item, ui?.item] }));
|
|
99
|
+
const itemIconClass = $derived(variantSlots.itemIcon({ class: [config.slots.itemIcon, ui?.itemIcon] }));
|
|
100
|
+
const itemAvatarClass = $derived(variantSlots.itemAvatar({ class: [config.slots.itemAvatar, ui?.itemAvatar] }));
|
|
101
|
+
const itemAvatarSizeClass = $derived(variantSlots.itemAvatarSize());
|
|
102
|
+
const itemLabelClass = $derived(variantSlots.itemLabel({ class: [config.slots.itemLabel, ui?.itemLabel] }));
|
|
103
|
+
const itemDescriptionClass = $derived(variantSlots.itemDescription({ class: [config.slots.itemDescription, ui?.itemDescription] }));
|
|
104
|
+
const itemIndicatorClass = $derived(variantSlots.itemIndicator({ class: [config.slots.itemIndicator, ui?.itemIndicator] }));
|
|
105
|
+
// ---- Type guards ----
|
|
106
|
+
function isSelectItem(item) {
|
|
107
|
+
return !("type" in item);
|
|
108
|
+
}
|
|
109
|
+
function isSeparator(item) {
|
|
110
|
+
return "type" in item && item.type === "separator";
|
|
111
|
+
}
|
|
112
|
+
function isLabel(item) {
|
|
113
|
+
return "type" in item && item.type === "label";
|
|
114
|
+
}
|
|
272
115
|
</script>
|
|
273
116
|
|
|
274
117
|
{#snippet renderItem(item: SelectItem, index: number)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SelectProps } from './select.types.js';
|
|
2
2
|
export type Props = SelectProps;
|
|
3
3
|
import { Select } from 'bits-ui';
|
|
4
|
-
declare const Select: import("svelte").Component<SelectProps, {}, "
|
|
4
|
+
declare const Select: import("svelte").Component<SelectProps, {}, "open" | "ref" | "value">;
|
|
5
5
|
type Select = ReturnType<typeof Select>;
|
|
6
6
|
export default Select;
|