@jxsuite/studio 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +23711 -35185
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +34 -9
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +270 -262
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -120
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +75 -2
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +113 -0
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
  363. package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
  364. package/dist/chunks/files-02zn5y24.js +0 -50
  365. package/dist/chunks/files-02zn5y24.js.map +0 -9
  366. package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
  367. package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
  368. package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
  369. package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
  370. package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
  371. package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  381. package/dist/chunks/studio-568nx4t5.js +0 -469
  382. package/dist/chunks/studio-568nx4t5.js.map +0 -14
  383. package/dist/chunks/studio-9smfzqhc.js +0 -19
  384. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  385. package/dist/chunks/studio-asvf0j9e.js +0 -429
  386. package/dist/chunks/studio-asvf0j9e.js.map +0 -13
  387. package/dist/chunks/studio-d77qm3pk.js +0 -3427
  388. package/dist/chunks/studio-d77qm3pk.js.map +0 -26
  389. package/dist/chunks/studio-j6gqyjf4.js +0 -1854
  390. package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
  391. package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-rq0vxb19.js +0 -3744
  394. package/dist/chunks/studio-rq0vxb19.js.map +0 -22
  395. package/dist/chunks/studio-wd6ewdvd.js +0 -853
  396. package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
  397. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  398. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  399. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  400. package/dist/chunks/studio-ygzav7z5.js.map +0 -46
  401. package/dist/chunks/studio-zmy7241e.js +0 -399
  402. package/dist/chunks/studio-zmy7241e.js.map +0 -12
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pushing a project-style edit to every live canvas — one definition site.
3
+ *
4
+ * Plan §9.4's promise is "tune a design token and watch the page change", and until now that was
5
+ * true of exactly one kind of canvas. `postSiteStyleToLiveHosts` skips stylebook hosts by
6
+ * construction ({@link file://../canvas/iframe-host.ts}: `host.ready && !host.stylebook`), because
7
+ * a specimen canvas does not render the site sheet — it renders a GENERATED document whose root
8
+ * carries the transposed effective style, and its live channel is `styleUpdate`, not
9
+ * `siteStyleUpdate`. So a token edited in the token editor reached every page canvas immediately
10
+ * and left the Project Styles canvas — the one the plan puts _beside_ the editor — showing the old
11
+ * palette until something forced a full re-render.
12
+ *
13
+ * Two hosts, two messages, one event. Every surface that writes `projectConfig.style` calls this
14
+ * instead of picking one of the two posts, which is the only arrangement in which the pair cannot
15
+ * drift apart again.
16
+ */
17
+
18
+ import { postSiteStyleToLiveHosts, postStyleUpdateToStylebookHosts } from "../canvas/iframe-host";
19
+ import { transposeStylebookStyle } from "../panels/stylebook-doc";
20
+ import { getEffectiveStyle } from "../site-context";
21
+ import { activeTab } from "../workspace/workspace";
22
+
23
+ /**
24
+ * Re-apply the project's style to every live canvas, in place — no re-render.
25
+ *
26
+ * The stylebook post needs the EFFECTIVE style (site merged with the open document's), because a
27
+ * specimen canvas opened on a component shows that component's `& <tag>` defaults too; posting the
28
+ * site style alone would silently drop them until the next full render. That is the one thing here
29
+ * that reads the focused document, and it reads it to refresh a document-level canvas, not to
30
+ * source a project-level badge.
31
+ */
32
+ export function pushProjectStylesToCanvas(): void {
33
+ postSiteStyleToLiveHosts();
34
+ const style = transposeStylebookStyle(getEffectiveStyle(activeTab.value?.doc.document?.style));
35
+ postStyleUpdateToStylebookHosts(style as Record<string, unknown>);
36
+ }
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Project Styles — the model behind the project's design tokens and element defaults.
3
+ *
4
+ * ## The name and the wire value are different things
5
+ *
6
+ * The surface a user reaches is called **Project Styles** (plan §9.4). The canvas view it opens is
7
+ * the string `"stylebook"`, a member of `CANVAS_MODES` in
8
+ * {@link file://../canvas/iframe-protocol.ts} and therefore half of a `ParentToIframe` union: the
9
+ * studio bundle and `dist/iframe-entry.js` agree on it, and changing it means rebuilding both in
10
+ * lockstep. So it is not a name and may never be renamed to follow one.
11
+ * {@link PROJECT_STYLES_TITLE} is the name; {@link PROJECT_STYLES_VIEW} is the wire value; a
12
+ * surface that needs one must not reach for the other.
13
+ *
14
+ * ## One vocabulary for the `@` blocks
15
+ *
16
+ * A token's value can differ per rendering context, and on disk every such override lives in the
17
+ * same place — a `@<name>` block beside the token, keyed by a `$media` entry name. Breakpoints and
18
+ * colour schemes are two _kinds_ of that one thing, and this module models them as one
19
+ * {@link TokenContext} list so a surface cannot grow a second override path for the second kind (a
20
+ * per-scheme writer and a per-media writer that disagreed about pruning an emptied block is exactly
21
+ * what this replaces). Contexts are **defined** in Project Settings › Contexts and only selected or
22
+ * overridden here — §2 principle 5.
23
+ *
24
+ * On-disk format is unchanged by anything in this module: it reads and writes the same
25
+ * `style["--token"]` and `style["@--ctx"]["--token"]` shapes the compiler already consumes.
26
+ */
27
+
28
+ import { parseMediaEntries, schemeOfQuery } from "../utils/canvas-media";
29
+ import { varDisplayName } from "../utils/studio-utils";
30
+
31
+ import type { JxStyle } from "@jxsuite/schema/types";
32
+ import type { CanvasMode } from "../canvas/iframe-protocol";
33
+
34
+ /** What the surface is called, everywhere a reader sees it. One definition site. */
35
+ export const PROJECT_STYLES_TITLE = "Project Styles";
36
+
37
+ /**
38
+ * The canvas view Project Styles opens — a WIRE value, not a name. See the module doc: it is a
39
+ * `CANVAS_MODES` member shared with the iframe bundle, and it stays `"stylebook"`.
40
+ */
41
+ export const PROJECT_STYLES_VIEW: CanvasMode = "stylebook";
42
+
43
+ // ─── Token groups ────────────────────────────────────────────────────────────
44
+
45
+ /** The four buckets the token editor lists, in display order. */
46
+ export type TokenGroupId = "color" | "font" | "size" | "other";
47
+
48
+ export interface TokenGroup {
49
+ id: TokenGroupId;
50
+ /** The group heading. */
51
+ title: string;
52
+ /** The prefix a token added in this group is named under. */
53
+ prefix: string;
54
+ }
55
+
56
+ /**
57
+ * The groups, in order. `other` is rendered only when something lands in it — a bucket named
58
+ * "Other" over an empty list teaches nothing (§2 principle 6).
59
+ *
60
+ * A group is a name and a prefix and nothing else. The example values an add row hints with are a
61
+ * property of the FORM, not of the model, and they live beside the form that shows them.
62
+ */
63
+ export const TOKEN_GROUPS: readonly TokenGroup[] = [
64
+ { id: "color", prefix: "--color-", title: "Colors" },
65
+ { id: "font", prefix: "--font-", title: "Fonts" },
66
+ { id: "size", prefix: "--size-", title: "Sizes & Spacing" },
67
+ { id: "other", prefix: "--", title: "Other" },
68
+ ];
69
+
70
+ /**
71
+ * Which group a custom property belongs to, by prefix.
72
+ *
73
+ * @param {string} name
74
+ * @returns {TokenGroupId}
75
+ */
76
+ export function groupIdOfToken(name: string): TokenGroupId {
77
+ if (name.startsWith("--color")) {
78
+ return "color";
79
+ }
80
+ if (name.startsWith("--font")) {
81
+ return "font";
82
+ }
83
+ if (name.startsWith("--size") || name.startsWith("--spacing") || name.startsWith("--radius")) {
84
+ return "size";
85
+ }
86
+ return "other";
87
+ }
88
+
89
+ /**
90
+ * The label a reader sees for a token: the friendly name it was added under, recovered from the
91
+ * variable name. `--color-primary-blue` → "Primary Blue".
92
+ *
93
+ * The `other` group keeps its raw name deliberately — a token there has no prefix to strip, so "Z
94
+ * Index Modal" would be a guess at a name its author never typed.
95
+ *
96
+ * @param {string} name
97
+ * @returns {string}
98
+ */
99
+ export function tokenLabel(name: string): string {
100
+ const group = groupIdOfToken(name);
101
+ if (group === "other") {
102
+ return name;
103
+ }
104
+ /*
105
+ * `varDisplayName` falls back to stripping a bare `--` when the prefix does not match, which is
106
+ * what turns `--spacing-lg` (group `size`, prefix `--size-`) into "Spacing Lg". The predecessor
107
+ * chained three prefixes with `||` and never reached the second, because the first always
108
+ * returns a truthy string.
109
+ */
110
+ const { prefix } = TOKEN_GROUPS.find((g) => g.id === group)!;
111
+ return varDisplayName(name, prefix);
112
+ }
113
+
114
+ // ─── Tokens ──────────────────────────────────────────────────────────────────
115
+
116
+ /** One design token declared at the top level of a style block. */
117
+ export interface ProjectToken {
118
+ /** The custom property, e.g. `--color-primary`. */
119
+ name: string;
120
+ group: TokenGroupId;
121
+ /** What a reader sees — {@link tokenLabel}. */
122
+ label: string;
123
+ value: string | number;
124
+ }
125
+
126
+ /**
127
+ * Every design token in a style block, in declaration order.
128
+ *
129
+ * Non-custom properties (`color: blue`) and object values are not tokens and are skipped — an
130
+ * object under a `--` key is malformed, and every `@ctx` block is an object by construction.
131
+ *
132
+ * @param {JxStyle | null | undefined} style
133
+ * @returns {ProjectToken[]}
134
+ */
135
+ export function listTokens(style: JxStyle | null | undefined): ProjectToken[] {
136
+ if (!style) {
137
+ return [];
138
+ }
139
+ const out: ProjectToken[] = [];
140
+ for (const [name, value] of Object.entries(style)) {
141
+ if (!name.startsWith("--")) {
142
+ continue;
143
+ }
144
+ if (typeof value !== "string" && typeof value !== "number") {
145
+ continue;
146
+ }
147
+ out.push({ group: groupIdOfToken(name), label: tokenLabel(name), name, value });
148
+ }
149
+ return out;
150
+ }
151
+
152
+ /**
153
+ * Group tokens for display: every group in {@link TOKEN_GROUPS} order, each with its members.
154
+ *
155
+ * @param {JxStyle | null | undefined} style
156
+ * @returns {{ group: TokenGroup; tokens: ProjectToken[] }[]}
157
+ */
158
+ export function groupTokens(
159
+ style: JxStyle | null | undefined,
160
+ ): { group: TokenGroup; tokens: ProjectToken[] }[] {
161
+ const tokens = listTokens(style);
162
+ return TOKEN_GROUPS.map((group) => ({
163
+ group,
164
+ tokens: tokens.filter((t) => t.group === group.id),
165
+ }));
166
+ }
167
+
168
+ // ─── Rendering contexts ──────────────────────────────────────────────────────
169
+
170
+ /**
171
+ * What a context IS, for a reader. `size` is a breakpoint, `scheme` is a colour scheme, `feature`
172
+ * is any other feature query. The distinction decides only how the row is labelled and whether it
173
+ * is offered unprompted — the on-disk block is the same shape for all three.
174
+ */
175
+ export type TokenContextKind = "size" | "scheme" | "feature";
176
+
177
+ /** A declared `$media` entry, seen as a place a token can carry a different value. */
178
+ export interface TokenContext {
179
+ /** The `$media` entry name, e.g. `--sm` or `--dark`. */
180
+ name: string;
181
+ /** The style key its overrides live under, e.g. `@--sm`. */
182
+ key: string;
183
+ /** What the reader sees: "Dark" for a scheme, the raw `@--sm` for anything else. */
184
+ label: string;
185
+ kind: TokenContextKind;
186
+ /** Present only when `kind` is `"scheme"`. */
187
+ scheme?: "light" | "dark";
188
+ }
189
+
190
+ /**
191
+ * The contexts a token can be overridden in, derived from `$media`.
192
+ *
193
+ * Schemes come first because they are the pair a colour token is always asked about; breakpoints
194
+ * follow in the order {@link parseMediaEntries} sorts them (the same order the canvas shows its
195
+ * panels in), then any other feature query. `--` is the base canvas width, not a context.
196
+ *
197
+ * @param {Record<string, string> | null | undefined} media
198
+ * @returns {TokenContext[]}
199
+ */
200
+ export function listTokenContexts(
201
+ media: Record<string, string> | null | undefined,
202
+ ): TokenContext[] {
203
+ if (!media) {
204
+ return [];
205
+ }
206
+ const { featureQueries, sizeBreakpoints } = parseMediaEntries(media);
207
+ const schemes: TokenContext[] = [];
208
+ const features: TokenContext[] = [];
209
+ for (const { name, query } of featureQueries) {
210
+ const scheme = schemeOfQuery(query);
211
+ if (scheme) {
212
+ schemes.push({
213
+ key: `@${name}`,
214
+ kind: "scheme",
215
+ label: scheme === "dark" ? "Dark" : "Light",
216
+ name,
217
+ scheme,
218
+ });
219
+ } else {
220
+ features.push({ key: `@${name}`, kind: "feature", label: `@${name}`, name });
221
+ }
222
+ }
223
+ const sizes: TokenContext[] = sizeBreakpoints.map(({ name }) => ({
224
+ key: `@${name}`,
225
+ kind: "size",
226
+ label: `@${name}`,
227
+ name,
228
+ }));
229
+ return [...schemes, ...sizes, ...features];
230
+ }
231
+
232
+ // ─── Overrides ───────────────────────────────────────────────────────────────
233
+
234
+ /** A token's value in one context, alongside the context it came from. */
235
+ export interface TokenOverride {
236
+ context: TokenContext;
237
+ value: string | number;
238
+ }
239
+
240
+ /**
241
+ * The block a context's overrides live in, or undefined when the context carries none.
242
+ *
243
+ * @param {JxStyle} style
244
+ * @param {TokenContext} context
245
+ */
246
+ function overrideBlock(style: JxStyle, context: TokenContext): Record<string, unknown> | undefined {
247
+ const block = style[context.key];
248
+ return block && typeof block === "object" ? (block as Record<string, unknown>) : undefined;
249
+ }
250
+
251
+ /**
252
+ * A token's value in one context, or undefined when it inherits the base value.
253
+ *
254
+ * @param {JxStyle} style
255
+ * @param {TokenContext} context
256
+ * @param {string} token
257
+ * @returns {string | number | undefined}
258
+ */
259
+ export function readTokenOverride(
260
+ style: JxStyle,
261
+ context: TokenContext,
262
+ token: string,
263
+ ): string | number | undefined {
264
+ const value = overrideBlock(style, context)?.[token];
265
+ return typeof value === "string" || typeof value === "number" ? value : undefined;
266
+ }
267
+
268
+ /**
269
+ * Write or clear a token's override in one context, IN PLACE.
270
+ *
271
+ * An empty value clears it, and an emptied block is removed rather than left as `"@--dark": {}` — a
272
+ * block that exists but says nothing is a diff on every save and a rule the compiler emits for no
273
+ * reason. The block is recreated on demand, so a caller holding a stale render still writes to the
274
+ * right place.
275
+ *
276
+ * @param {JxStyle} style
277
+ * @param {TokenContext} context
278
+ * @param {string} token
279
+ * @param {string} value — empty clears
280
+ */
281
+ export function writeTokenOverride(
282
+ style: JxStyle,
283
+ context: TokenContext,
284
+ token: string,
285
+ value: string,
286
+ ): void {
287
+ if (value) {
288
+ const block = (style[context.key] ??= {}) as Record<string, unknown>;
289
+ block[token] = value;
290
+ return;
291
+ }
292
+ const block = overrideBlock(style, context);
293
+ if (!block) {
294
+ return;
295
+ }
296
+ delete block[token];
297
+ if (Object.keys(block).length === 0) {
298
+ delete style[context.key];
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Every context in which a token already carries an override, in {@link listTokenContexts} order.
304
+ *
305
+ * @param {JxStyle} style
306
+ * @param {readonly TokenContext[]} contexts
307
+ * @param {string} token
308
+ * @returns {TokenOverride[]}
309
+ */
310
+ export function tokenOverrides(
311
+ style: JxStyle,
312
+ contexts: readonly TokenContext[],
313
+ token: string,
314
+ ): TokenOverride[] {
315
+ const out: TokenOverride[] = [];
316
+ for (const context of contexts) {
317
+ const value = readTokenOverride(style, context, token);
318
+ if (value !== undefined) {
319
+ out.push({ context, value });
320
+ }
321
+ }
322
+ return out;
323
+ }
324
+
325
+ /**
326
+ * The contexts a token can still be given an override in — the add affordance's menu.
327
+ *
328
+ * The predecessor had none: an override row appeared only for a token that already carried an
329
+ * `@media` block, so the only way to create the first one was to hand-edit `project.json`. This is
330
+ * the list of contexts that are declared and not yet used, minus the ones already shown unprompted
331
+ * (`alreadyShown`), so the menu never offers a row the reader is already looking at.
332
+ *
333
+ * @param {JxStyle} style
334
+ * @param {readonly TokenContext[]} contexts
335
+ * @param {string} token
336
+ * @param {readonly TokenContext[]} [alreadyShown]
337
+ * @returns {TokenContext[]}
338
+ */
339
+ export function addableContexts(
340
+ style: JxStyle,
341
+ contexts: readonly TokenContext[],
342
+ token: string,
343
+ alreadyShown: readonly TokenContext[] = [],
344
+ ): TokenContext[] {
345
+ const shown = new Set(alreadyShown.map((c) => c.name));
346
+ return contexts.filter(
347
+ (context) => !shown.has(context.name) && readTokenOverride(style, context, token) === undefined,
348
+ );
349
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Token references — reading `var(--token)` as a binding, and rendering it as a chip.
3
+ *
4
+ * A style value that is exactly `var(--something)` is not a value, it is a reference to one. Raw
5
+ * text says so only to a reader who already knows CSS: `var(--color-brand)` is eleven characters of
6
+ * syntax around a name, and the thing the author actually wants to know — _which_ token, and what
7
+ * it currently resolves to — is the part that is not shown. So a bound value renders as a **chip**
8
+ * (plan §9.4), in the same vocabulary as the provenance chips shipped in P5: the token's friendly
9
+ * name, and for a colour, its resolved swatch.
10
+ *
11
+ * The resolver follows a chain of references, because an alias token (`--color-accent:
12
+ * var(--color-brand)`) is the normal way a palette is built and a chip that stopped at the first
13
+ * hop would report `var(--color-brand)` as a colour.
14
+ */
15
+
16
+ import { html } from "lit-html";
17
+ import { tokenLabel } from "./project-styles";
18
+
19
+ import type { JxStyle } from "@jxsuite/schema/types";
20
+ import type { TemplateResult } from "lit-html";
21
+
22
+ /** A value that is EXACTLY one `var()` reference — not `calc(var(--a) * 2)`, which is a value. */
23
+ const TOKEN_REF_RE = /^var\(\s*(--[\w-]+)\s*\)$/;
24
+
25
+ /** How many hops the resolver follows before it decides the chain is a cycle. */
26
+ const MAX_HOPS = 10;
27
+
28
+ /**
29
+ * The token a value references, or null when the value is not a bare reference.
30
+ *
31
+ * @param {unknown} value
32
+ * @returns {string | null}
33
+ */
34
+ export function tokenRefName(value: unknown): string | null {
35
+ if (typeof value !== "string") {
36
+ return null;
37
+ }
38
+ return TOKEN_REF_RE.exec(value)?.[1] ?? null;
39
+ }
40
+
41
+ /**
42
+ * The reference form of a token name — the value written into a style field that follows it.
43
+ *
44
+ * @param {string} name
45
+ * @returns {string}
46
+ */
47
+ export function toTokenRef(name: string): string {
48
+ return `var(${name})`;
49
+ }
50
+
51
+ /**
52
+ * Follow a value's references to the concrete value at the end of the chain.
53
+ *
54
+ * Returns undefined when the chain leaves the style block (a token defined by a stylesheet the
55
+ * editor cannot see) or loops back on itself. A caller shows the raw text in both cases: an
56
+ * unresolvable reference is still a reference, and inventing a value for it would be worse than
57
+ * saying nothing.
58
+ *
59
+ * @param {JxStyle | null | undefined} style
60
+ * @param {string | number | null | undefined} value
61
+ * @returns {string | number | undefined}
62
+ */
63
+ export function resolveTokenValue(
64
+ style: JxStyle | null | undefined,
65
+ value: string | number | null | undefined,
66
+ ): string | number | undefined {
67
+ if (value === null || value === undefined) {
68
+ return undefined;
69
+ }
70
+ let current: string | number = value;
71
+ const seen = new Set<string>();
72
+ for (let hop = 0; hop < MAX_HOPS; hop += 1) {
73
+ const ref = tokenRefName(current);
74
+ if (!ref) {
75
+ return current;
76
+ }
77
+ if (seen.has(ref)) {
78
+ return undefined;
79
+ }
80
+ seen.add(ref);
81
+ const next = style?.[ref];
82
+ if (typeof next !== "string" && typeof next !== "number") {
83
+ return undefined;
84
+ }
85
+ current = next;
86
+ }
87
+ return undefined;
88
+ }
89
+
90
+ /**
91
+ * Render a bound value as a chip: the referenced token's name, and — for a colour — the swatch it
92
+ * resolves to. The `title` carries the full reference and its resolution, because the chip is
93
+ * deliberately short and a reader who needs the literal must still be able to get it.
94
+ *
95
+ * The chip is not a control. Following it somewhere would be a second navigation contract on a
96
+ * surface that already lists every token a scroll away, and a chip that looks clickable and is not
97
+ * is the defect §6.2 removed from the collapsed-section dot.
98
+ *
99
+ * @param {string} name — the referenced token
100
+ * @param {string | number | undefined} resolved — {@link resolveTokenValue} of the reference
101
+ * @param {{ swatch?: boolean }} [opts] — `swatch` renders the resolved value as a colour chip
102
+ * @returns {TemplateResult}
103
+ */
104
+ export function renderTokenChip(
105
+ name: string,
106
+ resolved: string | number | undefined,
107
+ opts: { swatch?: boolean } = {},
108
+ ): TemplateResult {
109
+ const shown = resolved === undefined ? "unresolved" : String(resolved);
110
+ return html`
111
+ <span class="style-token-chip" title="${toTokenRef(name)} → ${shown}">
112
+ ${
113
+ opts.swatch && resolved !== undefined
114
+ ? html`<span
115
+ class="style-token-chip-swatch"
116
+ style="background:${String(resolved)}"
117
+ ></span>`
118
+ : ""
119
+ }
120
+ <span class="style-token-chip-label">${tokenLabel(name)}</span>
121
+ </span>
122
+ `;
123
+ }
@@ -74,16 +74,28 @@ export interface TransactionRecord {
74
74
  export interface PatchConsumer {
75
75
  /** Decide whether this batch can be applied surgically in the current canvas state. */
76
76
  classify: (tab: Tab, ops: JxPatchOp[]) => { patchable: boolean; reason: string };
77
- /** Mark a document root reference as surgically consumed (checked by the canvas doc-effect). */
78
- markConsumed: (docRef: object) => void;
77
+ /**
78
+ * Mark a document root reference as surgically consumed, in every pane the patch will reach.
79
+ *
80
+ * `tab` is what decides those panes — one pane owns it, and a derived pane may be projecting that
81
+ * pane — and each pane's canvas doc-effect clears only its own mark. A single mark per reference
82
+ * was consumed by whichever pane's effect ran first, so the second full-rendered every patched
83
+ * edit while the skip counter reported one skip.
84
+ */
85
+ markConsumed: (docRef: object, tab: Tab) => void;
79
86
  /**
80
87
  * Apply the batch to all ready canvas panels. Throws on any failure (caller escalates). `record`
81
88
  * carries the value-carrying `docOps` the iframe consumer posts across the frame boundary; the
82
89
  * legacy (parent-DOM) consumer ignores it and reads the post-mutation reactive doc instead.
83
90
  */
84
91
  apply: (tab: Tab, ops: JxPatchOp[], record?: TransactionRecord) => void;
85
- /** Schedule a full canvas render as the fallback path, recording the reason. */
86
- escalate: (reason: string) => void;
92
+ /**
93
+ * Schedule a full canvas render as the fallback path, recording the reason.
94
+ *
95
+ * `tab` names the document that failed to patch, and so the PANE whose stage must be rebuilt: a
96
+ * stage that is not showing this document is not out of date and must not be re-rendered.
97
+ */
98
+ escalate: (reason: string, tab: Tab) => void;
87
99
  }
88
100
 
89
101
  let _consumer: PatchConsumer | null = null;