microui-wc 0.1.1 โ†’ 0.1.2

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 (339) hide show
  1. package/AGENTS.md +71 -71
  2. package/CHANGELOG.md +1 -1
  3. package/README.md +14 -9
  4. package/dist/AGENTS.md +71 -71
  5. package/dist/README.md +14 -9
  6. package/dist/microui.css +1 -1
  7. package/dist/microui.esm.js.map +1 -1
  8. package/dist/microui.min.js.map +1 -1
  9. package/docs/getting-started.md +3 -3
  10. package/package.json +39 -11
  11. package/src/components/mu-schema-form.js +1 -1
  12. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  13. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -33
  14. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  15. package/.github/workflows/ci.yml +0 -42
  16. package/.github/workflows/deploy-pages.yml +0 -112
  17. package/CODE_OF_CONDUCT.md +0 -59
  18. package/CONTRIBUTING.md +0 -156
  19. package/SECURITY.md +0 -58
  20. package/app/.generated/routes/alerts.js +0 -8
  21. package/app/.generated/routes/avatars.js +0 -8
  22. package/app/.generated/routes/badges.js +0 -8
  23. package/app/.generated/routes/buttons.js +0 -10
  24. package/app/.generated/routes/cards.js +0 -10
  25. package/app/.generated/routes/checkboxes.js +0 -9
  26. package/app/.generated/routes/chips.js +0 -8
  27. package/app/.generated/routes/dropdowns.js +0 -9
  28. package/app/.generated/routes/home.js +0 -7
  29. package/app/.generated/routes/icons.js +0 -9
  30. package/app/.generated/routes/inputs.js +0 -10
  31. package/app/.generated/routes/installation.js +0 -7
  32. package/app/.generated/routes/layout.js +0 -9
  33. package/app/.generated/routes/modals.js +0 -9
  34. package/app/.generated/routes/navbar.js +0 -7
  35. package/app/.generated/routes/progress.js +0 -9
  36. package/app/.generated/routes/radios.js +0 -9
  37. package/app/.generated/routes/switches.js +0 -9
  38. package/app/.generated/routes/tabs.js +0 -8
  39. package/app/.generated/routes/toasts.js +0 -9
  40. package/app/index.html +0 -67
  41. package/app/pages/alerts.html +0 -23
  42. package/app/pages/avatars.html +0 -22
  43. package/app/pages/badges.html +0 -22
  44. package/app/pages/buttons.html +0 -71
  45. package/app/pages/cards.html +0 -54
  46. package/app/pages/checkboxes.html +0 -39
  47. package/app/pages/chips.html +0 -23
  48. package/app/pages/dropdowns.html +0 -41
  49. package/app/pages/home.html +0 -59
  50. package/app/pages/icons.html +0 -29
  51. package/app/pages/inputs.html +0 -66
  52. package/app/pages/installation.html +0 -34
  53. package/app/pages/layout.html +0 -30
  54. package/app/pages/modals.html +0 -21
  55. package/app/pages/navbar.html +0 -22
  56. package/app/pages/progress.html +0 -35
  57. package/app/pages/radios.html +0 -40
  58. package/app/pages/switches.html +0 -39
  59. package/app/pages/tabs.html +0 -30
  60. package/app/pages/toasts.html +0 -22
  61. package/app-dist/index.html +0 -67
  62. package/app-dist/pages/alerts.html +0 -23
  63. package/app-dist/pages/avatars.html +0 -22
  64. package/app-dist/pages/badges.html +0 -22
  65. package/app-dist/pages/buttons.html +0 -71
  66. package/app-dist/pages/cards.html +0 -54
  67. package/app-dist/pages/checkboxes.html +0 -39
  68. package/app-dist/pages/chips.html +0 -23
  69. package/app-dist/pages/dropdowns.html +0 -41
  70. package/app-dist/pages/home.html +0 -59
  71. package/app-dist/pages/icons.html +0 -29
  72. package/app-dist/pages/inputs.html +0 -66
  73. package/app-dist/pages/installation.html +0 -34
  74. package/app-dist/pages/layout.html +0 -30
  75. package/app-dist/pages/modals.html +0 -21
  76. package/app-dist/pages/navbar.html +0 -22
  77. package/app-dist/pages/progress.html +0 -35
  78. package/app-dist/pages/radios.html +0 -40
  79. package/app-dist/pages/switches.html +0 -39
  80. package/app-dist/pages/tabs.html +0 -30
  81. package/app-dist/pages/toasts.html +0 -22
  82. package/app-dist/pages.json +0 -217
  83. package/app-dist/routes/alerts.js +0 -5
  84. package/app-dist/routes/avatars.js +0 -1
  85. package/app-dist/routes/badges.js +0 -1
  86. package/app-dist/routes/buttons.js +0 -1
  87. package/app-dist/routes/cards.js +0 -1
  88. package/app-dist/routes/checkboxes.js +0 -9
  89. package/app-dist/routes/chips.js +0 -4
  90. package/app-dist/routes/chunk-019e5e2f.js +0 -5
  91. package/app-dist/routes/chunk-0m4j19yd.js +0 -2
  92. package/app-dist/routes/chunk-0tmmp5q0.js +0 -1
  93. package/app-dist/routes/chunk-10xn709r.js +0 -1
  94. package/app-dist/routes/chunk-15m2qcda.js +0 -2
  95. package/app-dist/routes/chunk-1bh8g23n.js +0 -1
  96. package/app-dist/routes/chunk-1vg0v937.js +0 -1
  97. package/app-dist/routes/chunk-1zvcgy3j.js +0 -1
  98. package/app-dist/routes/chunk-2afb0861.js +0 -1
  99. package/app-dist/routes/chunk-2c6ttpzt.js +0 -5
  100. package/app-dist/routes/chunk-3dy30fhs.js +0 -1
  101. package/app-dist/routes/chunk-426dnces.js +0 -13
  102. package/app-dist/routes/chunk-44kgxery.js +0 -1
  103. package/app-dist/routes/chunk-47fdnejd.js +0 -33
  104. package/app-dist/routes/chunk-49a6t2vq.js +0 -1
  105. package/app-dist/routes/chunk-4fe1rm5b.js +0 -1
  106. package/app-dist/routes/chunk-4ggmvkta.js +0 -33
  107. package/app-dist/routes/chunk-4vkz81q7.js +0 -33
  108. package/app-dist/routes/chunk-4w4tmj8f.js +0 -31
  109. package/app-dist/routes/chunk-532s62kr.js +0 -31
  110. package/app-dist/routes/chunk-5hm3bssy.js +0 -33
  111. package/app-dist/routes/chunk-5vrh24hc.js +0 -1
  112. package/app-dist/routes/chunk-61pcg25a.js +0 -1
  113. package/app-dist/routes/chunk-6nfhygvf.js +0 -1
  114. package/app-dist/routes/chunk-700e7je6.js +0 -33
  115. package/app-dist/routes/chunk-7fsn17kg.js +0 -1
  116. package/app-dist/routes/chunk-7k789b32.js +0 -1
  117. package/app-dist/routes/chunk-7r46q0ys.js +0 -36
  118. package/app-dist/routes/chunk-86fmc1fr.js +0 -5
  119. package/app-dist/routes/chunk-8qth37vw.js +0 -1
  120. package/app-dist/routes/chunk-924wv8n0.js +0 -1
  121. package/app-dist/routes/chunk-9mbhgxk9.js +0 -1
  122. package/app-dist/routes/chunk-a216hyd9.js +0 -1
  123. package/app-dist/routes/chunk-akzxykh9.js +0 -33
  124. package/app-dist/routes/chunk-b3dcvy8c.js +0 -1
  125. package/app-dist/routes/chunk-b74zahz5.js +0 -31
  126. package/app-dist/routes/chunk-bftj53p2.js +0 -5
  127. package/app-dist/routes/chunk-c01hnz3e.js +0 -1
  128. package/app-dist/routes/chunk-d8pvv5km.js +0 -1
  129. package/app-dist/routes/chunk-dev0aezr.js +0 -2
  130. package/app-dist/routes/chunk-dh6vnv0e.js +0 -1
  131. package/app-dist/routes/chunk-dn2cbpva.js +0 -36
  132. package/app-dist/routes/chunk-dvn0my90.js +0 -1
  133. package/app-dist/routes/chunk-dvq8mnve.js +0 -36
  134. package/app-dist/routes/chunk-e8c2gc4d.js +0 -5
  135. package/app-dist/routes/chunk-ejf9ak2x.js +0 -1
  136. package/app-dist/routes/chunk-f083m55s.js +0 -1
  137. package/app-dist/routes/chunk-fnrj28s1.js +0 -31
  138. package/app-dist/routes/chunk-fvg3yjdp.js +0 -31
  139. package/app-dist/routes/chunk-g7k381n1.js +0 -1
  140. package/app-dist/routes/chunk-h01kq2ae.js +0 -13
  141. package/app-dist/routes/chunk-h4dk761v.js +0 -5
  142. package/app-dist/routes/chunk-hmx91z2x.js +0 -5
  143. package/app-dist/routes/chunk-hxbg4m42.js +0 -36
  144. package/app-dist/routes/chunk-jbjnfp2b.js +0 -2
  145. package/app-dist/routes/chunk-jxtz5vv6.js +0 -36
  146. package/app-dist/routes/chunk-jxzcs0ey.js +0 -36
  147. package/app-dist/routes/chunk-kt7wwhcx.js +0 -1
  148. package/app-dist/routes/chunk-kzptszyc.js +0 -33
  149. package/app-dist/routes/chunk-mhgca4w4.js +0 -2
  150. package/app-dist/routes/chunk-mhswxa20.js +0 -1
  151. package/app-dist/routes/chunk-n8zfeex6.js +0 -1
  152. package/app-dist/routes/chunk-pee47b2r.js +0 -1
  153. package/app-dist/routes/chunk-pesmw829.js +0 -1
  154. package/app-dist/routes/chunk-pgc4c6f3.js +0 -36
  155. package/app-dist/routes/chunk-q8egegm1.js +0 -1
  156. package/app-dist/routes/chunk-q9mn2qyq.js +0 -36
  157. package/app-dist/routes/chunk-qh0rtaf3.js +0 -5
  158. package/app-dist/routes/chunk-qqhmk6ye.js +0 -2
  159. package/app-dist/routes/chunk-qrxygmf7.js +0 -33
  160. package/app-dist/routes/chunk-r46yzksx.js +0 -36
  161. package/app-dist/routes/chunk-rgpbw2w0.js +0 -5
  162. package/app-dist/routes/chunk-rnpzv3d8.js +0 -2
  163. package/app-dist/routes/chunk-s5v8cv05.js +0 -2
  164. package/app-dist/routes/chunk-sbwn5bpc.js +0 -1
  165. package/app-dist/routes/chunk-sqbg8jbt.js +0 -33
  166. package/app-dist/routes/chunk-sv8dqnf7.js +0 -1
  167. package/app-dist/routes/chunk-t67sw3za.js +0 -1
  168. package/app-dist/routes/chunk-tjdpqwdf.js +0 -31
  169. package/app-dist/routes/chunk-tq2mfghg.js +0 -1
  170. package/app-dist/routes/chunk-ttn10vt6.js +0 -1
  171. package/app-dist/routes/chunk-v2hzpjxr.js +0 -1
  172. package/app-dist/routes/chunk-wfjjkw9y.js +0 -1
  173. package/app-dist/routes/chunk-wt8cxzmf.js +0 -31
  174. package/app-dist/routes/chunk-x45d372k.js +0 -5
  175. package/app-dist/routes/chunk-y3wsazkt.js +0 -1
  176. package/app-dist/routes/chunk-y7pmgc7t.js +0 -33
  177. package/app-dist/routes/chunk-zefdt2q3.js +0 -31
  178. package/app-dist/routes/dropdowns.js +0 -6
  179. package/app-dist/routes/home.js +0 -1
  180. package/app-dist/routes/icons.js +0 -1
  181. package/app-dist/routes/inputs.js +0 -12
  182. package/app-dist/routes/installation.js +0 -1
  183. package/app-dist/routes/layout.js +0 -1
  184. package/app-dist/routes/modals.js +0 -7
  185. package/app-dist/routes/navbar.js +0 -1
  186. package/app-dist/routes/progress.js +0 -1
  187. package/app-dist/routes/radios.js +0 -6
  188. package/app-dist/routes/switches.js +0 -6
  189. package/app-dist/routes/tabs.js +0 -1
  190. package/app-dist/routes/toasts.js +0 -16
  191. package/assets/fonts/material-symbols-mini.woff2 +0 -0
  192. package/assets/fonts/material-symbols.woff2 +0 -0
  193. package/assets/fonts/roboto-400.woff2 +0 -0
  194. package/assets/fonts/roboto-500.woff2 +0 -0
  195. package/assets/fonts/roboto-700.woff2 +0 -0
  196. package/assets/logo-banner-400.jpg +0 -0
  197. package/assets/logo-banner-400.webp +0 -0
  198. package/assets/logo-banner-800.webp +0 -0
  199. package/assets/logo-banner.jpg +0 -0
  200. package/assets/logo-icon-64.jpg +0 -0
  201. package/assets/logo-icon-64.webp +0 -0
  202. package/assets/logo-icon.jpg +0 -0
  203. package/assets/logo-square.jpg +0 -0
  204. package/bun.lock +0 -312
  205. package/bunfig.toml +0 -4
  206. package/custom-elements.json +0 -1916
  207. package/demo/api/sample-data.json +0 -38
  208. package/demo/content/alerts.html +0 -115
  209. package/demo/content/avatars.html +0 -70
  210. package/demo/content/badges.html +0 -65
  211. package/demo/content/buttons.html +0 -188
  212. package/demo/content/callouts.html +0 -91
  213. package/demo/content/cards.html +0 -121
  214. package/demo/content/checkboxes.html +0 -178
  215. package/demo/content/chips.html +0 -67
  216. package/demo/content/codeblocks.html +0 -101
  217. package/demo/content/confirms.html +0 -115
  218. package/demo/content/datatables.html +0 -149
  219. package/demo/content/dividers.html +0 -119
  220. package/demo/content/dropdowns.html +0 -89
  221. package/demo/content/enterprise.html +0 -252
  222. package/demo/content/home.html +0 -149
  223. package/demo/content/icons.html +0 -89
  224. package/demo/content/inputs.html +0 -135
  225. package/demo/content/installation.html +0 -16
  226. package/demo/content/layout.html +0 -136
  227. package/demo/content/modals.html +0 -141
  228. package/demo/content/navbar.html +0 -70
  229. package/demo/content/progress.html +0 -119
  230. package/demo/content/radios.html +0 -88
  231. package/demo/content/skeletons.html +0 -109
  232. package/demo/content/spinners.html +0 -96
  233. package/demo/content/switches.html +0 -84
  234. package/demo/content/tables.html +0 -124
  235. package/demo/content/tabs.html +0 -85
  236. package/demo/content/toasts.html +0 -116
  237. package/demo/content/tooltips.html +0 -107
  238. package/demo/content/virtual-lists.html +0 -233
  239. package/demo/favicon.ico +0 -0
  240. package/demo/favicon.png +0 -0
  241. package/demo/full.html +0 -52
  242. package/demo/iife.html +0 -46
  243. package/demo/manifest.json +0 -34
  244. package/demo/pages/datatable-demo.html +0 -237
  245. package/demo/pages/prompt-ui-demo.html +0 -218
  246. package/demo/pages/responsive-demo.html +0 -122
  247. package/demo/pages/schema-form-demo.html +0 -270
  248. package/demo/robots.txt +0 -6
  249. package/demo/shell.html +0 -712
  250. package/demo/sw.js +0 -387
  251. package/lighthouse-audit.mjs +0 -113
  252. package/scripts/analyze-components.js +0 -105
  253. package/scripts/build-app.js +0 -193
  254. package/scripts/build-framework.js +0 -444
  255. package/scripts/build-utils.js +0 -101
  256. package/scripts/test-isolated.js +0 -151
  257. package/server.js +0 -256
  258. package/tests/agents/agent-integration.test.js +0 -76
  259. package/tests/benchmark.html +0 -296
  260. package/tests/build/scan-components.test.js +0 -173
  261. package/tests/components/all-components.test.js +0 -245
  262. package/tests/components/all-missing-components.test.js +0 -574
  263. package/tests/components/mu-alert.test.js +0 -113
  264. package/tests/components/mu-avatar.test.js +0 -148
  265. package/tests/components/mu-badge.test.js +0 -92
  266. package/tests/components/mu-button.test.js +0 -112
  267. package/tests/components/mu-card.test.js +0 -89
  268. package/tests/components/mu-checkbox.test.js +0 -158
  269. package/tests/components/mu-chip.test.js +0 -118
  270. package/tests/components/mu-container.test.js +0 -120
  271. package/tests/components/mu-divider.test.js +0 -98
  272. package/tests/components/mu-drawer-item.test.js +0 -199
  273. package/tests/components/mu-drawer.test.js +0 -96
  274. package/tests/components/mu-dropdown.test.js +0 -125
  275. package/tests/components/mu-form.test.js +0 -138
  276. package/tests/components/mu-grid.test.js +0 -135
  277. package/tests/components/mu-icon.test.js +0 -110
  278. package/tests/components/mu-input.test.js +0 -131
  279. package/tests/components/mu-lazy.test.js +0 -103
  280. package/tests/components/mu-modal.test.js +0 -275
  281. package/tests/components/mu-navbar.test.js +0 -101
  282. package/tests/components/mu-progress.test.js +0 -115
  283. package/tests/components/mu-radio.test.js +0 -114
  284. package/tests/components/mu-repeat.test.js +0 -106
  285. package/tests/components/mu-sidebar.test.js +0 -126
  286. package/tests/components/mu-skeleton.test.js +0 -162
  287. package/tests/components/mu-stack.test.js +0 -143
  288. package/tests/components/mu-switch.test.js +0 -292
  289. package/tests/components/mu-table.test.js +0 -124
  290. package/tests/components/mu-tabs.test.js +0 -104
  291. package/tests/components/mu-textarea.test.js +0 -115
  292. package/tests/components/mu-toast.test.js +0 -321
  293. package/tests/components/mu-tooltip.test.js +0 -133
  294. package/tests/components/mu-virtual-list.test.js +0 -109
  295. package/tests/core/MuElement.test.js +0 -120
  296. package/tests/core/agent-api.test.js +0 -125
  297. package/tests/core/all-core-modules.test.js +0 -442
  298. package/tests/core/bus.test.js +0 -364
  299. package/tests/core/component-schema.test.js +0 -160
  300. package/tests/core/feature-registry.test.js +0 -198
  301. package/tests/core/form-state.test.js +0 -167
  302. package/tests/core/http.test.js +0 -119
  303. package/tests/core/keyboard.test.js +0 -319
  304. package/tests/core/layers.test.js +0 -129
  305. package/tests/core/namespaced-stores.test.js +0 -114
  306. package/tests/core/render.test.js +0 -121
  307. package/tests/core/ripple.test.js +0 -131
  308. package/tests/core/router.test.js +0 -89
  309. package/tests/core/scheduler.test.js +0 -121
  310. package/tests/core/signals.test.js +0 -128
  311. package/tests/core/store.test.js +0 -171
  312. package/tests/core/transitions.test.js +0 -82
  313. package/tests/e2e/accessibility-harness.html +0 -58
  314. package/tests/e2e/accessibility.test.js +0 -401
  315. package/tests/e2e/agent-features.test.js +0 -372
  316. package/tests/e2e/card-spacing.test.js +0 -287
  317. package/tests/e2e/components.test.js +0 -439
  318. package/tests/e2e/demo-routes.test.js +0 -478
  319. package/tests/e2e/layout-css-fallback.test.js +0 -334
  320. package/tests/e2e/mu-alert.e2e.test.js +0 -111
  321. package/tests/e2e/mu-checkbox.test.js +0 -489
  322. package/tests/e2e/mu-chip.test.js +0 -347
  323. package/tests/e2e/mu-form.test.js +0 -499
  324. package/tests/e2e/mu-icon.test.js +0 -114
  325. package/tests/e2e/mu-radio.test.js +0 -113
  326. package/tests/e2e/mu-skeleton.test.js +0 -140
  327. package/tests/e2e/mu-switch.test.js +0 -415
  328. package/tests/e2e/mu-tabs.test.js +0 -494
  329. package/tests/e2e/mu-textarea.test.js +0 -242
  330. package/tests/e2e/mu-virtual-list.test.js +0 -427
  331. package/tests/e2e/perf-memory.test.js +0 -161
  332. package/tests/e2e/puppeteer-helper.js +0 -137
  333. package/tests/e2e/puppeteer.test.js +0 -226
  334. package/tests/e2e/pwa.test.js +0 -261
  335. package/tests/e2e/test-harness.html +0 -319
  336. package/tests/manual/test-components.html +0 -120
  337. package/tests/memory-test.html +0 -309
  338. package/tests/setup-dom.js +0 -93
  339. package/tests/visual-test.html +0 -301
