@svelte-atoms/core 1.0.0-alpha.44 → 1.0.0-alpha.46

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 (178) hide show
  1. package/README.md +13 -0
  2. package/dist/components/accordion/item/accordion-item-body.svelte +5 -8
  3. package/dist/components/accordion/item/accordion-item-header.svelte +0 -13
  4. package/dist/components/accordion/item/accordion-item-indicator.svelte +0 -12
  5. package/dist/components/accordion/item/accordion-item-root.svelte +0 -12
  6. package/dist/components/alert/alert-actions.svelte +0 -12
  7. package/dist/components/alert/alert-close-button.svelte +0 -12
  8. package/dist/components/alert/alert-content.svelte +0 -12
  9. package/dist/components/alert/alert-description.svelte +0 -12
  10. package/dist/components/alert/alert-icon.svelte +0 -12
  11. package/dist/components/alert/alert-root.svelte +1 -13
  12. package/dist/components/alert/alert-title.svelte +0 -12
  13. package/dist/components/atom/html-atom.svelte +31 -17
  14. package/dist/components/atom/types.d.ts +9 -0
  15. package/dist/components/atom/utils/base.d.ts +6 -0
  16. package/dist/components/atom/utils/base.js +8 -0
  17. package/dist/components/atom/utils/cache.d.ts +17 -0
  18. package/dist/components/atom/utils/cache.js +134 -0
  19. package/dist/components/atom/utils/classes.d.ts +14 -0
  20. package/dist/components/atom/utils/classes.js +42 -0
  21. package/dist/components/atom/utils/constants.d.ts +9 -0
  22. package/dist/components/atom/utils/constants.js +9 -0
  23. package/dist/components/atom/utils/index.d.ts +6 -0
  24. package/dist/components/atom/utils/index.js +5 -0
  25. package/dist/components/atom/utils/preset.d.ts +22 -0
  26. package/dist/components/atom/utils/preset.js +94 -0
  27. package/dist/components/atom/utils/props.d.ts +13 -0
  28. package/dist/components/atom/utils/props.js +60 -0
  29. package/dist/components/atom/utils/variants.d.ts +31 -0
  30. package/dist/components/atom/utils/variants.js +270 -0
  31. package/dist/components/card/card-body.svelte +0 -12
  32. package/dist/components/card/card-description.svelte +0 -12
  33. package/dist/components/card/card-footer.svelte +0 -12
  34. package/dist/components/card/card-header.svelte +0 -12
  35. package/dist/components/card/card-media.svelte +0 -12
  36. package/dist/components/card/card-root.svelte +0 -12
  37. package/dist/components/card/card-subtitle.svelte +0 -12
  38. package/dist/components/card/card-title.svelte +0 -12
  39. package/dist/components/collapsible/collapsible-body.svelte +5 -12
  40. package/dist/components/collapsible/collapsible-header.svelte +0 -12
  41. package/dist/components/collapsible/collapsible-indicator.svelte +0 -12
  42. package/dist/components/collapsible/collapsible-root.svelte +0 -12
  43. package/dist/components/combobox/combobox-control.svelte +0 -12
  44. package/dist/components/combobox/combobox-item.svelte +0 -12
  45. package/dist/components/combobox/combobox-item.svelte.d.ts +0 -6
  46. package/dist/components/combobox/index.d.ts +1 -1
  47. package/dist/components/container/container.svelte +0 -12
  48. package/dist/components/datagrid/column/datagrid-column-sort-icon.svelte +3 -12
  49. package/dist/components/datagrid/column/datagrid-column-sort-icon.svelte.d.ts +0 -6
  50. package/dist/components/datagrid/datagrid-body.svelte +17 -1
  51. package/dist/components/dialog/dialog-body.svelte +0 -12
  52. package/dist/components/dialog/dialog-close-button.svelte +0 -12
  53. package/dist/components/dialog/dialog-close.svelte +0 -12
  54. package/dist/components/dialog/dialog-content.svelte +4 -12
  55. package/dist/components/dialog/dialog-description.svelte +0 -12
  56. package/dist/components/dialog/dialog-footer.svelte +0 -12
  57. package/dist/components/dialog/dialog-header.svelte +0 -12
  58. package/dist/components/dialog/dialog-title.svelte +0 -12
  59. package/dist/components/dialog/index.d.ts +3 -0
  60. package/dist/components/dialog/index.js +3 -0
  61. package/dist/components/drawer/drawer-backdrop.svelte +0 -12
  62. package/dist/components/drawer/drawer-body.svelte +0 -12
  63. package/dist/components/drawer/drawer-content.svelte +5 -12
  64. package/dist/components/drawer/drawer-description.svelte +0 -12
  65. package/dist/components/drawer/drawer-footer.svelte +0 -12
  66. package/dist/components/drawer/drawer-header.svelte +0 -12
  67. package/dist/components/drawer/drawer-root.svelte +5 -4
  68. package/dist/components/drawer/drawer-title.svelte +0 -12
  69. package/dist/components/dropdown/dropdown-placeholder.svelte +0 -6
  70. package/dist/components/dropdown/dropdown-placeholder.svelte.d.ts +0 -6
  71. package/dist/components/dropdown/dropdown-query.svelte +0 -12
  72. package/dist/components/dropdown-menu/bond.svelte.d.ts +0 -4
  73. package/dist/components/dropdown-menu/dropdown-menu-content.svelte +0 -12
  74. package/dist/components/dropdown-menu/dropdown-menu-content.svelte.d.ts +0 -6
  75. package/dist/components/dropdown-menu/index.d.ts +1 -1
  76. package/dist/components/form/field/bond.svelte.d.ts +29 -17
  77. package/dist/components/form/field/bond.svelte.js +73 -49
  78. package/dist/components/form/field/field-control.svelte +21 -18
  79. package/dist/components/form/field/field-label.svelte +2 -2
  80. package/dist/components/form/field/field-root.svelte +2 -1
  81. package/dist/components/index.d.ts +2 -0
  82. package/dist/components/index.js +2 -0
  83. package/dist/components/input/input-file-control.svelte +0 -12
  84. package/dist/components/input/input-icon.svelte +3 -3
  85. package/dist/components/input/input-number-control.svelte +28 -35
  86. package/dist/components/input/input-text-control.svelte +8 -3
  87. package/dist/components/input/input-url-control.svelte +2 -2
  88. package/dist/components/input/types.d.ts +4 -4
  89. package/dist/components/kbd/index.d.ts +3 -0
  90. package/dist/components/kbd/index.js +3 -0
  91. package/dist/components/kbd/kbd.svelte +19 -0
  92. package/dist/components/kbd/kbd.svelte.d.ts +4 -0
  93. package/dist/components/kbd/shortcut.svelte +38 -0
  94. package/dist/components/kbd/shortcut.svelte.d.ts +4 -0
  95. package/dist/components/kbd/types.d.ts +20 -0
  96. package/dist/components/kbd/types.js +1 -0
  97. package/dist/components/layer/layer-inner.svelte +0 -12
  98. package/dist/components/layer/layer-root.svelte +0 -12
  99. package/dist/components/menu/menu-content.svelte +0 -12
  100. package/dist/components/menu/menu-content.svelte.d.ts +0 -6
  101. package/dist/components/popover/bond.svelte.d.ts +29 -1
  102. package/dist/components/popover/bond.svelte.js +55 -2
  103. package/dist/components/popover/index.d.ts +1 -0
  104. package/dist/components/popover/index.js +1 -0
  105. package/dist/components/popover/popover-arrow.svelte +4 -2
  106. package/dist/components/popover/popover-content.svelte +17 -90
  107. package/dist/components/popover/popover-overlay.svelte +98 -0
  108. package/dist/components/popover/popover-overlay.svelte.d.ts +4 -0
  109. package/dist/components/popover/popover-trigger.svelte +9 -0
  110. package/dist/components/popover/strategies/floating.svelte +10 -10
  111. package/dist/components/popover/types.d.ts +7 -2
  112. package/dist/components/portal/portal-inner.svelte +0 -12
  113. package/dist/components/portal/portal-root.svelte +0 -12
  114. package/dist/components/portal/types.d.ts +1 -1
  115. package/dist/components/progress/index.d.ts +3 -0
  116. package/dist/components/progress/index.js +3 -0
  117. package/dist/components/progress/progress-circular.svelte +99 -0
  118. package/dist/components/progress/progress-circular.svelte.d.ts +6 -0
  119. package/dist/components/progress/progress-linear.svelte +66 -0
  120. package/dist/components/progress/progress-linear.svelte.d.ts +6 -0
  121. package/dist/components/progress/types.d.ts +18 -0
  122. package/dist/components/progress/types.js +1 -0
  123. package/dist/components/scrollable/scrollable-container.svelte +0 -12
  124. package/dist/components/scrollable/scrollable-content.svelte +0 -12
  125. package/dist/components/scrollable/scrollable-root.svelte +0 -12
  126. package/dist/components/scrollable/scrollable-thumb.svelte +1 -12
  127. package/dist/components/scrollable/scrollable-track.svelte +0 -12
  128. package/dist/components/select/bond.svelte.d.ts +0 -4
  129. package/dist/components/select/index.d.ts +1 -1
  130. package/dist/components/select/select-placeholder.svelte +0 -6
  131. package/dist/components/select/select-placeholder.svelte.d.ts +0 -6
  132. package/dist/components/sidebar/sidebar-content.svelte +5 -12
  133. package/dist/components/stack/bond.svelte.js +6 -0
  134. package/dist/components/stack/stack-item.svelte +4 -0
  135. package/dist/components/switch/switch.svelte +2 -0
  136. package/dist/components/tabs/tab/tab-header.svelte +4 -4
  137. package/dist/components/tabs/tabs-body.svelte +0 -2
  138. package/dist/components/tabs/tabs-root.svelte +11 -3
  139. package/dist/components/toast/atoms.d.ts +1 -1
  140. package/dist/components/toast/atoms.js +1 -1
  141. package/dist/components/toast/attachments.svelte.d.ts +10 -2
  142. package/dist/components/toast/attachments.svelte.js +9 -1
  143. package/dist/components/toast/bond.svelte.d.ts +73 -0
  144. package/dist/components/toast/bond.svelte.js +132 -0
  145. package/dist/components/toast/index.d.ts +1 -1
  146. package/dist/components/toast/index.js +1 -1
  147. package/dist/components/toast/toast-close.svelte +47 -0
  148. package/dist/components/toast/toast-close.svelte.d.ts +26 -0
  149. package/dist/components/toast/toast-description.svelte +16 -24
  150. package/dist/components/toast/toast-description.svelte.d.ts +15 -19
  151. package/dist/components/toast/toast-root.svelte +36 -26
  152. package/dist/components/toast/toast-root.svelte.d.ts +16 -15
  153. package/dist/components/toast/toast-title.svelte +17 -22
  154. package/dist/components/toast/toast-title.svelte.d.ts +13 -13
  155. package/dist/components/toast/toaster.svelte.d.ts +38 -0
  156. package/dist/components/toast/toaster.svelte.js +107 -0
  157. package/dist/components/toast/types.d.ts +13 -21
  158. package/dist/components/tree/tree-body.svelte +5 -12
  159. package/dist/components/tree/tree-header.svelte +0 -12
  160. package/dist/components/tree/tree-indicator.svelte +0 -12
  161. package/dist/components/tree/tree-root.svelte +0 -12
  162. package/dist/context/preset.svelte.d.ts +53 -37
  163. package/dist/context/preset.svelte.js +29 -3
  164. package/package.json +1 -1
  165. package/dist/components/atom/utils.d.ts +0 -44
  166. package/dist/components/atom/utils.js +0 -275
  167. package/dist/components/popover/popover-engine.svelte +0 -118
  168. package/dist/components/popover/popover-engine.svelte.d.ts +0 -3
  169. package/dist/components/toast/bond.d.ts +0 -35
  170. package/dist/components/toast/bond.js +0 -59
  171. package/dist/components/toast/manager.svelte.d.ts +0 -38
  172. package/dist/components/toast/manager.svelte.js +0 -82
  173. package/dist/components/toast/toast-root-managed.svelte +0 -64
  174. package/dist/components/toast/toast-root-managed.svelte.d.ts +0 -7
  175. package/dist/components/toast/toast-toaster.svelte +0 -42
  176. package/dist/components/toast/toast-toaster.svelte.d.ts +0 -4
  177. /package/dist/components/popover/{motion.d.ts → motion.svelte.d.ts} +0 -0
  178. /package/dist/components/popover/{motion.js → motion.svelte.js} +0 -0
