@stacksjs/components 0.2.35 → 0.2.54

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 (237) hide show
  1. package/dist/Accordion-19x8q4rj.stx +88 -0
  2. package/dist/{Audio-vdmg1258.stx → Audio-hjywk3qc.stx} +4 -4
  3. package/dist/{Avatar-365cvrh4.stx → Avatar-h3jmwcq0.stx} +23 -34
  4. package/dist/{Badge-8m3qete4.stx → Badge-k8dy3d53.stx} +11 -19
  5. package/dist/{Button-3tt4vsqt.stx → Button-1vknasy3.stx} +18 -33
  6. package/dist/Calendar-reny0et7.stx +189 -0
  7. package/dist/{Card-6wdbexqr.stx → Card-c1g1fd1w.stx} +27 -33
  8. package/dist/{Checkbox-p3q3e3nf.stx → Checkbox-zgdmy3p5.stx} +36 -44
  9. package/dist/{Checkout-e4037tyy.stx → Checkout-agt0ngpw.stx} +8 -16
  10. package/dist/Combobox-fdkr6cdq.stx +96 -0
  11. package/dist/{ComboboxButton-8gxwkhdx.stx → ComboboxButton-g76stp1e.stx} +14 -2
  12. package/dist/{ComboboxInput-mk99z65n.stx → ComboboxInput-z1293bbh.stx} +12 -5
  13. package/dist/ComboboxOption-hmxt3gte.stx +49 -0
  14. package/dist/{ListboxOptions-8kqvfp7z.stx → ComboboxOptions-sq5360ae.stx} +2 -2
  15. package/dist/CommandPalette-36mxf05w.stx +81 -0
  16. package/dist/CommandPaletteItem-mvk6q7a2.stx +27 -0
  17. package/dist/Dialog-hczpexs4.stx +37 -0
  18. package/dist/{Drawer-p7m351bn.stx → Drawer-xhevp5cw.stx} +29 -49
  19. package/dist/Dropdown-vvhemtc0.stx +82 -0
  20. package/dist/{DropdownButton-9w8zkfwj.stx → DropdownButton-wcz67dxy.stx} +12 -6
  21. package/dist/DropdownItem-c7rz08e5.stx +35 -0
  22. package/dist/{DropdownItems-aygjpxkx.stx → DropdownItems-1sxnd5qn.stx} +2 -2
  23. package/dist/EmailInput-vak3kkmk.stx +30 -0
  24. package/dist/Form-mas630hy.stx +95 -0
  25. package/dist/{Image-jhkm6w1f.stx → Image-yhxcvgzs.stx} +68 -100
  26. package/dist/Listbox-q49tnr90.stx +101 -0
  27. package/dist/{ListboxButton-spwx7513.stx → ListboxButton-keb8gm0q.stx} +12 -1
  28. package/dist/ListboxOption-e0dtv1gc.stx +49 -0
  29. package/dist/{ComboboxOptions-6b5ywc5x.stx → ListboxOptions-ejkatcfg.stx} +7 -3
  30. package/dist/{Login-rx9gyqhx.stx → Login-gepemsth.stx} +17 -19
  31. package/dist/Navigator-rk2a5wvk.stx +113 -0
  32. package/dist/Notification-tb9b525s.stx +78 -0
  33. package/dist/{NumberInput-nzpkx1ry.stx → NumberInput-drnvtqej.stx} +40 -53
  34. package/dist/{Pagination-h61eq390.stx → Pagination-n3d31cns.stx} +73 -108
  35. package/dist/PasswordInput-n02x6053.stx +142 -0
  36. package/dist/{PaymentMethods-j42jsk5x.stx → PaymentMethods-x4vrx9yb.stx} +21 -30
  37. package/dist/Popover-et2q44m7.stx +60 -0
  38. package/dist/{PopoverButton-fnaqc77g.stx → PopoverButton-mffzc9pr.stx} +12 -6
  39. package/dist/{PopoverPanel-y0vtf5w9.stx → PopoverPanel-054yh38h.stx} +6 -6
  40. package/dist/{Portal-s2q37yp0.stx → Portal-1vf14s4x.stx} +20 -37
  41. package/dist/{Progress-vmdkm06p.stx → Progress-yxcntr4x.stx} +36 -48
  42. package/dist/{Radio-04bs3d21.stx → Radio-cgjv2hb2.stx} +29 -34
  43. package/dist/RadioGroup-qxmnm3xm.stx +60 -0
  44. package/dist/RadioGroupOption-s1d6r221.stx +58 -0
  45. package/dist/SearchInput-pdx7agn0.stx +44 -0
  46. package/dist/{Select-g4mmvfv8.stx → Select-28y0pg83.stx} +23 -31
  47. package/dist/Sidebar-73vc78as.stx +236 -0
  48. package/dist/SidebarFooter-zsfsgcxb.stx +109 -0
  49. package/dist/SidebarHeader-7v174a9c.stx +122 -0
  50. package/dist/SidebarItem-3y3e8g2t.stx +92 -0
  51. package/dist/SidebarSection-z5ey6awe.stx +113 -0
  52. package/dist/{Signup-c4dyv6f3.stx → Signup-hxm5hwkr.stx} +26 -28
  53. package/dist/{StepperStep-en4r00zv.stx → StepperStep-wxgembat.stx} +9 -5
  54. package/dist/{SubscriptionCheckout-gawjzf3q.stx → SubscriptionCheckout-zy2ycrmw.stx} +99 -129
  55. package/dist/Switch-r5t5w04w.stx +70 -0
  56. package/dist/{TableHeader-ydys9rzz.stx → TableHeader-0eyzbqpz.stx} +10 -3
  57. package/dist/Tabs-bzvvn4ke.stx +126 -0
  58. package/dist/Teleport-tsx4bt4n.stx +65 -0
  59. package/dist/{TextInput-k2kfkgy1.stx → TextInput-kf084763.stx} +42 -59
  60. package/dist/{Textarea-szad57dz.stx → Textarea-xg4rr2xz.stx} +42 -54
  61. package/dist/{Tooltip-em7t551n.stx → Tooltip-m0tqd72e.stx} +34 -40
  62. package/dist/Transition-7smenaz8.stx +102 -0
  63. package/dist/{TwoFactorChallenge-an9yvxvq.stx → TwoFactorChallenge-y5m3nk79.stx} +49 -63
  64. package/dist/{Video-crxva65p.stx → Video-84j4pv6h.stx} +4 -4
  65. package/dist/VirtualList-fa7v5a3h.stx +67 -0
  66. package/dist/VirtualTable-f9crbfjr.stx +103 -0
  67. package/dist/components/CodeBlock.stx +1 -6
  68. package/dist/index.js +13 -13
  69. package/dist/ui/accordion/Accordion.stx +1 -3
  70. package/dist/ui/auth/Login.stx +0 -1
  71. package/dist/ui/auth/Signup.stx +0 -1
  72. package/dist/ui/auth/TwoFactorChallenge.stx +1 -3
  73. package/dist/ui/avatar/Avatar.stx +0 -2
  74. package/dist/ui/badge/Badge.stx +0 -1
  75. package/dist/ui/button/Button.stx +1 -2
  76. package/dist/ui/calendar/Calendar.stx +12 -2
  77. package/dist/ui/card/Card.stx +0 -2
  78. package/dist/ui/checkbox/Checkbox.stx +2 -2
  79. package/dist/ui/combobox/Combobox.stx +2 -1
  80. package/dist/ui/combobox/ComboboxButton.stx +1 -0
  81. package/dist/ui/combobox/ComboboxInput.stx +1 -4
  82. package/dist/ui/combobox/ComboboxOption.stx +2 -9
  83. package/dist/ui/combobox/ComboboxOptions.stx +1 -1
  84. package/dist/ui/command-palette/CommandPalette.stx +3 -6
  85. package/dist/ui/command-palette/CommandPaletteItem.stx +2 -7
  86. package/dist/ui/dialog/Dialog.stx +1 -3
  87. package/dist/ui/drawer/Drawer.stx +1 -3
  88. package/dist/ui/dropdown/Dropdown.stx +2 -5
  89. package/dist/ui/dropdown/DropdownButton.stx +1 -3
  90. package/dist/ui/dropdown/DropdownItem.stx +2 -7
  91. package/dist/ui/dropdown/DropdownItems.stx +1 -1
  92. package/dist/ui/form/Form.stx +0 -5
  93. package/dist/ui/image/Image.stx +1 -6
  94. package/dist/ui/input/EmailInput.stx +1 -1
  95. package/dist/ui/input/NumberInput.stx +0 -1
  96. package/dist/ui/input/PasswordInput.stx +1 -4
  97. package/dist/ui/input/SearchInput.stx +2 -2
  98. package/dist/ui/input/TextInput.stx +1 -2
  99. package/dist/ui/listbox/Listbox.stx +2 -1
  100. package/dist/ui/listbox/ListboxButton.stx +1 -0
  101. package/dist/ui/listbox/ListboxOption.stx +2 -9
  102. package/dist/ui/listbox/ListboxOptions.stx +1 -1
  103. package/dist/ui/navigator/Navigator.stx +4 -4
  104. package/dist/ui/notification/Notification.stx +1 -5
  105. package/dist/ui/pagination/Pagination.stx +1 -2
  106. package/dist/ui/payment/Checkout.stx +0 -4
  107. package/dist/ui/payment/PaymentMethods.stx +15 -2
  108. package/dist/ui/payment/SubscriptionCheckout.stx +3 -184
  109. package/dist/ui/popover/Popover.stx +2 -5
  110. package/dist/ui/popover/PopoverButton.stx +1 -3
  111. package/dist/ui/popover/PopoverPanel.stx +1 -1
  112. package/dist/ui/portal/Portal.stx +1 -0
  113. package/dist/ui/progress/Progress.stx +6 -1
  114. package/dist/ui/radio/Radio.stx +1 -1
  115. package/dist/ui/radio-group/RadioGroup.stx +2 -1
  116. package/dist/ui/radio-group/RadioGroupOption.stx +2 -9
  117. package/dist/ui/select/Select.stx +1 -1
  118. package/dist/ui/sidebar/Sidebar.stx +9 -26
  119. package/dist/ui/sidebar/SidebarFooter.stx +6 -21
  120. package/dist/ui/sidebar/SidebarHeader.stx +7 -18
  121. package/dist/ui/sidebar/SidebarItem.stx +4 -20
  122. package/dist/ui/sidebar/SidebarSection.stx +5 -18
  123. package/dist/ui/sidebar/index.d.ts +13 -1
  124. package/dist/ui/stepper/StepperStep.stx +1 -5
  125. package/dist/ui/switch/Switch.stx +4 -10
  126. package/dist/ui/table/TableHeader.stx +1 -1
  127. package/dist/ui/tabs/Tabs.stx +0 -1
  128. package/dist/ui/teleport/Teleport.stx +1 -0
  129. package/dist/ui/textarea/Textarea.stx +1 -1
  130. package/dist/ui/tooltip/Tooltip.stx +1 -2
  131. package/dist/ui/transition/Transition.stx +9 -16
  132. package/dist/ui/virtual-list/VirtualList.stx +2 -4
  133. package/dist/ui/virtual-table/VirtualTable.stx +1 -1
  134. package/package.json +5 -5
  135. package/src/components/CodeBlock.stx +26 -29
  136. package/src/components/Footer.stx +1 -1
  137. package/src/components/Hero.stx +1 -1
  138. package/src/components/Installation.stx +5 -7
  139. package/src/ui/accordion/Accordion.stx +48 -68
  140. package/src/ui/audio/Audio.stx +4 -4
  141. package/src/ui/auth/Login.stx +17 -19
  142. package/src/ui/auth/Signup.stx +26 -28
  143. package/src/ui/auth/TwoFactorChallenge.stx +49 -63
  144. package/src/ui/avatar/Avatar.stx +23 -34
  145. package/src/ui/badge/Badge.stx +11 -19
  146. package/src/ui/button/Button.stx +18 -33
  147. package/src/ui/calendar/Calendar.stx +93 -136
  148. package/src/ui/card/Card.stx +27 -33
  149. package/src/ui/checkbox/Checkbox.stx +36 -44
  150. package/src/ui/combobox/Combobox.stx +87 -4
  151. package/src/ui/combobox/ComboboxButton.stx +14 -2
  152. package/src/ui/combobox/ComboboxInput.stx +12 -5
  153. package/src/ui/combobox/ComboboxOption.stx +29 -32
  154. package/src/ui/combobox/ComboboxOptions.stx +7 -3
  155. package/src/ui/command-palette/CommandPalette.stx +70 -28
  156. package/src/ui/command-palette/CommandPaletteItem.stx +15 -20
  157. package/src/ui/dialog/Dialog.stx +28 -10
  158. package/src/ui/drawer/Drawer.stx +29 -49
  159. package/src/ui/dropdown/Dropdown.stx +69 -11
  160. package/src/ui/dropdown/DropdownButton.stx +12 -6
  161. package/src/ui/dropdown/DropdownItem.stx +18 -26
  162. package/src/ui/dropdown/DropdownItems.stx +2 -2
  163. package/src/ui/form/Form.stx +50 -164
  164. package/src/ui/heatmap/Heatmap.stx +16 -37
  165. package/src/ui/image/Image.stx +68 -100
  166. package/src/ui/input/EmailInput.stx +16 -27
  167. package/src/ui/input/NumberInput.stx +40 -53
  168. package/src/ui/input/PasswordInput.stx +64 -77
  169. package/src/ui/input/SearchInput.stx +27 -46
  170. package/src/ui/input/TextInput.stx +42 -59
  171. package/src/ui/listbox/Listbox.stx +91 -4
  172. package/src/ui/listbox/ListboxButton.stx +12 -1
  173. package/src/ui/listbox/ListboxOption.stx +30 -38
  174. package/src/ui/listbox/ListboxOptions.stx +2 -2
  175. package/src/ui/navigator/Navigator.stx +52 -77
  176. package/src/ui/notification/Notification.stx +46 -39
  177. package/src/ui/pagination/Pagination.stx +73 -108
  178. package/src/ui/payment/Checkout.stx +8 -16
  179. package/src/ui/payment/PaymentMethods.stx +21 -30
  180. package/src/ui/payment/SubscriptionCheckout.stx +99 -129
  181. package/src/ui/popover/Popover.stx +50 -14
  182. package/src/ui/popover/PopoverButton.stx +12 -6
  183. package/src/ui/popover/PopoverPanel.stx +6 -6
  184. package/src/ui/portal/Portal.stx +20 -37
  185. package/src/ui/progress/Progress.stx +36 -48
  186. package/src/ui/radio/Radio.stx +29 -34
  187. package/src/ui/radio-group/RadioGroup.stx +51 -4
  188. package/src/ui/radio-group/RadioGroupOption.stx +37 -30
  189. package/src/ui/select/Select.stx +23 -31
  190. package/src/ui/sidebar/Sidebar.stx +136 -188
  191. package/src/ui/sidebar/SidebarFooter.stx +49 -35
  192. package/src/ui/sidebar/SidebarHeader.stx +52 -30
  193. package/src/ui/sidebar/SidebarItem.stx +52 -78
  194. package/src/ui/sidebar/SidebarSection.stx +56 -51
  195. package/src/ui/sidebar/index.ts +21 -1
  196. package/src/ui/stepper/StepperStep.stx +9 -5
  197. package/src/ui/switch/Switch.stx +38 -42
  198. package/src/ui/table/TableHeader.stx +10 -3
  199. package/src/ui/tabs/Tabs.stx +68 -87
  200. package/src/ui/teleport/Teleport.stx +23 -59
  201. package/src/ui/textarea/Textarea.stx +42 -54
  202. package/src/ui/tooltip/Tooltip.stx +34 -40
  203. package/src/ui/transition/Transition.stx +76 -148
  204. package/src/ui/video/Video.stx +4 -4
  205. package/src/ui/virtual-list/VirtualList.stx +45 -61
  206. package/src/ui/virtual-table/VirtualTable.stx +62 -72
  207. package/dist/Accordion-sbfra0mz.stx +0 -108
  208. package/dist/Calendar-58nnkdh8.stx +0 -232
  209. package/dist/Combobox-th5ebw62.stx +0 -13
  210. package/dist/ComboboxOption-an9zyan6.stx +0 -52
  211. package/dist/CommandPalette-kwmdf2np.stx +0 -39
  212. package/dist/CommandPaletteItem-zx2fbpts.stx +0 -32
  213. package/dist/Dialog-rgmj8q2j.stx +0 -19
  214. package/dist/Dropdown-jz4jy0n3.stx +0 -24
  215. package/dist/DropdownItem-wagdspb8.stx +0 -43
  216. package/dist/EmailInput-ajsp9vw6.stx +0 -41
  217. package/dist/Form-1mdmx9b6.stx +0 -209
  218. package/dist/Listbox-pqqh72g8.stx +0 -14
  219. package/dist/ListboxOption-7nxzaexq.stx +0 -57
  220. package/dist/Navigator-aay8bjab.stx +0 -138
  221. package/dist/Notification-gk33gv7b.stx +0 -71
  222. package/dist/PasswordInput-zv4hm43j.stx +0 -155
  223. package/dist/Popover-469gbt6r.stx +0 -24
  224. package/dist/RadioGroup-bvb1mrhd.stx +0 -13
  225. package/dist/RadioGroupOption-cpdwgnhw.stx +0 -51
  226. package/dist/SearchInput-2521m475.stx +0 -63
  227. package/dist/Sidebar-40ckbzh8.stx +0 -288
  228. package/dist/SidebarFooter-hnth56mg.stx +0 -95
  229. package/dist/SidebarHeader-3wrte2p2.stx +0 -100
  230. package/dist/SidebarItem-zqtvvzpc.stx +0 -118
  231. package/dist/SidebarSection-3etwnbjr.stx +0 -108
  232. package/dist/Switch-036j9vm1.stx +0 -74
  233. package/dist/Tabs-svh721m0.stx +0 -145
  234. package/dist/Teleport-qfch3w0b.stx +0 -101
  235. package/dist/Transition-0hmr6zxb.stx +0 -174
  236. package/dist/VirtualList-cndhjejh.stx +0 -83
  237. package/dist/VirtualTable-ng0b48yp.stx +0 -113
