@x33025/sveltely 0.1.2 → 0.1.4

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.
Files changed (76) hide show
  1. package/dist/components/Library/AnimatedNumber/AnimatedNumber.demo.svelte +1 -1
  2. package/dist/components/Library/AsyncButton/AsyncButton.svelte +42 -16
  3. package/dist/components/Library/Button/Button.svelte +21 -13
  4. package/dist/components/Library/Calendar/Calendar.svelte +16 -16
  5. package/dist/components/Library/Checkbox/Checkbox.svelte +13 -14
  6. package/dist/components/Library/ChipInput/ChipInput.demo.svelte +1 -1
  7. package/dist/components/Library/ChipInput/ChipInput.svelte +7 -4
  8. package/dist/components/Library/Dropdown/Action.svelte +60 -0
  9. package/dist/components/Library/Dropdown/Action.svelte.d.ts +11 -0
  10. package/dist/components/Library/Dropdown/Divider.svelte +5 -0
  11. package/dist/components/Library/Dropdown/Divider.svelte.d.ts +19 -0
  12. package/dist/components/Library/Dropdown/Dropdown.demo.svelte +182 -72
  13. package/dist/components/Library/Dropdown/Dropdown.demo.svelte.d.ts +2 -1
  14. package/dist/components/Library/Dropdown/Dropdown.svelte +78 -267
  15. package/dist/components/Library/Dropdown/Dropdown.svelte.d.ts +17 -16
  16. package/dist/components/Library/Dropdown/Item.svelte +73 -0
  17. package/dist/components/Library/Dropdown/Item.svelte.d.ts +31 -0
  18. package/dist/components/Library/Dropdown/Section.svelte +34 -0
  19. package/dist/components/Library/Dropdown/Section.svelte.d.ts +8 -0
  20. package/dist/components/Library/Dropdown/context.d.ts +34 -0
  21. package/dist/components/Library/Dropdown/context.js +6 -0
  22. package/dist/components/Library/Dropdown/index.d.ts +13 -2
  23. package/dist/components/Library/Dropdown/index.js +11 -1
  24. package/dist/components/Library/Floating/Floating.svelte +10 -7
  25. package/dist/components/Library/ImageMask/BrushPreview.svelte +6 -6
  26. package/dist/components/Library/ImageMask/ImageMask.demo.svelte +7 -7
  27. package/dist/components/Library/ImageMask/MaskLayer.svelte +3 -3
  28. package/dist/components/Library/Label/Label.svelte +2 -4
  29. package/dist/components/Library/NavigationStack/NavigationStack.svelte +17 -7
  30. package/dist/components/Library/NavigationStack/Toolbar.svelte +7 -2
  31. package/dist/components/Library/NumberField/NumberField.svelte +14 -9
  32. package/dist/components/Library/Pagination/Pagination.svelte +16 -20
  33. package/dist/components/Library/Popover/Popover.demo.svelte +2 -2
  34. package/dist/components/Library/Popover/Popover.svelte +7 -4
  35. package/dist/components/Library/ScrollView/ScrollView.svelte +140 -3
  36. package/dist/components/Library/ScrollView/ScrollView.svelte.d.ts +28 -0
  37. package/dist/components/Library/ScrollView/index.d.ts +1 -0
  38. package/dist/components/Library/{SearchInput/SearchInput.demo.svelte → SearchField/SearchField.demo.svelte} +4 -4
  39. package/dist/components/Library/SearchField/SearchField.demo.svelte.d.ts +8 -0
  40. package/dist/components/Library/{SearchInput/SearchInput.svelte → SearchField/SearchField.svelte} +26 -30
  41. package/dist/components/Library/{SearchInput/SearchInput.svelte.d.ts → SearchField/SearchField.svelte.d.ts} +3 -3
  42. package/dist/components/Library/SearchField/index.d.ts +1 -0
  43. package/dist/components/Library/SearchField/index.js +1 -0
  44. package/dist/components/Library/SegmentedPicker/SegmentedPicker.demo.svelte +1 -1
  45. package/dist/components/Library/SegmentedPicker/SegmentedPicker.svelte +9 -9
  46. package/dist/components/Library/Sheet/Sheet.demo.svelte +1 -1
  47. package/dist/components/Library/Sheet/Sheet.svelte +8 -5
  48. package/dist/components/Library/Slider/Slider.demo.svelte +1 -1
  49. package/dist/components/Library/Slider/Slider.svelte +11 -10
  50. package/dist/components/Library/Spinner/Spinner.demo.svelte +1 -1
  51. package/dist/components/Library/Switch/Switch.svelte +6 -11
  52. package/dist/components/Library/TextField/TextField.svelte +14 -9
  53. package/dist/components/Library/{TokenSearchInput/TokenSearchInput.demo.svelte → TokenSearchField/TokenSearchField.demo.svelte} +4 -4
  54. package/dist/components/Library/TokenSearchField/TokenSearchField.demo.svelte.d.ts +9 -0
  55. package/dist/components/Library/{TokenSearchInput/TokenSearchInput.svelte → TokenSearchField/TokenSearchField.svelte} +70 -66
  56. package/dist/components/Library/{TokenSearchInput/TokenSearchInput.svelte.d.ts → TokenSearchField/TokenSearchField.svelte.d.ts} +3 -3
  57. package/dist/components/Library/TokenSearchField/index.d.ts +1 -0
  58. package/dist/components/Library/TokenSearchField/index.js +1 -0
  59. package/dist/components/Library/WheelPicker/WheelColumn.svelte +4 -10
  60. package/dist/components/Library/WheelPicker/WheelPicker.svelte +5 -9
  61. package/dist/components/Local/HeroCard.svelte +5 -3
  62. package/dist/components/Local/StyleControls.svelte +58 -27
  63. package/dist/components/Local/StyleControls.svelte.d.ts +3 -1
  64. package/dist/index.d.ts +3 -2
  65. package/dist/index.js +2 -2
  66. package/dist/style/index.css +9 -5
  67. package/dist/style.css +60 -29
  68. package/package.json +1 -1
  69. package/dist/components/Library/Dropdown/types.d.ts +0 -30
  70. package/dist/components/Library/Dropdown/types.js +0 -1
  71. package/dist/components/Library/SearchInput/SearchInput.demo.svelte.d.ts +0 -8
  72. package/dist/components/Library/SearchInput/index.d.ts +0 -1
  73. package/dist/components/Library/SearchInput/index.js +0 -1
  74. package/dist/components/Library/TokenSearchInput/TokenSearchInput.demo.svelte.d.ts +0 -9
  75. package/dist/components/Library/TokenSearchInput/index.d.ts +0 -1
  76. package/dist/components/Library/TokenSearchInput/index.js +0 -1
