@elurjs/ionic 1.6.1

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 (388) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/MIGRATION.md +221 -0
  3. package/README.md +695 -0
  4. package/dist/lib/IonRouterOutlet.d.ts +154 -0
  5. package/dist/lib/__tests__/IonRouterOutlet.test.d.ts +1 -0
  6. package/dist/lib/__tests__/bundles.test.d.ts +1 -0
  7. package/dist/lib/__tests__/cache-policy.test.d.ts +1 -0
  8. package/dist/lib/__tests__/capacitor.test.d.ts +1 -0
  9. package/dist/lib/__tests__/components.test.d.ts +1 -0
  10. package/dist/lib/__tests__/devtools.test.d.ts +1 -0
  11. package/dist/lib/__tests__/lifecycle.test.d.ts +1 -0
  12. package/dist/lib/__tests__/mocks/ionic.d.ts +61 -0
  13. package/dist/lib/__tests__/navigation.test.d.ts +1 -0
  14. package/dist/lib/__tests__/overlays.test.d.ts +1 -0
  15. package/dist/lib/__tests__/page-state.test.d.ts +1 -0
  16. package/dist/lib/__tests__/phase0-bugs.test.d.ts +1 -0
  17. package/dist/lib/__tests__/setup.d.ts +1 -0
  18. package/dist/lib/__tests__/setup.test.d.ts +1 -0
  19. package/dist/lib/__tests__/tabs.test.d.ts +1 -0
  20. package/dist/lib/__tests__/vite-plugin.test.d.ts +1 -0
  21. package/dist/lib/bundles/all.cjs +2 -0
  22. package/dist/lib/bundles/all.cjs.map +1 -0
  23. package/dist/lib/bundles/all.d.ts +16 -0
  24. package/dist/lib/bundles/all.js +21 -0
  25. package/dist/lib/bundles/all.js.map +1 -0
  26. package/dist/lib/bundles/buttons.cjs +2 -0
  27. package/dist/lib/bundles/buttons.cjs.map +1 -0
  28. package/dist/lib/bundles/buttons.d.ts +7 -0
  29. package/dist/lib/bundles/buttons.js +17 -0
  30. package/dist/lib/bundles/buttons.js.map +1 -0
  31. package/dist/lib/bundles/feedback.cjs +2 -0
  32. package/dist/lib/bundles/feedback.cjs.map +1 -0
  33. package/dist/lib/bundles/feedback.d.ts +8 -0
  34. package/dist/lib/bundles/feedback.js +19 -0
  35. package/dist/lib/bundles/feedback.js.map +1 -0
  36. package/dist/lib/bundles/forms.cjs +2 -0
  37. package/dist/lib/bundles/forms.cjs.map +1 -0
  38. package/dist/lib/bundles/forms.d.ts +11 -0
  39. package/dist/lib/bundles/forms.js +47 -0
  40. package/dist/lib/bundles/forms.js.map +1 -0
  41. package/dist/lib/bundles/layout.cjs +2 -0
  42. package/dist/lib/bundles/layout.cjs.map +1 -0
  43. package/dist/lib/bundles/layout.d.ts +9 -0
  44. package/dist/lib/bundles/layout.js +33 -0
  45. package/dist/lib/bundles/layout.js.map +1 -0
  46. package/dist/lib/bundles/lists.cjs +2 -0
  47. package/dist/lib/bundles/lists.cjs.map +1 -0
  48. package/dist/lib/bundles/lists.d.ts +15 -0
  49. package/dist/lib/bundles/lists.js +65 -0
  50. package/dist/lib/bundles/lists.js.map +1 -0
  51. package/dist/lib/bundles/navigation.cjs +2 -0
  52. package/dist/lib/bundles/navigation.cjs.map +1 -0
  53. package/dist/lib/bundles/navigation.d.ts +9 -0
  54. package/dist/lib/bundles/navigation.js +29 -0
  55. package/dist/lib/bundles/navigation.js.map +1 -0
  56. package/dist/lib/bundles/overlays.cjs +2 -0
  57. package/dist/lib/bundles/overlays.cjs.map +1 -0
  58. package/dist/lib/bundles/overlays.d.ts +9 -0
  59. package/dist/lib/bundles/overlays.js +25 -0
  60. package/dist/lib/bundles/overlays.js.map +1 -0
  61. package/dist/lib/capacitor.cjs +2 -0
  62. package/dist/lib/capacitor.cjs.map +1 -0
  63. package/dist/lib/capacitor.d.ts +217 -0
  64. package/dist/lib/capacitor.js +223 -0
  65. package/dist/lib/capacitor.js.map +1 -0
  66. package/dist/lib/components/accordion-group.cjs +1 -0
  67. package/dist/lib/components/accordion-group.d.ts +11 -0
  68. package/dist/lib/components/accordion-group.js +2 -0
  69. package/dist/lib/components/accordion.cjs +1 -0
  70. package/dist/lib/components/accordion.d.ts +11 -0
  71. package/dist/lib/components/accordion.js +2 -0
  72. package/dist/lib/components/action-sheet.cjs +1 -0
  73. package/dist/lib/components/action-sheet.d.ts +11 -0
  74. package/dist/lib/components/action-sheet.js +2 -0
  75. package/dist/lib/components/alert.cjs +1 -0
  76. package/dist/lib/components/alert.d.ts +11 -0
  77. package/dist/lib/components/alert.js +2 -0
  78. package/dist/lib/components/avatar.cjs +1 -0
  79. package/dist/lib/components/avatar.d.ts +11 -0
  80. package/dist/lib/components/avatar.js +2 -0
  81. package/dist/lib/components/backdrop.cjs +1 -0
  82. package/dist/lib/components/backdrop.d.ts +11 -0
  83. package/dist/lib/components/backdrop.js +2 -0
  84. package/dist/lib/components/badge.cjs +1 -0
  85. package/dist/lib/components/badge.d.ts +11 -0
  86. package/dist/lib/components/badge.js +2 -0
  87. package/dist/lib/components/breadcrumb.cjs +1 -0
  88. package/dist/lib/components/breadcrumb.d.ts +11 -0
  89. package/dist/lib/components/breadcrumb.js +2 -0
  90. package/dist/lib/components/breadcrumbs.cjs +1 -0
  91. package/dist/lib/components/breadcrumbs.d.ts +11 -0
  92. package/dist/lib/components/breadcrumbs.js +2 -0
  93. package/dist/lib/components/button.cjs +1 -0
  94. package/dist/lib/components/button.d.ts +11 -0
  95. package/dist/lib/components/button.js +2 -0
  96. package/dist/lib/components/buttons.cjs +1 -0
  97. package/dist/lib/components/buttons.d.ts +11 -0
  98. package/dist/lib/components/buttons.js +2 -0
  99. package/dist/lib/components/card-content.cjs +1 -0
  100. package/dist/lib/components/card-content.d.ts +11 -0
  101. package/dist/lib/components/card-content.js +2 -0
  102. package/dist/lib/components/card-header.cjs +1 -0
  103. package/dist/lib/components/card-header.d.ts +11 -0
  104. package/dist/lib/components/card-header.js +2 -0
  105. package/dist/lib/components/card-subtitle.cjs +1 -0
  106. package/dist/lib/components/card-subtitle.d.ts +11 -0
  107. package/dist/lib/components/card-subtitle.js +2 -0
  108. package/dist/lib/components/card-title.cjs +1 -0
  109. package/dist/lib/components/card-title.d.ts +11 -0
  110. package/dist/lib/components/card-title.js +2 -0
  111. package/dist/lib/components/card.cjs +1 -0
  112. package/dist/lib/components/card.d.ts +11 -0
  113. package/dist/lib/components/card.js +2 -0
  114. package/dist/lib/components/checkbox.cjs +1 -0
  115. package/dist/lib/components/checkbox.d.ts +11 -0
  116. package/dist/lib/components/checkbox.js +2 -0
  117. package/dist/lib/components/chip.cjs +1 -0
  118. package/dist/lib/components/chip.d.ts +11 -0
  119. package/dist/lib/components/chip.js +2 -0
  120. package/dist/lib/components/col.cjs +1 -0
  121. package/dist/lib/components/col.d.ts +11 -0
  122. package/dist/lib/components/col.js +2 -0
  123. package/dist/lib/components/content.cjs +1 -0
  124. package/dist/lib/components/content.d.ts +11 -0
  125. package/dist/lib/components/content.js +2 -0
  126. package/dist/lib/components/datetime-button.cjs +1 -0
  127. package/dist/lib/components/datetime-button.d.ts +11 -0
  128. package/dist/lib/components/datetime-button.js +2 -0
  129. package/dist/lib/components/datetime.cjs +1 -0
  130. package/dist/lib/components/datetime.d.ts +11 -0
  131. package/dist/lib/components/datetime.js +2 -0
  132. package/dist/lib/components/fab-button.cjs +1 -0
  133. package/dist/lib/components/fab-button.d.ts +11 -0
  134. package/dist/lib/components/fab-button.js +2 -0
  135. package/dist/lib/components/fab-list.cjs +1 -0
  136. package/dist/lib/components/fab-list.d.ts +11 -0
  137. package/dist/lib/components/fab-list.js +2 -0
  138. package/dist/lib/components/fab.cjs +1 -0
  139. package/dist/lib/components/fab.d.ts +11 -0
  140. package/dist/lib/components/fab.js +2 -0
  141. package/dist/lib/components/footer.cjs +1 -0
  142. package/dist/lib/components/footer.d.ts +11 -0
  143. package/dist/lib/components/footer.js +2 -0
  144. package/dist/lib/components/grid.cjs +1 -0
  145. package/dist/lib/components/grid.d.ts +11 -0
  146. package/dist/lib/components/grid.js +2 -0
  147. package/dist/lib/components/header.cjs +1 -0
  148. package/dist/lib/components/header.d.ts +11 -0
  149. package/dist/lib/components/header.js +2 -0
  150. package/dist/lib/components/img.cjs +1 -0
  151. package/dist/lib/components/img.d.ts +11 -0
  152. package/dist/lib/components/img.js +2 -0
  153. package/dist/lib/components/infinite-scroll-content.cjs +1 -0
  154. package/dist/lib/components/infinite-scroll-content.d.ts +11 -0
  155. package/dist/lib/components/infinite-scroll-content.js +2 -0
  156. package/dist/lib/components/infinite-scroll.cjs +1 -0
  157. package/dist/lib/components/infinite-scroll.d.ts +11 -0
  158. package/dist/lib/components/infinite-scroll.js +2 -0
  159. package/dist/lib/components/input-otp.cjs +1 -0
  160. package/dist/lib/components/input-otp.d.ts +11 -0
  161. package/dist/lib/components/input-otp.js +2 -0
  162. package/dist/lib/components/input-password-toggle.cjs +1 -0
  163. package/dist/lib/components/input-password-toggle.d.ts +11 -0
  164. package/dist/lib/components/input-password-toggle.js +2 -0
  165. package/dist/lib/components/input.cjs +1 -0
  166. package/dist/lib/components/input.d.ts +11 -0
  167. package/dist/lib/components/input.js +2 -0
  168. package/dist/lib/components/item-divider.cjs +1 -0
  169. package/dist/lib/components/item-divider.d.ts +11 -0
  170. package/dist/lib/components/item-divider.js +2 -0
  171. package/dist/lib/components/item-group.cjs +1 -0
  172. package/dist/lib/components/item-group.d.ts +11 -0
  173. package/dist/lib/components/item-group.js +2 -0
  174. package/dist/lib/components/item-option.cjs +1 -0
  175. package/dist/lib/components/item-option.d.ts +11 -0
  176. package/dist/lib/components/item-option.js +2 -0
  177. package/dist/lib/components/item-options.cjs +1 -0
  178. package/dist/lib/components/item-options.d.ts +11 -0
  179. package/dist/lib/components/item-options.js +2 -0
  180. package/dist/lib/components/item-sliding.cjs +1 -0
  181. package/dist/lib/components/item-sliding.d.ts +11 -0
  182. package/dist/lib/components/item-sliding.js +2 -0
  183. package/dist/lib/components/item.cjs +1 -0
  184. package/dist/lib/components/item.d.ts +11 -0
  185. package/dist/lib/components/item.js +2 -0
  186. package/dist/lib/components/label.cjs +1 -0
  187. package/dist/lib/components/label.d.ts +11 -0
  188. package/dist/lib/components/label.js +2 -0
  189. package/dist/lib/components/list-header.cjs +1 -0
  190. package/dist/lib/components/list-header.d.ts +11 -0
  191. package/dist/lib/components/list-header.js +2 -0
  192. package/dist/lib/components/list.cjs +1 -0
  193. package/dist/lib/components/list.d.ts +11 -0
  194. package/dist/lib/components/list.js +2 -0
  195. package/dist/lib/components/loading.cjs +1 -0
  196. package/dist/lib/components/loading.d.ts +11 -0
  197. package/dist/lib/components/loading.js +2 -0
  198. package/dist/lib/components/manifest.cjs +2 -0
  199. package/dist/lib/components/manifest.cjs.map +1 -0
  200. package/dist/lib/components/manifest.d.ts +43 -0
  201. package/dist/lib/components/manifest.js +647 -0
  202. package/dist/lib/components/manifest.js.map +1 -0
  203. package/dist/lib/components/menu-button.cjs +1 -0
  204. package/dist/lib/components/menu-button.d.ts +11 -0
  205. package/dist/lib/components/menu-button.js +2 -0
  206. package/dist/lib/components/menu-toggle.cjs +1 -0
  207. package/dist/lib/components/menu-toggle.d.ts +11 -0
  208. package/dist/lib/components/menu-toggle.js +2 -0
  209. package/dist/lib/components/menu.cjs +1 -0
  210. package/dist/lib/components/menu.d.ts +11 -0
  211. package/dist/lib/components/menu.js +2 -0
  212. package/dist/lib/components/modal.cjs +1 -0
  213. package/dist/lib/components/modal.d.ts +11 -0
  214. package/dist/lib/components/modal.js +2 -0
  215. package/dist/lib/components/nav-link.cjs +1 -0
  216. package/dist/lib/components/nav-link.d.ts +11 -0
  217. package/dist/lib/components/nav-link.js +2 -0
  218. package/dist/lib/components/nav.cjs +1 -0
  219. package/dist/lib/components/nav.d.ts +11 -0
  220. package/dist/lib/components/nav.js +2 -0
  221. package/dist/lib/components/note.cjs +1 -0
  222. package/dist/lib/components/note.d.ts +11 -0
  223. package/dist/lib/components/note.js +2 -0
  224. package/dist/lib/components/picker-column-option.cjs +1 -0
  225. package/dist/lib/components/picker-column-option.d.ts +11 -0
  226. package/dist/lib/components/picker-column-option.js +2 -0
  227. package/dist/lib/components/picker-column.cjs +1 -0
  228. package/dist/lib/components/picker-column.d.ts +11 -0
  229. package/dist/lib/components/picker-column.js +2 -0
  230. package/dist/lib/components/picker.cjs +1 -0
  231. package/dist/lib/components/picker.d.ts +11 -0
  232. package/dist/lib/components/picker.js +2 -0
  233. package/dist/lib/components/popover.cjs +1 -0
  234. package/dist/lib/components/popover.d.ts +11 -0
  235. package/dist/lib/components/popover.js +2 -0
  236. package/dist/lib/components/progress-bar.cjs +1 -0
  237. package/dist/lib/components/progress-bar.d.ts +11 -0
  238. package/dist/lib/components/progress-bar.js +2 -0
  239. package/dist/lib/components/radio-group.cjs +1 -0
  240. package/dist/lib/components/radio-group.d.ts +11 -0
  241. package/dist/lib/components/radio-group.js +2 -0
  242. package/dist/lib/components/radio.cjs +1 -0
  243. package/dist/lib/components/radio.d.ts +11 -0
  244. package/dist/lib/components/radio.js +2 -0
  245. package/dist/lib/components/range.cjs +1 -0
  246. package/dist/lib/components/range.d.ts +11 -0
  247. package/dist/lib/components/range.js +2 -0
  248. package/dist/lib/components/refresher-content.cjs +1 -0
  249. package/dist/lib/components/refresher-content.d.ts +11 -0
  250. package/dist/lib/components/refresher-content.js +2 -0
  251. package/dist/lib/components/refresher.cjs +1 -0
  252. package/dist/lib/components/refresher.d.ts +11 -0
  253. package/dist/lib/components/refresher.js +2 -0
  254. package/dist/lib/components/reorder-group.cjs +1 -0
  255. package/dist/lib/components/reorder-group.d.ts +11 -0
  256. package/dist/lib/components/reorder-group.js +2 -0
  257. package/dist/lib/components/reorder.cjs +1 -0
  258. package/dist/lib/components/reorder.d.ts +11 -0
  259. package/dist/lib/components/reorder.js +2 -0
  260. package/dist/lib/components/ripple-effect.cjs +1 -0
  261. package/dist/lib/components/ripple-effect.d.ts +11 -0
  262. package/dist/lib/components/ripple-effect.js +2 -0
  263. package/dist/lib/components/router-link.cjs +1 -0
  264. package/dist/lib/components/router-link.d.ts +11 -0
  265. package/dist/lib/components/router-link.js +2 -0
  266. package/dist/lib/components/row.cjs +1 -0
  267. package/dist/lib/components/row.d.ts +11 -0
  268. package/dist/lib/components/row.js +2 -0
  269. package/dist/lib/components/searchbar.cjs +1 -0
  270. package/dist/lib/components/searchbar.d.ts +11 -0
  271. package/dist/lib/components/searchbar.js +2 -0
  272. package/dist/lib/components/segment-button.cjs +1 -0
  273. package/dist/lib/components/segment-button.d.ts +11 -0
  274. package/dist/lib/components/segment-button.js +2 -0
  275. package/dist/lib/components/segment-content.cjs +1 -0
  276. package/dist/lib/components/segment-content.d.ts +11 -0
  277. package/dist/lib/components/segment-content.js +2 -0
  278. package/dist/lib/components/segment-view.cjs +1 -0
  279. package/dist/lib/components/segment-view.d.ts +11 -0
  280. package/dist/lib/components/segment-view.js +2 -0
  281. package/dist/lib/components/segment.cjs +1 -0
  282. package/dist/lib/components/segment.d.ts +11 -0
  283. package/dist/lib/components/segment.js +2 -0
  284. package/dist/lib/components/select-modal.cjs +1 -0
  285. package/dist/lib/components/select-modal.d.ts +11 -0
  286. package/dist/lib/components/select-modal.js +2 -0
  287. package/dist/lib/components/select-option.cjs +1 -0
  288. package/dist/lib/components/select-option.d.ts +11 -0
  289. package/dist/lib/components/select-option.js +2 -0
  290. package/dist/lib/components/select-popover.cjs +1 -0
  291. package/dist/lib/components/select-popover.d.ts +11 -0
  292. package/dist/lib/components/select-popover.js +2 -0
  293. package/dist/lib/components/select.cjs +1 -0
  294. package/dist/lib/components/select.d.ts +11 -0
  295. package/dist/lib/components/select.js +2 -0
  296. package/dist/lib/components/skeleton-text.cjs +1 -0
  297. package/dist/lib/components/skeleton-text.d.ts +11 -0
  298. package/dist/lib/components/skeleton-text.js +2 -0
  299. package/dist/lib/components/spinner.cjs +1 -0
  300. package/dist/lib/components/spinner.d.ts +11 -0
  301. package/dist/lib/components/spinner.js +2 -0
  302. package/dist/lib/components/split-pane.cjs +1 -0
  303. package/dist/lib/components/split-pane.d.ts +11 -0
  304. package/dist/lib/components/split-pane.js +2 -0
  305. package/dist/lib/components/tab-bar.cjs +1 -0
  306. package/dist/lib/components/tab-bar.d.ts +11 -0
  307. package/dist/lib/components/tab-bar.js +2 -0
  308. package/dist/lib/components/tab-button.cjs +1 -0
  309. package/dist/lib/components/tab-button.d.ts +11 -0
  310. package/dist/lib/components/tab-button.js +2 -0
  311. package/dist/lib/components/tab.cjs +1 -0
  312. package/dist/lib/components/tab.d.ts +11 -0
  313. package/dist/lib/components/tab.js +2 -0
  314. package/dist/lib/components/tabs.cjs +1 -0
  315. package/dist/lib/components/tabs.d.ts +11 -0
  316. package/dist/lib/components/tabs.js +2 -0
  317. package/dist/lib/components/text.cjs +1 -0
  318. package/dist/lib/components/text.d.ts +11 -0
  319. package/dist/lib/components/text.js +2 -0
  320. package/dist/lib/components/textarea.cjs +1 -0
  321. package/dist/lib/components/textarea.d.ts +11 -0
  322. package/dist/lib/components/textarea.js +2 -0
  323. package/dist/lib/components/thumbnail.cjs +1 -0
  324. package/dist/lib/components/thumbnail.d.ts +11 -0
  325. package/dist/lib/components/thumbnail.js +2 -0
  326. package/dist/lib/components/title.cjs +1 -0
  327. package/dist/lib/components/title.d.ts +11 -0
  328. package/dist/lib/components/title.js +2 -0
  329. package/dist/lib/components/toast.cjs +1 -0
  330. package/dist/lib/components/toast.d.ts +11 -0
  331. package/dist/lib/components/toast.js +2 -0
  332. package/dist/lib/components/toggle.cjs +1 -0
  333. package/dist/lib/components/toggle.d.ts +11 -0
  334. package/dist/lib/components/toggle.js +2 -0
  335. package/dist/lib/components/toolbar.cjs +1 -0
  336. package/dist/lib/components/toolbar.d.ts +11 -0
  337. package/dist/lib/components/toolbar.js +2 -0
  338. package/dist/lib/components.cjs +1 -0
  339. package/dist/lib/components.d.ts +110 -0
  340. package/dist/lib/components.js +94 -0
  341. package/dist/lib/definitions-CmPIrLhr.js +282 -0
  342. package/dist/lib/definitions-CmPIrLhr.js.map +1 -0
  343. package/dist/lib/definitions-CrcjkKEd.cjs +2 -0
  344. package/dist/lib/definitions-CrcjkKEd.cjs.map +1 -0
  345. package/dist/lib/devtools.cjs +2 -0
  346. package/dist/lib/devtools.cjs.map +1 -0
  347. package/dist/lib/devtools.d.ts +54 -0
  348. package/dist/lib/devtools.js +46 -0
  349. package/dist/lib/devtools.js.map +1 -0
  350. package/dist/lib/elur-ionic.cjs +1 -0
  351. package/dist/lib/elur-ionic.cjs.map +1 -0
  352. package/dist/lib/elur-ionic.js +1 -0
  353. package/dist/lib/elur-ionic.js.map +1 -0
  354. package/dist/lib/index.d.ts +47 -0
  355. package/dist/lib/lifecycle.d.ts +62 -0
  356. package/dist/lib/navigation.cjs +2 -0
  357. package/dist/lib/navigation.cjs.map +1 -0
  358. package/dist/lib/navigation.d.ts +214 -0
  359. package/dist/lib/navigation.js +205 -0
  360. package/dist/lib/navigation.js.map +1 -0
  361. package/dist/lib/overlays.cjs +2 -0
  362. package/dist/lib/overlays.cjs.map +1 -0
  363. package/dist/lib/overlays.d.ts +400 -0
  364. package/dist/lib/overlays.js +161 -0
  365. package/dist/lib/overlays.js.map +1 -0
  366. package/dist/lib/page-state.cjs +2 -0
  367. package/dist/lib/page-state.cjs.map +1 -0
  368. package/dist/lib/page-state.d.ts +160 -0
  369. package/dist/lib/page-state.js +91 -0
  370. package/dist/lib/page-state.js.map +1 -0
  371. package/dist/lib/setup.d.ts +105 -0
  372. package/dist/lib/tabs-ByPLrzax.cjs +50 -0
  373. package/dist/lib/tabs-ByPLrzax.cjs.map +1 -0
  374. package/dist/lib/tabs-DjD1_PTM.js +178 -0
  375. package/dist/lib/tabs-DjD1_PTM.js.map +1 -0
  376. package/dist/lib/tabs.cjs +1 -0
  377. package/dist/lib/tabs.d.ts +83 -0
  378. package/dist/lib/tabs.js +2 -0
  379. package/dist/lib/vite-plugin.cjs +38 -0
  380. package/dist/lib/vite-plugin.cjs.map +1 -0
  381. package/dist/lib/vite-plugin.d.ts +61 -0
  382. package/dist/lib/vite-plugin.js +25411 -0
  383. package/dist/lib/vite-plugin.js.map +1 -0
  384. package/dist/lib/web-Bnz2Zs_W.cjs +2 -0
  385. package/dist/lib/web-Bnz2Zs_W.cjs.map +1 -0
  386. package/dist/lib/web-Ce5OM4dv.js +56 -0
  387. package/dist/lib/web-Ce5OM4dv.js.map +1 -0
  388. package/package.json +216 -0
