@stacksjs/components 0.2.3

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 (342) hide show
  1. package/README.md +477 -0
  2. package/dist/Accordion-x2gjedap.stx +108 -0
  3. package/dist/Audio-0fk6p9tn.stx +50 -0
  4. package/dist/Avatar-5m0v0s4x.stx +88 -0
  5. package/dist/Badge-ynes82vv.stx +70 -0
  6. package/dist/Breadcrumb-h9n427sk.stx +79 -0
  7. package/dist/Button-7xtrzn14.stx +89 -0
  8. package/dist/Calendar-egvx1pma.stx +232 -0
  9. package/dist/Card-r9w7vy1a.stx +74 -0
  10. package/dist/Checkbox-m8v46pmx.stx +92 -0
  11. package/dist/Checkout-vcnnr176.stx +39 -0
  12. package/dist/CodeBlock-mwex82cm.stx +57 -0
  13. package/dist/Combobox-npb08vkp.stx +13 -0
  14. package/dist/ComboboxButton-vcdyq4zw.stx +13 -0
  15. package/dist/ComboboxInput-c9d2p02m.stx +25 -0
  16. package/dist/ComboboxOption-7d0h9ash.stx +52 -0
  17. package/dist/ComboboxOptions-4dtqc0qa.stx +12 -0
  18. package/dist/CommandPalette-ah00bf8v.stx +39 -0
  19. package/dist/CommandPaletteItem-2yx0gvtj.stx +32 -0
  20. package/dist/DefaultPaymentMethod-emw5fg8s.stx +62 -0
  21. package/dist/Dialog-1w4rz7x0.stx +19 -0
  22. package/dist/DialogBackdrop-qbm3y5ab.stx +9 -0
  23. package/dist/DialogDescription-01w5j74b.stx +11 -0
  24. package/dist/DialogPanel-brsszrrs.stx +16 -0
  25. package/dist/DialogTitle-3rxhwg21.stx +11 -0
  26. package/dist/Drawer-yfaz8q7f.stx +137 -0
  27. package/dist/Dropdown-ng7nx556.stx +24 -0
  28. package/dist/DropdownButton-vc4zpyrb.stx +23 -0
  29. package/dist/DropdownItem-z491y23c.stx +43 -0
  30. package/dist/DropdownItems-7ykf29sj.stx +18 -0
  31. package/dist/EmailInput-bfshpj92.stx +41 -0
  32. package/dist/Footer-xdaf02nr.stx +66 -0
  33. package/dist/Form-z4f7w6r1.stx +209 -0
  34. package/dist/Hero-9vvp7pxf.stx +25 -0
  35. package/dist/Image-ktk0451c.stx +197 -0
  36. package/dist/Installation-33bj4rm7.stx +39 -0
  37. package/dist/Listbox-xcejcmyc.stx +14 -0
  38. package/dist/ListboxButton-nx5kmw19.stx +17 -0
  39. package/dist/ListboxLabel-aky8a73n.stx +11 -0
  40. package/dist/ListboxOption-6h4hsdz5.stx +57 -0
  41. package/dist/ListboxOptions-2sacdtm5.stx +16 -0
  42. package/dist/Login-s2jkvd9y.stx +163 -0
  43. package/dist/Navigator-tqqdgdkw.stx +138 -0
  44. package/dist/Notification-sry8egea.stx +71 -0
  45. package/dist/NumberInput-zm93ddfw.stx +138 -0
  46. package/dist/Pagination-yza9v4qw.stx +183 -0
  47. package/dist/PasswordInput-4xnndp5y.stx +155 -0
  48. package/dist/PaymentMethods-jxba6kek.stx +113 -0
  49. package/dist/Popover-scbqatjq.stx +24 -0
  50. package/dist/PopoverButton-rbxhzj4k.stx +23 -0
  51. package/dist/PopoverPanel-9ng1rm6e.stx +23 -0
  52. package/dist/Portal-j111yvqp.stx +74 -0
  53. package/dist/Progress-gbmw3akr.stx +142 -0
  54. package/dist/Radio-1n9qamv1.stx +81 -0
  55. package/dist/RadioGroup-12dw2vhk.stx +13 -0
  56. package/dist/RadioGroupDescription-bjm3mdht.stx +11 -0
  57. package/dist/RadioGroupLabel-aky8a73n.stx +11 -0
  58. package/dist/RadioGroupOption-9pcxgwmd.stx +51 -0
  59. package/dist/SearchInput-g240e2nq.stx +63 -0
  60. package/dist/Select-p9f94b20.stx +89 -0
  61. package/dist/Sidebar-gwxw8q38.stx +288 -0
  62. package/dist/SidebarFooter-887kxret.stx +95 -0
  63. package/dist/SidebarHeader-qjeyx0hv.stx +100 -0
  64. package/dist/SidebarItem-4dpwtmb4.stx +118 -0
  65. package/dist/SidebarSection-kh92fk4m.stx +108 -0
  66. package/dist/Signup-3nxq5zag.stx +161 -0
  67. package/dist/Skeleton-g0nx1njm.stx +48 -0
  68. package/dist/Spinner-w4zj58xp.stx +109 -0
  69. package/dist/Stepper-rwc5actp.stx +17 -0
  70. package/dist/StepperStep-h0k657nm.stx +53 -0
  71. package/dist/SubscriptionCheckout-4cbxdg7w.stx +353 -0
  72. package/dist/Switch-kjq8qd2p.stx +74 -0
  73. package/dist/Table-59j9qwp0.stx +14 -0
  74. package/dist/TableBody-reka2gwv.stx +10 -0
  75. package/dist/TableCell-j7nh4sgr.stx +10 -0
  76. package/dist/TableHead-ecbrwpqm.stx +10 -0
  77. package/dist/TableHeader-jn2shwsv.stx +13 -0
  78. package/dist/TableRow-xz8rrxhc.stx +11 -0
  79. package/dist/Tabs-kb6ex6m7.stx +145 -0
  80. package/dist/Teleport-819cg9zm.stx +101 -0
  81. package/dist/TextInput-zx9kgr79.stx +146 -0
  82. package/dist/Textarea-5xvmrb0z.stx +119 -0
  83. package/dist/Tooltip-5ehqsy49.stx +76 -0
  84. package/dist/Transition-2j39s044.stx +174 -0
  85. package/dist/TwoFactorChallenge-2q4gg89m.stx +125 -0
  86. package/dist/Video-6aq4shh4.stx +45 -0
  87. package/dist/VirtualList-weh5qtm1.stx +83 -0
  88. package/dist/VirtualTable-59a1eskc.stx +113 -0
  89. package/dist/components/index.d.ts +4 -0
  90. package/dist/composables/index.d.ts +4 -0
  91. package/dist/composables/index.js +3 -0
  92. package/dist/composables/useCopyCode.d.ts +19 -0
  93. package/dist/composables/useDarkMode.d.ts +25 -0
  94. package/dist/composables/useSEO.d.ts +36 -0
  95. package/dist/composables/utilities/index.d.ts +5 -0
  96. package/dist/composables/utilities/useClickOutside.d.ts +28 -0
  97. package/dist/composables/utilities/useFocusTrap.d.ts +34 -0
  98. package/dist/composables/utilities/useKeyboard.d.ts +55 -0
  99. package/dist/composables/utilities/useLocalStorage.d.ts +33 -0
  100. package/dist/composables/utilities/useMediaQuery.d.ts +64 -0
  101. package/dist/index.d.ts +86 -0
  102. package/dist/index.js +19 -0
  103. package/dist/ui/accordion/index.d.ts +12 -0
  104. package/dist/ui/audio/index.d.ts +12 -0
  105. package/dist/ui/auth/index.d.ts +29 -0
  106. package/dist/ui/avatar/index.d.ts +11 -0
  107. package/dist/ui/badge/index.d.ts +9 -0
  108. package/dist/ui/breadcrumb/index.d.ts +13 -0
  109. package/dist/ui/button/index.d.ts +45 -0
  110. package/dist/ui/calendar/index.d.ts +13 -0
  111. package/dist/ui/card/index.d.ts +12 -0
  112. package/dist/ui/checkbox/index.d.ts +15 -0
  113. package/dist/ui/combobox/index.d.ts +35 -0
  114. package/dist/ui/command-palette/index.d.ts +13 -0
  115. package/dist/ui/dialog/index.d.ts +27 -0
  116. package/dist/ui/drawer/index.d.ts +8 -0
  117. package/dist/ui/dropdown/index.d.ts +25 -0
  118. package/dist/ui/form/index.d.ts +48 -0
  119. package/dist/ui/image/index.d.ts +21 -0
  120. package/dist/ui/input/index.d.ts +73 -0
  121. package/dist/ui/listbox/index.d.ts +34 -0
  122. package/dist/ui/navigator/index.d.ts +18 -0
  123. package/dist/ui/notification/index.d.ts +11 -0
  124. package/dist/ui/pagination/index.d.ts +10 -0
  125. package/dist/ui/payment/index.d.ts +53 -0
  126. package/dist/ui/popover/index.d.ts +19 -0
  127. package/dist/ui/portal/index.d.ts +5 -0
  128. package/dist/ui/progress/index.d.ts +11 -0
  129. package/dist/ui/radio/index.d.ts +14 -0
  130. package/dist/ui/radio-group/index.d.ts +26 -0
  131. package/dist/ui/select/index.d.ts +19 -0
  132. package/dist/ui/sidebar/index.d.ts +129 -0
  133. package/dist/ui/skeleton/index.d.ts +10 -0
  134. package/dist/ui/spinner/index.d.ts +8 -0
  135. package/dist/ui/stepper/index.d.ts +17 -0
  136. package/dist/ui/storage/index.d.ts +40 -0
  137. package/dist/ui/switch/index.d.ts +9 -0
  138. package/dist/ui/table/index.d.ts +29 -0
  139. package/dist/ui/tabs/index.d.ts +14 -0
  140. package/dist/ui/teleport/index.d.ts +6 -0
  141. package/dist/ui/textarea/index.d.ts +19 -0
  142. package/dist/ui/tooltip/index.d.ts +9 -0
  143. package/dist/ui/transition/index.d.ts +24 -0
  144. package/dist/ui/video/index.d.ts +15 -0
  145. package/dist/ui/virtual-list/index.d.ts +9 -0
  146. package/dist/ui/virtual-table/index.d.ts +19 -0
  147. package/dist/utils/accessibility.d.ts +285 -0
  148. package/dist/utils/animation/easing.d.ts +112 -0
  149. package/dist/utils/animation/helpers.d.ts +119 -0
  150. package/dist/utils/animation/index.d.ts +3 -0
  151. package/dist/utils/animation/keyframes.d.ts +334 -0
  152. package/dist/utils/error-handling.d.ts +182 -0
  153. package/dist/utils/highlighter.d.ts +27 -0
  154. package/dist/utils/highlighter.js +2 -0
  155. package/dist/utils/i18n.d.ts +245 -0
  156. package/dist/utils/keep-alive.d.ts +171 -0
  157. package/dist/utils/lazy-loading.d.ts +174 -0
  158. package/dist/utils/prop-validation.d.ts +106 -0
  159. package/dist/utils/theme.d.ts +234 -0
  160. package/package.json +69 -0
  161. package/src/components/CodeBlock.stx +57 -0
  162. package/src/components/Footer.stx +66 -0
  163. package/src/components/Hero.stx +25 -0
  164. package/src/components/Installation.stx +39 -0
  165. package/src/components/index.ts +4 -0
  166. package/src/composables/index.ts +4 -0
  167. package/src/composables/useCopyCode.ts +73 -0
  168. package/src/composables/useDarkMode.ts +100 -0
  169. package/src/composables/useSEO.ts +229 -0
  170. package/src/composables/utilities/index.ts +7 -0
  171. package/src/composables/utilities/useClickOutside.ts +72 -0
  172. package/src/composables/utilities/useFocusTrap.ts +159 -0
  173. package/src/composables/utilities/useKeyboard.ts +124 -0
  174. package/src/composables/utilities/useLocalStorage.ts +132 -0
  175. package/src/composables/utilities/useMediaQuery.ts +118 -0
  176. package/src/index.ts +99 -0
  177. package/src/stx.d.ts +4 -0
  178. package/src/ui/accordion/Accordion.stx +108 -0
  179. package/src/ui/accordion/index.ts +14 -0
  180. package/src/ui/audio/Audio.stx +50 -0
  181. package/src/ui/audio/README.md +42 -0
  182. package/src/ui/audio/index.ts +13 -0
  183. package/src/ui/auth/Login.stx +163 -0
  184. package/src/ui/auth/README.md +145 -0
  185. package/src/ui/auth/Signup.stx +161 -0
  186. package/src/ui/auth/TwoFactorChallenge.stx +125 -0
  187. package/src/ui/auth/index.ts +32 -0
  188. package/src/ui/avatar/Avatar.stx +88 -0
  189. package/src/ui/avatar/index.ts +12 -0
  190. package/src/ui/badge/Badge.stx +70 -0
  191. package/src/ui/badge/index.ts +10 -0
  192. package/src/ui/breadcrumb/Breadcrumb.stx +79 -0
  193. package/src/ui/breadcrumb/index.ts +15 -0
  194. package/src/ui/button/Button.stx +89 -0
  195. package/src/ui/button/README.md +100 -0
  196. package/src/ui/button/index.ts +85 -0
  197. package/src/ui/calendar/Calendar.stx +232 -0
  198. package/src/ui/calendar/README.md +254 -0
  199. package/src/ui/calendar/index.ts +14 -0
  200. package/src/ui/card/Card.stx +74 -0
  201. package/src/ui/card/index.ts +13 -0
  202. package/src/ui/checkbox/Checkbox.stx +92 -0
  203. package/src/ui/checkbox/index.ts +16 -0
  204. package/src/ui/combobox/Combobox.stx +13 -0
  205. package/src/ui/combobox/ComboboxButton.stx +13 -0
  206. package/src/ui/combobox/ComboboxInput.stx +25 -0
  207. package/src/ui/combobox/ComboboxOption.stx +52 -0
  208. package/src/ui/combobox/ComboboxOptions.stx +12 -0
  209. package/src/ui/combobox/README.md +154 -0
  210. package/src/ui/combobox/index.ts +40 -0
  211. package/src/ui/command-palette/CommandPalette.stx +39 -0
  212. package/src/ui/command-palette/CommandPaletteItem.stx +32 -0
  213. package/src/ui/command-palette/README.md +42 -0
  214. package/src/ui/command-palette/index.ts +15 -0
  215. package/src/ui/dialog/Dialog.stx +19 -0
  216. package/src/ui/dialog/DialogBackdrop.stx +9 -0
  217. package/src/ui/dialog/DialogDescription.stx +11 -0
  218. package/src/ui/dialog/DialogPanel.stx +16 -0
  219. package/src/ui/dialog/DialogTitle.stx +11 -0
  220. package/src/ui/dialog/README.md +133 -0
  221. package/src/ui/dialog/index.ts +32 -0
  222. package/src/ui/drawer/Drawer.stx +137 -0
  223. package/src/ui/drawer/README.md +110 -0
  224. package/src/ui/drawer/index.ts +9 -0
  225. package/src/ui/dropdown/Dropdown.stx +24 -0
  226. package/src/ui/dropdown/DropdownButton.stx +23 -0
  227. package/src/ui/dropdown/DropdownItem.stx +43 -0
  228. package/src/ui/dropdown/DropdownItems.stx +18 -0
  229. package/src/ui/dropdown/README.md +142 -0
  230. package/src/ui/dropdown/index.ts +29 -0
  231. package/src/ui/form/Form.stx +209 -0
  232. package/src/ui/form/index.ts +67 -0
  233. package/src/ui/heatmap/Heatmap.stx +315 -0
  234. package/src/ui/image/Image.stx +197 -0
  235. package/src/ui/image/README.md +171 -0
  236. package/src/ui/image/index.ts +22 -0
  237. package/src/ui/input/EmailInput.stx +41 -0
  238. package/src/ui/input/NumberInput.stx +138 -0
  239. package/src/ui/input/PasswordInput.stx +155 -0
  240. package/src/ui/input/SearchInput.stx +63 -0
  241. package/src/ui/input/TextInput.stx +146 -0
  242. package/src/ui/input/index.ts +180 -0
  243. package/src/ui/listbox/Listbox.stx +14 -0
  244. package/src/ui/listbox/ListboxButton.stx +17 -0
  245. package/src/ui/listbox/ListboxLabel.stx +11 -0
  246. package/src/ui/listbox/ListboxOption.stx +57 -0
  247. package/src/ui/listbox/ListboxOptions.stx +16 -0
  248. package/src/ui/listbox/README.md +143 -0
  249. package/src/ui/listbox/index.ts +39 -0
  250. package/src/ui/navigator/Navigator.stx +138 -0
  251. package/src/ui/navigator/README.md +352 -0
  252. package/src/ui/navigator/index.ts +20 -0
  253. package/src/ui/notification/Notification.stx +71 -0
  254. package/src/ui/notification/README.md +118 -0
  255. package/src/ui/notification/index.ts +12 -0
  256. package/src/ui/pagination/Pagination.stx +183 -0
  257. package/src/ui/pagination/index.ts +11 -0
  258. package/src/ui/payment/Checkout.stx +39 -0
  259. package/src/ui/payment/DefaultPaymentMethod.stx +62 -0
  260. package/src/ui/payment/PaymentMethods.stx +113 -0
  261. package/src/ui/payment/README.md +427 -0
  262. package/src/ui/payment/SubscriptionCheckout.stx +353 -0
  263. package/src/ui/payment/index.ts +59 -0
  264. package/src/ui/popover/Popover.stx +24 -0
  265. package/src/ui/popover/PopoverButton.stx +23 -0
  266. package/src/ui/popover/PopoverPanel.stx +23 -0
  267. package/src/ui/popover/README.md +95 -0
  268. package/src/ui/popover/index.ts +22 -0
  269. package/src/ui/portal/Portal.stx +74 -0
  270. package/src/ui/portal/index.ts +6 -0
  271. package/src/ui/progress/Progress.stx +142 -0
  272. package/src/ui/progress/index.ts +12 -0
  273. package/src/ui/radio/Radio.stx +81 -0
  274. package/src/ui/radio/index.ts +15 -0
  275. package/src/ui/radio-group/README.md +145 -0
  276. package/src/ui/radio-group/RadioGroup.stx +13 -0
  277. package/src/ui/radio-group/RadioGroupDescription.stx +11 -0
  278. package/src/ui/radio-group/RadioGroupLabel.stx +11 -0
  279. package/src/ui/radio-group/RadioGroupOption.stx +51 -0
  280. package/src/ui/radio-group/index.ts +30 -0
  281. package/src/ui/select/README.md +204 -0
  282. package/src/ui/select/Select.stx +89 -0
  283. package/src/ui/select/index.ts +21 -0
  284. package/src/ui/sidebar/Sidebar.stx +288 -0
  285. package/src/ui/sidebar/SidebarFooter.stx +95 -0
  286. package/src/ui/sidebar/SidebarHeader.stx +100 -0
  287. package/src/ui/sidebar/SidebarItem.stx +118 -0
  288. package/src/ui/sidebar/SidebarSection.stx +108 -0
  289. package/src/ui/sidebar/index.ts +175 -0
  290. package/src/ui/skeleton/Skeleton.stx +48 -0
  291. package/src/ui/skeleton/index.ts +11 -0
  292. package/src/ui/spinner/Spinner.stx +109 -0
  293. package/src/ui/spinner/index.ts +9 -0
  294. package/src/ui/stepper/README.md +36 -0
  295. package/src/ui/stepper/Stepper.stx +17 -0
  296. package/src/ui/stepper/StepperStep.stx +53 -0
  297. package/src/ui/stepper/index.ts +19 -0
  298. package/src/ui/storage/README.md +193 -0
  299. package/src/ui/storage/index.ts +347 -0
  300. package/src/ui/switch/README.md +133 -0
  301. package/src/ui/switch/Switch.stx +74 -0
  302. package/src/ui/switch/index.ts +10 -0
  303. package/src/ui/table/README.md +39 -0
  304. package/src/ui/table/Table.stx +14 -0
  305. package/src/ui/table/TableBody.stx +10 -0
  306. package/src/ui/table/TableCell.stx +10 -0
  307. package/src/ui/table/TableHead.stx +10 -0
  308. package/src/ui/table/TableHeader.stx +13 -0
  309. package/src/ui/table/TableRow.stx +11 -0
  310. package/src/ui/table/index.ts +35 -0
  311. package/src/ui/tabs/Tabs.stx +145 -0
  312. package/src/ui/tabs/index.ts +16 -0
  313. package/src/ui/teleport/Teleport.stx +101 -0
  314. package/src/ui/teleport/index.ts +7 -0
  315. package/src/ui/textarea/Textarea.stx +119 -0
  316. package/src/ui/textarea/index.ts +20 -0
  317. package/src/ui/tooltip/Tooltip.stx +76 -0
  318. package/src/ui/tooltip/index.ts +10 -0
  319. package/src/ui/transition/README.md +30 -0
  320. package/src/ui/transition/Transition.stx +174 -0
  321. package/src/ui/transition/index.ts +25 -0
  322. package/src/ui/video/README.md +48 -0
  323. package/src/ui/video/Video.stx +45 -0
  324. package/src/ui/video/index.ts +16 -0
  325. package/src/ui/virtual-list/VirtualList.stx +83 -0
  326. package/src/ui/virtual-list/index.ts +10 -0
  327. package/src/ui/virtual-table/VirtualTable.stx +113 -0
  328. package/src/ui/virtual-table/index.ts +21 -0
  329. package/src/utils/PROP_VALIDATION.md +458 -0
  330. package/src/utils/THEME_SYSTEM.md +702 -0
  331. package/src/utils/accessibility.ts +841 -0
  332. package/src/utils/animation/easing.ts +368 -0
  333. package/src/utils/animation/helpers.ts +223 -0
  334. package/src/utils/animation/index.ts +5 -0
  335. package/src/utils/animation/keyframes.ts +230 -0
  336. package/src/utils/error-handling.ts +473 -0
  337. package/src/utils/highlighter.ts +93 -0
  338. package/src/utils/i18n.ts +634 -0
  339. package/src/utils/keep-alive.ts +818 -0
  340. package/src/utils/lazy-loading.ts +530 -0
  341. package/src/utils/prop-validation.ts +478 -0
  342. package/src/utils/theme.ts +626 -0