@@ -0,0 +1,22 @@
1
+ import type { PresetEntryRecord, PresetEntryValue } from '../../../context/preset.svelte';
2
+ /**
3
+ * Merges an ordered list of {@link PresetEntryRecord}s into a single record.
4
+ *
5
+ * - `class`: collected into an array (all classes preserved, later ones appended)
6
+ * - `compounds`: arrays concatenated
7
+ * - `attachments`: arrays concatenated
8
+ * - `variants`: deep-merged
9
+ * - `defaults`: shallow-merged
10
+ * - any other field: last entry wins
11
+ */
12
+ export declare function mergePresetRecords(records: PresetEntryRecord[]): PresetEntryRecord | undefined;
13
+ /**
14
+ * Resolves a preset to its concrete value.
15
+ *
16
+ * - If `preset` is falsy, returns `undefined`.
17
+ * - If it is an array, each entry is resolved (unwrapping deferred factories)
18
+ * and the results are merged via {@link mergePresetRecords}.
19
+ * - Otherwise, unwraps up to two levels of factory functions.
20
+ */
21
+ export declare function resolvePreset(preset: PresetEntryValue | Array<PresetEntryValue> | undefined): PresetEntryRecord | undefined;
22
+ export declare function resolvePreset<T>(preset: T | (() => T) | undefined): T | undefined;
@@ -0,0 +1,94 @@
1
+ import { merge } from 'es-toolkit';
2
+ import { call } from '../../../utils/function';
3
+ /**
4
+ * Merges an ordered list of {@link PresetEntryRecord}s into a single record.
5
+ *
6
+ * - `class`: collected into an array (all classes preserved, later ones appended)
7
+ * - `compounds`: arrays concatenated
8
+ * - `attachments`: arrays concatenated
9
+ * - `variants`: deep-merged
10
+ * - `defaults`: shallow-merged
11
+ * - any other field: last entry wins
12
+ */
13
+ export function mergePresetRecords(records) {
14
+ const len = records.length;
15
+ if (!len)
16
+ return undefined;
17
+ if (len === 1)
18
+ return records[0];
19
+ const result = {};
20
+ const classes = [];
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ const compounds = [];
23
+ const attachments = [];
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ const variantsList = [];
26
+ for (let i = 0; i < len; i++) {
27
+ const record = records[i];
28
+ if (!record)
29
+ continue;
30
+ if (record.class !== undefined)
31
+ classes.push(record.class);
32
+ const recCompounds = record.compounds;
33
+ if (recCompounds?.length) {
34
+ for (let j = 0, jlen = recCompounds.length; j < jlen; j++)
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ compounds.push(recCompounds[j]);
37
+ }
38
+ const recAttachments = record.attachments;
39
+ if (recAttachments?.length) {
40
+ for (let j = 0, jlen = recAttachments.length; j < jlen; j++)
41
+ attachments.push(recAttachments[j]);
42
+ }
43
+ if (record.variants)
44
+ variantsList.push(record.variants);
45
+ if (record.defaults)
46
+ result.defaults =
47
+ result.defaults !== undefined
48
+ ? { ...result.defaults, ...record.defaults }
49
+ : record.defaults;
50
+ // Copy remaining own keys directly — avoids allocating an intermediate `rest` object.
51
+ // Use hasOwnProperty guard so prototype-chain properties are never copied.
52
+ for (const key in record) {
53
+ if (!Object.prototype.hasOwnProperty.call(record, key) ||
54
+ key === 'class' ||
55
+ key === 'compounds' ||
56
+ key === 'attachments' ||
57
+ key === 'variants' ||
58
+ key === 'defaults')
59
+ continue;
60
+ result[key] = record[key];
61
+ }
62
+ }
63
+ if (classes.length)
64
+ result.class = classes.length === 1 ? classes[0] : classes;
65
+ if (compounds.length)
66
+ result.compounds = compounds;
67
+ if (attachments.length)
68
+ result.attachments = attachments;
69
+ // Single merge pass over all variant maps — avoids N-1 intermediate objects
70
+ if (variantsList.length) {
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ let merged = {};
73
+ for (let j = 0; j < variantsList.length; j++)
74
+ merged = merge(merged, variantsList[j]);
75
+ result.variants = merged;
76
+ }
77
+ return result;
78
+ }
79
+ export function resolvePreset(preset) {
80
+ if (!preset)
81
+ return undefined;
82
+ if (Array.isArray(preset)) {
83
+ const resolved = [];
84
+ for (const entry of preset) {
85
+ const value = resolvePreset(entry);
86
+ if (value)
87
+ resolved.push(value);
88
+ }
89
+ return mergePresetRecords(resolved);
90
+ }
91
+ const result = call(preset);
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
+ return typeof result === 'function' ? result() : result;
94
+ }
@@ -0,0 +1,13 @@
1
+ import type { ResolvedProps } from './cache';
2
+ /**
3
+ * Builds the final spread-ready props object by layering, in ascending priority:
4
+ * fallback → preset → mergedVariants → restProps.
5
+ *
6
+ * `fallback` is the lowest-priority source and is intended for internal defaults
7
+ * (e.g. a default `animate` function) that should only apply when neither the
8
+ * preset nor the consumer has specified the prop.
9
+ *
10
+ * Internal atom keys (`class`, `base`, `as`, …) are stripped; Symbol-keyed
11
+ * attachment props are preserved at every layer.
12
+ */
13
+ export declare function extractRestProps(preset: Record<string, any> | undefined, mergedVariants: ResolvedProps | undefined, restProps: Record<string, unknown>, fallback?: Record<string, any> | undefined): Record<string, unknown>;
@@ -0,0 +1,60 @@
1
+ import { PRESET_SKIP, VARIANTS_SKIP } from './constants';
2
+ /**
3
+ * Copies own string-keyed props from `src` into `result`, skipping any keys in
4
+ * `skip` (or no skip list when `skip` is undefined). Falls back to `for...in`
5
+ * which only iterates own + enumerable inherited keys; the additional
6
+ * `Object.hasOwn` guard mirrors the original behavior for safety.
7
+ */
8
+ function copyStringKeys(src, skip, result) {
9
+ for (const k in src) {
10
+ if (!Object.hasOwn(src, k))
11
+ continue;
12
+ if (skip && skip.has(k))
13
+ continue;
14
+ result[k] = src[k];
15
+ }
16
+ }
17
+ /**
18
+ * Copies symbol-keyed props from `src` into `result`. Only allocates the
19
+ * symbols array when the source actually has any (the 99% case has none).
20
+ */
21
+ function copySymbolKeys(src, result) {
22
+ const syms = Object.getOwnPropertySymbols(src);
23
+ if (syms.length === 0)
24
+ return;
25
+ for (const s of syms)
26
+ result[s] = src[s];
27
+ }
28
+ /**
29
+ * Builds the final spread-ready props object by layering, in ascending priority:
30
+ * fallback → preset → mergedVariants → restProps.
31
+ *
32
+ * `fallback` is the lowest-priority source and is intended for internal defaults
33
+ * (e.g. a default `animate` function) that should only apply when neither the
34
+ * preset nor the consumer has specified the prop.
35
+ *
36
+ * Internal atom keys (`class`, `base`, `as`, …) are stripped; Symbol-keyed
37
+ * attachment props are preserved at every layer.
38
+ */
39
+ export function extractRestProps(
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ preset, mergedVariants, restProps,
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+ fallback) {
44
+ const result = {};
45
+ if (fallback) {
46
+ copyStringKeys(fallback, PRESET_SKIP, result);
47
+ copySymbolKeys(fallback, result);
48
+ }
49
+ if (preset) {
50
+ copyStringKeys(preset, PRESET_SKIP, result);
51
+ copySymbolKeys(preset, result);
52
+ }
53
+ if (mergedVariants) {
54
+ copyStringKeys(mergedVariants, VARIANTS_SKIP, result);
55
+ copySymbolKeys(mergedVariants, result);
56
+ }
57
+ copyStringKeys(restProps, undefined, result);
58
+ copySymbolKeys(restProps, result);
59
+ return result;
60
+ }
@@ -0,0 +1,31 @@
1
+ import type { Bond } from '../../../shared';
2
+ import { type ClassValue, type VariantDefinition } from '../../../utils';
3
+ import { type ResolvedProps } from './cache';
4
+ type AnyVariantDefinition = VariantDefinition<any>;
5
+ /**
6
+ * Resolves a `VariantDefinition` to a concrete `ResolvedProps` object.
7
+ *
8
+ * Results are cached in a per-definition LRU keyed by bond instance + a fast
9
+ * structural key over variant-relevant props, so the same inputs always return
10
+ * the same (reference-equal) object without re-computing.
11
+ */
12
+ export declare function resolveVariants(def: AnyVariantDefinition, bond: Bond | null | undefined, props: Record<string, unknown>): ResolvedProps;
13
+ /**
14
+ * Merges preset variant definitions with locally-supplied resolved variant props.
15
+ * Local values always take precedence; classes are concatenated (preset first).
16
+ */
17
+ 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;
18
+ /**
19
+ * Resolves locally-supplied `variants` to a `ResolvedProps` object.
20
+ *
21
+ * Handles three shapes:
22
+ * - A function tagged with `VARIANT_DEF_TAG` (created by `defineVariants`) → routed through the
23
+ * cached `resolveVariants` engine.
24
+ * - A plain function (manual/legacy) → called with a per-(fn, bond) snapshot
25
+ * cache so re-renders with the same primitive props return the same result
26
+ * reference. Falls back to direct invocation when props contain non-primitive
27
+ * values.
28
+ * - A raw `VariantDefinition` object → resolved through the cache.
29
+ */
30
+ export declare function resolveLocalVariants(variants: any, bond: Bond | null | undefined, props: Record<string, unknown>): ResolvedProps | undefined;
31
+ export {};
@@ -0,0 +1,270 @@
1
+ import { VARIANT_DEF_TAG } from '../../../utils';
2
+ import { getDefCacheMap, getCachedOwnKeys, getCompoundConditionKeys, hasOwnKeysCached, lruGet, lruSet, MAX_CACHE_SIZE } from './cache';
3
+ /**
4
+ * Builds a compact cache key from variant-relevant prop values without
5
+ * paying the cost of `JSON.stringify`. Variant prop values are almost always
6
+ * primitives (the keys of a variant map), so we serialize inline and only fall
7
+ * back to `JSON.stringify` for the rare object value.
8
+ */
9
+ function buildVariantKey(variantKeys, finalProps) {
10
+ let key = '';
11
+ for (const k of variantKeys) {
12
+ if (!(k in finalProps))
13
+ continue;
14
+ const v = finalProps[k];
15
+ // Discriminate type so e.g. `"true"` and `true` don't collide.
16
+ const t = typeof v;
17
+ if (v === undefined) {
18
+ key += k + '=u|';
19
+ }
20
+ else if (v === null) {
21
+ key += k + '=n|';
22
+ }
23
+ else if (t === 'string' || t === 'number' || t === 'boolean') {
24
+ key += k + '=' + t[0] + ':' + v + '|';
25
+ }
26
+ else {
27
+ key += k + '=o:' + JSON.stringify(v) + '|';
28
+ }
29
+ }
30
+ return key;
31
+ }
32
+ /**
33
+ * Resolves a `VariantDefinition` to a concrete `ResolvedProps` object.
34
+ *
35
+ * Results are cached in a per-definition LRU keyed by bond instance + a fast
36
+ * structural key over variant-relevant props, so the same inputs always return
37
+ * the same (reference-equal) object without re-computing.
38
+ */
39
+ export function resolveVariants(def, bond, props) {
40
+ const { variants: variantMap, compounds, defaults, class: baseClass } = def;
41
+ const finalProps = hasOwnKeysCached(defaults) ? { ...defaults, ...props } : props;
42
+ const variantKeys = getCachedOwnKeys(variantMap);
43
+ // Fast path: no variants or compounds — cached per `def` reference so
44
+ // repeated renders return the SAME object (preserves downstream identity).
45
+ if (variantKeys.length === 0 && !compounds?.length) {
46
+ const fastMap = getDefCacheMap(def, bond);
47
+ const fastHit = lruGet(fastMap, '');
48
+ if (fastHit !== undefined)
49
+ return fastHit;
50
+ const fastResult = { class: baseClass ? [baseClass] : [] };
51
+ lruSet(fastMap, '', fastResult, MAX_CACHE_SIZE);
52
+ return fastResult;
53
+ }
54
+ const cacheKey = buildVariantKey(variantKeys, finalProps);
55
+ const cacheMap = getDefCacheMap(def, bond);
56
+ const hit = lruGet(cacheMap, cacheKey);
57
+ if (hit !== undefined)
58
+ return hit;
59
+ const classes = [];
60
+ const attributes = {};
61
+ if (baseClass)
62
+ classes.push(baseClass);
63
+ if (variantMap) {
64
+ for (const key of variantKeys) {
65
+ const value = finalProps[key];
66
+ if (value === undefined)
67
+ continue;
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const variantValue = variantMap[key]?.[value];
70
+ if (variantValue === undefined)
71
+ continue;
72
+ const resolved = typeof variantValue === 'function' ? variantValue(bond) : variantValue;
73
+ if (typeof resolved === 'string') {
74
+ classes.push(resolved);
75
+ }
76
+ else if (typeof resolved === 'object' && resolved !== null) {
77
+ if ('class' in resolved)
78
+ classes.push(resolved.class);
79
+ const syms = Object.getOwnPropertySymbols(resolved);
80
+ if (syms.length) {
81
+ const src = resolved;
82
+ for (const sym of syms)
83
+ attributes[sym] = src[sym];
84
+ }
85
+ }
86
+ }
87
+ }
88
+ if (compounds?.length) {
89
+ for (const compound of compounds) {
90
+ const compoundClass = compound.class;
91
+ const conditionKeys = getCompoundConditionKeys(compound);
92
+ let matches = true;
93
+ for (const key of conditionKeys) {
94
+ if (finalProps[key] !== compound[key]) {
95
+ matches = false;
96
+ break;
97
+ }
98
+ }
99
+ if (!matches)
100
+ continue;
101
+ if (compoundClass)
102
+ classes.push(compoundClass);
103
+ }
104
+ }
105
+ const result = { class: classes, ...attributes };
106
+ lruSet(cacheMap, cacheKey, result, MAX_CACHE_SIZE);
107
+ return result;
108
+ }
109
+ /**
110
+ * Cache constructed preset variant defs by `presetVariants` reference so the
111
+ * downstream per-def cache (`getDefCacheMap`) hits across renders.
112
+ */
113
+ const presetDefCache = new WeakMap();
114
+ function getOrBuildPresetDef(
115
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
116
+ presetVariants, presetClass,
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ presetCompounds,
119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
+ presetDefaults) {
121
+ const cached = presetDefCache.get(presetVariants);
122
+ if (cached)
123
+ return cached;
124
+ const built = {
125
+ class: presetClass ?? '',
126
+ variants: presetVariants,
127
+ compounds: presetCompounds ?? [],
128
+ defaults: presetDefaults ?? {}
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
+ };
131
+ presetDefCache.set(presetVariants, built);
132
+ return built;
133
+ }
134
+ /**
135
+ * Merge cache: chained WeakMaps keyed by `(presetResolved, localVariants)`.
136
+ *
137
+ * Both inputs come from `resolveVariants` / `resolveLocalVariants`, which
138
+ * return reference-stable objects across renders. When neither flips, we
139
+ * return the SAME merged object every time — eliminating a fresh array+spread
140
+ * allocation on the hot path. Keys are weak so entries are GC'd whenever
141
+ * either input is unreachable.
142
+ */
143
+ const mergeCache = new WeakMap();
144
+ function getCachedMerge(presetResolved, localVariants) {
145
+ const inner = mergeCache.get(presetResolved);
146
+ return inner?.get(localVariants);
147
+ }
148
+ function setCachedMerge(presetResolved, localVariants, merged) {
149
+ let inner = mergeCache.get(presetResolved);
150
+ if (!inner) {
151
+ inner = new WeakMap();
152
+ mergeCache.set(presetResolved, inner);
153
+ }
154
+ inner.set(localVariants, merged);
155
+ }
156
+ /**
157
+ * Merges preset variant definitions with locally-supplied resolved variant props.
158
+ * Local values always take precedence; classes are concatenated (preset first).
159
+ */
160
+ export function mergeVariants(
161
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
162
+ presetVariants, presetClass,
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ presetCompounds,
165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
166
+ presetDefaults, localVariants, bond, props) {
167
+ if (!presetVariants && !localVariants)
168
+ return undefined;
169
+ if (presetVariants && !localVariants) {
170
+ const variantDef = getOrBuildPresetDef(presetVariants, presetClass, presetCompounds, presetDefaults);
171
+ return resolveVariants(variantDef, bond, props);
172
+ }
173
+ if (!presetVariants && localVariants)
174
+ return localVariants;
175
+ const presetVariantDef = getOrBuildPresetDef(
176
+ // `presetVariants` is non-null in this branch (TS narrowing lost via `&&`).
177
+ presetVariants, presetClass, presetCompounds, presetDefaults);
178
+ const presetResolved = resolveVariants(presetVariantDef, bond, props);
179
+ // `localVariants` is guaranteed non-null in this branch.
180
+ const local = localVariants;
181
+ const cachedMerge = getCachedMerge(presetResolved, local);
182
+ if (cachedMerge !== undefined)
183
+ return cachedMerge;
184
+ const presetClasses = Array.isArray(presetResolved.class)
185
+ ? presetResolved.class
186
+ : [presetResolved.class];
187
+ const localClasses = Array.isArray(local.class) ? local.class : [local.class];
188
+ const merged = {
189
+ ...presetResolved,
190
+ ...local,
191
+ class: [...presetClasses, ...localClasses].filter(Boolean)
192
+ };
193
+ setCachedMerge(presetResolved, local, merged);
194
+ return merged;
195
+ }
196
+ const plainFnCacheBond = new WeakMap();
197
+ const plainFnCacheNoBond = new WeakMap();
198
+ function getPlainFnEntry(fn, bond) {
199
+ if (!bond)
200
+ return plainFnCacheNoBond.get(fn);
201
+ const inner = plainFnCacheBond.get(fn);
202
+ return inner?.get(bond);
203
+ }
204
+ function setPlainFnEntry(fn, bond, entry) {
205
+ if (!bond) {
206
+ plainFnCacheNoBond.set(fn, entry);
207
+ return;
208
+ }
209
+ let inner = plainFnCacheBond.get(fn);
210
+ if (!inner) {
211
+ inner = new WeakMap();
212
+ plainFnCacheBond.set(fn, inner);
213
+ }
214
+ inner.set(bond, entry);
215
+ }
216
+ function snapshotPrimitiveProps(props) {
217
+ let s = '';
218
+ const keys = Object.keys(props).sort();
219
+ for (const k of keys) {
220
+ const v = props[k];
221
+ const t = typeof v;
222
+ if (v === null) {
223
+ s += k + '=n|';
224
+ }
225
+ else if (t === 'string' || t === 'number' || t === 'boolean' || t === 'undefined') {
226
+ s += k + '=' + (t === 'undefined' ? 'u' : t[0]) + ':' + String(v) + '|';
227
+ }
228
+ else {
229
+ // Non-primitive value: cannot safely structural-compare — bail out.
230
+ return null;
231
+ }
232
+ }
233
+ return s;
234
+ }
235
+ /**
236
+ * Resolves locally-supplied `variants` to a `ResolvedProps` object.
237
+ *
238
+ * Handles three shapes:
239
+ * - A function tagged with `VARIANT_DEF_TAG` (created by `defineVariants`) → routed through the
240
+ * cached `resolveVariants` engine.
241
+ * - A plain function (manual/legacy) → called with a per-(fn, bond) snapshot
242
+ * cache so re-renders with the same primitive props return the same result
243
+ * reference. Falls back to direct invocation when props contain non-primitive
244
+ * values.
245
+ * - A raw `VariantDefinition` object → resolved through the cache.
246
+ */
247
+ export function resolveLocalVariants(
248
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
+ variants, bond, props) {
250
+ if (!variants)
251
+ return undefined;
252
+ if (typeof variants === 'function' && VARIANT_DEF_TAG in variants) {
253
+ const config = variants[VARIANT_DEF_TAG];
254
+ const resolvedConfig = typeof config === 'function' ? config(bond) : config;
255
+ return resolveVariants(resolvedConfig, bond, props);
256
+ }
257
+ if (typeof variants === 'function') {
258
+ const snapshot = snapshotPrimitiveProps(props);
259
+ if (snapshot !== null) {
260
+ const cached = getPlainFnEntry(variants, bond);
261
+ if (cached && cached.snapshot === snapshot)
262
+ return cached.result;
263
+ const result = variants(bond, props);
264
+ setPlainFnEntry(variants, bond, { snapshot, result });
265
+ return result;
266
+ }
267
+ return variants(bond, props);
268
+ }
269
+ return resolveVariants(variants, bond, props);
270
+ }
@@ -8,12 +8,6 @@
8
8
  let {
9
9
  class: klass = '',
10
10
  children = undefined,
11
- onmount = undefined,
12
- ondestroy = undefined,
13
- animate = undefined,
14
- enter = undefined,
15
- exit = undefined,
16
- initial = undefined,
17
11
  ...restProps
18
12
  }: CardContentProps<E, B> = $props();
