@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
@@ -39,7 +39,16 @@
39
39
  * mount, updated rather than rebuilt on every repaint (specs/extensions.md §9.1).
40
40
  */
41
41
 
42
- import { isRef } from "@jxsuite/schema/guards";
42
+ import {
43
+ isBoolean,
44
+ isJsonObject,
45
+ isNonNullObject,
46
+ isNumber,
47
+ isRef,
48
+ isString,
49
+ } from "@jxsuite/schema/guards";
50
+ import type { ReadonlyJsonObject } from "@jxsuite/schema/project-schemas";
51
+ import type { JsonObject, JsonValue, JxDocumentValue } from "@jxsuite/schema/types";
43
52
  import { createSchemaFormSurface } from "../surfaces/schema-form";
44
53
  import { openMenu } from "../surfaces/menu";
45
54
  import type { MenuHandle } from "../surfaces/menu";
@@ -58,15 +67,13 @@ import {
58
67
  slotCaps,
59
68
  } from "./value-source";
60
69
  import type { SlotMode } from "./value-source";
61
- import type { SignalOption } from "./dynamic-slot";
62
- import type { JsonValue } from "../types";
63
70
  import type {
64
71
  SchemaFormCellView,
65
72
  SchemaFormFieldView,
66
- SchemaFormOption,
67
73
  SchemaFormRowView,
68
74
  SchemaFormSurface,
69
75
  } from "../surfaces/schema-form";
76
+ import type { SurfaceOption } from "./surface";
70
77
 
71
78
  /** A (possibly nested) JSON Schema node, covering both object and property level keys. */
