@svelte-atoms/core 1.0.0-alpha.31 → 1.0.0-alpha.32

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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -853
  3. package/dist/attachments/index.d.ts +1 -0
  4. package/dist/attachments/index.js +1 -0
  5. package/dist/components/accordion/accordion-root.svelte +65 -65
  6. package/dist/components/accordion/accordion.stories.svelte +70 -70
  7. package/dist/components/accordion/item/accordion-item-body.svelte +44 -44
  8. package/dist/components/accordion/item/accordion-item-header.svelte +51 -51
  9. package/dist/components/accordion/item/accordion-item-indicator.svelte +51 -51
  10. package/dist/components/accordion/item/accordion-item-root.svelte +66 -66
  11. package/dist/components/alert/alert-close-button.svelte +66 -66
  12. package/dist/components/alert/alert-description.svelte +42 -42
  13. package/dist/components/alert/alert-root.svelte +68 -68
  14. package/dist/components/atom/html-atom.svelte +26 -194
  15. package/dist/components/atom/types.d.ts +3 -2
  16. package/dist/components/atom/utils.d.ts +37 -0
  17. package/dist/components/atom/utils.js +208 -0
  18. package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
  19. package/dist/components/breadcrumb/breadcrumb-separator.svelte +5 -1
  20. package/dist/components/breadcrumb/breadcrumb.stories.svelte +16 -16
  21. package/dist/components/calendar/calendar-day.svelte +101 -101
  22. package/dist/components/checkbox/checkbox.svelte +159 -159
  23. package/dist/components/collapsible/bond.svelte.js +2 -1
  24. package/dist/components/collapsible/collapsible-body.svelte +3 -2
  25. package/dist/components/collapsible/motion.svelte.d.ts +6 -0
  26. package/dist/components/collapsible/motion.svelte.js +15 -0
  27. package/dist/components/combobox/atoms.d.ts +3 -3
  28. package/dist/components/combobox/atoms.js +3 -3
  29. package/dist/components/combobox/bond.svelte.d.ts +6 -6
  30. package/dist/components/combobox/bond.svelte.js +3 -26
  31. package/dist/components/combobox/combobox-control.svelte +52 -52
  32. package/dist/components/combobox/{compobox-item.svelte → combobox-item.svelte} +62 -68
  33. package/dist/components/combobox/combobox-item.svelte.d.ts +12 -0
  34. package/dist/components/combobox/combobox.stories.svelte +50 -0
  35. package/dist/components/combobox/combobox.stories.svelte.d.ts +3 -0
  36. package/dist/components/datagrid/tr/datagrid-tr.svelte +90 -90
  37. package/dist/components/date-picker/bond.svelte.d.ts +15 -5
  38. package/dist/components/date-picker/bond.svelte.js +5 -11
  39. package/dist/components/date-picker/date-picker-calendar.svelte +67 -67
  40. package/dist/components/dialog/bond.svelte.js +5 -20
  41. package/dist/components/dialog/dialog-content.svelte +44 -44
  42. package/dist/components/dialog/dialog-root.svelte +91 -91
  43. package/dist/components/drawer/bond.svelte.d.ts +18 -16
  44. package/dist/components/drawer/bond.svelte.js +8 -18
  45. package/dist/components/drawer/drawer-content.svelte +49 -49
  46. package/dist/components/drawer/drawer-root.svelte +5 -4
  47. package/dist/components/drawer/drawer.stories.svelte +141 -144
  48. package/dist/components/drawer/motion.js +1 -1
  49. package/dist/components/dropdown/atoms.d.ts +1 -1
  50. package/dist/components/dropdown/atoms.js +1 -1
  51. package/dist/components/dropdown/bond.svelte.d.ts +21 -22
  52. package/dist/components/dropdown/bond.svelte.js +29 -53
  53. package/dist/components/dropdown/dropdown-root.svelte +65 -59
  54. package/dist/components/dropdown/dropdown-values.svelte +17 -17
  55. package/dist/components/dropdown/dropdown-values.svelte.d.ts +1 -2
  56. package/dist/components/dropdown/dropdown.stories.svelte +83 -80
  57. package/dist/components/dropdown/index.d.ts +1 -0
  58. package/dist/components/dropdown/index.js +1 -0
  59. package/dist/components/dropdown/item/attachments.svelte.d.ts +2 -2
  60. package/dist/components/dropdown/item/attachments.svelte.js +2 -2
  61. package/dist/components/dropdown/item/controller.svelte.d.ts +34 -0
  62. package/dist/components/dropdown/item/controller.svelte.js +82 -0
  63. package/dist/components/dropdown/item/dropdown-item.svelte +109 -102
  64. package/dist/components/dropdown/item/dropdown-item.svelte.d.ts +13 -28
  65. package/dist/components/dropdown/item/index.d.ts +3 -0
  66. package/dist/components/dropdown/item/index.js +3 -0
  67. package/dist/components/dropdown/item/types.d.ts +29 -0
  68. package/dist/components/dropdown/item/types.js +1 -0
  69. package/dist/components/list/list-item.svelte +20 -20
  70. package/dist/components/menu/atoms.d.ts +8 -3
  71. package/dist/components/menu/atoms.js +8 -3
  72. package/dist/components/menu/bond.svelte.d.ts +54 -0
  73. package/dist/components/menu/bond.svelte.js +132 -0
  74. package/dist/components/menu/index.d.ts +1 -0
  75. package/dist/components/menu/index.js +1 -0
  76. package/dist/components/menu/item/controller.svelte.d.ts +26 -0
  77. package/dist/components/menu/item/controller.svelte.js +69 -0
  78. package/dist/components/menu/item/index.d.ts +2 -0
  79. package/dist/components/menu/item/index.js +2 -0
  80. package/dist/components/menu/item/menu-item.svelte +103 -0
  81. package/dist/components/menu/item/menu-item.svelte.d.ts +31 -0
  82. package/dist/components/menu/item/types.d.ts +62 -0
  83. package/dist/components/menu/item/types.js +1 -0
  84. package/dist/components/menu/{menu-list.svelte → menu-content.svelte} +40 -40
  85. package/dist/components/menu/{menu-list.svelte.d.ts → menu-content.svelte.d.ts} +3 -3
  86. package/dist/components/menu/menu-root.svelte +15 -0
  87. package/dist/components/menu/menu-root.svelte.d.ts +8 -0
  88. package/dist/components/menu/menu.stories.svelte +33 -33
  89. package/dist/components/menu/types.d.ts +0 -7
  90. package/dist/components/popover/bond.svelte.d.ts +11 -14
  91. package/dist/components/popover/bond.svelte.js +27 -44
  92. package/dist/components/popover/popover-content.svelte +137 -137
  93. package/dist/components/popover/popover.stories.svelte +37 -49
  94. package/dist/components/portal/active-portal.svelte +29 -29
  95. package/dist/components/portal/portal-root.svelte +76 -76
  96. package/dist/components/portal/teleport.svelte +49 -49
  97. package/dist/components/radio/radio.svelte +109 -109
  98. package/dist/components/root/index.d.ts +1 -0
  99. package/dist/components/root/index.js +1 -0
  100. package/dist/components/root/l0-portal.svelte +8 -0
  101. package/dist/components/root/l0-portal.svelte.d.ts +26 -0
  102. package/dist/components/root/l1-portal.svelte +7 -0
  103. package/dist/components/root/l1-portal.svelte.d.ts +26 -0
  104. package/dist/components/root/root.css +119 -119
  105. package/dist/components/root/root.svelte +17 -18
  106. package/dist/components/root/root.svelte.d.ts +2 -6
  107. package/dist/components/root/toasts-portal.svelte +7 -0
  108. package/dist/components/root/toasts-portal.svelte.d.ts +26 -0
  109. package/dist/components/root/types.d.ts +17 -0
  110. package/dist/components/sidebar/motion.svelte.js +3 -3
  111. package/dist/components/sidebar/sidebar-content.svelte +40 -40
  112. package/dist/components/textarea/textarea-input.svelte +9 -9
  113. package/dist/components/textarea/textarea-root.svelte +9 -9
  114. package/dist/components/tooltip/tooltip-trigger.svelte +39 -39
  115. package/dist/components/tree/index.d.ts +1 -0
  116. package/dist/components/tree/index.js +1 -0
  117. package/dist/components/tree/motion.svelte.d.ts +6 -0
  118. package/dist/components/tree/motion.svelte.js +14 -0
  119. package/dist/components/tree/tree-body.svelte +4 -3
  120. package/dist/context/preset.svelte.d.ts +3 -1
  121. package/dist/icons/icon-copy.svelte +6 -6
  122. package/dist/utils/dom.svelte.d.ts +2 -0
  123. package/dist/utils/dom.svelte.js +21 -0
  124. package/dist/utils/function.d.ts +1 -1
  125. package/dist/utils/promise.svelte.d.ts +5 -0
  126. package/dist/utils/promise.svelte.js +20 -0
  127. package/package.json +4 -2
  128. package/dist/components/combobox/compobox-item.svelte.d.ts +0 -34
  129. package/dist/components/combobox/compobox.stories.svelte +0 -51
  130. package/dist/components/combobox/compobox.stories.svelte.d.ts +0 -3
  131. package/dist/components/dropdown/item/bond.svelte.d.ts +0 -42
  132. package/dist/components/dropdown/item/bond.svelte.js +0 -99
  133. package/dist/components/menu/menu-item.svelte +0 -69
  134. package/dist/components/menu/menu-item.svelte.d.ts +0 -37
  135. package/dist/utils/markdown-to-llm.d.ts +0 -28
  136. package/dist/utils/markdown-to-llm.js +0 -76
