@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,204 @@
1
+ # Select Component
2
+
3
+ A styled native select dropdown with support for labels, validation, and dark mode.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @stacksjs/components
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Select
14
+
15
+ ```stx
16
+ <script>
17
+ export const options = [
18
+ { value: 'option1', label: 'Option 1' },
19
+ { value: 'option2', label: 'Option 2' },
20
+ { value: 'option3', label: 'Option 3' },
21
+ ]
22
+
23
+ export const selected = 'option1'
24
+
25
+ export const handleChange = (value) => {
26
+ console.log('Selected:', value)
27
+ selected = value
28
+ }
29
+ </script>
30
+
31
+ @component('Select', {
32
+ value: selected,
33
+ onChange: handleChange,
34
+ options: options,
35
+ placeholder: 'Choose an option'
36
+ })
37
+ @endcomponent
38
+ ```
39
+
40
+ ### With Label and Helper Text
41
+
42
+ ```stx
43
+ @component('Select', {
44
+ label: 'Country',
45
+ helperText: 'Select your country of residence',
46
+ value: country,
47
+ onChange: (val) => country = val,
48
+ options: countries,
49
+ required: true
50
+ })
51
+ @endcomponent
52
+ ```
53
+
54
+ ### With Error State
55
+
56
+ ```stx
57
+ @component('Select', {
58
+ label: 'Category',
59
+ value: category,
60
+ onChange: (val) => category = val,
61
+ options: categories,
62
+ error: true,
63
+ helperText: 'Please select a valid category',
64
+ required: true
65
+ })
66
+ @endcomponent
67
+ ```
68
+
69
+ ### Different Sizes
70
+
71
+ ```stx
72
+ <!-- Small -->
73
+ @component('Select', {
74
+ size: 'sm',
75
+ options: options
76
+ })
77
+ @endcomponent
78
+
79
+ <!-- Medium (default) -->
80
+ @component('Select', {
81
+ size: 'md',
82
+ options: options
83
+ })
84
+ @endcomponent
85
+
86
+ <!-- Large -->
87
+ @component('Select', {
88
+ size: 'lg',
89
+ options: options
90
+ })
91
+ @endcomponent
92
+ ```
93
+
94
+ ### Disabled State
95
+
96
+ ```stx
97
+ @component('Select', {
98
+ disabled: true,
99
+ value: 'locked',
100
+ options: options
101
+ })
102
+ @endcomponent
103
+ ```
104
+
105
+ ### With Disabled Options
106
+
107
+ ```stx
108
+ <script>
109
+ export const options = [
110
+ { value: '1', label: 'Available Option' },
111
+ { value: '2', label: 'Disabled Option', disabled: true },
112
+ { value: '3', label: 'Another Available' },
113
+ ]
114
+ </script>
115
+
116
+ @component('Select', {
117
+ options: options
118
+ })
119
+ @endcomponent
120
+ ```
121
+
122
+ ## Props
123
+
124
+ | Prop | Type | Default | Description |
125
+ |------|------|---------|-------------|
126
+ | `value` | `string \| number` | `''` | Selected value |
127
+ | `onChange` | `function` | - | Callback when selection changes |
128
+ | `options` | `SelectOption[]` | `[]` | Array of options |
129
+ | `placeholder` | `string` | `'Select an option'` | Placeholder text |
130
+ | `disabled` | `boolean` | `false` | Disable the select |
131
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Select size |
132
+ | `error` | `boolean` | `false` | Show error state |
133
+ | `label` | `string` | `''` | Label text |
134
+ | `helperText` | `string` | `''` | Helper/error text below select |
135
+ | `required` | `boolean` | `false` | Mark as required |
136
+ | `className` | `string` | `''` | Additional CSS classes |
137
+
138
+ ## SelectOption Interface
139
+
140
+ ```typescript
141
+ interface SelectOption {
142
+ value: string | number
143
+ label: string
144
+ disabled?: boolean
145
+ }
146
+ ```
147
+
148
+ ## Features
149
+
150
+ - **Native select** - Uses native `<select>` element for best UX
151
+ - **3 sizes** - Small, medium, and large
152
+ - **Dark mode** - Full dark mode support
153
+ - **Validation states** - Error and required states
154
+ - **Disabled options** - Individual options can be disabled
155
+ - **Labels and helpers** - Support for labels and helper text
156
+ - **Accessible** - Proper ARIA attributes and labels
157
+ - **Keyboard navigation** - Full keyboard support
158
+ - **Modern ES modules** - Clean export syntax
159
+ - **Headwind styling** - Utility-first CSS classes
160
+
161
+ ## Accessibility
162
+
163
+ - Proper `label` associations with `for` attribute
164
+ - `aria-invalid` for error states
165
+ - `aria-describedby` for helper text
166
+ - Required field indicator
167
+ - Disabled state properly communicated
168
+ - Keyboard navigable
169
+
170
+ ## Example: Form Select
171
+
172
+ ```stx
173
+ <script>
174
+ export const countries = [
175
+ { value: 'us', label: 'United States' },
176
+ { value: 'ca', label: 'Canada' },
177
+ { value: 'mx', label: 'Mexico' },
178
+ { value: 'uk', label: 'United Kingdom' },
179
+ { value: 'de', label: 'Germany' },
180
+ ]
181
+
182
+ export let selectedCountry = ''
183
+ export let hasError = false
184
+
185
+ export const handleCountryChange = (value) => {
186
+ selectedCountry = value
187
+ hasError = !value
188
+ }
189
+ </script>
190
+
191
+ <form>
192
+ @component('Select', {
193
+ label: 'Country',
194
+ value: selectedCountry,
195
+ onChange: handleCountryChange,
196
+ options: countries,
197
+ placeholder: 'Select your country',
198
+ required: true,
199
+ error: hasError,
200
+ helperText: hasError ? 'Country is required' : 'Choose your country'
201
+ })
202
+ @endcomponent
203
+ </form>
204
+ ```
@@ -0,0 +1,89 @@
1
+ <script>
2
+ export const value = $props.value || ''
3
+ export const onChange = $props.onChange || (() => {})
4
+ export const options = $props.options || []
5
+ export const placeholder = $props.placeholder || 'Select an option'
6
+ export const disabled = $props.disabled || false
7
+ export const size = $props.size || 'md'
8
+ export const error = $props.error || false
9
+ export const label = $props.label || ''
10
+ export const helperText = $props.helperText || ''
11
+ export const required = $props.required || false
12
+ export const className = $props.className || ''
13
+
14
+ // Size classes
15
+ const sizeClasses = {
16
+ sm: 'px-3 py-1.5 text-sm h-8',
17
+ md: 'px-4 py-2 text-base h-10',
18
+ lg: 'px-5 py-3 text-lg h-12',
19
+ }
20
+
21
+ // Base and state classes
22
+ const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset dark:bg-blue-gray-700 dark:text-gray-100'
23
+
24
+ const stateClasses = error
25
+ ? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
26
+ : 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
27
+
28
+ const disabledClasses = disabled
29
+ ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
30
+ : 'bg-white dark:bg-blue-gray-700 cursor-pointer hover:ring-gray-400 dark:hover:ring-gray-500'
31
+
32
+ export const selectClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${className}`.trim()
33
+ export const labelClasses = `block text-sm font-medium leading-6 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
34
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
35
+ </script>
36
+
37
+ <div class="w-full">
38
+ @if(label)
39
+ <label for="select-{{ value }}" class="{{ labelClasses }}">
40
+ {{ label }}
41
+ @if(required)
42
+ <span class="text-red-500 ml-1">*</span>
43
+ @endif
44
+ </label>
45
+ @endif
46
+
47
+ <div class="{{ label ? 'mt-2' : '' }}">
48
+ <select
49
+ id="select-{{ value }}"
50
+ class="{{ selectClasses }}"
51
+ value="{{ value }}"
52
+ disabled="{{ disabled }}"
53
+ required="{{ required }}"
54
+ onchange="handleChange(event)"
55
+ aria-invalid="{{ error ? 'true' : 'false' }}"
56
+ aria-describedby="{{ helperText ? 'helper-text' : '' }}"
57
+ >
58
+ @if(placeholder)
59
+ <option value="" disabled selected>{{ placeholder }}</option>
60
+ @endif
61
+
62
+ @foreach(option in options)
63
+ <option
64
+ value="{{ option.value }}"
65
+ selected="{{ option.value === value }}"
66
+ disabled="{{ option.disabled }}"
67
+ >
68
+ {{ option.label }}
69
+ </option>
70
+ @endforeach
71
+ </select>
72
+ </div>
73
+
74
+ @if(helperText)
75
+ <p id="helper-text" class="{{ helperClasses }}">
76
+ {{ helperText }}
77
+ </p>
78
+ @endif
79
+ </div>
80
+
81
+ <script>
82
+ function handleChange(event) {
83
+ const newValue = event.target.value
84
+
85
+ if (onChange) {
86
+ onChange(newValue)
87
+ }
88
+ }
89
+ </script>
@@ -0,0 +1,21 @@
1
+ export { default as Select } from './Select.stx'
2
+
3
+ export interface SelectOption {
4
+ value: string | number
5
+ label: string
6
+ disabled?: boolean
7
+ }
8
+
9
+ export interface SelectProps {
10
+ value?: string | number
11
+ onChange?: (value: string | number) => void
12
+ options?: SelectOption[]
13
+ placeholder?: string
14
+ disabled?: boolean
15
+ size?: 'sm' | 'md' | 'lg'
16
+ error?: boolean
17
+ label?: string
18
+ helperText?: string
19
+ required?: boolean
20
+ className?: string
21
+ }
@@ -0,0 +1,288 @@
1
+ <script>
2
+ /**
3
+ * Sidebar Component - macOS Native Style
4
+ *
5
+ * A native-feeling sidebar component that integrates with Craft for true native rendering
6
+ * when running in a Craft desktop environment, with beautiful macOS Tahoe-style fallback
7
+ * for web environments.
8
+ *
9
+ * @example
10
+ * <Sidebar
11
+ * :sections="sections"
12
+ * :collapsed="false"
13
+ * :width="240"
14
+ * variant="tahoe"
15
+ * >
16
+ * <template #header>
17
+ * <SidebarHeader title="My App" />
18
+ * </template>
19
+ * <template #footer>
20
+ * <SidebarFooter />
21
+ * </template>
22
+ * </Sidebar>
23
+ */
24
+
25
+ // Props
26
+ export const sections = $props.sections || []
27
+ export const collapsed = $props.collapsed ?? false
28
+ export const collapsible = $props.collapsible ?? true
29
+ export const width = $props.width || 240
30
+ export const minWidth = $props.minWidth || 64
31
+ export const variant = $props.variant || 'tahoe' // 'tahoe' | 'vibrancy' | 'solid' | 'transparent'
32
+ export const position = $props.position || 'left' // 'left' | 'right'
33
+ export const bordered = $props.bordered ?? true
34
+ export const className = $props.className || ''
35
+ export const onCollapse = $props.onCollapse
36
+ export const onSectionToggle = $props.onSectionToggle
37
+ export const onItemClick = $props.onItemClick
38
+
39
+ // Internal state
40
+ let isHovered = false
41
+ let nativeSidebarId = null
42
+
43
+ // Check if running in Craft environment with native sidebar enabled
44
+ // When Craft uses --native-sidebar, it sets these flags and we should NOT render the web sidebar
45
+ const hasNativeSidebar = typeof window !== 'undefined' && (
46
+ window.__craftNativeSidebar === true ||
47
+ window.craft?.hasNativeSidebar?.() ||
48
+ (window.webkit?.messageHandlers?.craft && document.body?.dataset?.nativeSidebar === 'true')
49
+ )
50
+
51
+ // Check if running in Craft environment (may not have native sidebar)
52
+ const isCraft = typeof window !== 'undefined' && window.craft?.isCraft?.()
53
+
54
+ // Variant styles - macOS Tahoe inspired
55
+ // Native macOS sidebars use vibrancy where desktop background shines through
56
+ const variantStyles = {
57
+ tahoe: {
58
+ // Translucent with warm tint overlay - desktop shows through
59
+ bg: 'bg-white/70 dark:bg-black/50',
60
+ border: 'border-black/5 dark:border-white/10',
61
+ backdrop: 'backdrop-blur-2xl backdrop-saturate-180',
62
+ // Warm tint is applied via pseudo-element in template
63
+ tint: true
64
+ },
65
+ vibrancy: {
66
+ bg: 'bg-white/50 dark:bg-black/40',
67
+ border: 'border-white/20 dark:border-white/10',
68
+ backdrop: 'backdrop-blur-3xl backdrop-saturate-200',
69
+ tint: false
70
+ },
71
+ solid: {
72
+ bg: 'bg-stone-100 dark:bg-neutral-900',
73
+ border: 'border-stone-200 dark:border-neutral-800',
74
+ backdrop: '',
75
+ tint: false
76
+ },
77
+ transparent: {
78
+ bg: 'bg-transparent',
79
+ border: 'border-transparent',
80
+ backdrop: '',
81
+ tint: false
82
+ }
83
+ }
84
+
85
+ // Get current variant style
86
+ function getVariantStyle() {
87
+ return variantStyles[variant] || variantStyles.tahoe
88
+ }
89
+
90
+ // Calculate sidebar width
91
+ function getSidebarWidth() {
92
+ if (collapsed && !isHovered) {
93
+ return `${minWidth}px`
94
+ }
95
+ return `${width}px`
96
+ }
97
+
98
+ // Check if showing expanded content
99
+ function showExpanded() {
100
+ return !collapsed || isHovered
101
+ }
102
+
103
+ // Initialize Craft native sidebar if available
104
+ async function initNativeSidebar() {
105
+ if (isCraft && window.craft?.components?.createSidebar) {
106
+ try {
107
+ const config = {
108
+ position,
109
+ width,
110
+ minWidth,
111
+ collapsible,
112
+ sections: sections.map(section => ({
113
+ id: section.id,
114
+ label: section.label,
115
+ items: section.items?.map(item => ({
116
+ id: item.id,
117
+ label: item.label,
118
+ icon: item.icon,
119
+ href: item.href,
120
+ badge: item.badge
121
+ }))
122
+ }))
123
+ }
124
+ nativeSidebarId = await window.craft.components.createSidebar(config)
125
+ } catch (err) {
126
+ console.warn('[Sidebar] Failed to create native sidebar, using web fallback:', err)
127
+ }
128
+ }
129
+ }
130
+
131
+ // Handle collapse toggle
132
+ function handleCollapseToggle() {
133
+ if (onCollapse) {
134
+ onCollapse(!collapsed)
135
+ }
136
+ }
137
+
138
+ // Handle mouse enter/leave for hover expand
139
+ function handleMouseEnter() {
140
+ if (collapsed && collapsible) {
141
+ isHovered = true
142
+ }
143
+ }
144
+
145
+ function handleMouseLeave() {
146
+ isHovered = false
147
+ }
148
+
149
+ // Handle section toggle
150
+ function handleSectionToggle(sectionId) {
151
+ if (onSectionToggle) {
152
+ onSectionToggle(sectionId)
153
+ }
154
+ }
155
+
156
+ // Handle item click
157
+ function handleItemClick(item, event) {
158
+ if (onItemClick) {
159
+ onItemClick(item, event)
160
+ }
161
+ }
162
+
163
+ // Build container classes
164
+ const style = getVariantStyle()
165
+
166
+ // Build border classes properly for Tailwind
167
+ function getBorderClasses() {
168
+ if (!bordered) return ''
169
+ const borderSide = position === 'left' ? 'border-r' : 'border-l'
170
+ return `${borderSide} ${style.border}`
171
+ }
172
+
173
+ const containerClasses = [
174
+ 'fixed inset-y-0 z-50 flex flex-col',
175
+ 'transition-all duration-300 ease-out',
176
+ 'overflow-hidden', // Contain the tint overlay
177
+ style.bg,
178
+ style.backdrop,
179
+ getBorderClasses(),
180
+ position === 'left' ? 'left-0' : 'right-0',
181
+ className
182
+ ].filter(Boolean).join(' ')
183
+
184
+ // Initialize native sidebar on mount
185
+ if (typeof window !== 'undefined') {
186
+ initNativeSidebar()
187
+ }
188
+ </script>
189
+
190
+ <!-- Only render web sidebar when NOT running in Craft native sidebar mode -->
191
+ @if(!hasNativeSidebar)
192
+ <aside
193
+ class="{{ containerClasses }} sidebar-container"
194
+ style="width: {{ getSidebarWidth() }}"
195
+ @mouseenter="handleMouseEnter"
196
+ @mouseleave="handleMouseLeave"
197
+ role="navigation"
198
+ aria-label="Sidebar navigation"
199
+ >
200
+ <!-- Warm tint overlay for macOS Tahoe effect - desktop shows through -->
201
+ @if(style.tint)
202
+ <div class="absolute inset-0 pointer-events-none bg-gradient-to-b from-amber-50/30 via-orange-50/20 to-stone-100/30 dark:from-neutral-800/20 dark:via-neutral-900/10 dark:to-neutral-800/20 mix-blend-overlay"></div>
203
+ @endif
204
+
205
+ <!-- Header slot -->
206
+ @if($slots.header)
207
+ <div class="flex-shrink-0 relative z-10">
208
+ <slot name="header" />
209
+ </div>
210
+ @endif
211
+
212
+ <!-- Main content area with sections -->
213
+ <div class="flex-1 overflow-y-auto overflow-x-hidden relative z-10">
214
+ @if(sections.length > 0)
215
+ <nav class="px-3 py-2 space-y-1">
216
+ @foreach(sections as section)
217
+ <SidebarSection
218
+ :id="section.id"
219
+ :label="section.label"
220
+ :icon="section.icon"
221
+ :items="section.items"
222
+ :expanded="section.expanded !== false"
223
+ :collapsible="section.collapsible !== false"
224
+ :showLabel="showExpanded()"
225
+ @toggle="handleSectionToggle(section.id)"
226
+ @itemClick="handleItemClick"
227
+ />
228
+ @endforeach
229
+ </nav>
230
+ @else
231
+ <!-- Default slot for custom content -->
232
+ <div class="px-3 py-2">
233
+ <slot />
234
+ </div>
235
+ @endif
236
+ </div>
237
+
238
+ <!-- Footer slot -->
239
+ @if($slots.footer)
240
+ <div class="flex-shrink-0 relative z-10">
241
+ <slot name="footer" />
242
+ </div>
243
+ @endif
244
+
245
+ <!-- Collapse toggle button -->
246
+ @if(collapsible && showExpanded())
247
+ <button
248
+ type="button"
249
+ class="absolute top-4 {{ position === 'left' ? 'right-2' : 'left-2' }} p-1.5 rounded-lg text-stone-400 hover:text-stone-600 hover:bg-black/5 dark:hover:text-neutral-300 dark:hover:bg-white/10 transition-colors z-20"
250
+ @click="handleCollapseToggle"
251
+ aria-label="{{ collapsed ? 'Expand sidebar' : 'Collapse sidebar' }}"
252
+ >
253
+ <div class="{{ collapsed ? 'i-hugeicons-sidebar-right' : 'i-hugeicons-sidebar-left' }} w-5 h-5"></div>
254
+ </button>
255
+ @endif
256
+ </aside>
257
+ @endif
258
+
259
+ <style scoped>
260
+ /* Smooth scrollbar styling for macOS feel */
261
+ .overflow-y-auto::-webkit-scrollbar {
262
+ width: 6px;
263
+ }
264
+
265
+ .overflow-y-auto::-webkit-scrollbar-track {
266
+ background: transparent;
267
+ }
268
+
269
+ .overflow-y-auto::-webkit-scrollbar-thumb {
270
+ background-color: rgba(0, 0, 0, 0.15);
271
+ border-radius: 3px;
272
+ }
273
+
274
+ .overflow-y-auto::-webkit-scrollbar-thumb:hover {
275
+ background-color: rgba(0, 0, 0, 0.25);
276
+ }
277
+
278
+ /* Dark mode scrollbar */
279
+ @media (prefers-color-scheme: dark) {
280
+ .overflow-y-auto::-webkit-scrollbar-thumb {
281
+ background-color: rgba(255, 255, 255, 0.15);
282
+ }
283
+
284
+ .overflow-y-auto::-webkit-scrollbar-thumb:hover {
285
+ background-color: rgba(255, 255, 255, 0.25);
286
+ }
287
+ }
288
+ </style>
@@ -0,0 +1,95 @@
1
+ <script>
2
+ /**
3
+ * SidebarFooter Component
4
+ *
5
+ * A footer component for the sidebar with quick actions and settings.
6
+ *
7
+ * @example
8
+ * <SidebarFooter
9
+ * :showSettings="true"
10
+ * :showThemeToggle="true"
11
+ * settingsHref="/settings"
12
+ * />
13
+ */
14
+
15
+ // Props
16
+ export const showSettings = $props.showSettings ?? true
17
+ export const showThemeToggle = $props.showThemeToggle ?? true
18
+ export const settingsHref = $props.settingsHref || '/settings'
19
+ export const settingsLabel = $props.settingsLabel || 'Settings'
20
+ export const collapsed = $props.collapsed ?? false
21
+ export const onThemeToggle = $props.onThemeToggle
22
+
23
+ // Quick action items
24
+ export const actions = $props.actions || []
25
+
26
+ // Handle theme toggle
27
+ function handleThemeToggle() {
28
+ if (onThemeToggle) {
29
+ onThemeToggle()
30
+ } else {
31
+ // Default theme toggle behavior
32
+ document.documentElement.classList.toggle('dark')
33
+ }
34
+ }
35
+ </script>
36
+
37
+ <div class="border-t border-black/5 dark:border-white/10 p-3 space-y-2">
38
+ <!-- Custom actions slot -->
39
+ <slot />
40
+
41
+ <!-- Quick actions row -->
42
+ @if(!collapsed && actions.length > 0)
43
+ <div class="flex items-center gap-2">
44
+ @foreach(actions as action)
45
+ @if(action.href)
46
+ <a
47
+ href="{{ action.href }}"
48
+ class="flex-1 flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-black/70 dark:text-white/70 hover:bg-black/5 dark:hover:bg-white/10 transition-colors"
49
+ >
50
+ @if(action.icon)
51
+ <div class="{{ action.icon }} w-4 h-4"></div>
52
+ @endif
53
+ <span>{{ action.label }}</span>
54
+ </a>
55
+ @else
56
+ <button
57
+ type="button"
58
+ class="flex-1 flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-black/70 dark:text-white/70 hover:bg-black/5 dark:hover:bg-white/10 transition-colors"
59
+ @click="action.onClick"
60
+ >
61
+ @if(action.icon)
62
+ <div class="{{ action.icon }} w-4 h-4"></div>
63
+ @endif
64
+ <span>{{ action.label }}</span>
65
+ </button>
66
+ @endif
67
+ @endforeach
68
+
69
+ @if(showThemeToggle)
70
+ <button
71
+ type="button"
72
+ class="p-2 rounded-lg text-black/50 hover:text-black/80 hover:bg-black/5 dark:text-white/50 dark:hover:text-white/80 dark:hover:bg-white/10 transition-colors"
73
+ @click="handleThemeToggle"
74
+ aria-label="Toggle dark mode"
75
+ >
76
+ <div class="i-hugeicons-moon-02 w-4 h-4 dark:hidden"></div>
77
+ <div class="i-hugeicons-sun-02 w-4 h-4 hidden dark:block"></div>
78
+ </button>
79
+ @endif
80
+ </div>
81
+ @endif
82
+
83
+ <!-- Settings link -->
84
+ @if(showSettings)
85
+ <a
86
+ href="{{ settingsHref }}"
87
+ class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors duration-150 text-black/70 dark:text-white/70 hover:bg-black/5 dark:hover:bg-white/10"
88
+ >
89
+ <div class="i-hugeicons-settings-02 w-5 h-5 text-black/50 dark:text-white/50"></div>
90
+ @if(!collapsed)
91
+ <span>{{ settingsLabel }}</span>
92
+ @endif
93
+ </a>
94
+ @endif
95
+ </div>