@svelte-atoms/core 1.0.0-alpha.24 → 1.0.0-alpha.26

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 (177) hide show
  1. package/dist/components/accordion/accordion-root.svelte +1 -1
  2. package/dist/components/accordion/accordion-root.svelte.d.ts +2 -2
  3. package/dist/components/accordion/item/accordion-item-body.svelte +1 -1
  4. package/dist/components/accordion/item/accordion-item-header.svelte +5 -1
  5. package/dist/components/accordion/item/accordion-item-indicator.svelte +1 -1
  6. package/dist/components/accordion/item/accordion-item-root.svelte +1 -1
  7. package/dist/components/alert/alert-actions.svelte +1 -1
  8. package/dist/components/alert/alert-actions.svelte.d.ts +1 -0
  9. package/dist/components/alert/alert-close-button.svelte +1 -1
  10. package/dist/components/alert/alert-close-button.svelte.d.ts +1 -0
  11. package/dist/components/alert/alert-content.svelte +1 -1
  12. package/dist/components/alert/alert-content.svelte.d.ts +1 -0
  13. package/dist/components/alert/alert-description.svelte +1 -1
  14. package/dist/components/alert/alert-icon.svelte +1 -1
  15. package/dist/components/alert/alert-root.svelte +1 -1
  16. package/dist/components/alert/alert-title.svelte +1 -1
  17. package/dist/components/atom/html-atom.svelte +147 -16
  18. package/dist/components/atom/html-atom.svelte.d.ts +4 -2
  19. package/dist/components/atom/types.d.ts +7 -0
  20. package/dist/components/badge/badge.svelte +1 -1
  21. package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
  22. package/dist/components/breadcrumb/breadcrumb-root.svelte +1 -1
  23. package/dist/components/breadcrumb/breadcrumb-separator.svelte +1 -1
  24. package/dist/components/button/button.stories.svelte +41 -1
  25. package/dist/components/button/button.stories.svelte.d.ts +6 -14
  26. package/dist/components/button/button.svelte +1 -1
  27. package/dist/components/button/button.svelte.d.ts +4 -1
  28. package/dist/components/button/types.d.ts +1 -1
  29. package/dist/components/card/card-body.svelte +1 -1
  30. package/dist/components/card/card-description.svelte +1 -1
  31. package/dist/components/card/card-footer.svelte +1 -1
  32. package/dist/components/card/card-header.svelte +1 -1
  33. package/dist/components/card/card-media.svelte +1 -1
  34. package/dist/components/card/card-subtitle.svelte +1 -1
  35. package/dist/components/card/card-title.svelte +5 -1
  36. package/dist/components/checkbox/checkbox.svelte +39 -28
  37. package/dist/components/checkbox/checkbox.svelte.d.ts +1 -1
  38. package/dist/components/collapsible/collapsible-body.svelte +1 -1
  39. package/dist/components/collapsible/collapsible-header.svelte +1 -1
  40. package/dist/components/collapsible/collapsible-indicator.svelte +1 -1
  41. package/dist/components/collapsible/collapsible-root.svelte +1 -1
  42. package/dist/components/combobox/atoms.d.ts +5 -1
  43. package/dist/components/combobox/atoms.js +5 -1
  44. package/dist/components/combobox/{combobox-input.svelte → combobox-control.svelte} +3 -3
  45. package/dist/components/combobox/{combobox-input.svelte.d.ts → combobox-control.svelte.d.ts} +3 -3
  46. package/dist/components/combobox/combobox-root.svelte.d.ts +2 -2
  47. package/dist/components/combobox/combobox-trigger.svelte +1 -1
  48. package/dist/components/combobox/compobox-item.svelte +1 -1
  49. package/dist/components/container/container.svelte +1 -1
  50. package/dist/components/datagrid/datagrid-body.svelte +1 -1
  51. package/dist/components/datagrid/datagrid-footer.svelte +1 -1
  52. package/dist/components/datagrid/datagrid-header.svelte +1 -1
  53. package/dist/components/datagrid/datagrid-root.svelte +1 -1
  54. package/dist/components/datagrid/td/datagrid-td.svelte +1 -1
  55. package/dist/components/datagrid/th/datagrid-th-sort-icon.svelte +1 -1
  56. package/dist/components/datagrid/th/datagrid-th.svelte +1 -1
  57. package/dist/components/dialog/dialog-body.svelte +1 -1
  58. package/dist/components/dialog/dialog-close-button.svelte +1 -1
  59. package/dist/components/dialog/dialog-content.svelte +8 -11
  60. package/dist/components/dialog/dialog-description.svelte +1 -1
  61. package/dist/components/dialog/dialog-footer.svelte +1 -1
  62. package/dist/components/dialog/dialog-header.svelte +1 -1
  63. package/dist/components/dialog/dialog-root.svelte +123 -120
  64. package/dist/components/dialog/dialog-root.svelte.d.ts +3 -1
  65. package/dist/components/dialog/dialog-title.svelte +1 -1
  66. package/dist/components/drawer/drawer-backdrop.svelte +1 -1
  67. package/dist/components/drawer/drawer-backdrop.svelte.d.ts +1 -0
  68. package/dist/components/drawer/drawer-body.svelte +1 -1
  69. package/dist/components/drawer/drawer-description.svelte +1 -1
  70. package/dist/components/drawer/drawer-footer.svelte +1 -1
  71. package/dist/components/drawer/drawer-header.svelte +1 -1
  72. package/dist/components/drawer/drawer-root.svelte +118 -113
  73. package/dist/components/drawer/drawer-root.svelte.d.ts +5 -2
  74. package/dist/components/drawer/drawer-title.svelte +1 -1
  75. package/dist/components/dropdown/dropdown-placeholder.svelte +1 -1
  76. package/dist/components/dropdown/dropdown-query.svelte +1 -1
  77. package/dist/components/dropdown/dropdown-trigger.svelte +1 -1
  78. package/dist/components/dropdown/dropdown-value.svelte +1 -3
  79. package/dist/components/dropdown/item/bond.svelte.d.ts +4 -0
  80. package/dist/components/dropdown/item/bond.svelte.js +9 -0
  81. package/dist/components/dropdown/item/dropdown-item.svelte +10 -6
  82. package/dist/components/form/field/bond.svelte.d.ts +8 -0
  83. package/dist/components/form/field/bond.svelte.js +13 -1
  84. package/dist/components/form/field/field-control.svelte +7 -0
  85. package/dist/components/form/field/field-control.svelte.d.ts +2 -2
  86. package/dist/components/form/form.stories.svelte +3 -3
  87. package/dist/components/icon/icon.svelte.d.ts +1 -0
  88. package/dist/components/input/atoms.d.ts +5 -1
  89. package/dist/components/input/atoms.js +5 -1
  90. package/dist/components/input/{input-value.svelte → input-control.svelte} +14 -20
  91. package/dist/components/input/input-control.svelte.d.ts +27 -0
  92. package/dist/components/input/input-icon.svelte +1 -1
  93. package/dist/components/input/input-placeholder.svelte +1 -3
  94. package/dist/components/input/input-placeholder.svelte.d.ts +1 -0
  95. package/dist/components/input/input-root.svelte +5 -12
  96. package/dist/components/input/input-root.svelte.d.ts +3 -19
  97. package/dist/components/input/input.stories.svelte +2 -2
  98. package/dist/components/input/types.d.ts +22 -0
  99. package/dist/components/input/types.js +1 -0
  100. package/dist/components/label/label.svelte.d.ts +1 -0
  101. package/dist/components/layer/layer-inner.svelte.d.ts +1 -0
  102. package/dist/components/layer/layer-root.svelte.d.ts +1 -0
  103. package/dist/components/list/list-group.svelte +1 -1
  104. package/dist/components/list/list-item.svelte +1 -1
  105. package/dist/components/list/list-root.svelte +6 -1
  106. package/dist/components/list/list-title.svelte +1 -1
  107. package/dist/components/menu/menu-list.svelte +1 -1
  108. package/dist/components/popover/bond.svelte.d.ts +2 -0
  109. package/dist/components/popover/bond.svelte.js +1 -1
  110. package/dist/components/popover/popover-arrow.svelte +111 -117
  111. package/dist/components/popover/popover-arrow.svelte.d.ts +2 -2
  112. package/dist/components/popover/popover-content.svelte +139 -147
  113. package/dist/components/popover/popover-content.svelte.d.ts +3 -17
  114. package/dist/components/popover/popover-indicator.svelte +1 -1
  115. package/dist/components/popover/popover-root.svelte +49 -63
  116. package/dist/components/popover/popover-root.svelte.d.ts +1 -15
  117. package/dist/components/popover/popover-trigger.svelte +47 -56
  118. package/dist/components/popover/popover-trigger.svelte.d.ts +2 -8
  119. package/dist/components/popover/types.d.ts +39 -0
  120. package/dist/components/popover/types.js +1 -0
  121. package/dist/components/portal/active-portal.svelte +22 -16
  122. package/dist/components/portal/active-portal.svelte.d.ts +2 -2
  123. package/dist/components/portal/portal-inner.svelte +1 -1
  124. package/dist/components/portal/portal-inner.svelte.d.ts +1 -0
  125. package/dist/components/portal/portal-root.svelte +1 -1
  126. package/dist/components/portal/portal-root.svelte.d.ts +1 -0
  127. package/dist/components/portal/teleport.svelte +55 -49
  128. package/dist/components/portal/teleport.svelte.d.ts +4 -2
  129. package/dist/components/radio/radio-group.stories.svelte +4 -4
  130. package/dist/components/radio/radio.svelte +3 -3
  131. package/dist/components/radio/radio.svelte.d.ts +2 -2
  132. package/dist/components/root/root.css +24 -66
  133. package/dist/components/root/root.svelte +1 -1
  134. package/dist/components/sidebar/sidebar-content.svelte +2 -16
  135. package/dist/components/sidebar/sidebar-content.svelte.d.ts +2 -9
  136. package/dist/components/sidebar/sidebar-root.svelte +4 -23
  137. package/dist/components/sidebar/sidebar-root.svelte.d.ts +2 -13
  138. package/dist/components/sidebar/types.d.ts +19 -0
  139. package/dist/components/sidebar/types.js +1 -0
  140. package/dist/components/stack/stack-item.svelte +5 -1
  141. package/dist/components/stack/stack-root.svelte +5 -1
  142. package/dist/components/stack/stack-root.svelte.d.ts +1 -0
  143. package/dist/components/tabs/tab/tab-body.svelte +1 -1
  144. package/dist/components/tabs/tab/tab-description.svelte +1 -1
  145. package/dist/components/tabs/tab/tab-header.svelte +2 -2
  146. package/dist/components/tabs/tab/tab-root.svelte +6 -1
  147. package/dist/components/tabs/tabs-body.svelte +1 -1
  148. package/dist/components/tabs/tabs-header.svelte +1 -1
  149. package/dist/components/tabs/tabs-root.svelte +1 -1
  150. package/dist/components/textarea/textarea-input.svelte +2 -1
  151. package/dist/components/toast/toast-description.svelte +1 -1
  152. package/dist/components/toast/toast-description.svelte.d.ts +1 -0
  153. package/dist/components/toast/toast-root.svelte +1 -1
  154. package/dist/components/toast/toast-root.svelte.d.ts +1 -0
  155. package/dist/components/toast/toast-title.svelte +1 -1
  156. package/dist/components/toast/toast-title.svelte.d.ts +1 -0
  157. package/dist/components/tree/tree-body.svelte +1 -1
  158. package/dist/components/tree/tree-header.svelte +1 -1
  159. package/dist/components/tree/tree-header.svelte.d.ts +1 -0
  160. package/dist/components/tree/tree-indicator.svelte +1 -1
  161. package/dist/components/tree/tree-root.svelte +1 -1
  162. package/dist/context/preset.svelte.d.ts +4 -1
  163. package/dist/utils/index.d.ts +1 -0
  164. package/dist/utils/index.js +1 -0
  165. package/dist/utils/variant.d.ts +213 -0
  166. package/dist/utils/variant.js +137 -0
  167. package/llm/composition.md +395 -0
  168. package/llm/crafting.md +838 -0
  169. package/llm/motion.md +970 -0
  170. package/llm/philosophy.md +23 -0
  171. package/llm/preset-variant-integration.md +516 -0
  172. package/llm/preset.md +383 -0
  173. package/llm/styling.md +216 -0
  174. package/llm/usage.md +46 -0
  175. package/llm/variants.md +712 -0
  176. package/package.json +2 -1
  177. package/dist/components/input/input-value.svelte.d.ts +0 -19
