@ibobbyts/svelte-ui-utils 0.2.11 → 0.2.12

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
@@ -76,6 +76,14 @@ import { ToastManager, Dropdown, DropdownSearch, Dialog, DataTable } from '@ibob
76
76
  Supported positions are `top-left`, `top-center`, `top-right`, `right-center`,
77
77
  `bottom-right`, `bottom-center`, `bottom-left`, and `left-center`.
78
78
 
79
+ ## Dropdown
80
+
81
+ Dropdown menus default to `placement="auto"` and open toward whichever side of
82
+ the trigger has more available viewport space. The direction is recalculated
83
+ while the menu is open when the viewport is resized or a scroll container
84
+ moves. Set `placement="up"` or `placement="down"` to force a direction. Use
85
+ `fitViewport={true}` as well to constrain the panel height to the chosen side.
86
+
79
87
  ## DropdownSearch
80
88
 
81
89
  ```svelte
@@ -279,6 +287,13 @@ scrollable when its contents exceed that height. When `fitViewport` is enabled,
279
287
  the component replaces that default with the space available above or below the
280
288
  trigger.
281
289
 
290
+ The original flat `options` API and all default behavior remain unchanged. New
291
+ callers may opt into grouped options with `optionGroups`; each group can have an
292
+ optional accessible label and its options keep the same keyboard and disabled
293
+ semantics. `width`, `minWidth`, `maxWidth`, and `className` are optional styling
294
+ hooks. `onTriggerClick` runs before the dropdown toggles, so a nested control
295
+ can stop event propagation without preventing the dropdown from opening.
296
+
282
297
  ## DataTable
283
298
 
284
299
  ```svelte
@@ -2,18 +2,32 @@
2
2
 
3
3
  <script lang="ts">
4
4
  import { onDestroy, tick } from 'svelte';
5
- import type { DropdownChangeHandler, DropdownMenuAlign, DropdownOption, DropdownPlacement, DropdownValue } from './types.js';
5
+ import type {
6
+ DropdownChangeHandler,
7
+ DropdownMenuAlign,
8
+ DropdownOption,
9
+ DropdownOptionGroup,
10
+ DropdownPlacement,
11
+ DropdownTriggerClickHandler,
12
+ DropdownValue
13
+ } from './types.js';
6
14
 
7
15
  export let id: string | undefined = undefined;
8
16
  export let value: DropdownValue = '';
9
17
  export let options: DropdownOption[] = [];
18
+ export let optionGroups: DropdownOptionGroup[] | undefined = undefined;
10
19
  export let ariaLabel: string | undefined = undefined;
11
- export let placement: DropdownPlacement = 'down';
20
+ export let placement: DropdownPlacement = 'auto';
12
21
  export let menuAlign: DropdownMenuAlign = 'right';
13
22
  export let fitViewport = false;
14
23
  export let fitContent = false;
15
24
  export let disabled = false;
25
+ export let width: string | undefined = undefined;
26
+ export let minWidth: string | undefined = undefined;
27
+ export let maxWidth: string | undefined = undefined;
28
+ export let className: string | undefined = undefined;
16
29
  export let onChange: DropdownChangeHandler | undefined = undefined;
30
+ export let onTriggerClick: DropdownTriggerClickHandler | undefined = undefined;
17
31
 
18
32
  const viewportMargin = 20;
19
33
  const menuGap = 6;
@@ -22,10 +36,12 @@
22
36
  let activeValue: DropdownValue = value;
23
37
  let dropdownElement: HTMLSpanElement | undefined;
24
38
  let buttonElement: HTMLButtonElement | undefined;
39
+ let resolvedPlacement: Exclude<DropdownPlacement, 'auto'> = placement === 'up' ? 'up' : 'down';
25
40
  let viewportPanelMaxHeight: string | undefined = undefined;
26
41
  let removeOpenViewportListeners: (() => void) | undefined = undefined;
27
42
 
28
- $: selectedOption = options.find((option) => option.value === value);
43
+ $: resolvedOptions = optionGroups === undefined ? options : optionGroups.flatMap((group) => group.options);
44
+ $: selectedOption = resolvedOptions.find((option) => option.value === value);
29
45
  $: selectedText = selectedOption?.label ?? String(value);
30
46
  $: if (!open) {
31
47
  activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
@@ -37,28 +53,29 @@
37
53
  void updateViewportPanelMaxHeight();
38
54
  } else {
39
55
  disableOpenViewportTracking();
56
+ resolvedPlacement = placement === 'up' ? 'up' : 'down';
40
57
  viewportPanelMaxHeight = undefined;
41
58
  }
42
59
  }
43
60
 
44
61
  function firstEnabledOption(): DropdownOption | undefined {
45
- return options.find((option) => !option.disabled);
62
+ return resolvedOptions.find((option) => !option.disabled);
46
63
  }