19
13
 
@@ -27,12 +21,6 @@
27
21
  {bond}
28
22
  preset="card.content"
29
23
  class={['card-content border-border px-4 pb-4', '$preset', klass]}
30
- enter={enter?.bind(bond.state)}
31
- exit={exit?.bind(bond.state)}
32
- initial={initial?.bind(bond.state)}
33
- animate={animate?.bind(bond.state)}
34
- onmount={onmount?.bind(bond.state)}
35
- ondestroy={ondestroy?.bind(bond.state)}
36
24
  {...contentProps}
37
25
  >
38
26
  {@render children?.()}
@@ -9,12 +9,6 @@
9
9
  class: klass = '',
10
10
  as = 'p' as E,
11
11
  children = undefined,
12
- onmount = undefined,
13
- ondestroy = undefined,
14
- animate = undefined,
15
- enter = undefined,
16
- exit = undefined,
17
- initial = undefined,
18
12
  ...restProps
19
13
  }: CardDescriptionProps<E, B> = $props();
20
14
 
@@ -29,12 +23,6 @@
29
23
  {bond}
30
24
  preset="card.description"
31
25
  class={['card-description border-border text-sm text-gray-500', '$preset', klass]}
32
- enter={enter?.bind(bond.state)}
33
- exit={exit?.bind(bond.state)}
34
- initial={initial?.bind(bond.state)}
35
- animate={animate?.bind(bond.state)}
36
- onmount={onmount?.bind(bond.state)}
37
- ondestroy={ondestroy?.bind(bond.state)}
38
26
  {...descriptionProps}
