@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,232 @@
1
+ <script>
2
+ // Calendar Component Props
3
+ export const value = $props.value || new Date()
4
+ export const onChange = $props.onChange
5
+ export const minDate = $props.minDate
6
+ export const maxDate = $props.maxDate
7
+ export const disabledDates = $props.disabledDates || []
8
+ export const locale = $props.locale || 'en-US'
9
+ export const firstDayOfWeek = $props.firstDayOfWeek || 0 // 0 = Sunday, 1 = Monday
10
+ export const showToday = $props.showToday !== false
11
+ export const className = $props.className || ''
12
+ export const highlightToday = $props.highlightToday !== false
13
+
14
+ // State
15
+ let currentMonth = value ? new Date(value) : new Date()
16
+ let selectedDate = value ? new Date(value) : null
17
+ const today = new Date()
18
+
19
+ // Helper functions
20
+ function getDaysInMonth(date) {
21
+ return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
22
+ }
23
+
24
+ function getFirstDayOfMonth(date) {
25
+ return new Date(date.getFullYear(), date.getMonth(), 1).getDay()
26
+ }
27
+
28
+ function isSameDay(date1, date2) {
29
+ if (!date1 || !date2) return false
30
+ return date1.getFullYear() === date2.getFullYear() &&
31
+ date1.getMonth() === date2.getMonth() &&
32
+ date1.getDate() === date2.getDate()
33
+ }
34
+
35
+ function isToday(date) {
36
+ return isSameDay(date, today)
37
+ }
38
+
39
+ function isDisabled(date) {
40
+ if (minDate && date < minDate) return true
41
+ if (maxDate && date > maxDate) return true
42
+ return disabledDates.some(d => isSameDay(d, date))
43
+ }
44
+
45
+ function getMonthName(date) {
46
+ return date.toLocaleDateString(locale, { month: 'long' })
47
+ }
48
+
49
+ function getYear(date) {
50
+ return date.getFullYear()
51
+ }
52
+
53
+ function getDayNames() {
54
+ const days = []
55
+ const baseDate = new Date(2024, 0, firstDayOfWeek) // Jan 2024 started on Monday
56
+ for (let i = 0; i < 7; i++) {
57
+ const day = new Date(baseDate)
58
+ day.setDate(baseDate.getDate() + i)
59
+ days.push(day.toLocaleDateString(locale, { weekday: 'short' }))
60
+ }
61
+ return days
62
+ }
63
+
64
+ function getCalendarDays() {
65
+ const daysInMonth = getDaysInMonth(currentMonth)
66
+ const firstDay = (getFirstDayOfMonth(currentMonth) - firstDayOfWeek + 7) % 7
67
+ const days = []
68
+
69
+ // Previous month days
70
+ const prevMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
71
+ const daysInPrevMonth = getDaysInMonth(prevMonth)
72
+ for (let i = firstDay - 1; i >= 0; i--) {
73
+ days.push({
74
+ date: new Date(prevMonth.getFullYear(), prevMonth.getMonth(), daysInPrevMonth - i),
75
+ isCurrentMonth: false,
76
+ })
77
+ }
78
+
79
+ // Current month days
80
+ for (let i = 1; i <= daysInMonth; i++) {
81
+ days.push({
82
+ date: new Date(currentMonth.getFullYear(), currentMonth.getMonth(), i),
83
+ isCurrentMonth: true,
84
+ })
85
+ }
86
+
87
+ // Next month days to fill the grid
88
+ const remainingDays = 42 - days.length // 6 rows * 7 days
89
+ const nextMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
90
+ for (let i = 1; i <= remainingDays; i++) {
91
+ days.push({
92
+ date: new Date(nextMonth.getFullYear(), nextMonth.getMonth(), i),
93
+ isCurrentMonth: false,
94
+ })
95
+ }
96
+
97
+ return days
98
+ }
99
+
100
+ function previousMonth() {
101
+ currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
102
+ }
103
+
104
+ function nextMonth() {
105
+ currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
106
+ }
107
+
108
+ function selectDate(date) {
109
+ if (isDisabled(date)) return
110
+ selectedDate = date
111
+ onChange?.(date)
112
+ }
113
+
114
+ function goToToday() {
115
+ currentMonth = new Date(today)
116
+ selectDate(today)
117
+ }
118
+
119
+ // Base classes
120
+ const baseClasses = 'bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4 w-full max-w-sm'
121
+ const calendarClasses = `${baseClasses} ${className}`.trim()
122
+
123
+ const headerClasses = 'flex items-center justify-between mb-4'
124
+ const monthYearClasses = 'text-lg font-semibold text-gray-900 dark:text-gray-100'
125
+ const buttonClasses = 'p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors'
126
+
127
+ const weekdaysClasses = 'grid grid-cols-7 gap-1 mb-2'
128
+ const weekdayClasses = 'text-center text-xs font-medium text-gray-600 dark:text-gray-400 py-2'
129
+
130
+ const daysGridClasses = 'grid grid-cols-7 gap-1'
131
+
132
+ function getDayClasses(day) {
133
+ const base = 'flex items-center justify-center h-10 w-10 rounded-md text-sm transition-colors'
134
+ const isSelected = isSameDay(day.date, selectedDate)
135
+ const isTodayDate = isToday(day.date)
136
+ const disabled = isDisabled(day.date)
137
+
138
+ let classes = base
139
+
140
+ if (!day.isCurrentMonth) {
141
+ classes += ' text-gray-400 dark:text-gray-600'
142
+ } else {
143
+ classes += ' text-gray-900 dark:text-gray-100'
144
+ }
145
+
146
+ if (disabled) {
147
+ classes += ' opacity-50 cursor-not-allowed'
148
+ } else {
149
+ classes += ' cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700'
150
+ }
151
+
152
+ if (isSelected) {
153
+ classes += ' bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600'
154
+ }
155
+
156
+ if (isTodayDate && highlightToday && !isSelected) {
157
+ classes += ' border-2 border-blue-600 dark:border-blue-400'
158
+ }
159
+
160
+ return classes
161
+ }
162
+
163
+ const dayNames = getDayNames()
164
+ const calendarDays = getCalendarDays()
165
+ </script>
166
+
167
+ <div class="{{ calendarClasses }}">
168
+ <!-- Header -->
169
+ <div class="{{ headerClasses }}">
170
+ <button
171
+ type="button"
172
+ class="{{ buttonClasses }}"
173
+ onclick="previousMonth()"
174
+ aria-label="Previous month"
175
+ >
176
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
177
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
178
+ </svg>
179
+ </button>
180
+
181
+ <div class="{{ monthYearClasses }}">
182
+ {{ getMonthName(currentMonth) }} {{ getYear(currentMonth) }}
183
+ </div>
184
+
185
+ <button
186
+ type="button"
187
+ class="{{ buttonClasses }}"
188
+ onclick="nextMonth()"
189
+ aria-label="Next month"
190
+ >
191
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
192
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
193
+ </svg>
194
+ </button>
195
+ </div>
196
+
197
+ <!-- Weekday names -->
198
+ <div class="{{ weekdaysClasses }}">
199
+ @foreach(dayNames as day)
200
+ <div class="{{ weekdayClasses }}">{{ day }}</div>
201
+ @endforeach
202
+ </div>
203
+
204
+ <!-- Calendar grid -->
205
+ <div class="{{ daysGridClasses }}">
206
+ @foreach(calendarDays as day)
207
+ <button
208
+ type="button"
209
+ class="{{ getDayClasses(day) }}"
210
+ onclick="selectDate(day.date)"
211
+ aria-label="{{ day.date.toLocaleDateString(locale) }}"
212
+ @if(isDisabled(day.date))
213
+ disabled
214
+ @endif
215
+ >
216
+ {{ day.date.getDate() }}
217
+ </button>
218
+ @endforeach
219
+ </div>
220
+
221
+ @if(showToday)
222
+ <div class="mt-4 flex justify-center">
223
+ <button
224
+ type="button"
225
+ class="px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-gray-700 rounded-md transition-colors"
226
+ onclick="goToToday()"
227
+ >
228
+ Today
229
+ </button>
230
+ </div>
231
+ @endif
232
+ </div>
@@ -0,0 +1,254 @@
1
+ # Calendar Component
2
+
3
+ A fully-featured calendar/date picker component with support for date selection, range constraints, and localization.
4
+
5
+ ## Features
6
+
7
+ - ✅ Date selection with visual feedback
8
+ - ✅ Month/year navigation
9
+ - ✅ Min/max date constraints
10
+ - ✅ Disabled dates support
11
+ - ✅ Localization support
12
+ - ✅ Configurable first day of week
13
+ - ✅ Today button for quick navigation
14
+ - ✅ Today highlighting
15
+ - ✅ Dark mode support
16
+ - ✅ Accessible with ARIA labels
17
+ - ✅ Keyboard navigation ready
18
+
19
+ ## Usage
20
+
21
+ ### Basic Calendar
22
+
23
+ ```stx
24
+ <script>
25
+ import { Calendar } from '@stacksjs/components'
26
+
27
+ let selectedDate = new Date()
28
+
29
+ function handleDateChange(date) {
30
+ selectedDate = date
31
+ console.log('Selected date:', date)
32
+ }
33
+ </script>
34
+
35
+ <Calendar value={selectedDate} onChange={handleDateChange} />
36
+ ```
37
+
38
+ ### With Date Constraints
39
+
40
+ ```stx
41
+ <script>
42
+ import { Calendar } from '@stacksjs/components'
43
+
44
+ const today = new Date()
45
+ const minDate = new Date(today.getFullYear(), today.getMonth(), 1) // First day of month
46
+ const maxDate = new Date(today.getFullYear(), today.getMonth() + 1, 0) // Last day of month
47
+
48
+ let selectedDate = today
49
+ </script>
50
+
51
+ <Calendar
52
+ value={selectedDate}
53
+ minDate={minDate}
54
+ maxDate={maxDate}
55
+ onChange={(date) => selectedDate = date}
56
+ />
57
+ ```
58
+
59
+ ### With Disabled Dates
60
+
61
+ ```stx
62
+ <script>
63
+ import { Calendar } from '@stacksjs/components'
64
+
65
+ const disabledDates = [
66
+ new Date(2024, 11, 25), // Christmas
67
+ new Date(2024, 0, 1), // New Year's Day
68
+ ]
69
+
70
+ let selectedDate = new Date()
71
+ </script>
72
+
73
+ <Calendar
74
+ value={selectedDate}
75
+ disabledDates={disabledDates}
76
+ onChange={(date) => selectedDate = date}
77
+ />
78
+ ```
79
+
80
+ ### Localized Calendar
81
+
82
+ ```stx
83
+ <script>
84
+ import { Calendar } from '@stacksjs/components'
85
+
86
+ let selectedDate = new Date()
87
+ </script>
88
+
89
+ <!-- Spanish calendar starting on Monday -->
90
+ <Calendar
91
+ value={selectedDate}
92
+ locale="es-ES"
93
+ firstDayOfWeek={1}
94
+ onChange={(date) => selectedDate = date}
95
+ />
96
+ ```
97
+
98
+ ### Without Today Button
99
+
100
+ ```stx
101
+ <script>
102
+ import { Calendar } from '@stacksjs/components'
103
+
104
+ let selectedDate = new Date()
105
+ </script>
106
+
107
+ <Calendar
108
+ value={selectedDate}
109
+ showToday={false}
110
+ highlightToday={false}
111
+ onChange={(date) => selectedDate = date}
112
+ />
113
+ ```
114
+
115
+ ## Props
116
+
117
+ | Prop | Type | Default | Description |
118
+ |------|------|---------|-------------|
119
+ | `value` | `Date` | `new Date()` | Currently selected date |
120
+ | `onChange` | `(date: Date) => void` | - | Callback when a date is selected |
121
+ | `minDate` | `Date` | - | Minimum selectable date |
122
+ | `maxDate` | `Date` | - | Maximum selectable date |
123
+ | `disabledDates` | `Date[]` | `[]` | Array of dates that cannot be selected |
124
+ | `locale` | `string` | `'en-US'` | Locale for month/day names (e.g., 'en-US', 'es-ES', 'fr-FR') |
125
+ | `firstDayOfWeek` | `number` | `0` | First day of week (0 = Sunday, 1 = Monday, etc.) |
126
+ | `showToday` | `boolean` | `true` | Show "Today" button |
127
+ | `highlightToday` | `boolean` | `true` | Highlight today's date with a border |
128
+ | `className` | `string` | `''` | Additional CSS classes |
129
+
130
+ ## Examples
131
+
132
+ ### Date Range Selector (Start Date)
133
+
134
+ ```stx
135
+ <script>
136
+ import { Calendar } from '@stacksjs/components'
137
+
138
+ let startDate = null
139
+ let endDate = null
140
+
141
+ function handleStartDateChange(date) {
142
+ startDate = date
143
+ if (endDate && date > endDate) {
144
+ endDate = null
145
+ }
146
+ }
147
+ </script>
148
+
149
+ <div>
150
+ <h3>Select Start Date</h3>
151
+ <Calendar
152
+ value={startDate}
153
+ maxDate={endDate}
154
+ onChange={handleStartDateChange}
155
+ />
156
+ </div>
157
+ ```
158
+
159
+ ### Meeting Scheduler (Exclude Weekends)
160
+
161
+ ```stx
162
+ <script>
163
+ import { Calendar } from '@stacksjs/components'
164
+
165
+ function getNextNDays(n) {
166
+ const dates = []
167
+ const today = new Date()
168
+ for (let i = 0; i < n; i++) {
169
+ const date = new Date(today)
170
+ date.setDate(today.getDate() + i)
171
+ dates.push(date)
172
+ }
173
+ return dates
174
+ }
175
+
176
+ function getWeekends(days) {
177
+ return days.filter(date => date.getDay() === 0 || date.getDay() === 6)
178
+ }
179
+
180
+ const next60Days = getNextNDays(60)
181
+ const weekends = getWeekends(next60Days)
182
+
183
+ let meetingDate = null
184
+ </script>
185
+
186
+ <Calendar
187
+ value={meetingDate}
188
+ minDate={new Date()}
189
+ disabledDates={weekends}
190
+ onChange={(date) => meetingDate = date}
191
+ />
192
+ ```
193
+
194
+ ### Birthday Picker
195
+
196
+ ```stx
197
+ <script>
198
+ import { Calendar } from '@stacksjs/components'
199
+
200
+ const today = new Date()
201
+ const minDate = new Date(today.getFullYear() - 120, 0, 1) // 120 years ago
202
+ const maxDate = new Date(today.getFullYear() - 18, today.getMonth(), today.getDate()) // 18+ only
203
+
204
+ let birthday = null
205
+ </script>
206
+
207
+ <Calendar
208
+ value={birthday}
209
+ minDate={minDate}
210
+ maxDate={maxDate}
211
+ onChange={(date) => birthday = date}
212
+ />
213
+ ```
214
+
215
+ ## Styling
216
+
217
+ The calendar uses utility-first CSS classes and supports dark mode out of the box. You can customize the appearance by passing additional classes:
218
+
219
+ ```stx
220
+ <Calendar
221
+ className="border-2 border-gray-300 shadow-xl"
222
+ value={selectedDate}
223
+ onChange={handleChange}
224
+ />
225
+ ```
226
+
227
+ ### Key Classes
228
+
229
+ - Container: `bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4`
230
+ - Selected date: `bg-blue-600 text-white`
231
+ - Today: `border-2 border-blue-600` (when not selected)
232
+ - Disabled: `opacity-50 cursor-not-allowed`
233
+ - Hover: `hover:bg-gray-100 dark:hover:bg-gray-700`
234
+
235
+ ## Accessibility
236
+
237
+ - Semantic HTML with proper ARIA labels
238
+ - Keyboard navigation support (ready for enhancement)
239
+ - Disabled dates are properly marked with `disabled` attribute
240
+ - Clear visual indicators for selected and current dates
241
+
242
+ ## Browser Support
243
+
244
+ Works in all modern browsers that support:
245
+ - ES6+ JavaScript features
246
+ - CSS Grid
247
+ - CSS custom properties (for dark mode)
248
+
249
+ ## Related Components
250
+
251
+ - **DatePicker**: Combines Calendar with an input field
252
+ - **DateRangePicker**: Select start and end dates
253
+ - **TimePicker**: Select time values
254
+ - **DateTimePicker**: Combines date and time selection
@@ -0,0 +1,14 @@
1
+ export { default as Calendar } from './Calendar.stx'
2
+
3
+ export interface CalendarProps {
4
+ value?: Date
5
+ onChange?: (date: Date) => void
6
+ minDate?: Date
7
+ maxDate?: Date
8
+ disabledDates?: Date[]
9
+ locale?: string
10
+ firstDayOfWeek?: number // 0 = Sunday, 1 = Monday, etc.
11
+ showToday?: boolean
12
+ highlightToday?: boolean
13
+ className?: string
14
+ }
@@ -0,0 +1,74 @@
1
+ <script>
2
+ export const variant = $props.variant || 'default'
3
+ export const padding = $props.padding || 'default'
4
+ export const hover = $props.hover || false
5
+ export const clickable = $props.clickable || false
6
+ export const image = $props.image || ''
7
+ export const imageAlt = $props.imageAlt || ''
8
+ export const imagePosition = $props.imagePosition || 'top'
9
+ export const className = $props.className || ''
10
+ export const onClick = $props.onClick
11
+
12
+ // Variant classes
13
+ const variantClasses = {
14
+ default: 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700',
15
+ outlined: 'bg-transparent border-2 border-gray-300 dark:border-gray-600',
16
+ elevated: 'bg-white dark:bg-gray-800 shadow-lg border-0',
17
+ flat: 'bg-gray-50 dark:bg-gray-900 border-0',
18
+ }
19
+
20
+ // Padding classes
21
+ const paddingClasses = {
22
+ none: 'p-0',
23
+ sm: 'p-3',
24
+ default: 'p-6',
25
+ lg: 'p-8',
26
+ }
27
+
28
+ // Hover effect classes
29
+ const hoverClasses = hover ? 'transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5' : ''
30
+
31
+ // Clickable classes
32
+ const clickableClasses = clickable ? 'cursor-pointer' : ''
33
+
34
+ export const cardClasses = `rounded-lg overflow-hidden ${variantClasses[variant]} ${paddingClasses[image ? 'none' : padding]} ${hoverClasses} ${clickableClasses} ${className}`.trim()
35
+ export const imageClasses = `w-full h-48 object-cover`.trim()
36
+ export const contentClasses = `${image ? paddingClasses[padding] : ''}`.trim()
37
+ </script>
38
+
39
+ @if(onClick)
40
+ <div class="{{ cardClasses }}" onclick="handleClick(event)" role="button" tabindex="0" onkeydown="handleKeyDown(event)">
41
+ @if(image)
42
+ <img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
43
+ @endif
44
+
45
+ <div class="{{ contentClasses }}">
46
+ <slot />
47
+ </div>
48
+ </div>
49
+ @else
50
+ <div class="{{ cardClasses }}">
51
+ @if(image)
52
+ <img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
53
+ @endif
54
+
55
+ <div class="{{ contentClasses }}">
56
+ <slot />
57
+ </div>
58
+ </div>
59
+ @endif
60
+
61
+ <script>
62
+ function handleClick(event) {
63
+ if (clickable && onClick) {
64
+ onClick(event)
65
+ }
66
+ }
67
+
68
+ function handleKeyDown(event) {
69
+ if ((event.key === 'Enter' || event.key === ' ') && clickable && onClick) {
70
+ event.preventDefault()
71
+ onClick(event)
72
+ }
73
+ }
74
+ </script>
@@ -0,0 +1,13 @@
1
+ export { default as Card } from './Card.stx'
2
+
3
+ export interface CardProps {
4
+ variant?: 'default' | 'outlined' | 'elevated' | 'flat'
5
+ padding?: 'none' | 'sm' | 'default' | 'lg'
6
+ hover?: boolean
7
+ clickable?: boolean
8
+ image?: string
9
+ imageAlt?: string
10
+ imagePosition?: 'top' | 'bottom'
11
+ onClick?: (event: Event) => void
12
+ className?: string
13
+ }
@@ -0,0 +1,92 @@
1
+ <script>
2
+ export const checked = $props.checked || false
3
+ export const onChange = $props.onChange || (() => {})
4
+ export const disabled = $props.disabled || false
5
+ export const indeterminate = $props.indeterminate || false
6
+ export const size = $props.size || 'md'
7
+ export const label = $props.label || ''
8
+ export const description = $props.description || ''
9
+ export const error = $props.error || false
10
+ export const required = $props.required || false
11
+ export const value = $props.value || ''
12
+ export const name = $props.name || ''
13
+ export const className = $props.className || ''
14
+
15
+ // Size classes
16
+ const sizeClasses = {
17
+ sm: 'h-4 w-4',
18
+ md: 'h-5 w-5',
19
+ lg: 'h-6 w-6',
20
+ }
21
+
22
+ // Base classes for checkbox
23
+ const baseClasses = 'rounded border-gray-300 dark:border-gray-600 text-indigo-600 dark:text-indigo-500 focus:ring-indigo-600 dark:focus:ring-indigo-500 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 transition-colors'
24
+
25
+ const stateClasses = error
26
+ ? 'border-red-300 dark:border-red-600 text-red-600 dark:text-red-500 focus:ring-red-500 dark:focus:ring-red-400'
27
+ : ''
28
+
29
+ const disabledClasses = disabled
30
+ ? 'opacity-50 cursor-not-allowed'
31
+ : 'cursor-pointer'
32
+
33
+ export const checkboxClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses}`.trim()
34
+ export const labelClasses = `text-sm font-medium ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`.trim()
35
+ export const descriptionClasses = `text-sm ${error ? 'text-red-500 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
36
+ </script>
37
+
38
+ <div class="relative flex items-start {{ className }}">
39
+ <div class="flex h-6 items-center">
40
+ <input
41
+ id="checkbox-{{ value || label }}"
42
+ type="checkbox"
43
+ name="{{ name }}"
44
+ value="{{ value }}"
45
+ checked="{{ checked }}"
46
+ disabled="{{ disabled }}"
47
+ required="{{ required }}"
48
+ class="{{ checkboxClasses }}"
49
+ onchange="handleChange(event)"
50
+ aria-invalid="{{ error ? 'true' : 'false' }}"
51
+ @if(description)aria-describedby="checkbox-description"@endif
52
+ />
53
+ </div>
54
+
55
+ @if(label || description)
56
+ <div class="ml-3 text-sm leading-6">
57
+ @if(label)
58
+ <label for="checkbox-{{ value || label }}" class="{{ labelClasses }}">
59
+ {{ label }}
60
+ @if(required)
61
+ <span class="text-red-500 ml-1">*</span>
62
+ @endif
63
+ </label>
64
+ @endif
65
+ @if(description)
66
+ <p id="checkbox-description" class="{{ descriptionClasses }}">
67
+ {{ description }}
68
+ </p>
69
+ @endif
70
+ </div>
71
+ @endif
72
+ </div>
73
+
74
+ <script>
75
+ function handleChange(event) {
76
+ const isChecked = event.target.checked
77
+
78
+ if (!disabled && onChange) {
79
+ onChange(isChecked)
80
+ }
81
+ }
82
+
83
+ // Handle indeterminate state
84
+ if (indeterminate && typeof window !== 'undefined') {
85
+ window.addEventListener('DOMContentLoaded', () => {
86
+ const checkbox = document.getElementById('checkbox-{{ value || label }}')
87
+ if (checkbox) {
88
+ checkbox.indeterminate = true
89
+ }
90
+ })
91
+ }
92
+ </script>
@@ -0,0 +1,16 @@
1
+ export { default as Checkbox } from './Checkbox.stx'
2
+
3
+ export interface CheckboxProps {
4
+ checked?: boolean
5
+ onChange?: (checked: boolean) => void
6
+ disabled?: boolean
7
+ indeterminate?: boolean
8
+ size?: 'sm' | 'md' | 'lg'
9
+ label?: string
10
+ description?: string
11
+ error?: boolean
12
+ required?: boolean
13
+ value?: string
14
+ name?: string
15
+ className?: string
16
+ }