@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,183 @@
1
+ <script>
2
+ export const currentPage = $props.currentPage || 1
3
+ export const totalPages = $props.totalPages || 1
4
+ export const siblingCount = $props.siblingCount || 1
5
+ export const showFirstLast = $props.showFirstLast ?? true
6
+ export const showPrevNext = $props.showPrevNext ?? true
7
+ export const className = $props.className || ''
8
+ export const onChange = $props.onChange
9
+
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)
24
+
25
+ const showLeftEllipsis = leftSiblingIndex > 2
26
+ const showRightEllipsis = rightSiblingIndex < totalPages - 1
27
+
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
+ }
54
+ }
55
+
56
+ return pages
57
+ }
58
+
59
+ const pageNumbers = generatePageNumbers()
60
+
61
+ function goToPage(page) {
62
+ if (page >= 1 && page <= totalPages && page !== currentPage) {
63
+ if (onChange) {
64
+ onChange(page)
65
+ }
66
+ }
67
+ }
68
+
69
+ function goToPrevious() {
70
+ goToPage(currentPage - 1)
71
+ }
72
+
73
+ function goToNext() {
74
+ goToPage(currentPage + 1)
75
+ }
76
+
77
+ function goToFirst() {
78
+ goToPage(1)
79
+ }
80
+
81
+ function goToLast() {
82
+ goToPage(totalPages)
83
+ }
84
+
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()
90
+ </script>
91
+
92
+ <nav class="{{ paginationClasses }}" role="navigation" aria-label="Pagination">
93
+ <!-- First page button -->
94
+ @if(showFirstLast)
95
+ <button
96
+ type="button"
97
+ onclick="goToFirst()"
98
+ class="{{ buttonClasses }}"
99
+ aria-label="Go to first page"
100
+ disabled="{{ currentPage === 1 }}"
101
+ >
102
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
103
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
104
+ </svg>
105
+ </button>
106
+ @endif
107
+
108
+ <!-- Previous button -->
109
+ @if(showPrevNext)
110
+ <button
111
+ type="button"
112
+ onclick="goToPrevious()"
113
+ class="{{ buttonClasses }}"
114
+ aria-label="Go to previous page"
115
+ disabled="{{ currentPage === 1 }}"
116
+ >
117
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
118
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
119
+ </svg>
120
+ </button>
121
+ @endif
122
+
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
+ onclick="goToPage({{ page }})"
145
+ class="{{ buttonClasses }}"
146
+ aria-label="Go to page {{ page }}"
147
+ >
148
+ {{ page }}
149
+ </button>
150
+ @endif
151
+ @endif
152
+ @endforeach
153
+
154
+ <!-- Next button -->
155
+ @if(showPrevNext)
156
+ <button
157
+ type="button"
158
+ onclick="goToNext()"
159
+ class="{{ buttonClasses }}"
160
+ aria-label="Go to next page"
161
+ disabled="{{ currentPage === totalPages }}"
162
+ >
163
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
164
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
165
+ </svg>
166
+ </button>
167
+ @endif
168
+
169
+ <!-- Last page button -->
170
+ @if(showFirstLast)
171
+ <button
172
+ type="button"
173
+ onclick="goToLast()"
174
+ class="{{ buttonClasses }}"
175
+ aria-label="Go to last page"
176
+ disabled="{{ currentPage === totalPages }}"
177
+ >
178
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
179
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
180
+ </svg>
181
+ </button>
182
+ @endif
183
+ </nav>
@@ -0,0 +1,155 @@
1
+ <script>
2
+ export const value = $props.value || ''
3
+ export const onChange = $props.onChange || (() => {})
4
+ export const placeholder = $props.placeholder || 'Enter your password'
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 showStrength = $props.showStrength || false
13
+ export const className = $props.className || ''
14
+ export const inputClassName = $props.inputClassName || ''
15
+
16
+ // State
17
+ let showPassword = false
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
+ // Icon size classes
27
+ const iconSizeClasses = {
28
+ sm: 'h-4 w-4',
29
+ md: 'h-5 w-5',
30
+ lg: 'h-6 w-6',
31
+ }
32
+
33
+ // Base and state classes
34
+ 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 pr-10'
35
+
36
+ const stateClasses = error
37
+ ? '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'
38
+ : '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'
39
+
40
+ const disabledClasses = disabled
41
+ ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
42
+ : readonly
43
+ ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
44
+ : 'bg-white dark:bg-blue-gray-700'
45
+
46
+ export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${inputClassName}`.trim()
47
+ 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()
48
+ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
49
+ export const iconClasses = iconSizeClasses[size]
50
+
51
+ // Password strength calculation
52
+ function calculateStrength(password) {
53
+ if (!password) return 0
54
+ let strength = 0
55
+ if (password.length >= 8) strength += 25
56
+ if (password.length >= 12) strength += 25
57
+ if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength += 25
58
+ if (/\d/.test(password)) strength += 15
59
+ if (/[^a-zA-Z\d]/.test(password)) strength += 10
60
+ return Math.min(strength, 100)
61
+ }
62
+
63
+ export const strength = calculateStrength(value)
64
+ export const strengthColor = strength < 40 ? 'bg-red-500' : strength < 70 ? 'bg-yellow-500' : 'bg-green-500'
65
+ export const strengthText = strength < 40 ? 'Weak' : strength < 70 ? 'Medium' : 'Strong'
66
+ </script>
67
+
68
+ <div class="w-full {{ className }}">
69
+ @if(label)
70
+ <label for="password-input" class="{{ labelClasses }}">
71
+ {{ label }}
72
+ @if(required)
73
+ <span class="text-red-500 ml-1">*</span>
74
+ @endif
75
+ </label>
76
+ @endif
77
+
78
+ <div class="relative">
79
+ <input
80
+ type="{{ showPassword ? 'text' : 'password' }}"
81
+ id="password-input"
82
+ class="{{ inputClasses }}"
83
+ value="{{ value }}"
84
+ placeholder="{{ placeholder }}"
85
+ disabled="{{ disabled }}"
86
+ readonly="{{ readonly }}"
87
+ required="{{ required }}"
88
+ oninput="handleInput(event)"
89
+ aria-invalid="{{ error ? 'true' : 'false' }}"
90
+ @if(helperText)aria-describedby="helper-text"@endif
91
+ />
92
+
93
+ <!-- Toggle visibility button -->
94
+ <div class="absolute inset-y-0 right-0 flex items-center pr-3">
95
+ <button
96
+ type="button"
97
+ onclick="toggleVisibility()"
98
+ class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
99
+ aria-label="{{ showPassword ? 'Hide password' : 'Show password' }}"
100
+ >
101
+ @if(showPassword)
102
+ <!-- Eye slash icon (hide) -->
103
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
104
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
105
+ </svg>
106
+ @else
107
+ <!-- Eye icon (show) -->
108
+ <svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
109
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
110
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
111
+ </svg>
112
+ @endif
113
+ </button>
114
+ </div>
115
+ </div>
116
+
117
+ @if(showStrength && value.length > 0)
118
+ <!-- Password strength indicator -->
119
+ <div class="mt-2">
120
+ <div class="flex items-center justify-between mb-1">
121
+ <span class="text-xs text-gray-600 dark:text-gray-400">Password strength</span>
122
+ <span class="text-xs font-medium {{ strength < 40 ? 'text-red-600' : strength < 70 ? 'text-yellow-600' : 'text-green-600' }}">
123
+ {{ strengthText }}
124
+ </span>
125
+ </div>
126
+ <div class="w-full h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
127
+ <div
128
+ class="{{ strengthColor }} h-full transition-all duration-300 rounded-full"
129
+ style="width: {{ strength }}%"
130
+ ></div>
131
+ </div>
132
+ </div>
133
+ @endif
134
+
135
+ @if(helperText)
136
+ <p id="helper-text" class="{{ helperClasses }}">
137
+ {{ helperText }}
138
+ </p>
139
+ @endif
140
+ </div>
141
+
142
+ <script>
143
+ function handleInput(event) {
144
+ const newValue = event.target.value
145
+
146
+ if (onChange) {
147
+ onChange(newValue)
148
+ }
149
+ }
150
+
151
+ function toggleVisibility() {
152
+ showPassword = !showPassword
153
+ // Re-render would be handled by the framework
154
+ }
155
+ </script>
@@ -0,0 +1,113 @@
1
+ <script>
2
+ export const paymentMethods = $props.paymentMethods || []
3
+ export const onDeletePaymentMethod = $props.onDeletePaymentMethod
4
+ export const onMakeDefault = $props.onMakeDefault
5
+ export const isLoading = $props.isLoading || false
6
+ export const className = $props.className || ''
7
+
8
+ // Card brand icon mapping
9
+ const brandIcons = {
10
+ visa: '💳',
11
+ mastercard: '💳',
12
+ amex: '💳',
13
+ discover: '💳',
14
+ default: '💳',
15
+ }
16
+
17
+ export const containerClasses = `mt-4 ${className}`.trim()
18
+ </script>
19
+
20
+ <div class="{{ containerClasses }}">
21
+ @if(isLoading)
22
+ <!-- Loading state -->
23
+ <div class="animate-pulse">
24
+ <div class="h-24 bg-gray-200 dark:bg-gray-700 rounded-lg"></div>
25
+ </div>
26
+ @else
27
+ @if(paymentMethods.length > 0)
28
+ <ul role="list" class="grid grid-cols-1 gap-6 lg:grid-cols-1 sm:grid-cols-1">
29
+ @foreach(method in paymentMethods)
30
+ <li class="col-span-1 border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-blue-gray-800 shadow divide-y divide-gray-200 dark:divide-gray-700">
31
+ <div class="w-full p-3">
32
+ <div class="flex items-center justify-between">
33
+ <div class="flex items-center space-x-4">
34
+ <!-- Card Brand Icon -->
35
+ <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center bg-gray-100 dark:bg-gray-700 rounded-md">
36
+ <span class="text-2xl">{{ brandIcons[method.brand.toLowerCase()] || brandIcons.default }}</span>
37
+ </div>
38
+
39
+ <!-- Card Details -->
40
+ <div>
41
+ <h2 class="text-sm text-gray-600 dark:text-gray-300">
42
+ {{ method.brand }} •••• {{ method.last_four }}
43
+ </h2>
44
+ <span class="text-xs text-gray-500 dark:text-gray-400 italic">
45
+ Expires {{ method.exp_month }} / {{ method.exp_year }}
46
+ </span>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="flex justify-end space-x-4">
51
+ <!-- Make Default Button -->
52
+ @if(onMakeDefault)
53
+ <button
54
+ type="button"
55
+ class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-gray-700 dark:text-gray-300 font-semibold shadow-sm hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
56
+ onclick="handleMakeDefault('{{ method.id }}')"
57
+ title="Make default"
58
+ >
59
+ <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
60
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
61
+ </svg>
62
+ </button>
63
+ @endif
64
+
65
+ <!-- Delete Button -->
66
+ @if(onDeletePaymentMethod)
67
+ <button
68
+ type="button"
69
+ class="border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-blue-gray-700 px-2 py-1 text-sm text-red-600 dark:text-red-400 font-semibold shadow-sm hover:bg-red-50 dark:hover:bg-red-900/20 focus-visible:outline-2 focus-visible:outline-red-600 focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
70
+ onclick="handleDelete('{{ method.id }}')"
71
+ title="Delete payment method"
72
+ >
73
+ <svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
74
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
75
+ </svg>
76
+ </button>
77
+ @endif
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </li>
82
+ @endforeach
83
+ </ul>
84
+ @else
85
+ <!-- Empty state -->
86
+ <div class="text-center py-12 bg-white dark:bg-blue-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
87
+ <svg class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
88
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
89
+ </svg>
90
+ <h3 class="mt-2 text-sm text-gray-900 dark:text-gray-100 font-medium">No payment methods</h3>
91
+ <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
92
+ You haven't added any payment methods yet.
93
+ </p>
94
+ </div>
95
+ @endif
96
+ @endif
97
+ </div>
98
+
99
+ <script>
100
+ function handleMakeDefault(methodId) {
101
+ if (onMakeDefault) {
102
+ onMakeDefault(methodId)
103
+ }
104
+ }
105
+
106
+ function handleDelete(methodId) {
107
+ if (onDeletePaymentMethod) {
108
+ if (confirm('Are you sure you want to delete this payment method?')) {
109
+ onDeletePaymentMethod(methodId)
110
+ }
111
+ }
112
+ }
113
+ </script>
@@ -0,0 +1,24 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'div'
4
+ export let isOpen = false
5
+
6
+ export function toggle() {
7
+ isOpen = !isOpen
8
+ }
9
+
10
+ export function close() {
11
+ isOpen = false
12
+ }
13
+
14
+ export function open() {
15
+ isOpen = true
16
+ }
17
+
18
+ const baseClasses = 'relative'
19
+ const popoverClasses = `${baseClasses} ${className}`.trim()
20
+ </script>
21
+
22
+ <component :is="{{ as }}" class="{{ popoverClasses }}">
23
+ <slot :isOpen="isOpen" :toggle="toggle" :close="close" :open="open" />
24
+ </component>
@@ -0,0 +1,23 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'button'
4
+ export const disabled = $props.disabled || false
5
+ export const onClick = $props.onClick
6
+
7
+ const baseClasses = 'inline-flex items-center gap-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75'
8
+ const buttonClasses = `${baseClasses} ${className}`.trim()
9
+
10
+ export function handleClick(e) {
11
+ if (disabled) return
12
+ onClick?.(e)
13
+ }
14
+ </script>
15
+
16
+ <component
17
+ :is="{{ as }}"
18
+ class="{{ buttonClasses }}"
19
+ @if(disabled)disabled aria-disabled="true"@endif
20
+ @click="handleClick"
21
+ >
22
+ <slot />
23
+ </component>
@@ -0,0 +1,23 @@
1
+ <script>
2
+ export const className = $props.className || ''
3
+ export const as = $props.as || 'div'
4
+ export const static_ = $props.static || false
5
+ export const position = $props.position || 'bottom'
6
+
7
+ const positionClasses = {
8
+ 'top': 'bottom-full mb-2',
9
+ 'bottom': 'top-full mt-2',
10
+ 'left': 'right-full mr-2',
11
+ 'right': 'left-full ml-2',
12
+ }
13
+
14
+ const baseClasses = 'absolute z-10 rounded-lg bg-white dark:bg-neutral-800 p-4 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'
15
+ const panelClasses = `${baseClasses} ${positionClasses[position]} ${className}`.trim()
16
+ </script>
17
+
18
+ <component
19
+ :is="{{ as }}"
20
+ class="{{ panelClasses }}"
21
+ >
22
+ <slot />
23
+ </component>
@@ -0,0 +1,74 @@
1
+ <script>
2
+ export const target = $props.target || 'body'
3
+ export const disabled = $props.disabled || false
4
+
5
+ let portalContainer = null
6
+ let mounted = false
7
+
8
+ // Create portal container
9
+ function createPortal() {
10
+ if (typeof window === 'undefined' || disabled)
11
+ return
12
+
13
+ // Get target element
14
+ const targetElement = typeof target === 'string'
15
+ ? document.querySelector(target)
16
+ : target
17
+
18
+ if (!targetElement) {
19
+ console.warn(`Portal target "${target}" not found`)
20
+ return
21
+ }
22
+
23
+ // Create portal container
24
+ portalContainer = document.createElement('div')
25
+ portalContainer.setAttribute('data-portal', 'true')
26
+
27
+ // Move portal content to target
28
+ const portalContent = document.getElementById('portal-content')
29
+ if (portalContent) {
30
+ while (portalContent.firstChild) {
31
+ portalContainer.appendChild(portalContent.firstChild)
32
+ }
33
+ }
34
+
35
+ targetElement.appendChild(portalContainer)
36
+ mounted = true
37
+ }
38
+
39
+ // Cleanup portal
40
+ function cleanupPortal() {
41
+ if (portalContainer && portalContainer.parentNode) {
42
+ portalContainer.parentNode.removeChild(portalContainer)
43
+ portalContainer = null
44
+ mounted = false
45
+ }
46
+ }
47
+
48
+ // Initialize portal on mount
49
+ if (typeof window !== 'undefined') {
50
+ window.addEventListener('DOMContentLoaded', () => {
51
+ setTimeout(createPortal, 0)
52
+ })
53
+
54
+ // Cleanup on page unload
55
+ window.addEventListener('beforeunload', cleanupPortal)
56
+ }
57
+ </script>
58
+
59
+ @if(disabled)
60
+ <!-- Render in place if disabled -->
61
+ <slot />
62
+ @else
63
+ <!-- Hidden container that will be moved to portal -->
64
+ <div id="portal-content" style="display: none;">
65
+ <slot />
66
+ </div>
67
+ @endif
68
+
69
+ <script>
70
+ // Trigger portal creation after render
71
+ if (typeof window !== 'undefined' && document.readyState === 'complete') {
72
+ setTimeout(createPortal, 0)
73
+ }
74
+ </script>