@urbicon-ui/blocks 6.1.8 → 6.3.1

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 (153) hide show
  1. package/README.md +12 -2
  2. package/dist/components/AreaChart/AreaChart.svelte +2 -6
  3. package/dist/components/BarChart/BarChart.svelte +2 -6
  4. package/dist/components/Calendar/Calendar.svelte +12 -10
  5. package/dist/components/Calendar/calendar.variants.d.ts +2 -1
  6. package/dist/components/Calendar/index.d.ts +2 -2
  7. package/dist/components/CommandPalette/CommandPalette.svelte +106 -39
  8. package/dist/components/CommandPalette/commandPalette.variants.d.ts +3 -7
  9. package/dist/components/CommandPalette/commandPalette.variants.js +0 -1
  10. package/dist/components/CommandPalette/index.d.ts +2 -2
  11. package/dist/components/CompositionBar/CompositionBar.svelte +12 -15
  12. package/dist/components/CompositionBar/composition-bar.variants.d.ts +3 -1
  13. package/dist/components/CompositionBar/index.d.ts +2 -2
  14. package/dist/components/DonutChart/DonutChart.svelte +2 -6
  15. package/dist/components/EmptyState/EmptyState.svelte +8 -9
  16. package/dist/components/EmptyState/emptyState.variants.d.ts +3 -1
  17. package/dist/components/EmptyState/index.d.ts +3 -3
  18. package/dist/components/FileUpload/FileUpload.svelte +17 -17
  19. package/dist/components/FileUpload/fileUpload.variants.d.ts +3 -11
  20. package/dist/components/FileUpload/fileUpload.variants.js +0 -5
  21. package/dist/components/FileUpload/index.d.ts +4 -3
  22. package/dist/components/Guide/Guide.svelte +5 -8
  23. package/dist/components/Guide/GuideArticle.svelte +5 -8
  24. package/dist/components/Guide/GuideBeacon.svelte +5 -8
  25. package/dist/components/Guide/GuideHint.svelte +5 -8
  26. package/dist/components/Guide/GuideMarker.svelte +5 -8
  27. package/dist/components/Guide/GuideMention.svelte +5 -8
  28. package/dist/components/Guide/GuidePanel.svelte +5 -8
  29. package/dist/components/Guide/guide.variants.d.ts +9 -1
  30. package/dist/components/Guide/index.d.ts +12 -9
  31. package/dist/components/LineChart/LineChart.svelte +2 -6
  32. package/dist/components/Planner/Planner.svelte +7 -10
  33. package/dist/components/Planner/index.d.ts +4 -4
  34. package/dist/components/Planner/planner.variants.d.ts +3 -1
  35. package/dist/components/Sankey/Sankey.svelte +8 -9
  36. package/dist/components/Sankey/index.d.ts +2 -2
  37. package/dist/components/Sankey/sankey.variants.d.ts +3 -1
  38. package/dist/components/SidebarLayout/SidebarLayout.svelte +17 -17
  39. package/dist/components/SidebarLayout/index.d.ts +8 -2
  40. package/dist/components/SidebarLayout/sidebar-layout.variants.d.ts +3 -1
  41. package/dist/components/ThemeSwitcher/ThemeSwitcher.svelte +30 -38
  42. package/dist/components/ThemeSwitcher/index.d.ts +6 -4
  43. package/dist/components/ThemeSwitcher/themeSwitcher.variants.d.ts +3 -1
  44. package/dist/primitives/Accordion/Accordion.svelte +7 -9
  45. package/dist/primitives/Accordion/AccordionItem.svelte +8 -20
  46. package/dist/primitives/Accordion/accordion.variants.d.ts +3 -1
  47. package/dist/primitives/Accordion/index.d.ts +6 -6
  48. package/dist/primitives/Alert/Alert.svelte +7 -21
  49. package/dist/primitives/Alert/alert.variants.d.ts +3 -1
  50. package/dist/primitives/Alert/index.d.ts +3 -3
  51. package/dist/primitives/Avatar/Avatar.svelte +17 -20
  52. package/dist/primitives/Avatar/avatar.variants.d.ts +3 -1
  53. package/dist/primitives/Avatar/index.d.ts +3 -3
  54. package/dist/primitives/Badge/Badge.svelte +20 -23
  55. package/dist/primitives/Badge/badge.variants.d.ts +3 -1
  56. package/dist/primitives/Badge/index.d.ts +2 -2
  57. package/dist/primitives/Breadcrumb/Breadcrumb.svelte +30 -32
  58. package/dist/primitives/Breadcrumb/breadcrumb.variants.d.ts +3 -1
  59. package/dist/primitives/Breadcrumb/index.d.ts +2 -2
  60. package/dist/primitives/Button/Button.svelte +21 -21
  61. package/dist/primitives/Button/button.variants.d.ts +3 -1
  62. package/dist/primitives/Button/index.d.ts +3 -3
  63. package/dist/primitives/ButtonGroup/ButtonGroup.svelte +15 -14
  64. package/dist/primitives/ButtonGroup/buttongroup.variants.d.ts +3 -1
  65. package/dist/primitives/ButtonGroup/index.d.ts +3 -2
  66. package/dist/primitives/Card/Card.svelte +15 -18
  67. package/dist/primitives/Card/card.variants.d.ts +3 -1
  68. package/dist/primitives/Card/index.d.ts +3 -3
  69. package/dist/primitives/Checkbox/Checkbox.svelte +20 -20
  70. package/dist/primitives/Checkbox/checkbox.variants.d.ts +3 -1
  71. package/dist/primitives/Checkbox/index.d.ts +7 -3
  72. package/dist/primitives/Collapsible/Collapsible.svelte +30 -30
  73. package/dist/primitives/Collapsible/collapsible.variants.d.ts +3 -1
  74. package/dist/primitives/Collapsible/index.d.ts +3 -3
  75. package/dist/primitives/Combobox/Combobox.svelte +20 -31
  76. package/dist/primitives/Combobox/combobox.variants.d.ts +3 -1
  77. package/dist/primitives/Combobox/index.d.ts +5 -3
  78. package/dist/primitives/Dialog/Dialog.svelte +7 -10
  79. package/dist/primitives/Dialog/dialog.variants.d.ts +3 -1
  80. package/dist/primitives/Dialog/index.d.ts +2 -2
  81. package/dist/primitives/Drawer/Drawer.svelte +7 -10
  82. package/dist/primitives/Drawer/drawer.variants.d.ts +3 -1
  83. package/dist/primitives/Drawer/index.d.ts +2 -2
  84. package/dist/primitives/Input/Input.svelte +54 -30
  85. package/dist/primitives/Input/index.d.ts +7 -3
  86. package/dist/primitives/Input/input.variants.d.ts +3 -1
  87. package/dist/primitives/Menu/Menu.svelte +23 -23
  88. package/dist/primitives/Menu/index.d.ts +4 -1
  89. package/dist/primitives/Menu/menu.variants.d.ts +3 -1
  90. package/dist/primitives/Pagination/Pagination.svelte +18 -16
  91. package/dist/primitives/Pagination/index.d.ts +2 -2
  92. package/dist/primitives/Pagination/pagination.variants.d.ts +3 -1
  93. package/dist/primitives/Popover/Popover.svelte +2 -6
  94. package/dist/primitives/Progress/Progress.svelte +17 -17
  95. package/dist/primitives/Progress/index.d.ts +8 -3
  96. package/dist/primitives/Progress/progress.variants.d.ts +3 -1
  97. package/dist/primitives/RadioGroup/RadioGroup.svelte +16 -16
  98. package/dist/primitives/RadioGroup/RadioItem.svelte +19 -19
  99. package/dist/primitives/RadioGroup/index.d.ts +3 -3
  100. package/dist/primitives/RadioGroup/radioGroup.variants.d.ts +4 -1
  101. package/dist/primitives/SegmentGroup/SegmentGroup.svelte +14 -11
  102. package/dist/primitives/SegmentGroup/SegmentItem.svelte +12 -11
  103. package/dist/primitives/SegmentGroup/index.d.ts +3 -3
  104. package/dist/primitives/SegmentGroup/segmentgroup.variants.d.ts +3 -1
  105. package/dist/primitives/Select/Select.svelte +31 -22
  106. package/dist/primitives/Select/index.d.ts +8 -3
  107. package/dist/primitives/Select/select.variants.d.ts +3 -1
  108. package/dist/primitives/Separator/Separator.svelte +2 -6
  109. package/dist/primitives/Sidebar/Sidebar.svelte +6 -9
  110. package/dist/primitives/Sidebar/index.d.ts +2 -2
  111. package/dist/primitives/Sidebar/sidebar.variants.d.ts +3 -1
  112. package/dist/primitives/Skeleton/Skeleton.svelte +7 -9
  113. package/dist/primitives/Skeleton/index.d.ts +3 -3
  114. package/dist/primitives/Skeleton/skeleton.variants.d.ts +3 -1
  115. package/dist/primitives/Skeleton/skeleton.variants.js +5 -6
  116. package/dist/primitives/Slider/Slider.svelte +19 -19
  117. package/dist/primitives/Slider/index.d.ts +8 -3
  118. package/dist/primitives/Slider/slider.variants.d.ts +3 -1
  119. package/dist/primitives/Spinner/Spinner.svelte +7 -9
  120. package/dist/primitives/Spinner/index.d.ts +5 -3
  121. package/dist/primitives/Spinner/spinner.variants.d.ts +3 -1
  122. package/dist/primitives/Stepper/Stepper.svelte +13 -18
  123. package/dist/primitives/Stepper/StepperStep.svelte +18 -19
  124. package/dist/primitives/Stepper/index.d.ts +5 -5
  125. package/dist/primitives/Stepper/stepper.variants.d.ts +3 -1
  126. package/dist/primitives/Tab/Tab.svelte +14 -17
  127. package/dist/primitives/Tab/TabItem.svelte +18 -19
  128. package/dist/primitives/Tab/TabPanel.svelte +10 -13
  129. package/dist/primitives/Tab/index.d.ts +7 -7
  130. package/dist/primitives/Tab/tab.variants.d.ts +3 -1
  131. package/dist/primitives/Textarea/Textarea.svelte +23 -23
  132. package/dist/primitives/Textarea/index.d.ts +7 -3
  133. package/dist/primitives/Textarea/textarea.variants.d.ts +3 -1
  134. package/dist/primitives/Toast/Toaster.svelte +5 -6
  135. package/dist/primitives/Toast/index.d.ts +2 -2
  136. package/dist/primitives/Toast/toast.variants.d.ts +3 -1
  137. package/dist/primitives/Toggle/Toggle.svelte +19 -19
  138. package/dist/primitives/Toggle/index.d.ts +7 -3
  139. package/dist/primitives/Toggle/toggle.variants.d.ts +3 -1
  140. package/dist/primitives/Toolbar/Toolbar.svelte +7 -9
  141. package/dist/primitives/Toolbar/index.d.ts +4 -3
  142. package/dist/primitives/Toolbar/toolbar.variants.d.ts +3 -1
  143. package/dist/primitives/Tooltip/Tooltip.svelte +7 -9
  144. package/dist/primitives/Tooltip/index.d.ts +2 -2
  145. package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -1
  146. package/dist/provider/blocks-context.d.ts +45 -0
  147. package/dist/provider/blocks-context.js +57 -0
  148. package/dist/provider/index.d.ts +1 -1
  149. package/dist/provider/index.js +1 -1
  150. package/dist/style/semantic.css +5 -0
  151. package/dist/utils/variants.d.ts +32 -0
  152. package/dist/utils/variants.js +26 -1
  153. package/package.json +3 -3
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { mintRegistry } from '../..';
3
- import { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from '../../provider';
3
+ import { getBlocksConfig, resolveSlotClasses } from '../../provider';
4
4
  import { useFormField, getTierContext } from '../../utils';
5
5
  import type { TextareaProps } from './index';
6
- import { textareaVariants } from './textarea.variants';
6
+ import { textareaVariants, type TextareaVariants } from './textarea.variants';
7
7
 
8
8
  let {
9
9
  label,
@@ -36,13 +36,6 @@
36
36
 
37
37
  const blocksConfig = getBlocksConfig();
38
38
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
39
- const slotClasses = $derived(
40
- mergeSlotClasses(
41
- blocksConfig?.defaults?.Textarea?.slotClasses,
42
- resolvePresetSlotClasses(blocksConfig?.presets, 'Textarea', preset),
43
- slotClassesProp
44
- )
45
- );
46
39
 
47
40
  let textareaRef = $state<HTMLTextAreaElement>();
48
41
 
@@ -66,20 +59,27 @@
66
59
 
67
60
  const showFooter = $derived(!!error || !!helper || (showCounter && maxlength));
68
61
 
69
- const styles = $derived(
70
- textareaVariants({
71
- tier: effectiveTier,
72
- variant,
73
- size,
74
- intent,
75
- autoResize: autoResize || undefined,
76
- disabled: disabled || undefined,
77
- readonly: readonly || undefined,
78
- error: !!error || undefined,
79
- required: required || undefined,
80
- messageType: error ? 'error' : 'helper',
81
- counterState
82
- })
62
+ // Variant props feed both the tv() style computation and the slot-class
63
+ // cascade — extracted into one derived so `resolveSlotClasses` can match
64
+ // conditional `overrides` against the textarea's active variants.
65
+ const variantProps: TextareaVariants = $derived({
66
+ tier: effectiveTier,
67
+ variant,
68
+ size,
69
+ intent,
70
+ autoResize: autoResize || undefined,
71
+ disabled: disabled || undefined,
72
+ readonly: readonly || undefined,
73
+ error: !!error || undefined,
74
+ required: required || undefined,
75
+ messageType: error ? 'error' : 'helper',
76
+ counterState
77
+ });
78
+
79
+ const styles = $derived(textareaVariants(variantProps));
80
+
81
+ const slotClasses = $derived(
82
+ resolveSlotClasses(blocksConfig, 'Textarea', preset, variantProps, slotClassesProp)
83
83
  );
84
84
 
85
85
  const lineHeight = $derived(size === 'sm' ? 20 : size === 'lg' ? 28 : 24);
@@ -1,6 +1,6 @@
1
1
  import type { HTMLTextareaAttributes } from 'svelte/elements';
2
2
  import type { MintProp } from '../../mint';
3
- import type { TextareaVariants } from './textarea.variants';
3
+ import type { TextareaSlots, TextareaVariants } from './textarea.variants';
4
4
  /**
5
5
  * @description Multi-line text input with auto-resize, character counter, and validation states.
6
6
  * Shares the same variant/intent/size system as Input for visual consistency.
@@ -59,8 +59,12 @@ export interface TextareaProps extends Omit<TextareaVariants, 'error' | 'counter
59
59
  class?: string;
60
60
  /** Remove all default tv() classes. Only user-provided classes apply. */
61
61
  unstyled?: boolean;
62
- /** Per-slot class overrides merged with tv() styles. */
63
- slotClasses?: Partial<Record<'wrapper' | 'base' | 'label' | 'footer' | 'message' | 'counter', string>>;
62
+ /**
63
+ * Per-slot class overrides merged with tv() styles. Slots: wrapper (root
64
+ * what `class` also targets) | base (the `<textarea>` element) | label |
65
+ * footer | message | counter.
66
+ */
67
+ slotClasses?: Partial<Record<TextareaSlots, string>>;
64
68
  /**
65
69
  * Apply a named preset registered via `<BlocksProvider presets={{ Textarea: {...} }}>`.
66
70
  * Prefer this over `class` overrides when the requested look falls outside the
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/variants';
1
+ import { type SlotNames, type VariantProps } from '../../utils/variants';
2
2
  export declare const textareaVariants: (props?: import("../../utils/variants").TVProps<{
3
3
  tier: {
4
4
  modify: {
@@ -191,3 +191,5 @@ export declare const textareaVariants: (props?: import("../../utils/variants").T
191
191
  }) | undefined) => string;
192
192
  };
193
193
  export type TextareaVariants = VariantProps<typeof textareaVariants>;
194
+ /** Slot names derived from the `tv()` config above — single source of truth for `slotClasses`. */
195
+ export type TextareaSlots = SlotNames<typeof textareaVariants>;
@@ -10,7 +10,7 @@
10
10
  import SuccessCircleIconDefault from '../../icons/SuccessCircleIcon.svelte';
11
11
  import WarningTriangleIconDefault from '../../icons/WarningTriangleIcon.svelte';
12
12
  import DangerCircleIconDefault from '../../icons/DangerCircleIcon.svelte';
13
- import { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from '../../provider';
13
+ import { getBlocksConfig, resolveSlotClasses } from '../../provider';
14
14
  import type { ToastProps } from './index';
15
15
 
16
16
  const bt = useBlocksI18n();
@@ -38,12 +38,11 @@
38
38
 
39
39
  const blocksConfig = getBlocksConfig();
40
40
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
41
+ // Component-level slot-class cascade. Per-toast `intent` is NOT part of
42
+ // activeProps — it is applied per row in the `slot(key, intent)` helper via
43
+ // its own `toastVariants({ placement, intent })` call (see below).
41
44
  const slotClasses = $derived(
42
- mergeSlotClasses(
43
- blocksConfig?.defaults?.Toaster?.slotClasses,
44
- resolvePresetSlotClasses(blocksConfig?.presets, 'Toaster', preset),
45
- slotClassesProp
46
- )
45
+ resolveSlotClasses(blocksConfig, 'Toaster', preset, { placement }, slotClassesProp)
47
46
  );
48
47
 
49
48
  $effect(() => {
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- import type { ToastPlacement } from './toast.variants';
2
+ import type { ToasterSlots, ToastPlacement } from './toast.variants';
3
3
  /**
4
4
  * Canonical intents accepted by the toaster. Use as a runtime list when
5
5
  * building dispatchers (e.g. `toaster[intent]?.(title, opts)`); use
@@ -82,7 +82,7 @@ export interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, 'childr
82
82
  /** Strip all default tv classes. Use with `slotClasses` for a fully custom look. */
83
83
  unstyled?: boolean;
84
84
  /** Per-slot class overrides merged with (or replacing, when `unstyled`) the default styles. */
85
- slotClasses?: Partial<Record<'container' | 'toast' | 'icon' | 'content' | 'title' | 'description' | 'dismissButton' | 'progress', string>>;
85
+ slotClasses?: Partial<Record<ToasterSlots, string>>;
86
86
  /**
87
87
  * Apply a named preset registered via `<BlocksProvider presets={{ Toaster: {...} }}>`.
88
88
  * Prefer this over `class` overrides when the requested look falls outside the
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/variants';
1
+ import { type SlotNames, type VariantProps } from '../../utils/variants';
2
2
  export declare const toastVariants: (props?: import("../../utils/variants").TVProps<{
3
3
  intent: {
4
4
  primary: {
@@ -111,4 +111,6 @@ export declare const toastVariants: (props?: import("../../utils/variants").TVPr
111
111
  }) | undefined) => string;
112
112
  };
113
113
  export type ToastVariants = VariantProps<typeof toastVariants>;
114
+ /** Slot names derived from the tv() config — single source of truth for slotClasses. */
115
+ export type ToasterSlots = SlotNames<typeof toastVariants>;
114
116
  export type ToastPlacement = 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center';
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { useBlocksI18n, mintRegistry } from '../..';
3
- import { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from '../../provider';
3
+ import { getBlocksConfig, resolveSlotClasses } from '../../provider';
4
4
  import { getTierContext, useFormField } from '../../utils';
5
- import { toggleVariants } from './toggle.variants';
5
+ import { toggleVariants, type ToggleVariants } from './toggle.variants';
6
6
  import type { ToggleProps } from './index';
7
7
 
8
8
  const bt = useBlocksI18n();
@@ -42,13 +42,6 @@
42
42
 
43
43
  const blocksConfig = getBlocksConfig();
44
44
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
45
- const slotClasses = $derived(
46
- mergeSlotClasses(
47
- blocksConfig?.defaults?.Toggle?.slotClasses,
48
- resolvePresetSlotClasses(blocksConfig?.presets, 'Toggle', preset),
49
- slotClassesProp
50
- )
51
- );
52
45
 
53
46
  let rootEl = $state<HTMLElement>();
54
47
 
@@ -58,16 +51,23 @@
58
51
  const tierCtx = getTierContext();
59
52
  const effectiveTier = $derived(tier ?? tierCtx?.tier ?? 'commit');
60
53
 
61
- const styles = $derived(
62
- toggleVariants({
63
- tier: effectiveTier,
64
- size,
65
- intent,
66
- appearance,
67
- checked,
68
- disabled,
69
- withBorder
70
- })
54
+ // Variant props feed both the tv() style computation and the slot-class
55
+ // cascade — extracted into one derived so `resolveSlotClasses` can match
56
+ // conditional `overrides` against the toggle's active variants.
57
+ const variantProps: ToggleVariants = $derived({
58
+ tier: effectiveTier,
59
+ size,
60
+ intent,
61
+ appearance,
62
+ checked,
63
+ disabled,
64
+ withBorder
65
+ });
66
+
67
+ const styles = $derived(toggleVariants(variantProps));
68
+
69
+ const slotClasses = $derived(
70
+ resolveSlotClasses(blocksConfig, 'Toggle', preset, variantProps, slotClassesProp)
71
71
  );
72
72
 
73
73
  const dataState = $derived(checked ? 'checked' : 'unchecked');
@@ -1,7 +1,7 @@
1
1
  import type { HTMLInputAttributes } from 'svelte/elements';
2
2
  import type { MintProp } from '../../mint';
3
3
  import type { InteractiveTier } from '../../utils';
4
- import type { ToggleVariants } from './toggle.variants';
4
+ import type { ToggleSlots, ToggleVariants } from './toggle.variants';
5
5
  /**
6
6
  * @description Accessible switch control for boolean on/off states.
7
7
  * Built on a hidden native input with semantic intents and Mint micro-interactions.
@@ -43,8 +43,12 @@ export interface ToggleProps extends Omit<ToggleVariants, 'checked'>, Omit<HTMLI
43
43
  class?: string;
44
44
  /** Strip all default tailwind-variants classes. Use with `slotClasses` for a fully custom look. The track exposes `data-state` for conditional styling. */
45
45
  unstyled?: boolean;
46
- /** Per-slot class overrides merged with (or replacing, when `unstyled`) the default styles. */
47
- slotClasses?: Partial<Record<'wrapper' | 'control' | 'track' | 'thumb' | 'label' | 'message', string>>;
46
+ /**
47
+ * Per-slot class overrides merged with (or replacing, when `unstyled`) the
48
+ * default styles. Slots: wrapper (root — what `class` also targets) | control
49
+ * (the `<label>` wrapping the input) | track | thumb | label | message.
50
+ */
51
+ slotClasses?: Partial<Record<ToggleSlots, string>>;
48
52
  /**
49
53
  * Apply a named preset registered via `<BlocksProvider presets={{ Toggle: {...} }}>`.
50
54
  * Prefer this over `class` overrides when the requested look falls outside the
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/variants';
1
+ import { type SlotNames, type VariantProps } from '../../utils/variants';
2
2
  export declare const toggleVariants: (props?: import("../../utils/variants").TVProps<{
3
3
  tier: {
4
4
  commit: {
@@ -132,3 +132,5 @@ export declare const toggleVariants: (props?: import("../../utils/variants").TVP
132
132
  }) | undefined) => string;
133
133
  };
134
134
  export type ToggleVariants = VariantProps<typeof toggleVariants>;
135
+ /** Slot names derived from the `tv()` config above — single source of truth for `slotClasses`. */
136
+ export type ToggleSlots = SlotNames<typeof toggleVariants>;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
- import { toolbarVariants } from './toolbar.variants';
2
+ import { toolbarVariants, type ToolbarVariants } from './toolbar.variants';
3
3
  import type { ToolbarProps } from './index';
4
- import { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from '../../provider';
4
+ import { getBlocksConfig, resolveSlotClasses } from '../../provider';
5
5
  import { setTierContext } from '../../utils/tier-context';
6
6
 
7
7
  let {
@@ -30,15 +30,13 @@
30
30
 
31
31
  const blocksConfig = getBlocksConfig();
32
32
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
33
+
34
+ const variantProps: ToolbarVariants = $derived({ variant, orientation, gap, padding });
35
+ const styles = $derived(toolbarVariants(variantProps));
36
+
33
37
  const slotClasses = $derived(
34
- mergeSlotClasses(
35
- blocksConfig?.defaults?.Toolbar?.slotClasses,
36
- resolvePresetSlotClasses(blocksConfig?.presets, 'Toolbar', preset),
37
- slotClassesProp
38
- )
38
+ resolveSlotClasses(blocksConfig, 'Toolbar', preset, variantProps, slotClassesProp)
39
39
  );
40
-
41
- const styles = $derived(toolbarVariants({ variant, orientation, gap, padding }));
42
40
  </script>
43
41
 
44
42
  <div
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { InteractiveTier } from '../../utils';
4
- import type { ToolbarVariants } from './toolbar.variants';
4
+ import type { ToolbarSlots, ToolbarVariants } from './toolbar.variants';
5
5
  /**
6
6
  * Props interface for Toolbar component
7
7
  *
@@ -54,8 +54,9 @@ export interface ToolbarProps extends ToolbarVariants, Omit<HTMLAttributes<HTMLD
54
54
  tier?: InteractiveTier;
55
55
  /** Remove all default tv() classes. Combine with `slotClasses` to restyle from scratch. */
56
56
  unstyled?: boolean;
57
- /** Per-slot class overrides merged with (or replacing when `unstyled`) the default classes. */
58
- slotClasses?: Partial<Record<'base', string>>;
57
+ /** Per-slot class overrides merged with (or replacing when `unstyled`) the default classes.
58
+ * Slots: base */
59
+ slotClasses?: Partial<Record<ToolbarSlots, string>>;
59
60
  /**
60
61
  * Apply a named preset registered via `<BlocksProvider presets={{ Toolbar: {...} }}>`.
61
62
  * Prefer this over `class` overrides when the requested look falls outside the
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/variants';
1
+ import { type SlotNames, type VariantProps } from '../../utils/variants';
2
2
  export declare const toolbarVariants: (props?: import("../../utils/variants").TVProps<{
3
3
  variant: {
4
4
  quiet: {
@@ -68,3 +68,5 @@ export declare const toolbarVariants: (props?: import("../../utils/variants").TV
68
68
  }) | undefined) => string;
69
69
  };
70
70
  export type ToolbarVariants = VariantProps<typeof toolbarVariants>;
71
+ /** Slot names derived from the tv() config — single source of truth for slotClasses. */
72
+ export type ToolbarSlots = SlotNames<typeof toolbarVariants>;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { tooltipVariants } from './tooltip.variants';
3
+ import type { VariantProps } from '../../utils/variants';
3
4
  import type { TooltipProps } from './index';
4
- import { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from '../../provider';
5
+ import { getBlocksConfig, resolveSlotClasses } from '../../provider';
5
6
  import {
6
7
  computePosition,
7
8
  autoUpdate,
@@ -31,13 +32,6 @@
31
32
 
32
33
  const blocksConfig = getBlocksConfig();
33
34
  const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
34
- const slotClasses = $derived(
35
- mergeSlotClasses(
36
- blocksConfig?.defaults?.Tooltip?.slotClasses,
37
- resolvePresetSlotClasses(blocksConfig?.presets, 'Tooltip', preset),
38
- slotClassesProp
39
- )
40
- );
41
35
 
42
36
  let visible = $state(false);
43
37
  let triggerElement = $state<HTMLElement>();
@@ -48,7 +42,11 @@
48
42
  const propsId = $props.id();
49
43
  const tooltipId = `tooltip-${propsId}`;
50
44
 
51
- const styles = $derived(tooltipVariants({ visible, intent, size }));
45
+ const variantProps: VariantProps<typeof tooltipVariants> = $derived({ visible, intent, size });
46
+ const styles = $derived(tooltipVariants(variantProps));
47
+ const slotClasses = $derived(
48
+ resolveSlotClasses(blocksConfig, 'Tooltip', preset, variantProps, slotClassesProp)
49
+ );
52
50
 
53
51
  let showTimeout: number;
54
52
  let hideTimeout: number;
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { Placement } from '../../utils/floating';
4
- import type { TooltipVariants } from './tooltip.variants';
4
+ import type { TooltipSlots, TooltipVariants } from './tooltip.variants';
5
5
  /**
6
6
  * @description Contextual overlay that displays brief, supplementary text on hover or focus.
7
7
  * Built with Floating UI for precise positioning and accessibility support.
@@ -43,7 +43,7 @@ export interface TooltipProps extends TooltipVariants, Omit<HTMLAttributes<HTMLD
43
43
  /** Remove default tv classes; only consumer classes apply. */
44
44
  unstyled?: boolean;
45
45
  /** Per-slot class overrides merged with (or replacing, when unstyled) tv styles. */
46
- slotClasses?: Partial<Record<'base' | 'arrow', string>>;
46
+ slotClasses?: Partial<Record<TooltipSlots, string>>;
47
47
  /**
48
48
  * Apply a named preset registered via `<BlocksProvider presets={{ Tooltip: {...} }}>`.
49
49
  * Prefer this over `class` overrides when the requested look falls outside the
@@ -1,4 +1,4 @@
1
- import { type VariantProps } from '../../utils/variants';
1
+ import { type SlotNames, type VariantProps } from '../../utils/variants';
2
2
  export declare const tooltipVariants: (props?: import("../../utils/variants").TVProps<{
3
3
  visible: {
4
4
  true: {
@@ -61,3 +61,5 @@ export declare const tooltipVariants: (props?: import("../../utils/variants").TV
61
61
  }) | undefined) => string;
62
62
  };
63
63
  export type TooltipVariants = Omit<VariantProps<typeof tooltipVariants>, 'visible'>;
64
+ /** Slot names derived from the `tv()` config above — single source of truth for `slotClasses`. */
65
+ export type TooltipSlots = SlotNames<typeof tooltipVariants>;
@@ -1,5 +1,28 @@
1
+ /**
2
+ * A prop-conditional style rule. Its non-`class` keys are matched against a
3
+ * component's active variant props — exactly like a `tv()` compoundVariant
4
+ * (`string` = equality, `string[]` = "one of"). On a match, the `class`
5
+ * record (slot → classes) is merged into the slot-class cascade. Additive:
6
+ * every matching rule contributes; later sources win per Tailwind bucket.
7
+ *
8
+ * @example
9
+ * { variant: 'outlined', class: { base: 'border' } } // 1px border only on outlined
10
+ */
11
+ export interface ConditionalOverride {
12
+ /** Per-slot classes applied when the prop conditions match. */
13
+ class: Record<string, string>;
14
+ /** Prop conditions: prop name → required value (or one of several). */
15
+ [propCondition: string]: string | string[] | Record<string, string> | undefined;
16
+ }
1
17
  export interface ComponentDefaults {
2
18
  slotClasses?: Record<string, string>;
19
+ /**
20
+ * Prop-conditional style rules, applied after unconditional `slotClasses`
21
+ * (so they win per bucket) but before instance-level `slotClasses` / `class`.
22
+ * Use for surgical per-variant tweaks the unconditional `slotClasses` cannot
23
+ * express, e.g. `overrides: [{ variant: 'outlined', class: { base: 'border' } }]`.
24
+ */
25
+ overrides?: ConditionalOverride[];
3
26
  }
4
27
  /**
5
28
  * A preset is a named, project-defined visual style for a component.
@@ -12,6 +35,8 @@ export interface ComponentDefaults {
12
35
  */
13
36
  export interface ComponentPreset {
14
37
  slotClasses?: Record<string, string>;
38
+ /** Prop-conditional rules scoped to this preset (see {@link ConditionalOverride}). */
39
+ overrides?: ConditionalOverride[];
15
40
  }
16
41
  /** Map of component name → preset name → preset definition. */
17
42
  export type PresetMap = Record<string, Record<string, ComponentPreset>>;
@@ -30,3 +55,23 @@ export declare function mergeSlotClasses(...sources: (Record<string, string> | u
30
55
  * is used but not registered, so missing presets are discoverable.
31
56
  */
32
57
  export declare function resolvePresetSlotClasses(presets: PresetMap | undefined, component: string, presetName: string | undefined): Record<string, string> | undefined;
58
+ /**
59
+ * Collect the per-slot classes of every `overrides` entry whose prop
60
+ * conditions match `activeProps`. Returns `undefined` when there are no
61
+ * overrides or none match. Multiple matches merge additively, in order.
62
+ */
63
+ export declare function resolveOverrideSlotClasses(overrides: ConditionalOverride[] | undefined, activeProps: Record<string, unknown>): Record<string, string> | undefined;
64
+ /**
65
+ * Resolve the full slot-class cascade for a component instance, honoring
66
+ * conditional `overrides` from both provider defaults and the active preset.
67
+ *
68
+ * Precedence (weak → strong), conflict-resolved per slot so a later source
69
+ * wins within the same Tailwind bucket:
70
+ *
71
+ * defaults.slotClasses → defaults.overrides[match]
72
+ * → preset.slotClasses → preset.overrides[match] → instance.slotClasses
73
+ *
74
+ * The result is handed to the component's `tv()` slot fn as the `class`
75
+ * override, where it additionally strips conflicting library classes.
76
+ */
77
+ export declare function resolveSlotClasses(config: BlocksConfig | undefined, component: string, preset: string | undefined, activeProps: Record<string, unknown>, instanceSlotClasses: Record<string, string> | undefined): Record<string, string>;
@@ -1,4 +1,5 @@
1
1
  import { createOptionalContext } from '../utils/optional-context';
2
+ import { matchesCompound, resolveClassChain } from '../utils/variants';
2
3
  // BlocksProvider is optional — components must work without one.
3
4
  const [getBlocksConfig, setBlocksConfig] = createOptionalContext();
4
5
  export { getBlocksConfig, setBlocksConfig };
@@ -34,3 +35,59 @@ export function resolvePresetSlotClasses(presets, component, presetName) {
34
35
  }
35
36
  return preset.slotClasses;
36
37
  }
38
+ /**
39
+ * Collect the per-slot classes of every `overrides` entry whose prop
40
+ * conditions match `activeProps`. Returns `undefined` when there are no
41
+ * overrides or none match. Multiple matches merge additively, in order.
42
+ */
43
+ export function resolveOverrideSlotClasses(overrides, activeProps) {
44
+ if (!overrides || overrides.length === 0)
45
+ return undefined;
46
+ let result;
47
+ for (const entry of overrides) {
48
+ if (!matchesCompound(entry, activeProps))
49
+ continue;
50
+ result ??= {};
51
+ for (const [slot, value] of Object.entries(entry.class)) {
52
+ if (!value)
53
+ continue;
54
+ result[slot] = result[slot] ? `${result[slot]} ${value}` : value;
55
+ }
56
+ }
57
+ return result;
58
+ }
59
+ /**
60
+ * Resolve the full slot-class cascade for a component instance, honoring
61
+ * conditional `overrides` from both provider defaults and the active preset.
62
+ *
63
+ * Precedence (weak → strong), conflict-resolved per slot so a later source
64
+ * wins within the same Tailwind bucket:
65
+ *
66
+ * defaults.slotClasses → defaults.overrides[match]
67
+ * → preset.slotClasses → preset.overrides[match] → instance.slotClasses
68
+ *
69
+ * The result is handed to the component's `tv()` slot fn as the `class`
70
+ * override, where it additionally strips conflicting library classes.
71
+ */
72
+ export function resolveSlotClasses(config, component, preset, activeProps, instanceSlotClasses) {
73
+ const defaults = config?.defaults?.[component];
74
+ const presetDef = preset ? config?.presets?.[component]?.[preset] : undefined;
75
+ const sources = [
76
+ defaults?.slotClasses,
77
+ resolveOverrideSlotClasses(defaults?.overrides, activeProps),
78
+ resolvePresetSlotClasses(config?.presets, component, preset),
79
+ resolveOverrideSlotClasses(presetDef?.overrides, activeProps),
80
+ instanceSlotClasses
81
+ ];
82
+ const result = {};
83
+ for (const source of sources) {
84
+ if (!source)
85
+ continue;
86
+ for (const [slot, value] of Object.entries(source)) {
87
+ if (!value)
88
+ continue;
89
+ result[slot] = result[slot] ? resolveClassChain(result[slot], value) : value;
90
+ }
91
+ }
92
+ return result;
93
+ }
@@ -1,2 +1,2 @@
1
1
  export { default as BlocksProvider } from './BlocksProvider.svelte';
2
- export { type BlocksConfig, type ComponentDefaults, type ComponentPreset, getBlocksConfig, mergeSlotClasses, type PresetMap, resolvePresetSlotClasses } from './blocks-context';
2
+ export { type BlocksConfig, type ComponentDefaults, type ComponentPreset, type ConditionalOverride, getBlocksConfig, mergeSlotClasses, type PresetMap, resolveOverrideSlotClasses, resolvePresetSlotClasses, resolveSlotClasses } from './blocks-context';
@@ -1,2 +1,2 @@
1
1
  export { default as BlocksProvider } from './BlocksProvider.svelte';
2
- export { getBlocksConfig, mergeSlotClasses, resolvePresetSlotClasses } from './blocks-context';
2
+ export { getBlocksConfig, mergeSlotClasses, resolveOverrideSlotClasses, resolvePresetSlotClasses, resolveSlotClasses } from './blocks-context';
@@ -38,6 +38,11 @@
38
38
  --color-surface-selected: light-dark(var(--color-primary-50), var(--color-primary-900));
39
39
  --color-surface-subtle: light-dark(var(--color-neutral-50), var(--color-neutral-800));
40
40
  --color-surface-inverted: light-dark(var(--color-neutral-900), var(--color-neutral-100));
41
+ /* Skeleton wave-shimmer highlight (Skeleton animation="wave"). A translucent
42
+ white glint that sweeps across `surface-interactive`; lower alpha in dark
43
+ mode so it reads as a subtle sheen, not a flash. light-dark() keeps it
44
+ mode-aware so the wave needs no `dark:` override. */
45
+ --color-skeleton-shimmer: light-dark(oklch(1 0 0 / 0.5), oklch(1 0 0 / 0.1));
41
46
 
42
47
  /* === TEXT ===
43
48
  tertiary/quaternary shifted darker (light) so informative text on
@@ -16,6 +16,23 @@ type CompoundVariant<V extends Record<string, Record<string, unknown>>> = {
16
16
  };
17
17
  export type TVProps<V extends Record<string, Record<string, unknown>>> = VariantPropsMap<V> & TVClassOverrides;
18
18
  export type VariantProps<T extends (...args: never[]) => unknown> = Omit<Exclude<Parameters<T>[0], undefined>, 'class' | 'className'>;
19
+ /**
20
+ * Extracts the slot-name union from a slotted `tv()` config function — the
21
+ * companion to {@link VariantProps}. The slot-mode overload returns
22
+ * `(props?) => { [K in keyof S]: SlotFn }`, so `keyof ReturnType<T>` is exactly
23
+ * the set of slot names a component declares in `tv({ slots: … })`.
24
+ *
25
+ * Use it to type a component's `slotClasses` prop from the single source of
26
+ * truth (its `*.variants.ts`) instead of hand-maintaining a parallel union
27
+ * that silently drifts when a slot is added or renamed:
28
+ *
29
+ * @example
30
+ * // button.variants.ts
31
+ * export type ButtonSlots = SlotNames<typeof buttonVariants>; // 'base' | 'content' | 'spinner'
32
+ * // index.ts
33
+ * slotClasses?: Partial<Record<ButtonSlots, string>>;
34
+ */
35
+ export type SlotNames<T extends (...args: never[]) => unknown> = keyof ReturnType<T> & string;
19
36
  /**
20
37
  * Concatenate class inputs into a single string. Accepts strings, nested
21
38
  * arrays, and falsy values (filtered out). Trims and joins with single
@@ -27,6 +44,21 @@ export type VariantProps<T extends (...args: never[]) => unknown> = Omit<Exclude
27
44
  * pass. See `docs/ARCHITECTURE.md` "tv() engine — explicit trade-offs".
28
45
  */
29
46
  export declare function cx(...inputs: ClassInput[]): string;
47
+ /**
48
+ * Merge class strings with the same Tailwind conflict resolution `tv()`
49
+ * applies between stages: a later source's classes strip any earlier class
50
+ * that shares their conflict bucket, so the last source wins per bucket.
51
+ * Within a single source, order is preserved and conflicts fall through to
52
+ * the CSS cascade. Falsy / empty sources are skipped.
53
+ *
54
+ * Reuses `tokenize` + `stripConflicts`. Powers the BlocksProvider slot-class
55
+ * cascade (`resolveSlotClasses`) so a conditional `overrides` entry
56
+ * deterministically defeats an unconditional `slotClasses` entry in the same
57
+ * bucket — instead of emitting both and leaving the winner to stylesheet
58
+ * order.
59
+ */
60
+ export declare function resolveClassChain(...sources: (string | null | undefined)[]): string;
61
+ export declare function matchesCompound(compound: Record<string, unknown>, effectiveProps: Record<string, unknown>): boolean;
30
62
  export declare function tv<V extends Record<string, Record<string, unknown>> = {}>(config: {
31
63
  base?: string | string[];
32
64
  variants?: V;
@@ -317,6 +317,31 @@ function tokenize(value) {
317
317
  return [];
318
318
  return value.split(/\s+/).filter(Boolean);
319
319
  }
320
+ /**
321
+ * Merge class strings with the same Tailwind conflict resolution `tv()`
322
+ * applies between stages: a later source's classes strip any earlier class
323
+ * that shares their conflict bucket, so the last source wins per bucket.
324
+ * Within a single source, order is preserved and conflicts fall through to
325
+ * the CSS cascade. Falsy / empty sources are skipped.
326
+ *
327
+ * Reuses `tokenize` + `stripConflicts`. Powers the BlocksProvider slot-class
328
+ * cascade (`resolveSlotClasses`) so a conditional `overrides` entry
329
+ * deterministically defeats an unconditional `slotClasses` entry in the same
330
+ * bucket — instead of emitting both and leaving the winner to stylesheet
331
+ * order.
332
+ */
333
+ export function resolveClassChain(...sources) {
334
+ let acc = [];
335
+ for (const source of sources) {
336
+ if (!source)
337
+ continue;
338
+ const tokens = tokenize(source);
339
+ if (tokens.length === 0)
340
+ continue;
341
+ acc = [...stripConflicts(acc, tokens), ...tokens];
342
+ }
343
+ return acc.join(' ');
344
+ }
320
345
  // ─── Internal Helpers ────────────────────────────────────────────────────────
321
346
  function falsyToString(value) {
322
347
  if (value === false)
@@ -337,7 +362,7 @@ function stripUndefined(obj) {
337
362
  }
338
363
  return result;
339
364
  }
340
- function matchesCompound(compound, effectiveProps) {
365
+ export function matchesCompound(compound, effectiveProps) {
341
366
  for (const key of Object.keys(compound)) {
342
367
  if (key === 'class' || key === 'className')
343
368
  continue;