39
27
  >
40
28
  {@render children?.()}
@@ -9,12 +9,6 @@
9
9
  class: klass = '',
10
10
  as = 'div' as E,
11
11
  children = undefined,
12
- onmount = undefined,
13
- ondestroy = undefined,
14
- animate = undefined,
15
- enter = undefined,
16
- exit = undefined,
17
- initial = undefined,
18
12
  ...restProps
19
13
  }: CardFooterProps<E, B> = $props();
20
14
 
@@ -29,12 +23,6 @@
29
23
  {bond}
30
24
  preset="card.footer"
31
25
  class={['card-footer border-border flex items-center gap-2 px-4 pb-4', '$preset', klass]}
32
- enter={enter?.bind(bond.state)}
33
- exit={exit?.bind(bond.state)}
34
- initial={initial?.bind(bond.state)}
35
- animate={animate?.bind(bond.state)}
36
- onmount={onmount?.bind(bond.state)}
37
- ondestroy={ondestroy?.bind(bond.state)}
38
26
  {...footerProps}
39
27
  >
40
28
  {@render children?.()}
@@ -9,12 +9,6 @@
9
9
  class: klass = '',
10
10
  as = 'div' as E,
11
11
  children = undefined,
12
- onmount = undefined,
13
- ondestroy = undefined,
14
- animate = undefined,
15
- enter = undefined,
16
- exit = undefined,
17
- initial = undefined,
18
12
  ...restProps
