@urbicon-ui/blocks 6.21.1 → 6.21.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.
Files changed (66) hide show
  1. package/dist/components/NumberInput/NumberInput.svelte +197 -0
  2. package/dist/components/NumberInput/NumberInput.svelte.d.ts +4 -0
  3. package/dist/components/NumberInput/index.d.ts +55 -0
  4. package/dist/components/NumberInput/index.js +1 -0
  5. package/dist/components/index.d.ts +2 -0
  6. package/dist/components/index.js +1 -0
  7. package/dist/i18n/index.d.ts +6 -0
  8. package/dist/primitives/Badge/Badge.svelte +12 -4
  9. package/dist/primitives/Badge/index.d.ts +26 -6
  10. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +11 -6
  11. package/dist/primitives/Breadcrumb/index.d.ts +2 -2
  12. package/dist/primitives/Checkbox/Checkbox.svelte +3 -3
  13. package/dist/primitives/Combobox/Combobox.svelte +478 -104
  14. package/dist/primitives/Combobox/combobox.variants.d.ts +89 -17
  15. package/dist/primitives/Combobox/combobox.variants.js +94 -13
  16. package/dist/primitives/Combobox/index.d.ts +166 -51
  17. package/dist/primitives/ConfirmDialog/index.d.ts +19 -0
  18. package/dist/primitives/Dialog/Dialog.svelte +74 -0
  19. package/dist/primitives/Dialog/index.d.ts +12 -1
  20. package/dist/primitives/Drawer/Drawer.svelte +2 -1
  21. package/dist/primitives/Drawer/drawer.variants.d.ts +8 -0
  22. package/dist/primitives/Drawer/drawer.variants.js +45 -10
  23. package/dist/primitives/Drawer/index.d.ts +13 -4
  24. package/dist/primitives/FormField/FormField.svelte +6 -6
  25. package/dist/primitives/FormField/index.d.ts +13 -4
  26. package/dist/primitives/Input/Input.svelte +8 -4
  27. package/dist/primitives/Menu/Menu.svelte +66 -4
  28. package/dist/primitives/Menu/index.d.ts +25 -0
  29. package/dist/primitives/Pagination/Pagination.svelte +28 -13
  30. package/dist/primitives/Pagination/index.d.ts +44 -0
  31. package/dist/primitives/Popover/Popover.svelte +10 -0
  32. package/dist/primitives/Popover/index.d.ts +3 -3
  33. package/dist/primitives/RadioGroup/RadioGroup.svelte +3 -3
  34. package/dist/primitives/Select/Select.svelte +21 -11
  35. package/dist/primitives/Select/index.d.ts +7 -0
  36. package/dist/primitives/Select/select.variants.d.ts +17 -17
  37. package/dist/primitives/Select/select.variants.js +18 -0
  38. package/dist/primitives/Slider/Slider.svelte +4 -8
  39. package/dist/primitives/Textarea/Textarea.svelte +4 -5
  40. package/dist/primitives/Textarea/textarea.variants.d.ts +7 -7
  41. package/dist/primitives/Textarea/textarea.variants.js +5 -2
  42. package/dist/primitives/Toast/Toaster.svelte +42 -2
  43. package/dist/primitives/Toast/index.d.ts +30 -0
  44. package/dist/primitives/Toast/toast.store.svelte.d.ts +25 -1
  45. package/dist/primitives/Toast/toast.store.svelte.js +91 -1
  46. package/dist/primitives/Toast/toast.variants.d.ts +18 -0
  47. package/dist/primitives/Toast/toast.variants.js +15 -0
  48. package/dist/primitives/Toggle/Toggle.svelte +17 -3
  49. package/dist/primitives/Toggle/index.d.ts +8 -2
  50. package/dist/primitives/Toggle/toggle.variants.d.ts +7 -0
  51. package/dist/primitives/Toggle/toggle.variants.js +26 -0
  52. package/dist/primitives/Tooltip/Tooltip.svelte +47 -21
  53. package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +1 -1
  54. package/dist/primitives/Tooltip/index.d.ts +31 -3
  55. package/dist/primitives/Tooltip/tooltip.variants.d.ts +4 -4
  56. package/dist/primitives/Tooltip/tooltip.variants.js +2 -2
  57. package/dist/primitives/index.d.ts +3 -3
  58. package/dist/translations/de.d.ts +3 -0
  59. package/dist/translations/de.js +4 -1
  60. package/dist/translations/en.d.ts +3 -0
  61. package/dist/translations/en.js +4 -1
  62. package/dist/utils/guide.svelte.d.ts +8 -2
  63. package/dist/utils/guide.svelte.js +86 -5
  64. package/dist/utils/use-form-field.svelte.d.ts +9 -9
  65. package/dist/utils/use-form-field.svelte.js +12 -12
  66. package/package.json +3 -3