@@ -3,13 +3,19 @@
3
3
  import type { Base, HtmlAtomProps, SnippetBase } from './types';
4
4
  import { RootBond } from '../root';
5
5
  import { HtmlElement } from '../element';
6
- import { cn, type ClassValue, type VariantDefinition } from '../../utils';
7
6
  import { getPreset } from '../../context';
8
7
  import type { PresetModuleName } from '../../context/preset.svelte';
9
- import type { Bond } from '../../shared';
10
8
  import SnippetRenderer from './snippet-renderer.svelte';
11
9
  import type { Component } from 'svelte';
12
- import { call } from '../../utils/function';
10
+ import type { ClassValue } from '../../utils';
11
+ import {
12
+ resolvePreset,
13
+ resolveLocalVariants,
14
+ mergeVariants,
15
+ mergeClassesWithPreset,
16
+ extractRestProps,
17
+ isSnippetBase
18
+ } from './utils';
13
19
 
14
20
  type Element = HTMLElementTagNameMap[E];
15
21
 
@@ -26,128 +32,41 @@
26
32
  ...restProps
27
33
  }: HtmlAtomProps<E, B> & Omit<HTMLAttributes<Element>, 'children'> = $props();
28
34
 
29
- /**
30
- * Resolve variant definition to props
31
- */
32
- // Cache for resolved variants to avoid recomputation
33
- // Key: JSON stringified combination of variant props
34
- const variantCache = new Map<string, Record<string, any>>();
35
-
36
35
  // Memoize preset resolution - only recompute when presetKey or bond changes