19
13
  }: CardHeaderProps<E, B> = $props();
20
14
 
@@ -29,12 +23,6 @@
29
23
  {bond}
30
24
  preset="card.header"
31
25
  class={['card-header border-border flex flex-col space-y-1.5 px-4 py-4', '$preset', klass]}
32
- enter={enter?.bind(bond.state)}
33
- exit={exit?.bind(bond.state)}
34
- initial={initial?.bind(bond.state)}
35
- animate={animate?.bind(bond.state)}
36
- onmount={onmount?.bind(bond.state)}
37
- ondestroy={ondestroy?.bind(bond.state)}
38
26
  {...headerProps}
39
27
  >
40
28
  {@render children?.()}
@@ -9,12 +9,6 @@
9
9
  class: klass = '',
10
10
  as = 'div' as E,
11
11
  children = undefined,
12
- onmount = undefined,
13
- ondestroy = undefined,
14
- animate = undefined,
15
- enter = undefined,
16
- exit = undefined,
17
- initial = undefined,
18
12
  ...restProps
19
13
  }: CardMediaProps<E, B> = $props();
20
14
 
@@ -29,12 +23,6 @@
29
23
  {bond}
30
24
  preset="card.media"
31
25
  class={['card-media border-border overflow-hidden', '$preset', klass]}
