@tmorrow/cre8-wc 2.0.7 → 2.0.8

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 (319) hide show
  1. package/a2ui/catalog +5 -5
  2. package/a2ui/catalog-kg.json +156 -20
  3. package/a2ui/catalog.json +393 -34
  4. package/a2ui/catalog.svg +2445 -2445
  5. package/a2ui/examples/compound-families.json +298 -0
  6. package/a2ui/examples/llm-observability.json +678 -650
  7. package/a2ui/generate-catalog.mjs +116 -3
  8. package/a2ui/inert-props.json +32 -0
  9. package/a2ui/render-audit.mjs +294 -0
  10. package/a2ui/renderer.d.ts +2 -1
  11. package/a2ui/renderer.js +1 -1
  12. package/a2ui/renderer.ts +1 -1
  13. package/a2ui/smoke-test.mjs +3 -3
  14. package/a2ui/stream/diff-test.mjs +299 -0
  15. package/a2ui/stream/diff.d.ts +28 -0
  16. package/a2ui/stream/diff.js +130 -0
  17. package/a2ui/stream/diff.ts +145 -0
  18. package/a2ui/stream/index.d.ts +11 -0
  19. package/a2ui/stream/index.js +11 -0
  20. package/a2ui/stream/index.ts +43 -0
  21. package/a2ui/stream/model.d.ts +66 -0
  22. package/a2ui/stream/model.js +429 -0
  23. package/a2ui/stream/model.ts +472 -0
  24. package/a2ui/stream/pointer.d.ts +34 -0
  25. package/a2ui/stream/pointer.js +146 -0
  26. package/a2ui/stream/pointer.ts +147 -0
  27. package/a2ui/stream/renderer.d.ts +51 -0
  28. package/a2ui/stream/renderer.js +282 -0
  29. package/a2ui/stream/renderer.ts +291 -0
  30. package/a2ui/stream/stream-test.mjs +592 -0
  31. package/a2ui/stream/types.d.ts +173 -0
  32. package/a2ui/stream/types.js +17 -0
  33. package/a2ui/stream/types.ts +127 -0
  34. package/cdn/cre8-wc.esm.js +3527 -3226
  35. package/cdn/cre8-wc.esm.js.map +1 -1
  36. package/cdn/cre8-wc.min.js +289 -289
  37. package/cdn/cre8-wc.min.js.map +1 -1
  38. package/dist/assets/{Changelog-Documentation-BguNswiM.js → Changelog-Documentation-CeOetLxK.js} +1 -1
  39. package/dist/assets/{Code-Guidelines-BM3dZyzL.js → Code-Guidelines-BjdezAjj.js} +1 -1
  40. package/dist/assets/{Color-6AOWCN3U-C4AEGNk3.js → Color-6AOWCN3U-DPFGZitI.js} +1 -1
  41. package/dist/assets/{Contributing-Guidelines-DZURVehh.js → Contributing-Guidelines-B1M2V1hW.js} +1 -1
  42. package/dist/assets/{DocsRenderer-JROSPFPF-DeZmCI9u.js → DocsRenderer-JROSPFPF-BBy8KWNl.js} +1 -1
  43. package/dist/assets/{Tokens-Documentation-ZecGbtQg.js → Tokens-Documentation-CdTxFDLe.js} +1 -1
  44. package/dist/assets/{WithTooltip-7X4HQR7L-2Hfrkir-.js → WithTooltip-7X4HQR7L-DZzTNMQ7.js} +1 -1
  45. package/dist/assets/{accordion-item.stories-D-MjrX5G.js → accordion-item.stories-Bl26JlHp.js} +1 -9
  46. package/dist/assets/{accordion.stories-icgNa1dl.js → accordion.stories-DjoLApQw.js} +3 -11
  47. package/dist/assets/{alert.stories-BzDaXtj-.js → alert.stories-pO1y3YCQ.js} +15 -31
  48. package/dist/assets/{badge-C5wOWgyg.js → badge-BTxW3bN2.js} +3 -11
  49. package/dist/assets/{badge.stories-5GfB4jVI.js → badge.stories-vqh63RJ2.js} +1 -1
  50. package/dist/assets/{band.stories-DhXaP_kL.js → band.stories-CjKRppSb.js} +1 -9
  51. package/dist/assets/{blocks-DhUVut8Z.js → blocks-1be_-L6v.js} +5 -5
  52. package/dist/assets/{breadcrumbs.stories-CrPUBVk1.js → breadcrumbs.stories-Doyfy3V9.js} +2 -18
  53. package/dist/assets/{button-CJL8yzAT.js → button-CgaWukz0.js} +1 -9
  54. package/dist/assets/{button-group-BgwgtSFC.js → button-group-G7qN4MwM.js} +1 -9
  55. package/dist/assets/{button-group.stories-W-07gO63.js → button-group.stories-cL3Kay6M.js} +1 -1
  56. package/dist/assets/{button.stories-BPzJ-sCv.js → button.stories-C9HSpxWb.js} +6 -6
  57. package/dist/assets/{card.stories-mlFGY2Xn.js → card.stories-BbU8YymD.js} +3 -11
  58. package/dist/assets/{chart.stories-C8yuHHeK.js → chart.stories-BL4FxIA_.js} +1 -1
  59. package/dist/assets/{checkbox-field-item-iHcdmTNw.js → checkbox-field-item-DIMHcWM0.js} +1 -9
  60. package/dist/assets/{checkbox-field-item.stories-D1aVLDXn.js → checkbox-field-item.stories-XbB4x_lO.js} +1 -1
  61. package/dist/assets/{checkbox-field.stories-BoVB2jCx.js → checkbox-field.stories-YnqFUI4K.js} +2 -10
  62. package/dist/assets/{cre8-element-DfmMtHJO.js → cre8-element-B35i4Lyg.js} +1 -1
  63. package/dist/assets/{cre8-form-element-bQpK8UYN.js → cre8-form-element-Cfc5VeYV.js} +1 -1
  64. package/dist/assets/{danger-button.stories-Cb4ljnhQ.js → danger-button.stories-xh25hmfd.js} +1 -9
  65. package/dist/assets/{date-picker.stories-Cje3qk8D.js → date-picker.stories-DD_ctzEF.js} +1 -49
  66. package/dist/assets/{divider-B_PXBGWD.js → divider-xZ2KARHf.js} +2 -10
  67. package/dist/assets/{divider.stories-CtfeBqVV.js → divider.stories-Bk9oF-OV.js} +1 -1
  68. package/dist/assets/{dropdown-Cgwne34I.js → dropdown-BEP5x3CW.js} +6 -22
  69. package/dist/assets/{dropdown-item.stories-pXkDLRuv.js → dropdown-item.stories-Iaw_UrEP.js} +1 -1
  70. package/dist/assets/{dropdown.stories-DZnmHieY.js → dropdown.stories-B0OlKD7h.js} +1 -1
  71. package/dist/assets/{example-drug-card.stories-DTzLXTFx.js → example-drug-card.stories-Bp5JIeE_.js} +1 -1
  72. package/dist/assets/{f-po-C2WpbOFJ.js → f-po-BdPzDRD-.js} +1 -1
  73. package/dist/assets/{feature.stories-DffXdJch.js → feature.stories-DYE1Js70.js} +1 -9
  74. package/dist/assets/{field-DzYRqQb2.js → field-BpUYyRW1.js} +1 -9
  75. package/dist/assets/{field-note-DKXZiXLU.js → field-note-fccBckVl.js} +3 -11
  76. package/dist/assets/{field-note.stories-DS_0bQul.js → field-note.stories-BH9AZMbF.js} +1 -1
  77. package/dist/assets/{field.stories-BvXn0oG6.js → field.stories-BQPtmziK.js} +1 -1
  78. package/dist/assets/{footer.stories-C3ZibisU.js → footer.stories-DCWEciqD.js} +1 -9
  79. package/dist/assets/{form-example.stories-C-TuOeF2.js → form-example.stories-9IDC0AgX.js} +1 -1
  80. package/dist/assets/{formatter-L2YTDE3Q-CJVnxOUW.js → formatter-L2YTDE3Q-B9u1AOWn.js} +1 -1
  81. package/dist/assets/{global-nav-item-xQL7wVjY.js → global-nav-item-T4htN-yO.js} +6 -14
  82. package/dist/assets/{global-nav-item.stories-Dp9TE3aR.js → global-nav-item.stories-2dWRfCXv.js} +1 -1
  83. package/dist/assets/{global-nav.stories-B5Nk8JZ0.js → global-nav.stories-Fh1gScqg.js} +2 -10
  84. package/dist/assets/{grid-DYgnZBsd.js → grid-C5CKMXNe.js} +3 -19
  85. package/dist/assets/{grid.stories-BFiXTq2C.js → grid.stories-BLmCNdeA.js} +1 -1
  86. package/dist/assets/{header.stories-D1f7xhjV.js → header.stories-BkDrjJtj.js} +1 -9
  87. package/dist/assets/{heading-485Jz7JZ.js → heading-Dbka33DK.js} +2 -10
  88. package/dist/assets/{heading.stories-gPF_SmTc.js → heading.stories-Be40_bmG.js} +1 -1
  89. package/dist/assets/{hero.stories-BHlFNdvF.js → hero.stories-vRu7PZG9.js} +1 -9
  90. package/dist/assets/{icon-DeTLDzTS.js → icon-ChfRWXWy.js} +2 -10
  91. package/dist/assets/{icon-description-o-YaiEjK.js → icon-description-BBSwDykJ.js} +1 -1
  92. package/dist/assets/{icon-description.stories-BdPRvEwe.js → icon-description.stories-Cg6ekOme.js} +1 -1
  93. package/dist/assets/{icon.stories-BxWpqxT5.js → icon.stories-Cj4U7L5G.js} +1 -1
  94. package/dist/assets/if-defined-Bxnzk64Q.js +1 -0
  95. package/dist/assets/{iframe-dHvya7sk.js → iframe-BNJP6ovU.js} +35 -35
  96. package/dist/assets/{inline-alert.stories-FH0bQ0jh.js → inline-alert.stories-CygBYI02.js} +1 -9
  97. package/dist/assets/{layout-container.stories-D6Z6Kx78.js → layout-container.stories-TMyIJteJ.js} +2 -10
  98. package/dist/assets/{layout.stories-CNYuwC_r.js → layout.stories-ylRM-ANL.js} +7 -23
  99. package/dist/assets/{linelength-container.stories-pCRXZvxS.js → linelength-container.stories-Br2v8jXE.js} +1 -9
  100. package/dist/assets/{link-BpCiLxNW.js → link-CRE0Eqdo.js} +1 -9
  101. package/dist/assets/{link-list.stories-12vsAa1P.js → link-list.stories--y-urrVo.js} +7 -23
  102. package/dist/assets/{link.stories-DAoQtY4_.js → link.stories-C3WQOgkY.js} +2 -2
  103. package/dist/assets/{list.stories-D0N3yBIf.js → list.stories-Bd2bxkxn.js} +7 -23
  104. package/dist/assets/{loading-spinner-g6iJajXH.js → loading-spinner-C52KNq6y.js} +4 -12
  105. package/dist/assets/{loading-spinner.stories-B6_mgPxB.js → loading-spinner.stories-DPRGEeHT.js} +1 -1
  106. package/dist/assets/{logo.stories-BvMwN2qg.js → logo.stories-2LBqqraT.js} +1 -9
  107. package/dist/assets/{main.stories-pL4zefbs.js → main.stories-BQzD7iWD.js} +2 -10
  108. package/dist/assets/{medication-card.stories-DK1XGJic.js → medication-card.stories-Wc-hA0-s.js} +5 -5
  109. package/dist/assets/{medication-form.stories-Bj5dLp5S.js → medication-form.stories-DfFOCDaU.js} +1 -1
  110. package/dist/assets/{modal-CO0M4e_8.js → modal-CCfbY4fF.js} +1 -9
  111. package/dist/assets/{modal-BNu8xy08.js → modal-GglWRNJp.js} +1 -1
  112. package/dist/assets/{modal.stories-CHYBrq_E.js → modal.stories-CpybCs79.js} +1 -1
  113. package/dist/assets/{multi-select.stories-C9XXsWio.js → multi-select.stories-BhzEKRui.js} +1 -9
  114. package/dist/assets/{nav-container.stories-DU9fhvDu.js → nav-container.stories-Be1YlegP.js} +3 -11
  115. package/dist/assets/{page-header.stories-BrstKiEY.js → page-header.stories-BOVLQ0YF.js} +1 -9
  116. package/dist/assets/{pagination.stories-Bw2M2iOn.js → pagination.stories-D62sa_1K.js} +9 -25
  117. package/dist/assets/{percent-bar.stories-UQRXYUqd.js → percent-bar.stories-CYi4El7T.js} +1 -9
  118. package/dist/assets/{popover.stories-ZkwrRFpR.js → popover.stories-B9O8F4yv.js} +1 -9
  119. package/dist/assets/{primary-nav.stories-wqOKwgQn.js → primary-nav.stories-Bt-o7h45.js} +1 -17
  120. package/dist/assets/{progress-meter-TzASasu0.js → progress-meter-Dit59091.js} +1 -9
  121. package/dist/assets/{progress-meter.stories-qfJALZf8.js → progress-meter.stories-CYnOCmjo.js} +1 -1
  122. package/dist/assets/{progress-steps-item-KvW1d_7L.js → progress-steps-item-CWJsad0s.js} +1 -9
  123. package/dist/assets/{progress-steps-item.stories-uOn6tJ1W.js → progress-steps-item.stories-ePn_6bPn.js} +1 -1
  124. package/dist/assets/{progress-steps.stories-CKFPx8D0.js → progress-steps.stories-CblrEcXF.js} +1 -9
  125. package/dist/assets/{radio-field-item-CTaR50XR.js → radio-field-item-Bm-0RWPe.js} +5 -21
  126. package/dist/assets/{radio-field-item.stories-DQSLj8W1.js → radio-field-item.stories-y_TrTRIW.js} +1 -1
  127. package/dist/assets/{radio-field.stories-Btmc_Iep.js → radio-field.stories-CSWrbUrn.js} +1 -1
  128. package/dist/assets/{remove-tag-BSEZ7VT8.js → remove-tag-lCr57c5r.js} +1 -9
  129. package/dist/assets/{remove-tag.stories-diRKi7Ua.js → remove-tag.stories-CDfwCdvZ.js} +1 -1
  130. package/dist/assets/{request-prescription.stories-DQvra7ia.js → request-prescription.stories-O4zqokfb.js} +1 -1
  131. package/dist/assets/{sample-modal.stories-deE1EBfZ.js → sample-modal.stories-BZ4N2R2Z.js} +1 -1
  132. package/dist/assets/{section.stories-DF4mcy2O.js → section.stories-D_1InThX.js} +1 -9
  133. package/dist/assets/{select-tile-D-C8oSrm.js → select-tile-BqqB3ZtE.js} +2 -10
  134. package/dist/assets/{select-tile-list.stories-vsBQUIcl.js → select-tile-list.stories-Di4ILgV8.js} +1 -9
  135. package/dist/assets/{select-tile.stories-CqHzN5fc.js → select-tile.stories-D3h_6zlV.js} +6 -6
  136. package/dist/assets/{select.stories-8aOGxTtr.js → select.stories-BB2phP9A.js} +1 -9
  137. package/dist/assets/{skeleton-loader.stories-CwR2-aC5.js → skeleton-loader.stories-y4uml_kV.js} +5 -13
  138. package/dist/assets/{split-button.stories-CyfdrK4u.js → split-button.stories-C_82I4ME.js} +2 -10
  139. package/dist/assets/{spread-BPiNgQQF.js → spread-CnPic3C2.js} +1 -1
  140. package/dist/assets/state-DkQhleoO.js +1 -0
  141. package/dist/assets/{submenu.stories-CDhNzZzh.js → submenu.stories-UDtaREr1.js} +2 -18
  142. package/dist/assets/{syntaxhighlighter-T5IQBZDB-BzI6WxUR.js → syntaxhighlighter-T5IQBZDB-D-I_s_yD.js} +1 -1
  143. package/dist/assets/{table-header-CfcchoYz.js → table-header-2837i43H.js} +3 -51
  144. package/dist/assets/{table-object.stories-Bd5qdfMU.js → table-object.stories-D4KoI-wA.js} +1 -9
  145. package/dist/assets/{table.stories-DxuBe9dJ.js → table.stories-DUJDibEp.js} +1 -1
  146. package/dist/assets/{tabs.stories-Cpc3OHJx.js → tabs.stories-C06SngOF.js} +5 -29
  147. package/dist/assets/{tag-list.stories-BmyCmrTF.js → tag-list.stories-Du-IoYzu.js} +2 -10
  148. package/dist/assets/{tag-vQFuZneb.js → tag-oHGdclJl.js} +1 -9
  149. package/dist/assets/{tag.stories-DGzrNUbb.js → tag.stories-C5D5IbuK.js} +1 -1
  150. package/dist/assets/{tertiary-nav.stories-D4q5K-am.js → tertiary-nav.stories-B1GU8Zi4.js} +3 -19
  151. package/dist/assets/{text-link-4qLRIeJB.js → text-link-B3m3KEqY.js} +1 -9
  152. package/dist/assets/{text-link.stories-D6BRm2I5.js → text-link.stories-4O6qn82H.js} +1 -1
  153. package/dist/assets/{text-passage-DGaI5i2I.js → text-passage-xQVosjOr.js} +3 -19
  154. package/dist/assets/{text-passage.stories-DkmXVUhH.js → text-passage.stories-Da1nspwG.js} +1 -1
  155. package/dist/assets/{tooltip.stories-B7ADDq7o.js → tooltip.stories-DLKyyeKn.js} +6 -14
  156. package/dist/assets/{utility-nav.stories-ffXVvyLp.js → utility-nav.stories-B6xBFe7z.js} +5 -21
  157. package/dist/design-tokens/brands/cre8/css/tokens_brand.css +1 -1
  158. package/dist/design-tokens/core/scss/theming/component.css +1 -1
  159. package/dist/design-tokens/core/scss/theming/variables.css +1 -7
  160. package/dist/design-tokens/core/scss/theming/variables.scss +0 -11
  161. package/dist/icons/cre8-icons.svg +1 -1
  162. package/dist/iframe.html +1 -24
  163. package/dist/index.html +25 -77
  164. package/dist/project.json +1 -1
  165. package/lib/a2ui/renderer.d.ts +2 -1
  166. package/lib/a2ui/renderer.d.ts.map +1 -1
  167. package/lib/a2ui/renderer.js +1 -1
  168. package/lib/a2ui/renderer.js.map +1 -1
  169. package/lib/a2ui/stream/diff.d.ts +29 -0
  170. package/lib/a2ui/stream/diff.d.ts.map +1 -0
  171. package/lib/a2ui/stream/diff.js +131 -0
  172. package/lib/a2ui/stream/diff.js.map +1 -0
  173. package/lib/a2ui/stream/index.d.ts +12 -0
  174. package/lib/a2ui/stream/index.d.ts.map +1 -0
  175. package/lib/a2ui/stream/index.js +12 -0
  176. package/lib/a2ui/stream/index.js.map +1 -0
  177. package/lib/a2ui/stream/model.d.ts +67 -0
  178. package/lib/a2ui/stream/model.d.ts.map +1 -0
  179. package/lib/a2ui/stream/model.js +423 -0
  180. package/lib/a2ui/stream/model.js.map +1 -0
  181. package/lib/a2ui/stream/pointer.d.ts +35 -0
  182. package/lib/a2ui/stream/pointer.d.ts.map +1 -0
  183. package/lib/a2ui/stream/pointer.js +147 -0
  184. package/lib/a2ui/stream/pointer.js.map +1 -0
  185. package/lib/a2ui/stream/renderer.d.ts +52 -0
  186. package/lib/a2ui/stream/renderer.d.ts.map +1 -0
  187. package/lib/a2ui/stream/renderer.js +279 -0
  188. package/lib/a2ui/stream/renderer.js.map +1 -0
  189. package/lib/a2ui/stream/types.d.ts +174 -0
  190. package/lib/a2ui/stream/types.d.ts.map +1 -0
  191. package/lib/a2ui/stream/types.js +18 -0
  192. package/lib/a2ui/stream/types.js.map +1 -0
  193. package/lib/components/accordion/accordion.d.ts +15 -0
  194. package/lib/components/accordion/accordion.d.ts.map +1 -1
  195. package/lib/components/accordion/accordion.js +23 -0
  196. package/lib/components/accordion/accordion.js.map +1 -1
  197. package/lib/components/badge/badge.d.ts +4 -17
  198. package/lib/components/badge/badge.d.ts.map +1 -1
  199. package/lib/components/badge/badge.js +0 -15
  200. package/lib/components/badge/badge.js.map +1 -1
  201. package/lib/components/breadcrumbs/breadcrumbs.d.ts +14 -0
  202. package/lib/components/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  203. package/lib/components/breadcrumbs/breadcrumbs.js +21 -0
  204. package/lib/components/breadcrumbs/breadcrumbs.js.map +1 -1
  205. package/lib/components/chart/chart.d.ts +3 -3
  206. package/lib/components/chart/chart.js +6 -6
  207. package/lib/components/chart/chart.js.map +1 -1
  208. package/lib/components/checkbox-field/checkbox-field.d.ts +19 -0
  209. package/lib/components/checkbox-field/checkbox-field.d.ts.map +1 -1
  210. package/lib/components/checkbox-field/checkbox-field.js +28 -0
  211. package/lib/components/checkbox-field/checkbox-field.js.map +1 -1
  212. package/lib/components/cre8-element.d.ts +19 -0
  213. package/lib/components/cre8-element.d.ts.map +1 -1
  214. package/lib/components/cre8-element.js +51 -2
  215. package/lib/components/cre8-element.js.map +1 -1
  216. package/lib/components/divider/divider.d.ts +1 -1
  217. package/lib/components/divider/divider.d.ts.map +1 -1
  218. package/lib/components/divider/divider.js.map +1 -1
  219. package/lib/components/dropdown/dropdown.d.ts +13 -0
  220. package/lib/components/dropdown/dropdown.d.ts.map +1 -1
  221. package/lib/components/dropdown/dropdown.js +19 -0
  222. package/lib/components/dropdown/dropdown.js.map +1 -1
  223. package/lib/components/dropdown-item/dropdown-item.d.ts +1 -1
  224. package/lib/components/dropdown-item/dropdown-item.js +2 -2
  225. package/lib/components/dropdown-item/dropdown-item.js.map +1 -1
  226. package/lib/components/heading/heading.d.ts +3 -5
  227. package/lib/components/heading/heading.d.ts.map +1 -1
  228. package/lib/components/heading/heading.js +2 -4
  229. package/lib/components/heading/heading.js.map +1 -1
  230. package/lib/components/link-list/link-list.d.ts +19 -0
  231. package/lib/components/link-list/link-list.d.ts.map +1 -1
  232. package/lib/components/link-list/link-list.js +19 -0
  233. package/lib/components/link-list/link-list.js.map +1 -1
  234. package/lib/components/list/list.d.ts +13 -0
  235. package/lib/components/list/list.d.ts.map +1 -1
  236. package/lib/components/list/list.js +15 -0
  237. package/lib/components/list/list.js.map +1 -1
  238. package/lib/components/modal/modal.d.ts +2 -2
  239. package/lib/components/modal/modal.js +2 -2
  240. package/lib/components/modal/modal.js.map +1 -1
  241. package/lib/components/multi-select/multi-select.d.ts +2 -2
  242. package/lib/components/multi-select/multi-select.js +5 -5
  243. package/lib/components/multi-select/multi-select.js.map +1 -1
  244. package/lib/components/pagination/pagination.d.ts +1 -1
  245. package/lib/components/pagination/pagination.js +2 -2
  246. package/lib/components/pagination/pagination.js.map +1 -1
  247. package/lib/components/percent-bar/percent-bar.d.ts +2 -0
  248. package/lib/components/percent-bar/percent-bar.d.ts.map +1 -1
  249. package/lib/components/percent-bar/percent-bar.js +3 -1
  250. package/lib/components/percent-bar/percent-bar.js.map +1 -1
  251. package/lib/components/popover/popover.d.ts +6 -7
  252. package/lib/components/popover/popover.d.ts.map +1 -1
  253. package/lib/components/popover/popover.js +4 -4
  254. package/lib/components/popover/popover.js.map +1 -1
  255. package/lib/components/progress-meter/progress-meter.d.ts +0 -8
  256. package/lib/components/progress-meter/progress-meter.d.ts.map +1 -1
  257. package/lib/components/progress-meter/progress-meter.js +0 -7
  258. package/lib/components/progress-meter/progress-meter.js.map +1 -1
  259. package/lib/components/progress-steps/progress-steps.d.ts +16 -0
  260. package/lib/components/progress-steps/progress-steps.d.ts.map +1 -1
  261. package/lib/components/progress-steps/progress-steps.js +25 -0
  262. package/lib/components/progress-steps/progress-steps.js.map +1 -1
  263. package/lib/components/progress-steps-item/progress-steps-item.d.ts +1 -3
  264. package/lib/components/progress-steps-item/progress-steps-item.d.ts.map +1 -1
  265. package/lib/components/progress-steps-item/progress-steps-item.js +0 -1
  266. package/lib/components/progress-steps-item/progress-steps-item.js.map +1 -1
  267. package/lib/components/radio-field/radio-field.d.ts +33 -0
  268. package/lib/components/radio-field/radio-field.d.ts.map +1 -1
  269. package/lib/components/radio-field/radio-field.js +62 -0
  270. package/lib/components/radio-field/radio-field.js.map +1 -1
  271. package/lib/components/remove-tag/remove-tag.d.ts +1 -1
  272. package/lib/components/remove-tag/remove-tag.js +3 -3
  273. package/lib/components/remove-tag/remove-tag.js.map +1 -1
  274. package/lib/components/split-button/split-button.d.ts +3 -0
  275. package/lib/components/split-button/split-button.d.ts.map +1 -1
  276. package/lib/components/split-button/split-button.js +5 -2
  277. package/lib/components/split-button/split-button.js.map +1 -1
  278. package/lib/components/tab/tab.d.ts +1 -1
  279. package/lib/components/tab/tab.js +3 -3
  280. package/lib/components/tab/tab.js.map +1 -1
  281. package/lib/components/table/table.d.ts +36 -0
  282. package/lib/components/table/table.d.ts.map +1 -1
  283. package/lib/components/table/table.js +55 -0
  284. package/lib/components/table/table.js.map +1 -1
  285. package/lib/components/tabs/tabs.d.ts +20 -3
  286. package/lib/components/tabs/tabs.d.ts.map +1 -1
  287. package/lib/components/tabs/tabs.js +33 -5
  288. package/lib/components/tabs/tabs.js.map +1 -1
  289. package/lib/components/tag-list/tag-list.d.ts +17 -0
  290. package/lib/components/tag-list/tag-list.d.ts.map +1 -1
  291. package/lib/components/tag-list/tag-list.js +25 -0
  292. package/lib/components/tag-list/tag-list.js.map +1 -1
  293. package/lib/components/tooltip/tooltip.d.ts +2 -2
  294. package/lib/components/tooltip/tooltip.js +4 -4
  295. package/lib/components/tooltip/tooltip.js.map +1 -1
  296. package/lib/components/utils/light-children.d.ts +40 -0
  297. package/lib/components/utils/light-children.d.ts.map +1 -0
  298. package/lib/components/utils/light-children.js +100 -0
  299. package/lib/components/utils/light-children.js.map +1 -0
  300. package/lib/directives/if-truthy.d.ts +1 -1
  301. package/lib/light-children-TlEXev5S.js +39 -0
  302. package/lib/scripts/generate-react-wrappers.d.ts +8 -1
  303. package/lib/scripts/generate-react-wrappers.d.ts.map +1 -1
  304. package/lib/scripts/generate-react-wrappers.js +45 -1
  305. package/lib/scripts/generate-react-wrappers.js.map +1 -1
  306. package/mcp-manifest.json +162 -52
  307. package/package.json +11 -4
  308. package/react-manifest.json +153 -47
  309. package/dist/assets/if-defined-HKKhGupN.js +0 -1
  310. package/dist/assets/iframe-CWwoGI65.css +0 -1
  311. package/dist/assets/state-CfuknrX8.js +0 -1
  312. package/dist/fonts/PlusJakartaSans-Bold.woff2 +0 -0
  313. package/dist/fonts/PlusJakartaSans-Medium.woff2 +0 -0
  314. package/dist/fonts/PlusJakartaSans-Regular.woff2 +0 -0
  315. package/dist/fonts/PlusJakartaSans-SemiBold.woff2 +0 -0
  316. package/dist/logo.svg +0 -1
  317. package/dist/sb-addons/storybook-4/manager-bundle.js +0 -8
  318. /package/dist/icons/{express-scripts copy.svg → pharmacy copy.svg} +0 -0
  319. /package/dist/icons/{express-scripts.svg → pharmacy.svg} +0 -0
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Tests for the spec differ.
3
+ *
4
+ * npx tsx a2ui/stream/diff-test.mjs
5
+ *
6
+ * The load-bearing test is the round trip: for every ordered pair of shipped
7
+ * example specs, applying `diffSpecs(a, b)` to a surface holding `a` must
8
+ * produce exactly `b`. A differ that is merely plausible passes unit tests; only
9
+ * the round trip catches an op that addresses the wrong index.
10
+ */
11
+
12
+ import { readFileSync, readdirSync } from 'node:fs';
13
+ import { fileURLToPath } from 'node:url';
14
+ import { dirname, join, resolve } from 'node:path';
15
+ import { JSDOM } from 'jsdom';
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const WC = resolve(__dirname, '../..');
19
+ const catalogJson = JSON.parse(readFileSync(resolve(WC, 'a2ui/catalog.json'), 'utf8'));
20
+
21
+ const dom = new JSDOM('<!doctype html><html><body></body></html>');
22
+ globalThis.document = dom.window.document;
23
+ globalThis.HTMLElement = dom.window.HTMLElement;
24
+
25
+ const { registerCatalog } = await import('../index.ts');
26
+ const { SurfaceModel, SurfaceRenderer, diffSpecs } = await import('./index.ts');
27
+ const catalog = registerCatalog(catalogJson);
28
+
29
+ let passed = 0;
30
+ const failures = [];
31
+
32
+ function test(name, fn) {
33
+ try {
34
+ fn();
35
+ passed++;
36
+ console.log(` ok ${name}`);
37
+ } catch (err) {
38
+ failures.push(name);
39
+ console.log(`FAIL ${name}\n ${err.message}`);
40
+ }
41
+ }
42
+
43
+ function assert(cond, message) {
44
+ if (!cond) throw new Error(message ?? 'assertion failed');
45
+ }
46
+
47
+ function assertEqual(actual, expected, message) {
48
+ if (actual !== expected) {
49
+ throw new Error(`${message ?? 'not equal'}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
50
+ }
51
+ }
52
+
53
+ /** Apply a diff through the real model, so ops face real validation. */
54
+ function applyDiff(prev, next) {
55
+ const model = new SurfaceModel(catalog, { surfaceId: 's' });
56
+ model.apply({
57
+ v: 1,
58
+ type: 'surface.create',
59
+ surfaceId: 's',
60
+ seq: 0,
61
+ catalogId: catalog.id,
62
+ root: prev ?? undefined,
63
+ });
64
+ const ops = diffSpecs(prev, next);
65
+ if (ops.length) {
66
+ model.apply({ v: 1, type: 'surface.patch', surfaceId: 's', seq: 1, ops });
67
+ }
68
+ return { ops, root: model.root };
69
+ }
70
+
71
+ /**
72
+ * Key order carries no meaning in a spec, and `setProps` merges into an existing
73
+ * object — so a correctly patched tree serialises with its keys in the original
74
+ * order, not the target's. Comparing raw JSON.stringify reports that as a
75
+ * failure. Sort first.
76
+ */
77
+ function canonical(value) {
78
+ if (Array.isArray(value)) return value.map(canonical);
79
+ if (value && typeof value === 'object') {
80
+ return Object.fromEntries(Object.keys(value).sort().map((k) => [k, canonical(value[k])]));
81
+ }
82
+ return value;
83
+ }
84
+
85
+ function roundTrip(prev, next, label) {
86
+ const { ops, root } = applyDiff(prev, next);
87
+ const got = JSON.stringify(canonical(root ?? null));
88
+ const want = JSON.stringify(canonical(next ?? null));
89
+ if (got !== want) {
90
+ throw new Error(
91
+ `${label}: diff did not reproduce the target\n ops: ${JSON.stringify(ops)}\n got: ${got.slice(0, 300)}\n want: ${want.slice(0, 300)}`
92
+ );
93
+ }
94
+ return ops;
95
+ }
96
+
97
+ const container = (children) => ({ component: 'cre8-layout-container', children });
98
+ const heading = (text, props = {}) => ({ component: 'cre8-heading', props, children: [text] });
99
+
100
+ // ─── the properties that matter ─────────────────────────────────────────────
101
+
102
+ test('an unchanged tree costs nothing', () => {
103
+ const tree = container([heading('One'), heading('Two')]);
104
+ const ops = diffSpecs(tree, JSON.parse(JSON.stringify(tree)));
105
+ assertEqual(ops.length, 0, 'resending an identical spec must be free');
106
+ });
107
+
108
+ test('a changed prop becomes setProps, not a replacement', () => {
109
+ const prev = container([{ component: 'cre8-button', props: { text: 'Save', variant: 'primary' } }]);
110
+ const next = container([{ component: 'cre8-button', props: { text: 'Save', variant: 'secondary' } }]);
111
+ const ops = roundTrip(prev, next, 'prop change');
112
+ assertEqual(ops.length, 1);
113
+ assertEqual(ops[0].op, 'setProps', 'the element must survive, so its focus and animation do');
114
+ assertEqual(ops[0].path, '$.children[0]');
115
+ assert(!('text' in ops[0].props), 'only what changed should be sent');
116
+ });
117
+
118
+ test('a dropped prop is sent as null', () => {
119
+ const prev = container([{ component: 'cre8-button', props: { text: 'Save', variant: 'primary' } }]);
120
+ const next = container([{ component: 'cre8-button', props: { text: 'Save' } }]);
121
+ const ops = roundTrip(prev, next, 'prop removal');
122
+ assertEqual(ops[0].props.variant, null);
123
+ });
124
+
125
+ test('changed text becomes setText rather than a rebuild', () => {
126
+ const prev = container([heading('Before')]);
127
+ const next = container([heading('After')]);
128
+ const ops = roundTrip(prev, next, 'text change');
129
+ assertEqual(ops.length, 1);
130
+ assertEqual(ops[0].op, 'setText');
131
+ assertEqual(ops[0].text, 'After');
132
+ });
133
+
134
+ test('a new trailing child is a single append', () => {
135
+ const prev = container([heading('One')]);
136
+ const next = container([heading('One'), heading('Two')]);
137
+ const ops = roundTrip(prev, next, 'append');
138
+ assertEqual(ops.length, 1);
139
+ assertEqual(ops[0].op, 'append');
140
+ assertEqual(ops[0].nodes.length, 1);
141
+ });
142
+
143
+ test('a dropped trailing child is a single remove', () => {
144
+ const prev = container([heading('One'), heading('Two')]);
145
+ const next = container([heading('One')]);
146
+ const ops = roundTrip(prev, next, 'remove');
147
+ assertEqual(ops.length, 1);
148
+ assertEqual(ops[0].op, 'remove');
149
+ assertEqual(ops[0].path, '$.children[1]');
150
+ });
151
+
152
+ test('several dropped children are removed back to front', () => {
153
+ const prev = container([heading('a'), heading('b'), heading('c')]);
154
+ const next = container([heading('a')]);
155
+ const ops = roundTrip(prev, next, 'multi remove');
156
+ assertEqual(ops.map((o) => o.path).join(','), '$.children[2],$.children[1]',
157
+ 'removing front-first would renumber the siblings still to be removed');
158
+ });
159
+
160
+ test('a different component at the same position is replaced', () => {
161
+ const prev = container([heading('One')]);
162
+ const next = container([{ component: 'cre8-text-passage', children: ['One'] }]);
163
+ const ops = roundTrip(prev, next, 'type change');
164
+ assertEqual(ops[0].op, 'replace');
165
+ });
166
+
167
+ test('slots are diffed independently of children', () => {
168
+ const prev = container([
169
+ { component: 'cre8-card', slots: { header: [heading('H')], default: [{ component: 'cre8-text-passage', children: ['Body'] }] } },
170
+ ]);
171
+ const next = container([
172
+ { component: 'cre8-card', slots: { header: [heading('H2')], default: [{ component: 'cre8-text-passage', children: ['Body'] }] } },
173
+ ]);
174
+ const ops = roundTrip(prev, next, 'slot change');
175
+ assertEqual(ops.length, 1, 'only the header changed');
176
+ assert(ops[0].path.includes('slots.header'), `expected a header path, got ${ops[0].path}`);
177
+ });
178
+
179
+ test('a removed slot is cleared', () => {
180
+ const prev = container([{ component: 'cre8-card', slots: { header: [heading('H')], default: [heading('B')] } }]);
181
+ const next = container([{ component: 'cre8-card', slots: { default: [heading('B')] } }]);
182
+ roundTrip(prev, next, 'slot removal');
183
+ });
184
+
185
+ test('event bindings are added, changed, and removed', () => {
186
+ const button = (events) => container([{ component: 'cre8-button', props: { text: 'Go' }, ...(events ? { events } : {}) }]);
187
+ roundTrip(button(null), button({ click: 'go' }), 'add event');
188
+ roundTrip(button({ click: 'go' }), button({ click: 'went' }), 'change event');
189
+ const ops = roundTrip(button({ click: 'go' }), button(null), 'remove event');
190
+ assertEqual(ops[0].events.click, null);
191
+ });
192
+
193
+ test('nested change touches only the node that changed', () => {
194
+ const build = (label) => container([
195
+ { component: 'cre8-card', slots: { footer: [{ component: 'cre8-button', props: { text: label } }] } },
196
+ ]);
197
+ const ops = roundTrip(build('Old'), build('New'), 'nested');
198
+ assertEqual(ops.length, 1);
199
+ assertEqual(ops[0].path, '$.children[0].slots.footer[0]');
200
+ });
201
+
202
+ test('a null target clears the surface; a new root replaces it', () => {
203
+ assertEqual(diffSpecs(container([]), null)[0].op, 'remove');
204
+ assertEqual(diffSpecs(null, container([]))[0].op, 'replace');
205
+ assertEqual(diffSpecs(null, null).length, 0);
206
+ });
207
+
208
+ test('a different root component is a root replace', () => {
209
+ const ops = diffSpecs(container([]), { component: 'cre8-grid' });
210
+ assertEqual(ops.length, 1);
211
+ assertEqual(ops[0].path, '$');
212
+ assertEqual(ops[0].op, 'replace');
213
+ });
214
+
215
+ // ─── the round trip, over real specs ────────────────────────────────────────
216
+
217
+ const examplesDir = resolve(WC, 'a2ui/examples');
218
+ const examples = readdirSync(examplesDir)
219
+ .filter((f) => f.endsWith('.json'))
220
+ .map((f) => ({ name: f, spec: JSON.parse(readFileSync(join(examplesDir, f), 'utf8')) }));
221
+
222
+ test(`every ordered pair of the ${examples.length} shipped examples round-trips`, () => {
223
+ let pairs = 0;
224
+ for (const from of examples) {
225
+ for (const to of examples) {
226
+ roundTrip(from.spec, to.spec, `${from.name} → ${to.name}`);
227
+ pairs++;
228
+ }
229
+ }
230
+ assert(pairs >= 25, `expected at least 25 pairs, ran ${pairs}`);
231
+ });
232
+
233
+ test('diffing a real spec against a small edit of itself stays small', () => {
234
+ const source = examples.find((e) => e.name === 'compound-families.json') ?? examples[0];
235
+ const edited = JSON.parse(JSON.stringify(source.spec));
236
+ // Change one leaf deep in the tree.
237
+ const target = edited.children.find((c) => c.component === 'cre8-tag-list');
238
+ assert(target, 'expected a tag list in the example');
239
+ target.children[0].props.text = 'Edited';
240
+ const ops = roundTrip(source.spec, edited, 'small edit');
241
+ assertEqual(ops.length, 1, `a one-word change should cost one op, got ${JSON.stringify(ops)}`);
242
+ assertEqual(ops[0].op, 'setProps');
243
+ });
244
+
245
+ // ─── the point of diffing at all ────────────────────────────────────────────
246
+
247
+ test('resending the whole tree keeps the elements that did not change', () => {
248
+ const host = dom.window.document.createElement('div');
249
+ dom.window.document.body.appendChild(host);
250
+ const model = new SurfaceModel(catalog, { surfaceId: 's' });
251
+ const renderer = new SurfaceRenderer(model, { root: host, doc: dom.window.document });
252
+
253
+ const build = (headline) => ({
254
+ component: 'cre8-layout-container',
255
+ children: [
256
+ { component: 'cre8-heading', props: { tagVariant: 'h1' }, children: [headline] },
257
+ { component: 'cre8-field', props: { label: 'Your name' } },
258
+ { component: 'cre8-button', props: { text: 'Continue', variant: 'primary' } },
259
+ ],
260
+ });
261
+
262
+ renderer.apply({
263
+ v: 1, type: 'surface.create', surfaceId: 's', seq: 0, catalogId: catalog.id, root: build('Before'),
264
+ });
265
+ const field = renderer.elementAt('$.children[1]');
266
+ const button = renderer.elementAt('$.children[2]');
267
+ field.dataset.userTyped = 'Ada Lovelace';
268
+
269
+ const ops = diffSpecs(model.root, build('After'));
270
+ renderer.apply({ v: 1, type: 'surface.patch', surfaceId: 's', seq: 1, ops });
271
+
272
+ assertEqual(renderer.elementAt('$.children[0]').textContent, 'After', 'the change lands');
273
+ assertEqual(renderer.elementAt('$.children[1]'), field, 'the untouched field is the same element');
274
+ assertEqual(renderer.elementAt('$.children[1]').dataset.userTyped, 'Ada Lovelace',
275
+ 'so whatever the user had put in it survives');
276
+ assertEqual(renderer.elementAt('$.children[2]'), button, 'and so does the button');
277
+ });
278
+
279
+ test('replacing the root instead would have destroyed all of it', () => {
280
+ const host = dom.window.document.createElement('div');
281
+ dom.window.document.body.appendChild(host);
282
+ const model = new SurfaceModel(catalog, { surfaceId: 's' });
283
+ const renderer = new SurfaceRenderer(model, { root: host, doc: dom.window.document });
284
+ const tree = { component: 'cre8-layout-container', children: [{ component: 'cre8-field', props: { label: 'Name' } }] };
285
+
286
+ renderer.apply({ v: 1, type: 'surface.create', surfaceId: 's', seq: 0, catalogId: catalog.id, root: tree });
287
+ const field = renderer.elementAt('$.children[0]');
288
+
289
+ // The naive alternative to a diff.
290
+ renderer.apply({
291
+ v: 1, type: 'surface.patch', surfaceId: 's', seq: 1,
292
+ ops: [{ op: 'replace', path: '$', node: JSON.parse(JSON.stringify(tree)) }],
293
+ });
294
+ assert(renderer.elementAt('$.children[0]') !== field,
295
+ 'a root replace remounts everything — this is the cost the differ avoids');
296
+ });
297
+
298
+ console.log(`\n${passed} passed, ${failures.length} failed`);
299
+ if (failures.length) process.exit(1);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Turn "here is the new tree" into the smallest set of patch ops that gets
3
+ * there.
4
+ *
5
+ * The op vocabulary is the right primitive, and it is the wrong interface for
6
+ * how models actually work: asked to change one label, a model regenerates the
7
+ * whole document. Without a diff, that costs a full remount — every element
8
+ * recreated, focus lost, scroll reset, animations restarted — which is exactly
9
+ * what streaming exists to avoid. With one, an agent gets incremental rendering
10
+ * without ever learning what `appendText` is.
11
+ *
12
+ * Node identity here is positional, matching the rest of the streaming layer.
13
+ * That means the diff is deliberately *not* a minimal edit script: it compares
14
+ * position by position and only appends or removes at the tail. Inserting at the
15
+ * head of a long list therefore rewrites the list rather than shifting it. A
16
+ * keyed diff would do better, but keys would have to come from somewhere, and
17
+ * the whole reason this dialect has no ids is that nothing has to invent them.
18
+ */
19
+ import type { ComponentSpec } from '../types.js';
20
+ import type { PatchOp } from './types.js';
21
+ /**
22
+ * Ops that turn `prev` into `next`. Returns an empty array when they already
23
+ * match, so an agent can resend an unchanged tree for free.
24
+ *
25
+ * `null` for either side means "no surface root": the result is a single
26
+ * `replace`/`remove` at `$`, which the model handles as a root swap.
27
+ */
28
+ export declare function diffSpecs(prev: ComponentSpec | null, next: ComponentSpec | null): PatchOp[];
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Turn "here is the new tree" into the smallest set of patch ops that gets
3
+ * there.
4
+ *
5
+ * The op vocabulary is the right primitive, and it is the wrong interface for
6
+ * how models actually work: asked to change one label, a model regenerates the
7
+ * whole document. Without a diff, that costs a full remount — every element
8
+ * recreated, focus lost, scroll reset, animations restarted — which is exactly
9
+ * what streaming exists to avoid. With one, an agent gets incremental rendering
10
+ * without ever learning what `appendText` is.
11
+ *
12
+ * Node identity here is positional, matching the rest of the streaming layer.
13
+ * That means the diff is deliberately *not* a minimal edit script: it compares
14
+ * position by position and only appends or removes at the tail. Inserting at the
15
+ * head of a long list therefore rewrites the list rather than shifting it. A
16
+ * keyed diff would do better, but keys would have to come from somewhere, and
17
+ * the whole reason this dialect has no ids is that nothing has to invent them.
18
+ */
19
+ import { childPath } from './pointer.js';
20
+ function isSpec(node) {
21
+ return typeof node === 'object' && node !== null;
22
+ }
23
+ function sameShape(a, b) {
24
+ if (typeof a === 'string' || typeof b === 'string')
25
+ return typeof a === typeof b;
26
+ return isSpec(a) && isSpec(b) && a.component === b.component;
27
+ }
28
+ function equal(a, b) {
29
+ return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
30
+ }
31
+ /**
32
+ * Props that changed, plus `null` for props that went away — the shape
33
+ * `setProps` already understands.
34
+ */
35
+ function propDelta(prev = {}, next = {}) {
36
+ const delta = {};
37
+ for (const [key, value] of Object.entries(next)) {
38
+ if (!equal(prev[key], value))
39
+ delta[key] = value;
40
+ }
41
+ for (const key of Object.keys(prev)) {
42
+ if (!(key in next))
43
+ delta[key] = null;
44
+ }
45
+ return Object.keys(delta).length ? delta : null;
46
+ }
47
+ function contentLists(spec) {
48
+ const lists = new Map();
49
+ if (spec.children)
50
+ lists.set(null, spec.children);
51
+ for (const [slot, list] of Object.entries(spec.slots ?? {}))
52
+ lists.set(slot, list);
53
+ return lists;
54
+ }
55
+ function diffList(path, slot, prev, next, ops) {
56
+ const shared = Math.min(prev.length, next.length);
57
+ for (let i = 0; i < shared; i++) {
58
+ const before = prev[i];
59
+ const after = next[i];
60
+ const childAt = childPath(path, slot, i);
61
+ if (typeof after === 'string') {
62
+ // A text child that changed. setText replaces the whole list, so it is
63
+ // only safe when the text is the entire content.
64
+ if (before !== after) {
65
+ if (prev.length === 1 && next.length === 1) {
66
+ ops.push({ op: 'setText', path, slot, text: after });
67
+ }
68
+ else {
69
+ ops.push({ op: 'replace', path: childAt, node: after });
70
+ }
71
+ }
72
+ continue;
73
+ }
74
+ if (!sameShape(before, after)) {
75
+ ops.push({ op: 'replace', path: childAt, node: after });
76
+ continue;
77
+ }
78
+ diffNode(childAt, before, after, ops);
79
+ }
80
+ // Tail only: positional identity means anything else would renumber the
81
+ // siblings the caller is about to address.
82
+ if (next.length > prev.length) {
83
+ ops.push({ op: 'append', path, slot, nodes: next.slice(prev.length) });
84
+ }
85
+ else if (prev.length > next.length) {
86
+ for (let i = prev.length - 1; i >= next.length; i--) {
87
+ ops.push({ op: 'remove', path: childPath(path, slot, i) });
88
+ }
89
+ }
90
+ }
91
+ function diffNode(path, prev, next, ops) {
92
+ const props = propDelta(prev.props, next.props);
93
+ if (props)
94
+ ops.push({ op: 'setProps', path, props });
95
+ if (!equal(prev.events, next.events)) {
96
+ const events = { ...(next.events ?? {}) };
97
+ for (const name of Object.keys(prev.events ?? {})) {
98
+ if (!(name in (next.events ?? {})))
99
+ events[name] = null;
100
+ }
101
+ if (Object.keys(events).length)
102
+ ops.push({ op: 'setEvents', path, events });
103
+ }
104
+ const prevLists = contentLists(prev);
105
+ const nextLists = contentLists(next);
106
+ for (const [slot, nextList] of nextLists) {
107
+ diffList(path, slot, prevLists.get(slot) ?? [], nextList, ops);
108
+ }
109
+ for (const [slot] of prevLists) {
110
+ if (!nextLists.has(slot))
111
+ ops.push({ op: 'clear', path, slot });
112
+ }
113
+ }
114
+ /**
115
+ * Ops that turn `prev` into `next`. Returns an empty array when they already
116
+ * match, so an agent can resend an unchanged tree for free.
117
+ *
118
+ * `null` for either side means "no surface root": the result is a single
119
+ * `replace`/`remove` at `$`, which the model handles as a root swap.
120
+ */
121
+ export function diffSpecs(prev, next) {
122
+ if (!next)
123
+ return prev ? [{ op: 'remove', path: '$' }] : [];
124
+ if (!prev || prev.component !== next.component) {
125
+ return [{ op: 'replace', path: '$', node: next }];
126
+ }
127
+ const ops = [];
128
+ diffNode('$', prev, next, ops);
129
+ return ops;
130
+ }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Turn "here is the new tree" into the smallest set of patch ops that gets
3
+ * there.
4
+ *
5
+ * The op vocabulary is the right primitive, and it is the wrong interface for
6
+ * how models actually work: asked to change one label, a model regenerates the
7
+ * whole document. Without a diff, that costs a full remount — every element
8
+ * recreated, focus lost, scroll reset, animations restarted — which is exactly
9
+ * what streaming exists to avoid. With one, an agent gets incremental rendering
10
+ * without ever learning what `appendText` is.
11
+ *
12
+ * Node identity here is positional, matching the rest of the streaming layer.
13
+ * That means the diff is deliberately *not* a minimal edit script: it compares
14
+ * position by position and only appends or removes at the tail. Inserting at the
15
+ * head of a long list therefore rewrites the list rather than shifting it. A
16
+ * keyed diff would do better, but keys would have to come from somewhere, and
17
+ * the whole reason this dialect has no ids is that nothing has to invent them.
18
+ */
19
+
20
+ import type { ComponentSpec, SpecChild } from '../types.js';
21
+ import type { ContentTarget, PatchOp } from './types.js';
22
+ import { childPath } from './pointer.js';
23
+
24
+ function isSpec(node: SpecChild | undefined): node is ComponentSpec {
25
+ return typeof node === 'object' && node !== null;
26
+ }
27
+
28
+ function sameShape(a: SpecChild | undefined, b: SpecChild | undefined): boolean {
29
+ if (typeof a === 'string' || typeof b === 'string') return typeof a === typeof b;
30
+ return isSpec(a) && isSpec(b) && a.component === b.component;
31
+ }
32
+
33
+ function equal(a: unknown, b: unknown): boolean {
34
+ return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
35
+ }
36
+
37
+ /**
38
+ * Props that changed, plus `null` for props that went away — the shape
39
+ * `setProps` already understands.
40
+ */
41
+ function propDelta(
42
+ prev: Record<string, unknown> = {},
43
+ next: Record<string, unknown> = {}
44
+ ): Record<string, unknown> | null {
45
+ const delta: Record<string, unknown> = {};
46
+ for (const [key, value] of Object.entries(next)) {
47
+ if (!equal(prev[key], value)) delta[key] = value;
48
+ }
49
+ for (const key of Object.keys(prev)) {
50
+ if (!(key in next)) delta[key] = null;
51
+ }
52
+ return Object.keys(delta).length ? delta : null;
53
+ }
54
+
55
+ function contentLists(spec: ComponentSpec): Map<ContentTarget, SpecChild[]> {
56
+ const lists = new Map<ContentTarget, SpecChild[]>();
57
+ if (spec.children) lists.set(null, spec.children);
58
+ for (const [slot, list] of Object.entries(spec.slots ?? {})) lists.set(slot, list);
59
+ return lists;
60
+ }
61
+
62
+ function diffList(
63
+ path: string,
64
+ slot: ContentTarget,
65
+ prev: SpecChild[],
66
+ next: SpecChild[],
67
+ ops: PatchOp[]
68
+ ): void {
69
+ const shared = Math.min(prev.length, next.length);
70
+
71
+ for (let i = 0; i < shared; i++) {
72
+ const before = prev[i];
73
+ const after = next[i];
74
+ const childAt = childPath(path, slot, i);
75
+
76
+ if (typeof after === 'string') {
77
+ // A text child that changed. setText replaces the whole list, so it is
78
+ // only safe when the text is the entire content.
79
+ if (before !== after) {
80
+ if (prev.length === 1 && next.length === 1) {
81
+ ops.push({ op: 'setText', path, slot, text: after });
82
+ } else {
83
+ ops.push({ op: 'replace', path: childAt, node: after });
84
+ }
85
+ }
86
+ continue;
87
+ }
88
+
89
+ if (!sameShape(before, after)) {
90
+ ops.push({ op: 'replace', path: childAt, node: after });
91
+ continue;
92
+ }
93
+ diffNode(childAt, before as ComponentSpec, after, ops);
94
+ }
95
+
96
+ // Tail only: positional identity means anything else would renumber the
97
+ // siblings the caller is about to address.
98
+ if (next.length > prev.length) {
99
+ ops.push({ op: 'append', path, slot, nodes: next.slice(prev.length) });
100
+ } else if (prev.length > next.length) {
101
+ for (let i = prev.length - 1; i >= next.length; i--) {
102
+ ops.push({ op: 'remove', path: childPath(path, slot, i) });
103
+ }
104
+ }
105
+ }
106
+
107
+ function diffNode(path: string, prev: ComponentSpec, next: ComponentSpec, ops: PatchOp[]): void {
108
+ const props = propDelta(prev.props, next.props);
109
+ if (props) ops.push({ op: 'setProps', path, props });
110
+
111
+ if (!equal(prev.events, next.events)) {
112
+ const events: Record<string, unknown> = { ...(next.events ?? {}) };
113
+ for (const name of Object.keys(prev.events ?? {})) {
114
+ if (!(name in (next.events ?? {}))) events[name] = null;
115
+ }
116
+ if (Object.keys(events).length) ops.push({ op: 'setEvents', path, events });
117
+ }
118
+
119
+ const prevLists = contentLists(prev);
120
+ const nextLists = contentLists(next);
121
+
122
+ for (const [slot, nextList] of nextLists) {
123
+ diffList(path, slot, prevLists.get(slot) ?? [], nextList, ops);
124
+ }
125
+ for (const [slot] of prevLists) {
126
+ if (!nextLists.has(slot)) ops.push({ op: 'clear', path, slot });
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Ops that turn `prev` into `next`. Returns an empty array when they already
132
+ * match, so an agent can resend an unchanged tree for free.
133
+ *
134
+ * `null` for either side means "no surface root": the result is a single
135
+ * `replace`/`remove` at `$`, which the model handles as a root swap.
136
+ */
137
+ export function diffSpecs(prev: ComponentSpec | null, next: ComponentSpec | null): PatchOp[] {
138
+ if (!next) return prev ? [{ op: 'remove', path: '$' }] : [];
139
+ if (!prev || prev.component !== next.component) {
140
+ return [{ op: 'replace', path: '$', node: next }];
141
+ }
142
+ const ops: PatchOp[] = [];
143
+ diffNode('$', prev, next, ops);
144
+ return ops;
145
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A2UI streaming surfaces for cre8.
3
+ *
4
+ * `SurfaceModel` is DOM-free and runs anywhere; `SurfaceRenderer` mirrors it
5
+ * into the browser. See `docs/kb/08-streaming-ui.md`.
6
+ */
7
+ export { A2UI_STREAM_VERSION, isBindingRef, type BindingRef, type ContentTarget, type DataPatch, type JsonPointer, type PatchOp, type SurfaceChange, type SurfaceEventMessage, type SurfaceMessage, type SurfaceState, } from './types.js';
8
+ export { SurfaceModel, SurfaceSeqGapError, resolveNode, type ApplyResult, type SurfaceModelOptions, } from './model.js';
9
+ export { SurfaceRenderer, findPath, type SurfaceRendererOptions } from './renderer.js';
10
+ export { diffSpecs } from './diff.js';
11
+ export { childPath, formatPath, parsePath, parsePointer, pointerGet, pointerRemove, pointerSet, type PathSegment, } from './pointer.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A2UI streaming surfaces for cre8.
3
+ *
4
+ * `SurfaceModel` is DOM-free and runs anywhere; `SurfaceRenderer` mirrors it
5
+ * into the browser. See `docs/kb/08-streaming-ui.md`.
6
+ */
7
+ export { A2UI_STREAM_VERSION, isBindingRef, } from './types.js';
8
+ export { SurfaceModel, SurfaceSeqGapError, resolveNode, } from './model.js';
9
+ export { SurfaceRenderer, findPath } from './renderer.js';
10
+ export { diffSpecs } from './diff.js';
11
+ export { childPath, formatPath, parsePath, parsePointer, pointerGet, pointerRemove, pointerSet, } from './pointer.js';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A2UI streaming surfaces for cre8.
3
+ *
4
+ * `SurfaceModel` is DOM-free and runs anywhere; `SurfaceRenderer` mirrors it
5
+ * into the browser. See `docs/kb/08-streaming-ui.md`.
6
+ */
7
+
8
+ export {
9
+ A2UI_STREAM_VERSION,
10
+ isBindingRef,
11
+ type BindingRef,
12
+ type ContentTarget,
13
+ type DataPatch,
14
+ type JsonPointer,
15
+ type PatchOp,
16
+ type SurfaceChange,
17
+ type SurfaceEventMessage,
18
+ type SurfaceMessage,
19
+ type SurfaceState,
20
+ } from './types.js';
21
+
22
+ export {
23
+ SurfaceModel,
24
+ SurfaceSeqGapError,
25
+ resolveNode,
26
+ type ApplyResult,
27
+ type SurfaceModelOptions,
28
+ } from './model.js';
29
+
30
+ export { SurfaceRenderer, findPath, type SurfaceRendererOptions } from './renderer.js';
31
+
32
+ export { diffSpecs } from './diff.js';
33
+
34
+ export {
35
+ childPath,
36
+ formatPath,
37
+ parsePath,
38
+ parsePointer,
39
+ pointerGet,
40
+ pointerRemove,
41
+ pointerSet,
42
+ type PathSegment,
43
+ } from './pointer.js';