37
36
  const preset = $derived.by(() => {
38
37
  if (!presetKey) return undefined;
39
38
  const result = getPreset(presetKey as PresetModuleName)?.apply?.(bond, [bond]);
40
- // Handle deferred preset result (factory function)
41
- return call(result);
39
+ return resolvePreset(result);
42
40
  });
43
41
 
44
- const presetProps = $derived(preset?.variants);
42
+ const presetVariantsProps = $derived(preset?.variants);
45
43
 
46
44
  // Resolve local variants - either VariantDefinition or function
47
- const localVariants = $derived.by(() => {
48
- if (!variants) return undefined;
49
-
50
- // If it's a function, call it directly
51
- if (typeof variants === 'function') {
52
- return variants(bond as Bond, restProps);
53
- }
54
-
55
- // Otherwise it's a VariantDefinition, resolve it
56
- return resolveVariants(variants, bond as Bond, restProps);
57
- });
45
+ const localVariants = $derived(resolveLocalVariants(variants, bond, restProps));
58
46
 
59
47
  // Merge preset variants with local variants
60
48
  // Memoized to avoid recomputation when inputs haven't changed
61
49
  const mergedVariants = $derived.by(() => {
62
- // No variants at all
63
- if (!presetProps && !localVariants) return undefined;
64
-
65
- // Only preset variants (raw object from preset)
66
- if (presetProps && !localVariants) {
67
- // Convert preset variants to VariantDefinition-like structure
68
- const variantDef: VariantDefinition<any> = {
69
- class: preset?.class ?? '',
70
- variants: presetProps,
71
- compounds: preset?.compounds ?? [],
72
- defaults: preset?.defaults ?? {}
73
- };
74
- return resolveVariants(variantDef, bond as Bond, restProps);
75
- }
76
-
77
- // Only local variants
78
- if (!presetProps && localVariants) {
79
- return localVariants;
80
- }
81
-
82
- // Both exist - merge them
83
- // When both preset and local variants exist, we need to merge the resolved props
84
- const presetVariantDef: VariantDefinition<any> = {
85
- class: preset?.class ?? '',
86
- variants: presetProps ?? {},
87
- compounds: preset?.compounds ?? [],
88
- defaults: preset?.defaults ?? {}
89
- };
90
-
91
- const presetResolved = resolveVariants(presetVariantDef, bond as Bond, restProps);
92
-
93
- // Merge the resolved variant props
94
- // Local variant classes and attributes override preset
95
- const presetClasses = Array.isArray(presetResolved.class)
96
- ? presetResolved.class
97
- : [presetResolved.class];
98
- const localClasses = Array.isArray(localVariants?.class)
99
- ? localVariants.class
100
- : [localVariants?.class];
101
-
102
- return {
103
- class: [...presetClasses, ...localClasses].filter(Boolean),
104
- ...presetResolved,
105
- ...localVariants
106
- };
107
- });
108
-
109
- const presetClassString = $derived(cn(preset?.class));
110
-
111
- const _klass = $derived.by(() => {
112
- const klassStr = cn(klass ?? '');
113
- // Check for $preset placeholder first
114
- if (!klassStr.includes('$preset')) {
115
- // No placeholder - normal merge: variants override direct class
116
- return cn(klass, mergedVariants?.class ?? '');
117
- }
118
-
119
- // Has placeholder - calculate position and inject preset classes
120
- const parts = klassStr.split('$preset');
121
-
122
- // Only keep the last $preset placeholder
123
- const beforeLastPlaceholder = parts.slice(0, -1).join('');
124
- const afterLastPlaceholder = parts[parts.length - 1];
125
-
126
- // Merge: before + preset + variants + after
127
- return cn(
128
- beforeLastPlaceholder,
129
- presetClassString,
130
- mergedVariants?.class ?? '',
131
- afterLastPlaceholder
50
+ return mergeVariants(
51
+ presetVariantsProps,
52
+ preset?.class,
53
+ preset?.compounds,
54
+ preset?.defaults,
55
+ localVariants,
56
+ bond,
57
+ restProps
132
58
  );
133
59
  });
134
60
 
61
+ const _klass = $derived(
62
+ mergeClassesWithPreset(klass, preset?.class, mergedVariants?.class as ClassValue)
63
+ );
64
+
135
65
  const _base = $derived(base ?? preset?.base);
136
66
  const _as = $derived(as ?? preset?.as);
137
- const _restProps = $derived.by(() => {
138
- const {
139
- class: klassPreset,
140
- base,
141
- as,
142
- variants: presetProps,
143
- ...restPresetProps
144
- } = preset ?? {};
145
- const { class: variantClass, ...variantsRestProps } = mergedVariants ?? {};
67
+ const _restProps = $derived(extractRestProps(preset, mergedVariants, restProps));
146
68
 
147
- return { ...restPresetProps, ...variantsRestProps, ...restProps };
148
- });
149
-
150
- const isSnippet = $derived(typeof _base === 'function' && _base.length === 1 && !_base.prototype);
69
+ const isSnippet = $derived(isSnippetBase(_base));
151
70
 
152
71
  const snippet = $derived(_base as SnippetBase);
153
72
 
@@ -165,93 +84,6 @@
165
84
  props: { class: _klass, as: _as, ..._restProps }
166
85
  };