package/README.md ADDED
@@ -0,0 +1,695 @@
1
+ # @elurjs/ionic
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@elurjs/ionic.svg)](https://www.npmjs.com/package/@elurjs/ionic)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ > Ionic mobile integration for [Elur](https://elur.dev/) — tree-shakeable components, reactive overlays, cache policies, page-state persistence, optional Capacitor, and a Vite plugin for auto-registration.
7
+
8
+ ## Why?
9
+
10
+ `@elurjs/ionic` bridges Elur signal-based reactivity with Ionic Core 8's native routing, transitions, and overlays. Unlike `@ionic/angular` or `@ionic/react`, it adds **zero framework runtime overhead** — no virtual DOM, no dependency arrays, no hooks rules.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @elurjs/ionic @elurjs/core @ionic/core ionicons
16
+ ```
17
+
18
+ For native mobile (optional):
19
+
20
+ ```bash
21
+ npm install @capacitor/core @capacitor/app @capacitor/status-bar @capacitor/splash-screen @capacitor/keyboard @capacitor/haptics
22
+ ```
23
+
24
+ ## Quick start
25
+
26
+ ```ts
27
+ // main.ts
28
+ import "@ionic/core/css/core.css";
29
+ import "@ionic/core/css/normalize.css";
30
+ import "@ionic/core/css/structure.css";
31
+ import "@ionic/core/css/typography.css";
32
+ import "@ionic/core/css/padding.css";
33
+ import "@ionic/core/css/flex-utils.css";
34
+ import "@ionic/core/css/display.css";
35
+
36
+ import { ElurComponent, html, mount } from "@elurjs/core";
37
+ import { IonRouterOutlet, IonPage, IonBackButton } from "@elurjs/ionic";
38
+ import { initializeElurIonic, registerIonicComponents } from "@elurjs/ionic";
39
+ import { defineIonHeader, defineIonToolbar, defineIonTitle, defineIonContent, defineIonButton } from "@elurjs/ionic/components";
40
+ import { home, homeOutline } from "ionicons/icons";
41
+
42
+ // 1. Initialize + register only what you use
43
+ initializeElurIonic();
44
+ registerIonicComponents(defineIonHeader, defineIonToolbar, defineIonTitle, defineIonContent, defineIonButton);
45
+
46
+ // 2. Define routes
47
+ const outlet = new IonRouterOutlet([
48
+ { path: "/", component: () => html`<ion-content><h1>Home</h1></ion-content>` },
49
+ { path: "/detail/:id", component: (ctx) => new DetailPage(ctx) },
50
+ ]);
51
+
52
+ // 3. Mount
53
+ class App extends ElurComponent {
54
+ override render() {
55
+ return html`<ion-app>${outlet}</ion-app>`;
56
+ }
57
+ }
58
+ mount(new App(), "#app");
59
+ ```
60
+
61
+ ## Subpaths
62
+
63
+ | Import | What it gives you |
64
+ |---|---|
65
+ | `@elurjs/ionic` | Core: router outlet, pages, lifecycle, setup, overlays, page-state |
66
+ | `@elurjs/ionic/components/*` | Individual component definers (tree-shakeable) |
67
+ | `@elurjs/ionic/bundles/*` | Category bundles (layout, forms, lists, etc.) |
68
+ | `@elurjs/ionic/overlays` | Reactive overlay controllers |
69
+ | `@elurjs/ionic/page-state` | Page-state persistence protocol |
70
+ | `@elurjs/ionic/navigation` | NavigationManager (single authority, hooks, tab switching) |
71
+ | `@elurjs/ionic/capacitor` | Optional Capacitor integration (zero web bundle cost) |
72
+
73
+ ## Testing
74
+
75
+ - **Unit tests**: `npm test` — 234 tests with happy-dom mocks
76
+ - **E2E tests**: `npm run e2e` — 12 Playwright tests with real `@ionic/core`
77
+ - Navigation, lifecycle, overlays, back button, contract tests
78
+ - Chromium mobile viewport, `prefers-reduced-motion: reduce`
79
+ - No mocks — real `ion-router-outlet.commit()`, real custom elements
80
+ | `@elurjs/ionic/vite-plugin` | Vite plugin for auto component/icon registration |
81
+
82
+ ## Setup
83
+
84
+ ### Incremental (recommended)
85
+
86
+ ```ts
87
+ import { initializeElurIonic, registerIonicComponents, registerIonicons } from "@elurjs/ionic";
88
+ import { defineIonButton, defineIonCard } from "@elurjs/ionic/components/button";
89
+ import { star, starOutline } from "ionicons/icons";
90
+
91
+ initializeElurIonic();
92
+ registerIonicComponents(defineIonButton, defineIonCard);
93
+ registerIonicons({ star, "star-outline": starOutline });
94
+ ```
95
+
96
+ ### Compatibility facade (1.x migration)
97
+
98
+ ```ts
99
+ import { setupElurIonic } from "@elurjs/ionic";
100
+ import { allComponents } from "@elurjs/ionic/bundles/all";
101
+
102
+ setupElurIonic({ components: allComponents });
103
+ ```
104
+
105
+ ### Vite plugin (auto-registration)
106
+
107
+ ```ts
108
+ // vite.config.ts
109
+ import { defineConfig } from "vite";
110
+ import { elur } from "@elurjs/vite-plugin-elur";
111
+ import { elurIonic } from "@elurjs/ionic/vite-plugin";
112
+
113
+ export default defineConfig({
114
+ plugins: [
115
+ elur(),
116
+ elurIonic(), // scans html`` for <ion-*> tags + static icons
117
+ ],
118
+ });
119
+
120
+ // Then in your app entry:
121
+ import "virtual:elur-ionic/registration";
122
+ ```
123
+
124
+ The plugin scans `html\`\`` templates for `<ion-*>` tags and `name="icon-name"` attributes, then generates a virtual module that imports and registers only what you use.
125
+
126
+ ## Pages
127
+
128
+ ### Class component with lifecycle
129
+
130
+ ```ts
131
+ import { html, signal } from "@elurjs/core";
132
+ import { IonPage, IonBackButton, type PageContext } from "@elurjs/ionic";
133
+
134
+ class DetailPage extends IonPage {
135
+ private data = signal<unknown>(null);
136
+ private id: string;
137
+
138
+ constructor({ lc, params }: PageContext) {
139
+ super(lc);
140
+ this.id = params.id;
141
+ }
142
+
143
+ override ionViewWillEnter() {
144
+ // Runs on every activation — even from cache
145
+ fetch(`/api/items/${this.id}`).then(r => r.json()).then(d => this.data.value = d);
146
+ }
147
+
148
+ override ionViewWillLeave() {
149
+ // Pause timers, subscriptions, etc.
150
+ }
151
+
152
+ override render() {
153
+ return html`
154
+ <ion-header>
155
+ <ion-toolbar>
156
+ <ion-buttons slot="start">${IonBackButton()}</ion-buttons>
157
+ <ion-title>Detail</ion-title>
158
+ </ion-toolbar>
159
+ </ion-header>
160
+ <ion-content class="ion-padding">
161
+ <p>${() => JSON.stringify(this.data.value)}</p>
162
+ </ion-content>
163
+ `;
164
+ }
165
+ }
166
+ ```
167
+
168
+ ### Function component with composables
169
+
170
+ ```ts
171
+ import { html, signal } from "@elurjs/core";
172
+ import { useIonViewWillEnter, useIonViewWillLeave, type PageContext } from "@elurjs/ionic";
173
+
174
+ function ProfilePage({ lc }: PageContext) {
175
+ const visits = signal(0);
176
+ useIonViewWillEnter(lc, () => visits.value++);
177
+ useIonViewWillLeave(lc, () => console.log("leaving"));
178
+ return html`<ion-content><p>Visits: ${() => visits.value}</p></ion-content>`;
179
+ }
180
+ ```
181
+
182
+ ### Lifecycle hooks
183
+
184
+ | Hook | When | Use for |
185
+ |---|---|---|
186
+ | `ionViewWillEnter` | Before visible (every activation) | Data refresh, restart timers |
187
+ | `ionViewDidEnter` | After fully visible | Analytics, scroll position |
188
+ | `ionViewWillLeave` | Before hidden | Pause timers, save state |
189
+ | `ionViewDidLeave` | After hidden | Cleanup subscriptions |
190
+
191
+ > **Key**: `onMount`/`onInit` fire once. `ionViewWillEnter` fires on every visit — even from cache.
192
+
193
+ ## Navigation
194
+
195
+ ```ts
196
+ import { elurRouter } from "@elurjs/core";
197
+
198
+ const router = elurRouter();
199
+ router.navigate("/detail/42");
200
+ router.navigate("/search", { query: { q: "hello" } });
201
+ router.replace("/home");
202
+ router.back();
203
+
204
+ router.current.value; // "/detail/42"
205
+ router.params.value; // { id: "42" }
206
+ router.query.value; // { q: "hello" }
207
+ router.canGoBack.value; // true/false
208
+ ```
209
+
210
+ ### Route guards
211
+
212
+ ```ts
213
+ new IonRouterOutlet([
214
+ {
215
+ path: "/admin",
216
+ component: (ctx) => new AdminPage(ctx),
217
+ beforeEnter: ({ params }) => {
218
+ if (!isLoggedIn()) return "/login"; // redirect
219
+ if (!isAdmin()) return false; // cancel
220
+ // void/undefined = allow
221
+ },
222
+ },
223
+ ]);
224
+ ```
225
+
226
+ ## Cache policies
227
+
228
+ Control how many pages stay cached and for how long.
229
+
230
+ ```ts
231
+ new IonRouterOutlet(routes, {
232
+ cachePolicy: { max: 10, ttl: 60000, strategy: "lru" },
233
+ });
234
+ ```
235
+
236
+ | Option | Default | Description |
237
+ |---|---|---|
238
+ | `max` | unlimited | Max cached entries per tab. Excess evicted by strategy. |
239
+ | `ttl` | unlimited | Time-to-live in ms. Entries auto-evicted on expiry. |
240
+ | `strategy` | `"lru"` | `"lru"` = evict least-recently-used, `"fifo"` = evict oldest |
241
+
242
+ ### Per-route override
243
+
244
+ ```ts
245
+ new IonRouterOutlet([
246
+ { path: "/", component: () => html`...` },
247
+ { path: "/transient", cache: false, component: () => html`...` }, // never cache
248
+ { path: "/heavy", cache: { max: 1 }, component: () => html`...` }, // max 1 instance
249
+ { path: "/volatile", cache: { ttl: 5000 }, component: () => html`...` }, // 5s TTL
250
+ ]);
251
+ ```
252
+
253
+ ## NavigationManager
254
+
255
+ A single coordination authority for navigation — hooks, tab switching, and cache invalidation by route pattern.
256
+
257
+ ```ts
258
+ import { NavigationManager, IonRouterOutlet } from "@elurjs/ionic";
259
+
260
+ const nav = new NavigationManager({ tabs: ["/home", "/search", "/profile"] });
261
+
262
+ // Navigation hooks
263
+ nav.beforeNav((path, intent) => {
264
+ console.log("navigating to", path);
265
+ // return false to cancel
266
+ });
267
+
268
+ nav.afterNav((path, direction) => {
269
+ analytics.track("page_view", { path, direction });
270
+ });
271
+
272
+ nav.onTabChange((tab, prev) => {
273
+ console.log("tab changed:", prev, "→", tab);
274
+ });
275
+
276
+ // Programmatic tab switching
277
+ const target = nav.switchTab("/search");
278
+ if (target) elurRouter().navigate(target);
279
+
280
+ // Cache invalidation by route pattern
281
+ nav.invalidateRoute("/user/:id", { id: "42" }); // invalidate user 42
282
+ nav.invalidatePattern("/admin/*"); // invalidate all admin pages
283
+
284
+ // Pass to outlet
285
+ const outlet = new IonRouterOutlet(routes, { navigation: nav });
286
+ ```
287
+
288
+ ### Stack inspection
289
+
290
+ ```ts
291
+ nav.stackDepth(); // current tab stack depth
292
+ nav.stackTop(); // current tab stack top path
293
+ nav.stackEntries(); // copy of current tab stack
294
+ nav.activeTab; // active tab prefix
295
+ ```
296
+
297
+ ## Overlays
298
+
299
+ Reactive overlay controllers using the `create*` pattern (like `createStore`, `createRouter`).
300
+
301
+ `createPopover()` and `createModal()` automatically inject a Elur framework
302
+ delegate when `component` is a function (e.g. `() => html\`...\``), so you can
303
+ pass Elur templates as overlay content without any extra setup.
304
+
305
+ ```ts
306
+ import { html } from "@elurjs/core";
307
+ import { createToast, createAlert, createModal, createPopover, confirm, withLoading } from "@elurjs/ionic";
308
+
309
+ function MyPage() {
310
+ const toast = createToast();
311
+ const modal = createModal();
312
+ const popover = createPopover();
313
+
314
+ const save = async () => {
315
+ await withLoading({ message: "Saving..." }, async () => {
316
+ await fetch("/api/save", { method: "POST" });
317
+ });
318
+ toast.present({ message: "Saved!", duration: 1500 });
319
+ };
320
+
321
+ const openModal = () => modal.present({
322
+ component: () => html`<ion-content><h1>Modal content mounted by Elur!</h1></ion-content>`,
323
+ });
324
+
325
+ const openPopover = (event: Event) => popover.present({
326
+ event,
327
+ component: () => html`
328
+ <div style="padding: 20px;">
329
+ <ion-button @click=${() => popover.dismiss()}>Close</ion-button>
330
+ </div>
331
+ `,
332
+ });
333
+
334
+ return html`
335
+ <ion-content>
336
+ <ion-button @click=${save}>Save</ion-button>
337
+ <ion-button @click=${openModal}>Open Modal</ion-button>
338
+ <ion-button @click=${(e: Event) => openPopover(e)}>Open Popover</ion-button>
339
+ ${() => modal.presented.value ? html`<p>Modal is open</p>` : null}
340
+ </ion-content>
341
+ `;
342
+ }
343
+ ```
344
+
345
+ > **Note:** The framework delegate is injected automatically when
346
+ > `component` is a function. If you pass a string (tag name) or
347
+ > `HTMLElement`, no delegate is needed and Ionic handles it natively.
348
+
349
+ ### Available controllers
350
+
351
+ | Controller | Description |
352
+ |---|---|
353
+ | `createToast()` | Reactive toast |
354
+ | `createAlert()` | Reactive alert |
355
+ | `createLoading()` | Reactive loading spinner |
356
+ | `createActionSheet()` | Reactive action sheet |
357
+ | `createPopover()` | Reactive popover (auto-injects Elur delegate for `component: () => html\`...\``) |
358
+ | `createModal()` | Reactive modal (auto-injects Elur delegate for `component: () => html\`...\``) |
359
+ | `createPicker()` | Column-based picker (lazy-registers `ion-picker-legacy`) |
360
+
361
+ ### One-shot helpers
362
+
363
+ ```ts
364
+ import { showToast, withLoading, confirm } from "@elurjs/ionic";
365
+
366
+ showToast({ message: "Done!", duration: 1000 });
367
+
368
+ const data = await withLoading({ message: "Fetching..." },
369
+ () => fetch("/api/data").then(r => r.json()));
370
+
371
+ const yes = await confirm({ header: "Delete", message: "Sure?", confirmText: "Delete" });
372
+ ```
373
+
374
+ ## Page-state persistence
375
+
376
+ Opt-in persistence of serializable state across navigation and app restarts.
377
+
378
+ ```ts
379
+ import { signal } from "@elurjs/core";
380
+ import { createPageState, IonPage } from "@elurjs/ionic";
381
+
382
+ class SearchPage extends IonPage {
383
+ private query = signal("");
384
+ private results = signal<string[]>([]);
385
+ private state = createPageState("search", {
386
+ query: this.query,
387
+ results: this.results,
388
+ }, { storage: "local" }); // persists across app restarts
389
+
390
+ override ionViewWillEnter() { this.state.restore(); }
391
+ override ionViewWillLeave() { this.state.save(); }
392
+ }
393
+ ```
394
+
395
+ **Rules:**
396
+ - Only serializable data (primitives, plain arrays/objects)
397
+ - DOM nodes, functions, symbols, class instances → rejected with warning
398
+ - `sessionStorage` (default) or `localStorage` (opt-in)
399
+ - `clearAllPageState()` for logout flows
400
+
401
+ ## Capacitor (optional native)
402
+
403
+ Isolated behind `@elurjs/ionic/capacitor` — **zero web bundle cost** (0 bytes of `@capacitor/*` in main bundle).
404
+
405
+ ```ts
406
+ import { createCapacitorApp } from "@elurjs/ionic/capacitor";
407
+
408
+ const app = createCapacitorApp({
409
+ statusBar: { style: "dark", backgroundColor: "#1a1a2e" },
410
+ splashScreen: { fadeOutDuration: 200 },
411
+ backButton: { defaultHref: "/home" },
412
+ });
413
+
414
+ await app.ready(); // configures status bar, hides splash, wires back button
415
+ ```
416
+
417
+ ### Individual plugins
418
+
419
+ ```ts
420
+ import { Haptics, StatusBar, App, Keyboard } from "@elurjs/ionic/capacitor";
421
+
422
+ await Haptics.impact("medium"); // no-op on web
423
+ await StatusBar.setStyle({ style: "dark" }); // no-op on web
424
+ App.onBackButton((info) => { /* ... */ }); // no-op on web
425
+ ```
426
+
427
+ All methods are **no-ops on web** — safe to call unconditionally.
428
+
429
+ ## Tabs
430
+
431
+ ```ts
432
+ import { createBottomTabBar, createTabsLayout, IonRouterOutlet, NavigationManager } from "@elurjs/ionic";
433
+ import { home, search, person, settings } from "ionicons/icons";
434
+
435
+ const nav = new NavigationManager({ tabs: ["/", "/search", "/profile", "/settings"] });
436
+
437
+ const outlet = new IonRouterOutlet(routes, {
438
+ tabs: ["/", "/search", "/profile", "/settings"],
439
+ navigation: nav,
440
+ });
441
+
442
+ const tabBar = createBottomTabBar([
443
+ { path: "/", label: "Home", icon: "home", exact: true },
444
+ { path: "/search", label: "Search", icon: "search" },
445
+ { path: "/profile", label: "Profile", icon: "person", badge: "!" },
446
+ { path: "/settings", label: "Settings", icon: "settings" },
447
+ ], {
448
+ hiddenPaths: ["/detail/*", "/profile/edit"],
449
+ icons: { home, search, person, settings },
450
+ cssVars: {
451
+ "--background": "var(--app-tab-bg)",
452
+ "--color-selected": "var(--ion-color-primary)",
453
+ },
454
+ });
455
+
456
+ // Wrap outlet + tab bar in <ion-tabs> with correct CSS layout
457
+ const tabsLayout = createTabsLayout(outlet, tabBar);
458
+
459
+ html`<ion-app>${tabsLayout}</ion-app>`;
460
+ ```
461
+
462
+ ### How tabs work
463
+
464
+ - **Navigation** is driven by the Elur router, not Ionic's internal tab
465
+ selection. Each `ion-tab-button` has `@click.prevent.stop` to prevent
466
+ Ionic's `select()` (which expects `<ion-tab>` children we don't use).
467
+ - **`createTabsLayout()`** wraps the outlet and tab bar in `<ion-tabs>`
468
+ and injects a small CSS snippet to ensure the tab bar sits at the
469
+ bottom and the outlet fills the remaining space.
470
+ - **Tab IDs** are derived from the path: `/` → `root`, `/search` →
471
+ `search`, `/profile/edit` → `profile-edit`. Override with `tabId`.
472
+ - **`selected` state** is set via JS property (`(btn as any).selected =
473
+ isActive`) using a `ref` + `effect` + `nextTick`, because Stencil
474
+ boolean props can't be set via HTML attributes with Elur.
475
+
476
+ ### Tab bar options
477
+
478
+ | Option | Type | Description |
479
+ |---|---|---|
480
+ | `slot` | `"top" \| "bottom"` | Tab bar position (default: `"bottom"`) |
481
+ | `layout` | `TabButtonLayout` | Icon/label layout (default: `"icon-top"`) |
482
+ | `hiddenPaths` | `string[]` | Paths where tab bar is hidden (supports `*` wildcards) |
483
+ | `hideWhen` | `(path: string) => boolean` | Dynamic hide callback |
484
+ | `icons` | `Record<string, IconDefinition>` | Icon SVG data for tab icons |
485
+ | `cssVars` | `Record<string, string>` | CSS custom properties on `ion-tab-bar` |
486
+ | `direction` | `NavigationDirection` | Navigation direction on tab switch (default: `"none"`) |
487
+
488
+ ### Tab item options
489
+
490
+ | Option | Type | Description |
491
+ |---|---|---|
492
+ | `path` | `string` | Route path |
493
+ | `label` | `string` | Tab label text |
494
+ | `icon` | `string` | Icon name (kebab-case) |
495
+ | `activeIcon` | `string` | Icon name when active (optional) |
496
+ | `exact` | `boolean` | Exact path match (default: `false`) |
497
+ | `tabId` | `string` | Override auto-generated tab ID |
498
+ | `badge` | `string \| number` | Badge content |
499
+ | `badgeColor` | `string` | Badge color (default: `"danger"`) |
500
+
501
+ ## Vite plugin
502
+
503
+ Auto-registers only the Ionic components and icons you actually use in `html\`\`` templates.
504
+
505
+ ```ts
506
+ // vite.config.ts
507
+ import { elurIonic } from "@elurjs/ionic/vite-plugin";
508
+
509
+ export default defineConfig({
510
+ plugins: [elurIonic()],
511
+ });
512
+ ```
513
+
514
+ ```ts
515
+ // app entry — imports the auto-generated virtual module
516
+ import "virtual:elur-ionic/registration";
517
+ ```
518
+
519
+ Features:
520
+ - Scans `html\`\`` for `<ion-*>` tags → generates direct subpath imports
521
+ - Scans `name="icon-name"` on `<ion-icon>` → generates `ionicons/icons` imports
522
+ - Warns on dynamic tags/icons (with allowlist suppression)
523
+ - `elurIonic({ allowTags: [...], allowIcons: [...] })` for dynamic usage
524
+
525
+ ### `allowTags` and `allowIcons` (important for lazy-loaded pages)
526
+
527
+ The Vite plugin scans your source files for `<ion-*>` tags and `name="icon-name"`
528
+ attributes, then generates a virtual module that imports and registers only what
529
+ you use. However, in dev mode, Vite loads modules on-demand. The virtual module
530
+ is served when your app entry imports it at startup, but pages loaded lazily by
531
+ the router may not have been scanned yet.
532
+
533
+ **Use `allowTags` and `allowIcons` to explicitly list tags/icons used in
534
+ lazy-loaded pages.** The plugin emits warnings when it detects tags or icons
535
+ that are not in the allowlists, so you know exactly what to add:
536
+
537
+ ```text
538
+ [elur-ionic] Tags used in src/pages/HomePage.ts but not in allowTags:
539
+ ion-header, ion-toolbar, ion-title, ion-content, ion-button, ...
540
+ Add them to `elurIonic({ allowTags: [...] })` to ensure they are
541
+ registered before first use.
542
+
543
+ [elur-ionic] Icons used in src/pages/HomePage.ts but not in allowIcons:
544
+ flash-outline, leaf-outline, toast-outline, ...
545
+ Add them to `elurIonic({ allowIcons: [...] })` to ensure they are
546
+ registered before first use.
547
+ ```
548
+
549
+ If new tags/icons are discovered after the registration module was already
550
+ served, an additional warning is emitted:
551
+
552
+ ```text
553
+ [elur-ionic] New tags discovered after registration: ion-header, ...
554
+ These were NOT included in the registration module. Add them to
555
+ allowTags and reload.
556
+ ```
557
+
558
+ Example with full allowlists:
559
+
560
+ ```ts
561
+ // vite.config.ts
562
+ import { defineConfig } from "vite";
563
+ import { elur } from "@elurjs/vite-plugin-elur";
564
+ import { elurIonic } from "@elurjs/ionic/vite-plugin";
565
+
566
+ export default defineConfig({
567
+ plugins: [
568
+ elur(),
569
+ elurIonic({
570
+ allowTags: [
571
+ "ion-app", "ion-header", "ion-toolbar", "ion-title", "ion-content",
572
+ "ion-buttons", "ion-button", "ion-back-button",
573
+ "ion-tab-bar", "ion-tab-button",
574
+ "ion-list", "ion-item", "ion-label",
575
+ "ion-card", "ion-card-content",
576
+ "ion-input", "ion-toggle", "ion-select", "ion-select-option",
577
+ "ion-icon", "ion-chip", "ion-badge",
578
+ // Overlays (programmatic)
579
+ "ion-toast", "ion-alert", "ion-loading",
580
+ "ion-action-sheet", "ion-popover", "ion-modal",
581
+ ],
582
+ allowIcons: [
583
+ "home", "search", "person", "settings",
584
+ "arrow-back", "arrow-forward",
585
+ "share-outline", "link-outline",
586
+ // ... all icons used in your templates
587
+ ],
588
+ }),
589
+ ],
590
+ });
591
+ ```
592
+
593
+ ## API reference
594
+
595
+ ### Core
596
+
597
+ | Export | Description |
598
+ |---|---|
599
+ | `IonRouterOutlet` | Router outlet with cache policies, guards, tabs |
600
+ | `IonPage` | Base class for pages with lifecycle hooks |
601
+ | `IonBackButton(defaultHref?)` | Back button component |
602
+ | `createBottomTabBar(tabs, opts?)` | Bottom tab bar |
603
+ | `initializeElurIonic()` | Initialize Ionic Core (incremental) |
604
+ | `registerIonicComponents(...definers)` | Register specific components |
605
+ | `registerIonicons(icons)` | Register specific icons |
606
+ | `setupElurIonic(opts?)` | 1.x compatibility facade |
607
+ | `createPageState(pageId, signals, opts?)` | Page-state persistence |
608
+ | `clearAllPageState(backend?, ns?)` | Clear all persisted state |
609
+ | `NavigationManager` | Single navigation authority (hooks, tabs, invalidation) |
610
+ | `StackManager` | Per-tab navigation stack management |
611
+
612
+ ### Overlays
613
+
614
+ | Export | Description |
615
+ |---|---|
616
+ | `createToast()` / `createAlert()` / `createLoading()` | Reactive overlay controllers |
617
+ | `createActionSheet()` / `createPopover()` / `createModal()` | Reactive overlay controllers |
618
+ | `createPicker()` | Column-based picker (lazy-registers `ion-picker-legacy`) |
619
+ | `showToast(opts)` | One-shot toast |
620
+ | `withLoading(opts, task)` | Loading + async task + auto-dismiss |
621
+ | `confirm(opts)` | Promise-based confirm dialog |
622
+
623
+ ### Capacitor (`@elurjs/ionic/capacitor`)
624
+
625
+ | Export | Description |
626
+ |---|---|
627
+ | `createCapacitorApp(opts)` | Bootstrap helper (status bar, splash, back button) |
628
+ | `StatusBar` / `SplashScreen` / `Keyboard` | Plugin wrappers (no-op on web) |
629
+ | `Haptics` / `App` | Plugin wrappers (no-op on web) |
630
+ | `isNative()` / `isWeb()` | Platform detection |
631
+
632
+ ### Vite plugin (`@elurjs/ionic/vite-plugin`)
633
+
634
+ | Export | Description |
635
+ |---|---|
636
+ | `elurIonic(opts?)` | Vite plugin for auto-registration |
637
+ | `generateRegistrationModule(tags, icons, opts)` | Code generator (for testing) |
638
+
639
+ ## Comparison
640
+
641
+ | Feature | `@ionic/angular` | `@ionic/react` | `@elurjs/ionic` |
642
+ |---|---|---|---|
643
+ | Virtual DOM | Angular | React | **None** |
644
+ | Bundle size overhead | Angular runtime | React runtime | **Zero** |
645
+ | Tree-shakeable components | No | No | **Yes** |
646
+ | Auto-registration plugin | No | No | **Yes** (Vite) |
647
+ | Cache policies (LRU/TTL) | No | No | **Yes** |
648
+ | Page-state persistence | Manual | Manual | **Built-in** |
649
+ | Capacitor integration | External | External | **Optional subpath** |
650
+ | Reactive overlays | Manual | Manual | **`create*` pattern** |
651
+
652
+ ## Testing
653
+
654
+ All tests run against real `@ionic/core` (no mocks).
655
+
656
+ | Suite | Tests | What it covers |
657
+ |---|---|---|
658
+ | Unit (Vitest) | 235 | Cache policies, navigation, overlays, page-state, Capacitor, Vite plugin, bundles |
659
+ | E2E application | 19 | Navigation, lifecycle, overlays (toast/modal/alert/loading/action-sheet/picker), back button |
660
+ | E2E contract | 24 | Custom elements, `commit()`, lifecycle events, overlay present/dismiss, properties, form events, network isolation |
661
+ | E2E accessibility/leaks | 13 | ARIA roles, shadow DOM, focus management, repeated navigation, overlay disposal, listener cleanup |
662
+
663
+ **Total: 291 tests, all passing.**
664
+
665
+ ### Bundle validation
666
+
667
+ ```bash
668
+ npm run measure-bundles
669
+ ```
670
+
671
+ Validates tree-shaking with 4 fixtures:
672
+
673
+ | Fixture | Gzip | Purpose |
674
+ |---|---|---|
675
+ | minimal (1 component) | 0.82 KB | Only `ion-button` — no other component code |
676
+ | partial (layout + buttons) | 1.05 KB | Two bundles — no forms/lists/overlays |
677
+ | full (all + overlays + nav) | 7.26 KB | Worst-case bundle |
678
+ | capacitor-only | 0.59 KB | Zero `@capacitor/*` in web bundle |
679
+
680
+ Minimal = 11.3% of full bundle (gzip) — tree-shaking works.
681
+
682
+ ## Limitations
683
+
684
+ ### iOS swipe-back gesture
685
+
686
+ iOS swipe-back (interactive pop gesture) is **not supported**. The integration
687
+ does not assign `swipeHandler` on `ion-router-outlet`. Native swipe-back requires
688
+ a WebKit/mobile test that reproduces both a completed swipe and a cancelled
689
+ swipe with correct lifecycle rollback — this has not been demonstrated.
690
+
691
+ Use `ion-back-button` or programmatic `router.back()` for back navigation.
692
+
693
+ ## License
694
+
695
+ MIT