microui-wc 0.1.0

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 (609) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +33 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
  4. package/.github/workflows/ci.yml +42 -0
  5. package/.github/workflows/deploy-pages.yml +112 -0
  6. package/AGENTS.md +2366 -0
  7. package/CHANGELOG.md +47 -0
  8. package/CODE_OF_CONDUCT.md +59 -0
  9. package/CONTRIBUTING.md +156 -0
  10. package/LICENSE +190 -0
  11. package/README.md +254 -0
  12. package/SECURITY.md +58 -0
  13. package/app/.generated/routes/alerts.js +8 -0
  14. package/app/.generated/routes/avatars.js +8 -0
  15. package/app/.generated/routes/badges.js +8 -0
  16. package/app/.generated/routes/buttons.js +10 -0
  17. package/app/.generated/routes/cards.js +10 -0
  18. package/app/.generated/routes/checkboxes.js +9 -0
  19. package/app/.generated/routes/chips.js +8 -0
  20. package/app/.generated/routes/dropdowns.js +9 -0
  21. package/app/.generated/routes/home.js +7 -0
  22. package/app/.generated/routes/icons.js +9 -0
  23. package/app/.generated/routes/inputs.js +10 -0
  24. package/app/.generated/routes/installation.js +7 -0
  25. package/app/.generated/routes/layout.js +9 -0
  26. package/app/.generated/routes/modals.js +9 -0
  27. package/app/.generated/routes/navbar.js +7 -0
  28. package/app/.generated/routes/progress.js +9 -0
  29. package/app/.generated/routes/radios.js +9 -0
  30. package/app/.generated/routes/switches.js +9 -0
  31. package/app/.generated/routes/tabs.js +8 -0
  32. package/app/.generated/routes/toasts.js +9 -0
  33. package/app/index.html +67 -0
  34. package/app/pages/alerts.html +23 -0
  35. package/app/pages/avatars.html +22 -0
  36. package/app/pages/badges.html +22 -0
  37. package/app/pages/buttons.html +71 -0
  38. package/app/pages/cards.html +54 -0
  39. package/app/pages/checkboxes.html +39 -0
  40. package/app/pages/chips.html +23 -0
  41. package/app/pages/dropdowns.html +41 -0
  42. package/app/pages/home.html +59 -0
  43. package/app/pages/icons.html +29 -0
  44. package/app/pages/inputs.html +66 -0
  45. package/app/pages/installation.html +34 -0
  46. package/app/pages/layout.html +30 -0
  47. package/app/pages/modals.html +21 -0
  48. package/app/pages/navbar.html +22 -0
  49. package/app/pages/progress.html +35 -0
  50. package/app/pages/radios.html +40 -0
  51. package/app/pages/switches.html +39 -0
  52. package/app/pages/tabs.html +30 -0
  53. package/app/pages/toasts.html +22 -0
  54. package/app-dist/index.html +67 -0
  55. package/app-dist/pages/alerts.html +23 -0
  56. package/app-dist/pages/avatars.html +22 -0
  57. package/app-dist/pages/badges.html +22 -0
  58. package/app-dist/pages/buttons.html +71 -0
  59. package/app-dist/pages/cards.html +54 -0
  60. package/app-dist/pages/checkboxes.html +39 -0
  61. package/app-dist/pages/chips.html +23 -0
  62. package/app-dist/pages/dropdowns.html +41 -0
  63. package/app-dist/pages/home.html +59 -0
  64. package/app-dist/pages/icons.html +29 -0
  65. package/app-dist/pages/inputs.html +66 -0
  66. package/app-dist/pages/installation.html +34 -0
  67. package/app-dist/pages/layout.html +30 -0
  68. package/app-dist/pages/modals.html +21 -0
  69. package/app-dist/pages/navbar.html +22 -0
  70. package/app-dist/pages/progress.html +35 -0
  71. package/app-dist/pages/radios.html +40 -0
  72. package/app-dist/pages/switches.html +39 -0
  73. package/app-dist/pages/tabs.html +30 -0
  74. package/app-dist/pages/toasts.html +22 -0
  75. package/app-dist/pages.json +217 -0
  76. package/app-dist/routes/alerts.js +5 -0
  77. package/app-dist/routes/avatars.js +1 -0
  78. package/app-dist/routes/badges.js +1 -0
  79. package/app-dist/routes/buttons.js +1 -0
  80. package/app-dist/routes/cards.js +1 -0
  81. package/app-dist/routes/checkboxes.js +9 -0
  82. package/app-dist/routes/chips.js +4 -0
  83. package/app-dist/routes/chunk-019e5e2f.js +5 -0
  84. package/app-dist/routes/chunk-0m4j19yd.js +2 -0
  85. package/app-dist/routes/chunk-0tmmp5q0.js +1 -0
  86. package/app-dist/routes/chunk-10xn709r.js +1 -0
  87. package/app-dist/routes/chunk-15m2qcda.js +2 -0
  88. package/app-dist/routes/chunk-1bh8g23n.js +1 -0
  89. package/app-dist/routes/chunk-1vg0v937.js +1 -0
  90. package/app-dist/routes/chunk-1zvcgy3j.js +1 -0
  91. package/app-dist/routes/chunk-2afb0861.js +1 -0
  92. package/app-dist/routes/chunk-2c6ttpzt.js +5 -0
  93. package/app-dist/routes/chunk-3dy30fhs.js +1 -0
  94. package/app-dist/routes/chunk-426dnces.js +13 -0
  95. package/app-dist/routes/chunk-44kgxery.js +1 -0
  96. package/app-dist/routes/chunk-47fdnejd.js +33 -0
  97. package/app-dist/routes/chunk-49a6t2vq.js +1 -0
  98. package/app-dist/routes/chunk-4fe1rm5b.js +1 -0
  99. package/app-dist/routes/chunk-4ggmvkta.js +33 -0
  100. package/app-dist/routes/chunk-4vkz81q7.js +33 -0
  101. package/app-dist/routes/chunk-4w4tmj8f.js +31 -0
  102. package/app-dist/routes/chunk-532s62kr.js +31 -0
  103. package/app-dist/routes/chunk-5hm3bssy.js +33 -0
  104. package/app-dist/routes/chunk-5vrh24hc.js +1 -0
  105. package/app-dist/routes/chunk-61pcg25a.js +1 -0
  106. package/app-dist/routes/chunk-6nfhygvf.js +1 -0
  107. package/app-dist/routes/chunk-700e7je6.js +33 -0
  108. package/app-dist/routes/chunk-7fsn17kg.js +1 -0
  109. package/app-dist/routes/chunk-7k789b32.js +1 -0
  110. package/app-dist/routes/chunk-7r46q0ys.js +36 -0
  111. package/app-dist/routes/chunk-86fmc1fr.js +5 -0
  112. package/app-dist/routes/chunk-8qth37vw.js +1 -0
  113. package/app-dist/routes/chunk-924wv8n0.js +1 -0
  114. package/app-dist/routes/chunk-9mbhgxk9.js +1 -0
  115. package/app-dist/routes/chunk-a216hyd9.js +1 -0
  116. package/app-dist/routes/chunk-akzxykh9.js +33 -0
  117. package/app-dist/routes/chunk-b3dcvy8c.js +1 -0
  118. package/app-dist/routes/chunk-b74zahz5.js +31 -0
  119. package/app-dist/routes/chunk-bftj53p2.js +5 -0
  120. package/app-dist/routes/chunk-c01hnz3e.js +1 -0
  121. package/app-dist/routes/chunk-d8pvv5km.js +1 -0
  122. package/app-dist/routes/chunk-dev0aezr.js +2 -0
  123. package/app-dist/routes/chunk-dh6vnv0e.js +1 -0
  124. package/app-dist/routes/chunk-dn2cbpva.js +36 -0
  125. package/app-dist/routes/chunk-dvn0my90.js +1 -0
  126. package/app-dist/routes/chunk-dvq8mnve.js +36 -0
  127. package/app-dist/routes/chunk-e8c2gc4d.js +5 -0
  128. package/app-dist/routes/chunk-ejf9ak2x.js +1 -0
  129. package/app-dist/routes/chunk-f083m55s.js +1 -0
  130. package/app-dist/routes/chunk-fnrj28s1.js +31 -0
  131. package/app-dist/routes/chunk-fvg3yjdp.js +31 -0
  132. package/app-dist/routes/chunk-g7k381n1.js +1 -0
  133. package/app-dist/routes/chunk-h01kq2ae.js +13 -0
  134. package/app-dist/routes/chunk-h4dk761v.js +5 -0
  135. package/app-dist/routes/chunk-hmx91z2x.js +5 -0
  136. package/app-dist/routes/chunk-hxbg4m42.js +36 -0
  137. package/app-dist/routes/chunk-jbjnfp2b.js +2 -0
  138. package/app-dist/routes/chunk-jxtz5vv6.js +36 -0
  139. package/app-dist/routes/chunk-jxzcs0ey.js +36 -0
  140. package/app-dist/routes/chunk-kt7wwhcx.js +1 -0
  141. package/app-dist/routes/chunk-kzptszyc.js +33 -0
  142. package/app-dist/routes/chunk-mhgca4w4.js +2 -0
  143. package/app-dist/routes/chunk-mhswxa20.js +1 -0
  144. package/app-dist/routes/chunk-n8zfeex6.js +1 -0
  145. package/app-dist/routes/chunk-pee47b2r.js +1 -0
  146. package/app-dist/routes/chunk-pesmw829.js +1 -0
  147. package/app-dist/routes/chunk-pgc4c6f3.js +36 -0
  148. package/app-dist/routes/chunk-q8egegm1.js +1 -0
  149. package/app-dist/routes/chunk-q9mn2qyq.js +36 -0
  150. package/app-dist/routes/chunk-qh0rtaf3.js +5 -0
  151. package/app-dist/routes/chunk-qqhmk6ye.js +2 -0
  152. package/app-dist/routes/chunk-qrxygmf7.js +33 -0
  153. package/app-dist/routes/chunk-r46yzksx.js +36 -0
  154. package/app-dist/routes/chunk-rgpbw2w0.js +5 -0
  155. package/app-dist/routes/chunk-rnpzv3d8.js +2 -0
  156. package/app-dist/routes/chunk-s5v8cv05.js +2 -0
  157. package/app-dist/routes/chunk-sbwn5bpc.js +1 -0
  158. package/app-dist/routes/chunk-sqbg8jbt.js +33 -0
  159. package/app-dist/routes/chunk-sv8dqnf7.js +1 -0
  160. package/app-dist/routes/chunk-t67sw3za.js +1 -0
  161. package/app-dist/routes/chunk-tjdpqwdf.js +31 -0
  162. package/app-dist/routes/chunk-tq2mfghg.js +1 -0
  163. package/app-dist/routes/chunk-ttn10vt6.js +1 -0
  164. package/app-dist/routes/chunk-v2hzpjxr.js +1 -0
  165. package/app-dist/routes/chunk-wfjjkw9y.js +1 -0
  166. package/app-dist/routes/chunk-wt8cxzmf.js +31 -0
  167. package/app-dist/routes/chunk-x45d372k.js +5 -0
  168. package/app-dist/routes/chunk-y3wsazkt.js +1 -0
  169. package/app-dist/routes/chunk-y7pmgc7t.js +33 -0
  170. package/app-dist/routes/chunk-zefdt2q3.js +31 -0
  171. package/app-dist/routes/dropdowns.js +6 -0
  172. package/app-dist/routes/home.js +1 -0
  173. package/app-dist/routes/icons.js +1 -0
  174. package/app-dist/routes/inputs.js +12 -0
  175. package/app-dist/routes/installation.js +1 -0
  176. package/app-dist/routes/layout.js +1 -0
  177. package/app-dist/routes/modals.js +7 -0
  178. package/app-dist/routes/navbar.js +1 -0
  179. package/app-dist/routes/progress.js +1 -0
  180. package/app-dist/routes/radios.js +6 -0
  181. package/app-dist/routes/switches.js +6 -0
  182. package/app-dist/routes/tabs.js +1 -0
  183. package/app-dist/routes/toasts.js +16 -0
  184. package/assets/fonts/material-symbols-mini.woff2 +0 -0
  185. package/assets/fonts/material-symbols.woff2 +0 -0
  186. package/assets/fonts/roboto-400.woff2 +0 -0
  187. package/assets/fonts/roboto-500.woff2 +0 -0
  188. package/assets/fonts/roboto-700.woff2 +0 -0
  189. package/assets/logo-banner-400.jpg +0 -0
  190. package/assets/logo-banner-400.webp +0 -0
  191. package/assets/logo-banner-800.webp +0 -0
  192. package/assets/logo-banner.jpg +0 -0
  193. package/assets/logo-icon-64.jpg +0 -0
  194. package/assets/logo-icon-64.webp +0 -0
  195. package/assets/logo-icon.jpg +0 -0
  196. package/assets/logo-square.jpg +0 -0
  197. package/bun.lock +312 -0
  198. package/bunfig.toml +4 -0
  199. package/custom-elements.json +1916 -0
  200. package/demo/api/sample-data.json +38 -0
  201. package/demo/content/alerts.html +115 -0
  202. package/demo/content/avatars.html +70 -0
  203. package/demo/content/badges.html +65 -0
  204. package/demo/content/buttons.html +188 -0
  205. package/demo/content/callouts.html +91 -0
  206. package/demo/content/cards.html +121 -0
  207. package/demo/content/checkboxes.html +178 -0
  208. package/demo/content/chips.html +67 -0
  209. package/demo/content/codeblocks.html +101 -0
  210. package/demo/content/confirms.html +115 -0
  211. package/demo/content/datatables.html +149 -0
  212. package/demo/content/dividers.html +119 -0
  213. package/demo/content/dropdowns.html +89 -0
  214. package/demo/content/enterprise.html +252 -0
  215. package/demo/content/home.html +149 -0
  216. package/demo/content/icons.html +89 -0
  217. package/demo/content/inputs.html +135 -0
  218. package/demo/content/installation.html +16 -0
  219. package/demo/content/layout.html +136 -0
  220. package/demo/content/modals.html +141 -0
  221. package/demo/content/navbar.html +70 -0
  222. package/demo/content/progress.html +119 -0
  223. package/demo/content/radios.html +88 -0
  224. package/demo/content/skeletons.html +109 -0
  225. package/demo/content/spinners.html +96 -0
  226. package/demo/content/switches.html +84 -0
  227. package/demo/content/tables.html +124 -0
  228. package/demo/content/tabs.html +85 -0
  229. package/demo/content/toasts.html +116 -0
  230. package/demo/content/tooltips.html +107 -0
  231. package/demo/content/virtual-lists.html +233 -0
  232. package/demo/favicon.ico +0 -0
  233. package/demo/favicon.png +0 -0
  234. package/demo/full.html +52 -0
  235. package/demo/iife.html +46 -0
  236. package/demo/manifest.json +34 -0
  237. package/demo/pages/datatable-demo.html +237 -0
  238. package/demo/pages/prompt-ui-demo.html +218 -0
  239. package/demo/pages/responsive-demo.html +122 -0
  240. package/demo/pages/schema-form-demo.html +270 -0
  241. package/demo/robots.txt +6 -0
  242. package/demo/shell.html +712 -0
  243. package/demo/sw.js +387 -0
  244. package/dist/AGENTS.md +2366 -0
  245. package/dist/README.md +254 -0
  246. package/dist/chunks/advanced.js +174 -0
  247. package/dist/chunks/chunk-1nhr1wrq.js +14 -0
  248. package/dist/chunks/chunk-hssyjbr0.js +2 -0
  249. package/dist/chunks/chunk-k8etzx0z.js +2 -0
  250. package/dist/chunks/chunk-rr1et8fg.js +2 -0
  251. package/dist/chunks/chunk-sjcx4fd5.js +6 -0
  252. package/dist/chunks/chunk-v1c777xh.js +5 -0
  253. package/dist/chunks/chunk-w5k5vwjd.js +13 -0
  254. package/dist/chunks/core.js +10 -0
  255. package/dist/chunks/display.js +17 -0
  256. package/dist/chunks/feedback.js +15 -0
  257. package/dist/chunks/forms.js +48 -0
  258. package/dist/chunks/layout.js +9 -0
  259. package/dist/components/chunk-4tezav8r.js +2 -0
  260. package/dist/components/chunk-fqyb2pms.js +2 -0
  261. package/dist/components/chunk-h7cdbhxw.js +13 -0
  262. package/dist/components/chunk-mzd8jwrs.js +2 -0
  263. package/dist/components/chunk-qwmxyn8e.js +2 -0
  264. package/dist/components/chunk-redtk47a.js +14 -0
  265. package/dist/components/mu-alert.js +5 -0
  266. package/dist/components/mu-api-table.js +33 -0
  267. package/dist/components/mu-avatar.js +1 -0
  268. package/dist/components/mu-badge.js +1 -0
  269. package/dist/components/mu-bottom-nav.js +1 -0
  270. package/dist/components/mu-button.js +1 -0
  271. package/dist/components/mu-callout.js +1 -0
  272. package/dist/components/mu-card.js +1 -0
  273. package/dist/components/mu-checkbox.js +9 -0
  274. package/dist/components/mu-chip.js +4 -0
  275. package/dist/components/mu-code.js +48 -0
  276. package/dist/components/mu-confirm.js +10 -0
  277. package/dist/components/mu-container.js +1 -0
  278. package/dist/components/mu-datatable.js +96 -0
  279. package/dist/components/mu-divider.js +1 -0
  280. package/dist/components/mu-doc-page.js +26 -0
  281. package/dist/components/mu-drawer-item.js +9 -0
  282. package/dist/components/mu-drawer.js +1 -0
  283. package/dist/components/mu-dropdown.js +6 -0
  284. package/dist/components/mu-error-boundary.js +10 -0
  285. package/dist/components/mu-example.js +38 -0
  286. package/dist/components/mu-fetch.js +1 -0
  287. package/dist/components/mu-form.js +1 -0
  288. package/dist/components/mu-grid.js +1 -0
  289. package/dist/components/mu-icon.js +5 -0
  290. package/dist/components/mu-input.js +12 -0
  291. package/dist/components/mu-layout.js +1 -0
  292. package/dist/components/mu-lazy.js +1 -0
  293. package/dist/components/mu-modal.js +7 -0
  294. package/dist/components/mu-navbar.js +1 -0
  295. package/dist/components/mu-page.js +1 -0
  296. package/dist/components/mu-progress.js +1 -0
  297. package/dist/components/mu-prompt-ui.js +20 -0
  298. package/dist/components/mu-radio.js +6 -0
  299. package/dist/components/mu-repeat.js +1 -0
  300. package/dist/components/mu-router.js +6 -0
  301. package/dist/components/mu-schema-form.js +76 -0
  302. package/dist/components/mu-sidebar.js +1 -0
  303. package/dist/components/mu-skeleton.js +13 -0
  304. package/dist/components/mu-spinner.js +1 -0
  305. package/dist/components/mu-stack.js +1 -0
  306. package/dist/components/mu-switch.js +6 -0
  307. package/dist/components/mu-table.js +1 -0
  308. package/dist/components/mu-tabs.js +1 -0
  309. package/dist/components/mu-textarea.js +11 -0
  310. package/dist/components/mu-theme-toggle.js +5 -0
  311. package/dist/components/mu-toast.js +4 -0
  312. package/dist/components/mu-tooltip.js +10 -0
  313. package/dist/components/mu-virtual-list.js +33 -0
  314. package/dist/components.css +1 -0
  315. package/dist/microui.css +1 -0
  316. package/dist/microui.d.ts +234 -0
  317. package/dist/microui.esm.js +549 -0
  318. package/dist/microui.esm.js.map +79 -0
  319. package/dist/microui.min.js +549 -0
  320. package/dist/microui.min.js.map +79 -0
  321. package/dist/routes/alerts.js +1 -0
  322. package/dist/routes/avatars.js +1 -0
  323. package/dist/routes/badges.js +1 -0
  324. package/dist/routes/buttons.js +1 -0
  325. package/dist/routes/callouts.js +1 -0
  326. package/dist/routes/cards.js +1 -0
  327. package/dist/routes/checkboxes.js +9 -0
  328. package/dist/routes/chips.js +4 -0
  329. package/dist/routes/chunk-19wgcncm.js +2 -0
  330. package/dist/routes/chunk-1khyr3v1.js +33 -0
  331. package/dist/routes/chunk-4rhxe97g.js +1 -0
  332. package/dist/routes/chunk-5qah04bh.js +2 -0
  333. package/dist/routes/chunk-7gfxy70n.js +5 -0
  334. package/dist/routes/chunk-e86zbeta.js +1 -0
  335. package/dist/routes/chunk-fagt36h6.js +2 -0
  336. package/dist/routes/chunk-fed7zr7m.js +1 -0
  337. package/dist/routes/chunk-hwj7pfwp.js +1 -0
  338. package/dist/routes/chunk-mhvcs2f8.js +5 -0
  339. package/dist/routes/chunk-nv3bddmj.js +13 -0
  340. package/dist/routes/chunk-q3f2aeqe.js +7 -0
  341. package/dist/routes/chunk-qxxa8trk.js +1 -0
  342. package/dist/routes/chunk-rw15y9zh.js +1 -0
  343. package/dist/routes/chunk-sfb7x11v.js +5 -0
  344. package/dist/routes/chunk-swyhghrm.js +48 -0
  345. package/dist/routes/chunk-sxddjs2d.js +2 -0
  346. package/dist/routes/chunk-vby0zg5w.js +17 -0
  347. package/dist/routes/chunk-w6zqjqqs.js +9 -0
  348. package/dist/routes/chunk-z960rexd.js +38 -0
  349. package/dist/routes/codeblocks.js +1 -0
  350. package/dist/routes/confirms.js +10 -0
  351. package/dist/routes/datatables.js +96 -0
  352. package/dist/routes/dividers.js +1 -0
  353. package/dist/routes/dropdowns.js +6 -0
  354. package/dist/routes/enterprise.js +15 -0
  355. package/dist/routes/home.js +1 -0
  356. package/dist/routes/icons.js +1 -0
  357. package/dist/routes/inputs.js +22 -0
  358. package/dist/routes/installation.js +1 -0
  359. package/dist/routes/layout.js +1 -0
  360. package/dist/routes/modals.js +1 -0
  361. package/dist/routes/navbar.js +1 -0
  362. package/dist/routes/page-components.json +316 -0
  363. package/dist/routes/progress.js +1 -0
  364. package/dist/routes/radios.js +6 -0
  365. package/dist/routes/route-deps.json +156 -0
  366. package/dist/routes/shell-critical.js +1 -0
  367. package/dist/routes/shell-deferred.js +1 -0
  368. package/dist/routes/shell.js +20 -0
  369. package/dist/routes/skeletons.js +13 -0
  370. package/dist/routes/spinners.js +1 -0
  371. package/dist/routes/src/chunks/core.js +36 -0
  372. package/dist/routes/switches.js +6 -0
  373. package/dist/routes/tables.js +1 -0
  374. package/dist/routes/tabs.js +1 -0
  375. package/dist/routes/toasts.js +1 -0
  376. package/dist/routes/tooltips.js +10 -0
  377. package/dist/routes/virtual-lists.js +33 -0
  378. package/dist/styles/common.css +1 -0
  379. package/dist/styles/components/animations.css +1 -0
  380. package/dist/styles/components/avatar.css +1 -0
  381. package/dist/styles/components/badge.css +1 -0
  382. package/dist/styles/components/bottom-nav.css +1 -0
  383. package/dist/styles/components/button.css +1 -0
  384. package/dist/styles/components/card.css +1 -0
  385. package/dist/styles/components/checkbox.css +1 -0
  386. package/dist/styles/components/chip.css +1 -0
  387. package/dist/styles/components/datatable.css +1 -0
  388. package/dist/styles/components/divider.css +1 -0
  389. package/dist/styles/components/drawer-item.css +1 -0
  390. package/dist/styles/components/drawer.css +1 -0
  391. package/dist/styles/components/grid.css +1 -0
  392. package/dist/styles/components/icon.css +1 -0
  393. package/dist/styles/components/input.css +1 -0
  394. package/dist/styles/components/layout.css +1 -0
  395. package/dist/styles/components/navbar.css +1 -0
  396. package/dist/styles/components/overlays.css +1 -0
  397. package/dist/styles/components/progress.css +1 -0
  398. package/dist/styles/components/prompt-ui.css +1 -0
  399. package/dist/styles/components/radio.css +1 -0
  400. package/dist/styles/components/schema-form.css +1 -0
  401. package/dist/styles/components/switch.css +1 -0
  402. package/dist/styles/components/tabs.css +1 -0
  403. package/dist/styles/components/tooltip.css +1 -0
  404. package/dist/styles/components/virtual-list.css +1 -0
  405. package/dist/tokens.css +1 -0
  406. package/docs/api-reference.md +175 -0
  407. package/docs/component-schema.md +231 -0
  408. package/docs/components.md +269 -0
  409. package/docs/design-system.md +183 -0
  410. package/docs/getting-started.md +198 -0
  411. package/docs/message-protocol.md +262 -0
  412. package/docs/utility-classes.md +205 -0
  413. package/lighthouse-audit.mjs +113 -0
  414. package/package.json +45 -0
  415. package/scripts/analyze-components.js +105 -0
  416. package/scripts/build-app.js +193 -0
  417. package/scripts/build-framework.js +444 -0
  418. package/scripts/build-utils.js +101 -0
  419. package/scripts/test-isolated.js +151 -0
  420. package/server.js +256 -0
  421. package/src/chunks/advanced.js +27 -0
  422. package/src/chunks/core.js +61 -0
  423. package/src/chunks/display.js +25 -0
  424. package/src/chunks/feedback.js +15 -0
  425. package/src/chunks/forms.js +25 -0
  426. package/src/chunks/layout.js +27 -0
  427. package/src/components/mu-alert.js +96 -0
  428. package/src/components/mu-api-table.js +167 -0
  429. package/src/components/mu-avatar.js +94 -0
  430. package/src/components/mu-badge.js +32 -0
  431. package/src/components/mu-bottom-nav.js +115 -0
  432. package/src/components/mu-button.js +61 -0
  433. package/src/components/mu-callout.js +71 -0
  434. package/src/components/mu-card.js +36 -0
  435. package/src/components/mu-checkbox.js +186 -0
  436. package/src/components/mu-chip.js +125 -0
  437. package/src/components/mu-code.js +534 -0
  438. package/src/components/mu-confirm.js +268 -0
  439. package/src/components/mu-container.js +53 -0
  440. package/src/components/mu-datatable.js +517 -0
  441. package/src/components/mu-divider.js +40 -0
  442. package/src/components/mu-doc-page.js +100 -0
  443. package/src/components/mu-drawer-item.js +158 -0
  444. package/src/components/mu-drawer.js +305 -0
  445. package/src/components/mu-dropdown.js +239 -0
  446. package/src/components/mu-error-boundary.js +191 -0
  447. package/src/components/mu-example.js +335 -0
  448. package/src/components/mu-fetch.js +256 -0
  449. package/src/components/mu-form.js +133 -0
  450. package/src/components/mu-grid.js +63 -0
  451. package/src/components/mu-icon.js +211 -0
  452. package/src/components/mu-input.js +142 -0
  453. package/src/components/mu-layout.js +129 -0
  454. package/src/components/mu-lazy.js +94 -0
  455. package/src/components/mu-modal.js +160 -0
  456. package/src/components/mu-navbar.js +71 -0
  457. package/src/components/mu-page.js +77 -0
  458. package/src/components/mu-progress.js +54 -0
  459. package/src/components/mu-prompt-ui.js +382 -0
  460. package/src/components/mu-radio.js +200 -0
  461. package/src/components/mu-repeat.js +135 -0
  462. package/src/components/mu-router.js +169 -0
  463. package/src/components/mu-schema-form.js +441 -0
  464. package/src/components/mu-sidebar.js +81 -0
  465. package/src/components/mu-skeleton.js +69 -0
  466. package/src/components/mu-spinner.js +30 -0
  467. package/src/components/mu-stack.js +59 -0
  468. package/src/components/mu-switch.js +150 -0
  469. package/src/components/mu-table.js +80 -0
  470. package/src/components/mu-tabs.js +112 -0
  471. package/src/components/mu-textarea.js +96 -0
  472. package/src/components/mu-theme-toggle.js +52 -0
  473. package/src/components/mu-toast.js +151 -0
  474. package/src/components/mu-tooltip.js +182 -0
  475. package/src/components/mu-virtual-list.js +184 -0
  476. package/src/core/MuElement.js +562 -0
  477. package/src/core/agent-api.js +771 -0
  478. package/src/core/breakpoints.js +195 -0
  479. package/src/core/bus.js +378 -0
  480. package/src/core/component-schema.js +287 -0
  481. package/src/core/feature-registry.js +241 -0
  482. package/src/core/form-state.js +252 -0
  483. package/src/core/http.js +104 -0
  484. package/src/core/keyboard.js +105 -0
  485. package/src/core/layers.js +71 -0
  486. package/src/core/render.js +201 -0
  487. package/src/core/ripple.js +158 -0
  488. package/src/core/router.js +100 -0
  489. package/src/core/scheduler.js +109 -0
  490. package/src/core/signals.js +164 -0
  491. package/src/core/store.js +268 -0
  492. package/src/core/theme.js +68 -0
  493. package/src/core/transitions.js +72 -0
  494. package/src/core/utils.js +30 -0
  495. package/src/index.d.ts +234 -0
  496. package/src/index.js +308 -0
  497. package/src/styles/animations.css +252 -0
  498. package/src/styles/common.css +82 -0
  499. package/src/styles/components/animations.css +129 -0
  500. package/src/styles/components/avatar.css +83 -0
  501. package/src/styles/components/badge.css +80 -0
  502. package/src/styles/components/bottom-nav.css +37 -0
  503. package/src/styles/components/button.css +348 -0
  504. package/src/styles/components/card.css +138 -0
  505. package/src/styles/components/checkbox.css +201 -0
  506. package/src/styles/components/chip.css +93 -0
  507. package/src/styles/components/datatable.css +180 -0
  508. package/src/styles/components/divider.css +49 -0
  509. package/src/styles/components/drawer-item.css +123 -0
  510. package/src/styles/components/drawer.css +273 -0
  511. package/src/styles/components/grid.css +189 -0
  512. package/src/styles/components/icon.css +40 -0
  513. package/src/styles/components/input.css +203 -0
  514. package/src/styles/components/layout.css +121 -0
  515. package/src/styles/components/navbar.css +91 -0
  516. package/src/styles/components/overlays.css +329 -0
  517. package/src/styles/components/progress.css +79 -0
  518. package/src/styles/components/prompt-ui.css +286 -0
  519. package/src/styles/components/radio.css +17 -0
  520. package/src/styles/components/schema-form.css +85 -0
  521. package/src/styles/components/switch.css +69 -0
  522. package/src/styles/components/tabs.css +145 -0
  523. package/src/styles/components/tooltip.css +93 -0
  524. package/src/styles/components/virtual-list.css +36 -0
  525. package/src/styles/components.css +3677 -0
  526. package/src/styles/routes/home.css +97 -0
  527. package/src/styles/tokens.css +675 -0
  528. package/tests/agents/agent-integration.test.js +76 -0
  529. package/tests/benchmark.html +296 -0
  530. package/tests/build/scan-components.test.js +173 -0
  531. package/tests/components/all-components.test.js +245 -0
  532. package/tests/components/all-missing-components.test.js +574 -0
  533. package/tests/components/mu-alert.test.js +113 -0
  534. package/tests/components/mu-avatar.test.js +148 -0
  535. package/tests/components/mu-badge.test.js +92 -0
  536. package/tests/components/mu-button.test.js +112 -0
  537. package/tests/components/mu-card.test.js +89 -0
  538. package/tests/components/mu-checkbox.test.js +158 -0
  539. package/tests/components/mu-chip.test.js +118 -0
  540. package/tests/components/mu-container.test.js +120 -0
  541. package/tests/components/mu-divider.test.js +98 -0
  542. package/tests/components/mu-drawer-item.test.js +199 -0
  543. package/tests/components/mu-drawer.test.js +96 -0
  544. package/tests/components/mu-dropdown.test.js +125 -0
  545. package/tests/components/mu-form.test.js +138 -0
  546. package/tests/components/mu-grid.test.js +135 -0
  547. package/tests/components/mu-icon.test.js +110 -0
  548. package/tests/components/mu-input.test.js +131 -0
  549. package/tests/components/mu-lazy.test.js +103 -0
  550. package/tests/components/mu-modal.test.js +275 -0
  551. package/tests/components/mu-navbar.test.js +101 -0
  552. package/tests/components/mu-progress.test.js +115 -0
  553. package/tests/components/mu-radio.test.js +114 -0
  554. package/tests/components/mu-repeat.test.js +106 -0
  555. package/tests/components/mu-sidebar.test.js +126 -0
  556. package/tests/components/mu-skeleton.test.js +162 -0
  557. package/tests/components/mu-stack.test.js +143 -0
  558. package/tests/components/mu-switch.test.js +292 -0
  559. package/tests/components/mu-table.test.js +124 -0
  560. package/tests/components/mu-tabs.test.js +104 -0
  561. package/tests/components/mu-textarea.test.js +115 -0
  562. package/tests/components/mu-toast.test.js +321 -0
  563. package/tests/components/mu-tooltip.test.js +133 -0
  564. package/tests/components/mu-virtual-list.test.js +109 -0
  565. package/tests/core/MuElement.test.js +120 -0
  566. package/tests/core/agent-api.test.js +125 -0
  567. package/tests/core/all-core-modules.test.js +442 -0
  568. package/tests/core/bus.test.js +364 -0
  569. package/tests/core/component-schema.test.js +160 -0
  570. package/tests/core/feature-registry.test.js +198 -0
  571. package/tests/core/form-state.test.js +167 -0
  572. package/tests/core/http.test.js +119 -0
  573. package/tests/core/keyboard.test.js +319 -0
  574. package/tests/core/layers.test.js +129 -0
  575. package/tests/core/namespaced-stores.test.js +114 -0
  576. package/tests/core/render.test.js +121 -0
  577. package/tests/core/ripple.test.js +131 -0
  578. package/tests/core/router.test.js +89 -0
  579. package/tests/core/scheduler.test.js +121 -0
  580. package/tests/core/signals.test.js +128 -0
  581. package/tests/core/store.test.js +171 -0
  582. package/tests/core/transitions.test.js +82 -0
  583. package/tests/e2e/accessibility-harness.html +58 -0
  584. package/tests/e2e/accessibility.test.js +401 -0
  585. package/tests/e2e/agent-features.test.js +372 -0
  586. package/tests/e2e/card-spacing.test.js +287 -0
  587. package/tests/e2e/components.test.js +439 -0
  588. package/tests/e2e/demo-routes.test.js +478 -0
  589. package/tests/e2e/layout-css-fallback.test.js +334 -0
  590. package/tests/e2e/mu-alert.e2e.test.js +111 -0
  591. package/tests/e2e/mu-checkbox.test.js +489 -0
  592. package/tests/e2e/mu-chip.test.js +347 -0
  593. package/tests/e2e/mu-form.test.js +499 -0
  594. package/tests/e2e/mu-icon.test.js +114 -0
  595. package/tests/e2e/mu-radio.test.js +113 -0
  596. package/tests/e2e/mu-skeleton.test.js +140 -0
  597. package/tests/e2e/mu-switch.test.js +415 -0
  598. package/tests/e2e/mu-tabs.test.js +494 -0
  599. package/tests/e2e/mu-textarea.test.js +242 -0
  600. package/tests/e2e/mu-virtual-list.test.js +427 -0
  601. package/tests/e2e/perf-memory.test.js +161 -0
  602. package/tests/e2e/puppeteer-helper.js +137 -0
  603. package/tests/e2e/puppeteer.test.js +226 -0
  604. package/tests/e2e/pwa.test.js +261 -0
  605. package/tests/e2e/test-harness.html +319 -0
  606. package/tests/manual/test-components.html +120 -0
  607. package/tests/memory-test.html +309 -0
  608. package/tests/setup-dom.js +93 -0
  609. package/tests/visual-test.html +301 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @fileoverview Render Utilities for Large-Scale Applications