@@ -1,91 +1,74 @@
1
1
  <script server>
2
- // Navigator Component Props
3
2
  export const items = $props.items || []
4
3
  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
4
+ export const orientation = $props.orientation || 'horizontal'
5
+ export const variant = $props.variant || 'default'
6
+ export const size = $props.size || 'md'
9
7
  export const className = $props.className || ''
10
8
 
11
- // Helper function to check if item is active
9
+ const containerBaseClasses = orientation === 'horizontal' ? 'flex items-center' : 'flex flex-col'
10
+ export const containerClasses = `${containerBaseClasses} ${className}`.trim()
11
+ export const gapClasses = orientation === 'horizontal' ? 'gap-1' : 'gap-0.5'
12
+ </script>
13
+
14
+ <script client>
15
+ const emit = defineEmits()
16
+ const items = {{ items }}
17
+ const variant = {{ variant }}
18
+ const size = {{ size }}
19
+ const initialActive = {{ active }}
20
+ const activeKey = state(initialActive)
21
+
12
22
  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
23
+ const a = activeKey()
24
+ if (typeof item.href === 'string' && typeof a === 'string') {
25
+ if (item.href === a) return true
26
+ if (a.startsWith(item.href)) return true
18
27
  }
19
- if (item.id && item.id === active) return true
28
+ if (item.id && item.id === a) return true
20
29
  return false
