@adia-ai/web-components 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/README.md +195 -0
  2. package/a2ui/dockables/action.js +152 -0
  3. package/a2ui/dockables/base.js +30 -0
  4. package/a2ui/dockables/controller.js +97 -0
  5. package/a2ui/dockables/data-source.js +103 -0
  6. package/a2ui/dockables/index.js +6 -0
  7. package/a2ui/dockables/lifecycle.js +84 -0
  8. package/a2ui/dockables/provider.js +59 -0
  9. package/a2ui/index.js +19 -0
  10. package/a2ui/manifest-runtime.js +226 -0
  11. package/a2ui/registry.js +200 -0
  12. package/a2ui/renderer.js +361 -0
  13. package/a2ui/root.js +152 -0
  14. package/a2ui/stream.js +243 -0
  15. package/a2ui/surface-manifest.js +294 -0
  16. package/a2ui/surface.js +222 -0
  17. package/a2ui/wire-factory.js +134 -0
  18. package/a2ui/wiring-engine.js +209 -0
  19. package/a2ui/wiring-registry.js +342 -0
  20. package/components/accordion/accordion.a2ui.json +129 -0
  21. package/components/accordion/accordion.css +133 -0
  22. package/components/accordion/accordion.js +125 -0
  23. package/components/accordion/accordion.yaml +527 -0
  24. package/components/action-list/action-list.a2ui.json +64 -0
  25. package/components/action-list/action-list.css +115 -0
  26. package/components/action-list/action-list.js +149 -0
  27. package/components/action-list/action-list.yaml +56 -0
  28. package/components/agent-artifact/agent-artifact.a2ui.json +99 -0
  29. package/components/agent-artifact/agent-artifact.css +94 -0
  30. package/components/agent-artifact/agent-artifact.js +169 -0
  31. package/components/agent-artifact/agent-artifact.yaml +71 -0
  32. package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +91 -0
  33. package/components/agent-feedback-bar/agent-feedback-bar.css +33 -0
  34. package/components/agent-feedback-bar/agent-feedback-bar.js +152 -0
  35. package/components/agent-feedback-bar/agent-feedback-bar.yaml +65 -0
  36. package/components/agent-questions/agent-questions.a2ui.json +89 -0
  37. package/components/agent-questions/agent-questions.css +146 -0
  38. package/components/agent-questions/agent-questions.js +189 -0
  39. package/components/agent-questions/agent-questions.yaml +63 -0
  40. package/components/agent-reasoning/agent-reasoning.a2ui.json +100 -0
  41. package/components/agent-reasoning/agent-reasoning.css +273 -0
  42. package/components/agent-reasoning/agent-reasoning.js +469 -0
  43. package/components/agent-reasoning/agent-reasoning.yaml +70 -0
  44. package/components/agent-suggestions/agent-suggestions.a2ui.json +87 -0
  45. package/components/agent-suggestions/agent-suggestions.css +18 -0
  46. package/components/agent-suggestions/agent-suggestions.js +87 -0
  47. package/components/agent-suggestions/agent-suggestions.yaml +59 -0
  48. package/components/agent-trace/agent-trace.a2ui.json +78 -0
  49. package/components/agent-trace/agent-trace.css +275 -0
  50. package/components/agent-trace/agent-trace.js +216 -0
  51. package/components/agent-trace/agent-trace.yaml +53 -0
  52. package/components/alert/alert.a2ui.json +211 -0
  53. package/components/alert/alert.css +88 -0
  54. package/components/alert/alert.js +96 -0
  55. package/components/alert/alert.yaml +205 -0
  56. package/components/avatar/avatar.a2ui.json +215 -0
  57. package/components/avatar/avatar.css +159 -0
  58. package/components/avatar/avatar.js +157 -0
  59. package/components/avatar/avatar.yaml +559 -0
  60. package/components/badge/badge.a2ui.json +169 -0
  61. package/components/badge/badge.css +78 -0
  62. package/components/badge/badge.js +53 -0
  63. package/components/badge/badge.yaml +612 -0
  64. package/components/block/block.a2ui.json +135 -0
  65. package/components/block/block.css +29 -0
  66. package/components/block/block.js +23 -0
  67. package/components/block/block.yaml +115 -0
  68. package/components/breadcrumb/breadcrumb.a2ui.json +86 -0
  69. package/components/breadcrumb/breadcrumb.css +78 -0
  70. package/components/breadcrumb/breadcrumb.js +44 -0
  71. package/components/breadcrumb/breadcrumb.yaml +84 -0
  72. package/components/button/button.a2ui.json +172 -0
  73. package/components/button/button.css +168 -0
  74. package/components/button/button.js +60 -0
  75. package/components/button/button.yaml +120 -0
  76. package/components/calendar-picker/calendar-picker.a2ui.json +139 -0
  77. package/components/calendar-picker/calendar-picker.css +321 -0
  78. package/components/calendar-picker/calendar-picker.js +324 -0
  79. package/components/calendar-picker/calendar-picker.yaml +243 -0
  80. package/components/canvas/canvas.a2ui.json +75 -0
  81. package/components/canvas/canvas.css +52 -0
  82. package/components/canvas/canvas.js +179 -0
  83. package/components/canvas/canvas.yaml +62 -0
  84. package/components/card/card.a2ui.json +276 -0
  85. package/components/card/card.css +362 -0
  86. package/components/card/card.js +58 -0
  87. package/components/card/card.yaml +527 -0
  88. package/components/chart/chart.a2ui.json +298 -0
  89. package/components/chart/chart.css +512 -0
  90. package/components/chart/chart.js +1075 -0
  91. package/components/chart/chart.yaml +540 -0
  92. package/components/chat/chat-input.css +141 -0
  93. package/components/chat/chat-input.js +242 -0
  94. package/components/chat/chat.a2ui.json +181 -0
  95. package/components/chat/chat.css +193 -0
  96. package/components/chat/chat.js +155 -0
  97. package/components/chat/chat.yaml +230 -0
  98. package/components/check/check.a2ui.json +134 -0
  99. package/components/check/check.css +126 -0
  100. package/components/check/check.js +58 -0
  101. package/components/check/check.yaml +109 -0
  102. package/components/code/code.a2ui.json +153 -0
  103. package/components/code/code.css +133 -0
  104. package/components/code/code.js +114 -0
  105. package/components/code/code.yaml +163 -0
  106. package/components/col/col.a2ui.json +104 -0
  107. package/components/col/col.css +36 -0
  108. package/components/col/col.js +19 -0
  109. package/components/col/col.yaml +364 -0
  110. package/components/color-picker/color-picker.a2ui.json +100 -0
  111. package/components/color-picker/color-picker.css +182 -0
  112. package/components/color-picker/color-picker.js +537 -0
  113. package/components/color-picker/color-picker.yaml +105 -0
  114. package/components/command/command.a2ui.json +221 -0
  115. package/components/command/command.css +251 -0
  116. package/components/command/command.js +284 -0
  117. package/components/command/command.yaml +186 -0
  118. package/components/description-list/description-list.a2ui.json +89 -0
  119. package/components/description-list/description-list.css +70 -0
  120. package/components/description-list/description-list.js +75 -0
  121. package/components/description-list/description-list.yaml +59 -0
  122. package/components/divider/divider.a2ui.json +126 -0
  123. package/components/divider/divider.css +102 -0
  124. package/components/divider/divider.js +47 -0
  125. package/components/divider/divider.yaml +366 -0
  126. package/components/drawer/drawer.a2ui.json +199 -0
  127. package/components/drawer/drawer.css +342 -0
  128. package/components/drawer/drawer.js +263 -0
  129. package/components/drawer/drawer.yaml +366 -0
  130. package/components/embed/embed.a2ui.json +150 -0
  131. package/components/embed/embed.css +28 -0
  132. package/components/embed/embed.js +63 -0
  133. package/components/embed/embed.yaml +224 -0
  134. package/components/empty-state/empty-state.a2ui.json +133 -0
  135. package/components/empty-state/empty-state.css +58 -0
  136. package/components/empty-state/empty-state.js +87 -0
  137. package/components/empty-state/empty-state.yaml +314 -0
  138. package/components/footer/footer.a2ui.json +79 -0
  139. package/components/footer/footer.yaml +239 -0
  140. package/components/grid/grid.a2ui.json +171 -0
  141. package/components/grid/grid.css +37 -0
  142. package/components/grid/grid.js +21 -0
  143. package/components/grid/grid.yaml +577 -0
  144. package/components/header/header.a2ui.json +76 -0
  145. package/components/header/header.yaml +336 -0
  146. package/components/heatmap/heatmap.a2ui.json +150 -0
  147. package/components/heatmap/heatmap.css +146 -0
  148. package/components/heatmap/heatmap.js +246 -0
  149. package/components/heatmap/heatmap.yaml +131 -0
  150. package/components/icon/icon.a2ui.json +79 -0
  151. package/components/icon/icon.css +20 -0
  152. package/components/icon/icon.js +26 -0
  153. package/components/icon/icon.yaml +233 -0
  154. package/components/image/image.a2ui.json +261 -0
  155. package/components/image/image.css +76 -0
  156. package/components/image/image.js +102 -0
  157. package/components/image/image.yaml +477 -0
  158. package/components/index.js +85 -0
  159. package/components/input/input.a2ui.json +284 -0
  160. package/components/input/input.css +162 -0
  161. package/components/input/input.js +148 -0
  162. package/components/input/input.yaml +496 -0
  163. package/components/inspector/inspector.a2ui.json +67 -0
  164. package/components/inspector/inspector.css +31 -0
  165. package/components/inspector/inspector.js +133 -0
  166. package/components/inspector/inspector.yaml +58 -0
  167. package/components/kbd/kbd.a2ui.json +96 -0
  168. package/components/kbd/kbd.css +62 -0
  169. package/components/kbd/kbd.js +24 -0
  170. package/components/kbd/kbd.yaml +213 -0
  171. package/components/list/list.a2ui.json +145 -0
  172. package/components/list/list.css +103 -0
  173. package/components/list/list.js +236 -0
  174. package/components/list/list.yaml +122 -0
  175. package/components/menu/menu.a2ui.json +146 -0
  176. package/components/menu/menu.css +146 -0
  177. package/components/menu/menu.js +296 -0
  178. package/components/menu/menu.yaml +123 -0
  179. package/components/modal/modal.a2ui.json +136 -0
  180. package/components/modal/modal.css +153 -0
  181. package/components/modal/modal.js +181 -0
  182. package/components/modal/modal.yaml +114 -0
  183. package/components/noodles/noodles.a2ui.json +145 -0
  184. package/components/noodles/noodles.css +118 -0
  185. package/components/noodles/noodles.js +470 -0
  186. package/components/noodles/noodles.yaml +123 -0
  187. package/components/otp-input/otp-input.a2ui.json +104 -0
  188. package/components/otp-input/otp-input.css +78 -0
  189. package/components/otp-input/otp-input.js +170 -0
  190. package/components/otp-input/otp-input.yaml +218 -0
  191. package/components/pagination/pagination.a2ui.json +122 -0
  192. package/components/pagination/pagination.css +162 -0
  193. package/components/pagination/pagination.js +185 -0
  194. package/components/pagination/pagination.yaml +165 -0
  195. package/components/pane/pane.a2ui.json +94 -0
  196. package/components/pane/pane.css +166 -0
  197. package/components/pane/pane.js +140 -0
  198. package/components/pane/pane.yaml +197 -0
  199. package/components/pipeline-status/pipeline-status.a2ui.json +90 -0
  200. package/components/pipeline-status/pipeline-status.css +162 -0
  201. package/components/pipeline-status/pipeline-status.js +176 -0
  202. package/components/pipeline-status/pipeline-status.yaml +99 -0
  203. package/components/popover/popover.a2ui.json +181 -0
  204. package/components/popover/popover.css +57 -0
  205. package/components/popover/popover.js +170 -0
  206. package/components/popover/popover.yaml +257 -0
  207. package/components/progress/progress.a2ui.json +199 -0
  208. package/components/progress/progress.css +88 -0
  209. package/components/progress/progress.js +64 -0
  210. package/components/progress/progress.yaml +342 -0
  211. package/components/progress-row/progress-row.a2ui.json +100 -0
  212. package/components/progress-row/progress-row.css +57 -0
  213. package/components/progress-row/progress-row.js +92 -0
  214. package/components/progress-row/progress-row.yaml +87 -0
  215. package/components/radio/radio.a2ui.json +232 -0
  216. package/components/radio/radio.css +102 -0
  217. package/components/radio/radio.js +73 -0
  218. package/components/radio/radio.yaml +248 -0
  219. package/components/range/range.a2ui.json +151 -0
  220. package/components/range/range.css +148 -0
  221. package/components/range/range.js +177 -0
  222. package/components/range/range.yaml +188 -0
  223. package/components/rating/rating.a2ui.json +105 -0
  224. package/components/rating/rating.css +92 -0
  225. package/components/rating/rating.js +138 -0
  226. package/components/rating/rating.yaml +74 -0
  227. package/components/richtext/richtext.a2ui.json +82 -0
  228. package/components/richtext/richtext.css +225 -0
  229. package/components/richtext/richtext.js +74 -0
  230. package/components/richtext/richtext.yaml +89 -0
  231. package/components/row/row.a2ui.json +102 -0
  232. package/components/row/row.css +51 -0
  233. package/components/row/row.js +39 -0
  234. package/components/row/row.yaml +358 -0
  235. package/components/search/search.a2ui.json +186 -0
  236. package/components/search/search.css +28 -0
  237. package/components/search/search.js +124 -0
  238. package/components/search/search.yaml +154 -0
  239. package/components/section/section.a2ui.json +78 -0
  240. package/components/section/section.yaml +338 -0
  241. package/components/segment/segment.a2ui.json +100 -0
  242. package/components/segment/segment.css +81 -0
  243. package/components/segment/segment.js +32 -0
  244. package/components/segment/segment.yaml +216 -0
  245. package/components/segmented/segmented.a2ui.json +106 -0
  246. package/components/segmented/segmented.css +67 -0
  247. package/components/segmented/segmented.js +149 -0
  248. package/components/segmented/segmented.yaml +91 -0
  249. package/components/select/select.a2ui.json +203 -0
  250. package/components/select/select.css +277 -0
  251. package/components/select/select.js +388 -0
  252. package/components/select/select.yaml +375 -0
  253. package/components/skeleton/skeleton.a2ui.json +120 -0
  254. package/components/skeleton/skeleton.css +47 -0
  255. package/components/skeleton/skeleton.js +43 -0
  256. package/components/skeleton/skeleton.yaml +153 -0
  257. package/components/slider/slider.a2ui.json +162 -0
  258. package/components/slider/slider.css +137 -0
  259. package/components/slider/slider.js +162 -0
  260. package/components/slider/slider.yaml +299 -0
  261. package/components/stack/stack.a2ui.json +62 -0
  262. package/components/stack/stack.css +28 -0
  263. package/components/stack/stack.js +18 -0
  264. package/components/stack/stack.yaml +54 -0
  265. package/components/stat/stat.a2ui.json +246 -0
  266. package/components/stat/stat.css +101 -0
  267. package/components/stat/stat.js +91 -0
  268. package/components/stat/stat.yaml +206 -0
  269. package/components/stepper/stepper.a2ui.json +77 -0
  270. package/components/stepper/stepper.css +243 -0
  271. package/components/stepper/stepper.js +118 -0
  272. package/components/stepper/stepper.yaml +73 -0
  273. package/components/stream/stream.a2ui.json +98 -0
  274. package/components/stream/stream.css +37 -0
  275. package/components/stream/stream.js +99 -0
  276. package/components/stream/stream.yaml +87 -0
  277. package/components/swiper/swiper.a2ui.json +140 -0
  278. package/components/swiper/swiper.css +267 -0
  279. package/components/swiper/swiper.js +285 -0
  280. package/components/swiper/swiper.yaml +268 -0
  281. package/components/switch/switch.a2ui.json +134 -0
  282. package/components/switch/switch.css +104 -0
  283. package/components/switch/switch.js +53 -0
  284. package/components/switch/switch.yaml +322 -0
  285. package/components/table/cell-types.js +296 -0
  286. package/components/table/table.a2ui.json +458 -0
  287. package/components/table/table.css +531 -0
  288. package/components/table/table.js +1392 -0
  289. package/components/table/table.yaml +528 -0
  290. package/components/tabs/tab.js +34 -0
  291. package/components/tabs/tabs.a2ui.json +174 -0
  292. package/components/tabs/tabs.css +162 -0
  293. package/components/tabs/tabs.js +226 -0
  294. package/components/tabs/tabs.yaml +255 -0
  295. package/components/tag/tag.a2ui.json +148 -0
  296. package/components/tag/tag.css +118 -0
  297. package/components/tag/tag.js +88 -0
  298. package/components/tag/tag.yaml +125 -0
  299. package/components/text/text.a2ui.json +99 -0
  300. package/components/text/text.css +65 -0
  301. package/components/text/text.js +35 -0
  302. package/components/text/text.yaml +360 -0
  303. package/components/textarea/textarea.a2ui.json +91 -0
  304. package/components/textarea/textarea.css +93 -0
  305. package/components/textarea/textarea.js +114 -0
  306. package/components/textarea/textarea.yaml +79 -0
  307. package/components/timeline/timeline.a2ui.json +82 -0
  308. package/components/timeline/timeline.css +389 -0
  309. package/components/timeline/timeline.js +171 -0
  310. package/components/timeline/timeline.yaml +185 -0
  311. package/components/toast/toast.a2ui.json +199 -0
  312. package/components/toast/toast.css +211 -0
  313. package/components/toast/toast.js +146 -0
  314. package/components/toast/toast.yaml +184 -0
  315. package/components/toggle-group/toggle-group.a2ui.json +126 -0
  316. package/components/toggle-group/toggle-group.css +102 -0
  317. package/components/toggle-group/toggle-group.js +147 -0
  318. package/components/toggle-group/toggle-group.yaml +98 -0
  319. package/components/toolbar/toolbar.a2ui.json +131 -0
  320. package/components/toolbar/toolbar.css +132 -0
  321. package/components/toolbar/toolbar.js +366 -0
  322. package/components/toolbar/toolbar.yaml +238 -0
  323. package/components/tooltip/tooltip.a2ui.json +148 -0
  324. package/components/tooltip/tooltip.css +39 -0
  325. package/components/tooltip/tooltip.js +96 -0
  326. package/components/tooltip/tooltip.yaml +201 -0
  327. package/components/tree/tree.a2ui.json +119 -0
  328. package/components/tree/tree.css +133 -0
  329. package/components/tree/tree.js +253 -0
  330. package/components/tree/tree.yaml +92 -0
  331. package/components/upload/upload.a2ui.json +185 -0
  332. package/components/upload/upload.css +115 -0
  333. package/components/upload/upload.js +189 -0
  334. package/components/upload/upload.yaml +302 -0
  335. package/core/anchor.js +187 -0
  336. package/core/controller.js +182 -0
  337. package/core/element.js +257 -0
  338. package/core/form.js +217 -0
  339. package/core/icons.js +180 -0
  340. package/core/markdown.js +95 -0
  341. package/core/polyfills.js +23 -0
  342. package/core/provider.js +262 -0
  343. package/core/signals.js +113 -0
  344. package/core/template.js +226 -0
  345. package/core/transport.js +77 -0
  346. package/package.json +38 -0
  347. package/patterns/adia-chat/adia-chat.a2ui.json +149 -0
  348. package/patterns/adia-chat/adia-chat.css +10 -0
  349. package/patterns/adia-chat/adia-chat.js +297 -0
  350. package/patterns/adia-chat/adia-chat.yaml +118 -0
  351. package/patterns/adia-chat/css/adia-chat.empty.css +12 -0
  352. package/patterns/adia-chat/css/adia-chat.layout.css +60 -0
  353. package/patterns/adia-chat/css/adia-chat.markdown.css +74 -0
  354. package/patterns/adia-chat/css/adia-chat.messages.css +87 -0
  355. package/patterns/adia-chat/css/adia-chat.streaming.css +30 -0
  356. package/patterns/adia-chat/css/adia-chat.tokens.css +95 -0
  357. package/patterns/adia-chat/index.html +93 -0
  358. package/patterns/adia-editor/adia-editor.a2ui.json +58 -0
  359. package/patterns/adia-editor/adia-editor.css +6 -0
  360. package/patterns/adia-editor/adia-editor.js +56 -0
  361. package/patterns/adia-editor/adia-editor.yaml +36 -0
  362. package/patterns/adia-editor/css/adia-editor.layout.css +86 -0
  363. package/patterns/adia-editor/css/adia-editor.tokens.css +28 -0
  364. package/patterns/adia-editor/index.html +179 -0
  365. package/patterns/app-nav/app-nav.a2ui.json +89 -0
  366. package/patterns/app-nav/app-nav.css +92 -0
  367. package/patterns/app-nav/app-nav.js +99 -0
  368. package/patterns/app-nav/app-nav.yaml +54 -0
  369. package/patterns/app-nav-group/app-nav-group.a2ui.json +82 -0
  370. package/patterns/app-nav-group/app-nav-group.css +261 -0
  371. package/patterns/app-nav-group/app-nav-group.js +116 -0
  372. package/patterns/app-nav-group/app-nav-group.yaml +59 -0
  373. package/patterns/app-nav-item/app-nav-item.a2ui.json +83 -0
  374. package/patterns/app-nav-item/app-nav-item.css +156 -0
  375. package/patterns/app-nav-item/app-nav-item.js +42 -0
  376. package/patterns/app-nav-item/app-nav-item.yaml +62 -0
  377. package/patterns/app-shell/app-shell.a2ui.json +114 -0
  378. package/patterns/app-shell/app-shell.css +14 -0
  379. package/patterns/app-shell/app-shell.js +251 -0
  380. package/patterns/app-shell/app-shell.yaml +66 -0
  381. package/patterns/app-shell/css/app-shell.collapsed.css +86 -0
  382. package/patterns/app-shell/css/app-shell.helpers.css +42 -0
  383. package/patterns/app-shell/css/app-shell.main.css +58 -0
  384. package/patterns/app-shell/css/app-shell.shell.css +44 -0
  385. package/patterns/app-shell/css/app-shell.sidebar.css +116 -0
  386. package/patterns/app-shell/css/app-shell.templates.css +214 -0
  387. package/patterns/app-shell/css/app-shell.tokens.css +116 -0
  388. package/patterns/app-shell/index.html +112 -0
  389. package/patterns/gen-ui/gen-ui.a2ui.json +72 -0
  390. package/patterns/gen-ui/gen-ui.css +83 -0
  391. package/patterns/gen-ui/gen-ui.js +136 -0
  392. package/patterns/gen-ui/gen-ui.yaml +43 -0
  393. package/patterns/index.js +10 -0
  394. package/patterns/section-nav/section-nav.a2ui.json +91 -0
  395. package/patterns/section-nav/section-nav.css +59 -0
  396. package/patterns/section-nav/section-nav.js +42 -0
  397. package/patterns/section-nav/section-nav.yaml +58 -0
  398. package/patterns/section-nav-group/section-nav-group.a2ui.json +95 -0
  399. package/patterns/section-nav-group/section-nav-group.css +74 -0
  400. package/patterns/section-nav-group/section-nav-group.js +84 -0
  401. package/patterns/section-nav-group/section-nav-group.yaml +66 -0
  402. package/patterns/section-nav-item/section-nav-item.a2ui.json +97 -0
  403. package/patterns/section-nav-item/section-nav-item.css +96 -0
  404. package/patterns/section-nav-item/section-nav-item.js +66 -0
  405. package/patterns/section-nav-item/section-nav-item.yaml +70 -0
  406. package/styles/colors/index.css +6 -0
  407. package/styles/colors/parameters.css +52 -0
  408. package/styles/colors/primitives-accent.css +89 -0
  409. package/styles/colors/primitives-brand.css +89 -0
  410. package/styles/colors/primitives-danger.css +89 -0
  411. package/styles/colors/primitives-info.css +89 -0
  412. package/styles/colors/primitives-neutral.css +91 -0
  413. package/styles/colors/primitives-shared.css +57 -0
  414. package/styles/colors/primitives-success.css +89 -0
  415. package/styles/colors/primitives-warning.css +89 -0
  416. package/styles/colors/primitives.css +17 -0
  417. package/styles/colors/scrims.css +182 -0
  418. package/styles/colors/semantics.css +595 -0
  419. package/styles/colors/surfaces.css +43 -0
  420. package/styles/fonts.css +99 -0
  421. package/styles/layouts/admin.css +7 -0
  422. package/styles/prose.css +186 -0
  423. package/styles/styles.css +193 -0
  424. package/styles/themes.css +155 -0
  425. package/styles/tokens.css +304 -0
  426. package/styles/typography.css +853 -0
  427. package/traits/active-state.js +24 -0
  428. package/traits/anchor-positioning.js +66 -0
  429. package/traits/attention-pulse.js +30 -0
  430. package/traits/confetti-burst.js +65 -0
  431. package/traits/confetti.js +57 -0
  432. package/traits/count-up.js +42 -0
  433. package/traits/define.js +76 -0
  434. package/traits/dirty-state.js +38 -0
  435. package/traits/drag-ghost.js +38 -0
  436. package/traits/draggable.js +73 -0
  437. package/traits/fade-presence.js +52 -0
  438. package/traits/focus-trap.js +63 -0
  439. package/traits/focusable.js +38 -0
  440. package/traits/glow-focus.js +33 -0
  441. package/traits/gradient-shift.js +32 -0
  442. package/traits/haptic-feedback.js +28 -0
  443. package/traits/hotkey.js +62 -0
  444. package/traits/hoverable.js +26 -0
  445. package/traits/index.js +55 -0
  446. package/traits/inertia-drag.js +133 -0
  447. package/traits/intersection-observer.js +33 -0
  448. package/traits/keyboard-nav.js +36 -0
  449. package/traits/magnetic-hover.js +37 -0
  450. package/traits/noise-texture.js +30 -0
  451. package/traits/parallax.js +42 -0
  452. package/traits/portal.js +27 -0
  453. package/traits/pressable.js +75 -0
  454. package/traits/resizable.js +100 -0
  455. package/traits/resize-observer.js +31 -0
  456. package/traits/ripple.js +53 -0
  457. package/traits/roving-tabindex.js +67 -0
  458. package/traits/scale-press.js +43 -0
  459. package/traits/scroll-lock.js +27 -0
  460. package/traits/shimmer-loading.js +44 -0
  461. package/traits/snap-to-grid.js +28 -0
  462. package/traits/sound-feedback.js +30 -0
  463. package/traits/spring-animate.js +56 -0
  464. package/traits/tilt-hover.js +37 -0
  465. package/traits/tossable.js +178 -0
  466. package/traits/typeahead.js +63 -0
  467. package/traits/typewriter.js +35 -0
  468. package/traits/validation.js +118 -0
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # @adia-ai/web-components
2
+
3
+ Vanilla web components + A2UI runtime for AdiaUI. **80 light-DOM custom
4
+ elements**, a reactive core, a trait system, and a renderer that turns
5
+ A2UI protocol messages into live DOM.
6
+
7
+ > This package ships UI atoms only. The generation pipeline lives in
8
+ > [`@adia-ai/gen-ui`](../gen-ui); the pattern corpus in
9
+ > [`@adia-ai/gen-ui-training`](../gen-ui-training); the MCP server in
10
+ > [`@adia-ai/gen-ui-mcp`](../gen-ui-mcp).
11
+
12
+ ## Quick start
13
+
14
+ ```html
15
+ <link rel="stylesheet" href="node_modules/@adia-ai/web-components/index.css" />
16
+
17
+ <script type="module">
18
+ import '@adia-ai/web-components'; // registers every *-n tag
19
+ </script>
20
+
21
+ <card-ui>
22
+ <header>
23
+ <span slot="icon"><avatar-ui icon="user"></avatar-ui></span>
24
+ <span slot="heading"><text-ui strong>Hello</text-ui></span>
25
+ </header>
26
+ <section>Composition works out of the box — no framework.</section>
27
+ </card-ui>
28
+ ```
29
+
30
+ The package `sideEffects` entry keeps the import above from being
31
+ tree-shaken; importing `index.js` side-effect-registers every component.
32
+
33
+ ## Layout
34
+
35
+ ```
36
+ web-components/
37
+ ├── core/ — Reactivity + base classes
38
+ │ ├── signals.js signal() / computed() / effect() / batch() / untracked()
39
+ │ ├── template.js tagged templates: html, css, repeat, stamp
40
+ │ ├── element.js AdiaElement — light-DOM reactive base
41
+ │ ├── form.js AdiaFormElement — form-associated + validation
42
+ │ ├── provider.js global provider registration + router-ui
43
+ │ ├── anchor.js popover + anchor-positioning
44
+ │ ├── markdown.js lightweight markdown renderer
45
+ │ └── transport.js SSE / streaming helpers for LLM adapters
46
+
47
+ ├── components/ — 80 *-n custom elements
48
+ │ └── <tag>/
49
+ │ ├── <tag>.js class definition (extends AdiaElement)
50
+ │ ├── <tag>.css @scope(tag-ui) two-block: tokens + styles
51
+ │ ├── <tag>.yaml authoring contract (props, slots, events, examples)
52
+ │ └── <tag>.a2ui.json generated — do NOT edit
53
+
54
+ ├── patterns/ — Higher-level compositions (tag: `adia-*`)
55
+ │ ├── app-shell, app-nav, section-nav — admin layout scaffolding
56
+ │ ├── adia-chat, adia-editor, gen-ui — LLM + editor + gen-UI patterns
57
+ │ └── index.js — registers all patterns
58
+
59
+ ├── traits/ — 40 composable behaviors via defineTrait()
60
+ │ (pressable, focusTrap, confetti, resizable, …)
61
+
62
+ ├── a2ui/ — A2UI runtime (renderer + wiring)
63
+ │ ├── renderer.js consumes A2UI JSON, stamps component trees
64
+ │ ├── registry.js component-name → class map (aliases included)
65
+ │ ├── wiring-engine.js binds controllers (toggle, form, data-stream)
66
+ │ ├── wiring-registry.js declarative event/data wiring catalog
67
+ │ ├── surface.js <canvas-ui> + <a2ui-root> hosts
68
+ │ ├── stream.js streamed-UI incremental hydration
69
+ │ └── manifest-runtime.js surface manifest loader
70
+
71
+ ├── styles/ — Global tokens and CSS layering
72
+ │ ├── tokens.css all --a-* design tokens
73
+ │ ├── colors/ primitives / semantics / scrims
74
+ │ ├── typography.css, space.css, radius.css, shadow.css
75
+ │ └── themes/*.css 8 themes (ocean, forest, sunset, …)
76
+
77
+ └── scripts/ — Build + dev utilities
78
+ └── build-components.mjs YAML → .a2ui.json per-component
79
+ ```
80
+
81
+ ## Component contract
82
+
83
+ Every component is a single-file class extending `AdiaElement` (or
84
+ `AdiaFormElement` for form fields). All styling lives in a sibling `.css`
85
+ file using **two-block `@scope`**:
86
+
87
+ ```css
88
+ @scope (button-ui) {
89
+ :where(:scope) {
90
+ /* Tokens only — zero specificity, parent overrides win */
91
+ --button-bg: var(--a-accent-bg);
92
+ --button-fg: var(--a-accent-fg);
93
+ --button-radius: var(--a-radius);
94
+ }
95
+ :scope {
96
+ /* Styles — consume component tokens only, never global directly */
97
+ background: var(--button-bg);
98
+ color: var(--button-fg);
99
+ border-radius: var(--button-radius);
100
+ }
101
+ :scope[variant="danger"] {
102
+ --button-bg: var(--a-danger-bg); /* variants override tokens, not styles */
103
+ }
104
+ }
105
+ ```
106
+
107
+ Authoring rules (enforced by `coherence-audit`):
108
+
109
+ 1. **No raw colors** in component CSS — every color goes through a token.
110
+ 2. **Variants change tokens, modes change layout.** A selector that sets
111
+ `display`, `padding`, `flex`, `grid`, etc. is a *mode* and needs a
112
+ Sanctioned Mode Attributes entry in the contract doc.
113
+ 3. **Boolean props default to `false`.** If the expected default is "on",
114
+ flip the name (`closable` → `permanent`).
115
+ 4. **Event listeners in `connected()` have matching `removeEventListener`
116
+ in `disconnected()`.** Handlers are stable `#field` arrows, never
117
+ inline.
118
+ 5. **Light DOM only.** No `::part()`, `::slotted()`, shadow roots. Use
119
+ attribute selectors on children: `:scope > [slot="icon"]`.
120
+
121
+ Full authoring contract: [`docs/specs/component-token-contract.md`](../../docs/specs/component-token-contract.md).
122
+ The `adia-ui-author` skill encodes the 20 non-negotiable rules.
123
+
124
+ ## Card-n / drawer-ui composition parity
125
+
126
+ Both accept bare `<header>` / `<section>` / `<footer>` tags OR explicit
127
+ `[slot="header|body|footer"]`. Both activate a 3-column header grid when
128
+ any direct `[slot="icon|heading|description|action"]` child is present
129
+ (`:has(> …)` — direct-child only). Drawer supports multi-section bodies
130
+ with sticky header/footer. See the drawer component page for worked
131
+ examples.
132
+
133
+ ## A2UI runtime
134
+
135
+ ```javascript
136
+ import { A2UIRenderer } from '@adia-ai/web-components/a2ui';
137
+
138
+ const renderer = new A2UIRenderer({ target: document.getElementById('canvas') });
139
+ renderer.apply({
140
+ type: 'updateComponents',
141
+ components: [
142
+ { id: 'root', component: 'Card', children: ['hdr', 'body'] },
143
+ { id: 'hdr', component: 'Header', slots: { heading: 'Generated UI' } },
144
+ { id: 'body', component: 'Section', children: ['btn'] },
145
+ { id: 'btn', component: 'Button', attrs: { variant: 'primary' }, content: 'Click' },
146
+ ],
147
+ });
148
+ ```
149
+
150
+ Accepts the four A2UI message kinds: `updateComponents`,
151
+ `updateDataModel`, `wireComponents`, `createSurface`. The registry
152
+ normalizes LLM-emitted aliases (e.g. `Carousel` → `swiper-ui`) so generated
153
+ output is robust to name drift.
154
+
155
+ ## Build
156
+
157
+ ```bash
158
+ npm run build:components # regenerate all .a2ui.json from YAML
159
+ ```
160
+
161
+ The build also writes `packages/gen-ui-training/catalog-a2ui_0_9.json` and
162
+ `catalog-a2ui_0_9_rules.txt` — the flat-file catalog the MCP server and
163
+ generation engine consume.
164
+
165
+ ## Themes, density, scale
166
+
167
+ ```html
168
+ <div data-theme="ocean" density="compact" size="sm">
169
+ …all descendants re-theme / re-densify / re-scale automatically…
170
+ </div>
171
+ ```
172
+
173
+ - `[data-theme]` — 8 themes: `default`, `ocean`, `forest`, `sunset`,
174
+ `lavender`, `rose`, `slate`, `midnight`
175
+ - `[density]` — `compact` (0.85×) · `spacious` (1.15×)
176
+ - `[size]` — `sm`|`md`|`lg` shifts the entire typescale + component
177
+ dimensions
178
+ - `[radius]` — `sharp` (0) · `rounded` (1) · `round` (2)
179
+
180
+ Each is a CSS-variable override; no class toggles, no re-imports.
181
+
182
+ ## Dependency direction
183
+
184
+ ```
185
+ gen-ui ──reads──> gen-ui-training ←─reads── web-components
186
+ gen-ui-mcp ──reads──> gen-ui, gen-ui-training
187
+ ```
188
+
189
+ Web-components never imports from gen-ui or gen-ui-mcp. The A2UI renderer
190
+ consumes a protocol, not a generator — anything that emits valid A2UI
191
+ messages drives it.
192
+
193
+ ## License
194
+
195
+ MIT
@@ -0,0 +1,152 @@
1
+ /**
2
+ * ActionDock — Binds a AdiaEvent on a component to a handler.
3
+ *
4
+ * The AdiaEvent is a typed object: { event, target?, debounce?, throttle?, condition? }
5
+ * When the DOM event fires, the handler runs with the surface context.
6
+ * onSuccess/onError chains run follow-up handlers based on the outcome.
7
+ */
8
+ import { Dockable } from './base.js';
9
+
10
+ /**
11
+ * AdiaEvent type → DOM event name.
12
+ * AdiaUI components emit semantic events; these map to the actual DOM event to listen on.
13
+ */
14
+ const NANO_TO_DOM = {
15
+ press: 'click',
16
+ submit: 'submit',
17
+ input: 'input',
18
+ change: 'change',
19
+ select: 'select',
20
+ toggle: 'change',
21
+ dismiss: 'close',
22
+ navigate: 'click',
23
+ mount: 'connectedCallback',
24
+ unmount: 'disconnectedCallback',
25
+ focus: 'focusin',
26
+ blur: 'focusout',
27
+ drag: 'dragstart',
28
+ drop: 'drop',
29
+ };
30
+
31
+ export { NANO_TO_DOM };
32
+
33
+ export class ActionDock extends Dockable {
34
+ kind = 'action';
35
+
36
+ /** @type {string} */
37
+ id;
38
+
39
+ /** @type {{ event: string, target?: string, debounce?: number, throttle?: number, condition?: object }} */
40
+ event;
41
+
42
+ /** @type {string} handler name */
43
+ handler;
44
+
45
+ /** @type {object} handler config */
46
+ config;
47
+
48
+ /** @type {Array|null} follow-up actions on success */
49
+ onSuccess;
50
+
51
+ /** @type {Array|null} follow-up actions on error */
52
+ onError;
53
+
54
+ /** @type {Function} (handlerName) => handlerFn */
55
+ #resolveHandler;
56
+
57
+ /**
58
+ * @param {object} decl — { event, handler, config?, onSuccess?, onError? }
59
+ * @param {Function} resolveHandler — (name) => async (config, ctx) => result
60
+ */
61
+ constructor(decl, resolveHandler) {
62
+ super();
63
+ this.event = decl.event;
64
+ this.handler = decl.handler;
65
+ this.config = decl.config || {};
66
+ this.onSuccess = decl.onSuccess || null;
67
+ this.onError = decl.onError || null;
68
+ this.#resolveHandler = resolveHandler;
69
+
70
+ // Auto-generate id from event + target
71
+ this.id = `action:${this.event.event}:${this.event.target || 'root'}:${this.handler}`;
72
+ }
73
+
74
+ dock(ctx) {
75
+ const target = this.event.target
76
+ ? ctx.getElement(this.event.target)
77
+ : ctx.getRootElement();
78
+
79
+ if (!target) {
80
+ console.warn(`ActionDock: target "${this.event.target}" not found`);
81
+ return;
82
+ }
83
+
84
+ const domEventName = NANO_TO_DOM[this.event.event] || this.event.event;
85
+ const handlerFn = this.#resolveHandler(this.handler);
86
+
87
+ if (!handlerFn) {
88
+ console.warn(`ActionDock: unknown handler "${this.handler}"`);
89
+ return;
90
+ }
91
+
92
+ let listener = async (domEvent) => {
93
+ // Condition guard
94
+ if (this.event.condition) {
95
+ const val = ctx.getModel(this.event.condition.path);
96
+ if ('equals' in this.event.condition && val !== this.event.condition.equals) return;
97
+ if ('notEquals' in this.event.condition && val === this.event.condition.notEquals) return;
98
+ if ('exists' in this.event.condition && this.event.condition.exists && val == null) return;
99
+ }
100
+
101
+ try {
102
+ const result = await handlerFn(this.config, ctx, domEvent);
103
+
104
+ // Run onSuccess chain
105
+ if (this.onSuccess) {
106
+ for (const follow of this.onSuccess) {
107
+ const followFn = this.#resolveHandler(follow.handler);
108
+ if (followFn) await followFn(follow.config || {}, ctx, result);
109
+ }
110
+ }
111
+ } catch (err) {
112
+ // Run onError chain
113
+ if (this.onError) {
114
+ for (const follow of this.onError) {
115
+ const followFn = this.#resolveHandler(follow.handler);
116
+ if (followFn) await followFn(follow.config || {}, ctx, err);
117
+ }
118
+ } else {
119
+ console.error(`ActionDock: handler "${this.handler}" failed`, err);
120
+ }
121
+ }
122
+ };
123
+
124
+ // Debounce
125
+ if (this.event.debounce > 0) {
126
+ const origListener = listener;
127
+ let timer;
128
+ listener = (...args) => {
129
+ clearTimeout(timer);
130
+ timer = setTimeout(() => origListener(...args), this.event.debounce);
131
+ };
132
+ }
133
+
134
+ // Throttle
135
+ if (this.event.throttle > 0) {
136
+ const origListener = listener;
137
+ let last = 0;
138
+ listener = (...args) => {
139
+ const now = Date.now();
140
+ if (now - last >= this.event.throttle) {
141
+ last = now;
142
+ origListener(...args);
143
+ }
144
+ };
145
+ }
146
+
147
+ target.addEventListener(domEventName, listener);
148
+ return () => target.removeEventListener(domEventName, listener);
149
+ }
150
+
151
+ undock() {}
152
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Dockable — Base class for objects that attach to a Surface.
3
+ *
4
+ * Every dockable has:
5
+ * kind — which port type it uses (controller, source, action, provider, lifecycle)
6
+ * id — unique identity within the surface
7
+ * dock(context) — attach and return cleanup function
8
+ * undock() — teardown
9
+ */
10
+ export class Dockable {
11
+ /** @type {'controller'|'source'|'action'|'provider'|'lifecycle'} */
12
+ get kind() { throw new Error('Dockable subclass must define kind'); }
13
+
14
+ /** @type {string} */
15
+ get id() { throw new Error('Dockable subclass must define id'); }
16
+
17
+ /**
18
+ * Attach to a surface. Receives the surface context.
19
+ * Return a cleanup function, or void.
20
+ * @param {import('../surface.js').SurfaceContext} ctx
21
+ * @returns {(() => void)|void}
22
+ */
23
+ dock(ctx) { throw new Error('Dockable subclass must implement dock()'); }
24
+
25
+ /**
26
+ * Detach from the surface. Cleanup fn from dock() is called
27
+ * automatically before this.
28
+ */
29
+ undock() {}
30
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * ControllerDock — Wraps a AdiaUI controller as a dockable.
3
+ *
4
+ * Instantiates the controller, connects it to its host element,
5
+ * and sets up two-way binding between controller state and model paths.
6
+ */
7
+ import { Dockable } from './base.js';
8
+
9
+ export class ControllerDock extends Dockable {
10
+ kind = 'controller';
11
+
12
+ /** @type {string} */
13
+ id;
14
+
15
+ /** @type {string} controller type name, e.g., 'FormController' */
16
+ type;
17
+
18
+ /** @type {string} component id to attach to */
19
+ hostId;
20
+
21
+ /** @type {object} controller config */
22
+ config;
23
+
24
+ /** @type {object|null} model path bindings { stateKey: '/model/path' } */
25
+ bind;
26
+
27
+ /** @type {import('../../controllers/base.js').BaseController|null} */
28
+ controller = null;
29
+
30
+ /** @type {Function|null} resolve controller class */
31
+ #resolveClass;
32
+
33
+ /**
34
+ * @param {object} decl — { id, type, host, config?, bind? }
35
+ * @param {Function} resolveClass — async (type) => ControllerClass
36
+ */
37
+ constructor(decl, resolveClass) {
38
+ super();
39
+ this.id = decl.id;
40
+ this.type = decl.type;
41
+ this.hostId = decl.host;
42
+ this.config = decl.config || {};
43
+ this.bind = decl.bind || null;
44
+ this.#resolveClass = resolveClass;
45
+ }
46
+
47
+ async dock(ctx) {
48
+ const host = ctx.getElement(this.hostId);
49
+ if (!host) {
50
+ console.warn(`ControllerDock: host element "${this.hostId}" not found`);
51
+ return;
52
+ }
53
+
54
+ const ControllerClass = await this.#resolveClass(this.type);
55
+ if (!ControllerClass) {
56
+ console.warn(`ControllerDock: unknown controller type "${this.type}"`);
57
+ return;
58
+ }
59
+
60
+ this.controller = new ControllerClass(this.config);
61
+ this.controller.connect(host);
62
+
63
+ // Two-way bind: controller state ↔ model paths
64
+ const unbinders = [];
65
+ if (this.bind) {
66
+ for (const [stateKey, modelPath] of Object.entries(this.bind)) {
67
+ // Controller → model
68
+ if (this.controller.subscribe) {
69
+ const unsub = this.controller.subscribe(stateKey, (value) => {
70
+ ctx.setModel(modelPath, value);
71
+ });
72
+ if (unsub) unbinders.push(unsub);
73
+ }
74
+
75
+ // Model → controller (initial sync)
76
+ const initial = ctx.getModel(modelPath);
77
+ if (initial !== undefined && this.controller.setState) {
78
+ this.controller.setState(stateKey, initial);
79
+ }
80
+ }
81
+ }
82
+
83
+ host.controller = this.controller;
84
+
85
+ return () => {
86
+ host.controller = null;
87
+ unbinders.forEach(u => u());
88
+ };
89
+ }
90
+
91
+ undock() {
92
+ if (this.controller) {
93
+ this.controller.disconnect?.();
94
+ this.controller = null;
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * DataSourceDock — Fetches data and pushes it into the surface model.
3
+ *
4
+ * Supports refresh strategies: once, on-focus, interval:{ms}, stream.
5
+ * Re-fetch on demand via refetch() (used by refresh-source handler).
6
+ */
7
+ import { Dockable } from './base.js';
8
+
9
+ export class DataSourceDock extends Dockable {
10
+ kind = 'source';
11
+
12
+ /** @type {string} */
13
+ id;
14
+
15
+ /** @type {string} URI template, e.g., "resource://users/{userId}" */
16
+ uri;
17
+
18
+ /** @type {string} model path to write to */
19
+ path;
20
+
21
+ /** @type {string} refresh strategy */
22
+ refresh;
23
+
24
+ /** @type {Function} (uri, params) => data */
25
+ #resolveData;
26
+
27
+ /** @type {import('../surface.js').SurfaceContext|null} */
28
+ #ctx = null;
29
+
30
+ /**
31
+ * @param {object} decl — { id, uri, path, refresh? }
32
+ * @param {Function} resolveData — async (uri, params) => data
33
+ */
34
+ constructor(decl, resolveData) {
35
+ super();
36
+ this.id = decl.id;
37
+ this.uri = decl.uri;
38
+ this.path = decl.path;
39
+ this.refresh = decl.refresh || 'once';
40
+ this.#resolveData = resolveData;
41
+ }
42
+
43
+ dock(ctx) {
44
+ this.#ctx = ctx;
45
+
46
+ // Initial fetch
47
+ this.#fetch(ctx);
48
+
49
+ // Refresh strategy
50
+ if (this.refresh === 'on-focus') {
51
+ const handler = () => this.#fetch(ctx);
52
+ window.addEventListener('focus', handler);
53
+ return () => window.removeEventListener('focus', handler);
54
+ }
55
+
56
+ if (this.refresh.startsWith('interval:')) {
57
+ const ms = parseInt(this.refresh.split(':')[1], 10);
58
+ if (ms > 0) {
59
+ const id = setInterval(() => this.#fetch(ctx), ms);
60
+ return () => clearInterval(id);
61
+ }
62
+ }
63
+
64
+ if (this.refresh === 'stream') {
65
+ const resolvedUri = this.#resolveUri(ctx);
66
+ try {
67
+ const source = new EventSource(resolvedUri);
68
+ source.onmessage = (e) => {
69
+ try { ctx.setModel(this.path, JSON.parse(e.data)); }
70
+ catch { /* malformed data */ }
71
+ };
72
+ return () => source.close();
73
+ } catch {
74
+ console.warn(`DataSourceDock: stream failed for ${resolvedUri}`);
75
+ }
76
+ }
77
+ }
78
+
79
+ undock() {
80
+ this.#ctx = null;
81
+ }
82
+
83
+ /** Re-fetch on demand (called by refresh-source handler). */
84
+ refetch() {
85
+ if (this.#ctx) this.#fetch(this.#ctx);
86
+ }
87
+
88
+ async #fetch(ctx) {
89
+ const resolvedUri = this.#resolveUri(ctx);
90
+ try {
91
+ const data = await this.#resolveData(resolvedUri, ctx);
92
+ if (data !== undefined) ctx.setModel(this.path, data);
93
+ } catch (err) {
94
+ console.warn(`DataSourceDock: fetch failed for ${resolvedUri}`, err);
95
+ }
96
+ }
97
+
98
+ #resolveUri(ctx) {
99
+ return this.uri.replace(/\{(\w+)\}/g, (_, key) => {
100
+ return ctx.getParam(key) ?? ctx.getModel('/' + key) ?? '';
101
+ });
102
+ }
103
+ }
@@ -0,0 +1,6 @@
1
+ export { Dockable } from './base.js';
2
+ export { ControllerDock } from './controller.js';
3
+ export { DataSourceDock } from './data-source.js';
4
+ export { ActionDock, NANO_TO_DOM } from './action.js';
5
+ export { ProviderDock } from './provider.js';
6
+ export { LifecycleDock } from './lifecycle.js';
@@ -0,0 +1,84 @@
1
+ /**
2
+ * LifecycleDock — Runs actions on mount, unmount, and model changes.
3
+ *
4
+ * One per surface. Fires onMount actions immediately on dock,
5
+ * watches model paths for changes, and runs onUnmount on undock.
6
+ */
7
+ import { Dockable } from './base.js';
8
+
9
+ export class LifecycleDock extends Dockable {
10
+ kind = 'lifecycle';
11
+ id = 'lifecycle';
12
+
13
+ /** @type {Array} actions to run on mount */
14
+ onMount;
15
+
16
+ /** @type {Array} actions to run on unmount */
17
+ onUnmount;
18
+
19
+ /** @type {Array} model path watchers */
20
+ onModelChange;
21
+
22
+ /** @type {Function} (handlerName) => handlerFn */
23
+ #resolveHandler;
24
+
25
+ /** @type {import('../surface.js').SurfaceContext|null} */
26
+ #ctx = null;
27
+
28
+ /**
29
+ * @param {object} decl — { onMount?, onUnmount?, onModelChange? }
30
+ * @param {Function} resolveHandler — (name) => async (config, ctx) => result
31
+ */
32
+ constructor(decl, resolveHandler) {
33
+ super();
34
+ this.onMount = decl.onMount || [];
35
+ this.onUnmount = decl.onUnmount || [];
36
+ this.onModelChange = decl.onModelChange || [];
37
+ this.#resolveHandler = resolveHandler;
38
+ }
39
+
40
+ dock(ctx) {
41
+ this.#ctx = ctx;
42
+
43
+ // Run onMount actions
44
+ for (const action of this.onMount) {
45
+ this.#run(action, ctx);
46
+ }
47
+
48
+ // Set up model watchers
49
+ const unwatchers = this.onModelChange.map((watcher) => {
50
+ let handler = () => this.#run(watcher, ctx);
51
+
52
+ // Debounce if specified
53
+ if (watcher.debounce > 0) {
54
+ const origHandler = handler;
55
+ let timer;
56
+ handler = () => {
57
+ clearTimeout(timer);
58
+ timer = setTimeout(origHandler, watcher.debounce);
59
+ };
60
+ }
61
+
62
+ return ctx.watchModel(watcher.path, handler);
63
+ });
64
+
65
+ return () => unwatchers.forEach(u => u());
66
+ }
67
+
68
+ undock() {
69
+ if (this.#ctx) {
70
+ for (const action of this.onUnmount) {
71
+ this.#run(action, this.#ctx);
72
+ }
73
+ this.#ctx = null;
74
+ }
75
+ }
76
+
77
+ async #run(action, ctx) {
78
+ const fn = this.#resolveHandler(action.handler);
79
+ if (fn) {
80
+ try { await fn(action.config || {}, ctx); }
81
+ catch (err) { console.warn(`LifecycleDock: ${action.handler} failed`, err); }
82
+ }
83
+ }
84
+ }