microui-wc 0.1.0 → 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 (343) 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 +116 -116
  5. package/dist/README.md +21 -16
  6. package/dist/components.css +1 -1
  7. package/dist/microui.css +1 -1
  8. package/dist/microui.esm.js.map +1 -1
  9. package/dist/microui.min.js.map +1 -1
  10. package/dist/styles/components/switch.css +1 -1
  11. package/docs/getting-started.md +3 -3
  12. package/package.json +38 -10
  13. package/src/components/mu-schema-form.js +1 -1
  14. package/src/styles/components/switch.css +7 -8
  15. package/src/styles/components.css +6 -6
  16. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  17. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -33
  18. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  19. package/.github/workflows/ci.yml +0 -42
  20. package/.github/workflows/deploy-pages.yml +0 -112
  21. package/CODE_OF_CONDUCT.md +0 -59
  22. package/CONTRIBUTING.md +0 -156
  23. package/SECURITY.md +0 -58
  24. package/app/.generated/routes/alerts.js +0 -8
  25. package/app/.generated/routes/avatars.js +0 -8
  26. package/app/.generated/routes/badges.js +0 -8
  27. package/app/.generated/routes/buttons.js +0 -10
  28. package/app/.generated/routes/cards.js +0 -10
  29. package/app/.generated/routes/checkboxes.js +0 -9
  30. package/app/.generated/routes/chips.js +0 -8
  31. package/app/.generated/routes/dropdowns.js +0 -9
  32. package/app/.generated/routes/home.js +0 -7
  33. package/app/.generated/routes/icons.js +0 -9
  34. package/app/.generated/routes/inputs.js +0 -10
  35. package/app/.generated/routes/installation.js +0 -7
  36. package/app/.generated/routes/layout.js +0 -9
  37. package/app/.generated/routes/modals.js +0 -9
  38. package/app/.generated/routes/navbar.js +0 -7
  39. package/app/.generated/routes/progress.js +0 -9
  40. package/app/.generated/routes/radios.js +0 -9
  41. package/app/.generated/routes/switches.js +0 -9
  42. package/app/.generated/routes/tabs.js +0 -8
  43. package/app/.generated/routes/toasts.js +0 -9
  44. package/app/index.html +0 -67
  45. package/app/pages/alerts.html +0 -23
  46. package/app/pages/avatars.html +0 -22
  47. package/app/pages/badges.html +0 -22
  48. package/app/pages/buttons.html +0 -71
  49. package/app/pages/cards.html +0 -54
  50. package/app/pages/checkboxes.html +0 -39
  51. package/app/pages/chips.html +0 -23
  52. package/app/pages/dropdowns.html +0 -41
  53. package/app/pages/home.html +0 -59
  54. package/app/pages/icons.html +0 -29
  55. package/app/pages/inputs.html +0 -66
  56. package/app/pages/installation.html +0 -34
  57. package/app/pages/layout.html +0 -30
  58. package/app/pages/modals.html +0 -21
  59. package/app/pages/navbar.html +0 -22
  60. package/app/pages/progress.html +0 -35
  61. package/app/pages/radios.html +0 -40
  62. package/app/pages/switches.html +0 -39
  63. package/app/pages/tabs.html +0 -30
  64. package/app/pages/toasts.html +0 -22
  65. package/app-dist/index.html +0 -67
  66. package/app-dist/pages/alerts.html +0 -23
  67. package/app-dist/pages/avatars.html +0 -22
  68. package/app-dist/pages/badges.html +0 -22
  69. package/app-dist/pages/buttons.html +0 -71
  70. package/app-dist/pages/cards.html +0 -54
  71. package/app-dist/pages/checkboxes.html +0 -39
  72. package/app-dist/pages/chips.html +0 -23
  73. package/app-dist/pages/dropdowns.html +0 -41
  74. package/app-dist/pages/home.html +0 -59
  75. package/app-dist/pages/icons.html +0 -29
  76. package/app-dist/pages/inputs.html +0 -66
  77. package/app-dist/pages/installation.html +0 -34
  78. package/app-dist/pages/layout.html +0 -30
  79. package/app-dist/pages/modals.html +0 -21
  80. package/app-dist/pages/navbar.html +0 -22
  81. package/app-dist/pages/progress.html +0 -35
  82. package/app-dist/pages/radios.html +0 -40
  83. package/app-dist/pages/switches.html +0 -39
  84. package/app-dist/pages/tabs.html +0 -30
  85. package/app-dist/pages/toasts.html +0 -22
  86. package/app-dist/pages.json +0 -217
  87. package/app-dist/routes/alerts.js +0 -5
  88. package/app-dist/routes/avatars.js +0 -1
  89. package/app-dist/routes/badges.js +0 -1
  90. package/app-dist/routes/buttons.js +0 -1
  91. package/app-dist/routes/cards.js +0 -1
  92. package/app-dist/routes/checkboxes.js +0 -9
  93. package/app-dist/routes/chips.js +0 -4
  94. package/app-dist/routes/chunk-019e5e2f.js +0 -5
  95. package/app-dist/routes/chunk-0m4j19yd.js +0 -2
  96. package/app-dist/routes/chunk-0tmmp5q0.js +0 -1
  97. package/app-dist/routes/chunk-10xn709r.js +0 -1
  98. package/app-dist/routes/chunk-15m2qcda.js +0 -2
  99. package/app-dist/routes/chunk-1bh8g23n.js +0 -1
  100. package/app-dist/routes/chunk-1vg0v937.js +0 -1
  101. package/app-dist/routes/chunk-1zvcgy3j.js +0 -1
  102. package/app-dist/routes/chunk-2afb0861.js +0 -1
  103. package/app-dist/routes/chunk-2c6ttpzt.js +0 -5
  104. package/app-dist/routes/chunk-3dy30fhs.js +0 -1
  105. package/app-dist/routes/chunk-426dnces.js +0 -13
  106. package/app-dist/routes/chunk-44kgxery.js +0 -1
  107. package/app-dist/routes/chunk-47fdnejd.js +0 -33
  108. package/app-dist/routes/chunk-49a6t2vq.js +0 -1
  109. package/app-dist/routes/chunk-4fe1rm5b.js +0 -1
  110. package/app-dist/routes/chunk-4ggmvkta.js +0 -33
  111. package/app-dist/routes/chunk-4vkz81q7.js +0 -33
  112. package/app-dist/routes/chunk-4w4tmj8f.js +0 -31
  113. package/app-dist/routes/chunk-532s62kr.js +0 -31
  114. package/app-dist/routes/chunk-5hm3bssy.js +0 -33
  115. package/app-dist/routes/chunk-5vrh24hc.js +0 -1
  116. package/app-dist/routes/chunk-61pcg25a.js +0 -1
  117. package/app-dist/routes/chunk-6nfhygvf.js +0 -1
  118. package/app-dist/routes/chunk-700e7je6.js +0 -33
  119. package/app-dist/routes/chunk-7fsn17kg.js +0 -1
  120. package/app-dist/routes/chunk-7k789b32.js +0 -1
  121. package/app-dist/routes/chunk-7r46q0ys.js +0 -36
  122. package/app-dist/routes/chunk-86fmc1fr.js +0 -5
  123. package/app-dist/routes/chunk-8qth37vw.js +0 -1
  124. package/app-dist/routes/chunk-924wv8n0.js +0 -1
  125. package/app-dist/routes/chunk-9mbhgxk9.js +0 -1
  126. package/app-dist/routes/chunk-a216hyd9.js +0 -1
  127. package/app-dist/routes/chunk-akzxykh9.js +0 -33
  128. package/app-dist/routes/chunk-b3dcvy8c.js +0 -1
  129. package/app-dist/routes/chunk-b74zahz5.js +0 -31
  130. package/app-dist/routes/chunk-bftj53p2.js +0 -5
  131. package/app-dist/routes/chunk-c01hnz3e.js +0 -1
  132. package/app-dist/routes/chunk-d8pvv5km.js +0 -1
  133. package/app-dist/routes/chunk-dev0aezr.js +0 -2
  134. package/app-dist/routes/chunk-dh6vnv0e.js +0 -1
  135. package/app-dist/routes/chunk-dn2cbpva.js +0 -36
  136. package/app-dist/routes/chunk-dvn0my90.js +0 -1
  137. package/app-dist/routes/chunk-dvq8mnve.js +0 -36
  138. package/app-dist/routes/chunk-e8c2gc4d.js +0 -5
  139. package/app-dist/routes/chunk-ejf9ak2x.js +0 -1
  140. package/app-dist/routes/chunk-f083m55s.js +0 -1
  141. package/app-dist/routes/chunk-fnrj28s1.js +0 -31
  142. package/app-dist/routes/chunk-fvg3yjdp.js +0 -31
  143. package/app-dist/routes/chunk-g7k381n1.js +0 -1
  144. package/app-dist/routes/chunk-h01kq2ae.js +0 -13
  145. package/app-dist/routes/chunk-h4dk761v.js +0 -5
  146. package/app-dist/routes/chunk-hmx91z2x.js +0 -5
  147. package/app-dist/routes/chunk-hxbg4m42.js +0 -36
  148. package/app-dist/routes/chunk-jbjnfp2b.js +0 -2
  149. package/app-dist/routes/chunk-jxtz5vv6.js +0 -36
  150. package/app-dist/routes/chunk-jxzcs0ey.js +0 -36
  151. package/app-dist/routes/chunk-kt7wwhcx.js +0 -1
  152. package/app-dist/routes/chunk-kzptszyc.js +0 -33
  153. package/app-dist/routes/chunk-mhgca4w4.js +0 -2
  154. package/app-dist/routes/chunk-mhswxa20.js +0 -1
  155. package/app-dist/routes/chunk-n8zfeex6.js +0 -1
  156. package/app-dist/routes/chunk-pee47b2r.js +0 -1
  157. package/app-dist/routes/chunk-pesmw829.js +0 -1
  158. package/app-dist/routes/chunk-pgc4c6f3.js +0 -36
  159. package/app-dist/routes/chunk-q8egegm1.js +0 -1
  160. package/app-dist/routes/chunk-q9mn2qyq.js +0 -36
  161. package/app-dist/routes/chunk-qh0rtaf3.js +0 -5
  162. package/app-dist/routes/chunk-qqhmk6ye.js +0 -2
  163. package/app-dist/routes/chunk-qrxygmf7.js +0 -33
  164. package/app-dist/routes/chunk-r46yzksx.js +0 -36
  165. package/app-dist/routes/chunk-rgpbw2w0.js +0 -5
  166. package/app-dist/routes/chunk-rnpzv3d8.js +0 -2
  167. package/app-dist/routes/chunk-s5v8cv05.js +0 -2
  168. package/app-dist/routes/chunk-sbwn5bpc.js +0 -1
  169. package/app-dist/routes/chunk-sqbg8jbt.js +0 -33
  170. package/app-dist/routes/chunk-sv8dqnf7.js +0 -1
  171. package/app-dist/routes/chunk-t67sw3za.js +0 -1
  172. package/app-dist/routes/chunk-tjdpqwdf.js +0 -31
  173. package/app-dist/routes/chunk-tq2mfghg.js +0 -1
  174. package/app-dist/routes/chunk-ttn10vt6.js +0 -1
  175. package/app-dist/routes/chunk-v2hzpjxr.js +0 -1
  176. package/app-dist/routes/chunk-wfjjkw9y.js +0 -1
  177. package/app-dist/routes/chunk-wt8cxzmf.js +0 -31
  178. package/app-dist/routes/chunk-x45d372k.js +0 -5
  179. package/app-dist/routes/chunk-y3wsazkt.js +0 -1
  180. package/app-dist/routes/chunk-y7pmgc7t.js +0 -33
  181. package/app-dist/routes/chunk-zefdt2q3.js +0 -31
  182. package/app-dist/routes/dropdowns.js +0 -6
  183. package/app-dist/routes/home.js +0 -1
  184. package/app-dist/routes/icons.js +0 -1
  185. package/app-dist/routes/inputs.js +0 -12
  186. package/app-dist/routes/installation.js +0 -1
  187. package/app-dist/routes/layout.js +0 -1
  188. package/app-dist/routes/modals.js +0 -7
  189. package/app-dist/routes/navbar.js +0 -1
  190. package/app-dist/routes/progress.js +0 -1
  191. package/app-dist/routes/radios.js +0 -6
  192. package/app-dist/routes/switches.js +0 -6
  193. package/app-dist/routes/tabs.js +0 -1
  194. package/app-dist/routes/toasts.js +0 -16
  195. package/assets/fonts/material-symbols-mini.woff2 +0 -0
  196. package/assets/fonts/material-symbols.woff2 +0 -0
  197. package/assets/fonts/roboto-400.woff2 +0 -0
  198. package/assets/fonts/roboto-500.woff2 +0 -0
  199. package/assets/fonts/roboto-700.woff2 +0 -0
  200. package/assets/logo-banner-400.jpg +0 -0
  201. package/assets/logo-banner-400.webp +0 -0
  202. package/assets/logo-banner-800.webp +0 -0
  203. package/assets/logo-banner.jpg +0 -0
  204. package/assets/logo-icon-64.jpg +0 -0
  205. package/assets/logo-icon-64.webp +0 -0
  206. package/assets/logo-icon.jpg +0 -0
  207. package/assets/logo-square.jpg +0 -0
  208. package/bun.lock +0 -312
  209. package/bunfig.toml +0 -4
  210. package/custom-elements.json +0 -1916
  211. package/demo/api/sample-data.json +0 -38
  212. package/demo/content/alerts.html +0 -115
  213. package/demo/content/avatars.html +0 -70
  214. package/demo/content/badges.html +0 -65
  215. package/demo/content/buttons.html +0 -188
  216. package/demo/content/callouts.html +0 -91
  217. package/demo/content/cards.html +0 -121
  218. package/demo/content/checkboxes.html +0 -178
  219. package/demo/content/chips.html +0 -67
  220. package/demo/content/codeblocks.html +0 -101
  221. package/demo/content/confirms.html +0 -115
  222. package/demo/content/datatables.html +0 -149
  223. package/demo/content/dividers.html +0 -119
  224. package/demo/content/dropdowns.html +0 -89
  225. package/demo/content/enterprise.html +0 -252
  226. package/demo/content/home.html +0 -149
  227. package/demo/content/icons.html +0 -89
  228. package/demo/content/inputs.html +0 -135
  229. package/demo/content/installation.html +0 -16
  230. package/demo/content/layout.html +0 -136
  231. package/demo/content/modals.html +0 -141
  232. package/demo/content/navbar.html +0 -70
  233. package/demo/content/progress.html +0 -119
  234. package/demo/content/radios.html +0 -88
  235. package/demo/content/skeletons.html +0 -109
  236. package/demo/content/spinners.html +0 -96
  237. package/demo/content/switches.html +0 -84
  238. package/demo/content/tables.html +0 -124
  239. package/demo/content/tabs.html +0 -85
  240. package/demo/content/toasts.html +0 -116
  241. package/demo/content/tooltips.html +0 -107
  242. package/demo/content/virtual-lists.html +0 -233
  243. package/demo/favicon.ico +0 -0
  244. package/demo/favicon.png +0 -0
  245. package/demo/full.html +0 -52
  246. package/demo/iife.html +0 -46
  247. package/demo/manifest.json +0 -34
  248. package/demo/pages/datatable-demo.html +0 -237
  249. package/demo/pages/prompt-ui-demo.html +0 -218
  250. package/demo/pages/responsive-demo.html +0 -122
  251. package/demo/pages/schema-form-demo.html +0 -270
  252. package/demo/robots.txt +0 -6
  253. package/demo/shell.html +0 -712
  254. package/demo/sw.js +0 -387
  255. package/lighthouse-audit.mjs +0 -113
  256. package/scripts/analyze-components.js +0 -105
  257. package/scripts/build-app.js +0 -193
  258. package/scripts/build-framework.js +0 -444
  259. package/scripts/build-utils.js +0 -101
  260. package/scripts/test-isolated.js +0 -151
  261. package/server.js +0 -256
  262. package/tests/agents/agent-integration.test.js +0 -76
  263. package/tests/benchmark.html +0 -296
  264. package/tests/build/scan-components.test.js +0 -173
  265. package/tests/components/all-components.test.js +0 -245
  266. package/tests/components/all-missing-components.test.js +0 -574
  267. package/tests/components/mu-alert.test.js +0 -113
  268. package/tests/components/mu-avatar.test.js +0 -148
  269. package/tests/components/mu-badge.test.js +0 -92
  270. package/tests/components/mu-button.test.js +0 -112
  271. package/tests/components/mu-card.test.js +0 -89
  272. package/tests/components/mu-checkbox.test.js +0 -158
  273. package/tests/components/mu-chip.test.js +0 -118
  274. package/tests/components/mu-container.test.js +0 -120
  275. package/tests/components/mu-divider.test.js +0 -98
  276. package/tests/components/mu-drawer-item.test.js +0 -199
  277. package/tests/components/mu-drawer.test.js +0 -96
  278. package/tests/components/mu-dropdown.test.js +0 -125
  279. package/tests/components/mu-form.test.js +0 -138
  280. package/tests/components/mu-grid.test.js +0 -135
  281. package/tests/components/mu-icon.test.js +0 -110
  282. package/tests/components/mu-input.test.js +0 -131
  283. package/tests/components/mu-lazy.test.js +0 -103
  284. package/tests/components/mu-modal.test.js +0 -275
  285. package/tests/components/mu-navbar.test.js +0 -101
  286. package/tests/components/mu-progress.test.js +0 -115
  287. package/tests/components/mu-radio.test.js +0 -114
  288. package/tests/components/mu-repeat.test.js +0 -106
  289. package/tests/components/mu-sidebar.test.js +0 -126
  290. package/tests/components/mu-skeleton.test.js +0 -162
  291. package/tests/components/mu-stack.test.js +0 -143
  292. package/tests/components/mu-switch.test.js +0 -292
  293. package/tests/components/mu-table.test.js +0 -124
  294. package/tests/components/mu-tabs.test.js +0 -104
  295. package/tests/components/mu-textarea.test.js +0 -115
  296. package/tests/components/mu-toast.test.js +0 -321
  297. package/tests/components/mu-tooltip.test.js +0 -133
  298. package/tests/components/mu-virtual-list.test.js +0 -109
  299. package/tests/core/MuElement.test.js +0 -120
  300. package/tests/core/agent-api.test.js +0 -125
  301. package/tests/core/all-core-modules.test.js +0 -442
  302. package/tests/core/bus.test.js +0 -364
  303. package/tests/core/component-schema.test.js +0 -160
  304. package/tests/core/feature-registry.test.js +0 -198
  305. package/tests/core/form-state.test.js +0 -167
  306. package/tests/core/http.test.js +0 -119
  307. package/tests/core/keyboard.test.js +0 -319
  308. package/tests/core/layers.test.js +0 -129
  309. package/tests/core/namespaced-stores.test.js +0 -114
  310. package/tests/core/render.test.js +0 -121
  311. package/tests/core/ripple.test.js +0 -131
  312. package/tests/core/router.test.js +0 -89
  313. package/tests/core/scheduler.test.js +0 -121
  314. package/tests/core/signals.test.js +0 -128
  315. package/tests/core/store.test.js +0 -171
  316. package/tests/core/transitions.test.js +0 -82
  317. package/tests/e2e/accessibility-harness.html +0 -58
  318. package/tests/e2e/accessibility.test.js +0 -401
  319. package/tests/e2e/agent-features.test.js +0 -372
  320. package/tests/e2e/card-spacing.test.js +0 -287
  321. package/tests/e2e/components.test.js +0 -439
  322. package/tests/e2e/demo-routes.test.js +0 -478
  323. package/tests/e2e/layout-css-fallback.test.js +0 -334
  324. package/tests/e2e/mu-alert.e2e.test.js +0 -111
  325. package/tests/e2e/mu-checkbox.test.js +0 -489
  326. package/tests/e2e/mu-chip.test.js +0 -347
  327. package/tests/e2e/mu-form.test.js +0 -499
  328. package/tests/e2e/mu-icon.test.js +0 -114
  329. package/tests/e2e/mu-radio.test.js +0 -113
  330. package/tests/e2e/mu-skeleton.test.js +0 -140
  331. package/tests/e2e/mu-switch.test.js +0 -415
  332. package/tests/e2e/mu-tabs.test.js +0 -494
  333. package/tests/e2e/mu-textarea.test.js +0 -242
  334. package/tests/e2e/mu-virtual-list.test.js +0 -427
  335. package/tests/e2e/perf-memory.test.js +0 -161
  336. package/tests/e2e/puppeteer-helper.js +0 -137
  337. package/tests/e2e/puppeteer.test.js +0 -226
  338. package/tests/e2e/pwa.test.js +0 -261
  339. package/tests/e2e/test-harness.html +0 -319
  340. package/tests/manual/test-components.html +0 -120
  341. package/tests/memory-test.html +0 -309
  342. package/tests/setup-dom.js +0 -93
  343. package/tests/visual-test.html +0 -301