@@ -1,145 +1,71 @@
1
- <script lang="ts" generics="T extends string | number = string">
2
- import { CheckIcon, ChevronDownIcon, ChevronRightIcon } from '@lucide/svelte';
3
- import Divider from '../Divider';
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
- items: DropdownEntry<T>[];
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
- onSearch?: (query: string) => void | Promise<void>;
29
- onSelect?: (item: DropdownItem<T>) => void;
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
- items,
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
- onSearch,
53
- onSelect,
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
- let query = $state('');
60
- let lastSearchedQuery = '';
61
-
62
- const searchEnabled = $derived(!!onSearch);
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 handleAction(item: DropdownAction) {
128
- if (disabled || item.disabled) return;
129
- item.onSelect();
130
- if (closeOnSelect) open = false;
131
- }
132
-
133
- const isEntryDisabled = (entry: { disabled?: boolean }, inheritedDisabled = false) =>
134
- disabled || inheritedDisabled || !!entry.disabled;
135
-
136
- const isRadiusSource = (label: string) => itemRadiusSourceEnabled && label === firstRenderableLabel;
137
-
138
- $effect(() => {
139
- if (!onSearch) return;
140
- if (query === lastSearchedQuery) return;
141
- lastSearchedQuery = query;
142
- void onSearch(query);
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
- <button
157
- use:floating.useTrigger
158
- type="button"
159
- class="dropdown-trigger justify-between"
160
- aria-label={label}
161
- aria-disabled={disabled}
162
- disabled={disabled}
163
- style={dropdownStyle}
164
- aria-expanded={floating.open}
165
- aria-haspopup="dialog"
166
- onclick={floating.toggle}
167
- >
168
- <span class="dropdown-trigger-label">{triggerText}</span>
169
- <ChevronDownIcon class="size-4 text-zinc-500" />
170
- </button>
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
- class="dropdown-content vstack"
175
- style={`${dropdownStyle} --dropdown-item-radius: ${searchEnabled ? 'var(--sveltely-border-radius)' : 'var(--sveltely-border-radius-nested)'};`}
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: white;
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: white;
294
- color: var(--color-zinc-800);
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: color 150ms, border-color 150ms, background-color 150ms;
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
- gap: var(--sveltely-inset);
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 type { DropdownEntry, DropdownItem } from './types';
4
- declare function $$render<T extends string | number = string>(): {
4
+ import { type DropdownTriggerState } from './context';
5
+ declare function $$render<TValue = unknown>(): {
5
6
  props: {
6
- items: DropdownEntry<T>[];
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
- onSearch?: (query: string) => void | Promise<void>;
17
- onSelect?: (item: DropdownItem<T>) => void;
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<T extends string | number = string> {
25
- props(): ReturnType<typeof $$render<T>>['props'];
26
- events(): ReturnType<typeof $$render<T>>['events'];
27
- slots(): ReturnType<typeof $$render<T>>['slots'];
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 <T extends string | number = string>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
33
- $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
34
- } & ReturnType<__sveltets_Render<T>['exports']>;
35
- <T extends string | number = string>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
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<T extends string | number = string> = InstanceType<typeof Dropdown<T>>;
40
+ type Dropdown<TValue = unknown> = InstanceType<typeof Dropdown<TValue>>;
40
41
  export default Dropdown;
@@ -0,0 +1,73 @@
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 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="dropdown-item-check 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
+
69
+ :global(.dropdown-item-check) {
70
+ margin-left: auto;
71
+ flex-shrink: 0;
72
+ }
73
+ </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,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ label?: string;
4
+ children?: Snippet;
5
+ };
6
+ declare const Section: import("svelte").Component<Props, {}, "">;
7
+ type Section = ReturnType<typeof Section>;
8
+ export default Section;
@@ -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);