32
- enter={enter?.bind(bond.state)}
33
- exit={exit?.bind(bond.state)}
34
- initial={initial?.bind(bond.state)}
35
- animate={animate?.bind(bond.state)}
36
- onmount={onmount?.bind(bond.state)}
37
- ondestroy={ondestroy?.bind(bond.state)}
38
26
  {...mediaProps}
39
27
  >
40
28
  {@render children?.()}
@@ -13,12 +13,6 @@
13
13
  children = undefined,
14
14
  onclick = undefined,
15
15
  onkeydown = undefined,
16
- onmount = undefined,
17
- ondestroy = undefined,
18
- animate = undefined,
19
- enter = undefined,
20
- exit = undefined,
21
- initial = undefined,
22
16
  ...restProps
23
17
  }: CardRootProps<E, B> = $props();
24
18
 
@@ -78,12 +72,6 @@
78
72
  klass
79
73
  ]}
80
74
  {bond}
81
- enter={enter?.bind(bond.state)}
82
- exit={exit?.bind(bond.state)}
83
- initial={initial?.bind(bond.state)}
84
- animate={animate?.bind(bond.state)}
85
- onmount={onmount?.bind(bond.state)}
86
- ondestroy={ondestroy?.bind(bond.state)}
87
75
  onclick={handleClick}
88
76
  onkeydown={handleKeydown}
89
77
  {...rootProps}
@@ -9,12 +9,6 @@
9
9
  class: klass = '',
10
10
  as = 'p' as E,
11
11
  children = undefined,
12
- onmount = undefined,
13
- ondestroy = undefined,
14
- animate = undefined,
15
- enter = undefined,
16
- exit = undefined,
17
- initial = undefined,
18
12
  ...restProps
19
13
  }: CardSubtitleProps<E, B> = $props();
20
14
 
@@ -29,12 +23,6 @@
29
23
  {bond}
30
24
  preset="card.subtitle"
31
25
  class={['card-subtitle border-border text-sm font-medium text-gray-600', '$preset', klass]}
32
- enter={enter?.bind(bond.state)}
33
- exit={exit?.bind(bond.state)}
34
- initial={initial?.bind(bond.state)}
35
- animate={animate?.bind(bond.state)}
36
- onmount={onmount?.bind(bond.state)}
37
- ondestroy={ondestroy?.bind(bond.state)}
38
26
  {...subtitleProps}
39
27
  >
40
28
  {@render children?.()}