21
30
  }
22
31
 
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
32
  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
33
+ const isActiveItem = isActive(item)
34
+ const sizeClasses = { sm: 'px-2 py-1 text-sm', md: 'px-3 py-2 text-base', lg: 'px-4 py-3 text-lg' }
35
+ let cls = sizeClasses[size] || sizeClasses.md
45
36
  if (variant === 'default') {
46
- classes += active
37
+ cls += isActiveItem
47
38
  ? ' text-gray-900 dark:text-gray-100 font-medium'
48
39
  : ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
49
- } else if (variant === 'pills') {
50
- classes += active
40
+ }
41
+ else if (variant === 'pills') {
42
+ cls += isActiveItem
51
43
  ? ' bg-blue-600 text-white font-medium rounded-full'
52
44
  : ' 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
45
+ }
46
+ else if (variant === 'underline') {
47
+ cls += isActiveItem
55
48
  ? ' text-blue-600 dark:text-blue-400 font-medium border-b-2 border-blue-600 dark:border-blue-400'
56
49
  : ' 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
50
+ }
51
+ else if (variant === 'sidebar') {
52
+ cls += isActiveItem
59
53
  ? ' 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
54
  : ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 border-l-4 border-transparent'
61
55
  }
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()
56
+ cls += ' transition-all duration-200 cursor-pointer flex items-center gap-2'
57
+ if (item.disabled) cls += ' opacity-50 cursor-not-allowed pointer-events-none'
58
+ return cls.trim()
71
59
  }
