@x33025/sveltely 0.1.2 → 0.1.3
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/Library/AnimatedNumber/AnimatedNumber.demo.svelte +1 -1
- package/dist/components/Library/AsyncButton/AsyncButton.svelte +42 -16
- package/dist/components/Library/Button/Button.svelte +21 -13
- package/dist/components/Library/Calendar/Calendar.svelte +16 -16
- package/dist/components/Library/Checkbox/Checkbox.svelte +13 -14
- package/dist/components/Library/ChipInput/ChipInput.demo.svelte +1 -1
- package/dist/components/Library/ChipInput/ChipInput.svelte +7 -4
- package/dist/components/Library/Dropdown/Action.svelte +60 -0
- package/dist/components/Library/Dropdown/Action.svelte.d.ts +11 -0
- package/dist/components/Library/Dropdown/Divider.svelte +5 -0
- package/dist/components/Library/Dropdown/Divider.svelte.d.ts +19 -0
- package/dist/components/Library/Dropdown/Dropdown.demo.svelte +182 -72
- package/dist/components/Library/Dropdown/Dropdown.demo.svelte.d.ts +2 -1
- package/dist/components/Library/Dropdown/Dropdown.svelte +78 -267
- package/dist/components/Library/Dropdown/Dropdown.svelte.d.ts +17 -16
- package/dist/components/Library/Dropdown/Item.svelte +68 -0
- package/dist/components/Library/Dropdown/Item.svelte.d.ts +31 -0
- package/dist/components/Library/Dropdown/Section.svelte +34 -0
- package/dist/components/Library/Dropdown/Section.svelte.d.ts +8 -0
- package/dist/components/Library/Dropdown/context.d.ts +34 -0
- package/dist/components/Library/Dropdown/context.js +6 -0
- package/dist/components/Library/Dropdown/index.d.ts +13 -2
- package/dist/components/Library/Dropdown/index.js +11 -1
- package/dist/components/Library/Floating/Floating.svelte +10 -7
- package/dist/components/Library/ImageMask/BrushPreview.svelte +6 -6
- package/dist/components/Library/ImageMask/ImageMask.demo.svelte +7 -7
- package/dist/components/Library/ImageMask/MaskLayer.svelte +3 -3
- package/dist/components/Library/Label/Label.svelte +2 -4
- package/dist/components/Library/NavigationStack/NavigationStack.svelte +17 -7
- package/dist/components/Library/NavigationStack/Toolbar.svelte +7 -2
- package/dist/components/Library/NumberField/NumberField.svelte +14 -9
- package/dist/components/Library/Pagination/Pagination.svelte +16 -20
- package/dist/components/Library/Popover/Popover.demo.svelte +2 -2
- package/dist/components/Library/Popover/Popover.svelte +7 -4
- package/dist/components/Library/ScrollView/ScrollView.svelte +140 -3
- package/dist/components/Library/ScrollView/ScrollView.svelte.d.ts +28 -0
- package/dist/components/Library/ScrollView/index.d.ts +1 -0
- package/dist/components/Library/{SearchInput/SearchInput.demo.svelte → SearchField/SearchField.demo.svelte} +4 -4
- package/dist/components/Library/SearchField/SearchField.demo.svelte.d.ts +8 -0
- package/dist/components/Library/{SearchInput/SearchInput.svelte → SearchField/SearchField.svelte} +26 -30
- package/dist/components/Library/{SearchInput/SearchInput.svelte.d.ts → SearchField/SearchField.svelte.d.ts} +3 -3
- package/dist/components/Library/SearchField/index.d.ts +1 -0
- package/dist/components/Library/SearchField/index.js +1 -0
- package/dist/components/Library/SegmentedPicker/SegmentedPicker.demo.svelte +1 -1
- package/dist/components/Library/SegmentedPicker/SegmentedPicker.svelte +9 -9
- package/dist/components/Library/Sheet/Sheet.demo.svelte +1 -1
- package/dist/components/Library/Sheet/Sheet.svelte +8 -5
- package/dist/components/Library/Slider/Slider.demo.svelte +1 -1
- package/dist/components/Library/Slider/Slider.svelte +11 -10
- package/dist/components/Library/Spinner/Spinner.demo.svelte +1 -1
- package/dist/components/Library/Switch/Switch.svelte +6 -11
- package/dist/components/Library/TextField/TextField.svelte +14 -9
- package/dist/components/Library/{TokenSearchInput/TokenSearchInput.demo.svelte → TokenSearchField/TokenSearchField.demo.svelte} +4 -4
- package/dist/components/Library/TokenSearchField/TokenSearchField.demo.svelte.d.ts +9 -0
- package/dist/components/Library/{TokenSearchInput/TokenSearchInput.svelte → TokenSearchField/TokenSearchField.svelte} +70 -66
- package/dist/components/Library/{TokenSearchInput/TokenSearchInput.svelte.d.ts → TokenSearchField/TokenSearchField.svelte.d.ts} +3 -3
- package/dist/components/Library/TokenSearchField/index.d.ts +1 -0
- package/dist/components/Library/TokenSearchField/index.js +1 -0
- package/dist/components/Library/WheelPicker/WheelColumn.svelte +4 -10
- package/dist/components/Library/WheelPicker/WheelPicker.svelte +5 -9
- package/dist/components/Local/HeroCard.svelte +5 -3
- package/dist/components/Local/StyleControls.svelte +58 -27
- package/dist/components/Local/StyleControls.svelte.d.ts +3 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/style/index.css +9 -5
- package/dist/style.css +60 -29
- package/package.json +1 -1
- package/dist/components/Library/Dropdown/types.d.ts +0 -30
- package/dist/components/Library/Dropdown/types.js +0 -1
- package/dist/components/Library/SearchInput/SearchInput.demo.svelte.d.ts +0 -8
- package/dist/components/Library/SearchInput/index.d.ts +0 -1
- package/dist/components/Library/SearchInput/index.js +0 -1
- package/dist/components/Library/TokenSearchInput/TokenSearchInput.demo.svelte.d.ts +0 -9
- package/dist/components/Library/TokenSearchInput/index.d.ts +0 -1
- package/dist/components/Library/TokenSearchInput/index.js +0 -1
|
@@ -1,145 +1,71 @@
|
|
|
1
|
-
<script lang="ts" generics="
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
<script lang="ts" generics="TValue = unknown">
|
|
2
|
+
import { ChevronDownIcon } from '@lucide/svelte';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
4
|
import Floating from '../Floating/Floating.svelte';
|
|
5
|
-
import SearchInput from '../SearchInput';
|
|
6
5
|
import { surfaceStyle, type StyleProps } from '../../../style/surface';
|
|
7
6
|
import type { Anchor } from '../../../utils/positioning';
|
|
8
|
-
import type
|
|
9
|
-
DropdownAction,
|
|
10
|
-
DropdownDivider,
|
|
11
|
-
DropdownEntry,
|
|
12
|
-
DropdownGroup,
|
|
13
|
-
DropdownItem,
|
|
14
|
-
DropdownSubmenu
|
|
15
|
-
} from './types';
|
|
7
|
+
import { setDropdownContext, type DropdownTriggerState } from './context';
|
|
16
8
|
|
|
17
9
|
type Props = {
|
|
18
|
-
|
|
19
|
-
value?: T | null;
|
|
10
|
+
value?: TValue | null;
|
|
20
11
|
open?: boolean;
|
|
21
12
|
label?: string;
|
|
22
13
|
placeholder?: string;
|
|
14
|
+
selectedLabel?: string | null;
|
|
23
15
|
disabled?: boolean;
|
|
24
16
|
closeOnSelect?: boolean;
|
|
25
17
|
showCheck?: boolean;
|
|
26
|
-
searchPlaceholder?: string;
|
|
27
18
|
placement?: Anchor;
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
trigger?: Snippet<[DropdownTriggerState<TValue>]>;
|
|
20
|
+
children?: Snippet;
|
|
21
|
+
onValueChange?: (value: TValue) => void;
|
|
30
22
|
} & StyleProps;
|
|
31
23
|
|
|
32
|
-
const isGroup = (entry: DropdownEntry<T>): entry is DropdownGroup<T> =>
|
|
33
|
-
'type' in entry && entry.type === 'group';
|
|
34
|
-
const isAction = (entry: DropdownItem<T> | DropdownAction): entry is DropdownAction =>
|
|
35
|
-
'type' in entry && entry.type === 'action';
|
|
36
|
-
const isDivider = (entry: DropdownEntry<T>): entry is DropdownDivider =>
|
|
37
|
-
'type' in entry && entry.type === 'divider';
|
|
38
|
-
const isSubmenu = (entry: DropdownEntry<T>): entry is DropdownSubmenu<T> =>
|
|
39
|
-
'type' in entry && entry.type === 'submenu';
|
|
40
|
-
|
|
41
24
|
let {
|
|
42
|
-
|
|
43
|
-
value = $bindable<T | null>(null),
|
|
25
|
+
value = $bindable<TValue | null>(null),
|
|
44
26
|
open = $bindable(false),
|
|
45
27
|
label = 'Select option',
|
|
46
28
|
placeholder = 'Select option',
|
|
29
|
+
selectedLabel = null,
|
|
47
30
|
disabled = false,
|
|
48
31
|
closeOnSelect = true,
|
|
49
32
|
showCheck = true,
|
|
50
|
-
searchPlaceholder = 'Search',
|
|
51
33
|
placement = 'bottom',
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
trigger: triggerContent,
|
|
35
|
+
children,
|
|
36
|
+
onValueChange,
|
|
54
37
|
...styleProps
|
|
55
38
|
}: Props = $props();
|
|
56
39
|
|
|
57
40
|
const dropdownStyle = $derived.by(() => surfaceStyle(styleProps, 'dropdown'));
|
|
41
|
+
const triggerText = $derived(selectedLabel ?? (value === null ? placeholder : String(value)));
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const flattenItems = (
|
|
65
|
-
entries: DropdownEntry<T>[],
|
|
66
|
-
inheritedDisabled = false
|
|
67
|
-
): DropdownItem<T>[] =>
|
|
68
|
-
entries.flatMap((entry) => {
|
|
69
|
-
if (isDivider(entry)) {
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const nextDisabled = inheritedDisabled || !!entry.disabled;
|
|
74
|
-
if (isGroup(entry) || isSubmenu(entry)) {
|
|
75
|
-
return flattenItems(entry.items, nextDisabled);
|
|
76
|
-
}
|
|
77
|
-
if (isAction(entry)) {
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
return [{ ...entry, disabled: nextDisabled || entry.disabled }];
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const findFirstRenderableLabel = (entries: DropdownEntry<T>[]): string | null => {
|
|
84
|
-
for (const entry of entries) {
|
|
85
|
-
if (isGroup(entry)) {
|
|
86
|
-
const nested = findFirstRenderableLabel(entry.items);
|
|
87
|
-
if (nested) return nested;
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (isDivider(entry)) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
return entry.label;
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const flatItems = $derived.by(() => flattenItems(items));
|
|
99
|
-
|
|
100
|
-
const selectedItem = $derived.by(
|
|
101
|
-
() => flatItems.find((item) => item.value === value) ?? null
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const triggerText = $derived(selectedItem?.label ?? placeholder);
|
|
105
|
-
|
|
106
|
-
const filteredItems = $derived(items);
|
|
107
|
-
|
|
108
|
-
const firstRenderableLabel = $derived.by(() => findFirstRenderableLabel(filteredItems));
|
|
109
|
-
|
|
110
|
-
const itemRadiusSourceEnabled = $derived.by(() => {
|
|
111
|
-
if (searchEnabled) return false;
|
|
112
|
-
const firstEntry = filteredItems[0];
|
|
113
|
-
if (!firstEntry) return false;
|
|
114
|
-
if (isGroup(firstEntry)) {
|
|
115
|
-
return !firstEntry.label;
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
function handleSelect(item: DropdownItem<T>) {
|
|
121
|
-
if (disabled || item.disabled) return;
|
|
122
|
-
value = item.value;
|
|
123
|
-
onSelect?.(item);
|
|
43
|
+
function select(nextValue: TValue) {
|
|
44
|
+
if (disabled) return;
|
|
45
|
+
value = nextValue;
|
|
46
|
+
onValueChange?.(nextValue);
|
|
124
47
|
if (closeOnSelect) open = false;
|
|
125
48
|
}
|
|
126
49
|
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
50
|
+
function close() {
|
|
51
|
+
open = false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setDropdownContext<TValue>({
|
|
55
|
+
get value() {
|
|
56
|
+
return value;
|
|
57
|
+
},
|
|
58
|
+
get disabled() {
|
|
59
|
+
return disabled;
|
|
60
|
+
},
|
|
61
|
+
get closeOnSelect() {
|
|
62
|
+
return closeOnSelect;
|
|
63
|
+
},
|
|
64
|
+
get showCheck() {
|
|
65
|
+
return showCheck;
|
|
66
|
+
},
|
|
67
|
+
select,
|
|
68
|
+
close
|
|
143
69
|
});
|
|
144
70
|
</script>
|
|
145
71
|
|
|
@@ -153,123 +79,41 @@
|
|
|
153
79
|
matchPanelRadiusToSource={true}
|
|
154
80
|
>
|
|
155
81
|
{#snippet trigger(floating)}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
<
|
|
170
|
-
|
|
82
|
+
{#if triggerContent}
|
|
83
|
+
{@render triggerContent({
|
|
84
|
+
useTrigger: floating.useTrigger,
|
|
85
|
+
open: floating.open,
|
|
86
|
+
value,
|
|
87
|
+
selectedLabel: triggerText,
|
|
88
|
+
placeholder,
|
|
89
|
+
disabled,
|
|
90
|
+
toggle: floating.toggle,
|
|
91
|
+
openPanel: floating.openPanel,
|
|
92
|
+
closePanel: floating.closePanel
|
|
93
|
+
})}
|
|
94
|
+
{:else}
|
|
95
|
+
<button
|
|
96
|
+
use:floating.useTrigger
|
|
97
|
+
type="button"
|
|
98
|
+
class="dropdown-trigger justify-between"
|
|
99
|
+
aria-label={label}
|
|
100
|
+
aria-disabled={disabled}
|
|
101
|
+
{disabled}
|
|
102
|
+
style={dropdownStyle}
|
|
103
|
+
aria-expanded={floating.open}
|
|
104
|
+
aria-haspopup="dialog"
|
|
105
|
+
onclick={floating.toggle}
|
|
106
|
+
>
|
|
107
|
+
<span class="dropdown-trigger-label">{triggerText}</span>
|
|
108
|
+
<ChevronDownIcon class="size-4 text-[var(--sveltely-secondary-color)]" />
|
|
109
|
+
</button>
|
|
110
|
+
{/if}
|
|
171
111
|
{/snippet}
|
|
172
112
|
|
|
173
|
-
<div
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
>
|
|
177
|
-
{#if searchEnabled}
|
|
178
|
-
<SearchInput
|
|
179
|
-
bind:value={query}
|
|
180
|
-
placeholder={searchPlaceholder}
|
|
181
|
-
radiusSource={true}
|
|
182
|
-
/>
|
|
113
|
+
<div class="dropdown-content vstack" style={dropdownStyle}>
|
|
114
|
+
{#if children}
|
|
115
|
+
{@render children()}
|
|
183
116
|
{/if}
|
|
184
|
-
{#snippet renderEntries(entries: DropdownEntry<T>[], inheritedDisabled = false)}
|
|
185
|
-
{#each entries as entry, index (`${index}-${entry.type ?? 'option'}-${isDivider(entry) ? 'divider' : entry.label}`)}
|
|
186
|
-
{#if isDivider(entry)}
|
|
187
|
-
<Divider />
|
|
188
|
-
{:else if isGroup(entry)}
|
|
189
|
-
<div class="dropdown-group vstack">
|
|
190
|
-
{#if entry.label}
|
|
191
|
-
<div class="dropdown-group-label">{entry.label}</div>
|
|
192
|
-
{/if}
|
|
193
|
-
{@render renderEntries(entry.items, inheritedDisabled || !!entry.disabled)}
|
|
194
|
-
</div>
|
|
195
|
-
{:else if isSubmenu(entry)}
|
|
196
|
-
<Floating
|
|
197
|
-
placement={entry.placement ?? 'right'}
|
|
198
|
-
rootClass="dropdown-submenu-root relative w-full"
|
|
199
|
-
panelClass="dropdown-panel fixed z-50 focus:outline-none"
|
|
200
|
-
panelStyle={dropdownStyle}
|
|
201
|
-
contentStyle=""
|
|
202
|
-
matchPanelRadiusToSource={true}
|
|
203
|
-
closeOnPointerLeave={true}
|
|
204
|
-
>
|
|
205
|
-
{#snippet trigger(floating)}
|
|
206
|
-
<button
|
|
207
|
-
use:floating.useTrigger
|
|
208
|
-
type="button"
|
|
209
|
-
class="dropdown-item dropdown-submenu-trigger inline-flex items-center justify-between text-left"
|
|
210
|
-
class:dropdown-item-open={floating.open}
|
|
211
|
-
data-popover-radius-source={isRadiusSource(entry.label) ? 'true' : undefined}
|
|
212
|
-
disabled={isEntryDisabled(entry, inheritedDisabled)}
|
|
213
|
-
aria-expanded={floating.open}
|
|
214
|
-
aria-haspopup="menu"
|
|
215
|
-
onmouseenter={() => {
|
|
216
|
-
if (!isEntryDisabled(entry, inheritedDisabled)) {
|
|
217
|
-
void floating.openPanel();
|
|
218
|
-
}
|
|
219
|
-
}}
|
|
220
|
-
onclick={(event) => {
|
|
221
|
-
event.stopPropagation();
|
|
222
|
-
floating.toggle();
|
|
223
|
-
}}
|
|
224
|
-
>
|
|
225
|
-
<span>{entry.label}</span>
|
|
226
|
-
<ChevronRightIcon class="size-4 text-zinc-500" />
|
|
227
|
-
</button>
|
|
228
|
-
{/snippet}
|
|
229
|
-
|
|
230
|
-
<div
|
|
231
|
-
class="dropdown-content vstack"
|
|
232
|
-
style={`${dropdownStyle} --dropdown-item-radius: var(--sveltely-border-radius-nested);`}
|
|
233
|
-
>
|
|
234
|
-
{@render renderEntries(entry.items, inheritedDisabled || !!entry.disabled)}
|
|
235
|
-
</div>
|
|
236
|
-
</Floating>
|
|
237
|
-
{:else if isAction(entry)}
|
|
238
|
-
<button
|
|
239
|
-
type="button"
|
|
240
|
-
class="dropdown-item inline-flex items-center justify-between text-left"
|
|
241
|
-
data-popover-radius-source={isRadiusSource(entry.label) ? 'true' : undefined}
|
|
242
|
-
disabled={isEntryDisabled(entry, inheritedDisabled)}
|
|
243
|
-
onclick={() =>
|
|
244
|
-
handleAction({
|
|
245
|
-
...entry,
|
|
246
|
-
disabled: inheritedDisabled || entry.disabled
|
|
247
|
-
})}
|
|
248
|
-
>
|
|
249
|
-
<span>{entry.label}</span>
|
|
250
|
-
</button>
|
|
251
|
-
{:else}
|
|
252
|
-
<button
|
|
253
|
-
type="button"
|
|
254
|
-
class="dropdown-item inline-flex items-center justify-between text-left"
|
|
255
|
-
data-popover-radius-source={isRadiusSource(entry.label) ? 'true' : undefined}
|
|
256
|
-
disabled={isEntryDisabled(entry, inheritedDisabled)}
|
|
257
|
-
onclick={() =>
|
|
258
|
-
handleSelect({
|
|
259
|
-
...entry,
|
|
260
|
-
disabled: inheritedDisabled || entry.disabled
|
|
261
|
-
})}
|
|
262
|
-
>
|
|
263
|
-
<span>{entry.label}</span>
|
|
264
|
-
{#if showCheck && entry.value === value}
|
|
265
|
-
<CheckIcon class="size-4 text-zinc-700" />
|
|
266
|
-
{/if}
|
|
267
|
-
</button>
|
|
268
|
-
{/if}
|
|
269
|
-
{/each}
|
|
270
|
-
{/snippet}
|
|
271
|
-
|
|
272
|
-
{@render renderEntries(filteredItems)}
|
|
273
117
|
</div>
|
|
274
118
|
</Floating>
|
|
275
119
|
|
|
@@ -279,7 +123,7 @@
|
|
|
279
123
|
--sveltely-nested-inset: var(--dropdown-inset);
|
|
280
124
|
border: 1px solid var(--sveltely-border-color);
|
|
281
125
|
border-radius: var(--sveltely-border-radius);
|
|
282
|
-
background:
|
|
126
|
+
background: var(--sveltely-background-color);
|
|
283
127
|
padding: var(--dropdown-inset);
|
|
284
128
|
}
|
|
285
129
|
|
|
@@ -290,13 +134,16 @@
|
|
|
290
134
|
align-items: center;
|
|
291
135
|
border: 1px solid var(--sveltely-border-color);
|
|
292
136
|
border-radius: var(--sveltely-border-radius);
|
|
293
|
-
background:
|
|
294
|
-
color: var(--
|
|
137
|
+
background: var(--sveltely-background-color);
|
|
138
|
+
color: var(--sveltely-primary-color);
|
|
295
139
|
gap: var(--sveltely-gap);
|
|
296
140
|
padding: calc(var(--sveltely-padding-y) * 0.67) var(--sveltely-padding-x);
|
|
297
141
|
font-size: 0.875rem;
|
|
298
142
|
line-height: 1.25rem;
|
|
299
|
-
transition:
|
|
143
|
+
transition:
|
|
144
|
+
color 150ms,
|
|
145
|
+
border-color 150ms,
|
|
146
|
+
background-color 150ms;
|
|
300
147
|
}
|
|
301
148
|
|
|
302
149
|
.dropdown-trigger-label {
|
|
@@ -315,22 +162,10 @@
|
|
|
315
162
|
background: var(--sveltely-hover-color);
|
|
316
163
|
}
|
|
317
164
|
|
|
318
|
-
.dropdown-group-label {
|
|
319
|
-
padding-inline: 0.25rem;
|
|
320
|
-
padding-top: 0.25rem;
|
|
321
|
-
color: var(--color-zinc-500);
|
|
322
|
-
font-size: 0.75rem;
|
|
323
|
-
line-height: 1rem;
|
|
324
|
-
font-weight: 500;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
165
|
.dropdown-content {
|
|
328
166
|
--dropdown-item-padding-x: calc(var(--sveltely-padding-x) * 0.67);
|
|
329
167
|
--dropdown-item-padding-y: calc(var(--sveltely-padding-y) * 0.33);
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
.dropdown-group {
|
|
168
|
+
--dropdown-item-radius: var(--sveltely-border-radius-nested);
|
|
334
169
|
gap: var(--sveltely-inset);
|
|
335
170
|
}
|
|
336
171
|
|
|
@@ -340,28 +175,4 @@
|
|
|
340
175
|
margin-block: calc(var(--sveltely-inset) * 0.5);
|
|
341
176
|
background: var(--sveltely-border-color);
|
|
342
177
|
}
|
|
343
|
-
|
|
344
|
-
.dropdown-item {
|
|
345
|
-
width: 100%;
|
|
346
|
-
gap: calc(var(--sveltely-inset) * 2);
|
|
347
|
-
border-radius: var(--dropdown-item-radius, var(--sveltely-border-radius-nested));
|
|
348
|
-
padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
.dropdown-item :global(*) {
|
|
352
|
-
border-radius: inherit;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
.dropdown-item:hover {
|
|
356
|
-
background: var(--sveltely-hover-color);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.dropdown-item-open {
|
|
360
|
-
background: var(--sveltely-hover-color);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
.dropdown-item:disabled {
|
|
364
|
-
cursor: not-allowed;
|
|
365
|
-
opacity: 0.5;
|
|
366
|
-
}
|
|
367
178
|
</style>
|
|
@@ -1,40 +1,41 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import { type StyleProps } from '../../../style/surface';
|
|
2
3
|
import type { Anchor } from '../../../utils/positioning';
|
|
3
|
-
import
|
|
4
|
-
declare function $$render<
|
|
4
|
+
import { type DropdownTriggerState } from './context';
|
|
5
|
+
declare function $$render<TValue = unknown>(): {
|
|
5
6
|
props: {
|
|
6
|
-
|
|
7
|
-
value?: T | null;
|
|
7
|
+
value?: TValue | null;
|
|
8
8
|
open?: boolean;
|
|
9
9
|
label?: string;
|
|
10
10
|
placeholder?: string;
|
|
11
|
+
selectedLabel?: string | null;
|
|
11
12
|
disabled?: boolean;
|
|
12
13
|
closeOnSelect?: boolean;
|
|
13
14
|
showCheck?: boolean;
|
|
14
|
-
searchPlaceholder?: string;
|
|
15
15
|
placement?: Anchor;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
trigger?: Snippet<[DropdownTriggerState<TValue>]>;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
onValueChange?: (value: TValue) => void;
|
|
18
19
|
} & StyleProps;
|
|
19
20
|
exports: {};
|
|
20
21
|
bindings: "value" | "open";
|
|
21
22
|
slots: {};
|
|
22
23
|
events: {};
|
|
23
24
|
};
|
|
24
|
-
declare class __sveltets_Render<
|
|
25
|
-
props(): ReturnType<typeof $$render<
|
|
26
|
-
events(): ReturnType<typeof $$render<
|
|
27
|
-
slots(): ReturnType<typeof $$render<
|
|
25
|
+
declare class __sveltets_Render<TValue = unknown> {
|
|
26
|
+
props(): ReturnType<typeof $$render<TValue>>['props'];
|
|
27
|
+
events(): ReturnType<typeof $$render<TValue>>['events'];
|
|
28
|
+
slots(): ReturnType<typeof $$render<TValue>>['slots'];
|
|
28
29
|
bindings(): "value" | "open";
|
|
29
30
|
exports(): {};
|
|
30
31
|
}
|
|
31
32
|
interface $$IsomorphicComponent {
|
|
32
|
-
new <
|
|
33
|
-
$$bindings?: ReturnType<__sveltets_Render<
|
|
34
|
-
} & ReturnType<__sveltets_Render<
|
|
35
|
-
<
|
|
33
|
+
new <TValue = unknown>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TValue>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TValue>['props']>, ReturnType<__sveltets_Render<TValue>['events']>, ReturnType<__sveltets_Render<TValue>['slots']>> & {
|
|
34
|
+
$$bindings?: ReturnType<__sveltets_Render<TValue>['bindings']>;
|
|
35
|
+
} & ReturnType<__sveltets_Render<TValue>['exports']>;
|
|
36
|
+
<TValue = unknown>(internal: unknown, props: ReturnType<__sveltets_Render<TValue>['props']> & {}): ReturnType<__sveltets_Render<TValue>['exports']>;
|
|
36
37
|
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
37
38
|
}
|
|
38
39
|
declare const Dropdown: $$IsomorphicComponent;
|
|
39
|
-
type Dropdown<
|
|
40
|
+
type Dropdown<TValue = unknown> = InstanceType<typeof Dropdown<TValue>>;
|
|
40
41
|
export default Dropdown;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts" generics="TValue = unknown">
|
|
2
|
+
import { CheckIcon } from '@lucide/svelte';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import { getDropdownContext, type DropdownItemState } from './context';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
value: TValue;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
showCheck?: boolean;
|
|
10
|
+
children?: Snippet<[DropdownItemState<TValue>]>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let { value, disabled = false, showCheck, children }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const dropdown = getDropdownContext<TValue>();
|
|
16
|
+
const selected = $derived(dropdown.value === value);
|
|
17
|
+
const resolvedDisabled = $derived(dropdown.disabled || disabled);
|
|
18
|
+
const resolvedShowCheck = $derived(showCheck ?? dropdown.showCheck);
|
|
19
|
+
|
|
20
|
+
function select() {
|
|
21
|
+
if (resolvedDisabled) return;
|
|
22
|
+
dropdown.select(value);
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
class="dropdown-item inline-flex items-center justify-between text-left"
|
|
29
|
+
data-popover-radius-source
|
|
30
|
+
disabled={resolvedDisabled}
|
|
31
|
+
aria-pressed={selected}
|
|
32
|
+
onclick={select}
|
|
33
|
+
>
|
|
34
|
+
{#if children}
|
|
35
|
+
{@render children({
|
|
36
|
+
value,
|
|
37
|
+
selected,
|
|
38
|
+
disabled: resolvedDisabled,
|
|
39
|
+
close: dropdown.close,
|
|
40
|
+
select
|
|
41
|
+
})}
|
|
42
|
+
{/if}
|
|
43
|
+
{#if resolvedShowCheck && selected}
|
|
44
|
+
<CheckIcon class="size-4 text-[var(--sveltely-primary-color)]" />
|
|
45
|
+
{/if}
|
|
46
|
+
</button>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
.dropdown-item {
|
|
50
|
+
width: 100%;
|
|
51
|
+
gap: calc(var(--sveltely-inset) * 2);
|
|
52
|
+
border-radius: var(--dropdown-item-radius, var(--sveltely-border-radius-nested));
|
|
53
|
+
padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.dropdown-item :global(*) {
|
|
57
|
+
border-radius: inherit;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.dropdown-item:hover {
|
|
61
|
+
background: var(--sveltely-hover-color);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.dropdown-item:disabled {
|
|
65
|
+
cursor: not-allowed;
|
|
66
|
+
opacity: 0.5;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import { type DropdownItemState } from './context';
|
|
3
|
+
declare function $$render<TValue = unknown>(): {
|
|
4
|
+
props: {
|
|
5
|
+
value: TValue;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
showCheck?: boolean;
|
|
8
|
+
children?: Snippet<[DropdownItemState<TValue>]>;
|
|
9
|
+
};
|
|
10
|
+
exports: {};
|
|
11
|
+
bindings: "";
|
|
12
|
+
slots: {};
|
|
13
|
+
events: {};
|
|
14
|
+
};
|
|
15
|
+
declare class __sveltets_Render<TValue = unknown> {
|
|
16
|
+
props(): ReturnType<typeof $$render<TValue>>['props'];
|
|
17
|
+
events(): ReturnType<typeof $$render<TValue>>['events'];
|
|
18
|
+
slots(): ReturnType<typeof $$render<TValue>>['slots'];
|
|
19
|
+
bindings(): "";
|
|
20
|
+
exports(): {};
|
|
21
|
+
}
|
|
22
|
+
interface $$IsomorphicComponent {
|
|
23
|
+
new <TValue = unknown>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TValue>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TValue>['props']>, ReturnType<__sveltets_Render<TValue>['events']>, ReturnType<__sveltets_Render<TValue>['slots']>> & {
|
|
24
|
+
$$bindings?: ReturnType<__sveltets_Render<TValue>['bindings']>;
|
|
25
|
+
} & ReturnType<__sveltets_Render<TValue>['exports']>;
|
|
26
|
+
<TValue = unknown>(internal: unknown, props: ReturnType<__sveltets_Render<TValue>['props']> & {}): ReturnType<__sveltets_Render<TValue>['exports']>;
|
|
27
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
28
|
+
}
|
|
29
|
+
declare const Item: $$IsomorphicComponent;
|
|
30
|
+
type Item<TValue = unknown> = InstanceType<typeof Item<TValue>>;
|
|
31
|
+
export default Item;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
label?: string;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
let { label, children }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div class="dropdown-section vstack">
|
|
13
|
+
{#if label}
|
|
14
|
+
<div class="dropdown-section-label">{label}</div>
|
|
15
|
+
{/if}
|
|
16
|
+
{#if children}
|
|
17
|
+
{@render children()}
|
|
18
|
+
{/if}
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<style>
|
|
22
|
+
.dropdown-section {
|
|
23
|
+
gap: var(--sveltely-inset);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.dropdown-section-label {
|
|
27
|
+
padding-inline: 0.25rem;
|
|
28
|
+
padding-top: 0.25rem;
|
|
29
|
+
color: var(--sveltely-secondary-color);
|
|
30
|
+
font-size: 0.75rem;
|
|
31
|
+
line-height: 1rem;
|
|
32
|
+
font-weight: 500;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Action } from 'svelte/action';
|
|
2
|
+
export type DropdownValue = unknown;
|
|
3
|
+
export type DropdownTriggerState<TValue = DropdownValue> = {
|
|
4
|
+
useTrigger: Action<HTMLElement>;
|
|
5
|
+
open: boolean;
|
|
6
|
+
value: TValue | null;
|
|
7
|
+
selectedLabel: string;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
disabled: boolean;
|
|
10
|
+
toggle: () => void;
|
|
11
|
+
openPanel: () => Promise<void>;
|
|
12
|
+
closePanel: () => void;
|
|
13
|
+
};
|
|
14
|
+
export type DropdownItemState<TValue = DropdownValue> = {
|
|
15
|
+
value: TValue;
|
|
16
|
+
selected: boolean;
|
|
17
|
+
disabled: boolean;
|
|
18
|
+
close: () => void;
|
|
19
|
+
select: () => void;
|
|
20
|
+
};
|
|
21
|
+
export type DropdownActionState = {
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
close: () => void;
|
|
24
|
+
};
|
|
25
|
+
export type DropdownContext<TValue = DropdownValue> = {
|
|
26
|
+
get value(): TValue | null;
|
|
27
|
+
get disabled(): boolean;
|
|
28
|
+
get closeOnSelect(): boolean;
|
|
29
|
+
get showCheck(): boolean;
|
|
30
|
+
select: (value: TValue) => void;
|
|
31
|
+
close: () => void;
|
|
32
|
+
};
|
|
33
|
+
export declare const setDropdownContext: <TValue>(context: DropdownContext<TValue>) => void;
|
|
34
|
+
export declare const getDropdownContext: <TValue>() => DropdownContext<TValue>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
const dropdownContextKey = Symbol('dropdown');
|
|
3
|
+
export const setDropdownContext = (context) => {
|
|
4
|
+
setContext(dropdownContextKey, context);
|
|
5
|
+
};
|
|
6
|
+
export const getDropdownContext = () => getContext(dropdownContextKey);
|
|
@@ -1,2 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import DropdownComponent from './Dropdown.svelte';
|
|
2
|
+
import Action from './Action.svelte';
|
|
3
|
+
import Divider from './Divider.svelte';
|
|
4
|
+
import Item from './Item.svelte';
|
|
5
|
+
import Section from './Section.svelte';
|
|
6
|
+
declare const Dropdown: typeof DropdownComponent & {
|
|
7
|
+
Action: typeof Action;
|
|
8
|
+
Divider: typeof Divider;
|
|
9
|
+
Item: typeof Item;
|
|
10
|
+
Section: typeof Section;
|
|
11
|
+
};
|
|
12
|
+
export default Dropdown;
|
|
13
|
+
export type { DropdownActionState, DropdownItemState, DropdownTriggerState } from './context';
|