@@ -71,7 +71,7 @@
71
71
 
72
72
  <HtmlAtom
73
73
  preset="accordion"
74
- class={['bg-card flex list-none flex-col', '$preset', klass]}
74
+ class={['bg-card border-border flex list-none flex-col', '$preset', klass]}
75
75
  {bond}
76
76
  {...rootProps}
77
77
  >
@@ -19,7 +19,7 @@ declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B exten
19
19
  exports: {
20
20
  getBond: () => AccordionBond;
21
21
  };
22
- bindings: "values" | "data" | "value";
22
+ bindings: "values" | "value" | "data";
23
23
  slots: {};
24
24
  events: {};
25
25
  };
@@ -27,7 +27,7 @@ declare class __sveltets_Render<E extends keyof HTMLElementTagNameMap = 'div', B
27
27
  props(): ReturnType<typeof $$render<E, B>>['props'];
28
28
  events(): ReturnType<typeof $$render<E, B>>['events'];
29
29
  slots(): ReturnType<typeof $$render<E, B>>['slots'];
30
- bindings(): "values" | "data" | "value";
30
+ bindings(): "values" | "value" | "data";
31
31
  exports(): {
32
32
  getBond: () => AccordionBond;
33
33
  };
@@ -37,7 +37,7 @@
37
37
  {#if isOpen}
38
38
  <HtmlAtom
39
39
  preset="accordion.item.body"
40
- class={['box-content', '$preset', klass]}
40
+ class={['border-border box-content', '$preset', klass]}
41
41
  {bond}
42
42
  onmount={onmount?.bind(bond.state)}
43
43
  ondestroy={ondestroy?.bind(bond.state)}
@@ -40,7 +40,11 @@
40
40
  {as}
41
41
  {bond}
42
42
  preset="accordion.item.header"
43
- class={['relative box-border flex w-full cursor-pointer items-center', '$preset', klass]}
43
+ class={[
44
+ 'border-border relative box-border flex w-full cursor-pointer items-center',
45
+ '$preset',
46
+ klass
47
+ ]}
44
48
  onmount={onmount?.bind(bond.state)}
45
49
  ondestroy={ondestroy?.bind(bond.state)}
46
50
  animate={animate?.bind(bond.state)}
@@ -42,7 +42,7 @@
42
42
 
43
43
  <HtmlAtom
44
44
  preset="accordion.item.indicator"
45
- class={['pointer-events-none flex items-center justify-center', '$preset', klass]}
45
+ class={['border-border pointer-events-none flex items-center justify-center', '$preset', klass]}
46
46
  onmount={onmount?.bind(bond.state)}
47
47
  ondestroy={ondestroy?.bind(bond.state)}
48
48
  animate={animate?.bind(bond.state)}
@@ -66,7 +66,7 @@
66
66
  <HtmlAtom
67
67
  {bond}
68
68
  preset="accordion.item"
69
- class={['$preset', klass]}
69
+ class={['border-border', '$preset', klass]}
70
70
  onmount={onmount?.bind(bond.state)}
71
71
  ondestroy={ondestroy?.bind(bond.state)}
72
72
  animate={animate?.bind(bond.state)}
@@ -39,7 +39,7 @@
39
39
  <HtmlAtom
40
40
  {bond}
41
41
  preset="alert.actions"
42
- class={['alert-actions mt-3 flex items-center gap-2', '$preset', klass]}
42
+ class={['alert-actions border-border mt-3 flex items-center gap-2', '$preset', klass]}
43
43
  onmount={onmount?.bind(bond.state)}
44
44
  ondestroy={ondestroy?.bind(bond.state)}
45
45
  animate={animate?.bind(bond.state)}
@@ -24,6 +24,7 @@ declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B exten
24
24
  bond?: import("../..").Bond;
25
25
  base?: B | undefined;
26
26
  preset?: import("../..").ModuleName | (string & {});
27
+ variants?: import("../..").VariantDefinition<any> | ((bond: import("../..").Bond, variantProps: Record<string, any>) => Record<string, any>);
27
28
  } & {
28
29
  children?: Snippet<[{
29
30
  alert: AlertBond;
@@ -45,7 +45,7 @@
45
45
  {bond}
46
46
  preset="alert.close-button"
47
47
  class={[
48
- 'alert-close-button absolute top-2 right-2 rounded p-1 transition-colors hover:bg-black/10 dark:hover:bg-white/10',
48
+ 'alert-close-button border-border absolute top-2 right-2 rounded p-1 transition-colors hover:bg-black/10 dark:hover:bg-white/10',
49
49
  'focus:ring-2 focus:ring-offset-1 focus:outline-none',
50
50
  {
51
51
  'focus:ring-blue-500': bond?.state.variant === 'info',
@@ -24,6 +24,7 @@ declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B exten
24
24
  bond?: import("../..").Bond;
25
25
  base?: B | undefined;
26
26
  preset?: import("../..").ModuleName | (string & {});
27
+ variants?: import("../..").VariantDefinition<any> | ((bond: import("../..").Bond, variantProps: Record<string, any>) => Record<string, any>);
27
28
  } & {
28
29
  children?: Snippet<[{
29
30
  alert: AlertBond;
@@ -39,7 +39,7 @@
39
39
  <HtmlAtom
40
40
  {bond}
41
41
  preset="alert.content"
42
- class={['alert-content flex-1 space-y-1', '$preset', klass]}
42
+ class={['alert-content border-border flex-1 space-y-1', '$preset', klass]}
43
43
  onmount={onmount?.bind(bond.state)}
44
44
  ondestroy={ondestroy?.bind(bond.state)}
45
45
  animate={animate?.bind(bond.state)}
@@ -24,6 +24,7 @@ declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B exten
24
24
  bond?: import("../..").Bond;
25
25
  base?: B | undefined;
26
26
  preset?: import("../..").ModuleName | (string & {});
27
+ variants?: import("../..").VariantDefinition<any> | ((bond: import("../..").Bond, variantProps: Record<string, any>) => Record<string, any>);
27
28
  } & {
28
29
  children?: Snippet<[{
29
30
  alert: AlertBond;
@@ -37,7 +37,7 @@
37
37
  <HtmlAtom
38
38
  {bond}
39
39
  preset="alert.description"
40
- class={['alert-description mt-1 text-sm leading-relaxed', '$preset', klass]}
40
+ class={['alert-description border-border mt-1 text-sm leading-relaxed', '$preset', klass]}
41
41
  onmount={onmount?.bind(bond.state)}
42
42
  ondestroy={ondestroy?.bind(bond.state)}
43
43
  animate={animate?.bind(bond.state)}
@@ -40,7 +40,7 @@
40
40
  {base}
41
41
  preset="alert.icon"
42
42
  class={[
43
- 'alert-icon inline-flex aspect-square h-5 items-center justify-center rounded-full text-sm font-medium',
43
+ 'alert-icon border-border inline-flex aspect-square h-5 items-center justify-center rounded-full text-sm font-medium',
44
44
  '$preset',
45
45
  klass
46
46
  ]}
@@ -94,7 +94,7 @@
94
94
  <HtmlAtom
95
95
  preset="alert"
96
96
  class={[
97
- 'alert relative flex gap-3 rounded-md border p-4 transition-all duration-200',
97
+ 'alert border-border relative flex gap-3 rounded-md border p-4 transition-all duration-200',
98
98
  // Base styles
99
99
  'bg-background text-foreground',
100
100
  // State styles
@@ -38,7 +38,7 @@
38
38
  {as}
39
39
  {bond}
40
40
  preset="alert.title"
41
- class={['alert-title text-sm leading-tight font-medium', '$preset', klass]}
41
+ class={['alert-title border-border text-sm leading-tight font-medium', '$preset', klass]}
42
42
  onmount={onmount?.bind(bond.state)}
43
43
  ondestroy={ondestroy?.bind(bond.state)}
44
44
  animate={animate?.bind(bond.state)}
@@ -3,9 +3,15 @@
3
3
  import type { Base, ComponentBase, HtmlAtomProps, SnippetBase } from './types';
4
4
  import { RootBond } from '../root';
5
5
  import { HtmlElement } from '../element';
6
- import { cn, toClassValue, type ClassValue } from '../../utils';
6
+ import {
7
+ cn,
8
+ toClassValue,
9
+ type ClassValue,
10
+ type VariantDefinition
11
+ } from '../../utils';
7
12
  import { getPreset } from '../../context';
8
13
  import type { PresetModuleName } from '../../context/preset.svelte';
14
+ import type { Bond } from '../../shared';
9
15
 
10
16
  type Element = HTMLElementTagNameMap[E];
11
17
 
@@ -17,6 +23,7 @@
17
23
  base = undefined,
18
24
  preset: presetKey = undefined,
19
25
  bond = undefined,
26
+ variants = undefined,
20
27
  children = undefined,
21
28
  ...restProps
22
29
  }: HtmlAtomProps<E, B> & HTMLAttributes<Element> = $props();
@@ -25,13 +32,87 @@
25
32
  presetKey ? getPreset(presetKey as PresetModuleName)?.apply?.(bond, [bond]) : undefined
26
33
  );
27
34
 
28
- const _klass = $derived(compilePresetPlaceholder(klass));
35
+ const presetProps = $derived(preset?.variants);
36
+
37
+ // Resolve local variants - either VariantDefinition or function
38
+ const localVariants = $derived.by(() => {
39
+ if (!variants) return undefined;
40
+
41
+ // If it's a function, call it directly
42
+ if (typeof variants === 'function') {
43
+ return variants(bond as Bond, restProps);
44
+ }
45
+
46
+ // Otherwise it's a VariantDefinition, resolve it
47
+ return resolveVariants(variants, bond as Bond, restProps);
48
+ });
49
+
50
+ // Merge preset variants with local variants
51
+ const mergedVariants = $derived.by(() => {
52
+ // No variants at all
53
+ if (!presetProps && !localVariants) return undefined;
54
+
55
+ // Only preset variants (raw object from preset)
56
+ if (presetProps && !localVariants) {
57
+ // Convert preset variants to VariantDefinition-like structure
58
+ const variantDef = {
59
+ class: preset?.class,
60
+ variants: presetProps,
61
+ compounds: preset?.compounds ?? [],
62
+ defaults: preset?.defaults ?? {}
63
+ };
64
+ return resolveVariants(variantDef, bond as Bond, restProps);
65
+ }
66
+
67
+ // Only local variants
68
+ if (!presetProps && localVariants) {
69
+ return localVariants;
70
+ }
71
+
72
+ // Both exist - merge them
73
+ // When both preset and local variants exist, we need to merge the resolved props
74
+ const presetVariantDef = {
75
+ class: preset?.class,
76
+ variants: presetProps,
77
+ compounds: preset?.compounds ?? [],
78
+ defaults: preset?.defaults ?? {}
79
+ };
80
+
81
+ const presetResolved = resolveVariants(presetVariantDef, bond as Bond, restProps);
82
+
83
+ // Merge the resolved variant props
84
+ // Local variant classes and attributes override preset
85
+ const presetClasses = Array.isArray(presetResolved.class)
86
+ ? presetResolved.class
87
+ : [presetResolved.class];
88
+ const localClasses = Array.isArray(localVariants?.class)
89
+ ? localVariants.class
90
+ : [localVariants?.class];
91
+
92
+ return {
93
+ class: [...presetClasses, ...localClasses].filter(Boolean),
94
+ ...presetResolved,
95
+ ...localVariants
96
+ };
97
+ });
98
+
99
+ const _klass = $derived(
100
+ cn(klass, mergedVariants?.class ?? '').replaceAll('$preset', cn(preset?.class))
101
+ );
29
102
 
30
103
  const _base = $derived(base ?? preset?.base);
31
104
  const _as = $derived(as ?? preset?.as);
32
105
  const _restProps = $derived.by(() => {
33
- const { class: klass, base, as, ...restPresetProps } = preset ?? {};
34
- return { ...restPresetProps, ...restProps };
106
+ const {
107
+ class: klassPreset,
108
+ base,
109
+ as,
110
+ variants: presetProps,
111
+ ...restPresetProps
112
+ } = preset ?? {};
113
+ const { class: variantClass, ...variantsRestProps } = mergedVariants ?? {};
114
+
115
+ return { ...restPresetProps, ...variantsRestProps, ...restProps };
35
116
  });
36
117
 
37
118
  const isSnippet = $derived(typeof _base === 'function' && _base.length === 1 && !_base.prototype);
@@ -42,22 +123,72 @@
42
123
 
43
124
  const Component = $derived(base ?? atom) as ComponentBase;
44
125
 
45
- function compilePresetPlaceholder(klass: ClassValue): ReturnType<typeof toClassValue> {
46
- if (Array.isArray(klass)) {
47
- return klass.map((k) => compilePresetPlaceholder(k));
48
- }
49
-
50
- const compiled = toClassValue.apply(bond, [klass, bond]);
51
-
52
- if (Array.isArray(compiled)) {
53
- return compiled.map((c) => compilePresetPlaceholder(c));
126
+ /**
127
+ * Resolve variant definition to props
128
+ */
129
+ function resolveVariants(
130
+ def: VariantDefinition<any>,
131
+ bond: Bond | null | undefined,
132
+ props: Record<string, any>
133
+ ): Record<string, any> {
134
+ const { variants: variantMap, compounds, defaults, class: baseClass } = def;
135
+
136
+ // Merge props with defaults
137
+ const finalProps = { ...defaults, ...props };
138
+
139
+ const classes: ClassValue[] = [];
140
+ const attributes: Record<string, any> = {};
141
+
142
+ // Add base class
143
+ if (baseClass) classes.push(baseClass);
144
+
145
+ // Add variant classes
146
+ if (variantMap) {
147
+ for (const [key, value] of Object.entries(finalProps)) {
148
+ const variantValue = variantMap[key]?.[value as string];
149
+ if (variantValue !== undefined) {
150
+ const resolved = typeof variantValue === 'function' ? variantValue(bond) : variantValue;
151
+
152
+ if (typeof resolved === 'string') {
153
+ classes.push(resolved);
154
+ } else if (typeof resolved === 'object' && resolved !== null) {
155
+ if ('class' in resolved) {
156
+ classes.push(resolved.class);
157
+ }
158
+ // Add other attributes
159
+ Object.entries(resolved).forEach(([k, v]) => {
160
+ if (k !== 'class') {
161
+ attributes[k] = v;
162
+ }
163
+ });
164
+ }
165
+ }
166
+ }
54
167
  }
55
168
 
56
- if (typeof compiled === 'string') {
57
- return compiled.replace('$preset', cn(preset?.class));
169
+ // Add compound variants
170
+ if (compounds) {
171
+ for (const compound of compounds) {
172
+ const { class: compoundClass, ...compoundProps } = compound;
173
+ const matches = Object.entries(compoundProps).every(
174
+ ([key, value]) => finalProps[key] === value
175
+ );
176
+ if (matches) {
177
+ if (compoundClass) classes.push(compoundClass);
178
+ // Add compound attributes
179
+ Object.entries(compound).forEach(([k, v]) => {
180
+ if (k !== 'class' && !Object.keys(compoundProps).includes(k)) {
181
+ attributes[k] = v;
182
+ }
183
+ });
184
+ }
185
+ }
58
186
  }
59
187
 
60
- return compiled;
188
+ return {
189
+ class: classes,
190
+ ...attributes
191
+ };
61
192
  }
62
193
  </script>
63
194
 
@@ -1,7 +1,8 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
2
  import type { Base } from './types';
3
- import { type ClassValue } from '../../utils';
3
+ import { type ClassValue, type VariantDefinition } from '../../utils';
4
4
  import type { PresetModuleName } from '../../context/preset.svelte';
5
+ import type { Bond } from '../../shared';
5
6
  declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base>(): {
6
7
  props: Record<string, unknown> & {
7
8
  [key: string]: unknown;
@@ -16,9 +17,10 @@ declare function $$render<E extends keyof HTMLElementTagNameMap = 'div', B exten
16
17
  ondestroy?: import("..").NodeFunction<E> | undefined;
17
18
  children?: import("svelte").Snippet;
18
19
  } & {
19
- bond?: import("../..").Bond;
20
+ bond?: Bond;
20
21
  base?: B | undefined;
21
22
  preset?: PresetModuleName | (string & {});
23
+ variants?: VariantDefinition<any> | ((bond: Bond, variantProps: Record<string, any>) => Record<string, any>);
22
24
  } & HTMLAttributes<HTMLElementTagNameMap[E]>;
23
25
  exports: {};
24
26
  bindings: "";
@@ -3,6 +3,7 @@ import { type HtmlElementTagName } from '../element';
3
3
  import type { HtmlElementProps, ElementType } from '../element/types';
4
4
  import type { PresetModuleName } from '../../context/preset.svelte';
5
5
  import type { Bond } from '../../shared';
6
+ import type { VariantDefinition } from '../../utils';
6
7
  export type ComponentBase = Component;
7
8
  export type SnippetBase = Snippet;
8
9
  export type Base<Args = any> = Args extends Record<string, any> ? ComponentBase : Args extends unknown[] ? SnippetBase : never;
@@ -10,5 +11,11 @@ export type HtmlAtomProps<E extends HtmlElementTagName = HtmlElementTagName, B e
10
11
  bond?: Bond;
11
12
  base?: B;
12
13
  preset?: PresetModuleName | (string & {});
14
+ /**
15
+ * Variant definition or function to resolve variants
16
+ * - VariantDefinition: Static variant config with base, variants, compoundVariants, defaultVariants
17
+ * - Function: Dynamic function that receives bond and props, returns props (legacy)
18
+ */
19
+ variants?: VariantDefinition<any> | ((bond: Bond, variantProps: Record<string, any>) => Record<string, any>);
13
20
  };
14
21
  export type { ElementType };
@@ -8,7 +8,7 @@
8
8
  <HtmlAtom
9
9
  preset="badge"
10
10
  class={[
11
- 'bg-foreground/10 text-foreground inline-flex h-auto items-center rounded-full px-2.5 py-0.5 text-xs font-medium',
11
+ 'bg-foreground/10 border-border text-foreground inline-flex h-auto items-center rounded-full px-2.5 py-0.5 text-xs font-medium',
12
12
  '$preset',
13
13
  klass
14
14
  ]}
@@ -9,7 +9,7 @@
9
9
  {href}
10
10
  preset="breadcrumb.item"
11
11
  class={[
12
- 'hover:text-primary hover:bg-primary/5 flex gap-2 rounded-lg px-2 py-1',
12
+ 'hover:text-primary hover:bg-primary/5 border-border flex gap-2 rounded-lg px-2 py-1',
13
13
  '$preset',
14
14
  klass
15
15
  ]}
@@ -7,7 +7,7 @@
7
7
  <HtmlAtom
8
8
  {as}
9
9
  preset="breadcrumb"
10
- class={['flex flex-nowrap items-center gap-1', '$preset', klass]}
10
+ class={['border-border flex flex-nowrap items-center gap-1', '$preset', klass]}
11
11
  data-kind="breadcrumb-root"
12
12
  {...restProps}
13
13
  >
@@ -7,7 +7,7 @@
7
7
  <HtmlAtom
8
8
  {as}
9
9
  preset="breadcrumb.separator"
10
- class={['text-stroke-0/50 px-0', '$preset', klass]}
10
+ class={['text-stroke-0/50 border-border px-0', '$preset', klass]}
11
11
  data-kind="breadcrumb-separator"
12
12
  {...restProps}
13
13
  >
@@ -2,16 +2,56 @@
2
2
  import { defineMeta } from '@storybook/addon-svelte-csf';
3
3
  import Root from '../root/root.svelte';
4
4
  import ButtonCmp from './button.svelte';
5
+ import { defineVariants } from '../../utils/variant';
5
6
 
6
7
  const { Story } = defineMeta({
7
8
  title: 'ATOMS/Button'
8
9
  });
9
10
  </script>
10
11
 
12
+ <script lang="ts">
13
+ const variants = defineVariants((bond) => ({
14
+ variants: {
15
+ variant: {
16
+ primary: {
17
+ class: 'bg-primary text-primary-foreground hover:bg-primary/80 active:bg-primary/90'
18
+ },
19
+ secondary: {
20
+ class:
21
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/90'
22
+ },
23
+ destructive: {
24
+ class:
25
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/80 active:bg-destructive/90'
26
+ },
27
+ outline: {
28
+ class:
29
+ 'bg-transparent hover:bg-foreground/5 active:bg-foreground/10 border border-border text-foreground'
30
+ },
31
+ ghost: {
32
+ class: 'hover:bg-accent hover:text-accent-foreground'
33
+ }
34
+ }
35
+ },
36
+ compounds: [],
37
+ defaults: {
38
+ variant: 'destructive'
39
+ }
40
+ }));
41
+ </script>
42
+
11
43
  <Story name="Button">
12
44
  <Root class="p-4">
13
45
  {#snippet children({ args })}
14
- <ButtonCmp>Clicke me</ButtonCmp>
46
+ <ButtonCmp variant="primary">Clicke me</ButtonCmp>
47
+ {/snippet}
48
+ </Root>
49
+ </Story>
50
+
51
+ <Story name="Button - Local Variants">
52
+ <Root class="p-4">
53
+ {#snippet children({ args })}
54
+ <ButtonCmp {variants} {...args}>Clicke me</ButtonCmp>
15
55
  {/snippet}
16
56
  </Root>
17
57
  </Story>
@@ -1,18 +1,5 @@
1
- export default Button;
2
- type Button = SvelteComponent<{
3
- [x: string]: never;
4
- }, {
5
- [evt: string]: CustomEvent<any>;
6
- }, {}> & {
7
- $$bindings?: string | undefined;
8
- };
9
- declare const Button: $$__sveltets_2_IsomorphicComponent<{
10
- [x: string]: never;
11
- }, {
12
- [evt: string]: CustomEvent<any>;
13
- }, {}, {}, string>;
14
1
  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> {
15
- new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
16
3
  $$bindings?: Bindings;
17
4
  } & Exports;
18
5
  (internal: unknown, props: {
@@ -24,3 +11,8 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
24
11
  };
25
12
  z_$$bindings?: Bindings;
26
13
  }
14
+ declare const Button: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Button = InstanceType<typeof Button>;
18
+ export default Button;
@@ -21,7 +21,7 @@
21
21
  {preset}
22
22
  as="button"
23
23
  class={[
24
- 'button text-primary-foreground bg-primary hover:bg-primary/95 active:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground w-fit cursor-pointer rounded-md px-3 py-2 transition-colors duration-200',
24
+ 'button text-primary-foreground bg-primary border-border hover:bg-primary/95 active:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground w-fit cursor-pointer rounded-md px-3 py-2 transition-colors duration-200',
25
25
  '$preset',
26
26
  klass
27
27
  ]}
@@ -1,3 +1,6 @@
1
- declare const Button: import("svelte").Component<any, {}, "">;
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { ButtonProps } from './types';
3
+ type $$ComponentProps = ButtonProps & HTMLAttributes<HTMLButtonElement>;
4
+ declare const Button: import("svelte").Component<$$ComponentProps, {}, "">;
2
5
  type Button = ReturnType<typeof Button>;
3
6
  export default Button;
@@ -1,4 +1,4 @@
1
- import type { HtmlAtomProps } from '../../helpers';
1
+ import type { HtmlAtomProps } from '../atom/types';
2
2
  import type { Snippet } from 'svelte';
3
3
  export type ButtonProps = HtmlAtomProps<'button'> & {
4
4
  type?: 'button' | 'submit' | 'reset';
@@ -32,7 +32,7 @@
32
32
  <HtmlAtom
33
33
  {bond}
34
34
  preset="card.content"
35
- class={['card-content px-4', '$preset', klass]}
35
+ class={['card-content border-border px-4', '$preset', klass]}
36
36
  enter={enter?.bind(bond.state)}
37
37
  exit={exit?.bind(bond.state)}
38
38
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,7 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.description"
38
- class={['card-description text-sm text-gray-500', '$preset', klass]}
38
+ class={['card-description border-border text-sm text-gray-500', '$preset', klass]}
39
39
  enter={enter?.bind(bond.state)}
40
40
  exit={exit?.bind(bond.state)}
41
41
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,7 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.footer"
38
- class={['card-footer flex items-center gap-2 px-4 py-4', '$preset', klass]}
38
+ class={['card-footer border-border flex items-center gap-2 px-4 py-4', '$preset', klass]}
39
39
  enter={enter?.bind(bond.state)}
40
40
  exit={exit?.bind(bond.state)}
41
41
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,7 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.header"
38
- class={['card-header flex flex-col space-y-1.5 px-4 py-4', '$preset', klass]}
38
+ class={['card-header border-border flex flex-col space-y-1.5 px-4 py-4', '$preset', klass]}
39
39
  enter={enter?.bind(bond.state)}
40
40
  exit={exit?.bind(bond.state)}
41
41
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,7 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.media"
38
- class={['card-media overflow-hidden', '$preset', klass]}
38
+ class={['card-media border-border overflow-hidden', '$preset', klass]}
39
39
  enter={enter?.bind(bond.state)}
40
40
  exit={exit?.bind(bond.state)}
41
41
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,7 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.subtitle"
38
- class={['card-subtitle text-sm font-medium text-gray-600', '$preset', klass]}
38
+ class={['card-subtitle border-border text-sm font-medium text-gray-600', '$preset', klass]}
39
39
  enter={enter?.bind(bond.state)}
40
40
  exit={exit?.bind(bond.state)}
41
41
  initial={initial?.bind(bond.state)}
@@ -35,7 +35,11 @@
35
35
  {as}
36
36
  {bond}
37
37
  preset="card.title"
38
- class={['card-title text-lg leading-none font-semibold tracking-tight', '$preset', klass]}
38
+ class={[
39
+ 'card-title border-border text-lg leading-none font-semibold tracking-tight',
40
+ '$preset',
41
+ klass
42
+ ]}
39
43
  enter={enter?.bind(bond.state)}
40
44
  exit={exit?.bind(bond.state)}
41
45
  initial={initial?.bind(bond.state)}