@adukiorg/anza 0.2.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 (349) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/README.md +215 -0
  3. package/bin/anza.js +63 -0
  4. package/bin/create.js +150 -0
  5. package/importmap.json +72 -0
  6. package/package.json +100 -0
  7. package/src/core/animations/index.js +55 -0
  8. package/src/core/animations/play.js +111 -0
  9. package/src/core/animations/registry.js +54 -0
  10. package/src/core/animations/scroll.js +50 -0
  11. package/src/core/animations/tokens.js +58 -0
  12. package/src/core/animations/usage.md +301 -0
  13. package/src/core/animations/waapi.js +86 -0
  14. package/src/core/api/cache.js +120 -0
  15. package/src/core/api/caches/glob.js +24 -0
  16. package/src/core/api/caches/index.js +118 -0
  17. package/src/core/api/events/index.js +75 -0
  18. package/src/core/api/fetch.js +99 -0
  19. package/src/core/api/index.js +158 -0
  20. package/src/core/api/pipeline.js +98 -0
  21. package/src/core/api/plan.md +209 -0
  22. package/src/core/api/prefixes/index.js +66 -0
  23. package/src/core/api/retry.js +69 -0
  24. package/src/core/api/stream.js +127 -0
  25. package/src/core/api/upload.js +180 -0
  26. package/src/core/api/usage.md +206 -0
  27. package/src/core/events/bus.js +38 -0
  28. package/src/core/events/delegate.js +79 -0
  29. package/src/core/events/index.js +26 -0
  30. package/src/core/events/listen.js +50 -0
  31. package/src/core/events/missing.md +103 -0
  32. package/src/core/events/once.js +49 -0
  33. package/src/core/events/plan.md +177 -0
  34. package/src/core/events/types/index.js +34 -0
  35. package/src/core/events/usage.md +107 -0
  36. package/src/core/offline/bridge.js +51 -0
  37. package/src/core/offline/clock.js +100 -0
  38. package/src/core/offline/connectivity.js +116 -0
  39. package/src/core/offline/index.js +41 -0
  40. package/src/core/offline/missing.md +89 -0
  41. package/src/core/offline/plan.md +143 -0
  42. package/src/core/offline/queue.js +168 -0
  43. package/src/core/offline/state.js +18 -0
  44. package/src/core/offline/sync.js +106 -0
  45. package/src/core/offline/usage.md +273 -0
  46. package/src/core/platform/guard.js +104 -0
  47. package/src/core/platform/index.js +42 -0
  48. package/src/core/platform/missing.md +119 -0
  49. package/src/core/platform/platform.d.ts +88 -0
  50. package/src/core/platform/polyfills/anchor.js +79 -0
  51. package/src/core/platform/polyfills/navigation.js +142 -0
  52. package/src/core/platform/polyfills/popover.js +142 -0
  53. package/src/core/platform/polyfills/scheduler.js +194 -0
  54. package/src/core/platform/polyfills/shadow.js +35 -0
  55. package/src/core/platform/polyfills/urlpattern.js +119 -0
  56. package/src/core/platform/supports.js +186 -0
  57. package/src/core/platform/usage.md +287 -0
  58. package/src/core/router/cache.js +95 -0
  59. package/src/core/router/container.js +146 -0
  60. package/src/core/router/handler.js +52 -0
  61. package/src/core/router/history.js +120 -0
  62. package/src/core/router/index.js +158 -0
  63. package/src/core/router/intercept.js +376 -0
  64. package/src/core/router/match.js +145 -0
  65. package/src/core/router/missing.md +716 -0
  66. package/src/core/router/outlet.js +139 -0
  67. package/src/core/router/plan.md +370 -0
  68. package/src/core/router/sync/index.js +16 -0
  69. package/src/core/router/sync/tab.js +115 -0
  70. package/src/core/router/sync/transport.js +139 -0
  71. package/src/core/router/transitions.js +59 -0
  72. package/src/core/router/usage.md +773 -0
  73. package/src/core/security/crypto.js +159 -0
  74. package/src/core/security/index.js +49 -0
  75. package/src/core/security/missing.md +97 -0
  76. package/src/core/security/permissions.js +64 -0
  77. package/src/core/security/sanitize.js +100 -0
  78. package/src/core/security/usage.md +283 -0
  79. package/src/core/state/derived.js +117 -0
  80. package/src/core/state/index.js +23 -0
  81. package/src/core/state/missing.md +165 -0
  82. package/src/core/state/persist.js +284 -0
  83. package/src/core/state/store.js +308 -0
  84. package/src/core/state/sync.js +46 -0
  85. package/src/core/state/usage.md +440 -0
  86. package/src/core/storage/cache.js +83 -0
  87. package/src/core/storage/idb.js +196 -0
  88. package/src/core/storage/index.js +373 -0
  89. package/src/core/storage/lru.js +107 -0
  90. package/src/core/storage/missing.md +165 -0
  91. package/src/core/storage/opfs.js +190 -0
  92. package/src/core/storage/plan.md +69 -0
  93. package/src/core/storage/quota.js +69 -0
  94. package/src/core/storage/usage.md +226 -0
  95. package/src/core/ui/base.js +50 -0
  96. package/src/core/ui/define/container.js +82 -0
  97. package/src/core/ui/define/define.js +12 -0
  98. package/src/core/ui/define/element.js +390 -0
  99. package/src/core/ui/define/index.js +9 -0
  100. package/src/core/ui/define/orchestrator.js +105 -0
  101. package/src/core/ui/define/proxy.js +644 -0
  102. package/src/core/ui/define/state.js +6 -0
  103. package/src/core/ui/define/utils.js +134 -0
  104. package/src/core/ui/implementation.md +170 -0
  105. package/src/core/ui/index.js +41 -0
  106. package/src/core/ui/observe.js +117 -0
  107. package/src/core/ui/plan.md +510 -0
  108. package/src/core/ui/schedule.js +60 -0
  109. package/src/core/ui/template.js +37 -0
  110. package/src/core/ui/transitions.js +37 -0
  111. package/src/core/ui/ui.types.md +890 -0
  112. package/src/core/ui/usage.md +1124 -0
  113. package/src/core/ui/watch.md +346 -0
  114. package/src/core/workers/broadcast.js +138 -0
  115. package/src/core/workers/dedicated.js +153 -0
  116. package/src/core/workers/index.js +169 -0
  117. package/src/core/workers/locks.js +160 -0
  118. package/src/core/workers/offscreen.js +166 -0
  119. package/src/core/workers/plan.md +381 -0
  120. package/src/core/workers/pool.js +267 -0
  121. package/src/core/workers/shared.js +137 -0
  122. package/src/core/workers/usage.md +622 -0
  123. package/src/elements/base.js +12 -0
  124. package/src/elements/data/card/index.html +9 -0
  125. package/src/elements/data/card/index.js +19 -0
  126. package/src/elements/data/card/index.tags.json +1 -0
  127. package/src/elements/data/card/style.css +46 -0
  128. package/src/elements/data/chart/index.html +1 -0
  129. package/src/elements/data/chart/index.js +143 -0
  130. package/src/elements/data/chart/index.tags.json +1 -0
  131. package/src/elements/data/chart/style.css +13 -0
  132. package/src/elements/data/list/index.html +3 -0
  133. package/src/elements/data/list/index.js +19 -0
  134. package/src/elements/data/list/index.tags.json +1 -0
  135. package/src/elements/data/list/style.css +39 -0
  136. package/src/elements/data/stat/index.html +9 -0
  137. package/src/elements/data/stat/index.js +19 -0
  138. package/src/elements/data/stat/index.tags.json +1 -0
  139. package/src/elements/data/stat/style.css +50 -0
  140. package/src/elements/data/table/index.html +1 -0
  141. package/src/elements/data/table/index.js +16 -0
  142. package/src/elements/data/table/index.tags.json +1 -0
  143. package/src/elements/data/table/style.css +50 -0
  144. package/src/elements/feedback/alert/index.html +11 -0
  145. package/src/elements/feedback/alert/index.js +28 -0
  146. package/src/elements/feedback/alert/index.tags.json +1 -0
  147. package/src/elements/feedback/alert/style.css +75 -0
  148. package/src/elements/feedback/empty/index.html +13 -0
  149. package/src/elements/feedback/empty/index.js +34 -0
  150. package/src/elements/feedback/empty/index.tags.json +1 -0
  151. package/src/elements/feedback/empty/style.css +45 -0
  152. package/src/elements/feedback/progress/index.html +7 -0
  153. package/src/elements/feedback/progress/index.js +46 -0
  154. package/src/elements/feedback/progress/index.tags.json +1 -0
  155. package/src/elements/feedback/progress/style.css +36 -0
  156. package/src/elements/feedback/skeleton/index.html +1 -0
  157. package/src/elements/feedback/skeleton/index.js +78 -0
  158. package/src/elements/feedback/skeleton/index.tags.json +1 -0
  159. package/src/elements/feedback/skeleton/style.css +28 -0
  160. package/src/elements/feedback/toast/index.html +3 -0
  161. package/src/elements/feedback/toast/index.js +65 -0
  162. package/src/elements/feedback/toast/index.tags.json +1 -0
  163. package/src/elements/feedback/toast/style.css +36 -0
  164. package/src/elements/forms/checkbox/index.html +7 -0
  165. package/src/elements/forms/checkbox/index.js +104 -0
  166. package/src/elements/forms/checkbox/index.tags.json +1 -0
  167. package/src/elements/forms/checkbox/style.css +86 -0
  168. package/src/elements/forms/field/index.html +13 -0
  169. package/src/elements/forms/field/index.js +42 -0
  170. package/src/elements/forms/field/index.tags.json +1 -0
  171. package/src/elements/forms/field/style.css +42 -0
  172. package/src/elements/forms/form/index.html +3 -0
  173. package/src/elements/forms/form/index.js +122 -0
  174. package/src/elements/forms/form/index.tags.json +1 -0
  175. package/src/elements/forms/form/style.css +11 -0
  176. package/src/elements/forms/input/index.html +4 -0
  177. package/src/elements/forms/input/index.js +103 -0
  178. package/src/elements/forms/input/index.tags.json +1 -0
  179. package/src/elements/forms/input/style.css +39 -0
  180. package/src/elements/forms/radio/index.html +4 -0
  181. package/src/elements/forms/radio/index.js +109 -0
  182. package/src/elements/forms/radio/index.tags.json +1 -0
  183. package/src/elements/forms/radio/style.css +65 -0
  184. package/src/elements/forms/select/index.html +9 -0
  185. package/src/elements/forms/select/index.js +114 -0
  186. package/src/elements/forms/select/index.tags.json +1 -0
  187. package/src/elements/forms/select/style.css +95 -0
  188. package/src/elements/forms/textarea/index.html +4 -0
  189. package/src/elements/forms/textarea/index.js +115 -0
  190. package/src/elements/forms/textarea/index.tags.json +1 -0
  191. package/src/elements/forms/textarea/style.css +46 -0
  192. package/src/elements/forms/toggle/index.html +4 -0
  193. package/src/elements/forms/toggle/index.js +89 -0
  194. package/src/elements/forms/toggle/index.tags.json +1 -0
  195. package/src/elements/forms/toggle/style.css +63 -0
  196. package/src/elements/forms/upload/index.html +13 -0
  197. package/src/elements/forms/upload/index.js +120 -0
  198. package/src/elements/forms/upload/index.tags.json +1 -0
  199. package/src/elements/forms/upload/style.css +61 -0
  200. package/src/elements/index.js +71 -0
  201. package/src/elements/layout/app/index.html +7 -0
  202. package/src/elements/layout/app/index.js +16 -0
  203. package/src/elements/layout/app/index.tags.json +1 -0
  204. package/src/elements/layout/app/style.css +41 -0
  205. package/src/elements/layout/grid/index.html +3 -0
  206. package/src/elements/layout/grid/index.js +41 -0
  207. package/src/elements/layout/grid/index.tags.json +1 -0
  208. package/src/elements/layout/grid/style.css +12 -0
  209. package/src/elements/layout/header/index.html +8 -0
  210. package/src/elements/layout/header/index.js +16 -0
  211. package/src/elements/layout/header/index.tags.json +1 -0
  212. package/src/elements/layout/header/style.css +28 -0
  213. package/src/elements/layout/scroll/index.html +3 -0
  214. package/src/elements/layout/scroll/index.js +19 -0
  215. package/src/elements/layout/scroll/index.tags.json +1 -0
  216. package/src/elements/layout/scroll/style.css +24 -0
  217. package/src/elements/layout/sidebar/index.html +3 -0
  218. package/src/elements/layout/sidebar/index.js +24 -0
  219. package/src/elements/layout/sidebar/index.tags.json +1 -0
  220. package/src/elements/layout/sidebar/style.css +30 -0
  221. package/src/elements/layout/split/index.html +3 -0
  222. package/src/elements/layout/split/index.js +18 -0
  223. package/src/elements/layout/split/index.tags.json +1 -0
  224. package/src/elements/layout/split/style.css +28 -0
  225. package/src/elements/layout/stack/index.html +3 -0
  226. package/src/elements/layout/stack/index.js +31 -0
  227. package/src/elements/layout/stack/index.tags.json +1 -0
  228. package/src/elements/layout/stack/style.css +15 -0
  229. package/src/elements/layout/surface/index.html +3 -0
  230. package/src/elements/layout/surface/index.js +19 -0
  231. package/src/elements/layout/surface/index.tags.json +1 -0
  232. package/src/elements/layout/surface/style.css +29 -0
  233. package/src/elements/navigation/breadcrumb/index.html +5 -0
  234. package/src/elements/navigation/breadcrumb/index.js +16 -0
  235. package/src/elements/navigation/breadcrumb/index.tags.json +1 -0
  236. package/src/elements/navigation/breadcrumb/style.css +36 -0
  237. package/src/elements/navigation/nav/index.html +3 -0
  238. package/src/elements/navigation/nav/index.js +24 -0
  239. package/src/elements/navigation/nav/index.tags.json +1 -0
  240. package/src/elements/navigation/nav/style.css +38 -0
  241. package/src/elements/navigation/pagination/index.html +3 -0
  242. package/src/elements/navigation/pagination/index.js +94 -0
  243. package/src/elements/navigation/pagination/index.tags.json +1 -0
  244. package/src/elements/navigation/pagination/style.css +39 -0
  245. package/src/elements/navigation/steps/index.html +6 -0
  246. package/src/elements/navigation/steps/index.js +64 -0
  247. package/src/elements/navigation/steps/index.tags.json +1 -0
  248. package/src/elements/navigation/steps/style.css +78 -0
  249. package/src/elements/navigation/tabs/index.html +6 -0
  250. package/src/elements/navigation/tabs/index.js +132 -0
  251. package/src/elements/navigation/tabs/index.tags.json +1 -0
  252. package/src/elements/navigation/tabs/style.css +52 -0
  253. package/src/elements/overlay/dialog/index.html +5 -0
  254. package/src/elements/overlay/dialog/index.js +57 -0
  255. package/src/elements/overlay/dialog/index.tags.json +1 -0
  256. package/src/elements/overlay/dialog/style.css +31 -0
  257. package/src/elements/overlay/drawer/index.html +3 -0
  258. package/src/elements/overlay/drawer/index.js +56 -0
  259. package/src/elements/overlay/drawer/index.tags.json +1 -0
  260. package/src/elements/overlay/drawer/style.css +48 -0
  261. package/src/elements/overlay/menu/index.html +3 -0
  262. package/src/elements/overlay/menu/index.js +107 -0
  263. package/src/elements/overlay/menu/index.tags.json +1 -0
  264. package/src/elements/overlay/menu/style.css +43 -0
  265. package/src/elements/overlay/popover/index.html +3 -0
  266. package/src/elements/overlay/popover/index.js +44 -0
  267. package/src/elements/overlay/popover/index.tags.json +1 -0
  268. package/src/elements/overlay/popover/style.css +21 -0
  269. package/src/elements/overlay/sheet/index.html +8 -0
  270. package/src/elements/overlay/sheet/index.js +105 -0
  271. package/src/elements/overlay/sheet/index.tags.json +1 -0
  272. package/src/elements/overlay/sheet/style.css +64 -0
  273. package/src/elements/overlay/tooltip/index.html +6 -0
  274. package/src/elements/overlay/tooltip/index.js +16 -0
  275. package/src/elements/overlay/tooltip/index.tags.json +1 -0
  276. package/src/elements/overlay/tooltip/style.css +41 -0
  277. package/src/elements/primitives/avatar/index.html +2 -0
  278. package/src/elements/primitives/avatar/index.js +79 -0
  279. package/src/elements/primitives/avatar/index.tags.json +1 -0
  280. package/src/elements/primitives/avatar/style.css +36 -0
  281. package/src/elements/primitives/badge/index.html +3 -0
  282. package/src/elements/primitives/badge/index.js +20 -0
  283. package/src/elements/primitives/badge/index.tags.json +1 -0
  284. package/src/elements/primitives/badge/style.css +67 -0
  285. package/src/elements/primitives/button/index.html +3 -0
  286. package/src/elements/primitives/button/index.js +61 -0
  287. package/src/elements/primitives/button/index.tags.json +1 -0
  288. package/src/elements/primitives/button/style.css +66 -0
  289. package/src/elements/primitives/divider/index.html +1 -0
  290. package/src/elements/primitives/divider/index.js +43 -0
  291. package/src/elements/primitives/divider/index.tags.json +1 -0
  292. package/src/elements/primitives/divider/style.css +39 -0
  293. package/src/elements/primitives/icon/index.html +3 -0
  294. package/src/elements/primitives/icon/index.js +66 -0
  295. package/src/elements/primitives/icon/index.tags.json +1 -0
  296. package/src/elements/primitives/icon/style.css +20 -0
  297. package/src/elements/primitives/link/index.html +3 -0
  298. package/src/elements/primitives/link/index.js +129 -0
  299. package/src/elements/primitives/link/index.tags.json +1 -0
  300. package/src/elements/primitives/link/style.css +40 -0
  301. package/src/elements/primitives/spinner/index.html +1 -0
  302. package/src/elements/primitives/spinner/index.js +62 -0
  303. package/src/elements/primitives/spinner/index.tags.json +1 -0
  304. package/src/elements/primitives/spinner/style.css +20 -0
  305. package/src/elements/primitives/text/index.html +1 -0
  306. package/src/elements/primitives/text/index.js +79 -0
  307. package/src/elements/primitives/text/index.tags.json +1 -0
  308. package/src/elements/primitives/text/style.css +25 -0
  309. package/src/index.js +23 -0
  310. package/src/styles/base.css +66 -0
  311. package/src/styles/index.css +10 -0
  312. package/src/styles/layers.css +9 -0
  313. package/src/styles/reset.css +66 -0
  314. package/src/sw/activate.js +51 -0
  315. package/src/sw/expire.js +47 -0
  316. package/src/sw/index.js +28 -0
  317. package/src/sw/install.js +35 -0
  318. package/src/sw/push.js +58 -0
  319. package/src/sw/queue.js +60 -0
  320. package/src/sw/routes.js +71 -0
  321. package/src/sw/strategies.js +247 -0
  322. package/src/sw/sync.js +80 -0
  323. package/src/tokens/index.css +26 -0
  324. package/src/tokens/primitives/colors.css +54 -0
  325. package/src/tokens/primitives/motion.css +34 -0
  326. package/src/tokens/primitives/radius.css +16 -0
  327. package/src/tokens/primitives/shadow.css +34 -0
  328. package/src/tokens/primitives/spacing.css +27 -0
  329. package/src/tokens/primitives/typography.css +46 -0
  330. package/src/tokens/primitives/zindex.css +18 -0
  331. package/src/tokens/registered/colors.css +133 -0
  332. package/src/tokens/registered/dimensions.css +31 -0
  333. package/src/tokens/semantic/components.css +125 -0
  334. package/src/tokens/semantic/contrast.css +33 -0
  335. package/src/tokens/semantic/dark.css +61 -0
  336. package/src/tokens/semantic/light.css +64 -0
  337. package/types/core/animations/index.d.ts +52 -0
  338. package/types/core/api/index.d.ts +68 -0
  339. package/types/core/events/index.d.ts +50 -0
  340. package/types/core/offline/index.d.ts +68 -0
  341. package/types/core/platform/index.d.ts +60 -0
  342. package/types/core/router/index.d.ts +203 -0
  343. package/types/core/security/index.d.ts +33 -0
  344. package/types/core/state/index.d.ts +68 -0
  345. package/types/core/storage/index.d.ts +40 -0
  346. package/types/core/ui/index.d.ts +446 -0
  347. package/types/core/workers/index.d.ts +221 -0
  348. package/types/elements/index.d.ts +150 -0
  349. package/types/index.d.ts +18 -0
