@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,818 @@
1
+ /**
2
+ * KeepAlive utilities for @stacksjs/components
3
+ *
4
+ * Provides component caching and state preservation with LRU (Least Recently Used)
5
+ * cache strategy for optimizing component lifecycle management
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { createKeepAlive } from '@stacksjs/components'
10
+ *
11
+ * // Create KeepAlive manager with max 10 components
12
+ * const keepAlive = createKeepAlive({ max: 10 })
13
+ *
14
+ * // Cache component
15
+ * const cached = keepAlive.cache('my-component', componentInstance, {
16
+ * state: { count: 0 },
17
+ * onActivate: (comp) => console.log('Component activated'),
18
+ * onDeactivate: (comp) => console.log('Component deactivated'),
19
+ * })
20
+ *
21
+ * // Retrieve cached component
22
+ * const instance = keepAlive.get('my-component')
23
+ *
24
+ * // Prune least recently used
25
+ * keepAlive.prune()
26
+ * ```
27
+ */
28
+
29
+ /**
30
+ * Component instance interface
31
+ */
32
+ export interface ComponentInstance {
33
+ /** Component ID */
34
+ id: string
35
+ /** Component type/name */
36
+ type: string
37
+ /** DOM element */
38
+ element?: HTMLElement
39
+ /** Component state */
40
+ state?: Record<string, any>
41
+ /** Custom component data */
42
+ data?: Record<string, any>
43
+ /** Lifecycle hooks */
44
+ hooks?: ComponentHooks
45
+ /** Timestamp when created */
46
+ createdAt: number
47
+ /** Timestamp when last accessed */
48
+ lastAccessedAt: number
49
+ }
50
+
51
+ /**
52
+ * Component lifecycle hooks
53
+ */
54
+ export interface ComponentHooks {
55
+ /** Called when component is mounted */
56
+ onMount?: (instance: ComponentInstance) => void
57
+ /** Called before component is unmounted */
58
+ onUnmount?: (instance: ComponentInstance) => void
59
+ /** Called when component is activated from cache */
60
+ onActivate?: (instance: ComponentInstance) => void
61
+ /** Called when component is deactivated to cache */
62
+ onDeactivate?: (instance: ComponentInstance) => void
63
+ /** Called when component state is restored */
64
+ onRestore?: (instance: ComponentInstance, state: Record<string, any>) => void
65
+ /** Called when component state is saved */
66
+ onSave?: (instance: ComponentInstance) => Record<string, any>
67
+ }
68
+
69
+ /**
70
+ * KeepAlive cache options
71
+ */
72
+ export interface KeepAliveOptions {
73
+ /** Maximum number of cached components (LRU eviction when exceeded) */
74
+ max?: number
75
+ /** Time to live for cached components in milliseconds (0 = no expiry) */
76
+ ttl?: number
77
+ /** Include/exclude patterns for component types */
78
+ include?: RegExp | string[]
79
+ /** Exclude patterns for component types */
80
+ exclude?: RegExp | string[]
81
+ /** Global hooks for all cached components */
82
+ hooks?: ComponentHooks
83
+ /** Enable debug logging */
84
+ debug?: boolean
85
+ }
86
+
87
+ /**
88
+ * Cache entry with metadata
89
+ */
90
+ interface CacheEntry {
91
+ /** Component instance */
92
+ instance: ComponentInstance
93
+ /** Access count */
94
+ accessCount: number
95
+ /** Creation timestamp */
96
+ createdAt: number
97
+ /** Last access timestamp */
98
+ lastAccessedAt: number
99
+ /** Expiry timestamp (if TTL set) */
100
+ expiresAt?: number
101
+ }
102
+
103
+ /**
104
+ * KeepAlive cache statistics
105
+ */
106
+ export interface CacheStats {
107
+ /** Total cache hits */
108
+ hits: number
109
+ /** Total cache misses */
110
+ misses: number
111
+ /** Current cache size */
112
+ size: number
113
+ /** Maximum cache size */
114
+ max: number
115
+ /** Hit rate (0-1) */
116
+ hitRate: number
117
+ /** Cache keys */
118
+ keys: string[]
119
+ }
120
+
121
+ /**
122
+ * KeepAlive manager interface
123
+ */
124
+ export interface KeepAlive {
125
+ /** Cache a component instance */
126
+ cache: (key: string, instance: ComponentInstance, hooks?: ComponentHooks) => ComponentInstance
127
+ /** Get cached component instance */
128
+ get: (key: string) => ComponentInstance | null
129
+ /** Check if key exists in cache */
130
+ has: (key: string) => boolean
131
+ /** Remove component from cache */
132
+ remove: (key: string) => boolean
133
+ /** Clear all cached components */
134
+ clear: () => void
135
+ /** Prune expired or least recently used components */
136
+ prune: () => number
137
+ /** Activate cached component */
138
+ activate: (key: string) => ComponentInstance | null
139
+ /** Deactivate component to cache */
140
+ deactivate: (key: string) => boolean
141
+ /** Get cache statistics */
142
+ getStats: () => CacheStats
143
+ /** Get all cached keys */
144
+ keys: () => string[]
145
+ /** Get cache size */
146
+ size: () => number
147
+ }
148
+
149
+ /**
150
+ * Create a KeepAlive manager
151
+ *
152
+ * Implements LRU (Least Recently Used) cache strategy for component instances
153
+ *
154
+ * @param options - KeepAlive configuration options
155
+ * @returns KeepAlive manager instance
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const keepAlive = createKeepAlive({
160
+ * max: 10,
161
+ * ttl: 5 * 60 * 1000, // 5 minutes
162
+ * include: ['user-profile', 'dashboard'],
163
+ * hooks: {
164
+ * onActivate: (comp) => console.log(`Activated: ${comp.id}`),
165
+ * onDeactivate: (comp) => console.log(`Deactivated: ${comp.id}`),
166
+ * },
167
+ * })
168
+ * ```
169
+ */
170
+ export function createKeepAlive(options: KeepAliveOptions = {}): KeepAlive {
171
+ const {
172
+ max = 10,
173
+ ttl = 0,
174
+ include,
175
+ exclude,
176
+ hooks: globalHooks,
177
+ debug = false,
178
+ } = options
179
+
180
+ // Cache storage (Map maintains insertion order for LRU)
181
+ const cache = new Map<string, CacheEntry>()
182
+
183
+ // Statistics
184
+ let hits = 0
185
+ let misses = 0
186
+
187
+ /**
188
+ * Log debug message
189
+ */
190
+ function log(...args: any[]): void {
191
+ if (debug) {
192
+ console.log('[KeepAlive]', ...args)
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Check if component type should be cached
198
+ */
199
+ function shouldCache(type: string): boolean {
200
+ // Check exclude patterns first
201
+ if (exclude) {
202
+ if (exclude instanceof RegExp && exclude.test(type)) {
203
+ return false
204
+ }
205
+ if (Array.isArray(exclude) && exclude.includes(type)) {
206
+ return false
207
+ }
208
+ }
209
+
210
+ // Check include patterns
211
+ if (include) {
212
+ if (include instanceof RegExp && !include.test(type)) {
213
+ return false
214
+ }
215
+ if (Array.isArray(include) && !include.includes(type)) {
216
+ return false
217
+ }
218
+ }
219
+
220
+ return true
221
+ }
222
+
223
+ /**
224
+ * Check if cache entry is expired
225
+ */
226
+ function isExpired(entry: CacheEntry): boolean {
227
+ if (!ttl || !entry.expiresAt) {
228
+ return false
229
+ }
230
+ return Date.now() > entry.expiresAt
231
+ }
232
+
233
+ /**
234
+ * Update entry access time (for LRU)
235
+ */
236
+ function touch(key: string): void {
237
+ const entry = cache.get(key)
238
+ if (entry) {
239
+ entry.lastAccessedAt = Date.now()
240
+ entry.accessCount++
241
+ entry.instance.lastAccessedAt = entry.lastAccessedAt
242
+
243
+ // Move to end (most recently used)
244
+ cache.delete(key)
245
+ cache.set(key, entry)
246
+
247
+ log(`Touched: ${key} (access count: ${entry.accessCount})`)
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Evict least recently used entry
253
+ */
254
+ function evictLRU(): boolean {
255
+ if (cache.size === 0) {
256
+ return false
257
+ }
258
+
259
+ // First entry is least recently used (Map maintains insertion order)
260
+ const firstKey = cache.keys().next().value as string | undefined
261
+ if (!firstKey) {
262
+ return false
263
+ }
264
+ const entry = cache.get(firstKey)
265
+
266
+ if (entry) {
267
+ log(`Evicting LRU: ${firstKey}`)
268
+
269
+ // Call deactivate hook
270
+ const hooks = entry.instance.hooks
271
+ if (hooks?.onDeactivate) {
272
+ hooks.onDeactivate(entry.instance)
273
+ }
274
+ if (globalHooks?.onDeactivate) {
275
+ globalHooks.onDeactivate(entry.instance)
276
+ }
277
+
278
+ cache.delete(firstKey)
279
+ return true
280
+ }
281
+
282
+ return false
283
+ }
284
+
285
+ /**
286
+ * Cache a component instance
287
+ */
288
+ function cacheComponent(
289
+ key: string,
290
+ instance: ComponentInstance,
291
+ hooks?: ComponentHooks,
292
+ ): ComponentInstance {
293
+ // Check if type should be cached
294
+ if (!shouldCache(instance.type)) {
295
+ log(`Type not cacheable: ${instance.type}`)
296
+ return instance
297
+ }
298
+
299
+ // Check cache size limit
300
+ if (cache.size >= max) {
301
+ evictLRU()
302
+ }
303
+
304
+ const now = Date.now()
305
+
306
+ // Create cache entry
307
+ const entry: CacheEntry = {
308
+ instance: {
309
+ ...instance,
310
+ hooks: hooks || instance.hooks,
311
+ createdAt: instance.createdAt || now,
312
+ lastAccessedAt: now,
313
+ },
314
+ accessCount: 0,
315
+ createdAt: now,
316
+ lastAccessedAt: now,
317
+ expiresAt: ttl ? now + ttl : undefined,
318
+ }
319
+
320
+ cache.set(key, entry)
321
+
322
+ log(`Cached: ${key} (size: ${cache.size}/${max})`)
323
+
324
+ // Call cache hook
325
+ if (hooks?.onMount) {
326
+ hooks.onMount(entry.instance)
327
+ }
328
+ if (globalHooks?.onMount) {
329
+ globalHooks.onMount(entry.instance)
330
+ }
331
+
332
+ return entry.instance
333
+ }
334
+
335
+ /**
336
+ * Get cached component instance
337
+ */
338
+ function get(key: string): ComponentInstance | null {
339
+ const entry = cache.get(key)
340
+
341
+ if (!entry) {
342
+ misses++
343
+ log(`Miss: ${key}`)
344
+ return null
345
+ }
346
+
347
+ // Check expiry
348
+ if (isExpired(entry)) {
349
+ log(`Expired: ${key}`)
350
+ cache.delete(key)
351
+ misses++
352
+ return null
353
+ }
354
+
355
+ hits++
356
+ touch(key)
357
+ log(`Hit: ${key}`)
358
+
359
+ return entry.instance
360
+ }
361
+
362
+ /**
363
+ * Check if key exists in cache
364
+ */
365
+ function has(key: string): boolean {
366
+ const entry = cache.get(key)
367
+ if (!entry) {
368
+ return false
369
+ }
370
+ if (isExpired(entry)) {
371
+ cache.delete(key)
372
+ return false
373
+ }
374
+ return true
375
+ }
376
+
377
+ /**
378
+ * Remove component from cache
379
+ */
380
+ function remove(key: string): boolean {
381
+ const entry = cache.get(key)
382
+
383
+ if (!entry) {
384
+ return false
385
+ }
386
+
387
+ log(`Removing: ${key}`)
388
+
389
+ // Call unmount hook
390
+ const hooks = entry.instance.hooks
391
+ if (hooks?.onUnmount) {
392
+ hooks.onUnmount(entry.instance)
393
+ }
394
+ if (globalHooks?.onUnmount) {
395
+ globalHooks.onUnmount(entry.instance)
396
+ }
397
+
398
+ return cache.delete(key)
399
+ }
400
+
401
+ /**
402
+ * Clear all cached components
403
+ */
404
+ function clear(): void {
405
+ log('Clearing cache')
406
+
407
+ // Call unmount hooks for all entries
408
+ cache.forEach((entry) => {
409
+ const hooks = entry.instance.hooks
410
+ if (hooks?.onUnmount) {
411
+ hooks.onUnmount(entry.instance)
412
+ }
413
+ if (globalHooks?.onUnmount) {
414
+ globalHooks.onUnmount(entry.instance)
415
+ }
416
+ })
417
+
418
+ cache.clear()
419
+ hits = 0
420
+ misses = 0
421
+ }
422
+
423
+ /**
424
+ * Prune expired or excess entries
425
+ */
426
+ function prune(): number {
427
+ let pruned = 0
428
+
429
+ // Remove expired entries
430
+ const _now = Date.now()
431
+ for (const [key, entry] of cache.entries()) {
432
+ if (isExpired(entry)) {
433
+ log(`Pruning expired: ${key}`)
434
+ remove(key)
435
+ pruned++
436
+ }
437
+ }
438
+
439
+ // Evict excess entries (LRU)
440
+ while (cache.size > max) {
441
+ if (evictLRU()) {
442
+ pruned++
443
+ }
444
+ else {
445
+ break
446
+ }
447
+ }
448
+
449
+ if (pruned > 0) {
450
+ log(`Pruned ${pruned} entries`)
451
+ }
452
+
453
+ return pruned
454
+ }
455
+
456
+ /**
457
+ * Activate cached component
458
+ */
459
+ function activate(key: string): ComponentInstance | null {
460
+ const instance = get(key)
461
+
462
+ if (!instance) {
463
+ return null
464
+ }
465
+
466
+ log(`Activating: ${key}`)
467
+
468
+ // Call activate hook
469
+ const hooks = instance.hooks
470
+ if (hooks?.onActivate) {
471
+ hooks.onActivate(instance)
472
+ }
473
+ if (globalHooks?.onActivate) {
474
+ globalHooks.onActivate(instance)
475
+ }
476
+
477
+ // Restore state if saved
478
+ if (instance.state && hooks?.onRestore) {
479
+ hooks.onRestore(instance, instance.state)
480
+ }
481
+
482
+ return instance
483
+ }
484
+
485
+ /**
486
+ * Deactivate component to cache
487
+ */
488
+ function deactivate(key: string): boolean {
489
+ const entry = cache.get(key)
490
+
491
+ if (!entry) {
492
+ return false
493
+ }
494
+
495
+ log(`Deactivating: ${key}`)
496
+
497
+ const instance = entry.instance
498
+ const hooks = instance.hooks
499
+
500
+ // Save state
501
+ if (hooks?.onSave) {
502
+ instance.state = hooks.onSave(instance)
503
+ }
504
+
505
+ // Call deactivate hook
506
+ if (hooks?.onDeactivate) {
507
+ hooks.onDeactivate(instance)
508
+ }
509
+ if (globalHooks?.onDeactivate) {
510
+ globalHooks.onDeactivate(instance)
511
+ }
512
+
513
+ return true
514
+ }
515
+
516
+ /**
517
+ * Get cache statistics
518
+ */
519
+ function getStats(): CacheStats {
520
+ const total = hits + misses
521
+ return {
522
+ hits,
523
+ misses,
524
+ size: cache.size,
525
+ max,
526
+ hitRate: total > 0 ? hits / total : 0,
527
+ keys: Array.from(cache.keys()),
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Get all cached keys
533
+ */
534
+ function keys(): string[] {
535
+ return Array.from(cache.keys())
536
+ }
537
+
538
+ /**
539
+ * Get cache size
540
+ */
541
+ function size(): number {
542
+ return cache.size
543
+ }
544
+
545
+ // Return KeepAlive manager
546
+ return {
547
+ cache: cacheComponent,
548
+ get,
549
+ has,
550
+ remove,
551
+ clear,
552
+ prune,
553
+ activate,
554
+ deactivate,
555
+ getStats,
556
+ keys,
557
+ size,
558
+ }
559
+ }
560
+
561
+ /**
562
+ * Create a simple LRU cache (without component-specific features)
563
+ *
564
+ * Generic LRU cache implementation for any type of data
565
+ *
566
+ * @param maxSize - Maximum number of items to cache
567
+ * @returns LRU cache instance
568
+ *
569
+ * @example
570
+ * ```ts
571
+ * const cache = createLRUCache<string>(100)
572
+ *
573
+ * cache.set('key1', 'value1')
574
+ * const value = cache.get('key1') // 'value1'
575
+ * cache.has('key1') // true
576
+ * ```
577
+ */
578
+ export function createLRUCache<T = any>(maxSize: number) {
579
+ const cache = new Map<string, T>()
580
+
581
+ return {
582
+ /**
583
+ * Set a value in cache
584
+ */
585
+ set(key: string, value: T): void {
586
+ // Delete and re-add to move to end
587
+ if (cache.has(key)) {
588
+ cache.delete(key)
589
+ }
590
+
591
+ cache.set(key, value)
592
+
593
+ // Evict oldest if over max size
594
+ if (cache.size > maxSize) {
595
+ const firstKey = cache.keys().next().value as string | undefined
596
+ if (firstKey) {
597
+ cache.delete(firstKey)
598
+ }
599
+ }
600
+ },
601
+
602
+ /**
603
+ * Get a value from cache
604
+ */
605
+ get(key: string): T | undefined {
606
+ if (!cache.has(key)) {
607
+ return undefined
608
+ }
609
+
610
+ const value = cache.get(key)!
611
+
612
+ // Move to end (most recently used)
613
+ cache.delete(key)
614
+ cache.set(key, value)
615
+
616
+ return value
617
+ },
618
+
619
+ /**
620
+ * Check if key exists
621
+ */
622
+ has(key: string): boolean {
623
+ return cache.has(key)
624
+ },
625
+
626
+ /**
627
+ * Delete a key
628
+ */
629
+ delete(key: string): boolean {
630
+ return cache.delete(key)
631
+ },
632
+
633
+ /**
634
+ * Clear all entries
635
+ */
636
+ clear(): void {
637
+ cache.clear()
638
+ },
639
+
640
+ /**
641
+ * Get cache size
642
+ */
643
+ get size(): number {
644
+ return cache.size
645
+ },
646
+
647
+ /**
648
+ * Get all keys
649
+ */
650
+ keys(): string[] {
651
+ return Array.from(cache.keys())
652
+ },
653
+
654
+ /**
655
+ * Get all values
656
+ */
657
+ values(): T[] {
658
+ return Array.from(cache.values())
659
+ },
660
+
661
+ /**
662
+ * Iterate over entries
663
+ */
664
+ forEach(callback: (value: T, key: string) => void): void {
665
+ cache.forEach(callback)
666
+ },
667
+ }
668
+ }
669
+
670
+ /**
671
+ * State manager for component state preservation
672
+ *
673
+ * Manages component state with automatic serialization/deserialization
674
+ *
675
+ * @example
676
+ * ```ts
677
+ * const stateManager = createStateManager()
678
+ *
679
+ * // Save state
680
+ * stateManager.save('my-component', { count: 5 })
681
+ *
682
+ * // Restore state
683
+ * const state = stateManager.restore('my-component')
684
+ * console.log(state.count) // 5
685
+ * ```
686
+ */
687
+ export function createStateManager() {
688
+ const states = new Map<string, Record<string, any>>()
689
+
690
+ return {
691
+ /**
692
+ * Save component state
693
+ */
694
+ save(key: string, state: Record<string, any>): void {
695
+ // Deep clone to avoid mutations
696
+ states.set(key, JSON.parse(JSON.stringify(state)))
697
+ },
698
+
699
+ /**
700
+ * Restore component state
701
+ */
702
+ restore(key: string): Record<string, any> | null {
703
+ const state = states.get(key)
704
+ return state ? JSON.parse(JSON.stringify(state)) : null
705
+ },
706
+
707
+ /**
708
+ * Check if state exists
709
+ */
710
+ has(key: string): boolean {
711
+ return states.has(key)
712
+ },
713
+
714
+ /**
715
+ * Remove saved state
716
+ */
717
+ remove(key: string): boolean {
718
+ return states.delete(key)
719
+ },
720
+
721
+ /**
722
+ * Clear all saved states
723
+ */
724
+ clear(): void {
725
+ states.clear()
726
+ },
727
+
728
+ /**
729
+ * Get all state keys
730
+ */
731
+ keys(): string[] {
732
+ return Array.from(states.keys())
733
+ },
734
+
735
+ /**
736
+ * Get number of saved states
737
+ */
738
+ get size(): number {
739
+ return states.size
740
+ },
741
+ }
742
+ }
743
+
744
+ /**
745
+ * Create a component pool for object reuse
746
+ *
747
+ * Useful for frequently created/destroyed components to reduce GC pressure
748
+ *
749
+ * @param factory - Function to create new instances
750
+ * @param options - Pool configuration
751
+ * @param options.maxSize - Maximum pool size
752
+ * @param options.reset - Function to reset instance before reuse
753
+ * @returns Component pool
754
+ *
755
+ * @example
756
+ * ```ts
757
+ * const pool = createComponentPool(
758
+ * () => ({ id: '', type: '', state: {} }),
759
+ * { maxSize: 50 }
760
+ * )
761
+ *
762
+ * const instance = pool.acquire()
763
+ * // Use instance...
764
+ * pool.release(instance)
765
+ * ```
766
+ */
767
+ export function createComponentPool<T>(
768
+ factory: () => T,
769
+ options: { maxSize?: number, reset?: (instance: T) => void } = {},
770
+ ) {
771
+ const { maxSize = 100, reset } = options
772
+ const pool: T[] = []
773
+
774
+ return {
775
+ /**
776
+ * Acquire instance from pool
777
+ */
778
+ acquire(): T {
779
+ if (pool.length > 0) {
780
+ return pool.pop()!
781
+ }
782
+ return factory()
783
+ },
784
+
785
+ /**
786
+ * Release instance back to pool
787
+ */
788
+ release(instance: T): void {
789
+ if (pool.length < maxSize) {
790
+ if (reset) {
791
+ reset(instance)
792
+ }
793
+ pool.push(instance)
794
+ }
795
+ },
796
+
797
+ /**
798
+ * Clear the pool
799
+ */
800
+ clear(): void {
801
+ pool.length = 0
802
+ },
803
+
804
+ /**
805
+ * Get pool size
806
+ */
807
+ get size(): number {
808
+ return pool.length
809
+ },
810
+
811
+ /**
812
+ * Get max pool size
813
+ */
814
+ get maxSize(): number {
815
+ return maxSize
816
+ },
817
+ }
818
+ }