3
+ *
4
+ * Optimizes rendering for complex apps with thousands of components.
5
+ *
6
+ * Features:
7
+ * - requestAnimationFrame batching
8
+ * - Lazy component rendering
9
+ * - Intersection Observer for viewport-based rendering
10
+ * - Memoization for expensive computations
11
+ */
12
+
13
+ /**
14
+ * Batch multiple DOM updates into single animation frame
15
+ * Prevents layout thrashing in complex updates
16
+ */
17
+ class RenderScheduler {
18
+ #queue = [];
19
+ #scheduled = false;
20
+
21
+ /**
22
+ * Schedule a render callback for next animation frame
23
+ * Multiple calls are batched together
24
+ */
25
+ schedule(callback) {
26
+ this.#queue.push(callback);
27
+
28
+ if (!this.#scheduled) {
29
+ this.#scheduled = true;
30
+ requestAnimationFrame(() => this.#flush());
31
+ }
32
+ }
33
+
34
+ #flush() {
35
+ const callbacks = this.#queue.slice();
36
+ this.#queue = [];
37
+ this.#scheduled = false;
38
+
39
+ // Execute all callbacks in single frame
40
+ for (const cb of callbacks) {
41
+ try {
42
+ cb();
43
+ } catch (e) {
44
+ console.error('[RenderScheduler] Error:', e);
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ export const scheduler = new RenderScheduler();
51
+
52
+ /**
53
+ * Memoize expensive function calls
54
+ * @param {Function} fn - Function to memoize
55
+ * @param {Function} keyFn - Optional key function for cache
56
+ */
57
+ export function memo(fn, keyFn = JSON.stringify) {
58
+ const cache = new Map();
59
+
60
+ return (...args) => {
61
+ const key = keyFn(args);
62
+
63
+ if (cache.has(key)) {
64
+ return cache.get(key);
65
+ }
66
+
67
+ const result = fn(...args);
68
+ cache.set(key, result);
69
+ return result;
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Debounce function calls
75
+ * @param {Function} fn
76
+ * @param {number} delay - Delay in ms
77
+ */
78
+ export function debounce(fn, delay = 100) {
79
+ let timer = null;
80
+
81
+ return (...args) => {
82
+ if (timer) clearTimeout(timer);
83
+ timer = setTimeout(() => fn(...args), delay);
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Throttle function calls
89
+ * @param {Function} fn
90
+ * @param {number} limit - Minimum time between calls in ms
91
+ */
92
+ export function throttle(fn, limit = 100) {
93
+ let inThrottle = false;
94
+
95
+ return (...args) => {
96
+ if (!inThrottle) {
97
+ fn(...args);
98
+ inThrottle = true;
99
+ setTimeout(() => inThrottle = false, limit);
100
+ }
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Create an intersection observer for lazy rendering
106
+ * @param {Function} onVisible - Called when element becomes visible
107
+ * @param {Object} options - IntersectionObserver options
108
+ */
109
+ export function createVisibilityObserver(onVisible, options = {}) {
110
+ const observer = new IntersectionObserver((entries) => {
111
+ for (const entry of entries) {
112
+ if (entry.isIntersecting) {
113
+ onVisible(entry.target);
114
+ observer.unobserve(entry.target);
115
+ }
116
+ }
117
+ }, {
118
+ rootMargin: '100px',
119
+ threshold: 0,
120
+ ...options
121
+ });
122
+
123
+ return {
124
+ observe: (el) => observer.observe(el),
125
+ disconnect: () => observer.disconnect()
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Batch DOM reads and writes to prevent layout thrashing
131
+ * Based on fastdom pattern
132
+ */
133
+ class DomBatch {
134
+ #reads = [];
135
+ #writes = [];
136
+ #scheduled = false;
137
+
138
+ /**
139
+ * Schedule a DOM read (measure)
140
+ */
141
+ read(fn) {
142
+ this.#reads.push(fn);
143
+ this.#schedule();
144
+ }
145
+
146
+ /**
147
+ * Schedule a DOM write (mutate)
148
+ */
149
+ write(fn) {
150
+ this.#writes.push(fn);
151
+ this.#schedule();
152
+ }
153
+
154
+ #schedule() {
155
+ if (!this.#scheduled) {
156
+ this.#scheduled = true;
157
+ requestAnimationFrame(() => this.#flush());
158
+ }
159
+ }
160
+
161
+ #flush() {
162
+ // Reads first (measure phase)
163
+ let fn;
164
+ while (fn = this.#reads.shift()) {
165
+ try { fn(); } catch (e) { console.error(e); }
166
+ }
167
+
168
+ // Writes second (mutate phase)
169
+ while (fn = this.#writes.shift()) {
170
+ try { fn(); } catch (e) { console.error(e); }
171
+ }
172
+
173
+ this.#scheduled = false;
174
+
175
+ // If more work was added during flush, schedule again
176
+ if (this.#reads.length || this.#writes.length) {
177
+ this.#schedule();
178
+ }
179
+ }
180
+ }
181
+
182
+ export const domBatch = new DomBatch();
183
+
184
+ /**
185
+ * Chunk large array operations to avoid blocking main thread
186
+ * @param {Array} items - Array to process
187
+ * @param {Function} processFn - Function to call for each item
188
+ * @param {number} chunkSize - Items per chunk
189
+ */
190
+ export async function processInChunks(items, processFn, chunkSize = 100) {
191
+ for (let i = 0; i < items.length; i += chunkSize) {
192
+ const chunk = items.slice(i, i + chunkSize);
193
+
194
+ for (const item of chunk) {
195
+ processFn(item, i);
196
+ }
197
+
198
+ // Yield to main thread between chunks
199
+ await new Promise(r => setTimeout(r, 0));
200
+ }
201
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @fileoverview MD3 Ripple Effect Utility
3
+ *
4
+ * Creates Material Design 3 compliant ripple effects on interactive elements.
5
+ * The ripple originates from the exact click/touch point and expands outward.
6
+ *
7
+ * Usage:
8
+ * import { attachRipple } from './core/ripple.js';
9
+ * attachRipple(element);
10
+ *
11
+ * Or for controlled ripple:
12
+ * import { createRipple } from './core/ripple.js';
13
+ * element.addEventListener('click', (e) => createRipple(element, e));
14
+ */
15
+
16
+ /**
17
+ * Create a ripple effect at the event position within the element.
18
+ * MD3 behavior: ripple expands immediately, persists while pressed, fades on release.
19
+ * @param {HTMLElement} element - Container element for the ripple
20
+ * @param {MouseEvent|TouchEvent} event - The triggering event
21
+ * @param {Object} options - Ripple options
22
+ * @param {string} options.color - Ripple color (default: currentColor)
23
+ * @param {boolean} options.centered - Force ripple to start from center
24
+ */
25
+ export function createRipple(element, event, options = {}) {
26
+ const { color = 'currentColor', centered = false } = options;
27
+
28
+ // Get element bounds
29
+ const rect = element.getBoundingClientRect();
30
+
31
+ // Calculate ripple position (from click point or center)
32
+ let x, y;
33
+ if (centered || !event) {
34
+ x = rect.width / 2;
35
+ y = rect.height / 2;
36
+ } else {
37
+ // Get click/touch position
38
+ const clientX = event.touches ? event.touches[0].clientX : event.clientX;
39
+ const clientY = event.touches ? event.touches[0].clientY : event.clientY;
40
+ x = clientX - rect.left;
41
+ y = clientY - rect.top;
42
+ }
43
+
44
+ // Calculate ripple size (must cover entire element from click point)
45
+ const size = Math.max(
46
+ Math.hypot(x, y),
47
+ Math.hypot(rect.width - x, y),
48
+ Math.hypot(x, rect.height - y),
49
+ Math.hypot(rect.width - x, rect.height - y)
50
+ ) * 2;
51
+
52
+ // Create ripple element
53
+ const ripple = document.createElement('span');
54
+ ripple.className = 'mu-ripple-wave';
55
+ ripple.style.cssText = `
56
+ position: absolute;
57
+ width: ${size}px;
58
+ height: ${size}px;
59
+ left: ${x - size / 2}px;
60
+ top: ${y - size / 2}px;
61
+ background: ${color};
62
+ border-radius: 50%;
63
+ transform: scale(0);
64
+ opacity: 0.10;
65
+ pointer-events: none;
66
+ `;
67
+
68
+ // Ensure container has proper positioning
69
+ const computedStyle = getComputedStyle(element);
70
+ if (computedStyle.position === 'static') {
71
+ element.style.position = 'relative';
72
+ }
73
+ if (computedStyle.overflow !== 'hidden') {
74
+ element.style.overflow = 'hidden';
75
+ }
76
+
77
+ // Add ripple to element
78
+ element.appendChild(ripple);
79
+
80
+ // Phase 1: Expand animation (GPU - transform only)
81
+ ripple.animate([
82
+ { transform: 'scale(0)' },
83
+ { transform: 'scale(1)' }
84
+ ], {
85
+ duration: 300,
86
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
87
+ fill: 'forwards'
88
+ });
89
+
90
+ // Phase 2: Fade out on release (pointer up or leave)
91
+ const fadeOut = () => {
92
+ ripple.animate([
93
+ { opacity: '0.10' },
94
+ { opacity: '0' }
95
+ ], {
96
+ duration: 150,
97
+ easing: 'ease-out',
98
+ fill: 'forwards'
99
+ }).onfinish = () => ripple.remove();
100
+
101
+ // Cleanup listeners
102
+ element.removeEventListener('pointerup', fadeOut);
103
+ element.removeEventListener('pointerleave', fadeOut);
104
+ element.removeEventListener('pointercancel', fadeOut);
105
+ };
106
+
107
+ element.addEventListener('pointerup', fadeOut, { once: true });
108
+ element.addEventListener('pointerleave', fadeOut, { once: true });
109
+ element.addEventListener('pointercancel', fadeOut, { once: true });
110
+
111
+ return ripple;
112
+ }
113
+
114
+ /**
115
+ * Attach ripple effect to an element.
116
+ * @param {HTMLElement} element - Element to attach ripple to
117
+ * @param {Object} options - Ripple options
118
+ * @returns {Function} Cleanup function to remove ripple listener
119
+ */
120
+ export function attachRipple(element, options = {}) {
121
+ const handler = (e) => {
122
+ // Don't create ripple if element is disabled
123
+ if (element.hasAttribute('disabled')) return;
124
+ createRipple(element, e, options);
125
+ };
126
+
127
+ element.addEventListener('pointerdown', handler);
128
+
129
+ // Return cleanup function
130
+ return () => {
131
+ element.removeEventListener('pointerdown', handler);
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Mixin for components that need ripple.
137
+ * Call this.initRipple(targetElement) in connectedCallback.
138
+ */
139
+ export const RippleMixin = (superclass) => class extends superclass {
140
+ #rippleCleanup = null;
141
+
142
+ /**
143
+ * Initialize ripple on target element (or self).
144
+ * @param {HTMLElement} target - Element to add ripple to (defaults to this)
145
+ * @param {Object} options - Ripple options
146
+ */
147
+ initRipple(target = this, options = {}) {
148
+ this.#rippleCleanup = attachRipple(target, options);
149
+ }
150
+
151
+ disconnectedCallback() {
152
+ if (this.#rippleCleanup) {
153
+ this.#rippleCleanup();
154
+ this.#rippleCleanup = null;
155
+ }
156
+ super.disconnectedCallback?.();
157
+ }
158
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @fileoverview Simple SPA Router for microUI
3
+ *
4
+ * Hash-based routing for single page applications.
5
+ *
6
+ * Usage:
7
+ * Router.on('/', () => renderHome());
8
+ * Router.on('/about', () => renderAbout());
9
+ * Router.on('/user/:id', ({ id }) => renderUser(id));
10
+ * Router.start();
11
+ */
12
+
13
+ class RouterClass {
14
+ #routes = [];
15
+ #notFound = null;
16
+ #currentPath = '';
17
+
18
+ /**
19
+ * Register a route
20
+ * @param {string} path - Route path (supports :param)
21
+ * @param {(params: Object) => void} handler
22
+ */
23
+ on(path, handler) {
24
+ // Convert path params to regex
25
+ const pattern = path
26
+ .replace(/:[a-zA-Z]+/g, '([^/]+)')
27
+ .replace(/\//g, '\\/');
28
+
29
+ const paramNames = (path.match(/:[a-zA-Z]+/g) || [])
30
+ .map(p => p.slice(1));
31
+
32
+ this.#routes.push({
33
+ path,
34
+ pattern: new RegExp(`^${pattern}$`),
35
+ paramNames,
36
+ handler
37
+ });
38
+
39
+ return this;
40
+ }
41
+
42
+ /**
43
+ * Set 404 handler
44
+ */
45
+ notFound(handler) {
46
+ this.#notFound = handler;
47
+ return this;
48
+ }
49
+
50
+ /**
51
+ * Navigate to a path
52
+ * @param {string} path
53
+ */
54
+ navigate(path) {
55
+ window.location.hash = path;
56
+ }
57
+
58
+ /**
59
+ * Get current path
60
+ */
61
+ get current() {
62
+ return this.#currentPath;
63
+ }
64
+
65
+ /**
66
+ * Start the router
67
+ */
68
+ start() {
69
+ const handleRoute = () => {
70
+ const hash = window.location.hash.slice(1) || '/';
71
+ this.#currentPath = hash;
72
+
73
+ for (const route of this.#routes) {
74
+ const match = hash.match(route.pattern);
75
+ if (match) {
76
+ // Extract params
77
+ const params = {};
78
+ route.paramNames.forEach((name, i) => {
79
+ params[name] = match[i + 1];
80
+ });
81
+
82
+ route.handler(params);
83
+ return;
84
+ }
85
+ }
86
+
87
+ // No match - 404
88
+ if (this.#notFound) {
89
+ this.#notFound(hash);
90
+ }
91
+ };
92
+
93
+ window.addEventListener('hashchange', handleRoute);
94
+ handleRoute(); // Handle initial route
95
+
96
+ return this;
97
+ }
98
+ }
99
+
100
+ export const Router = new RouterClass();
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Task Scheduler API (2026 SOTA)
3
+ *
4
+ * Uses scheduler.postTask() for priority-based scheduling.
5
+ * Falls back to setTimeout if not supported.
6
+ *
7
+ * Priority levels:
8
+ * - 'user-blocking': Highest priority (input handlers)
9
+ * - 'user-visible': Medium priority (rendering)
10
+ * - 'background': Lowest priority (analytics, prefetch)
11
+ *
12
+ * Usage:
13
+ * await scheduleTask(() => heavyComputation(), 'background');
14
+ * await yieldToMain();
15
+ */
16
+
17
+ /**
18
+ * Check if Scheduler API is supported
19
+ */
20
+ export const supportsScheduler = 'scheduler' in globalThis;
21
+
22
+ /**
23
+ * Schedule a task with priority
24
+ * @param {() => T} callback
25
+ * @param {'user-blocking' | 'user-visible' | 'background'} priority
26
+ * @returns {Promise<T>}
27
+ */
28
+ export async function scheduleTask(callback, priority = 'user-visible') {
29
+ if (supportsScheduler) {
30
+ return globalThis.scheduler.postTask(callback, { priority });
31
+ }
32
+
33
+ // Fallback with setTimeout based on priority
34
+ const delay = priority === 'user-blocking' ? 0 :
35
+ priority === 'user-visible' ? 0 : 1;
36
+
37
+ return new Promise(resolve => {
38
+ setTimeout(() => resolve(callback()), delay);
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Yield to main thread (allow input/rendering)
44
+ * @returns {Promise<void>}
45
+ */
46
+ export async function yieldToMain() {
47
+ if (supportsScheduler && 'yield' in globalThis.scheduler) {
48
+ return globalThis.scheduler.yield();
49
+ }
50
+
51
+ // Fallback: yield with setTimeout
52
+ return new Promise(resolve => setTimeout(resolve, 0));
53
+ }
54
+
55
+ /**
56
+ * Process items in chunks, yielding between chunks
57
+ * Better than processInChunks because it uses scheduler.yield()
58
+ *
59
+ * @param {T[]} items
60
+ * @param {(item: T, index: number) => void} process
61
+ * @param {number} chunkSize
62
+ */
63
+ export async function processWithYield(items, process, chunkSize = 50) {
64
+ for (let i = 0; i < items.length; i++) {
65
+ process(items[i], i);
66
+
67
+ // Yield every chunk
68
+ if ((i + 1) % chunkSize === 0) {
69
+ await yieldToMain();
70
+ }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Run background task (lowest priority, won't block UI)
76
+ * @param {() => T} callback
77
+ * @returns {Promise<T>}
78
+ */
79
+ export function runBackground(callback) {
80
+ return scheduleTask(callback, 'background');
81
+ }
82
+
83
+ /**
84
+ * Run user-blocking task (highest priority)
85
+ * @param {() => T} callback
86
+ * @returns {Promise<T>}
87
+ */
88
+ export function runImmediate(callback) {
89
+ return scheduleTask(callback, 'user-blocking');
90
+ }
91
+
92
+ /**
93
+ * Wait for next browser paint (double-rAF pattern)
94
+ * Use for CSS animation triggers after DOM changes.
95
+ * This ensures the browser has completed layout/paint before applying
96
+ * additional classes that would trigger transitions.
97
+ *
98
+ * @returns {Promise<void>}
99
+ * @example
100
+ * // Trigger CSS animation after DOM change
101
+ * element.classList.add('is-open');
102
+ * await afterPaint();
103
+ * element.classList.add('is-visible'); // Now transition will animate
104
+ */
105
+ export function afterPaint() {
106
+ return new Promise(resolve => {
107
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
108
+ });
109
+ }