@@ -0,0 +1,134 @@
1
+ import { assetCache } from './state.js';
2
+
3
+ // Detect constructable stylesheet + adoptedStyleSheets support once.
4
+ const supportsSheets =
5
+ typeof CSSStyleSheet !== 'undefined' &&
6
+ 'adoptedStyleSheets' in Document.prototype &&
7
+ 'adoptedStyleSheets' in ShadowRoot.prototype;
8
+
9
+ /**
10
+ * Preloads style and HTML template resources asynchronously exactly once.
11
+ * Returns { templateNode, stylesheet, cssText, tagsDescriptor }.
12
+ * When constructable stylesheets are unsupported, stylesheet is null and
13
+ * cssText carries the raw CSS for <style> injection.
14
+ */
15
+ export async function preloadResources(tag, styleUrl, templateUrl, inlineTemplate, inlineStyle) {
16
+ let templateNode = null;
17
+ let stylesheet = null;
18
+ let cssText = null;
19
+ let tagsDescriptor = null;
20
+
21
+ // Compile / Fetch styles
22
+ if (styleUrl) {
23
+ if (assetCache.has(styleUrl)) {
24
+ const cached = assetCache.get(styleUrl);
25
+ if (supportsSheets) {
26
+ stylesheet = cached;
27
+ } else {
28
+ cssText = cached;
29
+ }
30
+ } else {
31
+ try {
32
+ const res = await fetch(styleUrl);
33
+ if (res.ok) {
34
+ const css = await res.text();
35
+ if (supportsSheets) {
36
+ stylesheet = new CSSStyleSheet();
37
+ stylesheet.replaceSync(css);
38
+ assetCache.set(styleUrl, stylesheet);
39
+ } else {
40
+ cssText = css;
41
+ assetCache.set(styleUrl, css);
42
+ }
43
+ }
44
+ } catch (err) {
45
+ console.error(`Failed to load style resource for element ${tag}:`, err);
46
+ }
47
+ }
48
+ } else if (inlineStyle) {
49
+ if (supportsSheets) {
50
+ stylesheet = new CSSStyleSheet();
51
+ stylesheet.replaceSync(inlineStyle);
52
+ } else {
53
+ cssText = inlineStyle;
54
+ }
55
+ }
56
+
57
+ // Compile / Fetch Template markup
58
+ if (templateUrl) {
59
+ if (assetCache.has(templateUrl)) {
60
+ templateNode = assetCache.get(templateUrl);
61
+ } else {
62
+ try {
63
+ const res = await fetch(templateUrl);
64
+ if (res.ok) {
65
+ const html = await res.text();
66
+ templateNode = createTemplateFragment(html);
67
+ assetCache.set(templateUrl, templateNode);
68
+ }
69
+ } catch (err) {
70
+ console.error(`Failed to fetch template resource for element ${tag}:`, err);
71
+ }
72
+ }
73
+
74
+ // Fetch Tags Descriptor
75
+ const tagsUrl = templateUrl.replace(/\.html$/, '.tags.json');
76
+ if (assetCache.has(tagsUrl)) {
77
+ tagsDescriptor = assetCache.get(tagsUrl);
78
+ } else {
79
+ try {
80
+ const res = await fetch(tagsUrl);
81
+ if (res.ok) {
82
+ const raw = await res.json();
83
+ tagsDescriptor = validateDescriptor(raw);
84
+ assetCache.set(tagsUrl, tagsDescriptor);
85
+ }
86
+ } catch (_) {
87
+ // Safe to ignore — not all elements have a tags descriptor
88
+ }
89
+ }
90
+ } else if (inlineTemplate) {
91
+ templateNode = createTemplateFragment(inlineTemplate);
92
+ }
93
+
94
+ return { templateNode, stylesheet, cssText, tagsDescriptor };
95
+ }
96
+
97
+ /**
98
+ * Validates a raw tags descriptor JSON object.
99
+ * Returns a safe descriptor with only array-typed fields, or null if unusable.
100
+ */
101
+ export function validateDescriptor(raw) {
102
+ if (!raw || typeof raw !== 'object') return null;
103
+
104
+ const safe = {};
105
+ if (typeof raw.version === 'number') safe.version = raw.version;
106
+
107
+ const known = new Set(['version', 'refs', 'ids', 'classes', 'tags', 'compound']);
108
+
109
+ for (const field of ['refs', 'ids', 'classes', 'tags', 'compound']) {
110
+ safe[field] = Array.isArray(raw[field]) ? raw[field] : [];
111
+ }
112
+
113
+ // Preserve unknown future fields without mutating them
114
+ for (const [k, v] of Object.entries(raw)) {
115
+ if (!known.has(k)) {
116
+ safe[k] = v;
117
+ }
118
+ }
119
+
120
+ return safe;
121
+ }
122
+
123
+ /**
124
+ * Compiles an HTML string into a DocumentFragment utilizing the fastest native methods.
125
+ */
126
+ export function createTemplateFragment(htmlString) {
127
+ const tpl = document.createElement('template');
128
+ if (typeof tpl.setHTMLUnsafe === 'function') {
129
+ tpl.setHTMLUnsafe(htmlString);
130
+ } else {
131
+ tpl.innerHTML = htmlString;
132
+ }
133
+ return tpl.content;
134
+ }
@@ -0,0 +1,170 @@
1
+ # Native UI Implementation Checklist
2
+
3
+ This checklist is the execution companion to `plan.md`, `watch.md`, and `usage.md`.
4
+
5
+ Status: **Fully Implemented and Verified**
6
+
7
+ - All phases (Phase 1 through Phase 7) are completed, optimized, and verified.
8
+ - The runtime helpers, event delegation, mutation watcher, lifecycle injection, Rust scanner, and comprehensive test suite are fully operational and integrated.
9
+
10
+ ## Phase 1: Runtime Helpers
11
+
12
+ Files:
13
+
14
+ - `src/core/ui/define/proxy.js`
15
+ - `src/core/ui/define/element.js`
16
+ - optional new `src/core/ui/define/context.js`
17
+
18
+ Tasks:
19
+
20
+ - Split `TagsCache` into separate `one` and `all` caches.
21
+ - Add `TagsCache.has(selector)` if desired.
22
+ - Add descriptor-free `refs` fallback scanning.
23
+ - Add duplicate-ref development warnings.
24
+ - Add context builder for `{ el, ctrl, tags, on, refs, watch, internals }`.
25
+ - Install cache invalidation for `replaceChildren` and `innerHTML`.
26
+ - Return stable context objects for mount/update.
27
+
28
+ Acceptance:
29
+
30
+ - `tags.one('button')` and `tags.all('button')` can be called in any order.
31
+ - `refs` works with and without `.tags.json`.
32
+ - Existing `ui.element` components continue to mount.
33
+
34
+ ## Phase 2: Event Delegation
35
+
36
+ File:
37
+
38
+ - `src/core/ui/define/proxy.js`
39
+
40
+ Tasks:
41
+
42
+ - Replace per-binding root listeners with one root listener per event type.
43
+ - Store event registrations in sets keyed by event type.
44
+ - Support `on.click(selector, handler)`.
45
+ - Support `on.click(selector, handler, signal)`.
46
+ - Support `on.click(selector, handler, options)`.
47
+ - Support `on.click.once(selector, handler)`.
48
+ - Return disposer functions.
49
+ - Remove bindings on custom signal abort.
50
+ - Remove all bindings on component signal abort.
51
+
52
+ Acceptance:
53
+
54
+ - Dynamically added matching elements work without rebinding.
55
+ - Multiple click handlers do not create multiple native click listeners on the shadow root.
56
+ - `.once` fires once and removes only itself.
57
+
58
+ ## Phase 3: `watch`
59
+
60
+ File:
61
+
62
+ - `src/core/ui/define/proxy.js` or new `src/core/ui/define/watch.js`
63
+
64
+ Tasks:
65
+
66
+ - Implement `createMutationWatcher(shadowRoot, defaultSignal)`.
67
+ - Support `watch.attr`, `watch.kids`, `watch.text`, `watch.tree`.
68
+ - Support `.once` on each method.
69
+ - Accept selector strings and direct element references.
70
+ - Accept custom `AbortSignal` or options object.
71
+ - Return disposer functions.
72
+ - Recompute observer options from active registrations.
73
+ - Dispatch reshaped handler arguments.
74
+ - Guard callbacks after lifecycle abort.
75
+
76
+ Acceptance:
77
+
78
+ - One `MutationObserver` exists per component instance.
79
+ - Attribute, child, text, and tree handlers receive documented arguments.
80
+ - Component disconnect clears all registrations.
81
+
82
+ ## Phase 4: Lifecycle Injection
83
+
84
+ File:
85
+
86
+ - `src/core/ui/define/element.js`
87
+
88
+ Tasks:
89
+
90
+ - Use the context builder after template/style hydration.
91
+ - Pass `watch` to `spec.mount`.
92
+ - Pass `watch` and `prev` to `spec.update`.
93
+ - Preserve `internals` behavior for form-associated elements.
94
+ - Keep `spec.unmount` shape stable.
95
+
96
+ Acceptance:
97
+
98
+ - Existing components using `{ tags, on, refs }` still work.
99
+ - New components can destructure `{ watch }`.
100
+ - Updates receive `prev` consistently.
101
+
102
+ ## Phase 5: Rust Scanner
103
+
104
+ Files:
105
+
106
+ - `tools/src/extract/html.rs`
107
+ - `tools/src/extract/runner.rs`
108
+ - `tools/src/watcher/runner.rs`
109
+ - `tools/src/main.rs`
110
+
111
+ Tasks:
112
+
113
+ - Refactor scanner into `parse_html`, `parse_file`, `emit_descriptor`, and `parse_and_emit`.
114
+ - Return `Result` instead of silently swallowing errors.
115
+ - Add descriptor `version`.
116
+ - Add duplicate-ref diagnostics.
117
+ - Keep sorted deterministic output.
118
+ - Consider `attrs` and `refTypes` fields.
119
+ - Add subcommands or document current flags until subcommands land.
120
+ - Regenerate descriptors on HTML watcher events.
121
+ - Remove stale descriptors when source HTML is deleted.
122
+
123
+ Acceptance:
124
+
125
+ - Build mode emits descriptors for all HTML templates.
126
+ - Dev watcher regenerates a changed template descriptor.
127
+ - Malformed HTML fragments do not panic.
128
+
129
+ ## Phase 6: Tests
130
+
131
+ JavaScript tests:
132
+
133
+ - `tags` cache shapes and invalidation.
134
+ - `refs` descriptor and fallback behavior.
135
+ - `on` delegation, custom events, once, signal cleanup.
136
+ - `watch` attr/kids/text/tree, once, direct refs, selector misses, lifecycle abort.
137
+
138
+ Rust tests:
139
+
140
+ - Descriptor parsing.
141
+ - Stable JSON ordering.
142
+ - Duplicate refs.
143
+ - Watcher-triggered regeneration.
144
+
145
+ ## Phase 7: Documentation
146
+
147
+ Files:
148
+
149
+ - `src/core/ui/plan.md`
150
+ - `src/core/ui/watch.md`
151
+ - `src/core/ui/usage.md`
152
+ - `src/core/ui/implementation.md`
153
+
154
+ Tasks:
155
+
156
+ - Keep `plan.md` as the architectural implementation plan.
157
+ - Keep `watch.md` as the `watch` API and internals spec.
158
+ - Keep `usage.md` as the public usage guide.
159
+ - Keep this file as the execution checklist.
160
+
161
+ ## Done Definition
162
+
163
+ The work is complete when:
164
+
165
+ - Runtime injects `refs`, `tags`, `on`, and `watch`.
166
+ - All helpers clean up from `ctrl.signal`.
167
+ - Rust emits descriptors deterministically.
168
+ - Dev watcher keeps descriptors current.
169
+ - Usage docs cover every public call shape.
170
+ - Tests prove lifecycle cleanup and cache correctness.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * src/core/ui/index.js
3
+ *
4
+ * Public UI base entry point.
5
+ * Aggregates BaseElement foundations, cooperative task scheduling, transition
6
+ * orchestrators, templates, declarative element factory, and safe reactive element observers.
7
+ *
8
+ * Source: doc 04 — Web Components §1, doc 12 — Performance §2
9
+ */
10
+
11
+ import { BaseElement } from './base.js';
12
+ import { define, element, container } from './define/index.js';
13
+ import { schedule, scheduleFrame, yieldTask } from './schedule.js';
14
+ import { transition } from './transitions.js';
15
+ import { template } from './template.js';
16
+ import * as observe from './observe.js';
17
+
18
+ export const ui = {
19
+ define,
20
+ element,
21
+ container,
22
+ schedule,
23
+ scheduleFrame,
24
+ yield: yieldTask,
25
+ transition,
26
+ template,
27
+ observe
28
+ };
29
+
30
+ export {
31
+ BaseElement,
32
+ define,
33
+ element,
34
+ container,
35
+ schedule,
36
+ scheduleFrame,
37
+ yieldTask,
38
+ transition,
39
+ template,
40
+ observe
41
+ };
@@ -0,0 +1,117 @@
1
+ /**
2
+ * src/core/ui/observe.js
3
+ *
4
+ * Safe Observer Factories.
5
+ * Wraps browser ResizeObserver, IntersectionObserver, MutationObserver, and PerformanceObserver
6
+ * APIs with automatic AbortSignal-driven disconnect cleanups to secure observers
7
+ * against lifecycle memory leaks.
8
+ *
9
+ * Abort listeners are removed when manual disposal runs first, preventing
10
+ * long-lived signals from retaining stale closures.
11
+ *
12
+ * Source: doc 14 — Memory Management §5, doc 17 — Browser API §10
13
+ */
14
+
15
+ /**
16
+ * ResizeObserver with automatic AbortSignal cleanup.
17
+ */
18
+ export function resize(el, fn, signal) {
19
+ if (signal?.aborted) return () => {};
20
+
21
+ const observer = new ResizeObserver((entries) => {
22
+ try {
23
+ fn(entries);
24
+ } catch (err) {
25
+ console.error('Error in ResizeObserver callback:', err);
26
+ }
27
+ });
28
+
29
+ observer.observe(el);
30
+
31
+ const dispose = () => {
32
+ observer.disconnect();
33
+ signal?.removeEventListener('abort', dispose);
34
+ };
35
+
36
+ signal?.addEventListener('abort', dispose);
37
+
38
+ return dispose;
39
+ }
40
+
41
+ /**
42
+ * IntersectionObserver with automatic AbortSignal cleanup.
43
+ */
44
+ export function intersection(el, fn, signal, options = {}) {
45
+ if (signal?.aborted) return () => {};
46
+
47
+ const observer = new IntersectionObserver((entries) => {
48
+ try {
49
+ fn(entries);
50
+ } catch (err) {
51
+ console.error('Error in IntersectionObserver callback:', err);
52
+ }
53
+ }, options);
54
+
55
+ observer.observe(el);
56
+
57
+ const dispose = () => {
58
+ observer.disconnect();
59
+ signal?.removeEventListener('abort', dispose);
60
+ };
61
+
62
+ signal?.addEventListener('abort', dispose);
63
+
64
+ return dispose;
65
+ }
66
+
67
+ /**
68
+ * MutationObserver with automatic AbortSignal cleanup.
69
+ */
70
+ export function mutation(el, fn, signal, options = { childList: true }) {
71
+ if (signal?.aborted) return () => {};
72
+
73
+ const observer = new MutationObserver((mutations) => {
74
+ try {
75
+ fn(mutations);
76
+ } catch (err) {
77
+ console.error('Error in MutationObserver callback:', err);
78
+ }
79
+ });
80
+
81
+ observer.observe(el, options);
82
+
83
+ const dispose = () => {
84
+ observer.disconnect();
85
+ signal?.removeEventListener('abort', dispose);
86
+ };
87
+
88
+ signal?.addEventListener('abort', dispose);
89
+
90
+ return dispose;
91
+ }
92
+
93
+ /**
94
+ * PerformanceObserver with automatic AbortSignal cleanup.
95
+ */
96
+ export function performance(types, fn, signal, options = {}) {
97
+ if (signal?.aborted) return () => {};
98
+
99
+ const observer = new PerformanceObserver((list) => {
100
+ try {
101
+ fn(list);
102
+ } catch (err) {
103
+ console.error('Error in PerformanceObserver callback:', err);
104
+ }
105
+ });
106
+
107
+ observer.observe({ entryTypes: types, ...options });
108
+
109
+ const dispose = () => {
110
+ observer.disconnect();
111
+ signal?.removeEventListener('abort', dispose);
112
+ };
113
+
114
+ signal?.addEventListener('abort', dispose);
115
+
116
+ return dispose;
117
+ }