167
86
  }) as { component: Component; props: Record<string, any> };
168
-
169
- function resolveVariants(
170
- def: VariantDefinition<any>,
171
- bond: Bond | null | undefined,
172
- props: Record<string, any>
173
- ): Record<string, any> {
174
- const { variants: variantMap, compounds, defaults, class: baseClass } = def;
175
-
176
- // Merge props with defaults
177
- const finalProps = { ...defaults, ...props };
178
-
179
- // Create cache key from final props (only variant-related props)
180
- const variantKeys = variantMap ? Object.keys(variantMap) : [];
181
- const relevantProps = Object.fromEntries(
182
- Object.entries(finalProps).filter(([key]) => variantKeys.includes(key))
183
- );
184
- const cacheKey = JSON.stringify({ relevantProps, baseClass, compounds });
185
-
186
- // Check cache
187
- if (variantCache.has(cacheKey)) {
188
- return variantCache.get(cacheKey)!;
189
- }
190
-
191
- const classes: ClassValue[] = [];
192
- const attributes: Record<string, any> = {};
193
-
194
- // Add base class
195
- if (baseClass) classes.push(baseClass);
196
-
197
- // Add variant classes
198
- if (variantMap) {
199
- for (const [key, value] of Object.entries(finalProps)) {
200
- const variantValue = variantMap[key]?.[value as string];
201
- if (variantValue !== undefined) {
202
- const resolved = typeof variantValue === 'function' ? variantValue(bond) : variantValue;
203
-
204
- if (typeof resolved === 'string') {
205
- classes.push(resolved);
206
- } else if (typeof resolved === 'object' && resolved !== null) {
207
- if ('class' in resolved) {
208
- classes.push(resolved.class);
209
- }
210
- // Add other attributes
211
- Object.entries(resolved).forEach(([k, v]) => {
212
- if (k !== 'class') {
213
- attributes[k] = v;
214
- }
215
- });
216
- }
217
- }
218
- }
219
- }
220
-
221
- // Add compound variants
222
- if (compounds) {
223
- for (const compound of compounds) {
224
- const { class: compoundClass, ...compoundProps } = compound;
225
- const matches = Object.entries(compoundProps).every(
226
- ([key, value]) => finalProps[key] === value
227
- );
228
- if (matches) {
229
- if (compoundClass) classes.push(compoundClass);
230
- // Add compound attributes
231
- Object.entries(compound).forEach(([k, v]) => {
232
- if (k !== 'class' && !Object.keys(compoundProps).includes(k)) {
233
- attributes[k] = v;
234
- }
235
- });
236
- }
237
- }
238
- }
239
-
240
- const result = {
241
- class: classes,
242
- ...attributes
243
- };
244
-
245
- // Store in cache (limit cache size to prevent memory leaks)
246
- if (variantCache.size > 100) {
247
- // Clear oldest entry (first in Map)
248
- const firstKey = variantCache.keys().next().value;
249
- if (firstKey) variantCache.delete(firstKey);
250
- }
251
- variantCache.set(cacheKey, result);
252
-
253
- return result;
254
- }
255
87
  </script>