72
60
 
73
- // Gap classes between items
74
- const gapClasses = orientation === 'horizontal'
75
- ? 'gap-1'
76
- : 'gap-0.5'
77
-
78
- function handleClick(item, event) {
61
+ function onClickItem(item, event) {
79
62
  if (item.disabled) {
80
63
  event.preventDefault()
81
64
  return
82
65
  }
83
-
84
- if (onNavigate) {
85
- event.preventDefault()
86
- onNavigate(item)
87
- }
66
+ event.preventDefault()
67
+ activeKey.set(item.href || item.id || activeKey())
68
+ emit('navigate', item)
88
69
  }
70
+
71
+ defineExpose({ activeKey })
89
72
  </script>
90
73
 
91
74
  <nav class="{{ containerClasses }} {{ gapClasses }}" role="navigation" aria-label="Main navigation">
@@ -93,18 +76,13 @@ function handleClick(item, event) {
93
76
  @if(item.href)
94
77
  <a
95
78
  href="{{ item.href }}"
96
- class="{{ getItemClasses(item) }}"
97
- @click="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
79
+ :class="getItemClasses({{ JSON.stringify(item) }})"
80
+ @click="onClickItem({{ JSON.stringify(item) }}, $event)"
81
+ :aria-current="isActive({{ JSON.stringify(item) }}) ? 'page' : null"
82
+ @if(item.disabled)aria-disabled="true" tabindex="-1"@endif
105
83
  >
106
84
  @if(item.icon)
107
- <span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
85
+ <span class="flex-shrink-0">{!! item.icon !!}</span>
108
86
  @endif
109
87
  <span>{{ item.label }}</span>
110
88
  @if(item.badge)
@@ -116,15 +94,12 @@ function handleClick(item, event) {
116
94
  @else
117
95
  <button
118
96
  type="button"
119
- class="{{ getItemClasses(item) }}"
120
- @click="handleClick(item, event)"
121
- @if(item.disabled)
122
- disabled
123
- aria-disabled="true"
124
- @endif
97
+ :class="getItemClasses({{ JSON.stringify(item) }})"
98
+ @click="onClickItem({{ JSON.stringify(item) }}, $event)"
99
+ @if(item.disabled)disabled aria-disabled="true"@endif
125
100
  >
126
101
  @if(item.icon)
127
- <span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
102
+ <span class="flex-shrink-0">{!! item.icon !!}</span>
128
103
  @endif
129
104
  <span>{{ item.label }}</span>
130
105
  @if(item.badge)
@@ -5,7 +5,6 @@ export const message = $props.message || ''
5
5
  export const type = $props.type || 'info'
6
6
  export const position = $props.position || 'top-right'
7
7
  export const duration = $props.duration || 5000
8
- export const onClose = $props.onClose
9
8
  export const className = $props.className || ''
10
9
 
11
10
  const typeColors = {
@@ -25,47 +24,55 @@ const positions = {
25
24
  }
26
25
 
27
26
  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()
27
+ export const notificationClasses = `${baseClasses} ${typeColors[type]} ${positions[position]} ${className}`.trim()
28
+ </script>
29
+
30
+ <script client>
31
+ const emit = defineEmits()
32
+ const duration = {{ duration }}
33
+ const isVisible = state({{ show }})
29
34
 
30
- export function handleClose() {
31
- onClose?.()
35
+ function close() {
36
+ isVisible.set(false)
37
+ emit('close')
32
38
  }
33
- </script>
34
39
 
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>
40
+ onMount(() => {
41
+ if (duration > 0 && isVisible()) {
42
+ setTimeout(close, duration)
43
+ }
44
+ })
49
45
 
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>
46
+ defineExpose({
47
+ show: () => isVisible.set(true),
48
+ close,
49
+ isVisible,
50
+ })
51
+ </script>
52
+
53
+ <div :show="isVisible()" class="{{ notificationClasses }}" role="alert">
54
+ <div class="flex items-start">
55
+ <div class="flex-1">
56
+ @if(title)
57
+ <p class="text-sm font-medium">{{ title }}</p>
58
+ @endif
59
+ @if(message)
60
+ <p class="mt-1 text-sm {{ title ? 'opacity-90' : '' }}">{{ message }}</p>
61
+ @endif
62
+ @if(!title && !message)
63
+ <slot />
64
+ @endif
60
65
  </div>
61
- </div>
62
66
 
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
67
+ <button
68
+ type="button"
69
+ @click="close()"
70
+ class="ml-4 inline-flex rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2"
71
+ >
72
+ <span class="sr-only">Close</span>
73
+ <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
74
+ <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" />
75
+ </svg>
76
+ </button>
77
+ </div>
78
+ </div>
@@ -5,99 +5,84 @@ export const siblingCount = $props.siblingCount || 1
5
5
  export const showFirstLast = $props.showFirstLast ?? true
6
6
  export const showPrevNext = $props.showPrevNext ?? true
7
7
  export const className = $props.className || ''
8
- export const onChange = $props.onChange
9
8
 
10
- // Generate page numbers to display
11
- function generatePageNumbers() {
12
- const pages = []
13
- const totalNumbers = siblingCount * 2 + 3 // siblings on each side + current + first + last
14
- const totalBlocks = totalNumbers + 2 // + 2 for ellipsis
15
-
16
- if (totalPages <= totalBlocks) {
17
- // Show all pages
18
- for (let i = 1; i <= totalPages; i++) {
19
- pages.push(i)
20
- }
21
- } else {
22
- const leftSiblingIndex = Math.max(currentPage - siblingCount, 1)
23
- const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages)
9
+ export const paginationClasses = `flex items-center gap-1 ${className}`.trim()
10
+ export const buttonClasses = `px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white dark:disabled:hover:bg-gray-800 transition-colors duration-150`.trim()
11
+ export const activeButtonClasses = `px-3 py-2 text-sm font-medium text-white bg-blue-600 dark:bg-blue-500 border border-blue-600 dark:border-blue-500 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
12
+ export const ellipsisClasses = `px-3 py-2 text-sm font-medium text-gray-400 dark:text-gray-600`.trim()
13
+ export const iconClasses = `w-5 h-5`.trim()
14
+ </script>
24
15
 
25
- const showLeftEllipsis = leftSiblingIndex > 2
26
- const showRightEllipsis = rightSiblingIndex < totalPages - 1
16
+ <script client>
17
+ const emit = defineEmits()
18
+ const totalPages = {{ totalPages }}
19
+ const siblingCount = {{ siblingCount }}
20
+ const page = state({{ currentPage }})
27
21
 
28
- if (!showLeftEllipsis && showRightEllipsis) {
29
- // Show left pages + ellipsis + last
30
- const leftCount = 3 + 2 * siblingCount
31
- for (let i = 1; i <= leftCount; i++) {
32
- pages.push(i)
33
- }
34
- pages.push('ellipsis-right')
35
- pages.push(totalPages)
36
- } else if (showLeftEllipsis && !showRightEllipsis) {
37
- // Show first + ellipsis + right pages
38
- pages.push(1)
39
- pages.push('ellipsis-left')
40
- const rightCount = 3 + 2 * siblingCount
41
- for (let i = totalPages - rightCount + 1; i <= totalPages; i++) {
42
- pages.push(i)
43
- }
44
- } else {
45
- // Show first + ellipsis + middle + ellipsis + last
46
- pages.push(1)
47
- pages.push('ellipsis-left')
48
- for (let i = leftSiblingIndex; i <= rightSiblingIndex; i++) {
49
- pages.push(i)
50
- }
51
- pages.push('ellipsis-right')
52
- pages.push(totalPages)
53
- }
22
+ function goToPage(target) {
23
+ if (target >= 1 && target <= totalPages && target !== page()) {
24
+ page.set(target)
25
+ emit('change', target)
54
26
  }
55
-
56
- return pages
57
27
  }
58
28
 
59
- const pageNumbers = generatePageNumbers()
29
+ function goToPrevious() { goToPage(page() - 1) }
30
+ function goToNext() { goToPage(page() + 1) }
31
+ function goToFirst() { goToPage(1) }
32
+ function goToLast() { goToPage(totalPages) }
60
33
 
61
- function goToPage(page) {
62
- if (page >= 1 && page <= totalPages && page !== currentPage) {
63
- if (onChange) {
64
- onChange(page)
65
- }
66
- }
67
- }
34
+ const pageNumbers = derived(() => {
35
+ const cur = page()
36
+ const pages = []
37
+ const totalNumbers = siblingCount * 2 + 3
38
+ const totalBlocks = totalNumbers + 2
68
39
 
69
- function goToPrevious() {
70
- goToPage(currentPage - 1)
71
- }
40
+ if (totalPages <= totalBlocks) {
41
+ for (let i = 1; i <= totalPages; i++) pages.push(i)
42
+ return pages
43
+ }
72
44
 
73
- function goToNext() {
74
- goToPage(currentPage + 1)
75
- }
45
+ const leftSibling = Math.max(cur - siblingCount, 1)
46
+ const rightSibling = Math.min(cur + siblingCount, totalPages)
47
+ const showLeftEllipsis = leftSibling > 2
48
+ const showRightEllipsis = rightSibling < totalPages - 1
76
49
 
77
- function goToFirst() {
78
- goToPage(1)
79
- }
50
+ if (!showLeftEllipsis && showRightEllipsis) {
51
+ const leftCount = 3 + 2 * siblingCount
52
+ for (let i = 1; i <= leftCount; i++) pages.push(i)
53
+ pages.push('ellipsis-right')
54
+ pages.push(totalPages)
55
+ }
56
+ else if (showLeftEllipsis && !showRightEllipsis) {
57
+ pages.push(1)
58
+ pages.push('ellipsis-left')
59
+ const rightCount = 3 + 2 * siblingCount
60
+ for (let i = totalPages - rightCount + 1; i <= totalPages; i++) pages.push(i)
61
+ }
62
+ else {
63
+ pages.push(1)
64
+ pages.push('ellipsis-left')
65
+ for (let i = leftSibling; i <= rightSibling; i++) pages.push(i)
66
+ pages.push('ellipsis-right')
67
+ pages.push(totalPages)
68
+ }
69
+ return pages
70
+ })
80
71
 
81
- function goToLast() {
82
- goToPage(totalPages)
83
- }
72
+ const isFirstPage = derived(() => page() === 1)
73
+ const isLastPage = derived(() => page() === totalPages)
84
74
 
85
- export const paginationClasses = `flex items-center gap-1 ${className}`.trim()
86
- export const buttonClasses = `px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white dark:disabled:hover:bg-gray-800 transition-colors duration-150`.trim()
87
- export const activeButtonClasses = `px-3 py-2 text-sm font-medium text-white bg-blue-600 dark:bg-blue-500 border border-blue-600 dark:border-blue-500 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
88
- export const ellipsisClasses = `px-3 py-2 text-sm font-medium text-gray-400 dark:text-gray-600`.trim()
89
- export const iconClasses = `w-5 h-5`.trim()
75
+ defineExpose({ page, goToPage })
90
76
  </script>
91
77
 
92
78
  <nav class="{{ paginationClasses }}" role="navigation" aria-label="Pagination">
93
- <!-- First page button -->
94
79
  @if(showFirstLast)
95
80
  <button
96
81
  type="button"
97
82
  @click="goToFirst()"
98
83
  class="{{ buttonClasses }}"
99
84
  aria-label="Go to first page"
100
- disabled="{{ currentPage === 1 }}"
85
+ :disabled="isFirstPage()"
101
86
  >
102
87
  <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
103
88
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
@@ -105,14 +90,13 @@ export const iconClasses = `w-5 h-5`.trim()
105
90
  </button>
106
91
  @endif
107
92
 
108
- <!-- Previous button -->
109
93
  @if(showPrevNext)
110
94
  <button
111
95
  type="button"
112
96
  @click="goToPrevious()"
113
97
  class="{{ buttonClasses }}"
114
98
  aria-label="Go to previous page"
115
- disabled="{{ currentPage === 1 }}"
99
+ :disabled="isFirstPage()"
116
100
  >
117
101
  <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
118
102
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
@@ -120,45 +104,27 @@ export const iconClasses = `w-5 h-5`.trim()
120
104
  </button>
121
105
  @endif
122
106
 
123
- <!-- Page numbers -->
124
- @foreach(page in pageNumbers)
125
- @if(typeof page === 'string')
126
- <!-- Ellipsis -->
127
- <span class="{{ ellipsisClasses }}" aria-hidden="true">...</span>
128
- @else
129
- @if(page === currentPage)
130
- <!-- Current page -->
131
- <button
132
- type="button"
133
- class="{{ activeButtonClasses }}"
134
- aria-label="Page {{ page }}"
135
- aria-current="page"
136
- disabled
137
- >
138
- {{ page }}
139
- </button>
140
- @else
141
- <!-- Other pages -->
142
- <button
143
- type="button"
144
- @click="goToPage({{ page }})"
145
- class="{{ buttonClasses }}"
146
- aria-label="Go to page {{ page }}"
147
- >
148
- {{ page }}
149
- </button>
150
- @endif
151
- @endif
152
- @endforeach
107
+ <span :for="p in pageNumbers()" :key="p" class="contents">
108
+ <span :if="typeof p === 'string'" class="{{ ellipsisClasses }}" aria-hidden="true">...</span>
109
+ <button
110
+ :if="typeof p !== 'string'"
111
+ type="button"
112
+ :class="p === page() ? '{{ activeButtonClasses }}' : '{{ buttonClasses }}'"
113
+ :aria-label="`Go to page ${p}`"
114
+ :aria-current="p === page() ? 'page' : null"
115
+ :disabled="p === page()"
116
+ @click="goToPage(p)"
117
+ x-text="p"
118
+ ></button>
119
+ </span>
153
120
 
154
- <!-- Next button -->
155
121
  @if(showPrevNext)
156
122
  <button
157
123
  type="button"
158
124
  @click="goToNext()"
159
125
  class="{{ buttonClasses }}"
160
126
  aria-label="Go to next page"
161
- disabled="{{ currentPage === totalPages }}"
127
+ :disabled="isLastPage()"
162
128
  >
163
129
  <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
164
130
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
@@ -166,14 +132,13 @@ export const iconClasses = `w-5 h-5`.trim()
166
132
  </button>
167
133
  @endif
168
134
 
169
- <!-- Last page button -->
170
135
  @if(showFirstLast)
171
136
  <button
172
137
  type="button"
173
138
  @click="goToLast()"
174
139
  class="{{ buttonClasses }}"
175
140
  aria-label="Go to last page"
176
- disabled="{{ currentPage === totalPages }}"
141
+ :disabled="isLastPage()"
177
142
  >
178
143
  <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
179
144
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
@@ -1,36 +1,28 @@
1
1
  <script server>
2
2
  export const products = $props.products || []
3
- export const redirectUrl = $props.redirectUrl || ''
4
3
  export const mode = $props.mode || 'subscription'
5
4
  export const stripePublicKey = $props.stripePublicKey || ''
6
5
  export const apiUrl = $props.apiUrl || ''
7
- export const onSubmit = $props.onSubmit
8
- export const onRemoveProduct = $props.onRemoveProduct
9
6
  export const shipping = $props.shipping || 0
10
7
  export const taxes = $props.taxes || 0
11
8
  export const className = $props.className || ''
12
9
 
13
- // For future expansion - one-time payment support
14
10
  export const isSubscription = mode === 'subscription'
15
11
  export const isOneTime = mode === 'one-time'
16
12
  </script>
17
13
 
18
14
  @if(isSubscription)
19
- @component('SubscriptionCheckout', {
20
- products,
21
- stripePublicKey,
22
- apiUrl,
23
- onSubmit,
24
- onRemoveProduct,
25
- shipping,
26
- taxes,
27
- className
28
- })
29
- @endcomponent
15
+ <SubscriptionCheckout
16
+ :products="products"
17
+ :stripePublicKey="stripePublicKey"
18
+ :apiUrl="apiUrl"
19
+ :shipping="shipping"
20
+ :taxes="taxes"
21
+ :className="className"
22
+ />
30
23
  @endif
31
24
 
32
25
  @if(isOneTime)
33
- <!-- One-time payment component can be implemented here in the future -->
34
26
  <div class="p-8 text-center">
35
27
  <p class="text-gray-600 dark:text-gray-400">
36
28
  One-time payment mode is not yet implemented.