@svelte-atoms/core 1.0.0-alpha.25 → 1.0.0-alpha.27

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 (354) hide show
  1. package/README.md +645 -645
  2. package/dist/components/accordion/accordion-root.svelte +61 -79
  3. package/dist/components/accordion/accordion-root.svelte.d.ts +2 -15
  4. package/dist/components/accordion/index.d.ts +2 -1
  5. package/dist/components/accordion/index.js +2 -1
  6. package/dist/components/accordion/item/accordion-item-body.svelte +42 -52
  7. package/dist/components/accordion/item/accordion-item-body.svelte.d.ts +2 -8
  8. package/dist/components/accordion/item/accordion-item-header.svelte +50 -56
  9. package/dist/components/accordion/item/accordion-item-header.svelte.d.ts +3 -20
  10. package/dist/components/accordion/item/accordion-item-indicator.svelte +50 -59
  11. package/dist/components/accordion/item/accordion-item-indicator.svelte.d.ts +2 -8
  12. package/dist/components/accordion/item/accordion-item-root.svelte +65 -79
  13. package/dist/components/accordion/item/accordion-item-root.svelte.d.ts +2 -12
  14. package/dist/components/accordion/item/index.d.ts +1 -0
  15. package/dist/components/accordion/item/types.d.ts +52 -0
  16. package/dist/components/accordion/item/types.js +1 -0
  17. package/dist/components/accordion/types.d.ts +21 -0
  18. package/dist/components/accordion/types.js +1 -0
  19. package/dist/components/alert/alert-actions.svelte +42 -52
  20. package/dist/components/alert/alert-actions.svelte.d.ts +3 -30
  21. package/dist/components/alert/alert-close-button.svelte +72 -79
  22. package/dist/components/alert/alert-close-button.svelte.d.ts +8 -35
  23. package/dist/components/alert/alert-content.svelte +42 -52
  24. package/dist/components/alert/alert-content.svelte.d.ts +3 -30
  25. package/dist/components/alert/alert-description.svelte +41 -51
  26. package/dist/components/alert/alert-description.svelte.d.ts +7 -10
  27. package/dist/components/alert/alert-icon.svelte +46 -56
  28. package/dist/components/alert/alert-icon.svelte.d.ts +2 -8
  29. package/dist/components/alert/alert-root.svelte +102 -118
  30. package/dist/components/alert/alert-root.svelte.d.ts +2 -13
  31. package/dist/components/alert/alert-title.svelte +41 -51
  32. package/dist/components/alert/alert-title.svelte.d.ts +2 -8
  33. package/dist/components/alert/index.d.ts +1 -0
  34. package/dist/components/alert/index.js +1 -0
  35. package/dist/components/alert/types.d.ts +85 -0
  36. package/dist/components/alert/types.js +1 -0
  37. package/dist/components/atom/html-atom.svelte +201 -217
  38. package/dist/components/atom/html-atom.svelte.d.ts +2 -22
  39. package/dist/components/atom/types.d.ts +7 -2
  40. package/dist/components/avatar/types.d.ts +7 -2
  41. package/dist/components/badge/badge.svelte +1 -1
  42. package/dist/components/badge/types.d.ts +7 -2
  43. package/dist/components/breadcrumb/breadcrumb-item.svelte +1 -1
  44. package/dist/components/breadcrumb/breadcrumb-root.svelte +1 -1
  45. package/dist/components/breadcrumb/breadcrumb-separator.svelte +1 -1
  46. package/dist/components/button/button.stories.svelte +57 -57
  47. package/dist/components/button/button.svelte +1 -1
  48. package/dist/components/button/button.svelte.d.ts +4 -1
  49. package/dist/components/button/index.d.ts +1 -0
  50. package/dist/components/button/index.js +1 -0
  51. package/dist/components/button/types.d.ts +8 -3
  52. package/dist/components/card/card-body.svelte +39 -45
  53. package/dist/components/card/card-body.svelte.d.ts +7 -4
  54. package/dist/components/card/card-description.svelte +41 -48
  55. package/dist/components/card/card-description.svelte.d.ts +7 -7
  56. package/dist/components/card/card-footer.svelte +41 -48
  57. package/dist/components/card/card-footer.svelte.d.ts +7 -4
  58. package/dist/components/card/card-header.svelte +41 -48
  59. package/dist/components/card/card-header.svelte.d.ts +7 -4
  60. package/dist/components/card/card-media.svelte +41 -48
  61. package/dist/components/card/card-media.svelte.d.ts +7 -4
  62. package/dist/components/card/card-root.svelte +91 -91
  63. package/dist/components/card/card-root.svelte.d.ts +1 -1
  64. package/dist/components/card/card-subtitle.svelte +41 -48
  65. package/dist/components/card/card-subtitle.svelte.d.ts +12 -9
  66. package/dist/components/card/card-title.svelte +45 -48
  67. package/dist/components/card/card-title.svelte.d.ts +12 -9
  68. package/dist/components/card/index.d.ts +1 -0
  69. package/dist/components/card/index.js +1 -0
  70. package/dist/components/card/types.d.ts +57 -2
  71. package/dist/components/checkbox/checkbox.svelte +39 -28
  72. package/dist/components/checkbox/types.d.ts +7 -2
  73. package/dist/components/collapsible/collapsible-body.svelte +39 -52
  74. package/dist/components/collapsible/collapsible-body.svelte.d.ts +2 -9
  75. package/dist/components/collapsible/collapsible-header.svelte +39 -52
  76. package/dist/components/collapsible/collapsible-header.svelte.d.ts +2 -9
  77. package/dist/components/collapsible/collapsible-indicator.svelte +50 -65
  78. package/dist/components/collapsible/collapsible-indicator.svelte.d.ts +3 -10
  79. package/dist/components/collapsible/collapsible-root.svelte +66 -85
  80. package/dist/components/collapsible/collapsible-root.svelte.d.ts +2 -14
  81. package/dist/components/collapsible/index.d.ts +1 -0
  82. package/dist/components/collapsible/index.js +1 -0
  83. package/dist/components/collapsible/types.d.ts +54 -0
  84. package/dist/components/collapsible/types.js +1 -0
  85. package/dist/components/combobox/atoms.d.ts +5 -1
  86. package/dist/components/combobox/atoms.js +5 -1
  87. package/dist/components/combobox/{combobox-input.svelte → combobox-control.svelte} +3 -3
  88. package/dist/components/combobox/{combobox-input.svelte.d.ts → combobox-control.svelte.d.ts} +3 -3
  89. package/dist/components/combobox/combobox-root.svelte +65 -68
  90. package/dist/components/combobox/combobox-root.svelte.d.ts +5 -18
  91. package/dist/components/combobox/combobox-trigger.svelte +1 -1
  92. package/dist/components/combobox/compobox-item.svelte +1 -1
  93. package/dist/components/combobox/index.d.ts +1 -0
  94. package/dist/components/combobox/index.js +1 -0
  95. package/dist/components/combobox/types.d.ts +25 -0
  96. package/dist/components/combobox/types.js +1 -0
  97. package/dist/components/container/container.svelte +1 -1
  98. package/dist/components/container/types.d.ts +7 -2
  99. package/dist/components/contextmenu/types.d.ts +8 -0
  100. package/dist/components/contextmenu/types.js +1 -0
  101. package/dist/components/datagrid/datagrid-body.svelte +37 -44
  102. package/dist/components/datagrid/datagrid-body.svelte.d.ts +17 -20
  103. package/dist/components/datagrid/datagrid-checkbox.svelte +101 -108
  104. package/dist/components/datagrid/datagrid-checkbox.svelte.d.ts +4 -6
  105. package/dist/components/datagrid/datagrid-footer.svelte +34 -34
  106. package/dist/components/datagrid/datagrid-footer.svelte.d.ts +1 -1
  107. package/dist/components/datagrid/datagrid-header.svelte +49 -49
  108. package/dist/components/datagrid/datagrid-header.svelte.d.ts +1 -1
  109. package/dist/components/datagrid/datagrid-root.svelte +59 -59
  110. package/dist/components/datagrid/datagrid-root.svelte.d.ts +1 -1
  111. package/dist/components/datagrid/datagrid.stories.svelte +75 -75
  112. package/dist/components/datagrid/td/datagrid-td.svelte +66 -80
  113. package/dist/components/datagrid/td/datagrid-td.svelte.d.ts +7 -16
  114. package/dist/components/datagrid/th/datagrid-th-sort-icon.svelte +1 -1
  115. package/dist/components/datagrid/th/datagrid-th.svelte +106 -127
  116. package/dist/components/datagrid/th/datagrid-th.svelte.d.ts +2 -20
  117. package/dist/components/datagrid/tr/bond.svelte.d.ts +3 -1
  118. package/dist/components/datagrid/tr/bond.svelte.js +4 -2
  119. package/dist/components/datagrid/tr/datagrid-tr.svelte +88 -103
  120. package/dist/components/datagrid/tr/datagrid-tr.svelte.d.ts +2 -18
  121. package/dist/components/datagrid/types.d.ts +85 -37
  122. package/dist/components/dialog/dialog-body.svelte +39 -45
  123. package/dist/components/dialog/dialog-body.svelte.d.ts +2 -2
  124. package/dist/components/dialog/dialog-close-button.svelte +58 -61
  125. package/dist/components/dialog/dialog-close-button.svelte.d.ts +7 -7
  126. package/dist/components/dialog/dialog-content.svelte +62 -71
  127. package/dist/components/dialog/dialog-content.svelte.d.ts +2 -2
  128. package/dist/components/dialog/dialog-description.svelte +40 -46
  129. package/dist/components/dialog/dialog-description.svelte.d.ts +2 -2
  130. package/dist/components/dialog/dialog-footer.svelte +39 -45
  131. package/dist/components/dialog/dialog-footer.svelte.d.ts +2 -2
  132. package/dist/components/dialog/dialog-header.svelte +39 -45
  133. package/dist/components/dialog/dialog-header.svelte.d.ts +2 -2
  134. package/dist/components/dialog/dialog-root.svelte +110 -120
  135. package/dist/components/dialog/dialog-root.svelte.d.ts +2 -10
  136. package/dist/components/dialog/dialog-title.svelte +41 -47
  137. package/dist/components/dialog/dialog-title.svelte.d.ts +7 -7
  138. package/dist/components/dialog/index.d.ts +1 -0
  139. package/dist/components/dialog/index.js +1 -0
  140. package/dist/components/dialog/types.d.ts +67 -0
  141. package/dist/components/dialog/types.js +1 -0
  142. package/dist/components/divider/types.d.ts +10 -0
  143. package/dist/components/divider/types.js +1 -0
  144. package/dist/components/drawer/drawer-backdrop.svelte +38 -47
  145. package/dist/components/drawer/drawer-backdrop.svelte.d.ts +3 -26
  146. package/dist/components/drawer/drawer-body.svelte +42 -56
  147. package/dist/components/drawer/drawer-body.svelte.d.ts +3 -16
  148. package/dist/components/drawer/drawer-content.svelte +42 -55
  149. package/dist/components/drawer/drawer-content.svelte.d.ts +3 -14
  150. package/dist/components/drawer/drawer-description.svelte +44 -57
  151. package/dist/components/drawer/drawer-description.svelte.d.ts +3 -14
  152. package/dist/components/drawer/drawer-footer.svelte +41 -54
  153. package/dist/components/drawer/drawer-footer.svelte.d.ts +3 -14
  154. package/dist/components/drawer/drawer-header.svelte +43 -56
  155. package/dist/components/drawer/drawer-header.svelte.d.ts +3 -14
  156. package/dist/components/drawer/drawer-root.svelte +93 -113
  157. package/dist/components/drawer/drawer-root.svelte.d.ts +3 -31
  158. package/dist/components/drawer/drawer-title.svelte +44 -57
  159. package/dist/components/drawer/drawer-title.svelte.d.ts +3 -14
  160. package/dist/components/drawer/index.d.ts +1 -0
  161. package/dist/components/drawer/index.js +1 -0
  162. package/dist/components/drawer/types.d.ts +86 -0
  163. package/dist/components/drawer/types.js +1 -0
  164. package/dist/components/dropdown/dropdown-placeholder.svelte +1 -1
  165. package/dist/components/dropdown/dropdown-query.svelte +54 -53
  166. package/dist/components/dropdown/dropdown-query.svelte.d.ts +11 -10
  167. package/dist/components/dropdown/dropdown-root.svelte +59 -59
  168. package/dist/components/dropdown/dropdown-trigger.svelte +41 -52
  169. package/dist/components/dropdown/dropdown-trigger.svelte.d.ts +1 -8
  170. package/dist/components/dropdown/dropdown-value.svelte +60 -62
  171. package/dist/components/dropdown/index.d.ts +1 -0
  172. package/dist/components/dropdown/index.js +1 -0
  173. package/dist/components/dropdown/item/bond.svelte.d.ts +4 -0
  174. package/dist/components/dropdown/item/bond.svelte.js +9 -0
  175. package/dist/components/dropdown/item/dropdown-item.svelte +10 -6
  176. package/dist/components/dropdown/types.d.ts +37 -0
  177. package/dist/components/dropdown/types.js +1 -0
  178. package/dist/components/element/html-element.svelte.d.ts +2 -14
  179. package/dist/components/element/svg-element.svelte.d.ts +2 -14
  180. package/dist/components/element/types.d.ts +14 -7
  181. package/dist/components/form/field/bond.svelte.d.ts +8 -0
  182. package/dist/components/form/field/bond.svelte.js +13 -1
  183. package/dist/components/form/field/field-control.svelte +48 -58
  184. package/dist/components/form/field/field-control.svelte.d.ts +5 -19
  185. package/dist/components/form/field/field-label.svelte +24 -31
  186. package/dist/components/form/field/field-label.svelte.d.ts +1 -2
  187. package/dist/components/form/field/field-root.svelte +59 -88
  188. package/dist/components/form/field/field-root.svelte.d.ts +5 -20
  189. package/dist/components/form/form.stories.svelte +3 -3
  190. package/dist/components/form/index.d.ts +1 -0
  191. package/dist/components/form/index.js +1 -0
  192. package/dist/components/form/types.d.ts +76 -0
  193. package/dist/components/form/types.js +1 -0
  194. package/dist/components/icon/icon.svelte +44 -55
  195. package/dist/components/icon/icon.svelte.d.ts +4 -29
  196. package/dist/components/icon/types.d.ts +11 -7
  197. package/dist/components/input/atoms.d.ts +5 -1
  198. package/dist/components/input/atoms.js +5 -1
  199. package/dist/components/input/index.d.ts +1 -0
  200. package/dist/components/input/index.js +1 -0
  201. package/dist/components/input/{input-value.svelte → input-control.svelte} +14 -24
  202. package/dist/components/input/input-control.svelte.d.ts +26 -0
  203. package/dist/components/input/input-icon.svelte +1 -1
  204. package/dist/components/input/input-icon.svelte.d.ts +1 -1
  205. package/dist/components/input/input-placeholder.svelte +54 -56
  206. package/dist/components/input/input-placeholder.svelte.d.ts +2 -19
  207. package/dist/components/input/input-root.svelte +5 -12
  208. package/dist/components/input/input-root.svelte.d.ts +3 -20
  209. package/dist/components/input/input.stories.svelte +2 -2
  210. package/dist/components/input/types.d.ts +33 -0
  211. package/dist/components/input/types.js +1 -0
  212. package/dist/components/label/index.d.ts +1 -0
  213. package/dist/components/label/index.js +1 -0
  214. package/dist/components/label/label.svelte +25 -41
  215. package/dist/components/label/label.svelte.d.ts +3 -27
  216. package/dist/components/label/types.d.ts +11 -0
  217. package/dist/components/label/types.js +1 -0
  218. package/dist/components/layer/layer-inner.svelte.d.ts +2 -19
  219. package/dist/components/layer/layer-root.svelte.d.ts +2 -19
  220. package/dist/components/layer/types.d.ts +11 -0
  221. package/dist/components/layer/types.js +1 -0
  222. package/dist/components/link/types.d.ts +8 -0
  223. package/dist/components/link/types.js +1 -0
  224. package/dist/components/list/list-group.svelte +1 -1
  225. package/dist/components/list/list-item.svelte +1 -1
  226. package/dist/components/list/list-root.svelte +6 -1
  227. package/dist/components/list/list-title.svelte +1 -1
  228. package/dist/components/list/types.d.ts +8 -0
  229. package/dist/components/list/types.js +1 -0
  230. package/dist/components/menu/index.d.ts +1 -0
  231. package/dist/components/menu/index.js +1 -0
  232. package/dist/components/menu/menu-list.svelte +1 -1
  233. package/dist/components/menu/types.d.ts +15 -0
  234. package/dist/components/menu/types.js +1 -0
  235. package/dist/components/popover/bond.svelte.d.ts +2 -0
  236. package/dist/components/popover/bond.svelte.js +1 -1
  237. package/dist/components/popover/index.d.ts +1 -0
  238. package/dist/components/popover/index.js +1 -0
  239. package/dist/components/popover/popover-arrow.svelte +111 -117
  240. package/dist/components/popover/popover-arrow.svelte.d.ts +3 -20
  241. package/dist/components/popover/popover-content.svelte +139 -147
  242. package/dist/components/popover/popover-content.svelte.d.ts +3 -17
  243. package/dist/components/popover/popover-indicator.svelte +1 -1
  244. package/dist/components/popover/popover-root.svelte +4 -18
  245. package/dist/components/popover/popover-root.svelte.d.ts +1 -15
  246. package/dist/components/popover/popover-trigger.svelte +3 -12
  247. package/dist/components/popover/popover-trigger.svelte.d.ts +2 -8
  248. package/dist/components/popover/types.d.ts +61 -0
  249. package/dist/components/popover/types.js +1 -0
  250. package/dist/components/portal/active-portal.svelte +8 -2
  251. package/dist/components/portal/active-portal.svelte.d.ts +2 -2
  252. package/dist/components/portal/index.d.ts +1 -0
  253. package/dist/components/portal/index.js +1 -0
  254. package/dist/components/portal/portal-inner.svelte +1 -1
  255. package/dist/components/portal/portal-inner.svelte.d.ts +2 -19
  256. package/dist/components/portal/portal-root.svelte +83 -88
  257. package/dist/components/portal/portal-root.svelte.d.ts +2 -22
  258. package/dist/components/portal/teleport.svelte +50 -49
  259. package/dist/components/portal/teleport.svelte.d.ts +5 -23
  260. package/dist/components/portal/types.d.ts +39 -0
  261. package/dist/components/portal/types.js +1 -0
  262. package/dist/components/radio/radio-group.stories.svelte +4 -4
  263. package/dist/components/radio/radio.svelte +109 -109
  264. package/dist/components/radio/radio.svelte.d.ts +14 -36
  265. package/dist/components/root/root.css +24 -66
  266. package/dist/components/root/root.svelte +121 -121
  267. package/dist/components/root/types.d.ts +8 -0
  268. package/dist/components/root/types.js +1 -0
  269. package/dist/components/scrollable/index.d.ts +1 -0
  270. package/dist/components/scrollable/index.js +1 -0
  271. package/dist/components/scrollable/scrollable-container.svelte +82 -89
  272. package/dist/components/scrollable/scrollable-container.svelte.d.ts +2 -6
  273. package/dist/components/scrollable/scrollable-content.svelte +41 -51
  274. package/dist/components/scrollable/scrollable-content.svelte.d.ts +1 -6
  275. package/dist/components/scrollable/scrollable-root.svelte +100 -120
  276. package/dist/components/scrollable/scrollable-root.svelte.d.ts +3 -19
  277. package/dist/components/scrollable/scrollable-thumb.svelte +75 -86
  278. package/dist/components/scrollable/scrollable-thumb.svelte.d.ts +1 -7
  279. package/dist/components/scrollable/scrollable-track.svelte +59 -70
  280. package/dist/components/scrollable/scrollable-track.svelte.d.ts +1 -7
  281. package/dist/components/scrollable/types.d.ts +62 -0
  282. package/dist/components/scrollable/types.js +1 -0
  283. package/dist/components/sidebar/index.d.ts +1 -0
  284. package/dist/components/sidebar/index.js +1 -0
  285. package/dist/components/sidebar/sidebar-content.svelte +2 -16
  286. package/dist/components/sidebar/sidebar-content.svelte.d.ts +2 -9
  287. package/dist/components/sidebar/sidebar-root.svelte +4 -23
  288. package/dist/components/sidebar/sidebar-root.svelte.d.ts +2 -13
  289. package/dist/components/sidebar/types.d.ts +30 -0
  290. package/dist/components/sidebar/types.js +1 -0
  291. package/dist/components/stack/stack-item.svelte +5 -1
  292. package/dist/components/stack/stack-root.svelte +5 -1
  293. package/dist/components/stack/stack-root.svelte.d.ts +2 -19
  294. package/dist/components/stack/types.d.ts +12 -0
  295. package/dist/components/stack/types.js +1 -0
  296. package/dist/components/tabs/index.d.ts +1 -0
  297. package/dist/components/tabs/index.js +1 -0
  298. package/dist/components/tabs/tab/tab-body.svelte +52 -61
  299. package/dist/components/tabs/tab/tab-body.svelte.d.ts +2 -8
  300. package/dist/components/tabs/tab/tab-description.svelte +41 -50
  301. package/dist/components/tabs/tab/tab-description.svelte.d.ts +2 -8
  302. package/dist/components/tabs/tab/tab-header.svelte +71 -81
  303. package/dist/components/tabs/tab/tab-header.svelte.d.ts +2 -11
  304. package/dist/components/tabs/tab/tab-root.svelte +86 -81
  305. package/dist/components/tabs/tabs-body.svelte +1 -1
  306. package/dist/components/tabs/tabs-header.svelte +1 -1
  307. package/dist/components/tabs/tabs-root.svelte +1 -1
  308. package/dist/components/tabs/types.d.ts +55 -0
  309. package/dist/components/tabs/types.js +1 -0
  310. package/dist/components/textarea/index.d.ts +1 -0
  311. package/dist/components/textarea/index.js +1 -0
  312. package/dist/components/textarea/textarea-input.svelte +2 -1
  313. package/dist/components/textarea/types.d.ts +28 -0
  314. package/dist/components/textarea/types.js +1 -0
  315. package/dist/components/toast/index.d.ts +1 -0
  316. package/dist/components/toast/index.js +1 -0
  317. package/dist/components/toast/toast-description.svelte +38 -44
  318. package/dist/components/toast/toast-description.svelte.d.ts +8 -34
  319. package/dist/components/toast/toast-root.svelte +61 -74
  320. package/dist/components/toast/toast-root.svelte.d.ts +4 -43
  321. package/dist/components/toast/toast-title.svelte +35 -43
  322. package/dist/components/toast/toast-title.svelte.d.ts +2 -34
  323. package/dist/components/toast/types.d.ts +40 -0
  324. package/dist/components/toast/types.js +1 -0
  325. package/dist/components/tooltip/types.d.ts +13 -0
  326. package/dist/components/tooltip/types.js +1 -0
  327. package/dist/components/tree/index.d.ts +1 -0
  328. package/dist/components/tree/index.js +1 -0
  329. package/dist/components/tree/tree-body.svelte +39 -50
  330. package/dist/components/tree/tree-body.svelte.d.ts +2 -10
  331. package/dist/components/tree/tree-header.svelte +54 -66
  332. package/dist/components/tree/tree-header.svelte.d.ts +3 -29
  333. package/dist/components/tree/tree-indicator.svelte +40 -50
  334. package/dist/components/tree/tree-indicator.svelte.d.ts +3 -9
  335. package/dist/components/tree/tree-root.svelte +65 -80
  336. package/dist/components/tree/tree-root.svelte.d.ts +2 -12
  337. package/dist/components/tree/types.d.ts +59 -0
  338. package/dist/components/tree/types.js +1 -0
  339. package/dist/components/virtual/types.d.ts +23 -0
  340. package/dist/components/virtual/types.js +1 -0
  341. package/dist/components/virtual/virtual-root.svelte +239 -258
  342. package/dist/components/virtual/virtual-root.svelte.d.ts +1 -18
  343. package/dist/context/preset.svelte.d.ts +1 -1
  344. package/llm/composition.md +395 -395
  345. package/llm/crafting.md +838 -838
  346. package/llm/motion.md +970 -970
  347. package/llm/philosophy.md +23 -23
  348. package/llm/preset-variant-integration.md +516 -516
  349. package/llm/preset.md +383 -383
  350. package/llm/styling.md +216 -216
  351. package/llm/usage.md +46 -46
  352. package/llm/variants.md +712 -712
  353. package/package.json +437 -437
  354. package/dist/components/input/input-value.svelte.d.ts +0 -19