@@ -1,319 +0,0 @@
1
- /**
2
- * @fileoverview Unit tests for core/keyboard.js
3
- * Tests the centralized ESC Key Handler Stack
4
- */
5
-
6
- import { describe, expect, it, beforeEach, afterEach, mock } from 'bun:test';
7
- import { keyboard, KeyboardManager } from '../../src/core/keyboard.js';
8
-
9
- // Polyfill KeyboardEvent for happy-dom
10
- if (typeof globalThis.KeyboardEvent === 'undefined') {
11
- globalThis.KeyboardEvent = class KeyboardEvent extends Event {
12
- constructor(type, init = {}) {
13
- super(type, init);
14
- this.key = init.key || '';
15
- this.code = init.code || '';
16
- this.ctrlKey = init.ctrlKey || false;
17
- this.shiftKey = init.shiftKey || false;
18
- this.altKey = init.altKey || false;
19
- this.metaKey = init.metaKey || false;
20
- }
21
- };
22
- }
23
-
24
- describe('KeyboardManager Singleton', () => {
25
- it('should export keyboard singleton', () => {
26
- expect(keyboard).toBeDefined();
27
- expect(keyboard).toBeInstanceOf(KeyboardManager);
28
- });
29
-
30
- it('should export KeyboardManager class', () => {
31
- expect(KeyboardManager).toBeDefined();
32
- expect(typeof KeyboardManager).toBe('function');
33
- });
34
- });
35
-
36
- describe('KeyboardManager.pushEscapeHandler', () => {
37
- let unsubscribers = [];
38
-
39
- afterEach(() => {
40
- // Clean up all handlers after each test
41
- unsubscribers.forEach(unsub => unsub?.());
42
- unsubscribers = [];
43
- });
44
-
45
- it('should be a function', () => {
46
- expect(typeof keyboard.pushEscapeHandler).toBe('function');
47
- });
48
-
49
- it('should return an unsubscribe function', () => {
50
- const element = document.createElement('div');
51
- const callback = mock(() => { });
52
-
53
- const unsub = keyboard.pushEscapeHandler(element, callback);
54
- unsubscribers.push(unsub);
55
-
56
- expect(typeof unsub).toBe('function');
57
- });
58
-
59
- it('should increase stack depth when handler is added', () => {
60
- const initialDepth = keyboard.stackDepth;
61
-
62
- const element = document.createElement('div');
63
- const callback = mock(() => { });
64
- const unsub = keyboard.pushEscapeHandler(element, callback);
65
- unsubscribers.push(unsub);
66
-
67
- expect(keyboard.stackDepth).toBe(initialDepth + 1);
68
- });
69
-
70
- it('should decrease stack depth when unsubscribed', () => {
71
- const element = document.createElement('div');
72
- const callback = mock(() => { });
73
-
74
- const unsub = keyboard.pushEscapeHandler(element, callback);
75
- const depthAfterAdd = keyboard.stackDepth;
76
-
77
- unsub();
78
-
79
- expect(keyboard.stackDepth).toBe(depthAfterAdd - 1);
80
- });
81
-
82
- // NOTE: Event dispatching tests are skipped in unit tests due to linkedom limitations
83
- // ESC key behavior is verified in E2E tests (tests/e2e/)
84
- it.skip('should call topmost handler on ESC key (E2E only)', () => {
85
- const element = document.createElement('div');
86
- const callback = mock(() => { });
87
-
88
- const unsub = keyboard.pushEscapeHandler(element, callback);
89
- unsubscribers.push(unsub);
90
-
91
- // Simulate ESC key press
92
- const event = new KeyboardEvent('keydown', { key: 'Escape' });
93
- document.dispatchEvent(event);
94
-
95
- expect(callback).toHaveBeenCalled();
96
- });
97
-
98
- it.skip('should only call topmost handler in stack (LIFO) (E2E only)', () => {
99
- const element1 = document.createElement('div');
100
- const element2 = document.createElement('div');
101
- const callback1 = mock(() => { });
102
- const callback2 = mock(() => { });
103
-
104
- const unsub1 = keyboard.pushEscapeHandler(element1, callback1);
105
- const unsub2 = keyboard.pushEscapeHandler(element2, callback2);
106
- unsubscribers.push(unsub1, unsub2);
107
-
108
- // Simulate ESC key press
109
- const event = new KeyboardEvent('keydown', { key: 'Escape' });
110
- document.dispatchEvent(event);
111
-
112
- // Only the second (topmost) handler should be called
113
- expect(callback2).toHaveBeenCalled();
114
- expect(callback1).not.toHaveBeenCalled();
115
- });
116
-
117
- it.skip('should call next handler after topmost is removed (E2E only)', () => {
118
- const element1 = document.createElement('div');
119
- const element2 = document.createElement('div');
120
- const callback1 = mock(() => { });
121
- const callback2 = mock(() => { });
122
-
123
- const unsub1 = keyboard.pushEscapeHandler(element1, callback1);
124
- const unsub2 = keyboard.pushEscapeHandler(element2, callback2);
125
- unsubscribers.push(unsub1);
126
-
127
- // Remove the topmost handler
128
- unsub2();
129
-
130
- // Simulate ESC key press
131
- const event = new KeyboardEvent('keydown', { key: 'Escape' });
132
- document.dispatchEvent(event);
133
-
134
- // Now the first handler should be called
135
- expect(callback1).toHaveBeenCalled();
136
- });
137
-
138
- it.skip('should not call handler for other keys (E2E only)', () => {
139
- const element = document.createElement('div');
140
- const callback = mock(() => { });
141
-
142
- const unsub = keyboard.pushEscapeHandler(element, callback);
143
- unsubscribers.push(unsub);
144
-
145
- // Simulate Enter key press
146
- const event = new KeyboardEvent('keydown', { key: 'Enter' });
147
- document.dispatchEvent(event);
148
-
149
- expect(callback).not.toHaveBeenCalled();
150
- });
151
-
152
- it('should handle unsubscribe being called multiple times', () => {
153
- const element = document.createElement('div');
154
- const callback = mock(() => { });
155
-
156
- const unsub = keyboard.pushEscapeHandler(element, callback);
157
- const depthBefore = keyboard.stackDepth;
158
-
159
- // Call unsubscribe multiple times
160
- unsub();
161
- unsub();
162
- unsub();
163
-
164
- // Stack depth should only decrease once
165
- expect(keyboard.stackDepth).toBe(depthBefore - 1);
166
- });
167
- });
168
-
169
- describe('KeyboardManager.isTopmost', () => {
170
- let unsubscribers = [];
171
-
172
- afterEach(() => {
173
- unsubscribers.forEach(unsub => unsub?.());
174
- unsubscribers = [];
175
- });
176
-
177
- it('should be a function', () => {
178
- expect(typeof keyboard.isTopmost).toBe('function');
179
- });
180
-
181
- it('should return false when stack is empty', () => {
182
- // Clear stack first
183
- const element = document.createElement('div');
184
- expect(keyboard.isTopmost(element)).toBe(false);
185
- });
186
-
187
- it('should return true for topmost element', () => {
188
- const element1 = document.createElement('div');
189
- const element2 = document.createElement('div');
190
-
191
- const unsub1 = keyboard.pushEscapeHandler(element1, () => { });
192
- const unsub2 = keyboard.pushEscapeHandler(element2, () => { });
193
- unsubscribers.push(unsub1, unsub2);
194
-
195
- expect(keyboard.isTopmost(element2)).toBe(true);
196
- expect(keyboard.isTopmost(element1)).toBe(false);
197
- });
198
-
199
- it('should update after handler is removed', () => {
200
- const element1 = document.createElement('div');
201
- const element2 = document.createElement('div');
202
-
203
- const unsub1 = keyboard.pushEscapeHandler(element1, () => { });
204
- const unsub2 = keyboard.pushEscapeHandler(element2, () => { });
205
- unsubscribers.push(unsub1);
206
-
207
- // Remove topmost
208
- unsub2();
209
-
210
- expect(keyboard.isTopmost(element1)).toBe(true);
211
- });
212
- });
213
-
214
- describe('KeyboardManager.stackDepth', () => {
215
- let unsubscribers = [];
216
-
217
- afterEach(() => {
218
- unsubscribers.forEach(unsub => unsub?.());
219
- unsubscribers = [];
220
- });
221
-
222
- it('should be a number', () => {
223
- expect(typeof keyboard.stackDepth).toBe('number');
224
- });
225
-
226
- it('should start at 0 or greater', () => {
227
- expect(keyboard.stackDepth).toBeGreaterThanOrEqual(0);
228
- });
229
-
230
- it('should track multiple handlers correctly', () => {
231
- const initialDepth = keyboard.stackDepth;
232
-
233
- const unsub1 = keyboard.pushEscapeHandler(document.createElement('div'), () => { });
234
- const unsub2 = keyboard.pushEscapeHandler(document.createElement('div'), () => { });
235
- const unsub3 = keyboard.pushEscapeHandler(document.createElement('div'), () => { });
236
- unsubscribers.push(unsub1, unsub2, unsub3);
237
-
238
- expect(keyboard.stackDepth).toBe(initialDepth + 3);
239
- });
240
- });
241
-
242
- describe('KeyboardManager Event Handling', () => {
243
- let unsubscribers = [];
244
-
245
- afterEach(() => {
246
- unsubscribers.forEach(unsub => unsub?.());
247
- unsubscribers = [];
248
- });
249
-
250
- it.skip('should prevent default on ESC when handlers exist (E2E only)', () => {
251
- const element = document.createElement('div');
252
- const callback = mock(() => { });
253
-
254
- const unsub = keyboard.pushEscapeHandler(element, callback);
255
- unsubscribers.push(unsub);
256
-
257
- const event = new KeyboardEvent('keydown', { key: 'Escape', cancelable: true });
258
- const preventDefaultSpy = mock(() => { });
259
- event.preventDefault = preventDefaultSpy;
260
-
261
- document.dispatchEvent(event);
262
-
263
- expect(preventDefaultSpy).toHaveBeenCalled();
264
- });
265
-
266
- it.skip('should stop propagation on ESC when handlers exist (E2E only)', () => {
267
- const element = document.createElement('div');
268
- const callback = mock(() => { });
269
-
270
- const unsub = keyboard.pushEscapeHandler(element, callback);
271
- unsubscribers.push(unsub);
272
-
273
- const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
274
- const stopPropagationSpy = mock(() => { });
275
- event.stopPropagation = stopPropagationSpy;
276
-
277
- document.dispatchEvent(event);
278
-
279
- expect(stopPropagationSpy).toHaveBeenCalled();
280
- });
281
- });
282
-
283
- describe('KeyboardManager Edge Cases', () => {
284
- it.skip('should handle empty callback gracefully (E2E only)', () => {
285
- const element = document.createElement('div');
286
- const unsub = keyboard.pushEscapeHandler(element, () => { });
287
-
288
- // Should not throw
289
- const event = new KeyboardEvent('keydown', { key: 'Escape' });
290
- expect(() => document.dispatchEvent(event)).not.toThrow();
291
-
292
- unsub();
293
- });
294
-
295
- it.skip('should preserve order after middle element is removed (E2E only)', () => {
296
- const element1 = document.createElement('div');
297
- const element2 = document.createElement('div');
298
- const element3 = document.createElement('div');
299
- const callback1 = mock(() => { });
300
- const callback3 = mock(() => { });
301
-
302
- const unsub1 = keyboard.pushEscapeHandler(element1, callback1);
303
- const unsub2 = keyboard.pushEscapeHandler(element2, () => { });
304
- const unsub3 = keyboard.pushEscapeHandler(element3, callback3);
305
-
306
- // Remove middle element
307
- unsub2();
308
-
309
- // Send ESC - should call callback3 (still topmost)
310
- const event = new KeyboardEvent('keydown', { key: 'Escape' });
311
- document.dispatchEvent(event);
312
-
313
- expect(callback3).toHaveBeenCalled();
314
- expect(callback1).not.toHaveBeenCalled();
315
-
316
- unsub1();
317
- unsub3();
318
- });
319
- });
@@ -1,129 +0,0 @@
1
- /**
2
- * @fileoverview Unit tests for core/layers.js
3
- * Tests the centralized Z-Index Layer System
4
- */
5
-
6
- import { describe, expect, it, beforeEach } from 'bun:test';
7
- import { Z_INDEX, injectLayerTokens } from '../../src/core/layers.js';
8
-
9
- describe('Z_INDEX Constants', () => {
10
- it('should export Z_INDEX object', () => {
11
- expect(Z_INDEX).toBeDefined();
12
- expect(typeof Z_INDEX).toBe('object');
13
- });
14
-
15
- it('should have all required layer levels', () => {
16
- expect(Z_INDEX.base).toBeDefined();
17
- expect(Z_INDEX.sticky).toBeDefined();
18
- expect(Z_INDEX.dropdown).toBeDefined();
19
- expect(Z_INDEX.drawer).toBeDefined();
20
- expect(Z_INDEX.modal).toBeDefined();
21
- expect(Z_INDEX.toast).toBeDefined();
22
- expect(Z_INDEX.tooltip).toBeDefined();
23
- expect(Z_INDEX.overlay).toBeDefined();
24
- expect(Z_INDEX.devtools).toBeDefined();
25
- });
26
-
27
- it('should have correct numerical values', () => {
28
- expect(Z_INDEX.base).toBe(1);
29
- expect(Z_INDEX.sticky).toBe(100);
30
- expect(Z_INDEX.dropdown).toBe(1000);
31
- expect(Z_INDEX.drawer).toBe(1100);
32
- expect(Z_INDEX.modal).toBe(1200);
33
- expect(Z_INDEX.toast).toBe(1300);
34
- expect(Z_INDEX.tooltip).toBe(1400);
35
- expect(Z_INDEX.overlay).toBe(9999);
36
- expect(Z_INDEX.devtools).toBe(999999);
37
- });
38
-
39
- it('should have layers in ascending order', () => {
40
- expect(Z_INDEX.base).toBeLessThan(Z_INDEX.sticky);
41
- expect(Z_INDEX.sticky).toBeLessThan(Z_INDEX.dropdown);
42
- expect(Z_INDEX.dropdown).toBeLessThan(Z_INDEX.drawer);
43
- expect(Z_INDEX.drawer).toBeLessThan(Z_INDEX.modal);
44
- expect(Z_INDEX.modal).toBeLessThan(Z_INDEX.toast);
45
- expect(Z_INDEX.toast).toBeLessThan(Z_INDEX.tooltip);
46
- expect(Z_INDEX.tooltip).toBeLessThan(Z_INDEX.overlay);
47
- expect(Z_INDEX.overlay).toBeLessThan(Z_INDEX.devtools);
48
- });
49
-
50
- it('should be frozen (immutable)', () => {
51
- expect(Object.isFrozen(Z_INDEX)).toBe(true);
52
- });
53
-
54
- it('should not allow modifications', () => {
55
- // Attempt to modify should fail silently in strict mode
56
- const originalValue = Z_INDEX.modal;
57
- try {
58
- // @ts-ignore - intentionally testing immutability
59
- Z_INDEX.modal = 999;
60
- } catch (e) {
61
- // Expected in strict mode
62
- }
63
- expect(Z_INDEX.modal).toBe(originalValue);
64
- });
65
- });
66
-
67
- describe('injectLayerTokens', () => {
68
- beforeEach(() => {
69
- // Remove any existing layer tokens style element
70
- const existing = document.getElementById('mu-layer-tokens');
71
- if (existing) {
72
- existing.remove();
73
- }
74
- });
75
-
76
- it('should be a function', () => {
77
- expect(typeof injectLayerTokens).toBe('function');
78
- });
79
-
80
- it('should inject style element into document head', () => {
81
- injectLayerTokens();
82
- const styleEl = document.getElementById('mu-layer-tokens');
83
- expect(styleEl).toBeDefined();
84
- expect(styleEl?.tagName.toLowerCase()).toBe('style');
85
- });
86
-
87
- it('should be idempotent (only inject once)', () => {
88
- injectLayerTokens();
89
- injectLayerTokens();
90
- injectLayerTokens();
91
-
92
- const elements = document.querySelectorAll('#mu-layer-tokens');
93
- expect(elements.length).toBe(1);
94
- });
95
-
96
- it('should inject CSS custom properties for all layers', () => {
97
- injectLayerTokens();
98
- const styleEl = document.getElementById('mu-layer-tokens');
99
- const content = styleEl?.textContent || '';
100
-
101
- expect(content).toContain('--z-base');
102
- expect(content).toContain('--z-sticky');
103
- expect(content).toContain('--z-dropdown');
104
- expect(content).toContain('--z-drawer');
105
- expect(content).toContain('--z-modal');
106
- expect(content).toContain('--z-toast');
107
- expect(content).toContain('--z-tooltip');
108
- expect(content).toContain('--z-overlay');
109
- expect(content).toContain('--z-devtools');
110
- });
111
-
112
- it('should inject correct values in CSS', () => {
113
- injectLayerTokens();
114
- const styleEl = document.getElementById('mu-layer-tokens');
115
- const content = styleEl?.textContent || '';
116
-
117
- expect(content).toContain('--z-base: 1');
118
- expect(content).toContain('--z-modal: 1200');
119
- expect(content).toContain('--z-overlay: 9999');
120
- });
121
-
122
- it('should inject into :root selector', () => {
123
- injectLayerTokens();
124
- const styleEl = document.getElementById('mu-layer-tokens');
125
- const content = styleEl?.textContent || '';
126
-
127
- expect(content).toContain(':root');
128
- });
129
- });
@@ -1,114 +0,0 @@
1
- /**
2
- * @fileoverview Tests for Namespaced Stores (Enterprise Features)
3
- * Tests createNamespacedStore, getStore, getAllStores, captureAppState, restoreAppState
4
- */
5
-
6
- import { describe, test, expect } from 'bun:test';
7
-
8
- describe('Namespaced Stores', () => {
9
- describe('Module Exports', () => {
10
- test('should export createNamespacedStore function', async () => {
11
- const module = await import('../../src/core/store.js');
12
- expect(typeof module.createNamespacedStore).toBe('function');
13
- });
14
-
15
- test('should export getStore function', async () => {
16
- const module = await import('../../src/core/store.js');
17
- expect(typeof module.getStore).toBe('function');
18
- });
19
-
20
- test('should export getAllStores function', async () => {
21
- const module = await import('../../src/core/store.js');
22
- expect(typeof module.getAllStores).toBe('function');
23
- });
24
-
25
- test('should export captureAppState function', async () => {
26
- const module = await import('../../src/core/store.js');
27
- expect(typeof module.captureAppState).toBe('function');
28
- });
29
-
30
- test('should export restoreAppState function', async () => {
31
- const module = await import('../../src/core/store.js');
32
- expect(typeof module.restoreAppState).toBe('function');
33
- });
34
-
35
- test('should export enableObservability function', async () => {
36
- const module = await import('../../src/core/store.js');
37
- expect(typeof module.enableObservability).toBe('function');
38
- });
39
-
40
- test('should export disableObservability function', async () => {
41
- const module = await import('../../src/core/store.js');
42
- expect(typeof module.disableObservability).toBe('function');
43
- });
44
-
45
- test('should export getStateHistory function', async () => {
46
- const module = await import('../../src/core/store.js');
47
- expect(typeof module.getStateHistory).toBe('function');
48
- });
49
- });
50
-
51
- describe('createNamespacedStore Integration', () => {
52
- test('should create a store and retrieve it', async () => {
53
- const { createNamespacedStore, getStore } = await import('../../src/core/store.js');
54
-
55
- // Use unique namespace to avoid conflicts
56
- const ns = 'test-' + Date.now();
57
- const store = createNamespacedStore(ns, { count: 0 });
58
-
59
- expect(store).toBeDefined();
60
- expect(store.namespace).toBe(ns);
61
-
62
- const retrieved = getStore(ns);
63
- expect(retrieved).toBe(store);
64
- });
65
-
66
- test('should initialize with provided state', async () => {
67
- const { createNamespacedStore } = await import('../../src/core/store.js');
68
-
69
- const ns = 'init-test-' + Date.now();
70
- const store = createNamespacedStore(ns, { items: ['a', 'b'], total: 100 });
71
-
72
- const state = store.get();
73
- expect(state.items).toEqual(['a', 'b']);
74
- expect(state.total).toBe(100);
75
- });
76
- });
77
-
78
- describe('getAllStores', () => {
79
- test('should return object with stores', async () => {
80
- const { getAllStores } = await import('../../src/core/store.js');
81
-
82
- const stores = getAllStores();
83
- expect(typeof stores).toBe('object');
84
- });
85
- });
86
-
87
- describe('getStore', () => {
88
- test('should return undefined for non-existent store', async () => {
89
- const { getStore } = await import('../../src/core/store.js');
90
- const store = getStore('definitely-not-existing-' + Date.now());
91
- expect(store).toBeUndefined();
92
- });
93
- });
94
-
95
- describe('Observability', () => {
96
- test('should enable and disable observability', async () => {
97
- const { enableObservability, disableObservability } = await import('../../src/core/store.js');
98
-
99
- // Should not throw
100
- enableObservability();
101
- expect(true).toBe(true);
102
-
103
- disableObservability();
104
- expect(true).toBe(true);
105
- });
106
-
107
- test('should return history array', async () => {
108
- const { getStateHistory } = await import('../../src/core/store.js');
109
-
110
- const history = getStateHistory('any');
111
- expect(Array.isArray(history)).toBe(true);
112
- });
113
- });
114
- });
@@ -1,121 +0,0 @@
1
- /**
2
- * @fileoverview Unit Tests for render.js Module
3
- * Target: 82% → 95% coverage
4
- */
5
-
6
- import { describe, test, expect, beforeAll, beforeEach } from 'bun:test';
7
- import { scheduler, memo, debounce, throttle, domBatch, processInChunks } from '../../src/core/render.js';
8
-
9
- describe('render Module Unit Tests', () => {
10
-
11
- // Mock requestAnimationFrame
12
- beforeAll(() => {
13
- globalThis.requestAnimationFrame = (cb) => { cb(Date.now()); return 0; };
14
- });
15
-
16
- // SCHEDULER
17
- test('scheduler should exist', () => {
18
- expect(scheduler).toBeDefined();
19
- });
20
-
21
- test('scheduler.schedule should be a function', () => {
22
- expect(typeof scheduler.schedule).toBe('function');
23
- });
24
-
25
- test('scheduler should execute callbacks', () => {
26
- let called = false;
27
- scheduler.schedule(() => { called = true; });
28
- expect(called).toBe(true);
29
- });
30
-
31
- test('scheduler should batch multiple callbacks', () => {
32
- let count = 0;
33
- scheduler.schedule(() => { count++; });
34
- scheduler.schedule(() => { count++; });
35
- scheduler.schedule(() => { count++; });
36
- expect(count).toBe(3);
37
- });
38
-
39
- // MEMO
40
- test('memo should be a function', () => {
41
- expect(typeof memo).toBe('function');
42
- });
43
-
44
- test('memo should cache results', () => {
45
- let callCount = 0;
46
- const expensive = memo((x) => { callCount++; return x * 2; });
47
- expect(expensive(5)).toBe(10);
48
- expect(expensive(5)).toBe(10);
49
- expect(callCount).toBe(1); // Only called once
50
- });
51
-
52
- test('memo should compute for different args', () => {
53
- const fn = memo((x) => x * 2);
54
- expect(fn(2)).toBe(4);
55
- expect(fn(3)).toBe(6);
56
- });
57
-
58
- // DEBOUNCE
59
- test('debounce should be a function', () => {
60
- expect(typeof debounce).toBe('function');
61
- });
62
-
63
- test('debounce should return a function', () => {
64
- const debounced = debounce(() => { }, 100);
65
- expect(typeof debounced).toBe('function');
66
- });
67
-
68
- // THROTTLE
69
- test('throttle should be a function', () => {
70
- expect(typeof throttle).toBe('function');
71
- });
72
-
73
- test('throttle should return a function', () => {
74
- const throttled = throttle(() => { }, 100);
75
- expect(typeof throttled).toBe('function');
76
- });
77
-
78
- test('throttle should call function immediately', () => {
79
- let called = false;
80
- const throttled = throttle(() => { called = true; }, 100);
81
- throttled();
82
- expect(called).toBe(true);
83
- });
84
-
85
- // DOM BATCH
86
- test('domBatch should exist', () => {
87
- expect(domBatch).toBeDefined();
88
- });
89
-
90
- test('domBatch.read should be a function', () => {
91
- expect(typeof domBatch.read).toBe('function');
92
- });
93
-
94
- test('domBatch.write should be a function', () => {
95
- expect(typeof domBatch.write).toBe('function');
96
- });
97
-
98
- test('domBatch should execute reads', () => {
99
- let readCalled = false;
100
- domBatch.read(() => { readCalled = true; });
101
- expect(readCalled).toBe(true);
102
- });
103
-
104
- test('domBatch should execute writes', () => {
105
- let writeCalled = false;
106
- domBatch.write(() => { writeCalled = true; });
107
- expect(writeCalled).toBe(true);
108
- });
109
-
110
- // PROCESS IN CHUNKS
111
- test('processInChunks should be a function', () => {
112
- expect(typeof processInChunks).toBe('function');
113
- });
114
-
115
- test('processInChunks should process all items', async () => {
116
- const items = [1, 2, 3, 4, 5];
117
- const processed = [];
118
- await processInChunks(items, (item) => processed.push(item), 2);
119
- expect(processed).toEqual([1, 2, 3, 4, 5]);
120
- });
121
- });