@@ -1,101 +0,0 @@
1
- /**
2
- * @fileoverview Build utilities for microUI
3
- *
4
- * Contains reusable functions for the build process,
5
- * particularly for automatic component detection.
6
- */
7
-
8
- /**
9
- * Scan HTML content for mu-* components within page divs.
10
- * Extracts component names from each page section.
11
- *
12
- * @param {string} htmlContent - Full HTML content to scan
13
- * @returns {Object<string, string[]>} Map of pageId -> component names
14
- *
15
- * @example
16
- * const html = '<div id="page-home"><mu-button>Click</mu-button></div>';
17
- * const result = scanPageComponents(html);
18
- * // { home: ['mu-button'] }
19
- */
20
- export function scanPageComponents(htmlContent) {
21
- const pages = {};
22
-
23
- // Match page divs: <div id="page-xxx">...</div>
24
- // Use non-greedy matching and look ahead for next page or end
25
- const pageRegex = /<div\s+id="page-(\w+)"[^>]*>([\s\S]*?)(?=<div\s+id="page-|\s*<\/mu-layout|\s*<footer|\s*$)/gi;
26
-
27
- let match;
28
- while ((match = pageRegex.exec(htmlContent)) !== null) {
29
- const pageId = match[1];
30
- const pageContent = match[2];
31
-
32
- // Extract all mu-* tags (opening tags only)
33
- const components = new Set();
34
- const tagRegex = /<(mu-[\w-]+)/gi;
35
- let tagMatch;
36
- while ((tagMatch = tagRegex.exec(pageContent)) !== null) {
37
- // Normalize to lowercase
38
- components.add(tagMatch[1].toLowerCase());
39
- }
40
-
41
- if (components.size > 0) {
42
- pages[pageId] = [...components].sort();
43
- }
44
- }
45
-
46
- return pages;
47
- }
48
-
49
- /**
50
- * Map component names to their route file names.
51
- * Some components share routes (e.g., mu-tab is in tabs route).
52
- *
53
- * @param {string[]} components - Array of component names
54
- * @returns {string[]} Array of route names to load
55
- */
56
- export function componentsToRoutes(components) {
57
- // Component -> route mapping (most are 1:1 with pluralization)
58
- const componentRouteMap = {
59
- 'mu-tab': 'tabs',
60
- 'mu-tabs': 'tabs',
61
- 'mu-button': 'buttons',
62
- 'mu-input': 'inputs',
63
- 'mu-textarea': 'inputs',
64
- 'mu-checkbox': 'checkboxes',
65
- 'mu-switch': 'switches',
66
- 'mu-radio': 'radios',
67
- 'mu-dropdown': 'dropdowns',
68
- 'mu-card': 'cards',
69
- 'mu-stack': 'layout',
70
- 'mu-grid': 'layout',
71
- 'mu-alert': 'alerts',
72
- 'mu-toast': 'toasts',
73
- 'mu-modal': 'modals',
74
- 'mu-progress': 'progress',
75
- 'mu-spinner': 'progress',
76
- 'mu-avatar': 'avatars',
77
- 'mu-badge': 'badges',
78
- 'mu-chip': 'chips',
79
- 'mu-icon': 'icons',
80
- 'mu-navbar': 'navbar',
81
- 'mu-example': 'tabs', // part of tabs route
82
- 'mu-code': 'tabs', // part of tabs route
83
- 'mu-api-table': 'tabs', // part of tabs route
84
- // Shell components (always loaded)
85
- 'mu-layout': 'shell-critical',
86
- 'mu-drawer': 'shell-critical',
87
- 'mu-drawer-item': 'shell-critical',
88
- 'mu-theme-toggle': 'shell-deferred',
89
- 'mu-bottom-nav': 'shell-deferred',
90
- };
91
-
92
- const routes = new Set();
93
- for (const comp of components) {
94
- const route = componentRouteMap[comp];
95
- if (route) {
96
- routes.add(route);
97
- }
98
- }
99
-
100
- return [...routes].sort();
101
- }
@@ -1,151 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * @fileoverview Isolated Test Runner
4
- *
5
- * Runs each test file in a separate Bun process to ensure complete isolation
6
- * of globalThis, module cache, and custom element registries.
7
- *
8
- * This solves the linkedom globalThis pollution issue where tests pass
9
- * individually but fail when run together.
10
- *
11
- * Usage: bun run scripts/test-isolated.js [pattern]
12
- */
13
-
14
- import { spawn } from 'bun';
15
- import { readdirSync, statSync } from 'fs';
16
- import { join, relative } from 'path';
17
-
18
- const args = process.argv.slice(2);
19
- const filterPattern = args[0] || '';
20
-
21
- // Colors for output
22
- const colors = {
23
- reset: '\x1b[0m',
24
- green: '\x1b[32m',
25
- red: '\x1b[31m',
26
- yellow: '\x1b[33m',
27
- cyan: '\x1b[36m',
28
- dim: '\x1b[2m'
29
- };
30
-
31
- // Find all test files
32
- function findTestFiles(dir, files = []) {
33
- const entries = readdirSync(dir);
34
- for (const entry of entries) {
35
- const fullPath = join(dir, entry);
36
- const stat = statSync(fullPath);
37
- if (stat.isDirectory() && !entry.startsWith('.') && entry !== 'node_modules') {
38
- findTestFiles(fullPath, files);
39
- } else if (entry.endsWith('.test.js')) {
40
- files.push(fullPath);
41
- }
42
- }
43
- return files;
44
- }
45
-
46
- // Run a single test file in isolation
47
- async function runTestFile(testFile) {
48
- const relativePath = relative(process.cwd(), testFile);
49
-
50
- const proc = spawn({
51
- cmd: ['bun', 'test', testFile],
52
- cwd: process.cwd(),
53
- stdout: 'pipe',
54
- stderr: 'pipe',
55
- env: {
56
- ...process.env,
57
- FORCE_COLOR: '1'
58
- }
59
- });
60
-
61
- const stdout = await new Response(proc.stdout).text();
62
- const stderr = await new Response(proc.stderr).text();
63
- const exitCode = await proc.exited;
64
-
65
- // Combine output (bun test writes summary to stderr)
66
- const output = stdout + stderr;
67
-
68
- // Parse results from output
69
- const passMatch = output.match(/\s*(\d+)\s+pass/);
70
- const failMatch = output.match(/\s*(\d+)\s+fail/);
71
- const skipMatch = output.match(/\s*(\d+)\s+skip/);
72
-
73
- const pass = passMatch ? parseInt(passMatch[1]) : 0;
74
- const fail = failMatch ? parseInt(failMatch[1]) : 0;
75
- const skip = skipMatch ? parseInt(skipMatch[1]) : 0;
76
-
77
- return {
78
- file: relativePath,
79
- pass,
80
- fail,
81
- skip,
82
- exitCode,
83
- stdout,
84
- stderr
85
- };
86
- }
87
-
88
- // Main execution
89
- async function main() {
90
- const testsDir = join(process.cwd(), 'tests');
91
- let testFiles = findTestFiles(testsDir);
92
-
93
- // Filter by pattern if provided
94
- if (filterPattern) {
95
- testFiles = testFiles.filter(f => f.includes(filterPattern));
96
- }
97
-
98
- // Filter out e2e tests (they have their own runner)
99
- testFiles = testFiles.filter(f => !f.includes('/e2e/'));
100
-
101
- console.log(`${colors.cyan}๐Ÿงช Isolated Test Runner${colors.reset}`);
102
- console.log(`${colors.dim}Running ${testFiles.length} test files in separate processes...${colors.reset}\n`);
103
-
104
- const startTime = Date.now();
105
- const results = [];
106
-
107
- for (const testFile of testFiles) {
108
- const result = await runTestFile(testFile);
109
- results.push(result);
110
-
111
- // Print inline status
112
- const status = result.fail === 0
113
- ? `${colors.green}โœ“${colors.reset}`
114
- : `${colors.red}โœ—${colors.reset}`;
115
- const counts = `${colors.green}${result.pass}${colors.reset}/${colors.red}${result.fail}${colors.reset}/${colors.yellow}${result.skip}${colors.reset}`;
116
- console.log(`${status} ${result.file} [${counts}]`);
117
-
118
- // Show errors for failed files
119
- if (result.fail > 0 && process.env.VERBOSE) {
120
- console.log(result.stdout);
121
- }
122
- }
123
-
124
- const duration = Date.now() - startTime;
125
-
126
- // Summary
127
- const totalPass = results.reduce((sum, r) => sum + r.pass, 0);
128
- const totalFail = results.reduce((sum, r) => sum + r.fail, 0);
129
- const totalSkip = results.reduce((sum, r) => sum + r.skip, 0);
130
- const failedFiles = results.filter(r => r.fail > 0);
131
-
132
- console.log(`\n${colors.cyan}โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”${colors.reset}`);
133
- console.log(`${colors.green}${totalPass} pass${colors.reset} | ${colors.red}${totalFail} fail${colors.reset} | ${colors.yellow}${totalSkip} skip${colors.reset}`);
134
- console.log(`${colors.dim}Ran ${results.length} test files in ${(duration / 1000).toFixed(2)}s${colors.reset}`);
135
-
136
- if (failedFiles.length > 0) {
137
- console.log(`\n${colors.red}Failed files:${colors.reset}`);
138
- for (const f of failedFiles) {
139
- console.log(` ${colors.red}โœ—${colors.reset} ${f.file} (${f.fail} failures)`);
140
- }
141
- process.exit(1);
142
- }
143
-
144
- console.log(`\n${colors.green}โœ“ All tests passed!${colors.reset}`);
145
- process.exit(0);
146
- }
147
-
148
- main().catch(err => {
149
- console.error('Error:', err);
150
- process.exit(1);
151
- });
package/server.js DELETED
@@ -1,256 +0,0 @@
1
- /**
2
- * microUI Dev Server with caching + Brotli/gzip compression
3
- * Optimized for Lighthouse 100 - SOTA 2026
4
- * Run: bun run server.js
5
- */
6
-
7
- import { brotliCompressSync, constants as zlibConstants } from 'zlib';
8
-
9
- const PORT = 5001;
10
-
11
- // Cache durations
12
- const CACHE_LONG = 'public, max-age=31536000, immutable'; // 1 year for versioned assets
13
- const CACHE_SHORT = 'public, max-age=3600'; // 1 hour for HTML
14
- const CACHE_REVALIDATE = 'public, max-age=0, must-revalidate'; // Always revalidate but allow bf-cache
15
-
16
- // MIME types
17
- const MIME_TYPES = {
18
- '.html': 'text/html; charset=utf-8',
19
- '.css': 'text/css; charset=utf-8',
20
- '.js': 'text/javascript; charset=utf-8',
21
- '.mjs': 'text/javascript; charset=utf-8',
22
- '.json': 'application/json',
23
- '.txt': 'text/plain; charset=utf-8',
24
- '.png': 'image/png',
25
- '.jpg': 'image/jpeg',
26
- '.jpeg': 'image/jpeg',
27
- '.webp': 'image/webp',
28
- '.svg': 'image/svg+xml',
29
- '.ico': 'image/x-icon',
30
- '.woff': 'font/woff',
31
- '.woff2': 'font/woff2',
32
- '.webmanifest': 'application/manifest+json',
33
- };
34
-
35
- // Types that benefit from gzip
36
- const COMPRESSIBLE_TYPES = ['.html', '.css', '.js', '.mjs', '.json', '.svg'];
37
-
38
- // Preload hints for critical resources (Link headers)
39
- const PRELOAD_HINTS = {
40
- '/demo/shell.html': [
41
- '</dist/microui.css>; rel=preload; as=style',
42
- '</assets/fonts/roboto-400.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin',
43
- '</assets/logo-banner-400.webp>; rel=preload; as=image; type="image/webp"',
44
- ],
45
- };
46
-
47
- function getContentType(path) {
48
- const ext = path.match(/\.[^.]+$/)?.[0] || '';
49
- return MIME_TYPES[ext] || 'application/octet-stream';
50
- }
51
-
52
- function getCacheControl(path) {
53
- const cleanPath = path.split('?')[0];
54
-
55
- // Immutable assets: versioned bundles, fonts, images
56
- if (cleanPath.startsWith('/dist/') ||
57
- cleanPath.startsWith('/assets/') ||
58
- cleanPath.endsWith('.woff2') ||
59
- cleanPath.endsWith('.woff') ||
60
- cleanPath.endsWith('.png') ||
61
- cleanPath.endsWith('.webp') ||
62
- cleanPath.endsWith('.jpg') ||
63
- cleanPath.endsWith('.ico')) {
64
- return CACHE_LONG;
65
- }
66
-
67
- // HTML: allow bf-cache but revalidate
68
- if (cleanPath.endsWith('.html') || cleanPath === '/' || cleanPath === '/index.html') {
69
- return CACHE_REVALIDATE;
70
- }
71
-
72
- // SW and manifest need revalidate
73
- if (cleanPath.endsWith('sw.js') || cleanPath.endsWith('manifest.json')) {
74
- return CACHE_REVALIDATE;
75
- }
76
-
77
- return CACHE_SHORT;
78
- }
79
-
80
- function shouldCompress(path) {
81
- const cleanPath = path.split('?')[0];
82
- const ext = cleanPath.match(/\.[^.]+$/)?.[0] || '';
83
- return COMPRESSIBLE_TYPES.includes(ext);
84
- }
85
-
86
- function getPreloadLinks(path) {
87
- return PRELOAD_HINTS[path] || [];
88
- }
89
-
90
- const MAX_PORT_RETRIES = 10;
91
-
92
- function startServer(initialPort) {
93
- let port = initialPort;
94
-
95
- for (let i = 0; i < MAX_PORT_RETRIES; i++) {
96
- try {
97
- const server = Bun.serve({
98
- port: port,
99
- async fetch(req) {
100
- const url = new URL(req.url);
101
- let path = url.pathname;
102
-
103
- // ===== CACHE MANAGEMENT ENDPOINTS =====
104
-
105
- // Clear cache endpoint - sends headers to invalidate browser cache
106
- if (path === '/-/clear-cache') {
107
- return new Response(JSON.stringify({
108
- status: 'ok',
109
- message: 'Cache cleared. Reload the page with Ctrl+Shift+R',
110
- timestamp: new Date().toISOString()
111
- }), {
112
- headers: {
113
- 'Content-Type': 'application/json',
114
- 'Cache-Control': 'no-store, no-cache, must-revalidate',
115
- 'Clear-Site-Data': '"cache", "storage"',
116
- },
117
- });
118
- }
119
-
120
- // Health check
121
- if (path === '/-/health') {
122
- return new Response(JSON.stringify({ status: 'ok', port: server.port }), {
123
- headers: { 'Content-Type': 'application/json' },
124
- });
125
- }
126
-
127
- // Serve robots.txt inline (Lighthouse has issues with redirects)
128
- if (path === '/robots.txt') {
129
- const robotsTxt = `# robots.txt for microUI
130
- User-agent: *
131
- Allow: /
132
-
133
- # Sitemap
134
- Sitemap: https://microui.dev/sitemap.xml
135
- `;
136
- return new Response(robotsTxt, {
137
- headers: {
138
- 'Content-Type': 'text/plain; charset=utf-8',
139
- 'Cache-Control': 'public, max-age=86400',
140
- 'X-Robots-Tag': 'all',
141
- },
142
- });
143
- }
144
-
145
- // Default to demo/shell.html for root
146
- if (path === '/' || path === '/index.html') {
147
- path = '/demo/shell.html';
148
- }
149
-
150
- // Serve shell.html for App Shell pattern
151
- if (path === '/shell.html') {
152
- path = '/demo/shell.html';
153
- }
154
-
155
- // Serve content fragments for dynamic loading
156
- if (path.startsWith('/content/')) {
157
- path = '/demo' + path;
158
- }
159
-
160
- // Serve PWA assets from demo/
161
- if (path === '/sw.js' || path === '/manifest.json' ||
162
- path === '/favicon.ico' || path === '/favicon.png') {
163
- path = '/demo' + path;
164
- }
165
-
166
- // Security: prevent directory traversal
167
- if (path.includes('..')) {
168
- return new Response('Forbidden', { status: 403 });
169
- }
170
-
171
- const filePath = '.' + path;
172
- const file = Bun.file(filePath);
173
-
174
- if (await file.exists()) {
175
- const contentType = getContentType(path);
176
- const cacheControl = getCacheControl(path);
177
- const acceptEncoding = req.headers.get('accept-encoding') || '';
178
- const preloadLinks = getPreloadLinks(path);
179
-
180
- // Build headers
181
- const headers = {
182
- 'Content-Type': contentType,
183
- 'Cache-Control': cacheControl,
184
- 'X-Content-Type-Options': 'nosniff',
185
- // Enable bf-cache
186
- 'Vary': 'Accept-Encoding',
187
- };
188
-
189
- // Add Link preload headers for HTML
190
- if (preloadLinks.length > 0) {
191
- headers['Link'] = preloadLinks.join(', ');
192
- }
193
-
194
- // Brotli (priority) or Gzip compression for text assets
195
- if (shouldCompress(path)) {
196
- const content = await file.arrayBuffer();
197
- const rawData = Buffer.from(content);
198
-
199
- // Prefer Brotli (20-30% better compression than gzip)
200
- if (acceptEncoding.includes('br')) {
201
- try {
202
- const brotliCompressed = brotliCompressSync(rawData, {
203
- params: {
204
- [zlibConstants.BROTLI_PARAM_QUALITY]: 6, // Balance speed/compression
205
- }
206
- });
207
-
208
- return new Response(brotliCompressed, {
209
- headers: {
210
- ...headers,
211
- 'Content-Encoding': 'br',
212
- },
213
- });
214
- } catch {
215
- // Fallback to gzip if Brotli fails
216
- }
217
- }
218
-
219
- // Fallback to gzip
220
- if (acceptEncoding.includes('gzip')) {
221
- const compressed = Bun.gzipSync(new Uint8Array(content));
222
- return new Response(compressed, {
223
- headers: {
224
- ...headers,
225
- 'Content-Encoding': 'gzip',
226
- },
227
- });
228
- }
229
- }
230
-
231
- return new Response(file, { headers });
232
- }
233
-
234
- return new Response('Not Found', { status: 404 });
235
- },
236
- });
237
-
238
- console.log(`๐Ÿš€ microUI Dev Server running at http://localhost:${server.port}`);
239
- console.log(`๐Ÿ“ฆ Lighthouse-optimized: Cache-Control, Gzip, Link preload`);
240
- console.log(`๐Ÿงน Clear cache: http://localhost:${server.port}/-/clear-cache`);
241
- return server;
242
- } catch (e) {
243
- if (e.code === 'EADDRINUSE') {
244
- console.warn(`โš ๏ธ Port ${port} is busy, trying ${port + 1}...`);
245
- port++;
246
- } else {
247
- throw e;
248
- }
249
- }
250
- }
251
-
252
- console.error(`โŒ Failed to start server after ${MAX_PORT_RETRIES} attempts. Last port tried: ${port}`);
253
- process.exit(1);
254
- }
255
-
256
- startServer(PORT);
@@ -1,76 +0,0 @@
1
- import { describe, test, expect, beforeAll } from 'bun:test';
2
- import { parseHTML } from 'linkedom';
3
-
4
- // Mock Browser Environment
5
- const { document, customElements, HTMLElement, window } = parseHTML('<!DOCTYPE html><html><body></body></html>');
6
- globalThis.document = document;
7
- globalThis.customElements = customElements;
8
- globalThis.HTMLElement = HTMLElement;
9
- globalThis.window = window;
10
- globalThis.requestAnimationFrame = (cb) => cb();
11
-
12
- describe('Agent Integration Features', () => {
13
- let MuElement, MuInput, MuButton;
14
-
15
- beforeAll(async () => {
16
- // Load Core
17
- const core = await import('../../src/core/MuElement.js');
18
- MuElement = core.MuElement;
19
-
20
- // Load Components
21
- const inputModule = await import('../../src/components/mu-input.js');
22
- MuInput = inputModule.MuInput;
23
-
24
- const buttonModule = await import('../../src/components/mu-button.js');
25
- MuButton = buttonModule.MuButton;
26
- });
27
-
28
- test('should expose window.__MICROUI_ERRORS__', () => {
29
- // Create an element to trigger init
30
- const el = new MuInput();
31
- expect(Array.isArray(window.__MICROUI_ERRORS__)).toBe(true);
32
- });
33
-
34
- test('should expose window.microUIAgent helper', () => {
35
- expect(window.microUIAgent).toBeDefined();
36
- expect(typeof window.microUIAgent.reset).toBe('function');
37
- expect(typeof window.microUIAgent.getErrors).toBe('function');
38
- });
39
-
40
- test('should log error for invalid button variant', () => {
41
- window.microUIAgent.reset();
42
-
43
- const btn = document.createElement('mu-button');
44
- btn.setAttribute('variant', 'invalid-variant');
45
- document.body.appendChild(btn); // Render triggers updateClasses -> validation
46
-
47
- const errors = window.microUIAgent.getErrors();
48
- expect(errors.length).toBe(1);
49
- expect(errors[0].code).toBe('INVALID_VARIANT');
50
- expect(errors[0].component).toBe('mu-button');
51
- });
52
-
53
- test('should log error for missing input label', () => {
54
- window.microUIAgent.reset();
55
-
56
- const input = document.createElement('mu-input');
57
- // No label, no aria-label, no placeholder validation logic check?
58
- // Logic: if (!labelText && !ariaLabel) -> Error
59
- document.body.appendChild(input);
60
-
61
- const errors = window.microUIAgent.getErrors();
62
- expect(errors.length).toBe(1);
63
- expect(errors[0].code).toBe('A11Y_MISSING_LABEL');
64
- });
65
-
66
- test('should NOT log error if label is present', () => {
67
- window.microUIAgent.reset();
68
-
69
- const input = document.createElement('mu-input');
70
- input.setAttribute('label', 'Valid Label');
71
- document.body.appendChild(input);
72
-
73
- const errors = window.microUIAgent.getErrors();
74
- expect(errors.length).toBe(0);
75
- });
76
- });