256
88
 
257
89
  <renderer.component {...renderer.props}>
@@ -12,15 +12,16 @@ export type Base<Args = any> = Args extends Record<string, any> ? ComponentBase
12
12
  */
13
13
  export interface HtmlAtomExtendProps {
14
14
  }
15
+ type Variants = VariantDefinition<any> | ((bond: Bond, variantProps: Record<string, any>) => Record<string, any>);
15
16
  export interface HtmlAtomProps<E extends HtmlElementTagName = HtmlElementTagName, B extends Base<any> = Base> extends HtmlElementProps<E>, HtmlAtomExtendProps {
16
17
  bond?: Bond;
17
- base?: B;
18
+ base?: B | undefined;
18
19
  preset?: PresetModuleName | (string & {});
19
20
  /**
20
21
  * Variant definition or function to resolve variants
21
22
  * - VariantDefinition: Static variant config with base, variants, compoundVariants, defaultVariants
22
23
  * - Function: Dynamic function that receives bond and props, returns props (legacy)
23
24
  */
24
- variants?: VariantDefinition<any> | ((bond: Bond, variantProps: Record<string, any>) => Record<string, any>);
25
+ variants?: Variants;
25
26
  }
26
27
  export type { ElementType };
@@ -0,0 +1,37 @@
1
+ import type { Bond } from '../../shared';
2
+ import { type ClassValue, type VariantDefinition } from '../../utils';
3
+ type ResolvedProps = Record<string, unknown>;
4
+ type AnyVariantDefinition = VariantDefinition<any>;
5
+ /**
6
+ * Resolves preset to its final value, handling both direct values and factory functions
7
+ */
8
+ export declare function resolvePreset<T>(preset: T | (() => T) | undefined): T | undefined;
9
+ /**
10
+ * Pure function to resolve variant definition to props
11
+ * Caches results to avoid recomputation with same inputs
12
+ */
13
+ export declare function resolveVariants(def: AnyVariantDefinition, bond: Bond | null | undefined, props: Record<string, unknown>): ResolvedProps;
14
+ /**
15
+ * Pure function to merge preset and local variant definitions
16
+ * Returns merged variant props with local overriding preset
17
+ */
18
+ export declare function mergeVariants(presetVariants: Record<string, any> | undefined, presetClass: ClassValue | undefined, presetCompounds: Array<Record<string, any>> | undefined, presetDefaults: Record<string, any> | undefined, localVariants: ResolvedProps | undefined, bond: Bond | null | undefined, props: Record<string, unknown>): ResolvedProps | undefined;
19
+ /**
20
+ * Pure function to merge classes with $preset placeholder support
21
+ * Handles the special $preset placeholder for precise positioning of preset classes
22
+ */
23
+ export declare function mergeClassesWithPreset(userClass: string | ClassValue | undefined, presetClass: ClassValue | undefined, variantClass: ClassValue | undefined): string;
24
+ /**
25
+ * Pure function to resolve local variants
26
+ * Handles both function-based and VariantDefinition-based variants
27
+ */
28
+ export declare function resolveLocalVariants(variants: any, bond: Bond | null | undefined, props: Record<string, unknown>): ResolvedProps | undefined;
29
+ /**
30
+ * Pure function to extract rest props by filtering out preset and variant-specific props
31
+ */
32
+ export declare function extractRestProps(preset: Record<string, any> | undefined, mergedVariants: ResolvedProps | undefined, restProps: Record<string, unknown>): Record<string, unknown>;
33
+ /**
34
+ * Pure function to check if a base is a snippet
35
+ */
36
+ export declare function isSnippetBase(base: unknown): boolean;
37
+ export {};
@@ -0,0 +1,208 @@
1
+ import { cn } from '../../utils';
2
+ import { call } from '../../utils/function';
3
+ /**
4
+ * Cache for resolved variants to avoid recomputation
5
+ * Key: JSON stringified combination of variant props
6
+ */
7
+ const variantCache = new Map();
8
+ /**
9
+ * Maximum cache size to prevent memory leaks
10
+ */
11
+ const MAX_CACHE_SIZE = 100;
12
+ /**
13
+ * Resolves preset to its final value, handling both direct values and factory functions
14
+ */
15
+ export function resolvePreset(preset) {
16
+ if (!preset)
17
+ return undefined;
18
+ const result = call(preset);
19
+ // If call returns a function, call it again (handle deferred preset)
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ return typeof result === 'function' ? result() : result;
22
+ }
23
+ /**
24
+ * Pure function to resolve variant definition to props
25
+ * Caches results to avoid recomputation with same inputs
26
+ */
27
+ export function resolveVariants(def, bond, props) {
28
+ const { variants: variantMap, compounds, defaults, class: baseClass } = def;
29
+ // Merge props with defaults
30
+ const finalProps = { ...defaults, ...props };
31
+ // Create cache key from final props (only variant-related props)
32
+ const variantKeys = variantMap ? Object.keys(variantMap) : [];
33
+ const relevantProps = Object.fromEntries(Object.entries(finalProps).filter(([key]) => variantKeys.includes(key)));
34
+ const cacheKey = JSON.stringify({ relevantProps, baseClass, compounds });
35
+ // Check cache
36
+ if (variantCache.has(cacheKey)) {
37
+ return variantCache.get(cacheKey);
38
+ }
39
+ const classes = [];
40
+ const attributes = {};
41
+ // Add base class
42
+ if (baseClass)
43
+ classes.push(baseClass);
44
+ // Add variant classes
45
+ if (variantMap) {
46
+ for (const [key, value] of Object.entries(finalProps)) {
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ const variantValue = variantMap[key]?.[value];
49
+ if (variantValue !== undefined) {
50
+ const resolved = typeof variantValue === 'function' ? variantValue(bond) : variantValue;
51
+ if (typeof resolved === 'string') {
52
+ classes.push(resolved);
53
+ }
54
+ else if (typeof resolved === 'object' && resolved !== null) {
55
+ if ('class' in resolved) {
56
+ classes.push(resolved.class);
57
+ }
58
+ // Add other attributes (including Symbol-based attachment keys)
59
+ Object.getOwnPropertySymbols(resolved).forEach((sym) => {
60
+ attributes[sym] = resolved[sym];
61
+ });
62
+ }
63
+ }
64
+ }
65
+ }
66
+ // Add compound variants
67
+ if (compounds) {
68
+ for (const compound of compounds) {
69
+ const { class: compoundClass, ...compoundProps } = compound;
70
+ const matches = Object.entries(compoundProps).every(([key, value]) => finalProps[key] === value);
71
+ if (matches) {
72
+ if (compoundClass)
73
+ classes.push(compoundClass);
74
+ // Add compound attributes
75
+ Object.entries(compound).forEach(([k, v]) => {
76
+ if (k !== 'class' && !Object.keys(compoundProps).includes(k)) {
77
+ attributes[k] = v;
78
+ }
79
+ });
80
+ }
81
+ }
82
+ }
83
+ const result = {
84
+ class: classes,
85
+ ...attributes
86
+ };
87
+ // Store in cache (limit cache size to prevent memory leaks)
88
+ if (variantCache.size >= MAX_CACHE_SIZE) {
89
+ // Clear oldest entry (first in Map)
90
+ const firstKey = variantCache.keys().next().value;
91
+ if (firstKey)
92
+ variantCache.delete(firstKey);
93
+ }
94
+ variantCache.set(cacheKey, result);
95
+ return result;
96
+ }
97
+ /**
98
+ * Pure function to merge preset and local variant definitions
99
+ * Returns merged variant props with local overriding preset
100
+ */
101
+ export function mergeVariants(
102
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
103
+ presetVariants, presetClass,
104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
+ presetCompounds,
106
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
+ presetDefaults, localVariants, bond, props) {
108
+ // No variants at all
109
+ if (!presetVariants && !localVariants)
110
+ return undefined;
111
+ // Only preset variants (raw object from preset)
112
+ if (presetVariants && !localVariants) {
113
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
+ const variantDef = {
115
+ class: presetClass ?? '',
116
+ variants: presetVariants,
117
+ compounds: presetCompounds ?? [],
118
+ defaults: presetDefaults ?? {}
119
+ };
120
+ return resolveVariants(variantDef, bond, props);
121
+ }
122
+ // Only local variants
123
+ if (!presetVariants && localVariants) {
124
+ return localVariants;
125
+ }
126
+ // Both exist - merge them
127
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
+ const presetVariantDef = {
129
+ class: presetClass ?? '',
130
+ variants: presetVariants ?? {},
131
+ compounds: presetCompounds ?? [],
132
+ defaults: presetDefaults ?? {}
133
+ };
134
+ const presetResolved = resolveVariants(presetVariantDef, bond, props);
135
+ // Merge the resolved variant props
136
+ // Local variant classes and attributes override preset
137
+ const presetClasses = Array.isArray(presetResolved.class)
138
+ ? presetResolved.class
139
+ : [presetResolved.class];
140
+ const localClasses = Array.isArray(localVariants?.class)
141
+ ? localVariants.class
142
+ : [localVariants?.class];
143
+ return {
144
+ class: [...presetClasses, ...localClasses].filter(Boolean),
145
+ ...presetResolved,
146
+ ...localVariants
147
+ };
148
+ }
149
+ /**
150
+ * Pure function to merge classes with $preset placeholder support
151
+ * Handles the special $preset placeholder for precise positioning of preset classes
152
+ */
153
+ export function mergeClassesWithPreset(userClass, presetClass, variantClass) {
154
+ const klassStr = cn(userClass ?? '');
155
+ // Check for $preset placeholder first
156
+ if (!klassStr.includes('$preset')) {
157
+ // No placeholder - normal merge: variants override direct class
158
+ return cn(userClass, variantClass ?? '');
159
+ }
160
+ // Has placeholder - calculate position and inject preset classes
161
+ const parts = klassStr.split('$preset');
162
+ // Only keep the last $preset placeholder
163
+ const beforeLastPlaceholder = parts.slice(0, -1).join('');
164
+ const afterLastPlaceholder = parts[parts.length - 1];
165
+ const presetClassString = cn(presetClass);
166
+ // Merge: before + preset + variants + after
167
+ return cn(beforeLastPlaceholder, presetClassString, variantClass ?? '', afterLastPlaceholder);
168
+ }
169
+ /**
170
+ * Pure function to resolve local variants
171
+ * Handles both function-based and VariantDefinition-based variants
172
+ */
173
+ export function resolveLocalVariants(
174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
175
+ variants, bond, props) {
176
+ if (!variants)
177
+ return undefined;
178
+ // If it's a function, call it directly
179
+ if (typeof variants === 'function') {
180
+ return variants(bond, props);
181
+ }
182
+ // Otherwise it's a VariantDefinition, resolve it
183
+ return resolveVariants(variants, bond, props);
184
+ }
185
+ /**
186
+ * Pure function to extract rest props by filtering out preset and variant-specific props
187
+ */
188
+ export function extractRestProps(
189
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
190
+ preset, mergedVariants, restProps) {
191
+ const presetProps = { ...preset };
192
+ const presetKeysToRemove = ['class', 'base', 'as', 'variants', 'compounds', 'defaults'];
193
+ for (const key of presetKeysToRemove) {
194
+ delete presetProps[key];
195
+ }
196
+ const variantsRestProps = { ...mergedVariants };
197
+ const variantKeysToRemove = ['class', 'variants', 'compounds', 'defaults'];
198
+ for (const key of variantKeysToRemove) {
199
+ delete variantsRestProps[key];
200
+ }
201
+ return { ...presetProps, ...variantsRestProps, ...restProps };
202
+ }
203
+ /**
204
+ * Pure function to check if a base is a snippet
205
+ */
206
+ export function isSnippetBase(base) {
207
+ return typeof base === 'function' && base.length === 1 && !base.prototype;
208
+ }
@@ -9,7 +9,7 @@
9
9
  {href}