package/llm/variants.md CHANGED
@@ -1,712 +1,712 @@
1
- # Variant System
2
-
3
- ## Overview
4
-
5
- The variant system in @svelte-atoms/core provides a powerful way to define component styling variations. It's deeply integrated with the preset system, allowing both global theming and local customization.
6
-
7
- ## Problem Statement
8
-
9
- Currently, creating component variants (size, variant, appearance, etc.) requires:
10
-
11
- ```svelte
12
- <script>
13
- let { variant = 'primary', size = 'md' } = $props();
14
-
15
- const variantClasses = {
16
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
17
- secondary: 'bg-gray-500 text-white hover:bg-gray-600',
18
- danger: 'bg-red-500 text-white hover:bg-red-600'
19
- };
20
-
21
- const sizeClasses = {
22
- sm: 'px-2 py-1 text-sm',
23
- md: 'px-4 py-2 text-base',
24
- lg: 'px-6 py-3 text-lg'
25
- };
26
- </script>
27
-
28
- <HtmlAtom class={`${variantClasses[variant]} ${sizeClasses[size]}`} />
29
- ```
30
-
31
- **Pain points:**
32
-
33
- - Repeated boilerplate in every component
34
- - No access to component state (bond) for reactive variants
35
- - Can't return attributes, only classes
36
- - Not type-safe
37
-
38
- ## Integration with Preset System
39
-
40
- **Key Feature:** Variants are now integrated with the preset system, enabling global variant definitions that can be overridden locally.
41
-
42
- ### Preset Structure
43
-
44
- Presets support the full variant structure for comprehensive theming:
45
-
46
- ```typescript
47
- // Preset: Full variant support
48
- {
49
- class: 'base-classes',
50
- variants: {
51
- variant: { primary: '...', secondary: '...' },
52
- size: { sm: '...', md: '...', lg: '...' }
53
- },
54
- compounds: [
55
- { variant: 'primary', size: 'lg', class: 'shadow-lg' }
56
- ],
57
- defaults: {
58
- variant: 'primary',
59
- size: 'md'
60
- }
61
- }
62
-
63
- // Component: Same structure, overrides/extends preset
64
- {
65
- class: 'component-base',
66
- variants: { ... },
67
- compoundss: [...],
68
- defaults: { ... }
69
- }
70
- ```
71
-
72
- **Merge Behavior:**
73
-
74
- - `variants`: Deep merged (component extends preset)
75
- - `compounds`: Concatenated (preset first, then component compounds)
76
- - `defaults`: Deep merged (component overrides preset)
77
-
78
- ### Architecture
79
-
80
- ```
81
- Preset (Global Theme)
82
- ├─ class: ClassValue (base styling)
83
- ├─ variants: Record<string, Record<string, ClassValue>>
84
- │ ├─ variant: { primary: '...', secondary: '...' }
85
- │ └─ size: { sm: '...', md: '...', lg: '...' }
86
- ├─ compounds: Array<CompoundVariant> (conditional styling)
87
- ├─ defaults: Record<string, string> (default values)
88
- ├─ base: Component (component override)
89
- ├─ as: string (element type)
90
- └─ ...other props
91
-
92
- Component (Local)
93
- ├─ variants: VariantDefinition (extends/overrides preset)
94
- │ ├─ class: ClassValue (component-specific base)
95
- │ ├─ variants: { ... } (extends/overrides preset variants)
96
- │ ├─ compounds: [...] (appended to preset)
97
- │ └─ defaults: {...} (overrides preset defaults)
98
- └─ variant props (size, variant, etc.)
99
-
100
- Final Output = merge(preset, component)
101
- - variants: deep merged
102
- - compounds: concatenated (preset + component)
103
- - defaults: deep merged (component overrides)
104
- ```
105
-
106
- ### Hierarchy
107
-
108
- The system merges variants in this order (later overrides earlier):
109
-
110
- 1. **Preset variants** - Global theme variants
111
- 2. **Component variants** - Local component-specific variants
112
- 3. **Props** - Runtime variant prop values
113
-
114
- ### Example: Global + Local Variants
115
-
116
- ```typescript
117
- // +layout.svelte - Global theme
118
- import { setPreset } from '@svelte-atoms/core/context';
119
-
120
- setPreset({
121
- button: () => ({
122
- class: 'font-medium transition-colors rounded-md focus:outline-none focus:ring-2',
123
- variants: {
124
- variant: {
125
- primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
126
- secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/90',
127
- destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90'
128
- },
129
- size: {
130
- sm: 'h-8 px-3 text-xs',
131
- md: 'h-10 px-4 text-sm',
132
- lg: 'h-12 px-6 text-base'
133
- }
134
- },
135
- compounds: [
136
- {
137
- variant: 'primary',
138
- size: 'lg',
139
- class: 'shadow-lg font-semibold'
140
- }
141
- ],
142
- defaults: {
143
- variant: 'primary',
144
- size: 'md'
145
- }
146
- })
147
- });
148
- ```
149
-
150
- ```svelte
151
- <!-- Button.svelte - Local override -->
152
- <script>
153
- import { HtmlAtom } from '@svelte-atoms/core';
154
- import { defineVariants } from '@svelte-atoms/core/utils';
155
-
156
- // Extend preset variants with additional local variants
157
- const localVariants = defineVariants({
158
- variants: {
159
- variant: {
160
- // Add new variant not in preset
161
- ghost: 'hover:bg-accent hover:text-accent-foreground'
162
- },
163
- // Add new variant key
164
- loading: {
165
- true: 'opacity-50 cursor-wait',
166
- false: ''
167
- }
168
- }
169
- });
170
-
171
- let {
172
- variant = 'primary',
173
- size = 'md',
174
- loading = false,
175
- ...props
176
- } = $props();
177
- </script>
178
-
179
- <HtmlAtom
180
- preset="button" <!-- Uses global preset -->
181
- variants={localVariants} <!-- Merges with preset -->
182
- {variant}
183
- {size}
184
- {loading}
185
- {...props}
186
- >
187
- {@render children?.()}
188
- </HtmlAtom>
189
- ```
190
-
191
- **Result:** The button will have:
192
-
193
- - Base classes from preset
194
- - Preset variant classes (primary, sm/md/lg)
195
- - Local variant classes (ghost, loading)
196
- - Merged intelligently - local overrides preset
197
-
198
- ```typescript
199
- import { defineVariants } from '@svelte-atoms/core/utils';
200
-
201
- const buttonVariants = defineVariants({
202
- class: 'rounded-md font-medium transition-colors',
203
- variants: {
204
- variant: {
205
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
206
- secondary: 'bg-gray-500 text-white hover:bg-gray-600',
207
- danger: 'bg-red-500 text-white hover:bg-red-600'
208
- },
209
- size: {
210
- sm: 'px-2 py-1 text-sm',
211
- md: 'px-4 py-2 text-base',
212
- lg: 'px-6 py-3 text-lg'
213
- }
214
- },
215
- compounds: [
216
- {
217
- variant: 'primary',
218
- size: 'lg',
219
- class: 'shadow-lg' // Applied when both conditions match
220
- }
221
- ],
222
- defaults: {
223
- variant: 'primary',
224
- size: 'md'
225
- }
226
- });
227
- ```
228
-
229
- ```svelte
230
- <script>
231
- import { buttonVariants } from './variants';
232
-
233
- let { variant, size, ...props } = $props();
234
-
235
- const variantProps = buttonVariants({ variant, size });
236
- </script>
237
-
238
- <HtmlAtom {...variantProps} {...props}>
239
- {@render children?.()}
240
- </HtmlAtom>
241
- ```
242
-
243
- ## Key Features
244
-
245
- ### 1. Access to Component State (Bond)
246
-
247
- Variant values can be functions that receive the component's bond for reactive styling:
248
-
249
- ```typescript
250
- const accordionVariants = defineVariants({
251
- class: 'border rounded-md transition-all',
252
- variants: {
253
- state: {
254
- open: (bond) => ({
255
- class: bond?.state?.isOpen ? 'bg-blue-50 border-blue-200' : 'bg-white',
256
- 'aria-expanded': bond?.state?.isOpen,
257
- 'data-state': bond?.state?.isOpen ? 'open' : 'closed'
258
- }),
259
- disabled: (bond) => ({
260
- class: bond?.state?.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',
261
- 'aria-disabled': bond?.state?.disabled
262
- })
263
- }
264
- }
265
- });
266
-
267
- // Usage:
268
- const bond = AccordionBond.get();
269
- const variantProps = accordionVariants(bond, { state: 'open' });
270
- ```
271
-
272
- ### 2. Return Both Classes and Attributes
273
-
274
- Variants can return not just classes, but any HTML attributes:
275
-
276
- ```typescript
277
- const buttonVariants = defineVariants({
278
- variants: {
279
- variant: {
280
- primary: {
281
- class: 'bg-blue-500 text-white',
282
- 'aria-label': 'Primary action',
283
- 'data-variant': 'primary'
284
- },
285
- danger: (bond) => ({
286
- class: bond?.state?.disabled ? 'bg-red-300' : 'bg-red-500',
287
- 'aria-disabled': bond?.state?.disabled,
288
- role: 'button'
289
- })
290
- }
291
- }
292
- });
293
-
294
- // Returns: { class: '...', 'aria-label': '...', 'data-variant': '...', ... }
295
- ```
296
-
297
- ### 3. Compound Variants
298
-
299
- Apply additional styling when multiple conditions match:
300
-
301
- ```typescript
302
- const alertVariants = defineVariants({
303
- class: 'rounded-lg p-4 border',
304
- variants: {
305
- variant: {
306
- error: 'bg-red-50 border-red-200 text-red-900'
307
- },
308
- size: {
309
- lg: 'text-lg'
310
- }
311
- },
312
- compounds: [
313
- {
314
- variant: 'error',
315
- size: 'lg',
316
- class: 'font-bold', // Only applied when both variant=error AND size=lg
317
- role: 'alert'
318
- }
319
- ]
320
- });
321
- ```
322
-
323
- ### 4. Type Safety
324
-
325
- Full TypeScript support with automatic type inference:
326
-
327
- ```typescript
328
- type ButtonVariants = VariantPropsType<typeof buttonVariants>;
329
- // Inferred type: { variant?: 'primary' | 'secondary' | 'danger'; size?: 'sm' | 'md' | 'lg' }
330
- ```
331
-
332
- ### 5. Default Variants
333
-
334
- Specify default values that are used when no variant is provided:
335
-
336
- ```typescript
337
- const buttonVariants = defineVariants({
338
- class: 'rounded-md',
339
- variants: {
340
- variant: {
341
- primary: 'bg-blue-500',
342
- secondary: 'bg-gray-500'
343
- },
344
- size: {
345
- sm: 'text-sm',
346
- md: 'text-base',
347
- lg: 'text-lg'
348
- }
349
- },
350
- defaults: {
351
- variant: 'primary', // Used if variant prop is undefined
352
- size: 'md' // Used if size prop is undefined
353
- }
354
- });
355
-
356
- // Call without props - uses defaults
357
- buttonVariants(null); // Returns variant='primary', size='md'
358
- ```
359
-
360
- ## Complete Examples
361
-
362
- ### Example 1: Preset-based Button (Recommended)
363
-
364
- ```typescript
365
- // Theme.svelte - Define global button variants
366
- import { setPreset } from '@svelte-atoms/core/context';
367
-
368
- setPreset({
369
- button: () => ({
370
- class:
371
- 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2',
372
- variants: {
373
- variant: {
374
- default: 'bg-primary text-primary-foreground hover:bg-primary/90',
375
- destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
376
- outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
377
- secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
378
- ghost: 'hover:bg-accent hover:text-accent-foreground',
379
- link: 'text-primary underline-offset-4 hover:underline'
380
- },
381
- size: {
382
- default: 'h-10 px-4 py-2',
383
- sm: 'h-9 rounded-md px-3',
384
- lg: 'h-11 rounded-md px-8',
385
- icon: 'h-10 w-10'
386
- }
387
- },
388
- compounds: [
389
- {
390
- variant: 'default',
391
- size: 'lg',
392
- class: 'text-base font-semibold'
393
- }
394
- ],
395
- defaults: {
396
- variant: 'default',
397
- size: 'default'
398
- }
399
- })
400
- });
401
- ```
402
-
403
- ```svelte
404
- <!-- Button.svelte - Use preset variants -->
405
- <script lang="ts">
406
- import { HtmlAtom } from '@svelte-atoms/core';
407
-
408
- type ButtonProps = {
409
- variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
410
- size?: 'default' | 'sm' | 'lg' | 'icon';
411
- disabled?: boolean;
412
- };
413
-
414
- let { variant, size, disabled = false, class: klass = '', ...props }: ButtonProps = $props();
415
- </script>
416
-
417
- <HtmlAtom preset="button" as="button" {variant} {size} {disabled} class={klass} {...props}>
418
- {@render children?.()}
419
- </HtmlAtom>
420
- ```
421
-
422
- ### Example 2: Local Variants Only
423
-
424
- ````svelte
425
- ### Example 3: Extending Preset with Local Variants
426
-
427
- Combine global preset variants with component-specific variants:
428
-
429
- ```svelte
430
- <!-- special-button.svelte -->
431
- <script>
432
- import { HtmlAtom } from '@svelte-atoms/core';
433
- import { defineVariants } from '@svelte-atoms/core/utils';
434
-
435
- // Local variants that extend/override preset
436
- const localVariants = defineVariants({
437
- variants: {
438
- variant: {
439
- // Add new variants not in preset
440
- gradient: 'bg-gradient-to-r from-purple-500 to-pink-500 text-white',
441
- neon: 'bg-black text-neon-green border-2 border-neon-green'
442
- },
443
- // Add completely new variant key
444
- animated: {
445
- true: 'animate-pulse',
446
- false: ''
447
- }
448
- }
449
- });
450
-
451
- let {
452
- variant,
453
- size,
454
- animated = false,
455
- ...props
456
- } = $props();
457
- </script>
458
-
459
- <HtmlAtom
460
- preset="button" <!-- Gets base variants -->
461
- variants={localVariants} <!-- Merges/extends -->
462
- {variant}
463
- {size}
464
- {animated}
465
- {...props}
466
- >
467
- {@render children?.()}
468
- </HtmlAtom>
469
- ````
470
-
471
- ### Example 4: Reactive Variants with Bond State
472
-
473
- <script>
474
- import { HtmlAtom } from '@svelte-atoms/core';
475
- import { defineVariants } from '@svelte-atoms/core/utils';
476
-
477
- const alertVariants = defineVariants({
478
- class: 'rounded-lg p-4 border',
479
- variants: {
480
- variant: {
481
- info: 'bg-blue-50 border-blue-200 text-blue-900',
482
- success: 'bg-green-50 border-green-200 text-green-900',
483
- warning: 'bg-yellow-50 border-yellow-200 text-yellow-900',
484
- error: 'bg-red-50 border-red-200 text-red-900'
485
- },
486
- size: {
487
- sm: 'text-sm p-2',
488
- md: 'text-base p-4',
489
- lg: 'text-lg p-6'
490
- }
491
- },
492
- compounds: [
493
- {
494
- variant: 'error',
495
- size: 'lg',
496
- class: 'font-bold',
497
- role: 'alert',
498
- 'aria-live': 'assertive'
499
- }
500
- ],
501
- defaults: {
502
- variant: 'info',
503
- size: 'md'
504
- }
505
- });
506
-
507
- let { variant, size, ...props } = $props();
508
-
509
- const bond = null; // or get from context if needed
510
- const variantProps = alertVariants(bond, { variant, size });
511
- </script>
512
-
513
- <HtmlAtom {...variantProps} {...props}>
514
- {@render children?.()}
515
- </HtmlAtom>
516
-
517
- ````
518
-
519
- ### Example 3: Accordion with Reactive Bond State
520
-
521
- ```svelte
522
- <!-- accordion-item.svelte -->
523
- <script>
524
- import { HtmlAtom } from '@svelte-atoms/core';
525
- import { defineVariants } from '@svelte-atoms/core/utils';
526
- import { AccordionBond } from './bond.svelte';
527
-
528
- const accordionVariants = defineVariants({
529
- class: 'border rounded-md transition-all duration-200',
530
- variants: {
531
- state: {
532
- // Reactive: changes when bond.state.isOpen changes
533
- open: (bond) => ({
534
- class: bond?.state?.isOpen
535
- ? 'bg-blue-50 border-blue-200'
536
- : 'bg-white border-gray-200',
537
- 'aria-expanded': bond?.state?.isOpen,
538
- 'data-state': bond?.state?.isOpen ? 'open' : 'closed'
539
- }),
540
- disabled: (bond) => ({
541
- class: bond?.state?.disabled
542
- ? 'opacity-50 cursor-not-allowed'
543
- : 'cursor-pointer',
544
- 'aria-disabled': bond?.state?.disabled
545
- })
546
- }
547
- }
548
- });
549
-
550
- const bond = AccordionBond.get();
551
-
552
- // Automatically reactive - updates when bond state changes
553
- const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
554
- </script>
555
-
556
- <HtmlAtom {...variantProps}>
557
- {@render children?.({ accordion: bond })}
558
- </HtmlAtom>
559
- ````
560
-
561
- ## Migration Guide
562
-
563
- ### Before: Manual Variant Management
564
-
565
- ```svelte
566
- <script>
567
- let { variant = 'primary', size = 'md' } = $props();
568
-
569
- const variantClasses = {
570
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
571
- secondary: 'bg-gray-500 text-white hover:bg-gray-600',
572
- danger: 'bg-red-500 text-white hover:bg-red-600'
573
- };
574
-
575
- const sizeClasses = {
576
- sm: 'px-2 py-1 text-sm',
577
- md: 'px-4 py-2 text-base',
578
- lg: 'px-6 py-3 text-lg'
579
- };
580
-
581
- const classes = `rounded-md ${variantClasses[variant]} ${sizeClasses[size]}`;
582
- </script>
583
-
584
- <button class={classes}> Click me </button>
585
- ```
586
-
587
- ### After: defineVariants
588
-
589
- ```svelte
590
- <script>
591
- import { HtmlAtom } from '@svelte-atoms/core';
592
- import { defineVariants } from '@svelte-atoms/core/utils';
593
-
594
- const buttonVariants = defineVariants({
595
- class: 'rounded-md',
596
- variants: {
597
- variant: {
598
- primary: 'bg-blue-500 text-white hover:bg-blue-600',
599
- secondary: 'bg-gray-500 text-white hover:bg-gray-600',
600
- danger: 'bg-red-500 text-white hover:bg-red-600'
601
- },
602
- size: {
603
- sm: 'px-2 py-1 text-sm',
604
- md: 'px-4 py-2 text-base',
605
- lg: 'px-6 py-3 text-lg'
606
- }
607
- },
608
- defaults: {
609
- variant: 'primary',
610
- size: 'md'
611
- }
612
- });
613
-
614
- let { variant, size, ...props } = $props();
615
-
616
- const bond = null; // or get from context if needed
617
- const variantProps = buttonVariants(bond, { variant, size });
618
- </script>
619
-
620
- <HtmlAtom as="button" {...variantProps} {...props}>Click me</HtmlAtom>
621
- ```
622
-
623
- ### Benefits After Migration
624
-
625
- ✅ **Less boilerplate** - Define once, use everywhere
626
- ✅ **Type safety** - Automatic type inference
627
- ✅ **Compound variants** - Complex styling combinations
628
- ✅ **Default values** - No need for fallback logic
629
- ✅ **Bond integration** - Access component state for reactive variants
630
- ✅ **Return attributes** - Not just classes, any HTML attributes
631
-
632
- ## Best Practices
633
-
634
- ### 1. Organize Variants in Separate Files
635
-
636
- ```typescript
637
- // variants.ts
638
- import { defineVariants } from '@svelte-atoms/core/utils';
639
-
640
- export const buttonVariants = defineVariants({
641
- class: 'rounded-md font-medium transition-colors',
642
- variants: {
643
- /* ... */
644
- },
645
- defaults: {
646
- /* ... */
647
- }
648
- });
649
-
650
- export const cardVariants = defineVariants({
651
- class: 'rounded-lg border',
652
- variants: {
653
- /* ... */
654
- },
655
- defaults: {
656
- /* ... */
657
- }
658
- });
659
- ```
660
-
661
- ### 2. Use $derived for Reactive Variants
662
-
663
- When using bond state, wrap the variant call in `$derived`:
664
-
665
- ```svelte
666
- <script>
667
- const bond = AccordionBond.get();
668
-
669
- // Reactive - updates when bond state changes
670
- const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
671
- </script>
672
- ```
673
-
674
- ### 3. Extend with Additional Classes
675
-
676
- Merge variant classes with custom classes:
677
-
678
- ```svelte
679
- <script>
680
- const bond = null; // or get from context if needed
681
- const variantProps = buttonVariants(bond, { variant, size });
682
- </script>
683
-
684
- <HtmlAtom class={[variantProps.class, 'custom-class']} {...variantProps} />
685
- ```
686
-
687
- ### 4. Type Props from Variants
688
-
689
- Extract variant types for component props:
690
-
691
- ```typescript
692
- import { VariantPropsType } from '@svelte-atoms/core/utils';
693
- import { buttonVariants } from './variants';
694
-
695
- type ButtonProps = VariantPropsType<typeof buttonVariants> & {
696
- disabled?: boolean;
697
- // other props...
698
- };
699
- ```
700
-
701
- ## Summary
702
-
703
- `defineVariants()` provides:
704
-
705
- ✅ **Single function** - One API for all variant needs
706
- ✅ **Type-safe** - Automatic TypeScript inference
707
- ✅ **Reactive** - Access bond state for dynamic styling
708
- ✅ **Powerful** - Base classes, compound variants, defaults
709
- ✅ **Flexible** - Return both classes and attributes
710
- ✅ **Clean** - No manual object merging or conditionals
711
-
712
- Inspired by Class Variance Authority but integrated with @svelte-atoms/core's bond system.
1
+ # Variant System
2
+
3
+ ## Overview
4
+
5
+ The variant system in @svelte-atoms/core provides a powerful way to define component styling variations. It's deeply integrated with the preset system, allowing both global theming and local customization.
6
+
7
+ ## Problem Statement
8
+
9
+ Currently, creating component variants (size, variant, appearance, etc.) requires:
10
+
11
+ ```svelte
12
+ <script>
13
+ let { variant = 'primary', size = 'md' } = $props();
14
+
15
+ const variantClasses = {
16
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
17
+ secondary: 'bg-gray-500 text-white hover:bg-gray-600',
18
+ danger: 'bg-red-500 text-white hover:bg-red-600'
19
+ };
20
+
21
+ const sizeClasses = {
22
+ sm: 'px-2 py-1 text-sm',
23
+ md: 'px-4 py-2 text-base',
24
+ lg: 'px-6 py-3 text-lg'
25
+ };
26
+ </script>
27
+
28
+ <HtmlAtom class={`${variantClasses[variant]} ${sizeClasses[size]}`} />
29
+ ```
30
+
31
+ **Pain points:**
32
+
33
+ - Repeated boilerplate in every component
34
+ - No access to component state (bond) for reactive variants
35
+ - Can't return attributes, only classes
36
+ - Not type-safe
37
+
38
+ ## Integration with Preset System
39
+
40
+ **Key Feature:** Variants are now integrated with the preset system, enabling global variant definitions that can be overridden locally.
41
+
42
+ ### Preset Structure
43
+
44
+ Presets support the full variant structure for comprehensive theming:
45
+
46
+ ```typescript
47
+ // Preset: Full variant support
48
+ {
49
+ class: 'base-classes',
50
+ variants: {
51
+ variant: { primary: '...', secondary: '...' },
52
+ size: { sm: '...', md: '...', lg: '...' }
53
+ },
54
+ compounds: [
55
+ { variant: 'primary', size: 'lg', class: 'shadow-lg' }
56
+ ],
57
+ defaults: {
58
+ variant: 'primary',
59
+ size: 'md'
60
+ }
61
+ }
62
+
63
+ // Component: Same structure, overrides/extends preset
64
+ {
65
+ class: 'component-base',
66
+ variants: { ... },
67
+ compoundss: [...],
68
+ defaults: { ... }
69
+ }
70
+ ```
71
+
72
+ **Merge Behavior:**
73
+
74
+ - `variants`: Deep merged (component extends preset)
75
+ - `compounds`: Concatenated (preset first, then component compounds)
76
+ - `defaults`: Deep merged (component overrides preset)
77
+
78
+ ### Architecture
79
+
80
+ ```
81
+ Preset (Global Theme)
82
+ ├─ class: ClassValue (base styling)
83
+ ├─ variants: Record<string, Record<string, ClassValue>>
84
+ │ ├─ variant: { primary: '...', secondary: '...' }
85
+ │ └─ size: { sm: '...', md: '...', lg: '...' }
86
+ ├─ compounds: Array<CompoundVariant> (conditional styling)
87
+ ├─ defaults: Record<string, string> (default values)
88
+ ├─ base: Component (component override)
89
+ ├─ as: string (element type)
90
+ └─ ...other props
91
+
92
+ Component (Local)
93
+ ├─ variants: VariantDefinition (extends/overrides preset)
94
+ │ ├─ class: ClassValue (component-specific base)
95
+ │ ├─ variants: { ... } (extends/overrides preset variants)
96
+ │ ├─ compounds: [...] (appended to preset)
97
+ │ └─ defaults: {...} (overrides preset defaults)
98
+ └─ variant props (size, variant, etc.)
99
+
100
+ Final Output = merge(preset, component)
101
+ - variants: deep merged
102
+ - compounds: concatenated (preset + component)
103
+ - defaults: deep merged (component overrides)
104
+ ```
105
+
106
+ ### Hierarchy
107
+
108
+ The system merges variants in this order (later overrides earlier):
109
+
110
+ 1. **Preset variants** - Global theme variants
111
+ 2. **Component variants** - Local component-specific variants
112
+ 3. **Props** - Runtime variant prop values
113
+
114
+ ### Example: Global + Local Variants
115
+
116
+ ```typescript
117
+ // +layout.svelte - Global theme
118
+ import { setPreset } from '@svelte-atoms/core/context';
119
+
120
+ setPreset({
121
+ button: () => ({
122
+ class: 'font-medium transition-colors rounded-md focus:outline-none focus:ring-2',
123
+ variants: {
124
+ variant: {
125
+ primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
126
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/90',
127
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90'
128
+ },
129
+ size: {
130
+ sm: 'h-8 px-3 text-xs',
131
+ md: 'h-10 px-4 text-sm',
132
+ lg: 'h-12 px-6 text-base'
133
+ }
134
+ },
135
+ compounds: [
136
+ {
137
+ variant: 'primary',
138
+ size: 'lg',
139
+ class: 'shadow-lg font-semibold'
140
+ }
141
+ ],
142
+ defaults: {
143
+ variant: 'primary',
144
+ size: 'md'
145
+ }
146
+ })
147
+ });
148
+ ```
149
+
150
+ ```svelte
151
+ <!-- Button.svelte - Local override -->
152
+ <script>
153
+ import { HtmlAtom } from '@svelte-atoms/core';
154
+ import { defineVariants } from '@svelte-atoms/core/utils';
155
+
156
+ // Extend preset variants with additional local variants
157
+ const localVariants = defineVariants({
158
+ variants: {
159
+ variant: {
160
+ // Add new variant not in preset
161
+ ghost: 'hover:bg-accent hover:text-accent-foreground'
162
+ },
163
+ // Add new variant key
164
+ loading: {
165
+ true: 'opacity-50 cursor-wait',
166
+ false: ''
167
+ }
168
+ }
169
+ });
170
+
171
+ let {
172
+ variant = 'primary',
173
+ size = 'md',
174
+ loading = false,
175
+ ...props
176
+ } = $props();
177
+ </script>
178
+
179
+ <HtmlAtom
180
+ preset="button" <!-- Uses global preset -->
181
+ variants={localVariants} <!-- Merges with preset -->
182
+ {variant}
183
+ {size}
184
+ {loading}
185
+ {...props}
186
+ >
187
+ {@render children?.()}
188
+ </HtmlAtom>
189
+ ```
190
+
191
+ **Result:** The button will have:
192
+
193
+ - Base classes from preset
194
+ - Preset variant classes (primary, sm/md/lg)
195
+ - Local variant classes (ghost, loading)
196
+ - Merged intelligently - local overrides preset
197
+
198
+ ```typescript
199
+ import { defineVariants } from '@svelte-atoms/core/utils';
200
+
201
+ const buttonVariants = defineVariants({
202
+ class: 'rounded-md font-medium transition-colors',
203
+ variants: {
204
+ variant: {
205
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
206
+ secondary: 'bg-gray-500 text-white hover:bg-gray-600',
207
+ danger: 'bg-red-500 text-white hover:bg-red-600'
208
+ },
209
+ size: {
210
+ sm: 'px-2 py-1 text-sm',
211
+ md: 'px-4 py-2 text-base',
212
+ lg: 'px-6 py-3 text-lg'
213
+ }
214
+ },
215
+ compounds: [
216
+ {
217
+ variant: 'primary',
218
+ size: 'lg',
219
+ class: 'shadow-lg' // Applied when both conditions match
220
+ }
221
+ ],
222
+ defaults: {
223
+ variant: 'primary',
224
+ size: 'md'
225
+ }
226
+ });
227
+ ```
228
+
229
+ ```svelte
230
+ <script>
231
+ import { buttonVariants } from './variants';
232
+
233
+ let { variant, size, ...props } = $props();
234
+
235
+ const variantProps = buttonVariants({ variant, size });
236
+ </script>
237
+
238
+ <HtmlAtom {...variantProps} {...props}>
239
+ {@render children?.()}
240
+ </HtmlAtom>
241
+ ```
242
+
243
+ ## Key Features
244
+
245
+ ### 1. Access to Component State (Bond)
246
+
247
+ Variant values can be functions that receive the component's bond for reactive styling:
248
+
249
+ ```typescript
250
+ const accordionVariants = defineVariants({
251
+ class: 'border rounded-md transition-all',
252
+ variants: {
253
+ state: {
254
+ open: (bond) => ({
255
+ class: bond?.state?.isOpen ? 'bg-blue-50 border-blue-200' : 'bg-white',
256
+ 'aria-expanded': bond?.state?.isOpen,
257
+ 'data-state': bond?.state?.isOpen ? 'open' : 'closed'
258
+ }),
259
+ disabled: (bond) => ({
260
+ class: bond?.state?.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',
261
+ 'aria-disabled': bond?.state?.disabled
262
+ })
263
+ }
264
+ }
265
+ });
266
+
267
+ // Usage:
268
+ const bond = AccordionBond.get();
269
+ const variantProps = accordionVariants(bond, { state: 'open' });
270
+ ```
271
+
272
+ ### 2. Return Both Classes and Attributes
273
+
274
+ Variants can return not just classes, but any HTML attributes:
275
+
276
+ ```typescript
277
+ const buttonVariants = defineVariants({
278
+ variants: {
279
+ variant: {
280
+ primary: {
281
+ class: 'bg-blue-500 text-white',
282
+ 'aria-label': 'Primary action',
283
+ 'data-variant': 'primary'
284
+ },
285
+ danger: (bond) => ({
286
+ class: bond?.state?.disabled ? 'bg-red-300' : 'bg-red-500',
287
+ 'aria-disabled': bond?.state?.disabled,
288
+ role: 'button'
289
+ })
290
+ }
291
+ }
292
+ });
293
+
294
+ // Returns: { class: '...', 'aria-label': '...', 'data-variant': '...', ... }
295
+ ```
296
+
297
+ ### 3. Compound Variants
298
+
299
+ Apply additional styling when multiple conditions match:
300
+
301
+ ```typescript
302
+ const alertVariants = defineVariants({
303
+ class: 'rounded-lg p-4 border',
304
+ variants: {
305
+ variant: {
306
+ error: 'bg-red-50 border-red-200 text-red-900'
307
+ },
308
+ size: {
309
+ lg: 'text-lg'
310
+ }
311
+ },
312
+ compounds: [
313
+ {
314
+ variant: 'error',
315
+ size: 'lg',
316
+ class: 'font-bold', // Only applied when both variant=error AND size=lg
317
+ role: 'alert'
318
+ }
319
+ ]
320
+ });
321
+ ```
322
+
323
+ ### 4. Type Safety
324
+
325
+ Full TypeScript support with automatic type inference:
326
+
327
+ ```typescript
328
+ type ButtonVariants = VariantPropsType<typeof buttonVariants>;
329
+ // Inferred type: { variant?: 'primary' | 'secondary' | 'danger'; size?: 'sm' | 'md' | 'lg' }
330
+ ```
331
+
332
+ ### 5. Default Variants
333
+
334
+ Specify default values that are used when no variant is provided:
335
+
336
+ ```typescript
337
+ const buttonVariants = defineVariants({
338
+ class: 'rounded-md',
339
+ variants: {
340
+ variant: {
341
+ primary: 'bg-blue-500',
342
+ secondary: 'bg-gray-500'
343
+ },
344
+ size: {
345
+ sm: 'text-sm',
346
+ md: 'text-base',
347
+ lg: 'text-lg'
348
+ }
349
+ },
350
+ defaults: {
351
+ variant: 'primary', // Used if variant prop is undefined
352
+ size: 'md' // Used if size prop is undefined
353
+ }
354
+ });
355
+
356
+ // Call without props - uses defaults
357
+ buttonVariants(null); // Returns variant='primary', size='md'
358
+ ```
359
+
360
+ ## Complete Examples
361
+
362
+ ### Example 1: Preset-based Button (Recommended)
363
+
364
+ ```typescript
365
+ // Theme.svelte - Define global button variants
366
+ import { setPreset } from '@svelte-atoms/core/context';
367
+
368
+ setPreset({
369
+ button: () => ({
370
+ class:
371
+ 'inline-flex items-center justify-center font-medium rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2',
372
+ variants: {
373
+ variant: {
374
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
375
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
376
+ outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
377
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
378
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
379
+ link: 'text-primary underline-offset-4 hover:underline'
380
+ },
381
+ size: {
382
+ default: 'h-10 px-4 py-2',
383
+ sm: 'h-9 rounded-md px-3',
384
+ lg: 'h-11 rounded-md px-8',
385
+ icon: 'h-10 w-10'
386
+ }
387
+ },
388
+ compounds: [
389
+ {
390
+ variant: 'default',
391
+ size: 'lg',
392
+ class: 'text-base font-semibold'
393
+ }
394
+ ],
395
+ defaults: {
396
+ variant: 'default',
397
+ size: 'default'
398
+ }
399
+ })
400
+ });
401
+ ```
402
+
403
+ ```svelte
404
+ <!-- Button.svelte - Use preset variants -->
405
+ <script lang="ts">
406
+ import { HtmlAtom } from '@svelte-atoms/core';
407
+
408
+ type ButtonProps = {
409
+ variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
410
+ size?: 'default' | 'sm' | 'lg' | 'icon';
411
+ disabled?: boolean;
412
+ };
413
+
414
+ let { variant, size, disabled = false, class: klass = '', ...props }: ButtonProps = $props();
415
+ </script>
416
+
417
+ <HtmlAtom preset="button" as="button" {variant} {size} {disabled} class={klass} {...props}>
418
+ {@render children?.()}
419
+ </HtmlAtom>
420
+ ```
421
+
422
+ ### Example 2: Local Variants Only
423
+
424
+ ````svelte
425
+ ### Example 3: Extending Preset with Local Variants
426
+
427
+ Combine global preset variants with component-specific variants:
428
+
429
+ ```svelte
430
+ <!-- special-button.svelte -->
431
+ <script>
432
+ import { HtmlAtom } from '@svelte-atoms/core';
433
+ import { defineVariants } from '@svelte-atoms/core/utils';
434
+
435
+ // Local variants that extend/override preset
436
+ const localVariants = defineVariants({
437
+ variants: {
438
+ variant: {
439
+ // Add new variants not in preset
440
+ gradient: 'bg-gradient-to-r from-purple-500 to-pink-500 text-white',
441
+ neon: 'bg-black text-neon-green border-2 border-neon-green'
442
+ },
443
+ // Add completely new variant key
444
+ animated: {
445
+ true: 'animate-pulse',
446
+ false: ''
447
+ }
448
+ }
449
+ });
450
+
451
+ let {
452
+ variant,
453
+ size,
454
+ animated = false,
455
+ ...props
456
+ } = $props();
457
+ </script>
458
+
459
+ <HtmlAtom
460
+ preset="button" <!-- Gets base variants -->
461
+ variants={localVariants} <!-- Merges/extends -->
462
+ {variant}
463
+ {size}
464
+ {animated}
465
+ {...props}
466
+ >
467
+ {@render children?.()}
468
+ </HtmlAtom>
469
+ ````
470
+
471
+ ### Example 4: Reactive Variants with Bond State
472
+
473
+ <script>
474
+ import { HtmlAtom } from '@svelte-atoms/core';
475
+ import { defineVariants } from '@svelte-atoms/core/utils';
476
+
477
+ const alertVariants = defineVariants({
478
+ class: 'rounded-lg p-4 border',
479
+ variants: {
480
+ variant: {
481
+ info: 'bg-blue-50 border-blue-200 text-blue-900',
482
+ success: 'bg-green-50 border-green-200 text-green-900',
483
+ warning: 'bg-yellow-50 border-yellow-200 text-yellow-900',
484
+ error: 'bg-red-50 border-red-200 text-red-900'
485
+ },
486
+ size: {
487
+ sm: 'text-sm p-2',
488
+ md: 'text-base p-4',
489
+ lg: 'text-lg p-6'
490
+ }
491
+ },
492
+ compounds: [
493
+ {
494
+ variant: 'error',
495
+ size: 'lg',
496
+ class: 'font-bold',
497
+ role: 'alert',
498
+ 'aria-live': 'assertive'
499
+ }
500
+ ],
501
+ defaults: {
502
+ variant: 'info',
503
+ size: 'md'
504
+ }
505
+ });
506
+
507
+ let { variant, size, ...props } = $props();
508
+
509
+ const bond = null; // or get from context if needed
510
+ const variantProps = alertVariants(bond, { variant, size });
511
+ </script>
512
+
513
+ <HtmlAtom {...variantProps} {...props}>
514
+ {@render children?.()}
515
+ </HtmlAtom>
516
+
517
+ ````
518
+
519
+ ### Example 3: Accordion with Reactive Bond State
520
+
521
+ ```svelte
522
+ <!-- accordion-item.svelte -->
523
+ <script>
524
+ import { HtmlAtom } from '@svelte-atoms/core';
525
+ import { defineVariants } from '@svelte-atoms/core/utils';
526
+ import { AccordionBond } from './bond.svelte';
527
+
528
+ const accordionVariants = defineVariants({
529
+ class: 'border rounded-md transition-all duration-200',
530
+ variants: {
531
+ state: {
532
+ // Reactive: changes when bond.state.isOpen changes
533
+ open: (bond) => ({
534
+ class: bond?.state?.isOpen
535
+ ? 'bg-blue-50 border-blue-200'
536
+ : 'bg-white border-gray-200',
537
+ 'aria-expanded': bond?.state?.isOpen,
538
+ 'data-state': bond?.state?.isOpen ? 'open' : 'closed'
539
+ }),
540
+ disabled: (bond) => ({
541
+ class: bond?.state?.disabled
542
+ ? 'opacity-50 cursor-not-allowed'
543
+ : 'cursor-pointer',
544
+ 'aria-disabled': bond?.state?.disabled
545
+ })
546
+ }
547
+ }
548
+ });
549
+
550
+ const bond = AccordionBond.get();
551
+
552
+ // Automatically reactive - updates when bond state changes
553
+ const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
554
+ </script>
555
+
556
+ <HtmlAtom {...variantProps}>
557
+ {@render children?.({ accordion: bond })}
558
+ </HtmlAtom>
559
+ ````
560
+
561
+ ## Migration Guide
562
+
563
+ ### Before: Manual Variant Management
564
+
565
+ ```svelte
566
+ <script>
567
+ let { variant = 'primary', size = 'md' } = $props();
568
+
569
+ const variantClasses = {
570
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
571
+ secondary: 'bg-gray-500 text-white hover:bg-gray-600',
572
+ danger: 'bg-red-500 text-white hover:bg-red-600'
573
+ };
574
+
575
+ const sizeClasses = {
576
+ sm: 'px-2 py-1 text-sm',
577
+ md: 'px-4 py-2 text-base',
578
+ lg: 'px-6 py-3 text-lg'
579
+ };
580
+
581
+ const classes = `rounded-md ${variantClasses[variant]} ${sizeClasses[size]}`;
582
+ </script>
583
+
584
+ <button class={classes}> Click me </button>
585
+ ```
586
+
587
+ ### After: defineVariants
588
+
589
+ ```svelte
590
+ <script>
591
+ import { HtmlAtom } from '@svelte-atoms/core';
592
+ import { defineVariants } from '@svelte-atoms/core/utils';
593
+
594
+ const buttonVariants = defineVariants({
595
+ class: 'rounded-md',
596
+ variants: {
597
+ variant: {
598
+ primary: 'bg-blue-500 text-white hover:bg-blue-600',
599
+ secondary: 'bg-gray-500 text-white hover:bg-gray-600',
600
+ danger: 'bg-red-500 text-white hover:bg-red-600'
601
+ },
602
+ size: {
603
+ sm: 'px-2 py-1 text-sm',
604
+ md: 'px-4 py-2 text-base',
605
+ lg: 'px-6 py-3 text-lg'
606
+ }
607
+ },
608
+ defaults: {
609
+ variant: 'primary',
610
+ size: 'md'
611
+ }
612
+ });
613
+
614
+ let { variant, size, ...props } = $props();
615
+
616
+ const bond = null; // or get from context if needed
617
+ const variantProps = buttonVariants(bond, { variant, size });
618
+ </script>
619
+
620
+ <HtmlAtom as="button" {...variantProps} {...props}>Click me</HtmlAtom>
621
+ ```
622
+
623
+ ### Benefits After Migration
624
+
625
+ ✅ **Less boilerplate** - Define once, use everywhere
626
+ ✅ **Type safety** - Automatic type inference
627
+ ✅ **Compound variants** - Complex styling combinations
628
+ ✅ **Default values** - No need for fallback logic
629
+ ✅ **Bond integration** - Access component state for reactive variants
630
+ ✅ **Return attributes** - Not just classes, any HTML attributes
631
+
632
+ ## Best Practices
633
+
634
+ ### 1. Organize Variants in Separate Files
635
+
636
+ ```typescript
637
+ // variants.ts
638
+ import { defineVariants } from '@svelte-atoms/core/utils';
639
+
640
+ export const buttonVariants = defineVariants({
641
+ class: 'rounded-md font-medium transition-colors',
642
+ variants: {
643
+ /* ... */
644
+ },
645
+ defaults: {
646
+ /* ... */
647
+ }
648
+ });
649
+
650
+ export const cardVariants = defineVariants({
651
+ class: 'rounded-lg border',
652
+ variants: {
653
+ /* ... */
654
+ },
655
+ defaults: {
656
+ /* ... */
657
+ }
658
+ });
659
+ ```
660
+
661
+ ### 2. Use $derived for Reactive Variants
662
+
663
+ When using bond state, wrap the variant call in `$derived`:
664
+
665
+ ```svelte
666
+ <script>
667
+ const bond = AccordionBond.get();
668
+
669
+ // Reactive - updates when bond state changes
670
+ const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
671
+ </script>
672
+ ```
673
+
674
+ ### 3. Extend with Additional Classes
675
+
676
+ Merge variant classes with custom classes:
677
+
678
+ ```svelte
679
+ <script>
680
+ const bond = null; // or get from context if needed
681
+ const variantProps = buttonVariants(bond, { variant, size });
682
+ </script>
683
+
684
+ <HtmlAtom class={[variantProps.class, 'custom-class']} {...variantProps} />
685
+ ```
686
+
687
+ ### 4. Type Props from Variants
688
+
689
+ Extract variant types for component props:
690
+
691
+ ```typescript
692
+ import { VariantPropsType } from '@svelte-atoms/core/utils';
693
+ import { buttonVariants } from './variants';
694
+
695
+ type ButtonProps = VariantPropsType<typeof buttonVariants> & {
696
+ disabled?: boolean;
697
+ // other props...
698
+ };
699
+ ```
700
+
701
+ ## Summary
702
+
703
+ `defineVariants()` provides:
704
+
705
+ ✅ **Single function** - One API for all variant needs
706
+ ✅ **Type-safe** - Automatic TypeScript inference
707
+ ✅ **Reactive** - Access bond state for dynamic styling
708
+ ✅ **Powerful** - Base classes, compound variants, defaults
709
+ ✅ **Flexible** - Return both classes and attributes
710
+ ✅ **Clean** - No manual object merging or conditionals
711
+
712
+ Inspired by Class Variance Authority but integrated with @svelte-atoms/core's bond system.