@@ -0,0 +1,88 @@
1
+ <script>
2
+ export const src = $props.src || ''
3
+ export const alt = $props.alt || ''
4
+ export const initials = $props.initials || ''
5
+ export const size = $props.size || 'md'
6
+ export const shape = $props.shape || 'circle'
7
+ export const status = $props.status || ''
8
+ export const className = $props.className || ''
9
+ export const onError = $props.onError
10
+
11
+ let imageError = false
12
+
13
+ // Size classes
14
+ const sizeClasses = {
15
+ xs: 'w-6 h-6 text-xs',
16
+ sm: 'w-8 h-8 text-sm',
17
+ md: 'w-10 h-10 text-base',
18
+ lg: 'w-12 h-12 text-lg',
19
+ xl: 'w-16 h-16 text-xl',
20
+ '2xl': 'w-20 h-20 text-2xl',
21
+ }
22
+
23
+ // Shape classes
24
+ const shapeClasses = {
25
+ circle: 'rounded-full',
26
+ square: 'rounded-md',
27
+ }
28
+
29
+ // Status indicator size classes
30
+ const statusSizeClasses = {
31
+ xs: 'w-1.5 h-1.5 border',
32
+ sm: 'w-2 h-2 border',
33
+ md: 'w-2.5 h-2.5 border-2',
34
+ lg: 'w-3 h-3 border-2',
35
+ xl: 'w-3.5 h-3.5 border-2',
36
+ '2xl': 'w-4 h-4 border-2',
37
+ }
38
+
39
+ // Status color classes
40
+ const statusColorClasses = {
41
+ online: 'bg-green-500 dark:bg-green-400',
42
+ offline: 'bg-gray-400 dark:bg-gray-600',
43
+ away: 'bg-yellow-500 dark:bg-yellow-400',
44
+ busy: 'bg-red-500 dark:bg-red-400',
45
+ }
46
+
47
+ export const containerClasses = `relative inline-block ${className}`.trim()
48
+ export const avatarClasses = `flex items-center justify-center overflow-hidden bg-gray-200 dark:bg-gray-700 ${sizeClasses[size]} ${shapeClasses[shape]}`.trim()
49
+ export const imageClasses = `w-full h-full object-cover`.trim()
50
+ export const initialsClasses = `font-medium text-gray-600 dark:text-gray-300 uppercase select-none`.trim()
51
+ export const statusClasses = `absolute bottom-0 right-0 ${statusSizeClasses[size]} ${statusColorClasses[status]} ${shapeClasses[shape]} border-white dark:border-gray-900`.trim()
52
+
53
+ // Generate initials from name if not provided
54
+ export const displayInitials = initials || (alt ? alt.split(' ').map(n => n[0]).join('').substring(0, 2) : '?')
55
+ </script>
56
+
57
+ <div class="{{ containerClasses }}">
58
+ <div class="{{ avatarClasses }}">
59
+ @if(src && !imageError)
60
+ <img
61
+ src="{{ src }}"
62
+ alt="{{ alt }}"
63
+ class="{{ imageClasses }}"
64
+ onerror="handleImageError(event)"
65
+ />
66
+ @else
67
+ <span class="{{ initialsClasses }}">{{ displayInitials }}</span>
68
+ @endif
69
+ </div>
70
+
71
+ @if(status)
72
+ <span
73
+ class="{{ statusClasses }}"
74
+ role="status"
75
+ aria-label="{{ status }}"
76
+ ></span>
77
+ @endif
78
+ </div>
79
+
80
+ <script>
81
+ function handleImageError(event) {
82
+ imageError = true
83
+
84
+ if (onError) {
85
+ onError(event)
86
+ }
87
+ }
88
+ </script>
@@ -0,0 +1,12 @@
1
+ export { default as Avatar } from './Avatar.stx'
2
+
3
+ export interface AvatarProps {
4
+ src?: string
5
+ alt?: string
6
+ initials?: string
7
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
8
+ shape?: 'circle' | 'square'
9
+ status?: 'online' | 'offline' | 'away' | 'busy' | ''
10
+ onError?: (event: Event) => void
11
+ className?: string
12
+ }
@@ -0,0 +1,70 @@
1
+ <script>
2
+ export const variant = $props.variant || 'default'
3
+ export const size = $props.size || 'md'
4
+ export const dot = $props.dot || false
5
+ export const removable = $props.removable || false
6
+ export const className = $props.className || ''
7
+ export const onRemove = $props.onRemove
8
+
9
+ // Variant classes
10
+ const variantClasses = {
11
+ default: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
12
+ primary: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
13
+ secondary: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200',
14
+ success: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
15
+ warning: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
16
+ danger: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
17
+ info: 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-200',
18
+ }
19
+
20
+ // Size classes
21
+ const sizeClasses = {
22
+ sm: 'px-2 py-0.5 text-xs',
23
+ md: 'px-2.5 py-0.5 text-sm',
24
+ lg: 'px-3 py-1 text-base',
25
+ }
26
+
27
+ // Dot color classes
28
+ const dotColorClasses = {
29
+ default: 'bg-gray-500 dark:bg-gray-400',
30
+ primary: 'bg-blue-500 dark:bg-blue-400',
31
+ secondary: 'bg-purple-500 dark:bg-purple-400',
32
+ success: 'bg-green-500 dark:bg-green-400',
33
+ warning: 'bg-yellow-500 dark:bg-yellow-400',
34
+ danger: 'bg-red-500 dark:bg-red-400',
35
+ info: 'bg-cyan-500 dark:bg-cyan-400',
36
+ }
37
+
38
+ export const badgeClasses = `inline-flex items-center gap-1.5 font-medium rounded-full ${variantClasses[variant]} ${sizeClasses[size]} ${className}`.trim()
39
+ export const dotClasses = `w-2 h-2 rounded-full ${dotColorClasses[variant]}`.trim()
40
+ export const removeButtonClasses = `ml-0.5 -mr-1 text-current hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10 rounded-full p-0.5 transition-colors duration-150`.trim()
41
+ </script>
42
+
43
+ <span class="{{ badgeClasses }}" role="status">
44
+ @if(dot)
45
+ <span class="{{ dotClasses }}" aria-hidden="true"></span>
46
+ @endif
47
+
48
+ <slot />
49
+
50
+ @if(removable && onRemove)
51
+ <button
52
+ type="button"
53
+ onclick="handleRemove()"
54
+ class="{{ removeButtonClasses }}"
55
+ aria-label="Remove"
56
+ >
57
+ <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
58
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
59
+ </svg>
60
+ </button>
61
+ @endif
62
+ </span>
63
+
64
+ <script>
65
+ function handleRemove() {
66
+ if (onRemove) {
67
+ onRemove()
68
+ }
69
+ }
70
+ </script>
@@ -0,0 +1,10 @@
1
+ export { default as Badge } from './Badge.stx'
2
+
3
+ export interface BadgeProps {
4
+ variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info'
5
+ size?: 'sm' | 'md' | 'lg'
6
+ dot?: boolean
7
+ removable?: boolean
8
+ onRemove?: () => void
9
+ className?: string
10
+ }
@@ -0,0 +1,79 @@
1
+ <script>
2
+ export const items = $props.items || []
3
+ export const separator = $props.separator || '/'
4
+ export const maxItems = $props.maxItems || 0
5
+ export const className = $props.className || ''
6
+
7
+ // Handle collapse if maxItems is set
8
+ let displayItems = items
9
+ if (maxItems > 0 && items.length > maxItems) {
10
+ const firstItems = items.slice(0, 1)
11
+ const lastItems = items.slice(-(maxItems - 1))
12
+ displayItems = [...firstItems, { label: '...', href: '#', collapsed: true }, ...lastItems]
13
+ }
14
+
15
+ // Separator element
16
+ const separatorElement = separator === '/' ? '/' :
17
+ separator === '>' ? '›' :
18
+ separator === 'arrow' ? `<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>` :
19
+ separator
20
+
21
+ export const breadcrumbClasses = `flex items-center flex-wrap gap-2 text-sm ${className}`.trim()
22
+ export const itemClasses = `text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors duration-150`.trim()
23
+ export const activeItemClasses = `text-gray-900 dark:text-gray-100 font-medium`.trim()
24
+ export const separatorClasses = `text-gray-400 dark:text-gray-600 select-none`.trim()
25
+ export const collapsedClasses = `text-gray-400 dark:text-gray-600 cursor-default`.trim()
26
+ </script>
27
+
28
+ <nav class="{{ breadcrumbClasses }}" aria-label="Breadcrumb">
29
+ <ol class="flex items-center gap-2">
30
+ @foreach(item in displayItems)
31
+ <li class="flex items-center gap-2">
32
+ @if(item.collapsed)
33
+ <!-- Collapsed indicator -->
34
+ <span class="{{ collapsedClasses }}">{{ item.label }}</span>
35
+ @else
36
+ @if($loop.last)
37
+ <!-- Last item (current page) -->
38
+ <span class="{{ activeItemClasses }}" aria-current="page">
39
+ @if(item.icon)
40
+ <span class="inline-flex items-center gap-1.5">
41
+ <span innerHTML="{!! item.icon !!}"></span>
42
+ <span>{{ item.label }}</span>
43
+ </span>
44
+ @else
45
+ {{ item.label }}
46
+ @endif
47
+ </span>
48
+ @else
49
+ <!-- Link item -->
50
+ <a
51
+ href="{{ item.href }}"
52
+ class="{{ itemClasses }}"
53
+ >
54
+ @if(item.icon)
55
+ <span class="inline-flex items-center gap-1.5">
56
+ <span innerHTML="{!! item.icon !!}"></span>
57
+ <span>{{ item.label }}</span>
58
+ </span>
59
+ @else
60
+ {{ item.label }}
61
+ @endif
62
+ </a>
63
+ @endif
64
+ @endif
65
+
66
+ <!-- Separator (not after last item) -->
67
+ @if(!$loop.last)
68
+ <span class="{{ separatorClasses }}" aria-hidden="true">
69
+ @if(separator === 'arrow')
70
+ {!! separatorElement !!}
71
+ @else
72
+ {{ separatorElement }}
73
+ @endif
74
+ </span>
75
+ @endif
76
+ </li>
77
+ @endforeach
78
+ </ol>
79
+ </nav>
@@ -0,0 +1,15 @@
1
+ export { default as Breadcrumb } from './Breadcrumb.stx'
2
+
3
+ export interface BreadcrumbItem {
4
+ label: string
5
+ href: string
6
+ icon?: string
7
+ collapsed?: boolean
8
+ }
9
+
10
+ export interface BreadcrumbProps {
11
+ items: BreadcrumbItem[]
12
+ separator?: '/' | '>' | 'arrow' | string
13
+ maxItems?: number
14
+ className?: string
15
+ }
@@ -0,0 +1,89 @@
1
+ <script>
2
+ export const variant = $props.variant || 'primary'
3
+ export const size = $props.size || 'md'
4
+ export const disabled = $props.disabled || false
5
+ export const loading = $props.loading || false
6
+ export const type = $props.type || 'button'
7
+ export const fullWidth = $props.fullWidth || false
8
+ export const leftIcon = $props.leftIcon || ''
9
+ export const rightIcon = $props.rightIcon || ''
10
+ export const className = $props.className || ''
11
+ export const onClick = $props.onClick
12
+
13
+ // Variant styles using headwind
14
+ const variantClasses = {
15
+ primary: 'bg-blue-500 hover:bg-blue-600 text-white shadow-md hover:shadow-lg dark:bg-blue-600 dark:hover:bg-blue-700',
16
+ secondary: 'bg-neutral-200 hover:bg-neutral-300 text-neutral-900 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:text-white',
17
+ outline: 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50 dark:border-blue-400 dark:text-blue-400 dark:hover:bg-blue-950',
18
+ ghost: 'hover:bg-neutral-100 text-neutral-700 dark:hover:bg-neutral-800 dark:text-neutral-300',
19
+ danger: 'bg-red-500 hover:bg-red-600 text-white shadow-md hover:shadow-lg dark:bg-red-600 dark:hover:bg-red-700',
20
+ }
21
+
22
+ // Size styles using headwind
23
+ const sizeClasses = {
24
+ xs: 'px-2.5 py-1 text-xs h-7 gap-1',
25
+ sm: 'px-3 py-1.5 text-sm h-8 gap-1.5',
26
+ md: 'px-4 py-2 text-base h-10 gap-2',
27
+ lg: 'px-6 py-3 text-lg h-12 gap-2.5',
28
+ xl: 'px-8 py-4 text-xl h-14 gap-3',
29
+ }
30
+
31
+ // Icon size styles
32
+ const iconSizeClasses = {
33
+ xs: 'h-3 w-3',
34
+ sm: 'h-4 w-4',
35
+ md: 'h-5 w-5',
36
+ lg: 'h-6 w-6',
37
+ xl: 'h-7 w-7',
38
+ }
39
+
40
+ // Base classes
41
+ const baseClasses = 'inline-flex items-center justify-center font-semibold rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none'
42
+
43
+ // Width classes
44
+ const widthClasses = fullWidth ? 'w-full' : ''
45
+
46
+ // Loading state disables interactions
47
+ const isDisabled = disabled || loading
48
+
49
+ // Combine classes
50
+ export const buttonClasses = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${widthClasses} ${className}`.trim()
51
+ export const iconClasses = iconSizeClasses[size]
52
+ export const spinnerClasses = `animate-spin ${iconClasses}`.trim()
53
+ </script>
54
+
55
+ <button
56
+ type="{{ type }}"
57
+ class="{{ buttonClasses }}"
58
+ @if(isDisabled)disabled@endif
59
+ @if(onClick)onclick="handleClick(event)"@endif
60
+ aria-busy="{{ loading ? 'true' : 'false' }}"
61
+ >
62
+ @if(loading)
63
+ <!-- Loading spinner -->
64
+ <svg class="{{ spinnerClasses }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
65
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
66
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
67
+ </svg>
68
+ @else
69
+ @if(leftIcon)
70
+ <!-- Left icon -->
71
+ <span class="{{ iconClasses }}" innerHTML="{!! leftIcon !!}"></span>
72
+ @endif
73
+ @endif
74
+
75
+ <slot />
76
+
77
+ @if(!loading && rightIcon)
78
+ <!-- Right icon -->
79
+ <span class="{{ iconClasses }}" innerHTML="{!! rightIcon !!}"></span>
80
+ @endif
81
+ </button>
82
+
83
+ <script>
84
+ function handleClick(event) {
85
+ if (!isDisabled && onClick) {
86
+ onClick(event)
87
+ }
88
+ }
89
+ </script>
@@ -0,0 +1,100 @@
1
+ # Button Component
2
+
3
+ A versatile button component built with STX and headwind utility classes.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @stacksjs/components
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```stx
14
+ @component('Button', { variant: 'primary', size: 'md' })
15
+ Click me
16
+ @endcomponent
17
+ ```
18
+
19
+ ## Props
20
+
21
+ | Prop | Type | Default | Description |
22
+ |------|------|---------|-------------|
23
+ | `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'danger'` | `'primary'` | Button visual style |
24
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
25
+ | `disabled` | `boolean` | `false` | Disable the button |
26
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Button HTML type |
27
+ | `className` | `string` | `''` | Additional CSS classes |
28
+ | `onClick` | `() => void` | - | Click handler |
29
+
30
+ ## Examples
31
+
32
+ ### Variants
33
+
34
+ ```stx
35
+ @component('Button', { variant: 'primary' })
36
+ Primary Button
37
+ @endcomponent
38
+
39
+ @component('Button', { variant: 'secondary' })
40
+ Secondary Button
41
+ @endcomponent
42
+
43
+ @component('Button', { variant: 'outline' })
44
+ Outline Button
45
+ @endcomponent
46
+
47
+ @component('Button', { variant: 'ghost' })
48
+ Ghost Button
49
+ @endcomponent
50
+
51
+ @component('Button', { variant: 'danger' })
52
+ Danger Button
53
+ @endcomponent
54
+ ```
55
+
56
+ ### Sizes
57
+
58
+ ```stx
59
+ @component('Button', { size: 'sm' })
60
+ Small Button
61
+ @endcomponent
62
+
63
+ @component('Button', { size: 'md' })
64
+ Medium Button
65
+ @endcomponent
66
+
67
+ @component('Button', { size: 'lg' })
68
+ Large Button
69
+ @endcomponent
70
+ ```
71
+
72
+ ### Disabled State
73
+
74
+ ```stx
75
+ @component('Button', { disabled: true })
76
+ Disabled Button
77
+ @endcomponent
78
+ ```
79
+
80
+ ### With Icon
81
+
82
+ ```stx
83
+ @component('Button', { variant: 'primary' })
84
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
85
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
86
+ </svg>
87
+ Add Item
88
+ @endcomponent
89
+ ```
90
+
91
+ ## Features
92
+
93
+ - 5 visual variants (primary, secondary, outline, ghost, danger)
94
+ - 3 size options (sm, md, lg)
95
+ - Disabled state support
96
+ - Focus ring with keyboard navigation
97
+ - Dark mode support
98
+ - Accessible by default
99
+ - Smooth transitions
100
+ - Headwind utility classes for easy customization
@@ -0,0 +1,85 @@
1
+ import type { PropSchema, ValidationResult } from '../../utils/prop-validation'
2
+ import { ErrorTypes, wrapErrorHandler } from '../../utils/error-handling'
3
+ import { createPropValidator, PropTypes } from '../../utils/prop-validation'
4
+
5
+ export { default as Button } from './Button.stx'
6
+
7
+ export interface ButtonProps {
8
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'
9
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
10
+ disabled?: boolean
11
+ loading?: boolean
12
+ type?: 'button' | 'submit' | 'reset'
13
+ fullWidth?: boolean
14
+ leftIcon?: string
15
+ rightIcon?: string
16
+ className?: string
17
+ onClick?: (event: Event) => void
18
+ }
19
+
20
+ /**
21
+ * Button prop validation schema
22
+ */
23
+ export const buttonPropSchema: PropSchema = {
24
+ variant: PropTypes.oneOf(['primary', 'secondary', 'outline', 'ghost', 'danger']),
25
+ size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
26
+ disabled: PropTypes.boolean,
27
+ loading: PropTypes.boolean,
28
+ type: PropTypes.oneOf(['button', 'submit', 'reset']),
29
+ fullWidth: PropTypes.boolean,
30
+ leftIcon: PropTypes.string,
31
+ rightIcon: PropTypes.string,
32
+ className: PropTypes.string,
33
+ onClick: PropTypes.func,
34
+ }
35
+
36
+ /**
37
+ * Validate Button component props
38
+ * Only runs in development mode
39
+ */
40
+ export const validateButtonProps: (props: Record<string, any>) => ValidationResult = createPropValidator('Button', buttonPropSchema)
41
+
42
+ /**
43
+ * Create a safe onClick handler that catches and reports errors
44
+ *
45
+ * @param handler - Click handler function
46
+ * @returns Wrapped handler with error handling
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const safeHandler = createSafeClickHandler(() => {
51
+ * // Your click logic
52
+ * })
53
+ * ```
54
+ */
55
+ export function createSafeClickHandler(handler: (event: Event) => void): (event: Event) => void {
56
+ return wrapErrorHandler(handler, 'Button', 'onClick')
57
+ }
58
+
59
+ /**
60
+ * Helper to validate button variant
61
+ */
62
+ export function validateVariant(variant?: string): void {
63
+ if (variant && !['primary', 'secondary', 'outline', 'ghost', 'danger'].includes(variant)) {
64
+ throw ErrorTypes.invalidProp(
65
+ 'Button',
66
+ 'variant',
67
+ variant,
68
+ ['primary', 'secondary', 'outline', 'ghost', 'danger'],
69
+ )
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Helper to validate button size
75
+ */
76
+ export function validateSize(size?: string): void {
77
+ if (size && !['xs', 'sm', 'md', 'lg', 'xl'].includes(size)) {
78
+ throw ErrorTypes.invalidProp(
79
+ 'Button',
80
+ 'size',
81
+ size,
82
+ ['xs', 'sm', 'md', 'lg', 'xl'],
83
+ )
84
+ }
85
+ }