@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,39 @@
1
+ <script>
2
+ import { CodeBlock } from './CodeBlock.stx'
3
+
4
+ export const packageName = $props.packageName || '@stacksjs/component'
5
+ export const installCode = `bun add ${packageName}`
6
+ export const npmCode = `npm install ${packageName}`
7
+ export const pnpmCode = `pnpm add ${packageName}`
8
+ export const yarnCode = `yarn add ${packageName}`
9
+ </script>
10
+
11
+ <div class="installation">
12
+ <h2 class="my-2 text-lg font-semibold">Installation</h2>
13
+
14
+ <p class="my-3 text-base">
15
+ Install the component using your preferred package manager:
16
+ </p>
17
+
18
+ <div class="space-y-4">
19
+ <div>
20
+ <h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Bun (recommended)</h3>
21
+ @component('CodeBlock', { code: installCode, language: 'bash' })
22
+ </div>
23
+
24
+ <div>
25
+ <h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">npm</h3>
26
+ @component('CodeBlock', { code: npmCode, language: 'bash' })
27
+ </div>
28
+
29
+ <div>
30
+ <h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">pnpm</h3>
31
+ @component('CodeBlock', { code: pnpmCode, language: 'bash' })
32
+ </div>
33
+
34
+ <div>
35
+ <h3 class="text-sm font-medium mb-2 text-neutral-700 dark:text-neutral-300">Yarn</h3>
36
+ @component('CodeBlock', { code: yarnCode, language: 'bash' })
37
+ </div>
38
+ </div>
39
+ </div>
@@ -0,0 +1,14 @@
1
+ <script>
2
+ export const value = $props.value
3
+ export const onChange = $props.onChange
4
+ export const multiple = $props.multiple || false
5
+ export const className = $props.className || ''
6
+ export const as = $props.as || 'div'
7
+
8
+ const baseClasses = 'relative'
9
+ const listboxClasses = `${baseClasses} ${className}`.trim()
10
+ </script>
11
+
12
+ <component :is="{{ as }}" class="{{ listboxClasses }}">
13
+ <slot :value="value" :onChange="onChange" :multiple="multiple" />
14
+ </component>
@@ -0,0 +1,17 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'button'
4
+ export const disabled = $props.disabled || false
5
+
6
+ const baseClasses = 'relative w-full cursor-pointer rounded-lg bg-white dark:bg-neutral-800 py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-blue-300'
7
+ const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
8
+ const buttonClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
9
+ </script>
10
+
11
+ <component
12
+ :is="{{ as }}"
13
+ class="{{ buttonClasses }}"
14
+ @if(disabled)disabled aria-disabled="true"@endif
15
+ >
16
+ <slot />
17
+ </component>
@@ -0,0 +1,11 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'label'
4
+
5
+ const baseClasses = 'block text-sm font-medium text-neutral-900 dark:text-white'
6
+ const labelClasses = `${baseClasses} ${className}`.trim()
7
+ </script>
8
+
9
+ <component :is="{{ as }}" class="{{ labelClasses }}">
10
+ <slot />
11
+ </component>
@@ -0,0 +1,57 @@
1
+ <script>
2
+ export const value = $props.value
3
+ export const disabled = $props.disabled || false
4
+ export const className = $props.className || ''
5
+ export const as = $props.as || 'li'
6
+ export const currentValue = $props.currentValue
7
+ export const onChange = $props.onChange
8
+
9
+ export let active = false
10
+ export const selected = Array.isArray(currentValue)
11
+ ? currentValue.includes(value)
12
+ : currentValue === value
13
+
14
+ const baseClasses = 'relative cursor-pointer select-none py-2 pl-10 pr-4'
15
+ const stateClasses = active
16
+ ? 'bg-blue-100 text-blue-900 dark:bg-blue-900 dark:text-blue-100'
17
+ : 'text-neutral-900 dark:text-neutral-100'
18
+ const disabledClasses = disabled
19
+ ? 'opacity-50 cursor-not-allowed'
20
+ : ''
21
+
22
+ const optionClasses = `${baseClasses} ${stateClasses} ${disabledClasses} ${className}`.trim()
23
+
24
+ export function handleClick() {
25
+ if (disabled) return
26
+ onChange?.(value)
27
+ }
28
+
29
+ export function handleMouseEnter() {
30
+ if (!disabled) active = true
31
+ }
32
+
33
+ export function handleMouseLeave() {
34
+ active = false
35
+ }
36
+ </script>
37
+
38
+ <component
39
+ :is="{{ as }}"
40
+ class="{{ optionClasses }}"
41
+ role="option"
42
+ aria-selected="{{ selected ? 'true' : 'false' }}"
43
+ @if(disabled)aria-disabled="true"@endif
44
+ @click="handleClick"
45
+ @mouseenter="handleMouseEnter"
46
+ @mouseleave="handleMouseLeave"
47
+ >
48
+ @if(selected)
49
+ <span class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600 dark:text-blue-400">
50
+ <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
51
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
52
+ </svg>
53
+ </span>
54
+ @endif
55
+
56
+ <slot :active="active" :selected="selected" :disabled="disabled" />
57
+ </component>
@@ -0,0 +1,16 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'ul'
4
+ export const static_ = $props.static || false
5
+
6
+ const baseClasses = 'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-neutral-800 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'
7
+ const optionsClasses = `${baseClasses} ${className}`.trim()
8
+ </script>
9
+
10
+ <component
11
+ :is="{{ as }}"
12
+ class="{{ optionsClasses }}"
13
+ role="listbox"
14
+ >
15
+ <slot />
16
+ </component>
@@ -0,0 +1,163 @@
1
+ <script>
2
+ export const showLogo = $props.showLogo ?? true
3
+ export const headingText = $props.headingText || 'Sign in to your account'
4
+ export const showSocialLogin = $props.showSocialLogin ?? true
5
+ export const showRememberMe = $props.showRememberMe ?? true
6
+ export const showForgotPassword = $props.showForgotPassword ?? true
7
+ export const showSignup = $props.showSignup ?? true
8
+ export const signupText = $props.signupText || 'Start a 14 day free trial'
9
+ export const onSubmit = $props.onSubmit || (() => {})
10
+ export const className = $props.className || ''
11
+
12
+ export const containerClasses = `min-h-full flex flex-col justify-center py-12 lg:px-8 sm:px-6 dark:bg-blue-gray-900 ${className}`.trim()
13
+ </script>
14
+
15
+ <div class="{{ containerClasses }}">
16
+ <div class="sm:mx-auto sm:max-w-md sm:w-full">
17
+ @if(showLogo)
18
+ <img src="/logo.svg" alt="Logo" class="mx-auto h-11 w-auto" />
19
+ @endif
20
+ <h2 class="mt-6 text-center text-2xl text-gray-900 dark:text-gray-100 font-bold leading-9 tracking-tight">
21
+ {{ headingText }}
22
+ </h2>
23
+ </div>
24
+
25
+ <form onsubmit="event.preventDefault(); handleSubmit(event)">
26
+ <div class="mt-10 sm:mx-auto sm:max-w-[480px] sm:w-full">
27
+ <div class="bg-white dark:bg-blue-gray-800 px-6 py-12 shadow sm:rounded-lg sm:px-12">
28
+ <div class="space-y-6">
29
+ <div>
30
+ <label for="email" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
31
+ Email address
32
+ </label>
33
+ <div class="mt-2">
34
+ <input
35
+ id="email"
36
+ name="email"
37
+ type="email"
38
+ autocomplete="email"
39
+ required
40
+ class="block w-full border-0 rounded-md py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-indigo-600 focus:ring-inset dark:bg-blue-gray-700"
41
+ />
42
+ </div>
43
+ </div>
44
+
45
+ <div>
46
+ <label for="password" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
47
+ Password
48
+ </label>
49
+ <div class="mt-2">
50
+ <input
51
+ id="password"
52
+ name="password"
53
+ type="password"
54
+ autocomplete="current-password"
55
+ required
56
+ class="block w-full border-0 rounded-md py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-indigo-600 focus:ring-inset dark:bg-blue-gray-700"
57
+ />
58
+ </div>
59
+ </div>
60
+
61
+ <div class="flex items-center justify-between">
62
+ @if(showRememberMe)
63
+ <div class="flex items-center">
64
+ <input
65
+ id="remember-me"
66
+ name="remember-me"
67
+ type="checkbox"
68
+ class="h-4 w-4 border-gray-300 dark:border-gray-600 rounded text-indigo-600 focus:ring-indigo-600 dark:bg-blue-gray-700"
69
+ />
70
+ <label for="remember-me" class="ml-3 block text-sm text-gray-900 dark:text-gray-100 leading-6">
71
+ Remember me
72
+ </label>
73
+ </div>
74
+ @endif
75
+
76
+ @if(showForgotPassword)
77
+ <div class="text-sm leading-6">
78
+ <a href="#" class="text-indigo-600 dark:text-indigo-400 font-semibold hover:text-indigo-500 dark:hover:text-indigo-300">
79
+ Forgot password?
80
+ </a>
81
+ </div>
82
+ @endif
83
+ </div>
84
+
85
+ <div>
86
+ <button
87
+ type="submit"
88
+ class="w-full flex justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm text-white font-semibold leading-6 shadow-sm hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-indigo-600 focus-visible:outline-offset-2 focus-visible:outline"
89
+ >
90
+ Sign in
91
+ </button>
92
+ </div>
93
+ </div>
94
+
95
+ @if(showSocialLogin)
96
+ <div>
97
+ <div class="relative mt-10">
98
+ <div class="absolute inset-0 flex items-center" aria-hidden="true">
99
+ <div class="w-full border-t border-gray-200 dark:border-gray-600"></div>
100
+ </div>
101
+ <div class="relative flex justify-center text-sm font-medium leading-6">
102
+ <span class="bg-white dark:bg-blue-gray-800 px-6 text-gray-900 dark:text-gray-100">
103
+ Or continue with
104
+ </span>
105
+ </div>
106
+ </div>
107
+
108
+ <div class="grid grid-cols-2 mt-6 gap-4">
109
+ <a
110
+ href="#"
111
+ class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
112
+ >
113
+ <svg class="h-5 w-5" viewBox="0 0 24 24" aria-hidden="true">
114
+ <path d="M12.0003 4.75C13.7703 4.75 15.3553 5.36002 16.6053 6.54998L20.0303 3.125C17.9502 1.19 15.2353 0 12.0003 0C7.31028 0 3.25527 2.69 1.28027 6.60998L5.27028 9.70498C6.21525 6.86002 8.87028 4.75 12.0003 4.75Z" fill="#EA4335" />
115
+ <path d="M23.49 12.275C23.49 11.49 23.415 10.73 23.3 10H12V14.51H18.47C18.18 15.99 17.34 17.25 16.08 18.1L19.945 21.1C22.2 19.01 23.49 15.92 23.49 12.275Z" fill="#4285F4" />
116
+ <path d="M5.26498 14.2949C5.02498 13.5699 4.88501 12.7999 4.88501 11.9999C4.88501 11.1999 5.01998 10.4299 5.26498 9.7049L1.275 6.60986C0.46 8.22986 0 10.0599 0 11.9999C0 13.9399 0.46 15.7699 1.28 17.3899L5.26498 14.2949Z" fill="#FBBC05" />
117
+ <path d="M12.0004 24.0001C15.2404 24.0001 17.9654 22.935 19.9454 21.095L16.0804 18.095C15.0054 18.82 13.6204 19.245 12.0004 19.245C8.8704 19.245 6.21537 17.135 5.2654 14.29L1.27539 17.385C3.25539 21.31 7.3104 24.0001 12.0004 24.0001Z" fill="#34A853" />
118
+ </svg>
119
+ <span class="text-sm font-semibold leading-6">Google</span>
120
+ </a>
121
+
122
+ <a
123
+ href="#"
124
+ class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
125
+ >
126
+ <svg class="h-5 w-5 fill-[#24292F]" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
127
+ <path fill-rule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clip-rule="evenodd" />
128
+ </svg>
129
+ <span class="text-sm font-semibold leading-6">GitHub</span>
130
+ </a>
131
+ </div>
132
+ </div>
133
+ @endif
134
+ </div>
135
+
136
+ @if(showSignup)
137
+ <p class="mt-10 text-center text-sm text-gray-500 dark:text-gray-400">
138
+ Not a member?
139
+ <a href="#" class="text-indigo-600 dark:text-indigo-400 font-semibold leading-6 hover:text-indigo-500 dark:hover:text-indigo-300">
140
+ {{ signupText }}
141
+ </a>
142
+ </p>
143
+ @endif
144
+ </div>
145
+ </form>
146
+ </div>
147
+
148
+ <script>
149
+ function handleSubmit(event) {
150
+ const formData = new FormData(event.target)
151
+ const email = formData.get('email')
152
+ const password = formData.get('password')
153
+
154
+ if (onSubmit) {
155
+ onSubmit({ email, password })
156
+ }
157
+
158
+ // Clear password after submission
159
+ setTimeout(() => {
160
+ event.target.querySelector('#password').value = ''
161
+ }, 1000)
162
+ }
163
+ </script>
@@ -0,0 +1,138 @@
1
+ <script>
2
+ // Navigator Component Props
3
+ export const items = $props.items || []
4
+ export const active = $props.active || ''
5
+ export const orientation = $props.orientation || 'horizontal' // 'horizontal' | 'vertical'
6
+ export const variant = $props.variant || 'default' // 'default' | 'pills' | 'underline' | 'sidebar'
7
+ export const size = $props.size || 'md' // 'sm' | 'md' | 'lg'
8
+ export const onNavigate = $props.onNavigate
9
+ export const className = $props.className || ''
10
+
11
+ // Helper function to check if item is active
12
+ function isActive(item) {
13
+ if (typeof item.href === 'string' && typeof active === 'string') {
14
+ // Exact match
15
+ if (item.href === active) return true
16
+ // Match with query params/hash
17
+ if (active.startsWith(item.href)) return true
18
+ }
19
+ if (item.id && item.id === active) return true
20
+ return false
21
+ }
22
+
23
+ // Base classes
24
+ const containerBaseClasses = orientation === 'horizontal'
25
+ ? 'flex items-center'
26
+ : 'flex flex-col'
27
+
28
+ const containerClasses = `${containerBaseClasses} ${className}`.trim()
29
+
30
+ // Item classes based on variant and size
31
+ function getItemClasses(item) {
32
+ const active = isActive(item)
33
+ let classes = ''
34
+
35
+ // Size classes
36
+ const sizeClasses = {
37
+ sm: 'px-2 py-1 text-sm',
38
+ md: 'px-3 py-2 text-base',
39
+ lg: 'px-4 py-3 text-lg',
40
+ }
41
+
42
+ classes += sizeClasses[size] || sizeClasses.md
43
+
44
+ // Variant classes
45
+ if (variant === 'default') {
46
+ classes += active
47
+ ? ' text-gray-900 dark:text-gray-100 font-medium'
48
+ : ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
49
+ } else if (variant === 'pills') {
50
+ classes += active
51
+ ? ' bg-blue-600 text-white font-medium rounded-full'
52
+ : ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full'
53
+ } else if (variant === 'underline') {
54
+ classes += active
55
+ ? ' text-blue-600 dark:text-blue-400 font-medium border-b-2 border-blue-600 dark:border-blue-400'
56
+ : ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 border-b-2 border-transparent'
57
+ } else if (variant === 'sidebar') {
58
+ classes += active
59
+ ? ' bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-medium border-l-4 border-blue-600 dark:border-blue-400'
60
+ : ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 border-l-4 border-transparent'
61
+ }
62
+
63
+ // Common classes
64
+ classes += ' transition-all duration-200 cursor-pointer flex items-center gap-2'
65
+
66
+ if (item.disabled) {
67
+ classes += ' opacity-50 cursor-not-allowed pointer-events-none'
68
+ }
69
+
70
+ return classes.trim()
71
+ }
72
+
73
+ // Gap classes between items
74
+ const gapClasses = orientation === 'horizontal'
75
+ ? 'gap-1'
76
+ : 'gap-0.5'
77
+
78
+ function handleClick(item, event) {
79
+ if (item.disabled) {
80
+ event.preventDefault()
81
+ return
82
+ }
83
+
84
+ if (onNavigate) {
85
+ event.preventDefault()
86
+ onNavigate(item)
87
+ }
88
+ }
89
+ </script>
90
+
91
+ <nav class="{{ containerClasses }} {{ gapClasses }}" role="navigation" aria-label="Main navigation">
92
+ @foreach(item in items)
93
+ @if(item.href)
94
+ <a
95
+ href="{{ item.href }}"
96
+ class="{{ getItemClasses(item) }}"
97
+ onclick="handleClick(item, event)"
98
+ @if(isActive(item))
99
+ aria-current="page"
100
+ @endif
101
+ @if(item.disabled)
102
+ aria-disabled="true"
103
+ tabindex="-1"
104
+ @endif
105
+ >
106
+ @if(item.icon)
107
+ <span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
108
+ @endif
109
+ <span>{{ item.label }}</span>
110
+ @if(item.badge)
111
+ <span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
112
+ {{ item.badge }}
113
+ </span>
114
+ @endif
115
+ </a>
116
+ @else
117
+ <button
118
+ type="button"
119
+ class="{{ getItemClasses(item) }}"
120
+ onclick="handleClick(item, event)"
121
+ @if(item.disabled)
122
+ disabled
123
+ aria-disabled="true"
124
+ @endif
125
+ >
126
+ @if(item.icon)
127
+ <span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
128
+ @endif
129
+ <span>{{ item.label }}</span>
130
+ @if(item.badge)
131
+ <span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
132
+ {{ item.badge }}
133
+ </span>
134
+ @endif
135
+ </button>
136
+ @endif
137
+ @endforeach
138
+ </nav>
@@ -0,0 +1,71 @@
1
+ <script>
2
+ export const show = $props.show !== false
3
+ export const title = $props.title || ''
4
+ export const message = $props.message || ''
5
+ export const type = $props.type || 'info'
6
+ export const position = $props.position || 'top-right'
7
+ export const duration = $props.duration || 5000
8
+ export const onClose = $props.onClose
9
+ export const className = $props.className || ''
10
+
11
+ const typeColors = {
12
+ info: 'bg-blue-50 text-blue-900 dark:bg-blue-900 dark:text-blue-100',
13
+ success: 'bg-green-50 text-green-900 dark:bg-green-900 dark:text-green-100',
14
+ warning: 'bg-yellow-50 text-yellow-900 dark:bg-yellow-900 dark:text-yellow-100',
15
+ error: 'bg-red-50 text-red-900 dark:bg-red-900 dark:text-red-100',
16
+ }
17
+
18
+ const positions = {
19
+ 'top-left': 'top-0 left-0',
20
+ 'top-right': 'top-0 right-0',
21
+ 'top-center': 'top-0 left-1/2 -translate-x-1/2',
22
+ 'bottom-left': 'bottom-0 left-0',
23
+ 'bottom-right': 'bottom-0 right-0',
24
+ 'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2',
25
+ }
26
+
27
+ const baseClasses = 'fixed z-50 m-4 max-w-md w-full pointer-events-auto rounded-lg p-4 shadow-lg ring-1 ring-black ring-opacity-5 transition-all'
28
+ const notificationClasses = `${baseClasses} ${typeColors[type]} ${positions[position]} ${className}`.trim()
29
+
30
+ export function handleClose() {
31
+ onClose?.()
32
+ }
33
+ </script>
34
+
35
+ @if(show)
36
+ <div class="{{ notificationClasses }}" role="alert">
37
+ <div class="flex items-start">
38
+ <div class="flex-1">
39
+ @if(title)
40
+ <p class="text-sm font-medium">{{ title }}</p>
41
+ @endif
42
+ @if(message)
43
+ <p class="mt-1 text-sm {{ title ? 'opacity-90' : '' }}">{{ message }}</p>
44
+ @endif
45
+ @if(!title && !message)
46
+ <slot />
47
+ @endif
48
+ </div>
49
+
50
+ <button
51
+ type="button"
52
+ @click="handleClose"
53
+ class="ml-4 inline-flex rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2"
54
+ >
55
+ <span class="sr-only">Close</span>
56
+ <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
57
+ <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
58
+ </svg>
59
+ </button>
60
+ </div>
61
+ </div>
62
+
63
+ <script>
64
+ // Auto-hide after duration (client-side only)
65
+ if (typeof window !== 'undefined' && duration > 0) {
66
+ setTimeout(() => {
67
+ handleClose()
68
+ }, duration)
69
+ }
70
+ </script>
71
+ @endif
@@ -0,0 +1,138 @@
1
+ <script>
2
+ export const value = $props.value || ''
3
+ export const onChange = $props.onChange || (() => {})
4
+ export const placeholder = $props.placeholder || '0'
5
+ export const disabled = $props.disabled || false
6
+ export const readonly = $props.readonly || 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 min = $props.min
13
+ export const max = $props.max
14
+ export const step = $props.step || 1
15
+ export const showControls = $props.showControls ?? true
16
+ export const className = $props.className || ''
17
+ export const inputClassName = $props.inputClassName || ''
18
+
19
+ // Size classes
20
+ const sizeClasses = {
21
+ sm: 'px-3 py-1.5 text-sm h-8',
22
+ md: 'px-4 py-2 text-base h-10',
23
+ lg: 'px-5 py-3 text-lg h-12',
24
+ }
25
+
26
+ // Base and state classes
27
+ 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'
28
+
29
+ const stateClasses = error
30
+ ? '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'
31
+ : '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'
32
+
33
+ const disabledClasses = disabled
34
+ ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
35
+ : readonly
36
+ ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
37
+ : 'bg-white dark:bg-blue-gray-700'
38
+
39
+ const paddingClasses = showControls ? 'pr-10' : ''
40
+
41
+ export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${paddingClasses} ${inputClassName}`.trim()
42
+ export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
43
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
44
+ </script>
45
+
46
+ <div class="w-full {{ className }}">
47
+ @if(label)
48
+ <label for="number-input" class="{{ labelClasses }}">
49
+ {{ label }}
50
+ @if(required)
51
+ <span class="text-red-500 ml-1">*</span>
52
+ @endif
53
+ </label>
54
+ @endif
55
+
56
+ <div class="relative">
57
+ <input
58
+ type="number"
59
+ id="number-input"
60
+ class="{{ inputClasses }}"
61
+ value="{{ value }}"
62
+ placeholder="{{ placeholder }}"
63
+ disabled="{{ disabled }}"
64
+ readonly="{{ readonly }}"
65
+ required="{{ required }}"
66
+ @if(min !== undefined)min="{{ min }}"@endif
67
+ @if(max !== undefined)max="{{ max }}"@endif
68
+ step="{{ step }}"
69
+ oninput="handleInput(event)"
70
+ aria-invalid="{{ error ? 'true' : 'false' }}"
71
+ @if(helperText)aria-describedby="helper-text"@endif
72
+ />
73
+
74
+ @if(showControls && !disabled && !readonly)
75
+ <!-- Increment/Decrement controls -->
76
+ <div class="absolute inset-y-0 right-0 flex flex-col">
77
+ <button
78
+ type="button"
79
+ onclick="handleIncrement()"
80
+ class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none border-b border-gray-300 dark:border-gray-600"
81
+ aria-label="Increment"
82
+ >
83
+ <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
84
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
85
+ </svg>
86
+ </button>
87
+ <button
88
+ type="button"
89
+ onclick="handleDecrement()"
90
+ class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
91
+ aria-label="Decrement"
92
+ >
93
+ <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
94
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
95
+ </svg>
96
+ </button>
97
+ </div>
98
+ @endif
99
+ </div>
100
+
101
+ @if(helperText)
102
+ <p id="helper-text" class="{{ helperClasses }}">
103
+ {{ helperText }}
104
+ </p>
105
+ @endif
106
+ </div>
107
+
108
+ <script>
109
+ function handleInput(event) {
110
+ const newValue = event.target.value
111
+
112
+ if (onChange) {
113
+ onChange(newValue)
114
+ }
115
+ }
116
+
117
+ function handleIncrement() {
118
+ const currentValue = parseFloat(value) || 0
119
+ const newValue = currentValue + step
120
+
121
+ if (max !== undefined && newValue > max) return
122
+
123
+ if (onChange) {
124
+ onChange(String(newValue))
125
+ }
126
+ }
127
+
128
+ function handleDecrement() {
129
+ const currentValue = parseFloat(value) || 0
130
+ const newValue = currentValue - step
131
+
132
+ if (min !== undefined && newValue < min) return
133
+
134
+ if (onChange) {
135
+ onChange(String(newValue))
136
+ }
137
+ }
138
+ </script>