47
64
 
48
65
  function activeOptionIndex(nextActiveValue: DropdownValue): number {
49
- const index = options.findIndex((option) => option.value === nextActiveValue && !option.disabled);
66
+ const index = resolvedOptions.findIndex((option) => option.value === nextActiveValue && !option.disabled);
50
67
  if (index >= 0) {
51
68
  return index;
52
69
  }
53
- const fallbackIndex = options.findIndex((option) => option.value === value && !option.disabled);
70
+ const fallbackIndex = resolvedOptions.findIndex((option) => option.value === value && !option.disabled);
54
71
  if (fallbackIndex >= 0) {
55
72
  return fallbackIndex;
56
73
  }
57
- return options.findIndex((option) => !option.disabled);
74
+ return resolvedOptions.findIndex((option) => !option.disabled);
58
75
  }
59
76
 
60
77
  function moveActiveOption(offset: number) {
61
- const enabledOptions = options.filter((option) => !option.disabled);
78
+ const enabledOptions = resolvedOptions.filter((option) => !option.disabled);
62
79
  if (enabledOptions.length === 0) {
63
80
  return;
64
81
  }
@@ -82,10 +99,18 @@
82
99
  if (disabled) {
83
100
  return;
84
101
  }
102
+ if (!open) {
103
+ updateResolvedPlacement();
104
+ }
85
105
  open = !open;
86
106
  activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
87
107
  }
88
108
 