72
79
  export interface JsonSchema {
@@ -91,10 +98,19 @@ export interface JsonSchema {
91
98
  $ref?: string;
92
99
  }
93
100
 
101
+ /**
102
+ * What a form commits: the properties that changed, each with its new value. `undefined` removes
103
+ * the property — a cleared field is absent from the record, not stored as an empty string.
104
+ */
105
+ export type SchemaFormPatch = Record<string, JsonValue | undefined>;
106
+
94
107
  /** Host-provided context threaded to every control. */
95
108
  export interface SchemaFormContext {
96
- /** Resolve a `#/$context/…` pointer (or legacy sentinel) against the host's project config. */
97
- resolvePointer: (pointer: string, scope?: Record<string, unknown>) => unknown;
109
+ /**
110
+ * Resolve a `#/$context/…` pointer (or legacy sentinel) against the host's project config. A
111
+ * config section is document data, so the answer is whatever the config holds there.
112
+ */
113
+ resolvePointer: (pointer: string, scope?: JsonObject) => JxDocumentValue | JsonValue | undefined;
98
114
  /** Route params available for `$ref` bindings (e.g. from the document path). */
99
115
  params?: string[] | undefined;
100
116
  /**
@@ -117,8 +133,8 @@ export interface SchemaFormContext {
117
133
  export interface SchemaFormControlArgs {
118
134
  key: string;
119
135
  schema: JsonSchema;
120
- value: unknown;
121
- onChange: (next: unknown) => void;
136
+ value: JsonValue | undefined;
137
+ onChange: (next: JsonValue | undefined) => void;
122
138
  ctx: SchemaFormContext;
123
139
  /**
124
140
  * Ask the HOST to draw the form again, where it offered a way to.
@@ -153,7 +169,7 @@ export interface SchemaFormControlHandle {
153
169
 
154
170
  /** Options for {@link mountSchemaForm}. */
155
171
  export interface RenderFormOptions {
156
- onChange: (patch: Record<string, unknown>) => void;
172
+ onChange: (patch: SchemaFormPatch) => void;
157
173
  context?: SchemaFormContext | undefined;
158
174
  /**
159
175
  * Per-field overrides from `$studio.settings.entry.ui`: a registered control name, and/or an
@@ -217,7 +233,9 @@ const CONTENT_REF = /^#\/content\/([^/]+)$/;
217
233
  * reading of `$ref` is how the picker ends up existing three times with three behaviours.
218
234
  */
219
235
  export function referenceTarget(schema: { $ref?: string } | undefined): string | null {
220
- const match = typeof schema?.$ref === "string" ? CONTENT_REF.exec(schema.$ref) : null;
236
+ // The schema is project JSON, so the declared `string` is checked rather than trusted.
237
+ const ref = schema?.$ref;
238
+ const match = isString(ref) ? CONTENT_REF.exec(ref) : null;
221
239
  return match ? match[1]! : null;
222
240
  }
223
241
 
@@ -240,26 +258,30 @@ export const NULL_FORM_CONTEXT: SchemaFormContext = {
240
258
  * and sentinel strings resolve through the context's pointer resolver, applying object →
241
259
  * `Object.keys` and string[] → itself.
242
260
  *
243
- * @param {unknown} enumDef
261
+ * @param {JsonValue | undefined} enumDef
244
262
  * @param {SchemaFormContext | undefined} ctx
245
- * @param {Record<string, unknown>} [scope] - Scope for `{@param}` substitution (the form value)
263
+ * @param {JsonObject} [scope] - Scope for `{@param}` substitution (the form value)
246
264
  * @returns {string[] | undefined}
247
265
  */
248
266
  export function resolveFormEnum(
249
- enumDef: unknown,
267
+ enumDef: JsonValue | undefined,
250
268
  ctx?: SchemaFormContext,
251
- scope?: Record<string, unknown>,
269
+ scope?: JsonObject,
252
270
  ): string[] | undefined {
253
271
  if (Array.isArray(enumDef)) {
272
+ /* SAFETY: a form `enum` is a list of string choices — every select this engine draws is fed by
273
+ a settings fragment or collection schema that declares `type: "string"` beside its enum, and
274
+ each choice is only ever interpolated as text (an option label and value), which is what a
275
+ stray number would be read as too. */
254
276
  return enumDef as string[];
255
277
  }
256
278
  let pointer: string | undefined;
257
- if (enumDef && typeof enumDef === "object") {
258
- const ref = (enumDef as Record<string, unknown>).$ref;
259
- if (typeof ref === "string") {
279
+ if (isJsonObject(enumDef)) {
280
+ const ref = enumDef.$ref;
281
+ if (isString(ref)) {
260
282
  pointer = ref;
261
283
  }
262
- } else if (typeof enumDef === "string") {
284
+ } else if (isString(enumDef)) {
263
285
  // Legacy sentinel strings (e.g. "$contentTypes") resolve through the host's pointer resolver
264
286
  pointer = enumDef;
265
287
  }
@@ -270,7 +292,7 @@ export function resolveFormEnum(
270
292
  if (Array.isArray(resolved)) {
271
293
  return resolved.map(String);
272
294
  }
273
- if (resolved && typeof resolved === "object") {
295
+ if (isJsonObject(resolved)) {
274
296
  return Object.keys(resolved);
275
297
  }
276
298
  return undefined;
@@ -296,7 +318,7 @@ function isBindableField(ps: JsonSchema): boolean {
296
318
  }
297
319
 
298
320
  /** Every pointer this form's host says a value may come from. */
299
- function refSourcesFor(ctx: SchemaFormContext): SignalOption[] {
321
+ function refSourcesFor(ctx: SchemaFormContext): SurfaceOption[] {
300
322
  return [
301
323
  ...(ctx.signals ?? []).map((name) => ({ label: name, value: `#/state/${name}` })),
302
324
  ...(ctx.params ?? []).map((name) => ({ label: `$params/${name}`, value: `#/$params/${name}` })),
@@ -307,11 +329,11 @@ function refSourcesFor(ctx: SchemaFormContext): SignalOption[] {
307
329
  const NONE = "__none__";
308
330
 
309
331
  /** A value as a control reads it: a string, and never `"[object Object]"`. */
310
- function asText(value: unknown): string {
332
+ function asText(value: JsonValue | undefined): string {
311
333
  if (value === undefined || value === null) {
312
334
  return "";
313
335
  }
314
- return typeof value === "object" ? JSON.stringify(value, null, 2) : String(value);
336
+ return isNonNullObject(value) ? JSON.stringify(value, null, 2) : String(value);
315
337
  }
316
338
 
317
339
  // ─── Field validation (§16.1, inline tier) ───────────────────────────────────
@@ -328,13 +350,13 @@ function asText(value: unknown): string {
328
350
  * cannot see, so type-checking the reference itself would refuse every correct binding.
329
351
  *
330
352
  * @param {JsonSchema} schema
331
- * @param {unknown} value
353
+ * @param {JsonValue | undefined} value
332
354
  * @param {boolean} isRequired
333
355
  * @returns {string}
334
356
  */
335
357
  export function validateFieldValue(
336
358
  schema: JsonSchema,
337
- value: unknown,
359
+ value: JsonValue | undefined,
338
360
  isRequired: boolean,
339
361
  ): string {
340
362
  if (isRef(value)) {
@@ -348,7 +370,7 @@ export function validateFieldValue(
348
370
  return `Choose one of: ${schema.enum.map(String).join(", ")}.`;
349
371
  }
350
372
  if (schema.type === "number" || schema.type === "integer") {
351
- const n = typeof value === "number" ? value : Number(value);
373
+ const n = isNumber(value) ? value : Number(value);
352
374
  if (!Number.isFinite(n)) {
353
375
  return "Enter a number.";
354
376
  }
@@ -363,13 +385,14 @@ export function validateFieldValue(
363
385
  }
364
386
  return "";
365
387
  }
366
- if (schema.type === "boolean" && typeof value !== "boolean") {
388
+ if (schema.type === "boolean" && !isBoolean(value)) {
367
389
  return "Must be true or false.";
368
390
  }
369
391
  if (schema.type === "array" && !Array.isArray(value)) {
370
392
  return "Must be a list.";
371
393
  }
372
- if (schema.type === "object" && (typeof value !== "object" || Array.isArray(value))) {
394
+ // `null` is "empty" and answered above, so only a primitive or an array can fail here.
395
+ if (schema.type === "object" && !isJsonObject(value)) {
373
396
  return "Must be an object.";
374
397
  }
375
398
  return "";
@@ -392,9 +415,9 @@ interface FieldPlan {
392
415
  /** Item-property schemas, for an array-of-objects field. */
393
416
  itemProps?: Record<string, JsonSchema> | undefined;
394
417
  /** The rows currently held, so a cell edit can rebuild the array. */
395
- rows?: Record<string, unknown>[] | undefined;
418
+ rows?: JsonObject[] | undefined;
396
419
  /** The ladder, when this position offers one. */
397
- ladder?: { fieldKey: string; mode: SlotMode; offered: SlotMode[]; sources: SignalOption[] };
420
+ ladder?: { fieldKey: string; mode: SlotMode; offered: SlotMode[]; sources: SurfaceOption[] };
398
421
  /** A registered control owns the whole field; args are rebuilt for it on every repaint. */
399
422
  control?: SchemaFormMountedControl | undefined;
400
423
  /**
@@ -427,11 +450,7 @@ const TEXT_COMMIT_MS = 400;
427
450
 
428
451
  interface FormController {
429
452
  readonly host: HTMLElement;
430
- readonly update: (
431
- schema: JsonSchema,
432
- value: Record<string, unknown>,
433
- opts: RenderFormOptions,
434
- ) => void;
453
+ readonly update: (schema: JsonSchema, value: JsonObject, opts: RenderFormOptions) => void;
435
454
  readonly dispose: () => void;
436
455
  }
437
456
 
@@ -452,14 +471,14 @@ export function resetSchemaForms(): void {
452
471
  * @param {string} formKey Stable identity for this form — the same key updates the standing mount
453
472
  * instead of building a second one, which is what keeps the caret in a field across a repaint.
454
473
  * @param {JsonSchema} schema
455
- * @param {Record<string, unknown>} value The record being edited
474
+ * @param {JsonObject} value The record being edited
456
475
  * @param {RenderFormOptions} opts
457
476
  * @returns {HTMLElement} The form's own host, for a lit caller to place in its tree
458
477
  */
459
478
  export function mountSchemaForm(
460
479
  formKey: string,
461
480
  schema: JsonSchema,
462
- value: Record<string, unknown>,
481
+ value: JsonObject,
463
482
  opts: RenderFormOptions,
464
483
  ): HTMLElement {
465
484
  sweep(formKey);
@@ -490,7 +509,7 @@ function sweep(exceptKey: string): void {
490
509
 
491
510
  function createController(): FormController {
492
511
  let schema: JsonSchema = {};
493
- let value: Record<string, unknown> = {};
512
+ let value: JsonObject = {};
494
513
  let opts: RenderFormOptions = { onChange: () => {} };
495
514
  let ctx: SchemaFormContext = NULL_FORM_CONTEXT;
496
515
  const plans = new Map<string, FieldPlan>();
@@ -515,7 +534,7 @@ function createController(): FormController {
515
534
  run();
516
535
  };
517
536
 
518
- const patch = (prop: string, next: unknown): void => {
537
+ const patch = (prop: string, next: JsonValue | undefined): void => {
519
538
  opts.onChange({ [prop]: next });
520
539
  };
521
540
 
@@ -546,7 +565,8 @@ function createController(): FormController {
546
565
  }
547
566
  case "json": {
548
567
  try {
549
- patch(plan.prop, JSON.parse(raw) as unknown);
568
+ // SAFETY: `JSON.parse` with no reviver yields only JSON values, which is all a JsonValue is.
569
+ patch(plan.prop, JSON.parse(raw) as JsonValue);
550
570
  } catch {
551
571
  /* A half-typed object is not a refusal: the last parsable text is what the document
552
572
  keeps, and the field goes on showing what is actually in it. */
@@ -560,8 +580,8 @@ function createController(): FormController {
560
580
  };
561
581
 
562
582
  /** The field's items, each shallow-copied so a cell edit never writes through to the document. */
563
- const cellRows = (plan: FieldPlan): Record<string, unknown>[] => {
564
- const copies: Record<string, unknown>[] = [];
583
+ const cellRows = (plan: FieldPlan): JsonObject[] => {
584
+ const copies: JsonObject[] = [];
565
585
  for (const item of plan.rows ?? []) {
566
586
  copies.push({ ...item });
567
587
  }
@@ -574,10 +594,12 @@ function createController(): FormController {
574
594
  if (!plan?.itemProps) {
575
595
  return;
576
596
  }
577
- const seed: Record<string, unknown> = {};
597
+ const seed: JsonObject = {};
578
598
  for (const [k, v] of Object.entries(plan.itemProps)) {
579
599
  if (v.default !== undefined) {
580
- seed[k] = v.default;
600
+ /* SAFETY: an item schema is read from a JSON schema document, so the `default` it
601
+ declares is a JSON value. */
602
+ seed[k] = v.default as JsonValue;
581
603
  }
582
604
  }
583
605
  patch(field, [...cellRows(plan), seed]);
@@ -628,7 +650,7 @@ function createController(): FormController {
628
650
  },
629
651
  };
630
652
 
631
- function writeCell(field: string, row: string, cell: string, next: unknown): void {
653
+ function writeCell(field: string, row: string, cell: string, next: JsonValue | undefined): void {
632
654
  const plan = plans.get(field);
633
655
  if (!plan?.itemProps) {
634
656
  return;
@@ -640,20 +662,23 @@ function createController(): FormController {
640
662
  return;
641
663
  }
642
664
  const cellSchema = plan.itemProps[cell];
665
+ /* SAFETY: the one non-JSON member this row can gain is an `undefined` for a cleared cell, and
666
+ every host's `onChange` persists the patch as JSON (the entry, the def and the project config
667
+ are all serialized), where an undefined member is simply omitted. */
643
668
  rows[idx] = {
644
669
  ...target,
645
670
  [cell]: coerceCell(cellSchema, next, plan.refCells?.has(`${field}/${row}/${cell}`) ?? false),
646
- };
671
+ } as JsonObject;
647
672
  patch(field, rows);
648
673
  }
649
674
 
650
675
  /** A cell's committed string, as the item property's declared type. */
651
676
  function coerceCell(
652
677
  cellSchema: JsonSchema | undefined,
653
- next: unknown,
678
+ next: JsonValue | undefined,
654
679
  isPointer: boolean,
655
- ): unknown {
656
- if (typeof next === "boolean") {
680
+ ): JsonValue | undefined {
681
+ if (isBoolean(next)) {
657
682
  return next;
658
683
  }
659
684
  const raw = String(next);
@@ -687,7 +712,7 @@ function createController(): FormController {
687
712
  opener: anchor,
688
713
  region: "value-source",
689
714
  rows: offered.map((rung) => ({
690
- checked: (rung === mode ? "true" : "false") as "true" | "false",
715
+ checked: rung === mode ? ("true" as const) : ("false" as const),
691
716
  destructive: false,
692
717
  disabled: false,
693
718
  dividerAbove: false,
@@ -695,12 +720,14 @@ function createController(): FormController {
695
720
  title: VALUE_SOURCE_LABELS[rung],
696
721
  })),
697
722
  run: (id) => {
698
- const next = id as SlotMode;
699
- if (next === mode) {
723
+ // The menu's rows are `offered`, so an id is always one of its rungs.
724
+ const next = offered.find((rung) => rung === id);
725
+ if (next === undefined || next === mode) {
700
726
  return;
701
727
  }
702
728
  /* Leaving From data… seeds an empty Fixed value stash with the property's declared default,
703
729
  so unbind-restores-default survives a detour through Mixed text. */
730
+ // SAFETY: the field schema is read from JSON, so the `default` it declares is a JSON value.
704
731
  const literalDefault = plan.schema.default as JsonValue | undefined;
705
732
  if (
706
733
  mode === "ref" &&
@@ -715,7 +742,7 @@ function createController(): FormController {
715
742
  fieldKey,
716
743
  mode,
717
744
  next,
718
- cloneValue(value[plan.prop] as JsonValue | undefined),
745
+ cloneValue(value[plan.prop]),
719
746
  slotModeSeed(next, { extraSignals: sources, literalDefault, stateDefs: [] }),
720
747
  ),
721
748
  );
@@ -853,7 +880,7 @@ function createController(): FormController {
853
880
  /** Every row the document draws, and the plan that reads each one's gestures back. */
854
881
  function deriveFields(
855
882
  schema: JsonSchema,
856
- value: Record<string, unknown>,
883
+ value: JsonObject,
857
884
  opts: RenderFormOptions,
858
885
  ctx: SchemaFormContext,
859
886
  plans: Map<string, FieldPlan>,
@@ -877,8 +904,8 @@ interface DeriveArgs {
877
904
  opts: RenderFormOptions;
878
905
  plans: Map<string, FieldPlan>;
879
906
  required: boolean;
880
- sources: SignalOption[];
881
- value: Record<string, unknown>;
907
+ sources: SurfaceOption[];
908
+ value: JsonObject;
882
909
  }
883
910
 
884
911
  function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaFormFieldView {
@@ -938,7 +965,10 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
938
965
  const mode = effectiveSlotMode(fieldKey, current);
939
966
  /* A From data… rung with nothing to point at is a dead end — but this engine only ladders a
940
967
  field once the host has named a source, so the rung always has something in it. */
941
- const offered = slotCaps({ schema: configFieldSchema(ps) });
968
+ /* SAFETY: `JsonSchema` names only the keywords this engine acts on; the node itself is a schema
969
+ read from JSON (a settings fragment, a collection or plugin schema), so it and every keyword
970
+ it carries beyond the named ones are JSON, which is all the ladder's walk reads it as. */
971
+ const offered = slotCaps({ schema: configFieldSchema(ps as ReadonlyJsonObject) });
942
972
  plan.ladder = { fieldKey, mode, offered, sources };
943
973
  row.hasChip = true;
944
974
  row.sourceLabel = VALUE_SOURCE_LABELS[mode];
@@ -1002,7 +1032,10 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1002
1032
  }
1003
1033
  }
1004
1034
 
1005
- const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);
1035
+ /* SAFETY: both sources are read from JSON — the descriptor's `$studio.settings.entry.ui` and the
1036
+ field schema — so whichever `enum` is present is a JSON value. */
1037
+ const enumSource = (opts.ui?.[prop]?.enum ?? ps.enum) as JsonValue | undefined;
1038
+ const enumValues = resolveFormEnum(enumSource, ctx, value);
1006
1039
  if (enumValues) {
1007
1040
  plan.commit = "select";
1008
1041
  plan.debounceMs = 0;
@@ -1041,7 +1074,7 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1041
1074
  row.kind = "json";
1042
1075
  row.value = current !== undefined ? JSON.stringify(current, null, 2) : "";
1043
1076
  row.placeholder = ps.description ?? "JSON Schema defining the data shape…";
1044
- row.chips = shapeChips(current);
1077
+ row.chips = schemaPropertyChips(current);
1045
1078
  row.hasChips = row.chips.length > 0;
1046
1079
  return row;
1047
1080
  }
@@ -1066,17 +1099,19 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1066
1099
  }
1067
1100
 
1068
1101
  /** The property chips above a JSON-Schema field: what shape is in there right now. */
1069
- function shapeChips(current: unknown): { key: string; label: string }[] {
1070
- if (!current || typeof current !== "object") {
1102
+ function schemaPropertyChips(current: JsonValue | undefined): { key: string; label: string }[] {
1103
+ // An array names no `properties`, so it has no chips either.
1104
+ if (!isJsonObject(current)) {
1071
1105
  return [];
1072
1106
  }
1073
- const held = current as Record<string, unknown>;
1074
- if (held.$ref || typeof held.properties !== "object" || held.properties === null) {
1107
+ const { properties } = current;
1108
+ if (current.$ref || properties === null || !isNonNullObject(properties)) {
1075
1109
  return [];
1076
1110
  }
1077
- return Object.entries(held.properties as Record<string, Record<string, unknown>>).map(
1078
- ([key, spec]) => ({ key, label: `${key}: ${String(spec.type ?? "any")}` }),
1079
- );
1111
+ return Object.entries(properties).map(([key, spec]) => ({
1112
+ key,
1113
+ label: `${key}: ${String((isJsonObject(spec) ? spec.type : undefined) ?? "any")}`,
1114
+ }));
1080
1115
  }
1081
1116
 
1082
1117
  /** An array whose items have a declared shape: one row per item, one cell per property. */
@@ -1088,7 +1123,10 @@ function arrayOfObjects(
1088
1123
  row: SchemaFormFieldView,
1089
1124
  ): SchemaFormFieldView {
1090
1125
  const held = args.value[prop];
1091
- const rows = Array.isArray(held) ? (held as Record<string, unknown>[]) : [];
1126
+ /* SAFETY: the caller dispatches here only for a property whose schema declares
1127
+ `items.type: "object"`, so a conforming record holds an object per item; a malformed item is
1128
+ still drawn as the row it should be, as it always was, rather than silently dropped. */
1129
+ const rows = Array.isArray(held) ? (held as JsonObject[]) : [];
1092
1130
  plan.commit = "none";
1093
1131
  plan.itemProps = itemProps;
1094
1132
  plan.rows = rows;
@@ -1102,7 +1140,7 @@ function arrayOfObjects(
1102
1140
  function deriveRow(
1103
1141
  prop: string,
1104
1142
  key: string,
1105
- item: Record<string, unknown>,
1143
+ item: JsonObject,
1106
1144
  itemProps: Record<string, JsonSchema>,
1107
1145
  args: DeriveArgs,
1108
1146
  plan: FieldPlan,
@@ -1122,7 +1160,7 @@ function deriveCell(
1122
1160
  rowKey: string,
1123
1161
  cellKey: string,
1124
1162
  cellSchema: JsonSchema,
1125
- held: unknown,
1163
+ held: JsonValue | undefined,
1126
1164
  args: DeriveArgs,
1127
1165
  plan: FieldPlan,
1128
1166
  ): SchemaFormCellView {
@@ -1160,13 +1198,18 @@ function deriveCell(
1160
1198
  return cell;
1161
1199
  }
1162
1200
  }
1163
- const enumValues = resolveFormEnum(cellSchema.enum, args.ctx, args.value);
1201
+ // SAFETY: an item property's schema is read from JSON, so its `enum` is a JSON value.
1202
+ const enumValues = resolveFormEnum(
1203
+ cellSchema.enum as JsonValue | undefined,
1204
+ args.ctx,
1205
+ args.value,
1206
+ );
1164
1207
  if (enumValues) {
1165
1208
  cell.kind = "select";
1166
1209
  cell.value = held !== undefined ? String(held) : NONE;
1167
1210
  cell.options = [
1168
1211
  { label: "—", value: NONE },
1169
- ...enumValues.map((v: string): SchemaFormOption => ({ label: v, value: v })),
1212
+ ...enumValues.map((v: string): SurfaceOption => ({ label: v, value: v })),
1170
1213
  ];
1171
1214
  return cell;
1172
1215
  }
package/src/ui/surface.ts CHANGED
@@ -11,8 +11,9 @@
11
11
  * @docs extending/ui-kit
12
12
  */
13
13
  import { mount, preloadDocument } from "@jxsuite/runtime";
14
- import type { JxMountOptions, JxScope } from "@jxsuite/runtime/types";
14
+ import type { JxHostScope, JxMountOptions, JxScope } from "@jxsuite/runtime/types";
15
15
  import type { JxDocument } from "@jxsuite/schema/types";
16
+ import type { SelectRow } from "@jxsuite/ui/behaviors/select";
16
17
  import { registerMount, unregisterMount } from "../services/surface-registry";
17
18
  import { kitReady } from "./kit";
18
19
  import { REGION_ATTR } from "./regions";
@@ -49,6 +50,61 @@ export function surfaceResolver(url: string): JxDocument | undefined {
49
50
  return surfaces.get(url.slice(SURFACES_BASE.length, -".json".length));
50
51
  }
51
52
 
53
+ /**
54
+ * One row a surface document draws in a picker (a `jx-select` option, a radio, a segmented button):
55
+ * the value the control reports back, and the label the reader sees. The kit's own row, the one
56
+ * `jx-select` draws.
57
+ */
58
+ export type { SelectRow as SurfaceOption } from "@jxsuite/ui/behaviors/select";
59
+
60
+ /**
61
+ * One thing a surface document draws for the reader to act on (an empty state's button, an openable
62
+ * source): an id only the flow knows the meaning of, and the words on it.
63
+ */
64
+ export interface SurfaceAction {
65
+ id: string;
66
+ label: string;
67
+ }
68
+
69
+ /** A delimited, labelled run of picker rows: the kit's `optgroup`, which draws both halves of it. */
70
+ export interface SurfaceOptionGroup {
71
+ id: string;
72
+ label: string;
73
+ rows: SelectRow[];
74
+ }
75
+
76
+ /** A dialog document mounted into the dialog layer, as the flow that opened it holds it. */
77
+ export interface DialogLayerHandle {
78
+ /** The slot in the dialog layer that carries the region. */
79
+ host: HTMLElement;
80
+ /** Resolves with the `jx-dialog` element once it has rendered and been opened. */
81
+ ready: Promise<HTMLElement>;
82
+ /** Close the dialog (the platform restores focus) and dispose the document. Idempotent. */
83
+ close: () => void;
84
+ }
85
+
86
+ /** A label, and the key that identifies what it names (a chip, a section, a menu choice). */
87
+ export interface KeyedLabel {
88
+ key: string;
89
+ label: string;
90
+ }
91
+
92
+ /** A label, and the tag it stands for (a declared language, an element a button adds). */
93
+ export interface TaggedLabel {
94
+ tag: string;
95
+ label: string;
96
+ }
97
+
98
+ /** One tab a surface document draws in a tablist strip. */
99
+ export interface SurfaceTab {
100
+ /** The tab's identity: the row key, the strip's `selected` value, and `data-tab`. */
101
+ key: string;
102
+ /** What the tab reads, badge included ("Problems 2"). */
103
+ label: string;
104
+ /** The tab element's own id, which the one panel names as its `aria-labelledby`. */
105
+ tabId: string;
106
+ }
107
+
52
108
  export interface SurfaceHandle {
53
109
  readonly scope: JxScope;
54
110
  readonly root: HTMLElement | Text;
@@ -69,9 +125,9 @@ export interface MountSurfaceOptions {
69
125
  *
70
126
  * @throws {Error} When no document is registered under `name`
71
127
  */
72
- export async function mountSurface(
128
+ export async function mountSurface<S extends JxHostScope<S>>(
73
129
  name: string,
74
- hostScope: Record<string, unknown>,
130
+ hostScope: S,
75
131
  host: HTMLElement,
76
132
  options: MountSurfaceOptions = {},
77
133
  ): Promise<SurfaceHandle> {
@@ -83,14 +139,21 @@ export async function mountSurface(
83
139
  if (options.region) {
84
140
  host.setAttribute(REGION_ATTR, options.region);
85
141
  }
86
- const handle = await mount(doc, host, {
142
+ const mountOptions: JxMountOptions<S> = {
87
143
  scope: hostScope,
88
144
  base: SURFACES_BASE,
89
145
  resolver: surfaceResolver,
90
- ...(options.onNodeCreated ? { onNodeCreated: options.onNodeCreated } : {}),
91
- ...(options.onNodeMoved ? { onNodeMoved: options.onNodeMoved } : {}),
92
- ...(options.signal ? { signal: options.signal } : {}),
93
- });
146
+ };
147
+ if (options.onNodeCreated) {
148
+ mountOptions.onNodeCreated = options.onNodeCreated;
149
+ }
150
+ if (options.onNodeMoved) {
151
+ mountOptions.onNodeMoved = options.onNodeMoved;
152
+ }
153
+ if (options.signal) {
154
+ mountOptions.signal = options.signal;
155
+ }
156
+ const handle = await mount(doc, host, mountOptions);
94
157
 
95
158
  const surfaceHandle = (dispose: () => void): SurfaceHandle => ({
96
159
  dispose,
package/src/ui/timing.ts CHANGED
@@ -35,6 +35,15 @@ export const CODE_DEBOUNCE = 500;
35
35
  */
36
36
  export const LIVE_PREVIEW = 350;
37
37
 
38
+ /**
39
+ * How long a keystroke in a `<head>` field waits before it is written: the Search-appearance
40
+ * dialog's fields (a document mutation the previews repaint from) and Project Settings' `$head`
41
+ * rows (a `project.json` write). Both time each field separately, so editing one field and then
42
+ * another inside the window lands both, and a `change` (blur, or a clear button) commits at once,
43
+ * so nothing is lost to the wait.
44
+ */
45
+ export const HEAD_EDIT_DEBOUNCE = 300;
46
+
38
47
  /*
39
48
  * `STATUS_MESSAGE = 3000` used to live here: how long a transient message stayed in the status bar
40
49
  * before it erased itself. It had one reader, `statusMessage`, which is deleted — the bar carries