10
10
  preset="breadcrumb.item"
11
11
  class={[
12
- 'hover:text-primary hover:bg-primary/5 border-border flex gap-2 rounded-lg px-2 py-1',
12
+ 'border-border text-foreground/70 hover:text-foreground flex gap-2 rounded-lg px-2 py-1',
13
13
  '$preset',
14
14
  klass
15
15
  ]}
@@ -11,5 +11,9 @@
11
11
  data-kind="breadcrumb-separator"
12
12
  {...restProps}
13
13
  >
14
- {@render children?.()}
14
+ {#if children}
15
+ {@render children?.()}
16
+ {:else}
17
+ /
18
+ {/if}
15
19
  </HtmlAtom>
@@ -1,16 +1,16 @@
1
- <script module>
2
- import { defineMeta } from '@storybook/addon-svelte-csf';
3
- import { Breadcrumb as BreadcrumbModule } from '.';
4
-
5
- const { Story } = defineMeta({
6
- title: 'ATOMS/Breadcrumb'
7
- });
8
- </script>
9
-
10
- <Story name="Breadcrumb">
11
- <BreadcrumbModule.Root>
12
- <BreadcrumbModule.Item href="/">Home</BreadcrumbModule.Item>
13
- <BreadcrumbModule.Separator>/</BreadcrumbModule.Separator>
14
- <BreadcrumbModule.Item href="/vehicles">Vehicles</BreadcrumbModule.Item>
15
- </BreadcrumbModule.Root>
16
- </Story>
1
+ <script module>
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import { Breadcrumb as BreadcrumbModule } from '.';
4
+
5
+ const { Story } = defineMeta({
6
+ title: 'ATOMS/Breadcrumb'
7
+ });
8
+ </script>
9
+
10
+ <Story name="Breadcrumb">
11
+ <BreadcrumbModule.Root>
12
+ <BreadcrumbModule.Item href="/">Home</BreadcrumbModule.Item>
13
+ <BreadcrumbModule.Separator>/</BreadcrumbModule.Separator>
14
+ <BreadcrumbModule.Item href="/vehicles">Vehicles</BreadcrumbModule.Item>
15
+ </BreadcrumbModule.Root>
16
+ </Story>