109
+ function handleTriggerClick(event: MouseEvent) {
110
+ onTriggerClick?.(event);
111
+ toggleOpen();
112
+ }
113
+
89
114
  function handleKeydown(event: KeyboardEvent) {
90
115
  if (disabled) {
91
116
  return;
@@ -102,6 +127,7 @@
102
127
  if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
103
128
  event.preventDefault();
104
129
  if (!open) {
130
+ updateResolvedPlacement();
105
131
  open = true;
106
132
  activeValue = selectedOption?.value ?? firstEnabledOption()?.value ?? value;
107
133
  }
@@ -112,7 +138,7 @@
112
138
  if ((event.key === 'Enter' || event.key === ' ') && open) {
113
139
  event.preventDefault();
114
140
  const index = activeOptionIndex(activeValue);
115
- const option = index >= 0 ? options[index] : undefined;
141
+ const option = index >= 0 ? resolvedOptions[index] : undefined;
116
142
  if (option) {
117
143
  selectOption(option);
118
144
  }
@@ -144,6 +170,21 @@
144
170
  return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
145
171
  }
146
172
 
173
+ function updateResolvedPlacement(rect = dropdownElement?.getBoundingClientRect()) {
174
+ if (placement !== 'auto') {
175
+ resolvedPlacement = placement;
176
+ return;
177
+ }
178
+ if (!rect || typeof window === 'undefined') {
179
+ resolvedPlacement = 'down';
180
+ return;
181
+ }
182
+
183
+ const availableAbove = rect.top - viewportMargin - menuGap;
184
+ const availableBelow = window.innerHeight - rect.bottom - viewportMargin - menuGap;
185
+ resolvedPlacement = availableBelow >= availableAbove ? 'down' : 'up';
186
+ }
187
+
147
188
  async function updateViewportPanelMaxHeight() {
148
189
  await tick();
149
190
 
@@ -156,17 +197,18 @@
156
197
  return;
157
198
  }
158
199
 
159
- if (!fitViewport) {
200
+ const rect = dropdownElement?.getBoundingClientRect();
201
+ if (!rect) {
160
202
  return;
161
203
  }
162
204
 
163
- const rect = dropdownElement?.getBoundingClientRect();
164
- if (!rect) {
205
+ updateResolvedPlacement(rect);
206
+ if (!fitViewport) {
165
207
  return;
166
208
  }
167
209
 
168
210
  const available =
169
- placement === 'up'
211
+ resolvedPlacement === 'up'
170
212
  ? rect.top - viewportMargin - menuGap
171
213
  : window.innerHeight - rect.bottom - viewportMargin - menuGap;
172
214
  viewportPanelMaxHeight = `${Math.max(0, Math.floor(available))}px`;
@@ -199,8 +241,17 @@
199
241
 
200
242
  <span
201
243
  bind:this={dropdownElement}
202
- class="suu-dropdown"
244
+ class={[
245
+ 'suu-dropdown',
246
+ width !== undefined || minWidth !== undefined || maxWidth !== undefined
247
+ ? 'suu-dropdown--sized'
248
+ : '',
249
+ className ?? ''
250
+ ].filter(Boolean).join(' ')}
203
251
  style:--suu-dropdown-panel-max-height={viewportPanelMaxHeight}
252
+ style:width
253
+ style:min-width={minWidth}
254
+ style:max-width={maxWidth}
204
255
  on:focusout={handleFocusout}
205
256
  >
206
257
  <button
@@ -213,7 +264,7 @@
213
264
  aria-haspopup="listbox"
214
265
  aria-expanded={open}
215
266
  data-value={String(value)}
216
- on:click={toggleOpen}
267
+ on:click={handleTriggerClick}
217
268
  on:keydown={handleKeydown}
218
269
  >
219
270
  <span>{selectedText}</span>
@@ -223,35 +274,67 @@
223
274
  {#if open}
224
275
  <div
225
276
  class="suu-dropdown__menu"
226
- class:suu-dropdown__menu--up={placement === 'up'}
227
- class:suu-dropdown__menu--down={placement === 'down'}
277
+ class:suu-dropdown__menu--up={resolvedPlacement === 'up'}
278
+ class:suu-dropdown__menu--down={resolvedPlacement === 'down'}
228
279
  class:suu-dropdown__menu--left={menuAlign === 'left'}
229
280
  class:suu-dropdown__menu--right={menuAlign === 'right'}
230
281
  class:suu-dropdown__menu--fit-content={fitContent}
231
282
  >
232
283
  <div class="suu-dropdown__panel" role="listbox" aria-label={ariaLabel}>
233
- {#each options as option}
234
- <button
235
- type="button"
236
- class="suu-dropdown__option"
237
- class:suu-dropdown__option--active={option.value === activeValue}
238
- class:suu-dropdown__option--disabled={option.disabled}
239
- role="option"
240
- aria-selected={option.value === value}
241
- aria-disabled={option.disabled}
242
- disabled={option.disabled}
243
- data-value={String(option.value)}
244
- on:mousedown|preventDefault={() => undefined}
245
- on:mouseenter={() => {
246
- if (!option.disabled) {
247
- activeValue = option.value;
248
- }
249
- }}
250
- on:click={() => selectOption(option)}
251
- >
252
- {option.label}
253
- </button>
254
- {/each}
284
+ {#if optionGroups === undefined}
285
+ {#each options as option}
286
+ <button
287
+ type="button"
288
+ class="suu-dropdown__option"
289
+ class:suu-dropdown__option--active={option.value === activeValue}
290
+ class:suu-dropdown__option--disabled={option.disabled}
291
+ role="option"
292
+ aria-selected={option.value === value}
293
+ aria-disabled={option.disabled}
294
+ disabled={option.disabled}
295
+ data-value={String(option.value)}
296
+ on:mousedown|preventDefault={() => undefined}
297
+ on:mouseenter={() => {
298
+ if (!option.disabled) {
299
+ activeValue = option.value;
300
+ }
301
+ }}
302
+ on:click={() => selectOption(option)}
303
+ >
304
+ {option.label}
305
+ </button>
306
+ {/each}
307
+ {:else}
308
+ {#each optionGroups as group}
309
+ <div class="suu-dropdown__group" role="group" aria-label={group.label}>
310
+ {#if group.label}
311
+ <div class="suu-dropdown__group-label">{group.label}</div>
312
+ {/if}
313
+ {#each group.options as option}
314
+ <button
315
+ type="button"
316
+ class="suu-dropdown__option"
317
+ class:suu-dropdown__option--active={option.value === activeValue}
318
+ class:suu-dropdown__option--disabled={option.disabled}
319
+ role="option"
320
+ aria-selected={option.value === value}
321
+ aria-disabled={option.disabled}
322
+ disabled={option.disabled}
323
+ data-value={String(option.value)}
324
+ on:mousedown|preventDefault={() => undefined}
325
+ on:mouseenter={() => {
326
+ if (!option.disabled) {
327
+ activeValue = option.value;
328
+ }
329
+ }}
330
+ on:click={() => selectOption(option)}
331
+ >
332
+ {option.label}
333
+ </button>
334
+ {/each}
335
+ </div>
336
+ {/each}
337
+ {/if}
255
338
  </div>
256
339
  </div>
257
340
  {/if}
@@ -1,4 +1,4 @@
1
- import type { DropdownChangeHandler, DropdownMenuAlign, DropdownOption, DropdownPlacement, DropdownValue } from './types.js';
1
+ import type { DropdownChangeHandler, DropdownMenuAlign, DropdownOption, DropdownOptionGroup, DropdownPlacement, DropdownTriggerClickHandler, DropdownValue } from './types.js';
2
2
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
3
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
4
  $$bindings?: Bindings;
@@ -16,13 +16,19 @@ declare const Dropdown: $$__sveltets_2_IsomorphicComponent<{
16
16
  id?: string | undefined;
17
17
  value?: DropdownValue;
18
18
  options?: DropdownOption[];
19
+ optionGroups?: DropdownOptionGroup[] | undefined;
19
20
  ariaLabel?: string | undefined;
20
21
  placement?: DropdownPlacement;
21
22
  menuAlign?: DropdownMenuAlign;
22
23
  fitViewport?: boolean;
23
24
  fitContent?: boolean;
24
25
  disabled?: boolean;
26
+ width?: string | undefined;
27
+ minWidth?: string | undefined;
28
+ maxWidth?: string | undefined;
29
+ className?: string | undefined;
25
30
  onChange?: DropdownChangeHandler | undefined;
31
+ onTriggerClick?: DropdownTriggerClickHandler | undefined;
26
32
  }, {
27
33
  [evt: string]: CustomEvent<any>;
28
34
  }, {}, {}, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkO7H,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,QAAQ;SAVyN,MAAM,GAAG,SAAS;YAAU,aAAa;cAAY,cAAc,EAAE;gBAAc,MAAM,GAAG,SAAS;gBAAc,iBAAiB;gBAAc,iBAAiB;;;;eAA2G,qBAAqB,GAAG,SAAS;;;kBAUzb,CAAC;AAC5E,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Dropdown.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/Dropdown.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACR,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,EAC3B,aAAa,EACd,MAAM,YAAY,CAAC;AA6RtB,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,QAAQ;SAVuW,MAAM,GAAG,SAAS;YAAU,aAAa;cAAY,cAAc,EAAE;mBAAiB,mBAAmB,EAAE,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,iBAAiB;gBAAc,iBAAiB;;;;YAAwG,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;eAAa,qBAAqB,GAAG,SAAS;qBAAmB,2BAA2B,GAAG,SAAS;;;kBAU7yB,CAAC;AAC5E,KAAK,QAAQ,GAAG,YAAY,CAAC,OAAO,QAAQ,CAAC,CAAC;AAChD,eAAe,QAAQ,CAAC"}
@@ -1,3 +1,3 @@
1
1
  export { default as Dropdown } from './Dropdown.svelte';
2
- export type { DropdownChangeHandler, DropdownMenuAlign, DropdownOption, DropdownPlacement, DropdownValue } from './types.js';
2
+ export type { DropdownChangeHandler, DropdownMenuAlign, DropdownOption, DropdownOptionGroup, DropdownPlacement, DropdownTriggerClickHandler, DropdownValue } from './types.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,EAC3B,aAAa,EACd,MAAM,YAAY,CAAC"}
@@ -1,10 +1,15 @@
1
1
  export type DropdownValue = string | number;
2
- export type DropdownPlacement = 'up' | 'down';
2
+ export type DropdownPlacement = 'auto' | 'up' | 'down';
3
3
  export type DropdownMenuAlign = 'left' | 'right';
4
4
  export interface DropdownOption {
5
5
  label: string;
6
6
  value: DropdownValue;
7
7
  disabled?: boolean;
8
8
  }
9
+ export interface DropdownOptionGroup {
10
+ label?: string;
11
+ options: DropdownOption[];
12
+ }
9
13
  export type DropdownChangeHandler = (value: DropdownValue) => void | Promise<void>;
14
+ export type DropdownTriggerClickHandler = (event: MouseEvent) => void;
10
15
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnF,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC"}
package/dist/style.css CHANGED
@@ -1139,6 +1139,10 @@
1139
1139
  line-height: 1;
1140
1140
  }
1141
1141
 
1142
+ .suu-dropdown--sized .suu-dropdown__button {
1143
+ width: 100%;
1144
+ }
1145
+
1142
1146
  .suu-dropdown__button:hover,
1143
1147
  .suu-dropdown__button:focus-visible {
1144
1148
  border-color: var(--suu-color-accent);
@@ -1208,6 +1212,19 @@
1208
1212
  overscroll-behavior: contain;
1209
1213
  }
1210
1214
 
1215
+ .suu-dropdown__group + .suu-dropdown__group {
1216
+ border-top: 1px solid var(--suu-color-border);
1217
+ }
1218
+
1219
+ .suu-dropdown__group-label {
1220
+ padding: 8px 14px 6px;
1221
+ background: var(--suu-color-surface);
1222
+ color: var(--suu-color-muted);
1223
+ font-size: 0.75em;
1224
+ font-weight: 700;
1225
+ letter-spacing: 0.02em;
1226
+ }
1227
+
1211
1228
  .suu-dropdown__option {
1212
1229
  display: block;
1213
1230
  width: 100%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibobbyts/svelte-ui-utils",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "Reusable Svelte 5 UI utilities for dialogs, toast notifications, dropdown search, and data tables.",
5
5
  "type": "module",
6
6
  "license": "MIT",