@@ -34,6 +34,7 @@
34
34
  nextIcon,
35
35
  firstIcon,
36
36
  lastIcon,
37
+ renderItem,
37
38
  itemsPerPage = 10,
38
39
  totalItems,
39
40
  startItem,
@@ -323,19 +324,33 @@
323
324
 
324
325
  {#if showNumbers}
325
326
  {#each visiblePageNumbers as page (page)}
326
- <PaginationItem
327
- {size}
328
- {variant}
329
- {intent}
330
- {tier}
331
- {page}
332
- active={page === currentPage}
333
- disabled={disabled || loading}
334
- onPageClick={goToPage(page)}
335
- {mint}
336
- >
337
- {page}
338
- </PaginationItem>
327
+ {#if renderItem}
328
+ {@render renderItem({
329
+ page,
330
+ active: page === currentPage,
331
+ disabled: disabled || loading,
332
+ size,
333
+ variant,
334
+ intent,
335
+ tier,
336
+ mint,
337
+ select: goToPage(page)
338
+ })}
339
+ {:else}
340
+ <PaginationItem
341
+ {size}
342
+ {variant}
343
+ {intent}
344
+ {tier}
345
+ {page}
346
+ active={page === currentPage}
347
+ disabled={disabled || loading}
348
+ onPageClick={goToPage(page)}
349
+ {mint}
350
+ >
351
+ {page}
352
+ </PaginationItem>
353
+ {/if}
339
354
  {/each}
340
355
  {/if}
341
356
 
@@ -10,6 +10,33 @@ export interface PaginationPageItem {
10
10
  active?: boolean;
11
11
  disabled?: boolean;
12
12
  }
13
+ /**
14
+ * Context handed to the `renderItem` snippet for a single numbered page button.
15
+ * Bundles the page number, its active/disabled state, the style props forwarded
16
+ * from the Pagination (so a custom item stays visually consistent), and a
17
+ * `select` callback that changes the page (guarded against disabled / no-op /
18
+ * out-of-range internally).
19
+ */
20
+ export interface PaginationItemContext {
21
+ /** The 1-based page number this item represents. */
22
+ page: number;
23
+ /** Whether this item is the currently active page. */
24
+ active: boolean;
25
+ /** Whether the item is inert (component `disabled` or `loading`). */
26
+ disabled: boolean;
27
+ /** Button size forwarded from the Pagination props. */
28
+ size: 'sm' | 'md' | 'lg';
29
+ /** Button variant forwarded from the Pagination props. */
30
+ variant: 'outlined' | 'filled' | 'ghost';
31
+ /** Semantic intent forwarded from the Pagination props. */
32
+ intent: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'neutral';
33
+ /** Semantic radius tier forwarded from the Pagination props. */
34
+ tier?: InteractiveTier;
35
+ /** Micro-interaction preset forwarded from the Pagination props. */
36
+ mint: MintProp;
37
+ /** Navigate to this page. No-op when disabled, already active, or out of range. */
38
+ select: () => void;
39
+ }
13
40
  /**
14
41
  * @description Navigation control for paged data sets.
15
42
  * Supports multiple layouts, intents, button variants, and configurable ellipsis behaviour.
@@ -69,6 +96,23 @@ export interface PaginationProps extends Omit<PaginationVariants, 'disabled' | '
69
96
  firstIcon?: Snippet;
70
97
  /** Custom icon rendered inside the "Last" button. */
71
98
  lastIcon?: Snippet;
99
+ /**
100
+ * Render each numbered page button yourself. Receives a {@link PaginationItemContext}
101
+ * with the page number, its active/disabled state, the forwarded style props
102
+ * (size, variant, intent, tier, mint) and a `select` callback. Only affects the
103
+ * numbered page buttons in the default layout — prev/next/first/last keep their
104
+ * own icon snippets, and the ellipsis is unaffected.
105
+ *
106
+ * @example
107
+ * ```svelte
108
+ * <Pagination {currentPage} {totalPages} {onPageChange}>
109
+ * {#snippet renderItem({ page, active, disabled, select })}
110
+ * <button class:active onclick={select} {disabled}>{page}</button>
111
+ * {/snippet}
112
+ * </Pagination>
113
+ * ```
114
+ */
115
+ renderItem?: Snippet<[PaginationItemContext]>;
72
116
  /** Items shown per page. Used by the table layout to compute "Showing X to Y of Z". */
73
117
  itemsPerPage?: number;
74
118
  /** Total number of items across all pages. Used by the table layout info text. */
@@ -209,6 +209,12 @@
209
209
  // intentionally consume Escape.
210
210
  function handleEscape(e: KeyboardEvent) {
211
211
  if (e.key !== 'Escape' || e.defaultPrevented) return;
212
+ // Re-check `open` (like the auto-mode toggle handler does): the
213
+ // listener teardown is deferred to the next effect flush, so a
214
+ // consumer handler earlier in this same dispatch may already have
215
+ // closed via `bind:open` — without this guard we'd report a second,
216
+ // transition-less onOpenChange(false) + onEscape and steal focus.
217
+ if (!open) return;
212
218
  e.preventDefault();
213
219
  open = false;
214
220
  onOpenChange?.(false);
@@ -231,6 +237,10 @@
231
237
  if (!target) return;
232
238
  if (popoverElement?.contains(target)) return;
233
239
  if (effectiveTriggerElement?.contains(target)) return;
240
+ // Same deferred-teardown re-check as handleEscape above: a consumer
241
+ // capture-phase pointerdown handler may have closed via `bind:open`
242
+ // within this dispatch — don't report a second close.
243
+ if (!open) return;
234
244
  open = false;
235
245
  onOpenChange?.(false);
236
246
  onClickOutsideProp?.();
@@ -4,8 +4,8 @@ import type { Placement } from '../../utils/floating.js';
4
4
  import type { PopoverVariants } from './popover.variants.js';
5
5
  /**
6
6
  * @description Floating panel anchored to a trigger element. Uses the native Popover API
7
- * for top-layer rendering, light dismiss, and Escape handling. Floating UI provides
8
- * precise positioning with automatic flip, shift, and optional width syncing.
7
+ * for top-layer rendering, light dismiss, and Escape handling. The library's built-in
8
+ * positioning engine provides automatic flip, shift, and optional width syncing.
9
9
  *
10
10
  * @tag overlay
11
11
  * @related Tooltip
@@ -45,7 +45,7 @@ export interface PopoverProps extends PopoverVariants, Omit<HTMLAttributes<HTMLD
45
45
  trigger?: Snippet;
46
46
  /** External trigger element ref. Use instead of the `trigger` snippet when the trigger lives outside the Popover tree. Supports `bind:triggerElement`. */
47
47
  triggerElement?: HTMLElement;
48
- /** Where the popover appears relative to the trigger. All Floating UI `Placement` values are supported. */
48
+ /** Where the popover appears relative to the trigger. All standard `Placement` values (side plus optional `-start`/`-end` alignment) are supported. */
49
49
  placement?: Placement;
50
50
  /** Gap in px between the trigger edge and the popover. */
51
51
  offsetDistance?: number;
@@ -46,7 +46,7 @@
46
46
  // ARIA wiring is shared with every form primitive — see XC-2.
47
47
  const ff = useFormField(() => ({
48
48
  fieldId: groupId,
49
- hint: helper,
49
+ helper,
50
50
  error,
51
51
  required,
52
52
  disabled
@@ -174,9 +174,9 @@
174
174
  >
175
175
  {error}
176
176
  </div>
177
- {:else if ff.hintId}
177
+ {:else if ff.helperId}
178
178
  <div
179
- id={ff.hintId}
179
+ id={ff.helperId}
180
180
  class={unstyled
181
181
  ? (slotClasses?.message ?? '')
182
182
  : styles.message({ class: slotClasses?.message })}
@@ -38,6 +38,7 @@
38
38
  mint = 'none',
39
39
  onValueChange,
40
40
  open = $bindable(false),
41
+ onOpenChange,
41
42
  usePortal = true,
42
43
  syncWidth = true,
43
44
  customTrigger,
@@ -101,7 +102,7 @@
101
102
  const labelId = $derived(label ? `${uid}-label` : undefined);
102
103
  const ff = useFormField(() => ({
103
104
  fieldId: uid,
104
- hint: helper,
105
+ helper,
105
106
  error,
106
107
  required,
107
108
  disabled
@@ -235,12 +236,21 @@
235
236
  syncWidth: () => syncWidth
236
237
  });
237
238
 
239
+ // Single mutation point for internally-driven open changes, so
240
+ // `onOpenChange` fires exactly once per transition (and never when the
241
+ // consumer writes `bind:open` directly).
242
+ function setOpen(next: boolean) {
243
+ if (open === next) return;
244
+ open = next;
245
+ onOpenChange?.(next);
246
+ }
247
+
238
248
  function toggle() {
239
249
  if (disabled) return;
240
250
  // Pointer-driven open (trigger onclick). Mark modality so the open effect
241
251
  // doesn't pre-highlight the first row for a mouse/touch user.
242
252
  if (!open) openedViaKeyboard = false;
243
- open = !open;
253
+ setOpen(!open);
244
254
  if (!open) activeIndex = -1;
245
255
  }
246
256
 
@@ -271,7 +281,7 @@
271
281
  dispatchValueChange?.(nextValue);
272
282
  }
273
283
  if (effectiveCloseOnSelect) {
274
- open = false;
284
+ setOpen(false);
275
285
  activeIndex = -1;
276
286
  focusTrigger();
277
287
  }
@@ -297,7 +307,7 @@
297
307
  // explicitly intent to focus elsewhere)
298
308
  function dismissByEscape() {
299
309
  if (!closeOnEscape) return false;
300
- open = false;
310
+ setOpen(false);
301
311
  activeIndex = -1;
302
312
  onEscape?.();
303
313
  return true;
@@ -319,7 +329,7 @@
319
329
  event.preventDefault();
320
330
  if (!open) {
321
331
  openedViaKeyboard = true;
322
- open = true;
332
+ setOpen(true);
323
333
  } else {
324
334
  activeIndex = activeIndex < enabledOptions.length - 1 ? activeIndex + 1 : 0;
325
335
  }
@@ -328,7 +338,7 @@
328
338
  event.preventDefault();
329
339
  if (!open) {
330
340
  openedViaKeyboard = true;
331
- open = true;
341
+ setOpen(true);
332
342
  } else {
333
343
  activeIndex = activeIndex > 0 ? activeIndex - 1 : enabledOptions.length - 1;
334
344
  }
@@ -338,7 +348,7 @@
338
348
  event.preventDefault();
339
349
  if (!open) {
340
350
  openedViaKeyboard = true;
341
- open = true;
351
+ setOpen(true);
342
352
  } else if (activeIndex >= 0 && activeIndex < enabledOptions.length) {
343
353
  selectOption(enabledOptions[activeIndex]);
344
354
  }
@@ -353,7 +363,7 @@
353
363
  // Tab leaves the widget — close (focus moves on via the default tab),
354
364
  // independent of closeOnEscape/closeOnClickOutside.
355
365
  if (open) {
356
- open = false;
366
+ setOpen(false);
357
367
  activeIndex = -1;
358
368
  }
359
369
  break;
@@ -382,7 +392,7 @@
382
392
  !listboxRef.contains(target)
383
393
  ) {
384
394
  if (!closeOnClickOutside) return;
385
- open = false;
395
+ setOpen(false);
386
396
  activeIndex = -1;
387
397
  onClickOutside?.();
388
398
  }
@@ -725,9 +735,9 @@
725
735
  >
726
736
  {error}
727
737
  </div>
728
- {:else if ff.hintId}
738
+ {:else if ff.helperId}
729
739
  <div
730
- id={ff.hintId}
740
+ id={ff.helperId}
731
741
  class={unstyled
732
742
  ? (slotClasses?.message ?? '')
733
743
  : styles.message({ class: slotClasses?.message })}
@@ -164,6 +164,13 @@ interface SelectBaseProps<T extends SelectValue = string> extends Omit<SelectVar
164
164
  * the Select wrapper). @default false
165
165
  */
166
166
  open?: boolean;
167
+ /**
168
+ * Fires when the listbox opens or closes from user interaction (trigger
169
+ * click, keyboard, selection, Escape, Tab-out, outside click). Receives the
170
+ * new open state — use it e.g. to lazy-load options on first open. Not
171
+ * called when the consumer writes `bind:open` directly.
172
+ */
173
+ onOpenChange?: (open: boolean) => void;
167
174
  /**
168
175
  * When true, the listbox is rendered into the browser top layer via the native
169
176
  * `popover` API, so it cannot be clipped by `overflow: auto` ancestors. When
@@ -2,7 +2,7 @@ import { type SlotNames, type VariantProps } from '../../utils/variants.js';
2
2
  export declare const selectVariants: ((props?: {
3
3
  tier?: "commit" | "modify" | undefined;
4
4
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
5
- size?: "sm" | "md" | "lg" | undefined;
5
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
6
6
  open?: boolean | undefined;
7
7
  disabled?: boolean | undefined;
8
8
  messageType?: "error" | "helper" | undefined;
@@ -13,7 +13,7 @@ export declare const selectVariants: ((props?: {
13
13
  wrapper: (props?: ({
14
14
  tier?: "commit" | "modify" | undefined;
15
15
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
16
- size?: "sm" | "md" | "lg" | undefined;
16
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
17
17
  open?: boolean | undefined;
18
18
  disabled?: boolean | undefined;
19
19
  messageType?: "error" | "helper" | undefined;
@@ -26,7 +26,7 @@ export declare const selectVariants: ((props?: {
26
26
  base: (props?: ({
27
27
  tier?: "commit" | "modify" | undefined;
28
28
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
29
- size?: "sm" | "md" | "lg" | undefined;
29
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
30
30
  open?: boolean | undefined;
31
31
  disabled?: boolean | undefined;
32
32
  messageType?: "error" | "helper" | undefined;
@@ -39,7 +39,7 @@ export declare const selectVariants: ((props?: {
39
39
  trigger: (props?: ({
40
40
  tier?: "commit" | "modify" | undefined;
41
41
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
42
- size?: "sm" | "md" | "lg" | undefined;
42
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
43
43
  open?: boolean | undefined;
44
44
  disabled?: boolean | undefined;
45
45
  messageType?: "error" | "helper" | undefined;
@@ -52,7 +52,7 @@ export declare const selectVariants: ((props?: {
52
52
  triggerText: (props?: ({
53
53
  tier?: "commit" | "modify" | undefined;
54
54
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
55
- size?: "sm" | "md" | "lg" | undefined;
55
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
56
56
  open?: boolean | undefined;
57
57
  disabled?: boolean | undefined;
58
58
  messageType?: "error" | "helper" | undefined;
@@ -65,7 +65,7 @@ export declare const selectVariants: ((props?: {
65
65
  placeholder: (props?: ({
66
66
  tier?: "commit" | "modify" | undefined;
67
67
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
68
- size?: "sm" | "md" | "lg" | undefined;
68
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
69
69
  open?: boolean | undefined;
70
70
  disabled?: boolean | undefined;
71
71
  messageType?: "error" | "helper" | undefined;
@@ -78,7 +78,7 @@ export declare const selectVariants: ((props?: {
78
78
  chevron: (props?: ({
79
79
  tier?: "commit" | "modify" | undefined;
80
80
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
81
- size?: "sm" | "md" | "lg" | undefined;
81
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
82
82
  open?: boolean | undefined;
83
83
  disabled?: boolean | undefined;
84
84
  messageType?: "error" | "helper" | undefined;
@@ -91,7 +91,7 @@ export declare const selectVariants: ((props?: {
91
91
  clear: (props?: ({
92
92
  tier?: "commit" | "modify" | undefined;
93
93
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
94
- size?: "sm" | "md" | "lg" | undefined;
94
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
95
95
  open?: boolean | undefined;
96
96
  disabled?: boolean | undefined;
97
97
  messageType?: "error" | "helper" | undefined;
@@ -104,7 +104,7 @@ export declare const selectVariants: ((props?: {
104
104
  listbox: (props?: ({
105
105
  tier?: "commit" | "modify" | undefined;
106
106
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
107
- size?: "sm" | "md" | "lg" | undefined;
107
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
108
108
  open?: boolean | undefined;
109
109
  disabled?: boolean | undefined;
110
110
  messageType?: "error" | "helper" | undefined;
@@ -117,7 +117,7 @@ export declare const selectVariants: ((props?: {
117
117
  option: (props?: ({
118
118
  tier?: "commit" | "modify" | undefined;
119
119
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
120
- size?: "sm" | "md" | "lg" | undefined;
120
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
121
121
  open?: boolean | undefined;
122
122
  disabled?: boolean | undefined;
123
123
  messageType?: "error" | "helper" | undefined;
@@ -130,7 +130,7 @@ export declare const selectVariants: ((props?: {
130
130
  optionLabel: (props?: ({
131
131
  tier?: "commit" | "modify" | undefined;
132
132
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
133
- size?: "sm" | "md" | "lg" | undefined;
133
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
134
134
  open?: boolean | undefined;
135
135
  disabled?: boolean | undefined;
136
136
  messageType?: "error" | "helper" | undefined;
@@ -143,7 +143,7 @@ export declare const selectVariants: ((props?: {
143
143
  optionCheck: (props?: ({
144
144
  tier?: "commit" | "modify" | undefined;
145
145
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
146
- size?: "sm" | "md" | "lg" | undefined;
146
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
147
147
  open?: boolean | undefined;
148
148
  disabled?: boolean | undefined;
149
149
  messageType?: "error" | "helper" | undefined;
@@ -156,7 +156,7 @@ export declare const selectVariants: ((props?: {
156
156
  optionCheckbox: (props?: ({
157
157
  tier?: "commit" | "modify" | undefined;
158
158
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
159
- size?: "sm" | "md" | "lg" | undefined;
159
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
160
160
  open?: boolean | undefined;
161
161
  disabled?: boolean | undefined;
162
162
  messageType?: "error" | "helper" | undefined;
@@ -169,7 +169,7 @@ export declare const selectVariants: ((props?: {
169
169
  group: (props?: ({
170
170
  tier?: "commit" | "modify" | undefined;
171
171
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
172
- size?: "sm" | "md" | "lg" | undefined;
172
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
173
173
  open?: boolean | undefined;
174
174
  disabled?: boolean | undefined;
175
175
  messageType?: "error" | "helper" | undefined;
@@ -182,7 +182,7 @@ export declare const selectVariants: ((props?: {
182
182
  groupLabel: (props?: ({
183
183
  tier?: "commit" | "modify" | undefined;
184
184
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
185
- size?: "sm" | "md" | "lg" | undefined;
185
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
186
186
  open?: boolean | undefined;
187
187
  disabled?: boolean | undefined;
188
188
  messageType?: "error" | "helper" | undefined;
@@ -195,7 +195,7 @@ export declare const selectVariants: ((props?: {
195
195
  label: (props?: ({
196
196
  tier?: "commit" | "modify" | undefined;
197
197
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
198
- size?: "sm" | "md" | "lg" | undefined;
198
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
199
199
  open?: boolean | undefined;
200
200
  disabled?: boolean | undefined;
201
201
  messageType?: "error" | "helper" | undefined;
@@ -208,7 +208,7 @@ export declare const selectVariants: ((props?: {
208
208
  message: (props?: ({
209
209
  tier?: "commit" | "modify" | undefined;
210
210
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
211
- size?: "sm" | "md" | "lg" | undefined;
211
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
212
212
  open?: boolean | undefined;
213
213
  disabled?: boolean | undefined;
214
214
  messageType?: "error" | "helper" | undefined;
@@ -82,6 +82,16 @@ export const selectVariants = tv({
82
82
  }
83
83
  },
84
84
  size: {
85
+ // Full xs–xl scale, mirroring Input's h-7…h-14 ladder (form-family
86
+ // symmetry: a dense form should not pair an xs Input with an sm Select).
87
+ xs: {
88
+ trigger: 'h-7 pl-2 pr-7 text-xs gap-1.5',
89
+ chevron: 'w-3 h-3',
90
+ clear: 'right-1.5 p-0.5 [&_svg]:w-3 [&_svg]:h-3',
91
+ option: 'py-1 text-xs min-h-[1.75rem]',
92
+ optionCheck: 'w-3 h-3',
93
+ optionCheckbox: 'w-3 h-3 [&_svg]:w-2 [&_svg]:h-2'
94
+ },
85
95
  sm: {
86
96
  trigger: 'h-8 pl-3 pr-8 text-sm gap-2',
87
97
  chevron: 'w-3.5 h-3.5',
@@ -105,6 +115,14 @@ export const selectVariants = tv({
105
115
  option: 'py-2.5 text-base min-h-[3rem]',
106
116
  optionCheck: 'w-5 h-5',
107
117
  optionCheckbox: 'w-[18px] h-[18px] [&_svg]:w-3.5 [&_svg]:h-3.5'
118
+ },
119
+ xl: {
120
+ trigger: 'h-14 pl-6 pr-14 text-xl gap-3',
121
+ chevron: 'w-6 h-6',
122
+ clear: 'right-5 p-1 [&_svg]:w-6 [&_svg]:h-6',
123
+ option: 'py-3 text-lg min-h-[3.5rem]',
124
+ optionCheck: 'w-6 h-6',
125
+ optionCheckbox: 'w-5 h-5 [&_svg]:w-4 [&_svg]:h-4'
108
126
  }
109
127
  },
110
128
  open: {
@@ -47,7 +47,7 @@
47
47
  const uid = `slider-${propsId}`;
48
48
  const ff = useFormField(() => ({
49
49
  fieldId: uid,
50
- hint: helper,
50
+ helper,
51
51
  error,
52
52
  disabled
53
53
  }));
@@ -86,11 +86,7 @@
86
86
 
87
87
  // ─── Range-Constraints ──────────────────────────────────────────────────
88
88
  type ZoneStatus =
89
- | 'none'
90
- | 'insideRecommended'
91
- | 'insideValidOnly'
92
- | 'outsideValidDanger'
93
- | 'outsideValidWarning';
89
+ 'none' | 'insideRecommended' | 'insideValidOnly' | 'outsideValidDanger' | 'outsideValidWarning';
94
90
 
95
91
  const hasRangeConstraints = $derived(!!validRange || !!recommendedRange);
96
92
 
@@ -537,9 +533,9 @@
537
533
  >
538
534
  {error}
539
535
  </div>
540
- {:else if ff.hintId}
536
+ {:else if ff.helperId}
541
537
  <div
542
- id={ff.hintId}
538
+ id={ff.helperId}
543
539
  class={unstyled
544
540
  ? (slotClasses?.message ?? '')
545
541
  : styles.message({ class: slotClasses?.message })}
@@ -43,7 +43,7 @@
43
43
  const propsId = $props.id();
44
44
  const ff = useFormField(() => ({
45
45
  fieldId: `textarea-${propsId}`,
46
- hint: helper,
46
+ helper,
47
47
  error,
48
48
  required,
49
49
  disabled
@@ -137,8 +137,7 @@
137
137
  {required}
138
138
  aria-invalid={ff.invalid ? 'true' : undefined}
139
139
  aria-describedby={ff.describedBy}
140
- oninput={autoResize ? adjustHeight : undefined}
141
- ></textarea>
140
+ oninput={autoResize ? adjustHeight : undefined}></textarea>
142
141
 
143
142
  {#if showFooter}
144
143
  <div
@@ -154,9 +153,9 @@
154
153
  >
155
154
  {error}
156
155
  </div>
157
- {:else if ff.hintId}
156
+ {:else if ff.helperId}
158
157
  <div
159
- id={ff.hintId}
158
+ id={ff.helperId}
160
159
  class={unstyled
161
160
  ? (slotClasses?.message ?? '')
162
161
  : styles.message({ class: slotClasses?.message })}
@@ -2,7 +2,7 @@ import { type SlotNames, type VariantProps } from '../../utils/variants.js';
2
2
  export declare const textareaVariants: ((props?: {
3
3
  tier?: "commit" | "modify" | undefined;
4
4
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
5
- size?: "sm" | "md" | "lg" | undefined;
5
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
6
6
  intent?: "default" | "success" | "warning" | "danger" | undefined;
7
7
  autoResize?: boolean | undefined;
8
8
  disabled?: boolean | undefined;
@@ -15,7 +15,7 @@ export declare const textareaVariants: ((props?: {
15
15
  wrapper: (props?: ({
16
16
  tier?: "commit" | "modify" | undefined;
17
17
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
18
- size?: "sm" | "md" | "lg" | undefined;
18
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
19
19
  intent?: "default" | "success" | "warning" | "danger" | undefined;
20
20
  autoResize?: boolean | undefined;
21
21
  disabled?: boolean | undefined;
@@ -30,7 +30,7 @@ export declare const textareaVariants: ((props?: {
30
30
  base: (props?: ({
31
31
  tier?: "commit" | "modify" | undefined;
32
32
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
33
- size?: "sm" | "md" | "lg" | undefined;
33
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
34
34
  intent?: "default" | "success" | "warning" | "danger" | undefined;
35
35
  autoResize?: boolean | undefined;
36
36
  disabled?: boolean | undefined;
@@ -45,7 +45,7 @@ export declare const textareaVariants: ((props?: {
45
45
  label: (props?: ({
46
46
  tier?: "commit" | "modify" | undefined;
47
47
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
48
- size?: "sm" | "md" | "lg" | undefined;
48
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
49
49
  intent?: "default" | "success" | "warning" | "danger" | undefined;
50
50
  autoResize?: boolean | undefined;
51
51
  disabled?: boolean | undefined;
@@ -60,7 +60,7 @@ export declare const textareaVariants: ((props?: {
60
60
  footer: (props?: ({
61
61
  tier?: "commit" | "modify" | undefined;
62
62
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
63
- size?: "sm" | "md" | "lg" | undefined;
63
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
64
64
  intent?: "default" | "success" | "warning" | "danger" | undefined;
65
65
  autoResize?: boolean | undefined;
66
66
  disabled?: boolean | undefined;
@@ -75,7 +75,7 @@ export declare const textareaVariants: ((props?: {
75
75
  message: (props?: ({
76
76
  tier?: "commit" | "modify" | undefined;
77
77
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
78
- size?: "sm" | "md" | "lg" | undefined;
78
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
79
79
  intent?: "default" | "success" | "warning" | "danger" | undefined;
80
80
  autoResize?: boolean | undefined;
81
81
  disabled?: boolean | undefined;
@@ -90,7 +90,7 @@ export declare const textareaVariants: ((props?: {
90
90
  counter: (props?: ({
91
91
  tier?: "commit" | "modify" | undefined;
92
92
  variant?: "ghost" | "filled" | "outlined" | "underline" | undefined;
93
- size?: "sm" | "md" | "lg" | undefined;
93
+ size?: "sm" | "md" | "lg" | "xl" | "xs" | undefined;
94
94
  intent?: "default" | "success" | "warning" | "danger" | undefined;
95
95
  autoResize?: boolean | undefined;
96
96
  disabled?: boolean | undefined;
@@ -39,11 +39,14 @@ export const textareaVariants = tv({
39
39
  }
40
40
  },
41
41
  size: {
42
+ // Full xs–xl scale (form-family symmetry with Input's ladder).
42
43
  // `pointer-coarse:text-base` floors the font to 16px on touch so iOS
43
- // Safari doesn't auto-zoom the field on focus. Desktop keeps 14px.
44
+ // Safari doesn't auto-zoom the field on focus. Desktop keeps 12/14px.
45
+ xs: { base: 'px-2 py-1.5 text-xs pointer-coarse:text-base min-h-[4rem]' },
44
46
  sm: { base: 'px-3 py-2 text-sm pointer-coarse:text-base min-h-[5rem]' },
45
47
  md: { base: 'px-4 py-3 text-base min-h-[7rem]' },
46
- lg: { base: 'px-6 py-4 text-lg min-h-[9rem]' }
48
+ lg: { base: 'px-6 py-4 text-lg min-h-[9rem]' },
49
+ xl: { base: 'px-8 py-5 text-xl min-h-[11rem]' }
47
50
  },
48
51
  // Message colour is owned by messageType/error (declared below) — an
49
52
  // intent-level message tone could never win the fold and shipped