@jxsuite/studio 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/studio-y64hrt8p.js +12 -0
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/tsMode-sf49ee9x.js +14 -0
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
@@ -13,6 +13,7 @@
13
13
  * that drops it, for callers that only want the value.
14
14
  */
15
15
 
16
+ import { getNestedStyle, isNumber, isString } from "@jxsuite/schema/guards";
16
17
  import type { JxStyle } from "@jxsuite/schema/types";
17
18
 
18
19
  /** One inherited property: the value that shows through, and the breakpoint it was set on. */
@@ -42,30 +43,29 @@ export function computeInheritedSources(
42
43
  return {};
43
44
  }
44
45
 
45
- const inherited: Record<string, InheritedSource> = {};
46
+ // A Map re-set keeps the key's first position, exactly as reassigning an object property does.
47
+ const inherited = new Map<string, InheritedSource>();
46
48
 
47
49
  /** Layer one block over the accumulator, recording `donor` for everything it contributes. */
48
- const layer = (block: JxStyle, donor: string | null) => {
49
- for (const [p, v] of Object.entries(block)) {
50
- if (typeof v !== "object") {
51
- inherited[p] = { donor, value: (v as string | number) ?? "" };
50
+ const layer = (block: JxStyle | undefined, donor: string | null) => {
51
+ for (const [p, v] of Object.entries(block ?? {})) {
52
+ // Declarations only: nested blocks, block lists and `$ref` objects are not inherited values.
53
+ if (v === undefined || isString(v) || isNumber(v)) {
54
+ inherited.set(p, { donor, value: v ?? "" });
52
55
  }
53
56
  }
54
57
  };
55
58
 
56
59
  if (activeSelector) {
57
60
  // Selector inheritance: base selector → each media's selector block, in cascade order.
58
- layer((style[activeSelector] || {}) as JxStyle, null);
61
+ layer(getNestedStyle(style, activeSelector), null);
59
62
  for (const name of mediaNames) {
60
63
  if (name === activeTab) {
61
64
  break;
62
65
  }
63
- layer(
64
- (((style[`@${name}`] || {}) as Record<string, unknown>)[activeSelector] || {}) as JxStyle,
65
- name,
66
- );
66
+ layer(getNestedStyle(getNestedStyle(style, `@${name}`), activeSelector), name);
67
67
  }
68
- return inherited;
68
+ return Object.fromEntries(inherited);
69
69
  }
70
70
 
71
71
  // Base flat props first, then each media block in order until the current tab.
@@ -74,9 +74,9 @@ export function computeInheritedSources(
74
74
  if (name === activeTab) {
75
75
  break;
76
76
  }
77
- layer((style[`@${name}`] || {}) as JxStyle, name);
77
+ layer(getNestedStyle(style, `@${name}`), name);
78
78
  }
79
- return inherited;
79
+ return Object.fromEntries(inherited);
80
80
  }
81
81
 
82
82
  /**
@@ -95,11 +95,9 @@ export function computeInheritedStyle(
95
95
  activeTab: string | null,
96
96
  activeSelector: string | null = null,
97
97
  ): Record<string, string | number> {
98
- const values: Record<string, string | number> = {};
99
- for (const [prop, source] of Object.entries(
100
- computeInheritedSources(style, mediaNames, activeTab, activeSelector),
101
- )) {
102
- values[prop] = source.value;
103
- }
104
- return values;
98
+ return Object.fromEntries(
99
+ Object.entries(computeInheritedSources(style, mediaNames, activeTab, activeSelector)).map(
100
+ ([prop, source]) => [prop, source.value],
101
+ ),
102
+ );
105
103
  }
@@ -71,7 +71,7 @@ export function classifyHref(href = ""): LinkTarget {
71
71
  * @param value The bare value for that kind (address/number/fragment/path/href)
72
72
  */
73
73
  export function composeHref(kind: LinkKind, value: string): string {
74
- const bare = (value ?? "").trim();
74
+ const bare = value.trim();
75
75
  if (!bare) {
76
76
  return "";
77
77
  }
@@ -5,17 +5,39 @@
5
5
  * strip-events pattern) so importing it never grows the iframe bundle.
6
6
  */
7
7
 
8
+ import type { JsonPrimitive } from "@jxsuite/schema/types";
9
+
8
10
  const MAX_BADGE_LENGTH = 48;
9
11
 
12
+ /**
13
+ * A value an expression evaluated to, as a badge has to show it: JSON from state, a bigint or
14
+ * symbol a helper returned, a function, and arrays and records of those. A record can be cyclic,
15
+ * and a bigint cannot be stringified at all, which is why formatting falls back to `String()`.
16
+ */
17
+ export type PreviewValue =
18
+ | JsonPrimitive
19
+ | undefined
20
+ | bigint
21
+ | symbol
22
+ | ((...args: never[]) => void)
23
+ | PreviewValue[]
24
+ | PreviewRecord;
25
+
26
+ /** An object an expression evaluated to, read key by key. */
27
+ export interface PreviewRecord {
28
+ [key: string]: PreviewValue;
29
+ }
30
+
10
31
  /** Format a runtime value as a short badge string. */
11
- export function formatPreviewValue(value?: unknown): string {
32
+ export function formatPreviewValue(value?: PreviewValue): string {
12
33
  if (value === undefined) {
13
34
  return "undefined";
14
35
  }
15
36
  let text: string;
16
37
  try {
17
- text =
18
- typeof value === "string" ? JSON.stringify(value) : (JSON.stringify(value) ?? "undefined");
38
+ // SAFETY: lib.d.ts declares a string, but JSON.stringify answers undefined for a function or a symbol.
39
+ const json = JSON.stringify(value) as string | undefined;
40
+ text = json ?? "undefined";
19
41
  } catch {
20
42
  text = String(value);
21
43
  }
@@ -8,44 +8,71 @@
8
8
  * editor's reactive `store.ts`; `store.ts` re-exports it for the legacy in-realm patcher.
9
9
  */
10
10
 
11
- import { isEventBinding } from "@jxsuite/schema/guards";
12
- import type { JxMutableNode } from "@jxsuite/schema/types";
11
+ import {
12
+ isEventBinding,
13
+ isJsonObject,
14
+ isNodeObject,
15
+ isNonNullObject,
16
+ } from "@jxsuite/schema/guards";
17
+ import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
13
18
 
14
- /** Strip all `on*` event-handler properties (and server-timed state) from a document tree. */
15
- export function stripEventHandlers(node: JxMutableNode): JxMutableNode {
16
- if (!node || typeof node !== "object") {
17
- return node;
18
- }
19
+ /**
20
+ * A node object as a document walker rebuilds it. Every key holds a document value, including the
21
+ * keys {@link JxMutableNode} names, because a walker copies whatever the source document holds;
22
+ * `undefined` is a key an editor cleared.
23
+ */
24
+ export type RebuiltNode = Record<string, JxDocumentValue | undefined>;
25
+
26
+ /**
27
+ * Whether a walker descends into `value`: any object, arrays included. A document is JSON, so every
28
+ * own value of such an object is itself a document value.
29
+ *
30
+ * @param value A value read out of a document.
31
+ */
32
+ export function isDocumentContainer(
33
+ value: JxDocumentValue | undefined,
34
+ ): value is JxDocumentValue[] | Readonly<RebuiltNode> {
35
+ return isNonNullObject(value);
36
+ }
37
+
38
+ /**
39
+ * Strip all `on*` event-handler properties (and server-timed state) from a document tree. Arrays
40
+ * are stripped member by member, and primitives and a cleared (`undefined`) key return unchanged,
41
+ * so the walk can recurse through any document value.
42
+ */
43
+ export function stripEventHandlers(node: JxMutableNode): JxMutableNode;
44
+ export function stripEventHandlers(node: JxDocumentValue): JxDocumentValue;
45
+ export function stripEventHandlers(node: JxDocumentValue | undefined): JxDocumentValue | undefined;
46
+ export function stripEventHandlers(node: JxDocumentValue | undefined): JxDocumentValue | undefined {
19
47
  if (Array.isArray(node)) {
20
48
  // Arrays of nodes round-trip element-wise; the array itself is not a node.
21
- return node.map((n: JxMutableNode) => stripEventHandlers(n)) as unknown as JxMutableNode;
49
+ return node.map((n) => stripEventHandlers(n));
22
50
  }
23
- const out: Record<string, unknown> = {};
51
+ if (!isNodeObject(node)) {
52
+ return node;
53
+ }
54
+ const out: RebuiltNode = {};
24
55
  for (const [k, v] of Object.entries(node)) {
25
56
  if (k.startsWith("on") && isEventBinding(v)) {
26
57
  continue;
27
58
  }
28
59
  if (k === "children") {
29
- out.children = Array.isArray(v)
30
- ? v.map((c: JxMutableNode) => stripEventHandlers(c))
31
- : stripEventHandlers(v as JxMutableNode);
32
- } else if (k === "cases" && typeof v === "object") {
33
- const cases: Record<string, unknown> = {};
34
- for (const [ck, cv] of Object.entries(v as Record<string, unknown>)) {
35
- cases[ck] = stripEventHandlers(cv as JxMutableNode);
60
+ out.children = Array.isArray(v) ? v.map((c) => stripEventHandlers(c)) : stripEventHandlers(v);
61
+ } else if (k === "cases" && isDocumentContainer(v)) {
62
+ const cases: RebuiltNode = {};
63
+ for (const [ck, cv] of Object.entries(v)) {
64
+ cases[ck] = stripEventHandlers(cv);
36
65
  }
37
66
  out.cases = cases;
38
- } else if (k === "state" && typeof v === "object" && v !== null) {
39
- const state: Record<string, unknown> = {};
40
- for (const [sk, sv] of Object.entries(v as Record<string, unknown>)) {
41
- if (sv && typeof sv === "object" && (sv as Record<string, unknown>).timing === "server") {
67
+ } else if (k === "state" && isDocumentContainer(v)) {
68
+ const state: RebuiltNode = {};
69
+ for (const [sk, sv] of Object.entries(v)) {
70
+ if (isJsonObject(sv) && sv.timing === "server") {
42
71
  continue;
43
72
  }
44
73
  state[sk] = sv;
45
74
  }
46
75
  out.state = state;
47
- } else if (k === "style" || k === "attributes" || k === "$media") {
48
- out[k] = v;
49
76
  } else {
50
77
  out[k] = v;
51
78
  }
@@ -6,7 +6,8 @@
6
6
 
7
7
  import { collectionForFile } from "../content/collection-match";
8
8
  import { defaultContentFormat } from "../format/format-host";
9
- import type { ProjectConfig } from "@jxsuite/schema/types";
9
+ import type { JsonValue, ProjectConfig } from "@jxsuite/schema/types";
10
+ import type { CssFontPreset } from "../panels/style-utils";
10
11
 
11
12
  /**
12
13
  * Convert camelCase property name to "Title Case" label (e.g. "backgroundColor" → "Background
@@ -39,31 +40,42 @@ export function kebabToLabel(val: string) {
39
40
  );
40
41
  }
41
42
 
43
+ /**
44
+ * What a css-meta or html-meta entry says about the field that edits it: its label, and the keys
45
+ * {@link inferInputType} picks the control from. Every other key an entry carries is ignored here.
46
+ */
47
+ export interface FieldControlMeta {
48
+ readonly $label?: string | undefined;
49
+ /** `true` on a shorthand row; css-meta puts the shorthand's own name on each longhand. */
50
+ readonly $shorthand?: string | boolean | undefined;
51
+ readonly $input?: string | undefined;
52
+ readonly $units?: readonly string[] | undefined;
53
+ readonly format?: string | undefined;
54
+ readonly type?: string | undefined;
55
+ readonly enum?: readonly JsonValue[] | undefined;
56
+ readonly examples?: readonly JsonValue[] | undefined;
57
+ readonly presets?: readonly (CssFontPreset | JsonValue)[] | undefined;
58
+ }
59
+
42
60
  /**
43
61
  * Get display label from metadata entry or prop name
44
62
  *
45
- * @param {{ $label?: string; [key: string]: unknown } | null | undefined} entry
63
+ * @param {FieldControlMeta | null | undefined} entry
46
64
  * @param {string} prop
47
65
  * @returns {string}
48
66
  */
49
- export function propLabel(
50
- entry: { $label?: string; [key: string]: unknown } | null | undefined,
51
- prop: string,
52
- ) {
67
+ export function propLabel(entry: FieldControlMeta | null | undefined, prop: string) {
53
68
  return entry?.$label || camelToLabel(prop);
54
69
  }
55
70
 
56
71
  /**
57
72
  * Label for HTML attributes — handles kebab-case (aria-label → "Aria Label")
58
73
  *
59
- * @param {{ $label?: string; [key: string]: unknown } | null | undefined} entry
74
+ * @param {FieldControlMeta | null | undefined} entry
60
75
  * @param {string} attr
61
76
  * @returns {string}
62
77
  */
63
- export function attrLabel(
64
- entry: { $label?: string; [key: string]: unknown } | null | undefined,
65
- attr: string,
66
- ) {
78
+ export function attrLabel(entry: FieldControlMeta | null | undefined, attr: string) {
67
79
  if (entry?.$label) {
68
80
  return entry.$label;
69
81
  }
@@ -92,17 +104,17 @@ export function attrLabel(
92
104
  * @param {unknown} format - A schema entry's `format`
93
105
  * @returns {boolean}
94
106
  */
95
- export function isMediaFormat(format: unknown): boolean {
107
+ export function isMediaFormat(format: unknown): format is "image" | "uri-reference" {
96
108
  return format === "image" || format === "uri-reference";
97
109
  }
98
110
 
99
111
  /**
100
112
  * Determine input widget type from a css-meta entry
101
113
  *
102
- * @param {Record<string, unknown>} entry
114
+ * @param {FieldControlMeta} entry
103
115
  * @returns {string}
104
116
  */
105
- export function inferInputType(entry: Record<string, unknown>) {
117
+ export function inferInputType(entry: FieldControlMeta) {
106
118
  if (entry.$shorthand === true) {
107
119
  return "shorthand";
108
120
  }
@@ -248,6 +260,9 @@ export function parseCemType(typeText: string | undefined | null) {
248
260
  * both required for document snapshots and clipboard payloads.
249
261
  */
250
262
  export function jsonClone<T>(value: T): T {
263
+ /* SAFETY: callers pass documents and clipboard payloads, which are JSON-shaped, and a JSON round
264
+ trip rebuilds such a value with the same structure. The only keys it loses hold undefined or a
265
+ function, which is the normalization this helper exists to perform. */
251
266
  // oxlint-disable-next-line unicorn/prefer-structured-clone -- structuredClone throws on reactive proxies; JSON normalization is the point
252
267
  return JSON.parse(JSON.stringify(value)) as T;
253
268
  }
package/src/view.ts CHANGED
@@ -66,8 +66,8 @@ export type MonacoSurface = editor.IStandaloneCodeEditor & {
66
66
  * offsets, the source-view Monaco and the render generation were all fields of "the canvas" — a
67
67
  * singular that stopped existing when the shell grew a pane grid. They are fields of a
68
68
  * {@link import("./canvas/canvas-surface").CanvasSurface} now, one record per pane, and
69
- * `scripts/check-pane-singletons.ts` fails the build if one grows back: the index signature below
70
- * means `view.panX` is not a type error, only a silently-`unknown` read.
69
+ * `scripts/check-pane-singletons.ts` fails the build if one grows back, and with no index signature
70
+ * on this record a read of `view.panX` is a type error as well.
71
71
  */
72
72
  interface ViewState {
73
73
  /**
@@ -103,7 +103,6 @@ interface ViewState {
103
103
  layerDragSourceHeight: number;
104
104
  _completionRegistered: boolean;
105
105
  _layersCollapsed: Set<string> | null;
106
- [key: string]: unknown;
107
106
  }
108
107
 
109
108
  export const view: ViewState = {
@@ -31,12 +31,13 @@
31
31
 
32
32
  import { effect } from "../reactivity";
33
33
  import { componentRegistry } from "../files/components";
34
- import { getNodeAtPath, parentElementPath } from "../store";
34
+ import { parentElementPath } from "../store";
35
35
 
36
36
  import { canvasPerf } from "../canvas/canvas-perf";
37
37
  import { canvasModeOfTab, tabOfPane } from "../canvas/canvas-surface";
38
38
  import { parseMediaEntries } from "../utils/canvas-media";
39
39
  import { getEffectiveLayoutPath, getEffectiveLocales, getEffectiveMedia } from "../site-context";
40
+ import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
40
41
  import { localeLabel, translationPathFor } from "@jxsuite/schema/locale";
41
42
  import { shell } from "../shell";
42
43
  import {
@@ -97,14 +98,14 @@ export type DerivePreset = (typeof DERIVE_PRESETS)[number];
97
98
  * pinned by a test (`per-preset refusals` · "Layout's gate is the layout RESOLVING") instead of
98
99
  * being asserted here in prose.
99
100
  */
100
- const MODE_FOR_PRESET: Readonly<Partial<Record<DerivePreset, string>>> = {
101
+ const MODE_FOR_PRESET: Readonly<Partial<Record<DerivePreset, keyof typeof MODE_WORDS>>> = {
101
102
  breakpoint: "design",
102
103
  code: "source",
103
104
  component: "design",
104
105
  };
105
106
 
106
107
  /** How a mode is spelled in a refusal — the words on the Editor axis, not the internal ids. */
107
- const MODE_WORDS: Readonly<Record<string, string>> = { design: "Design", source: "Code" };
108
+ const MODE_WORDS = { design: "Design", source: "Code" } as const;
108
109
 
109
110
  /** Said by a diff lens whose comparison came back empty. One sentence, one home. */
110
111
  const DIFF_UNREADABLE = "Could not read this file's comparison against HEAD.";
@@ -399,9 +400,7 @@ function companionTarget(
399
400
  hit is transient — `iframe-host.ts` clears it the moment the author clicks page content —
400
401
  so the page's own layout remains the answer for a derivation created from the preset menu. */
401
402
  const hit = shell.layoutSelection;
402
- const path =
403
- hit?.layoutFile ??
404
- getEffectiveLayoutPath(source.doc.document.$layout as string | false | undefined);
403
+ const path = hit?.layoutFile ?? getEffectiveLayoutPath(source.doc.document.$layout);
405
404
  return path === null
406
405
  ? {
407
406
  ...base,
@@ -421,7 +420,7 @@ function companionTarget(
421
420
  was a condition with no false branch, and an unreachable branch is a claim nobody can
422
421
  check. What stops a node path from layout A landing inside layout B is
423
422
  {@link selectInPane}, which compares against the document actually on screen. */
424
- select: hit ? (hit.layoutPath as JxPath) : null,
423
+ select: hit ? hit.layoutPath : null,
425
424
  status: "ready",
426
425
  };
427
426
  }
@@ -534,7 +533,7 @@ export function componentPathUnderSelection(tab: Tab | null): string | null {
534
533
  if (entry?.path) {
535
534
  return entry.path;
536
535
  }
537
- path = parentElementPath(path) as JxPath | null;
536
+ path = parentElementPath(path);
538
537
  }
539
538
  return null;
540
539
  }
@@ -758,7 +757,7 @@ function loadDiffFor(paneId: string, target: DerivedTarget, deps: DerivationDeps
758
757
  cannot re-enter, because neither of those answers carries a `diffPath`. */
759
758
  applyDerivation(paneId, deps);
760
759
  })
761
- .catch((error: unknown) => {
760
+ .catch((error) => {
762
761
  console.error("loadDiff error:", error);
763
762
  });
764
763
  }
@@ -808,7 +807,7 @@ function probeTranslationFor(paneId: string, target: DerivedTarget, deps: Deriva
808
807
  them carries a `probePath`, so this cannot re-enter. */
809
808
  applyDerivation(paneId, deps);
810
809
  })
811
- .catch((error: unknown) => {
810
+ .catch((error) => {
812
811
  console.error("fileExists error:", error);
813
812
  });
814
813
  }
@@ -1016,8 +1015,7 @@ export function presetRefusal(
1016
1015
  which `paneIsEmpty` will not collapse, whose strip drew nothing and whose stage drew nothing.
1017
1016
  `component` is deliberately NOT refused the same way — "select an element inside a component"
1018
1017
  is a rule that resolves on the next click, which is the whole point of leaving it open. */
1019
- return getEffectiveLayoutPath(source.doc.document.$layout as string | false | undefined) ===
1020
- null
1018
+ return getEffectiveLayoutPath(source.doc.document.$layout) === null
1021
1019
  ? "a page with a layout — this one declares none"
1022
1020
  : null;
1023
1021
  }
@@ -26,8 +26,16 @@
26
26
  */
27
27
 
28
28
  import { PRIMARY_PANE, SECONDARY_PANE, focusPane, workspace } from "./workspace";
29
+ import {
30
+ isBoolean,
31
+ isJsonObject,
32
+ isNonNullObject,
33
+ isNumber,
34
+ isString,
35
+ } from "@jxsuite/schema/guards";
29
36
  import { isWellFormedLocale } from "@jxsuite/schema/locale";
30
- import type { Tab } from "../tabs/tab";
37
+ import type { JsonValue } from "@jxsuite/schema/types";
38
+ import type { Tab, TabUi } from "../tabs/tab";
31
39
 
32
40
  /** One pane's share of a session. */
33
41
  export interface PersistedPane {
@@ -46,7 +54,7 @@ export interface PersistedTabUi {
46
54
  zoom?: number;
47
55
  editZoom?: number;
48
56
  activeMedia?: string | null;
49
- previewColorScheme?: string;
57
+ previewColorScheme?: TabUi["previewColorScheme"];
50
58
  /** BCP 47 tag, or `null` for "the document's own language". */
51
59
  previewLocale?: string | null;
52
60
  showLayout?: boolean;
@@ -62,7 +70,12 @@ export interface PersistedSession {
62
70
  }
63
71
 
64
72
  const PANE_IDS = new Set([PRIMARY_PANE, SECONDARY_PANE]);
65
- const SCHEMES = new Set(["auto", "light", "dark"]);
73
+ const SCHEMES: ReadonlySet<string> = new Set(["auto", "light", "dark"]);
74
+
75
+ /** Whether a stored value is one of the three schemes a tab's preview may be forced into. */
76
+ function isColorScheme(value: JsonValue | undefined): value is TabUi["previewColorScheme"] {
77
+ return isString(value) && SCHEMES.has(value);
78
+ }
66
79
 
67
80
  /** The view settings this tab was left in — the ones a person chose, not the ones derived. */
68
81
  function uiOf(tab: Tab): PersistedTabUi {
@@ -118,40 +131,42 @@ export function captureSession(): PersistedSession {
118
131
  }
119
132
 
120
133
  /** Whether a parsed value is a usable {@link PersistedTabUi}. Hand-edited storage is input. */
121
- function readTabUi(value: unknown): PersistedTabUi {
122
- if (typeof value !== "object" || value === null) {
134
+ function readTabUi(value: JsonValue | undefined): PersistedTabUi {
135
+ if (!isJsonObject(value)) {
123
136
  return {};
124
137
  }
125
- const raw = value as Record<string, unknown>;
126
138
  const out: PersistedTabUi = {};
127
- if (typeof raw.canvasMode === "string") {
128
- out.canvasMode = raw.canvasMode;
139
+ if (isString(value.canvasMode)) {
140
+ out.canvasMode = value.canvasMode;
129
141
  }
130
- if (typeof raw.preview === "boolean") {
131
- out.preview = raw.preview;
142
+ if (isBoolean(value.preview)) {
143
+ out.preview = value.preview;
132
144
  }
133
- if (typeof raw.zoom === "number" && Number.isFinite(raw.zoom)) {
134
- out.zoom = raw.zoom;
145
+ if (isNumber(value.zoom) && Number.isFinite(value.zoom)) {
146
+ out.zoom = value.zoom;
135
147
  }
136
- if (typeof raw.editZoom === "number" && Number.isFinite(raw.editZoom)) {
137
- out.editZoom = raw.editZoom;
148
+ if (isNumber(value.editZoom) && Number.isFinite(value.editZoom)) {
149
+ out.editZoom = value.editZoom;
138
150
  }
139
- if (raw.activeMedia === null || typeof raw.activeMedia === "string") {
140
- out.activeMedia = raw.activeMedia;
151
+ if (value.activeMedia === null || isString(value.activeMedia)) {
152
+ out.activeMedia = value.activeMedia;
141
153
  }
142
- if (typeof raw.previewColorScheme === "string" && SCHEMES.has(raw.previewColorScheme)) {
143
- out.previewColorScheme = raw.previewColorScheme;
154
+ if (isColorScheme(value.previewColorScheme)) {
155
+ out.previewColorScheme = value.previewColorScheme;
144
156
  }
145
157
  /* `null` is a value here, not an absence: it is "the document's own language", so a pane put
146
158
  deliberately back onto its own file's language would otherwise restore the tag it left.
147
159
  A tag is checked for WELL-FORMEDNESS only — whether the project still declares it is a
148
160
  question about `project.json`, which the reader cannot see and which changes between sessions;
149
161
  the control refuses an undeclared tag on the way in and the render falls back on the way out. */
150
- if (raw.previewLocale === null || isWellFormedLocale(raw.previewLocale)) {
151
- out.previewLocale = raw.previewLocale as string | null;
162
+ if (
163
+ value.previewLocale === null ||
164
+ (isString(value.previewLocale) && isWellFormedLocale(value.previewLocale))
165
+ ) {
166
+ out.previewLocale = value.previewLocale;
152
167
  }
153
- if (typeof raw.showLayout === "boolean") {
154
- out.showLayout = raw.showLayout;
168
+ if (isBoolean(value.showLayout)) {
169
+ out.showLayout = value.showLayout;
155
170
  }
156
171
  return out;
157
172
  }
@@ -159,35 +174,28 @@ function readTabUi(value: unknown): PersistedTabUi {
159
174
  /**
160
175
  * Validate a stored session. Returns `null` for anything that is not one — a corrupt record
161
176
  * restores nothing rather than restoring half a workspace.
177
+ *
178
+ * The input is whatever `JSON.parse` gave back for the stored record (or `undefined` when the
179
+ * project record has no session), so every field is decoded here rather than trusted.
162
180
  */
163
- export function readSession(value: unknown): PersistedSession | null {
164
- if (typeof value !== "object" || value === null) {
165
- return null;
166
- }
167
- const raw = value as Partial<PersistedSession>;
168
- if (!Array.isArray(raw.panes)) {
181
+ export function readSession(value: JsonValue | undefined): PersistedSession | null {
182
+ if (!isJsonObject(value) || !Array.isArray(value.panes)) {
169
183
  return null;
170
184
  }
171
185
  const panes: PersistedPane[] = [];
172
- for (const entry of raw.panes) {
173
- if (typeof entry !== "object" || entry === null) {
174
- continue;
175
- }
176
- const pane = entry as Partial<PersistedPane>;
177
- if (typeof pane.id !== "string" || !PANE_IDS.has(pane.id)) {
186
+ for (const pane of value.panes) {
187
+ if (!isJsonObject(pane) || !isString(pane.id) || !PANE_IDS.has(pane.id)) {
178
188
  continue;
179
189
  }
180
190
  const files = Array.isArray(pane.files)
181
- ? pane.files.filter((file): file is string => typeof file === "string" && file !== "")
191
+ ? pane.files.filter((file): file is string => isString(file) && file !== "")
182
192
  : [];
183
193
  if (files.length === 0) {
184
194
  continue;
185
195
  }
186
196
  panes.push({
187
197
  activeFile:
188
- typeof pane.activeFile === "string" && files.includes(pane.activeFile)
189
- ? pane.activeFile
190
- : null,
198
+ isString(pane.activeFile) && files.includes(pane.activeFile) ? pane.activeFile : null,
191
199
  files,
192
200
  id: pane.id,
193
201
  });
@@ -196,15 +204,17 @@ export function readSession(value: unknown): PersistedSession | null {
196
204
  return null;
197
205
  }
198
206
  const ui: Record<string, PersistedTabUi> = {};
199
- if (typeof raw.ui === "object" && raw.ui !== null) {
200
- for (const [path, entry] of Object.entries(raw.ui as Record<string, unknown>)) {
207
+ /* `isNonNullObject`, not `isJsonObject`: a hand-edited array here has always been read entry by
208
+ entry under its index keys, and this decoder keeps that rather than silently dropping it. */
209
+ if (isNonNullObject(value.ui)) {
210
+ for (const [path, entry] of Object.entries(value.ui)) {
201
211
  ui[path] = readTabUi(entry);
202
212
  }
203
213
  }
204
214
  return {
205
215
  focusedPane:
206
- typeof raw.focusedPane === "string" && PANE_IDS.has(raw.focusedPane)
207
- ? raw.focusedPane
216
+ isString(value.focusedPane) && PANE_IDS.has(value.focusedPane)
217
+ ? value.focusedPane
208
218
  : PRIMARY_PANE,
209
219
  panes,
210
220
  ui,
@@ -288,7 +298,7 @@ export async function restoreSession(
288
298
  ui.activeMedia = stored.activeMedia;
289
299
  }
290
300
  if (stored.previewColorScheme !== undefined) {
291
- ui.previewColorScheme = stored.previewColorScheme as "auto" | "dark" | "light";
301
+ ui.previewColorScheme = stored.previewColorScheme;
292
302
  }
293
303
  if (stored.previewLocale !== undefined) {
294
304
  ui.previewLocale = stored.previewLocale;