@jxsuite/studio 6.1.1 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (785) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  4. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  5. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  6. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  7. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  8. package/dist/chunks/color-area-6rbra5dy.js +4 -0
  9. package/dist/chunks/color-field-gy56c94g.js +4 -0
  10. package/dist/chunks/color-m7r1vk54.js +4 -0
  11. package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
  12. package/dist/chunks/combobox-72h32ejk.js +4 -0
  13. package/dist/chunks/components-r22xca09.js +4 -0
  14. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  15. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  16. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  17. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  18. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  19. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  20. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  21. package/dist/chunks/files-rcn56qvm.js +4 -0
  22. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  23. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  24. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  25. package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
  26. package/dist/chunks/icons-63bjtbs7.js +4 -0
  27. package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
  28. package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
  29. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  30. package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
  31. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  32. package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
  33. package/dist/chunks/index-f0jn7nnp.js +4 -0
  34. package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
  35. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  36. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  37. package/dist/chunks/layers-bgyr11tr.js +4 -0
  38. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  39. package/dist/chunks/listbox-c421cf8c.js +4 -0
  40. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  41. package/dist/chunks/media-library-sq468wts.js +4 -0
  42. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  43. package/dist/chunks/menu-bdpzbfvs.js +4 -0
  44. package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
  45. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  46. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  47. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  48. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  49. package/dist/chunks/parse-v77xtwv7.js +4 -0
  50. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  51. package/dist/chunks/popover-b89sfej7.js +4 -0
  52. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  53. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  54. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  55. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  56. package/dist/chunks/references-9547rg5s.js +4 -0
  57. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  58. package/dist/chunks/select-rzds841e.js +4 -0
  59. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  60. package/dist/chunks/split-c9zfdgxf.js +4 -0
  61. package/dist/chunks/studio-03ct6yfv.js +9 -0
  62. package/dist/chunks/studio-07rcfje3.js +5 -0
  63. package/dist/chunks/studio-3e54qh39.js +7 -0
  64. package/dist/chunks/studio-3exxhz5g.js +5 -0
  65. package/dist/chunks/studio-3q40e3rj.js +5 -0
  66. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  67. package/dist/chunks/studio-3qqjeep5.js +6 -0
  68. package/dist/chunks/studio-43sd2mam.js +4 -0
  69. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  70. package/dist/chunks/studio-58xg6j2q.js +9 -0
  71. package/dist/chunks/studio-5g0rprdt.js +7 -0
  72. package/dist/chunks/studio-6m380wp7.js +5 -0
  73. package/dist/chunks/studio-80jyh1xh.js +4 -0
  74. package/dist/chunks/studio-83mk4bgg.js +9 -0
  75. package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
  76. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  77. package/dist/chunks/studio-8tr6cfrc.js +5 -0
  78. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  79. package/dist/chunks/studio-9tmebf0s.js +5 -0
  80. package/dist/chunks/studio-a2bvaptz.js +5 -0
  81. package/dist/chunks/studio-b7y5mr30.js +5 -0
  82. package/dist/chunks/studio-bavb31r0.js +5 -0
  83. package/dist/chunks/studio-bbe4c90a.js +5 -0
  84. package/dist/chunks/studio-c05wdnt3.js +5 -0
  85. package/dist/chunks/studio-ccv2svc6.js +5 -0
  86. package/dist/chunks/studio-d5grtb9e.js +16 -0
  87. package/dist/chunks/studio-df0baea9.js +5 -0
  88. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  89. package/dist/chunks/studio-e1g64q43.js +5 -0
  90. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  91. package/dist/chunks/studio-ed3xx40h.js +7 -0
  92. package/dist/chunks/studio-f14e1zdj.js +5 -0
  93. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  94. package/dist/chunks/studio-fyh0jc96.js +5 -0
  95. package/dist/chunks/studio-gcxk20n7.js +5 -0
  96. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  97. package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
  98. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  99. package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
  100. package/dist/chunks/studio-k7evxqh4.js +5 -0
  101. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  102. package/dist/chunks/studio-m8g16bgz.js +5 -0
  103. package/dist/chunks/studio-mn0476ag.js +5 -0
  104. package/dist/chunks/studio-mx1smyq0.js +5 -0
  105. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  106. package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
  107. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  108. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  109. package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
  110. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  111. package/dist/chunks/studio-ph84avkf.js +5 -0
  112. package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
  113. package/dist/chunks/studio-q0tccd43.js +5 -0
  114. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  115. package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
  116. package/dist/chunks/studio-qmn1xc24.js +5 -0
  117. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  118. package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
  119. package/dist/chunks/studio-rj9eamf8.js +5 -0
  120. package/dist/chunks/studio-rptgsk96.js +5 -0
  121. package/dist/chunks/studio-rthyg42z.js +928 -0
  122. package/dist/chunks/studio-s19tp1xr.js +5 -0
  123. package/dist/chunks/studio-s32578pn.js +5 -0
  124. package/dist/chunks/studio-svb7yyve.js +5 -0
  125. package/dist/chunks/studio-syreb644.js +5 -0
  126. package/dist/chunks/studio-tf9jryb1.js +10 -0
  127. package/dist/chunks/studio-tfkznv39.js +5 -0
  128. package/dist/chunks/studio-tft6r105.js +5 -0
  129. package/dist/chunks/studio-txf2kysx.js +5 -0
  130. package/dist/chunks/studio-v8867ddv.js +12 -0
  131. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  132. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  133. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  134. package/dist/chunks/studio-wc649wss.js +5 -0
  135. package/dist/chunks/studio-wys23mxz.js +5 -0
  136. package/dist/chunks/studio-x1x167jh.js +5 -0
  137. package/dist/chunks/studio-x9hsze61.js +5 -0
  138. package/dist/chunks/studio-y0n7yxea.js +9 -0
  139. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  140. package/dist/chunks/studio-z97c48fk.js +5 -0
  141. package/dist/chunks/studio-zat62m0c.js +5 -0
  142. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  143. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  144. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  145. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  146. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  147. package/dist/chunks/toast-1gv0h53h.js +4 -0
  148. package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
  149. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  150. package/dist/chunks/tooltip-yypz28gq.js +4 -0
  151. package/dist/chunks/tree-9xa4hm7n.js +4 -0
  152. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  153. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  154. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  155. package/dist/chunks/ws-client-bv552sfx.js +4 -0
  156. package/dist/iframe-entry.js +20 -16
  157. package/dist/manifest.json +77 -63
  158. package/dist/studio.js +106 -107
  159. package/dist/workers/ts.worker.js +3 -3
  160. package/package.json +17 -16
  161. package/src/about/about-modal.ts +4 -3
  162. package/src/account/action-flow.ts +45 -38
  163. package/src/account-status.ts +7 -2
  164. package/src/browse/component-examples.ts +272 -0
  165. package/src/browse/library-commands.ts +64 -104
  166. package/src/browse/library-layouts.ts +270 -53
  167. package/src/browse/library-model.ts +194 -134
  168. package/src/browse/library-pane.ts +748 -440
  169. package/src/browse/library-preview.ts +161 -26
  170. package/src/browse/library-source.ts +308 -41
  171. package/src/browse/preview-root.ts +78 -0
  172. package/src/browse/preview-style.ts +155 -0
  173. package/src/canvas/asset-refs.ts +40 -10
  174. package/src/canvas/asset-resolve.ts +19 -23
  175. package/src/canvas/canvas-helpers.ts +7 -6
  176. package/src/canvas/canvas-live-render.ts +260 -77
  177. package/src/canvas/canvas-origin.ts +37 -12
  178. package/src/canvas/canvas-page-context.ts +112 -0
  179. package/src/canvas/canvas-patcher.ts +30 -30
  180. package/src/canvas/canvas-perf.ts +11 -5
  181. package/src/canvas/canvas-render.ts +175 -148
  182. package/src/canvas/canvas-surface.ts +5 -3
  183. package/src/canvas/canvas-utils.ts +147 -61
  184. package/src/canvas/dialog-path.ts +9 -4
  185. package/src/canvas/dialog-state.ts +1 -2
  186. package/src/canvas/diff-marks.ts +9 -16
  187. package/src/canvas/diff-toolbar.ts +8 -7
  188. package/src/canvas/edit-width-drag.ts +4 -1
  189. package/src/canvas/edit-width.ts +1 -3
  190. package/src/canvas/iframe-channel.ts +27 -13
  191. package/src/canvas/iframe-drop.ts +120 -12
  192. package/src/canvas/iframe-editable-root.ts +29 -16
  193. package/src/canvas/iframe-entry.ts +104 -75
  194. package/src/canvas/iframe-eval.ts +73 -49
  195. package/src/canvas/iframe-host.ts +269 -158
  196. package/src/canvas/iframe-inline-edit.ts +49 -30
  197. package/src/canvas/iframe-insert.ts +5 -4
  198. package/src/canvas/iframe-interaction.ts +30 -25
  199. package/src/canvas/iframe-keys.ts +11 -0
  200. package/src/canvas/iframe-overlay.ts +1 -1
  201. package/src/canvas/iframe-patch.ts +25 -21
  202. package/src/canvas/iframe-position.ts +12 -6
  203. package/src/canvas/iframe-protocol.ts +36 -21
  204. package/src/canvas/iframe-render.ts +84 -35
  205. package/src/canvas/iframe-slash.ts +24 -11
  206. package/src/canvas/iframe-subtree.ts +10 -3
  207. package/src/canvas/npm-modules.ts +22 -0
  208. package/src/canvas/path-mapping.ts +19 -12
  209. package/src/canvas/popover-path.ts +7 -3
  210. package/src/canvas/popover-state.ts +1 -2
  211. package/src/canvas/preview-navigate.ts +16 -0
  212. package/src/canvas/repeater-sources.ts +200 -0
  213. package/src/canvas/serialize-scope.ts +13 -5
  214. package/src/canvas/stage-scrollbar.ts +7 -2
  215. package/src/canvas/surface-registry.ts +27 -3
  216. package/src/collab/collab-commands.ts +7 -2
  217. package/src/collab/collab-session.ts +84 -45
  218. package/src/collab/collab-state.ts +4 -3
  219. package/src/collab/monaco-binding.ts +16 -13
  220. package/src/collab/monaco-cursors.ts +5 -2
  221. package/src/commands/app-commands.ts +16 -6
  222. package/src/commands/budget.ts +13 -11
  223. package/src/commands/command-args.ts +103 -71
  224. package/src/commands/context.ts +55 -28
  225. package/src/commands/defaults.ts +69 -45
  226. package/src/commands/keymap.ts +56 -43
  227. package/src/commands/levels.ts +14 -8
  228. package/src/commands/live-context.ts +9 -7
  229. package/src/commands/reference.ts +2 -1
  230. package/src/commands/registry.ts +22 -11
  231. package/src/commands/run-reported.ts +15 -10
  232. package/src/component-props.ts +46 -30
  233. package/src/content/collection-match.ts +11 -9
  234. package/src/content/collection-pages.ts +412 -0
  235. package/src/content/content-collections.ts +270 -0
  236. package/src/content/draft-state.ts +4 -3
  237. package/src/content/entry-commands.ts +54 -62
  238. package/src/content/entry-editor.ts +137 -32
  239. package/src/content/entry-fields.ts +25 -8
  240. package/src/content/entry-inspector.ts +225 -0
  241. package/src/content/entry-model.ts +38 -15
  242. package/src/content/entry-open.ts +80 -0
  243. package/src/content/entry-summaries.ts +440 -0
  244. package/src/content/file-record-ids.ts +80 -0
  245. package/src/content/file-records.ts +125 -0
  246. package/src/content/page-summaries.ts +129 -0
  247. package/src/content/record-entry.ts +201 -0
  248. package/src/content/writing-banner.ts +177 -0
  249. package/src/create/add-new-commands.ts +185 -0
  250. package/src/create/add-new-flow.ts +1116 -0
  251. package/src/create/add-new.ts +1014 -0
  252. package/src/create/element-name.ts +121 -0
  253. package/src/editor/canvas-context-menu.ts +1 -2
  254. package/src/editor/canvas-slash-bridge.ts +3 -6
  255. package/src/editor/content-slice.ts +16 -14
  256. package/src/editor/context-menu.ts +35 -22
  257. package/src/editor/convert-targets.ts +30 -35
  258. package/src/editor/convert-to-component.ts +78 -48
  259. package/src/editor/convert-to-repeater.ts +34 -22
  260. package/src/editor/editable-tags.ts +17 -2
  261. package/src/editor/file-drop-action.ts +29 -22
  262. package/src/editor/inline-edit-apply.ts +79 -17
  263. package/src/editor/inline-edit.ts +76 -50
  264. package/src/editor/inline-format.ts +59 -56
  265. package/src/editor/inline-link.ts +40 -15
  266. package/src/editor/insert-component.ts +91 -0
  267. package/src/editor/insert-zone-action.ts +14 -5
  268. package/src/editor/merge-tags.ts +58 -19
  269. package/src/editor/repeater-scope.ts +39 -28
  270. package/src/editor/shortcuts.ts +76 -42
  271. package/src/editor/slash-menu.ts +52 -14
  272. package/src/files/asset-versions.ts +4 -4
  273. package/src/files/components.ts +89 -20
  274. package/src/files/elements.ts +5 -6
  275. package/src/files/file-ops.ts +92 -41
  276. package/src/files/files.ts +248 -239
  277. package/src/files/fs-events.ts +18 -7
  278. package/src/files/media-meta.ts +97 -2
  279. package/src/files/media-paths.ts +3 -0
  280. package/src/files/media-types.ts +55 -0
  281. package/src/files/media-upload.ts +209 -52
  282. package/src/files/new-file-name.ts +156 -0
  283. package/src/files/serialize-document.ts +15 -5
  284. package/src/format/constraints.ts +1 -1
  285. package/src/format/convert-file.ts +27 -13
  286. package/src/format/format-choices.ts +2 -1
  287. package/src/format/format-host.ts +91 -50
  288. package/src/github/github-auth-status.ts +27 -3
  289. package/src/github/github-auth.ts +21 -11
  290. package/src/github/github-publish.ts +28 -23
  291. package/src/grid/cell-editors.ts +46 -31
  292. package/src/grid/cell-popovers.ts +5 -3
  293. package/src/grid/edit-buffer.ts +10 -9
  294. package/src/grid/grid-controller.ts +25 -23
  295. package/src/grid/grid-layout.ts +21 -5
  296. package/src/grid/grid-open.ts +3 -33
  297. package/src/grid/grid-panel.ts +65 -6
  298. package/src/grid/grid-reveal.ts +34 -0
  299. package/src/grid/grid-source.ts +9 -31
  300. package/src/grid/grid-view.ts +45 -23
  301. package/src/grid/redirects-grid.ts +14 -5
  302. package/src/grid/redirects.ts +16 -14
  303. package/src/grid/schema-columns.ts +25 -19
  304. package/src/grid/sources/connector-source.ts +47 -20
  305. package/src/grid/sources/content-source.ts +100 -31
  306. package/src/grid/sources/csv-file-source.ts +2 -2
  307. package/src/grid/tabulator-tables.d.ts +61 -34
  308. package/src/hosting/document.ts +2 -2
  309. package/src/hosting/stage.ts +7 -7
  310. package/src/i18n/i18n-commands.ts +3 -3
  311. package/src/media/media-commands.ts +181 -0
  312. package/src/media/media-library-model.ts +232 -0
  313. package/src/media/media-library.ts +1283 -0
  314. package/src/media/media-pane.ts +51 -20
  315. package/src/new-project/add-repo-modal.ts +20 -19
  316. package/src/new-project/import-tab.ts +10 -14
  317. package/src/new-project/location-fields.ts +2 -1
  318. package/src/new-project/new-project-modal.ts +12 -9
  319. package/src/packages/jxsuite-update.ts +4 -3
  320. package/src/packages/pull-package-sync.ts +26 -25
  321. package/src/page-params.ts +97 -68
  322. package/src/panels/activity-panel.ts +38 -14
  323. package/src/panels/ai-chat/attached-context.ts +13 -7
  324. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  325. package/src/panels/ai-chat/chat-view.ts +80 -73
  326. package/src/panels/ai-chat/composer.ts +30 -33
  327. package/src/panels/ai-chat/sessions-view.ts +1 -2
  328. package/src/panels/ai-panel.ts +23 -20
  329. package/src/panels/block-action-bar.ts +57 -46
  330. package/src/panels/bottom-dock.ts +5 -3
  331. package/src/panels/canvas-dnd-bridge.ts +36 -26
  332. package/src/panels/chat-panel.ts +6 -6
  333. package/src/panels/collections-panel.ts +306 -0
  334. package/src/panels/component-preview.ts +35 -13
  335. package/src/panels/data-explorer.ts +63 -26
  336. package/src/panels/data-grid.ts +18 -11
  337. package/src/panels/dnd.ts +115 -138
  338. package/src/panels/editors.ts +52 -21
  339. package/src/panels/elements-panel.ts +19 -5
  340. package/src/panels/empty-state.ts +2 -2
  341. package/src/panels/events-panel.ts +84 -69
  342. package/src/panels/formula-workspace.ts +78 -54
  343. package/src/panels/frontmatter-fields.ts +33 -28
  344. package/src/panels/git-diff-open.ts +10 -6
  345. package/src/panels/head-panel.ts +488 -202
  346. package/src/panels/i18n-panel.ts +20 -12
  347. package/src/panels/imports-panel.ts +25 -47
  348. package/src/panels/jump-bar.ts +75 -31
  349. package/src/panels/layers-panel.ts +130 -101
  350. package/src/panels/left-panel.ts +25 -11
  351. package/src/panels/navigator-panels.ts +23 -11
  352. package/src/panels/pane-context.ts +140 -49
  353. package/src/panels/pane-grid.ts +55 -26
  354. package/src/panels/panel-registry.ts +36 -46
  355. package/src/panels/properties-panel.ts +182 -124
  356. package/src/panels/quick-search.ts +53 -31
  357. package/src/panels/right-panel.ts +201 -45
  358. package/src/panels/seo-modal.ts +54 -125
  359. package/src/panels/settings-menu.ts +63 -61
  360. package/src/panels/settings-pane.ts +268 -162
  361. package/src/panels/signals-panel.ts +156 -135
  362. package/src/panels/site-model.ts +367 -0
  363. package/src/panels/site-panel.ts +638 -0
  364. package/src/panels/statement-editor.ts +230 -140
  365. package/src/panels/style-panel.ts +253 -206
  366. package/src/panels/style-utils.ts +114 -51
  367. package/src/panels/stylebook-doc.ts +195 -60
  368. package/src/panels/stylebook-layers-panel.ts +48 -89
  369. package/src/panels/stylebook-panel.ts +60 -27
  370. package/src/panels/styles-panel.ts +327 -0
  371. package/src/panels/tab-drop.ts +27 -11
  372. package/src/panels/tab-strip.ts +143 -49
  373. package/src/platform-errors.ts +57 -43
  374. package/src/platform.ts +59 -31
  375. package/src/platforms/cloud.ts +373 -176
  376. package/src/platforms/default-platform.ts +14 -8
  377. package/src/platforms/devserver.ts +180 -142
  378. package/src/platforms/read-batcher.ts +16 -8
  379. package/src/project-list.ts +2 -1
  380. package/src/publish/deploy-checklist.ts +20 -9
  381. package/src/publish/pages-service.ts +66 -27
  382. package/src/publish/publish-changes.ts +491 -0
  383. package/src/publish/publish-commands.ts +88 -22
  384. package/src/publish/publish-ids.ts +49 -0
  385. package/src/publish/publish-panel.ts +10 -6
  386. package/src/publish/publish-quick.ts +148 -0
  387. package/src/publish/publish-workspace.ts +926 -0
  388. package/src/publish/source-control.ts +907 -0
  389. package/src/recent-projects.ts +15 -8
  390. package/src/resize-edges.ts +26 -36
  391. package/src/services/a11y-report.ts +26 -19
  392. package/src/services/agent-seed.ts +23 -11
  393. package/src/services/ai-ask.ts +9 -12
  394. package/src/services/ai-command-tools.ts +68 -62
  395. package/src/services/ai-import-tools.ts +80 -67
  396. package/src/services/ai-models.ts +17 -13
  397. package/src/services/ai-project-tools.ts +68 -32
  398. package/src/services/ai-session-store.ts +19 -10
  399. package/src/services/ai-system-prompt.ts +46 -20
  400. package/src/services/ai-tools.ts +71 -27
  401. package/src/services/ai-write-report.ts +20 -12
  402. package/src/services/ai-writes.ts +4 -4
  403. package/src/services/automation.ts +74 -51
  404. package/src/services/cem-export.ts +149 -58
  405. package/src/services/cf-settings.ts +4 -4
  406. package/src/services/clock.ts +6 -1
  407. package/src/services/code-services.ts +37 -31
  408. package/src/services/connection.ts +2 -2
  409. package/src/services/context-manager.ts +14 -10
  410. package/src/services/context-resolver.ts +20 -8
  411. package/src/services/data-service.ts +19 -15
  412. package/src/services/directory-picker.ts +20 -14
  413. package/src/services/document-assistant.ts +39 -19
  414. package/src/services/gated-registry.ts +10 -6
  415. package/src/services/harness/chat-reducer.ts +23 -1
  416. package/src/services/import-client.ts +91 -38
  417. package/src/services/import-seed.ts +8 -2
  418. package/src/services/jx-validate.ts +28 -31
  419. package/src/services/live-preview.ts +0 -0
  420. package/src/services/live-surfaces.ts +6 -3
  421. package/src/services/model-uri.ts +10 -2
  422. package/src/services/module-preloads.ts +12 -8
  423. package/src/services/monaco-buffer.ts +43 -24
  424. package/src/services/monaco-lazy.ts +7 -8
  425. package/src/services/monaco-setup.ts +23 -16
  426. package/src/services/notify.ts +44 -17
  427. package/src/services/popover-report.ts +25 -10
  428. package/src/services/preview-eval.ts +20 -8
  429. package/src/services/profile.ts +13 -6
  430. package/src/services/project-path.ts +13 -10
  431. package/src/services/references.ts +0 -0
  432. package/src/services/render-critic.ts +29 -9
  433. package/src/services/settings/definitions.ts +25 -14
  434. package/src/services/settings/kernel.ts +13 -4
  435. package/src/services/settings/write-queue.ts +9 -9
  436. package/src/services/token-lint.ts +12 -10
  437. package/src/services/tool-executor.ts +17 -5
  438. package/src/services/tool-outcomes.ts +44 -24
  439. package/src/services/trusted-types.ts +24 -7
  440. package/src/settings/contexts-section.ts +11 -8
  441. package/src/settings/contributed-section.ts +128 -70
  442. package/src/settings/css-vars-editor.ts +119 -32
  443. package/src/settings/defs-editor.ts +38 -35
  444. package/src/settings/developer-panels.ts +43 -0
  445. package/src/settings/extension-rows.ts +16 -8
  446. package/src/settings/extension-sections.ts +42 -14
  447. package/src/settings/extensions-section.ts +4 -1
  448. package/src/settings/general-settings.ts +101 -28
  449. package/src/settings/locales-section.ts +20 -12
  450. package/src/settings/preferences-dialog.ts +17 -7
  451. package/src/settings/preferences-keymap.ts +7 -5
  452. package/src/settings/preferences-sections.ts +11 -5
  453. package/src/settings/project-sections.ts +28 -11
  454. package/src/settings/schema-field-ui.ts +12 -1
  455. package/src/settings/section-registry.ts +116 -11
  456. package/src/settings/settings-dialog.ts +192 -0
  457. package/src/settings/settings-document.ts +186 -166
  458. package/src/shell/tree.ts +6 -5
  459. package/src/shell.ts +536 -477
  460. package/src/site-context.ts +101 -32
  461. package/src/state.ts +68 -57
  462. package/src/store.ts +54 -34
  463. package/src/studio.ts +219 -116
  464. package/src/style/live-preview.ts +1 -1
  465. package/src/style/project-styles.ts +40 -7
  466. package/src/style/stylebook-specimens.ts +89 -0
  467. package/src/style/stylebook-target.ts +26 -0
  468. package/src/style/tag-inheritance.ts +105 -0
  469. package/src/style/token-ref.ts +5 -4
  470. package/src/style/variables-focus.ts +61 -0
  471. package/src/style/variables-view.ts +235 -0
  472. package/src/surfaces/about.ts +18 -19
  473. package/src/surfaces/add-new.json +1482 -0
  474. package/src/surfaces/add-new.ts +325 -0
  475. package/src/surfaces/add-repo.ts +17 -19
  476. package/src/surfaces/ai-chat.ts +33 -38
  477. package/src/surfaces/ai-credentials-form.ts +6 -16
  478. package/src/surfaces/ai-managed-connect.ts +3 -4
  479. package/src/surfaces/ai-model-picker.ts +3 -5
  480. package/src/surfaces/block-action-bar.ts +22 -11
  481. package/src/surfaces/boot-failure.json +4 -3
  482. package/src/surfaces/boot-failure.ts +4 -5
  483. package/src/surfaces/bottom-dock.json +1 -1
  484. package/src/surfaces/bottom-dock.ts +9 -18
  485. package/src/surfaces/canvas-stage.json +30 -19
  486. package/src/surfaces/canvas-stage.ts +17 -16
  487. package/src/surfaces/cf-account-picker.ts +17 -18
  488. package/src/surfaces/collections-panel.json +615 -0
  489. package/src/surfaces/collections-panel.ts +168 -0
  490. package/src/surfaces/commandbar.json +241 -96
  491. package/src/surfaces/commandbar.ts +145 -105
  492. package/src/surfaces/convert-repeater.ts +17 -19
  493. package/src/surfaces/data-actions.ts +9 -7
  494. package/src/surfaces/dialog.ts +26 -28
  495. package/src/surfaces/diff-toolbar.ts +9 -7
  496. package/src/surfaces/empty-state.json +1 -1
  497. package/src/surfaces/empty-state.ts +7 -10
  498. package/src/surfaces/entry-editor.json +136 -0
  499. package/src/surfaces/entry-editor.ts +35 -11
  500. package/src/surfaces/entry-inspector.json +371 -0
  501. package/src/surfaces/entry-inspector.ts +143 -0
  502. package/src/surfaces/expression-editor.ts +11 -25
  503. package/src/surfaces/files-panel.ts +27 -14
  504. package/src/surfaces/formula-palette.ts +4 -5
  505. package/src/surfaces/github-auth.ts +16 -20
  506. package/src/surfaces/github-publish.ts +17 -22
  507. package/src/surfaces/grid-cell.ts +30 -31
  508. package/src/surfaces/grid-open.ts +10 -14
  509. package/src/surfaces/grid-panel.ts +13 -9
  510. package/src/surfaces/grid-replace.ts +13 -13
  511. package/src/surfaces/grid-views.ts +15 -18
  512. package/src/surfaces/inspector-dock.json +162 -14
  513. package/src/surfaces/inspector-dock.ts +59 -31
  514. package/src/surfaces/jump-bar.ts +5 -6
  515. package/src/surfaces/jxsuite-update.ts +16 -22
  516. package/src/surfaces/library-pane.json +670 -437
  517. package/src/surfaces/library-pane.ts +111 -77
  518. package/src/surfaces/logic-panel.ts +17 -30
  519. package/src/surfaces/logic-workspace.ts +13 -15
  520. package/src/surfaces/media-browser.json +62 -6
  521. package/src/surfaces/media-browser.ts +26 -11
  522. package/src/surfaces/media-field.json +1 -1
  523. package/src/surfaces/media-field.ts +4 -5
  524. package/src/surfaces/media-library.json +1586 -0
  525. package/src/surfaces/media-library.ts +282 -0
  526. package/src/surfaces/media-pane.ts +8 -7
  527. package/src/surfaces/media-pick-dialog.json +71 -0
  528. package/src/surfaces/media-pick-dialog.ts +132 -0
  529. package/src/surfaces/menu.ts +47 -23
  530. package/src/surfaces/navigator-dock.ts +11 -12
  531. package/src/surfaces/new-project.ts +27 -26
  532. package/src/surfaces/pane-context.json +144 -77
  533. package/src/surfaces/pane-context.ts +44 -25
  534. package/src/surfaces/pane-grid.ts +15 -10
  535. package/src/surfaces/panel-activity.ts +5 -6
  536. package/src/surfaces/panel-data.ts +3 -4
  537. package/src/surfaces/panel-deploy-checklist.json +12 -6
  538. package/src/surfaces/panel-deploy-checklist.ts +8 -7
  539. package/src/surfaces/panel-elements.ts +5 -7
  540. package/src/surfaces/panel-i18n.ts +5 -7
  541. package/src/surfaces/panel-imports.ts +6 -13
  542. package/src/surfaces/panel-outline.ts +25 -19
  543. package/src/surfaces/panel-page.json +72 -2
  544. package/src/surfaces/panel-page.ts +49 -25
  545. package/src/surfaces/panel-problems.ts +5 -7
  546. package/src/surfaces/panel-signals.json +1 -1
  547. package/src/surfaces/panel-signals.ts +25 -39
  548. package/src/surfaces/panel-stylebook-layers.json +71 -204
  549. package/src/surfaces/panel-stylebook-layers.ts +5 -29
  550. package/src/surfaces/preferences.json +120 -48
  551. package/src/surfaces/preferences.ts +29 -11
  552. package/src/surfaces/progress-modal.ts +15 -9
  553. package/src/surfaces/properties-panel.json +1 -1
  554. package/src/surfaces/properties-panel.ts +20 -42
  555. package/src/surfaces/publish-quick.json +428 -0
  556. package/src/surfaces/publish-quick.ts +165 -0
  557. package/src/surfaces/publish-workspace.json +2892 -0
  558. package/src/surfaces/publish-workspace.ts +391 -0
  559. package/src/surfaces/publish.ts +18 -18
  560. package/src/surfaces/push-plan.ts +7 -8
  561. package/src/surfaces/rail.json +1 -159
  562. package/src/surfaces/rail.ts +22 -79
  563. package/src/surfaces/reference-field.ts +11 -15
  564. package/src/surfaces/schema-builder.ts +16 -22
  565. package/src/surfaces/schema-form.json +10 -2
  566. package/src/surfaces/schema-form.ts +17 -25
  567. package/src/surfaces/secret-field.ts +9 -6
  568. package/src/surfaces/seo.json +1 -1
  569. package/src/surfaces/seo.ts +21 -15
  570. package/src/surfaces/settings-contexts.ts +9 -7
  571. package/src/surfaces/settings-contributed.json +5 -5
  572. package/src/surfaces/settings-contributed.ts +32 -12
  573. package/src/surfaces/settings-css-vars.json +44 -36
  574. package/src/surfaces/settings-css-vars.ts +82 -16
  575. package/src/surfaces/settings-defs.json +2 -2
  576. package/src/surfaces/settings-defs.ts +17 -21
  577. package/src/surfaces/settings-deploy.json +2 -15
  578. package/src/surfaces/settings-deploy.ts +9 -16
  579. package/src/surfaces/settings-dialog.json +51 -0
  580. package/src/surfaces/settings-dialog.ts +169 -0
  581. package/src/surfaces/settings-extensions.ts +5 -6
  582. package/src/surfaces/settings-head.ts +33 -39
  583. package/src/surfaces/settings-locales.ts +8 -20
  584. package/src/surfaces/settings-overview.json +3 -3
  585. package/src/surfaces/settings-overview.ts +14 -8
  586. package/src/surfaces/settings-packages.ts +8 -7
  587. package/src/surfaces/settings-pane.json +269 -46
  588. package/src/surfaces/settings-pane.ts +88 -36
  589. package/src/surfaces/settings-rawjson.ts +5 -6
  590. package/src/surfaces/shell.json +2 -1
  591. package/src/surfaces/shell.ts +1 -2
  592. package/src/surfaces/site-panel.json +1029 -0
  593. package/src/surfaces/site-panel.ts +233 -0
  594. package/src/surfaces/slash-menu.json +63 -21
  595. package/src/surfaces/slash-menu.ts +42 -9
  596. package/src/surfaces/statements.ts +13 -18
  597. package/src/surfaces/statusbar.ts +56 -29
  598. package/src/surfaces/style-panel.ts +18 -31
  599. package/src/surfaces/stylebook-chrome.ts +3 -5
  600. package/src/surfaces/styles-panel.json +735 -0
  601. package/src/surfaces/styles-panel.ts +195 -0
  602. package/src/surfaces/styles-variables.json +149 -0
  603. package/src/surfaces/styles-variables.ts +145 -0
  604. package/src/surfaces/tab-strip.json +4 -4
  605. package/src/surfaces/tab-strip.ts +14 -13
  606. package/src/surfaces/target-line.ts +6 -7
  607. package/src/surfaces/welcome.ts +6 -8
  608. package/src/surfaces/writing-banner.json +94 -0
  609. package/src/surfaces/writing-banner.ts +80 -0
  610. package/src/tabs/bare-repeaters.ts +101 -0
  611. package/src/tabs/patch-ops.ts +4 -3
  612. package/src/tabs/project-config.ts +32 -21
  613. package/src/tabs/selection.ts +36 -8
  614. package/src/tabs/tab.ts +99 -48
  615. package/src/tabs/transact.ts +98 -53
  616. package/src/types.ts +53 -43
  617. package/src/ui/ai-credentials-form.ts +10 -13
  618. package/src/ui/ai-model-picker.ts +3 -3
  619. package/src/ui/cf-account-picker.ts +7 -9
  620. package/src/ui/color-selector.ts +9 -5
  621. package/src/ui/dynamic-slot.ts +7 -8
  622. package/src/ui/expression-editor.ts +112 -105
  623. package/src/ui/form-controls.ts +104 -56
  624. package/src/ui/formula-catalog.ts +239 -230
  625. package/src/ui/formula-chips.ts +33 -18
  626. package/src/ui/layers.ts +57 -31
  627. package/src/ui/media-picker.ts +300 -47
  628. package/src/ui/popover-surface.ts +20 -12
  629. package/src/ui/progress-modal.ts +13 -8
  630. package/src/ui/regions.ts +14 -12
  631. package/src/ui/schema-form.ts +372 -97
  632. package/src/ui/surface.ts +71 -8
  633. package/src/ui/timing.ts +9 -0
  634. package/src/ui/value-source.ts +44 -31
  635. package/src/ui/virtual-window.ts +29 -3
  636. package/src/utils/base64.ts +6 -4
  637. package/src/utils/edit-display.ts +366 -111
  638. package/src/utils/element-selectors.ts +3 -2
  639. package/src/utils/google-fonts.ts +15 -14
  640. package/src/utils/inherited-style.ts +18 -20
  641. package/src/utils/link-target.ts +1 -1
  642. package/src/utils/local-day.ts +18 -0
  643. package/src/utils/preview-format.ts +25 -3
  644. package/src/utils/strip-events.ts +49 -22
  645. package/src/utils/studio-utils.ts +29 -14
  646. package/src/view.ts +2 -3
  647. package/src/workspace/pane-derive.ts +14 -16
  648. package/src/workspace/session.ts +81 -50
  649. package/src/workspace/tab-workspace.ts +137 -0
  650. package/src/workspace/workspace-back.ts +189 -0
  651. package/src/workspace/workspace-home.ts +133 -0
  652. package/src/workspace/workspace-ids.ts +129 -0
  653. package/src/workspace/workspace-switch.ts +372 -0
  654. package/src/workspace/workspace.ts +165 -47
  655. package/styles/shell-frame.css +30 -7
  656. package/styles/shell-frame.json +15 -3
  657. package/dist/chunks/2020-va2wwra4.js +0 -4
  658. package/dist/chunks/adapter-f93pafd7.js +0 -4
  659. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  660. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  661. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  662. package/dist/chunks/color-field-embq5ctg.js +0 -4
  663. package/dist/chunks/color-fpezvnkt.js +0 -4
  664. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  665. package/dist/chunks/combobox-773hdzyj.js +0 -4
  666. package/dist/chunks/components-ax2f1fnn.js +0 -4
  667. package/dist/chunks/content-source-108aqtk1.js +0 -4
  668. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  669. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  670. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  671. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  672. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  673. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  674. package/dist/chunks/files-44vp8a2s.js +0 -4
  675. package/dist/chunks/format-host-7q1petb9.js +0 -4
  676. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  677. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  678. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  679. package/dist/chunks/icons-p44xhjf0.js +0 -4
  680. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  681. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  682. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  683. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  684. package/dist/chunks/index-wkyfjeqz.js +0 -4
  685. package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
  686. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  687. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  688. package/dist/chunks/layers-xd92fg8d.js +0 -4
  689. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  690. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  691. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  692. package/dist/chunks/menu-37d07z9m.js +0 -4
  693. package/dist/chunks/menu-5c55ea3d.js +0 -4
  694. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  695. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  696. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  697. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  698. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  699. package/dist/chunks/parse-897fvqah.js +0 -4
  700. package/dist/chunks/platform-v1qctbe6.js +0 -4
  701. package/dist/chunks/popover-8htra4er.js +0 -4
  702. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  703. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  704. package/dist/chunks/references-gmqp82fs.js +0 -4
  705. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  706. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  707. package/dist/chunks/select-n3v7gwas.js +0 -4
  708. package/dist/chunks/split-pff8f3ze.js +0 -4
  709. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  710. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  711. package/dist/chunks/studio-1b04pd0j.js +0 -64
  712. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  713. package/dist/chunks/studio-4tanh828.js +0 -5
  714. package/dist/chunks/studio-55h4mstj.js +0 -4
  715. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  716. package/dist/chunks/studio-60dqgb0c.js +0 -5
  717. package/dist/chunks/studio-61dp09qg.js +0 -9
  718. package/dist/chunks/studio-63epcrj2.js +0 -5
  719. package/dist/chunks/studio-74k29dy9.js +0 -5
  720. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  721. package/dist/chunks/studio-7zx31knw.js +0 -9
  722. package/dist/chunks/studio-8bxk97km.js +0 -5
  723. package/dist/chunks/studio-933e30n4.js +0 -5
  724. package/dist/chunks/studio-98wnwhbg.js +0 -5
  725. package/dist/chunks/studio-9mccjwjh.js +0 -14
  726. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  727. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  728. package/dist/chunks/studio-e81q1vb9.js +0 -5
  729. package/dist/chunks/studio-epgrmqqm.js +0 -5
  730. package/dist/chunks/studio-ery42sqr.js +0 -4
  731. package/dist/chunks/studio-g1shz58g.js +0 -5
  732. package/dist/chunks/studio-gf0fz03c.js +0 -5
  733. package/dist/chunks/studio-gjtpe62q.js +0 -6
  734. package/dist/chunks/studio-gkskhg7m.js +0 -5
  735. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  736. package/dist/chunks/studio-j03zga3y.js +0 -9
  737. package/dist/chunks/studio-jhpxeckz.js +0 -5
  738. package/dist/chunks/studio-k01r7ykp.js +0 -5
  739. package/dist/chunks/studio-kk7h30ne.js +0 -7
  740. package/dist/chunks/studio-kt1zqney.js +0 -5
  741. package/dist/chunks/studio-m3cwhvye.js +0 -5
  742. package/dist/chunks/studio-mcayt6hz.js +0 -5
  743. package/dist/chunks/studio-myjcghv3.js +0 -5
  744. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  745. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  746. package/dist/chunks/studio-nj5a01jy.js +0 -928
  747. package/dist/chunks/studio-pcgz8heb.js +0 -5
  748. package/dist/chunks/studio-qcsq0t15.js +0 -5
  749. package/dist/chunks/studio-qkstvve9.js +0 -5
  750. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  751. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  752. package/dist/chunks/studio-s8dmmz66.js +0 -5
  753. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  754. package/dist/chunks/studio-szsjbj0g.js +0 -5
  755. package/dist/chunks/studio-t1xzawhr.js +0 -16
  756. package/dist/chunks/studio-tdcprbqb.js +0 -5
  757. package/dist/chunks/studio-vrmcjf9g.js +0 -7
  758. package/dist/chunks/studio-vyc0b4he.js +0 -10
  759. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  760. package/dist/chunks/studio-w3hskzqk.js +0 -5
  761. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  762. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  763. package/dist/chunks/studio-y6n42tgs.js +0 -5
  764. package/dist/chunks/studio-yb560vxr.js +0 -5
  765. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  766. package/dist/chunks/studio-yw05w8f0.js +0 -7
  767. package/dist/chunks/studio-z16sgavc.js +0 -5
  768. package/dist/chunks/studio-zey7zsdw.js +0 -12
  769. package/dist/chunks/studio-zyqn40w4.js +0 -5
  770. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  771. package/dist/chunks/tabs-jwthg40w.js +0 -4
  772. package/dist/chunks/textfield-spy3hc77.js +0 -4
  773. package/dist/chunks/toast-4d35zd64.js +0 -4
  774. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  775. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  776. package/dist/chunks/tree-h19v1jfz.js +0 -4
  777. package/dist/chunks/tsMode-2frah6h1.js +0 -14
  778. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  779. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
  780. package/src/panels/frontmatter-panel.ts +0 -701
  781. package/src/panels/git-panel.ts +0 -1120
  782. package/src/surfaces/doc-header.json +0 -776
  783. package/src/surfaces/doc-header.ts +0 -231
  784. package/src/surfaces/git-panel.json +0 -1880
  785. package/src/surfaces/git-panel.ts +0 -272
@@ -3,11 +3,11 @@
3
3
  * Schema-form — the reusable JSON-Schema → form engine, and the FLOW half of it.
4
4
  *
5
5
  * Maps schema property types to controls (enum → select, boolean → checkbox, number/integer →
6
- * number field, `json-schema` format → JSON editor, array-of-objects → a row per item, other
7
- * array/object → JSON text, default → text field); hosts commit edits through a single
8
- * `onChange(patch)` callback; dynamic enum choices resolve through a {@link SchemaFormContext}.
9
- * Custom controls register by name via {@link registerFormControl} and are consulted first for `ui`
10
- * overrides.
6
+ * number field, `json-schema` format → JSON editor, array-of-objects → a row per item, an array of
7
+ * single values (text, numbers, pictures, entries) → a row per item too, other array/object → JSON
8
+ * text, default → text field); hosts commit edits through a single `onChange(patch)` callback;
9
+ * dynamic enum choices resolve through a {@link SchemaFormContext}. Custom controls register by
10
+ * name via {@link registerFormControl} and are consulted first for `ui` overrides.
11
11
  *
12
12
  * **This module decides; `surfaces/schema-form.json` draws.** Every question with an answer — which
13
13
  * control a property gets, what its choices are, which rungs of the value ladder the position
@@ -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,14 +169,15 @@ 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
160
176
  * `enum` source (choice list or `{ "$ref": "#/$context/<pointer>" }`) layered over the field
161
- * schema — fragments stay valid JSON Schema while descriptors add dynamic choices.
177
+ * schema — fragments stay valid JSON Schema while descriptors add dynamic choices. `label` is the
178
+ * words the row is titled with in place of the property's key.
162
179
  */
163
- ui?: Record<string, { control?: string; enum?: unknown }> | undefined;
180
+ ui?: Record<string, { control?: string; enum?: unknown; label?: string }> | undefined;
164
181
  rerender?: (() => void) | undefined;
165
182
  /**
166
183
  * Externally-produced diagnostics, keyed by property name — §16.1's inline tier, sourced.
@@ -217,7 +234,9 @@ const CONTENT_REF = /^#\/content\/([^/]+)$/;
217
234
  * reading of `$ref` is how the picker ends up existing three times with three behaviours.
218
235
  */
219
236
  export function referenceTarget(schema: { $ref?: string } | undefined): string | null {
220
- const match = typeof schema?.$ref === "string" ? CONTENT_REF.exec(schema.$ref) : null;
237
+ // The schema is project JSON, so the declared `string` is checked rather than trusted.
238
+ const ref = schema?.$ref;
239
+ const match = isString(ref) ? CONTENT_REF.exec(ref) : null;
221
240
  return match ? match[1]! : null;
222
241
  }
223
242
 
@@ -240,26 +259,30 @@ export const NULL_FORM_CONTEXT: SchemaFormContext = {
240
259
  * and sentinel strings resolve through the context's pointer resolver, applying object →
241
260
  * `Object.keys` and string[] → itself.
242
261
  *
243
- * @param {unknown} enumDef
262
+ * @param {JsonValue | undefined} enumDef
244
263
  * @param {SchemaFormContext | undefined} ctx
245
- * @param {Record<string, unknown>} [scope] - Scope for `{@param}` substitution (the form value)
264
+ * @param {JsonObject} [scope] - Scope for `{@param}` substitution (the form value)
246
265
  * @returns {string[] | undefined}
247
266
  */
248
267
  export function resolveFormEnum(
249
- enumDef: unknown,
268
+ enumDef: JsonValue | undefined,
250
269
  ctx?: SchemaFormContext,
251
- scope?: Record<string, unknown>,
270
+ scope?: JsonObject,
252
271
  ): string[] | undefined {
253
272
  if (Array.isArray(enumDef)) {
273
+ /* SAFETY: a form `enum` is a list of string choices — every select this engine draws is fed by
274
+ a settings fragment or collection schema that declares `type: "string"` beside its enum, and
275
+ each choice is only ever interpolated as text (an option label and value), which is what a
276
+ stray number would be read as too. */
254
277
  return enumDef as string[];
255
278
  }
256
279
  let pointer: string | undefined;
257
- if (enumDef && typeof enumDef === "object") {
258
- const ref = (enumDef as Record<string, unknown>).$ref;
259
- if (typeof ref === "string") {
280
+ if (isJsonObject(enumDef)) {
281
+ const ref = enumDef.$ref;
282
+ if (isString(ref)) {
260
283
  pointer = ref;
261
284
  }
262
- } else if (typeof enumDef === "string") {
285
+ } else if (isString(enumDef)) {
263
286
  // Legacy sentinel strings (e.g. "$contentTypes") resolve through the host's pointer resolver
264
287
  pointer = enumDef;
265
288
  }
@@ -270,7 +293,7 @@ export function resolveFormEnum(
270
293
  if (Array.isArray(resolved)) {
271
294
  return resolved.map(String);
272
295
  }
273
- if (resolved && typeof resolved === "object") {
296
+ if (isJsonObject(resolved)) {
274
297
  return Object.keys(resolved);
275
298
  }
276
299
  return undefined;
@@ -296,7 +319,7 @@ function isBindableField(ps: JsonSchema): boolean {
296
319
  }
297
320
 
298
321
  /** Every pointer this form's host says a value may come from. */
299
- function refSourcesFor(ctx: SchemaFormContext): SignalOption[] {
322
+ function refSourcesFor(ctx: SchemaFormContext): SurfaceOption[] {
300
323
  return [
301
324
  ...(ctx.signals ?? []).map((name) => ({ label: name, value: `#/state/${name}` })),
302
325
  ...(ctx.params ?? []).map((name) => ({ label: `$params/${name}`, value: `#/$params/${name}` })),
@@ -307,11 +330,11 @@ function refSourcesFor(ctx: SchemaFormContext): SignalOption[] {
307
330
  const NONE = "__none__";
308
331
 
309
332
  /** A value as a control reads it: a string, and never `"[object Object]"`. */
310
- function asText(value: unknown): string {
333
+ function asText(value: JsonValue | undefined): string {
311
334
  if (value === undefined || value === null) {
312
335
  return "";
313
336
  }
314
- return typeof value === "object" ? JSON.stringify(value, null, 2) : String(value);
337
+ return isNonNullObject(value) ? JSON.stringify(value, null, 2) : String(value);
315
338
  }
316
339
 
317
340
  // ─── Field validation (§16.1, inline tier) ───────────────────────────────────
@@ -328,13 +351,13 @@ function asText(value: unknown): string {
328
351
  * cannot see, so type-checking the reference itself would refuse every correct binding.
329
352
  *
330
353
  * @param {JsonSchema} schema
331
- * @param {unknown} value
354
+ * @param {JsonValue | undefined} value
332
355
  * @param {boolean} isRequired
333
356
  * @returns {string}
334
357
  */
335
358
  export function validateFieldValue(
336
359
  schema: JsonSchema,
337
- value: unknown,
360
+ value: JsonValue | undefined,
338
361
  isRequired: boolean,
339
362
  ): string {
340
363
  if (isRef(value)) {
@@ -348,7 +371,7 @@ export function validateFieldValue(
348
371
  return `Choose one of: ${schema.enum.map(String).join(", ")}.`;
349
372
  }
350
373
  if (schema.type === "number" || schema.type === "integer") {
351
- const n = typeof value === "number" ? value : Number(value);
374
+ const n = isNumber(value) ? value : Number(value);
352
375
  if (!Number.isFinite(n)) {
353
376
  return "Enter a number.";
354
377
  }
@@ -363,13 +386,14 @@ export function validateFieldValue(
363
386
  }
364
387
  return "";
365
388
  }
366
- if (schema.type === "boolean" && typeof value !== "boolean") {
389
+ if (schema.type === "boolean" && !isBoolean(value)) {
367
390
  return "Must be true or false.";
368
391
  }
369
392
  if (schema.type === "array" && !Array.isArray(value)) {
370
393
  return "Must be a list.";
371
394
  }
372
- if (schema.type === "object" && (typeof value !== "object" || Array.isArray(value))) {
395
+ // `null` is "empty" and answered above, so only a primitive or an array can fail here.
396
+ if (schema.type === "object" && !isJsonObject(value)) {
373
397
  return "Must be an object.";
374
398
  }
375
399
  return "";
@@ -392,17 +416,29 @@ interface FieldPlan {
392
416
  /** Item-property schemas, for an array-of-objects field. */
393
417
  itemProps?: Record<string, JsonSchema> | undefined;
394
418
  /** The rows currently held, so a cell edit can rebuild the array. */
395
- rows?: Record<string, unknown>[] | undefined;
419
+ rows?: JsonObject[] | undefined;
420
+ /**
421
+ * The field is an array of single values (`string[]`, a gallery of pictures), drawn as rows of
422
+ * one cell each: every row is `{ [SCALAR_CELL]: item }` here, and a commit writes the bare items
423
+ * back. One row editor for both shapes, rather than a list control beside the row control.
424
+ */
425
+ scalarItems?: boolean | undefined;
396
426
  /** The ladder, when this position offers one. */
397
- ladder?: { fieldKey: string; mode: SlotMode; offered: SlotMode[]; sources: SignalOption[] };
427
+ ladder?: { fieldKey: string; mode: SlotMode; offered: SlotMode[]; sources: SurfaceOption[] };
398
428
  /** A registered control owns the whole field; args are rebuilt for it on every repaint. */
399
429
  control?: SchemaFormMountedControl | undefined;
430
+ /**
431
+ * The member of the property's OBJECT this row edits, when the row is one part of an object
432
+ * field: an image object's `alt` is a text row of its own, and its commit writes the whole object
433
+ * back with that one member changed.
434
+ */
435
+ member?: string | undefined;
400
436
  /**
401
437
  * Registered controls owning one cell, keyed by the cell's host id.
402
438
  *
403
439
  * The same kind of entry a field's own control is, and reached by the same dispatch: a cell host
404
- * is a host like any other. The one control a cell is ever given is `reference` (see
405
- * {@link deriveCell}).
440
+ * is a host like any other. A cell is given `reference` for an entry of another collection and
441
+ * `media` for a picture (see {@link deriveCell}).
406
442
  */
407
443
  cellControls?: Map<
408
444
  string,
@@ -427,11 +463,7 @@ const TEXT_COMMIT_MS = 400;
427
463
 
428
464
  interface FormController {
429
465
  readonly host: HTMLElement;
430
- readonly update: (
431
- schema: JsonSchema,
432
- value: Record<string, unknown>,
433
- opts: RenderFormOptions,
434
- ) => void;
466
+ readonly update: (schema: JsonSchema, value: JsonObject, opts: RenderFormOptions) => void;
435
467
  readonly dispose: () => void;
436
468
  }
437
469
 
@@ -452,14 +484,14 @@ export function resetSchemaForms(): void {
452
484
  * @param {string} formKey Stable identity for this form — the same key updates the standing mount
453
485
  * instead of building a second one, which is what keeps the caret in a field across a repaint.
454
486
  * @param {JsonSchema} schema
455
- * @param {Record<string, unknown>} value The record being edited
487
+ * @param {JsonObject} value The record being edited
456
488
  * @param {RenderFormOptions} opts
457
489
  * @returns {HTMLElement} The form's own host, for a lit caller to place in its tree
458
490
  */
459
491
  export function mountSchemaForm(
460
492
  formKey: string,
461
493
  schema: JsonSchema,
462
- value: Record<string, unknown>,
494
+ value: JsonObject,
463
495
  opts: RenderFormOptions,
464
496
  ): HTMLElement {
465
497
  sweep(formKey);
@@ -490,7 +522,7 @@ function sweep(exceptKey: string): void {
490
522
 
491
523
  function createController(): FormController {
492
524
  let schema: JsonSchema = {};
493
- let value: Record<string, unknown> = {};
525
+ let value: JsonObject = {};
494
526
  let opts: RenderFormOptions = { onChange: () => {} };
495
527
  let ctx: SchemaFormContext = NULL_FORM_CONTEXT;
496
528
  const plans = new Map<string, FieldPlan>();
@@ -515,7 +547,7 @@ function createController(): FormController {
515
547
  run();
516
548
  };
517
549
 
518
- const patch = (prop: string, next: unknown): void => {
550
+ const patch = (prop: string, next: JsonValue | undefined): void => {
519
551
  opts.onChange({ [prop]: next });
520
552
  };
521
553
 
@@ -546,7 +578,8 @@ function createController(): FormController {
546
578
  }
547
579
  case "json": {
548
580
  try {
549
- patch(plan.prop, JSON.parse(raw) as unknown);
581
+ // SAFETY: `JSON.parse` with no reviver yields only JSON values, which is all a JsonValue is.
582
+ patch(plan.prop, JSON.parse(raw) as JsonValue);
550
583
  } catch {
551
584
  /* A half-typed object is not a refusal: the last parsable text is what the document
552
585
  keeps, and the field goes on showing what is actually in it. */
@@ -554,14 +587,40 @@ function createController(): FormController {
554
587
  return;
555
588
  }
556
589
  default: {
590
+ if (plan.member !== undefined) {
591
+ // One member of an object: the object goes back whole, with that member set or removed.
592
+ const held = value[plan.prop];
593
+ const base: JsonObject = isJsonObject(held) ? { ...held } : {};
594
+ if (raw) {
595
+ base[plan.member] = raw;
596
+ } else {
597
+ delete base[plan.member];
598
+ }
599
+ patch(plan.prop, Object.keys(base).length > 0 ? base : undefined);
600
+ return;
601
+ }
557
602
  patch(plan.prop, raw || undefined);
558
603
  }
559
604
  }
560
605
  };
561
606
 
607
+ /**
608
+ * Write a row field's rows back as the array the document holds: the rows themselves for an array
609
+ * of objects, each row's one value for an array of single values. A row whose value was cleared
610
+ * stays as an empty string, so clearing the text of an item does not delete its row under the
611
+ * caret; Remove is how an item goes.
612
+ */
613
+ const patchRows = (plan: FieldPlan, rows: JsonObject[]): void => {
614
+ let next: JsonValue | undefined;
615
+ if (rows.length > 0) {
616
+ next = plan.scalarItems ? rows.map((row) => row[SCALAR_CELL] ?? "") : rows;
617
+ }
618
+ patch(plan.prop, next);
619
+ };
620
+
562
621
  /** 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>[] = [];
622
+ const cellRows = (plan: FieldPlan): JsonObject[] => {
623
+ const copies: JsonObject[] = [];
565
624
  for (const item of plan.rows ?? []) {
566
625
  copies.push({ ...item });
567
626
  }
@@ -574,13 +633,15 @@ function createController(): FormController {
574
633
  if (!plan?.itemProps) {
575
634
  return;
576
635
  }
577
- const seed: Record<string, unknown> = {};
636
+ const seed: JsonObject = {};
578
637
  for (const [k, v] of Object.entries(plan.itemProps)) {
579
638
  if (v.default !== undefined) {
580
- seed[k] = v.default;
639
+ /* SAFETY: an item schema is read from a JSON schema document, so the `default` it
640
+ declares is a JSON value. */
641
+ seed[k] = v.default as JsonValue;
581
642
  }
582
643
  }
583
- patch(field, [...cellRows(plan), seed]);
644
+ patchRows(plan, [...cellRows(plan), seed]);
584
645
  opts.rerender?.();
585
646
  },
586
647
  commit: (key: string, raw: string) => {
@@ -622,13 +683,15 @@ function createController(): FormController {
622
683
  return;
623
684
  }
624
685
  const idx = Number(row);
625
- const kept = cellRows(plan).filter((_, i) => i !== idx);
626
- patch(field, kept.length > 0 ? kept : undefined);
686
+ patchRows(
687
+ plan,
688
+ cellRows(plan).filter((_, i) => i !== idx),
689
+ );
627
690
  opts.rerender?.();
628
691
  },
629
692
  };
630
693
 
631
- function writeCell(field: string, row: string, cell: string, next: unknown): void {
694
+ function writeCell(field: string, row: string, cell: string, next: JsonValue | undefined): void {
632
695
  const plan = plans.get(field);
633
696
  if (!plan?.itemProps) {
634
697
  return;
@@ -640,20 +703,23 @@ function createController(): FormController {
640
703
  return;
641
704
  }
642
705
  const cellSchema = plan.itemProps[cell];
706
+ /* SAFETY: the one non-JSON member this row can gain is an `undefined` for a cleared cell, and
707
+ every host's `onChange` persists the patch as JSON (the entry, the def and the project config
708
+ are all serialized), where an undefined member is simply omitted. */
643
709
  rows[idx] = {
644
710
  ...target,
645
711
  [cell]: coerceCell(cellSchema, next, plan.refCells?.has(`${field}/${row}/${cell}`) ?? false),
646
- };
647
- patch(field, rows);
712
+ } as JsonObject;
713
+ patchRows(plan, rows);
648
714
  }
649
715
 
650
716
  /** A cell's committed string, as the item property's declared type. */
651
717
  function coerceCell(
652
718
  cellSchema: JsonSchema | undefined,
653
- next: unknown,
719
+ next: JsonValue | undefined,
654
720
  isPointer: boolean,
655
- ): unknown {
656
- if (typeof next === "boolean") {
721
+ ): JsonValue | undefined {
722
+ if (isBoolean(next)) {
657
723
  return next;
658
724
  }
659
725
  const raw = String(next);
@@ -687,7 +753,7 @@ function createController(): FormController {
687
753
  opener: anchor,
688
754
  region: "value-source",
689
755
  rows: offered.map((rung) => ({
690
- checked: (rung === mode ? "true" : "false") as "true" | "false",
756
+ checked: rung === mode ? ("true" as const) : ("false" as const),
691
757
  destructive: false,
692
758
  disabled: false,
693
759
  dividerAbove: false,
@@ -695,12 +761,14 @@ function createController(): FormController {
695
761
  title: VALUE_SOURCE_LABELS[rung],
696
762
  })),
697
763
  run: (id) => {
698
- const next = id as SlotMode;
699
- if (next === mode) {
764
+ // The menu's rows are `offered`, so an id is always one of its rungs.
765
+ const next = offered.find((rung) => rung === id);
766
+ if (next === undefined || next === mode) {
700
767
  return;
701
768
  }
702
769
  /* Leaving From data… seeds an empty Fixed value stash with the property's declared default,
703
770
  so unbind-restores-default survives a detour through Mixed text. */
771
+ // SAFETY: the field schema is read from JSON, so the `default` it declares is a JSON value.
704
772
  const literalDefault = plan.schema.default as JsonValue | undefined;
705
773
  if (
706
774
  mode === "ref" &&
@@ -715,7 +783,7 @@ function createController(): FormController {
715
783
  fieldKey,
716
784
  mode,
717
785
  next,
718
- cloneValue(value[plan.prop] as JsonValue | undefined),
786
+ cloneValue(value[plan.prop]),
719
787
  slotModeSeed(next, { extraSignals: sources, literalDefault, stateDefs: [] }),
720
788
  ),
721
789
  );
@@ -853,32 +921,107 @@ function createController(): FormController {
853
921
  /** Every row the document draws, and the plan that reads each one's gestures back. */
854
922
  function deriveFields(
855
923
  schema: JsonSchema,
856
- value: Record<string, unknown>,
924
+ value: JsonObject,
857
925
  opts: RenderFormOptions,
858
926
  ctx: SchemaFormContext,
859
927
  plans: Map<string, FieldPlan>,
860
928
  ): SchemaFormFieldView[] {
861
929
  const required = new Set(schema.required);
862
930
  const sources = refSourcesFor(ctx);
863
- return Object.entries(schema.properties ?? {}).map(([prop, ps]) =>
864
- deriveField(prop, ps, {
865
- ctx,
866
- opts,
867
- plans,
868
- required: required.has(prop),
869
- sources,
870
- value,
871
- }),
931
+ return Object.entries(schema.properties ?? {}).flatMap(([prop, ps]) => {
932
+ const args = { ctx, opts, plans, required: required.has(prop), sources, value };
933
+ const field = deriveField(prop, ps, args);
934
+ // An image object's alt text is a row of its own, under the picture it describes.
935
+ return field.kind === "control" && isImageObjectSchema(ps) && ps.properties?.["alt"]
936
+ ? [field, imageAltRow(prop, args)]
937
+ : [field];
938
+ });
939
+ }
940
+
941
+ /** The members an image object may have beside its `src`: what an `<img>` says about itself. */
942
+ const IMAGE_OBJECT_MEMBERS: ReadonlySet<string> = new Set([
943
+ "src",
944
+ "alt",
945
+ "width",
946
+ "height",
947
+ "title",
948
+ ]);
949
+
950
+ /**
951
+ * Whether a property is an image OBJECT: `{ src, alt?, width?, height?, title? }`, the shape a site
952
+ * imported from a CMS keeps a picture in (`featuredImage: { src, width, height, alt }`). Such a
953
+ * field is a picture to pick, not a record to type JSON into.
954
+ */
955
+ export function isImageObjectSchema(ps: JsonSchema): boolean {
956
+ const properties = ps.properties ?? {};
957
+ return (
958
+ ps.type === "object" &&
959
+ properties["src"]?.type === "string" &&
960
+ Object.keys(properties).every((name) => IMAGE_OBJECT_MEMBERS.has(name))
872
961
  );
873
962
  }
874
963
 
964
+ /** The media control over an image object's `src`, writing the object back around it. */
965
+ function imageObjectControl(media: SchemaFormMountedControl): SchemaFormMountedControl {
966
+ /** The args the media control sees: the `src`, and a commit that rebuilds the object. */
967
+ const srcArgs = (args: SchemaFormControlArgs): SchemaFormControlArgs => {
968
+ const held = isJsonObject(args.value) ? args.value : {};
969
+ const { src } = held;
970
+ return {
971
+ ...args,
972
+ onChange: (next) => {
973
+ if (next === src) {
974
+ return;
975
+ }
976
+ /* A different picture: its alt text and title still describe what the author meant, but the
977
+ old picture's width and height would be a lie about the new one, so they go. A cleared
978
+ field clears the whole object: an image with no picture is no image. */
979
+ const { height: _height, width: _width, ...kept } = held;
980
+ let rebuilt: JsonValue | undefined;
981
+ if (next !== undefined && next !== "") {
982
+ rebuilt = { ...kept, src: next };
983
+ }
984
+ args.onChange(rebuilt);
985
+ },
986
+ value: isString(src) ? src : undefined,
987
+ };
988
+ };
989
+ return {
990
+ mount(host, args) {
991
+ const handle = media.mount(host, srcArgs(args));
992
+ return {
993
+ dispose: () => handle.dispose(),
994
+ update: (next) => handle.update(srcArgs(next)),
995
+ };
996
+ },
997
+ };
998
+ }
999
+
1000
+ /** The text row an image object's `alt` is edited in. */
1001
+ function imageAltRow(prop: string, args: DeriveArgs): SchemaFormFieldView {
1002
+ const key = `${prop}/alt`;
1003
+ const held = args.value[prop];
1004
+ const alt = isJsonObject(held) ? held["alt"] : undefined;
1005
+ const row = deriveField(key, { type: "string" }, { ...args, required: false });
1006
+ const plan = args.plans.get(key);
1007
+ if (plan) {
1008
+ plan.prop = prop;
1009
+ plan.member = "alt";
1010
+ }
1011
+ return {
1012
+ ...row,
1013
+ label: `${args.opts.ui?.[prop]?.label ?? prop} alt text`,
1014
+ value: isString(alt) ? alt : "",
1015
+ };
1016
+ }
1017
+
875
1018
  interface DeriveArgs {
876
1019
  ctx: SchemaFormContext;
877
1020
  opts: RenderFormOptions;
878
1021
  plans: Map<string, FieldPlan>;
879
1022
  required: boolean;
880
- sources: SignalOption[];
881
- value: Record<string, unknown>;
1023
+ sources: SurfaceOption[];
1024
+ value: JsonObject;
882
1025
  }
883
1026
 
884
1027
  function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaFormFieldView {
@@ -914,11 +1057,12 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
914
1057
  invalid: error !== "",
915
1058
  key: prop,
916
1059
  kind: "text",
917
- label: prop,
1060
+ label: opts.ui?.[prop]?.label ?? prop,
918
1061
  max: "",
919
1062
  min: "",
920
1063
  mono: false,
921
1064
  multiline: false,
1065
+ inputType: "text",
922
1066
  options: [],
923
1067
  placeholder: "",
924
1068
  prop: ps.name || prop,
@@ -938,7 +1082,10 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
938
1082
  const mode = effectiveSlotMode(fieldKey, current);
939
1083
  /* A From data… rung with nothing to point at is a dead end — but this engine only ladders a
940
1084
  field once the host has named a source, so the rung always has something in it. */
941
- const offered = slotCaps({ schema: configFieldSchema(ps) });
1085
+ /* SAFETY: `JsonSchema` names only the keywords this engine acts on; the node itself is a schema
1086
+ read from JSON (a settings fragment, a collection or plugin schema), so it and every keyword
1087
+ it carries beyond the named ones are JSON, which is all the ladder's walk reads it as. */
1088
+ const offered = slotCaps({ schema: configFieldSchema(ps as ReadonlyJsonObject) });
942
1089
  plan.ladder = { fieldKey, mode, offered, sources };
943
1090
  row.hasChip = true;
944
1091
  row.sourceLabel = VALUE_SOURCE_LABELS[mode];
@@ -1002,7 +1149,33 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1002
1149
  }
1003
1150
  }
1004
1151
 
1005
- const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);
1152
+ /* An image field (`format: "image"`) is the registered `media` control: the same field, Upload and
1153
+ Browse the page's Icon and OG Image rows draw (`surfaces/media-field.json`), so a collection
1154
+ entry's picture is picked from the project's media rather than typed as a path. Unregistered
1155
+ (a bare-Bun import of this engine), it falls through to the text control below. */
1156
+ if (ps.format === "image") {
1157
+ const media = controlRegistry.get("media");
1158
+ if (media) {
1159
+ plan.commit = "none";
1160
+ plan.control = media;
1161
+ row.kind = "control";
1162
+ return row;
1163
+ }
1164
+ }
1165
+ /* An image OBJECT (`{ src, alt, width, height }`) is the same media field over its `src`; its
1166
+ `alt` is a text row of its own (`deriveFields`). Unregistered, it falls through to JSON. */
1167
+ const imageMedia = isImageObjectSchema(ps) ? controlRegistry.get("media") : undefined;
1168
+ if (imageMedia) {
1169
+ plan.commit = "none";
1170
+ plan.control = imageObjectControl(imageMedia);
1171
+ row.kind = "control";
1172
+ return row;
1173
+ }
1174
+
1175
+ /* SAFETY: both sources are read from JSON — the descriptor's `$studio.settings.entry.ui` and the
1176
+ field schema — so whichever `enum` is present is a JSON value. */
1177
+ const enumSource = (opts.ui?.[prop]?.enum ?? ps.enum) as JsonValue | undefined;
1178
+ const enumValues = resolveFormEnum(enumSource, ctx, value);
1006
1179
  if (enumValues) {
1007
1180
  plan.commit = "select";
1008
1181
  plan.debounceMs = 0;
@@ -1041,13 +1214,16 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1041
1214
  row.kind = "json";
1042
1215
  row.value = current !== undefined ? JSON.stringify(current, null, 2) : "";
1043
1216
  row.placeholder = ps.description ?? "JSON Schema defining the data shape…";
1044
- row.chips = shapeChips(current);
1217
+ row.chips = schemaPropertyChips(current);
1045
1218
  row.hasChips = row.chips.length > 0;
1046
1219
  return row;
1047
1220
  }
1048
1221
  if (ps.type === "array" && ps.items?.type === "object" && ps.items.properties) {
1049
1222
  return arrayOfObjects(prop, ps.items.properties, args, plan, row);
1050
1223
  }
1224
+ if (ps.type === "array" && isSingleValueSchema(ps.items)) {
1225
+ return arrayOfSingleValues(prop, ps.items, args, plan, row);
1226
+ }
1051
1227
  /* A union with an object or a list in it (`alerts` is an object of types or `false`) is JSON too:
1052
1228
  a text box would store what is typed as a string, which is none of the members. */
1053
1229
  const types = Array.isArray(ps.type) ? ps.type : [ps.type];
@@ -1062,21 +1238,41 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1062
1238
  row.kind = "text";
1063
1239
  row.value = asText(current);
1064
1240
  row.placeholder = ps.default !== undefined ? String(ps.default) : (ps.examples?.[0] ?? "");
1241
+ row.inputType = TEXT_INPUT_TYPES.get(ps.format ?? "") ?? "text";
1242
+ /* A date input shows nothing for a value it cannot read, so a timestamp is shown as its day. YAML
1243
+ reads an unquoted date as a Date, which reaches here as its quoted JSON. */
1244
+ const day = /^"?(\d{4}-\d{2}-\d{2})/.exec(row.value);
1245
+ if (row.inputType === "date" && day) {
1246
+ row.value = day[1] ?? row.value;
1247
+ }
1065
1248
  return row;
1066
1249
  }
1067
1250
 
1251
+ /**
1252
+ * The native input a string format is typed in. `date` is the one that changes what can be typed: a
1253
+ * date picker, and a value that is always `YYYY-MM-DD`, the `full-date` JSON Schema's `date` names.
1254
+ * `email` and `uri` only change the keyboard a phone shows, and the value stays the text typed.
1255
+ */
1256
+ const TEXT_INPUT_TYPES: ReadonlyMap<string, string> = new Map([
1257
+ ["date", "date"],
1258
+ ["email", "email"],
1259
+ ["uri", "url"],
1260
+ ]);
1261
+
1068
1262
  /** 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") {
1263
+ function schemaPropertyChips(current: JsonValue | undefined): { key: string; label: string }[] {
1264
+ // An array names no `properties`, so it has no chips either.
1265
+ if (!isJsonObject(current)) {
1071
1266
  return [];
1072
1267
  }
1073
- const held = current as Record<string, unknown>;
1074
- if (held.$ref || typeof held.properties !== "object" || held.properties === null) {
1268
+ const { properties } = current;
1269
+ if (current.$ref || properties === null || !isNonNullObject(properties)) {
1075
1270
  return [];
1076
1271
  }
1077
- return Object.entries(held.properties as Record<string, Record<string, unknown>>).map(
1078
- ([key, spec]) => ({ key, label: `${key}: ${String(spec.type ?? "any")}` }),
1079
- );
1272
+ return Object.entries(properties).map(([key, spec]) => ({
1273
+ key,
1274
+ label: `${key}: ${String((isJsonObject(spec) ? spec.type : undefined) ?? "any")}`,
1275
+ }));
1080
1276
  }
1081
1277
 
1082
1278
  /** An array whose items have a declared shape: one row per item, one cell per property. */
@@ -1088,7 +1284,10 @@ function arrayOfObjects(
1088
1284
  row: SchemaFormFieldView,
1089
1285
  ): SchemaFormFieldView {
1090
1286
  const held = args.value[prop];
1091
- const rows = Array.isArray(held) ? (held as Record<string, unknown>[]) : [];
1287
+ /* SAFETY: the caller dispatches here only for a property whose schema declares
1288
+ `items.type: "object"`, so a conforming record holds an object per item; a malformed item is
1289
+ still drawn as the row it should be, as it always was, rather than silently dropped. */
1290
+ const rows = Array.isArray(held) ? (held as JsonObject[]) : [];
1092
1291
  plan.commit = "none";
1093
1292
  plan.itemProps = itemProps;
1094
1293
  plan.rows = rows;
@@ -1099,10 +1298,73 @@ function arrayOfObjects(
1099
1298
  return row;
1100
1299
  }
1101
1300
 
1301
+ /** The one cell key a row of an array of single values is drawn under. */
1302
+ const SCALAR_CELL = "value";
1303
+
1304
+ /**
1305
+ * Whether an array's items are single values a cell can edit: text, a number, a yes/no, one of an
1306
+ * enum, or an entry of another collection. A picture is text with `format: "image"`, so it is one.
1307
+ */
1308
+ function isSingleValueSchema(items: JsonSchema | undefined): items is JsonSchema {
1309
+ if (items === undefined || items.format === "json-schema") {
1310
+ return false;
1311
+ }
1312
+ if (referenceTarget(items) !== null || Array.isArray(items.enum)) {
1313
+ return true;
1314
+ }
1315
+ return (
1316
+ items.type === "string" ||
1317
+ items.type === "number" ||
1318
+ items.type === "integer" ||
1319
+ items.type === "boolean"
1320
+ );
1321
+ }
1322
+
1323
+ /**
1324
+ * An array of single values (`categories: string[]`, a gallery's picture paths): one row per item,
1325
+ * each a single cell drawn by the item schema, with the same remove and add an array of objects
1326
+ * gets. A value that is not yet a list (a CSV cell holding one category) is shown as its one item,
1327
+ * and becomes a list the moment it is edited; the field's own check still says it is not one.
1328
+ */
1329
+ function arrayOfSingleValues(
1330
+ prop: string,
1331
+ items: JsonSchema,
1332
+ args: DeriveArgs,
1333
+ plan: FieldPlan,
1334
+ row: SchemaFormFieldView,
1335
+ ): SchemaFormFieldView {
1336
+ const held = args.value[prop];
1337
+ let list: JsonValue[] = [];
1338
+ if (Array.isArray(held)) {
1339
+ list = held;
1340
+ } else if (held !== undefined && held !== null && held !== "") {
1341
+ list = [held];
1342
+ }
1343
+ const rows: JsonObject[] = list.map((item) => ({ [SCALAR_CELL]: item }));
1344
+ const itemProps = { [SCALAR_CELL]: items };
1345
+ const label = args.opts.ui?.[prop]?.label ?? prop;
1346
+ plan.commit = "none";
1347
+ plan.itemProps = itemProps;
1348
+ plan.rows = rows;
1349
+ plan.scalarItems = true;
1350
+ plan.cellControls = new Map();
1351
+ plan.refCells = new Set();
1352
+ row.kind = "rows";
1353
+ row.rows = rows.map((item, idx) => {
1354
+ const drawn = deriveRow(prop, String(idx), item, itemProps, args, plan);
1355
+ // A row has one cell, so the cell is named by its place in the list rather than by `value`.
1356
+ for (const cell of drawn.cells) {
1357
+ cell.label = `${label} ${idx + 1}`;
1358
+ }
1359
+ return drawn;
1360
+ });
1361
+ return row;
1362
+ }
1363
+
1102
1364
  function deriveRow(
1103
1365
  prop: string,
1104
1366
  key: string,
1105
- item: Record<string, unknown>,
1367
+ item: JsonObject,
1106
1368
  itemProps: Record<string, JsonSchema>,
1107
1369
  args: DeriveArgs,
1108
1370
  plan: FieldPlan,
@@ -1122,7 +1384,7 @@ function deriveCell(
1122
1384
  rowKey: string,
1123
1385
  cellKey: string,
1124
1386
  cellSchema: JsonSchema,
1125
- held: unknown,
1387
+ held: JsonValue | undefined,
1126
1388
  args: DeriveArgs,
1127
1389
  plan: FieldPlan,
1128
1390
  ): SchemaFormCellView {
@@ -1144,10 +1406,10 @@ function deriveCell(
1144
1406
  return cell;
1145
1407
  }
1146
1408
  if (referenceTarget(cellSchema) !== null) {
1147
- /* A CELL's control is mounted into a host of the cell's own, exactly as a field's is: the one
1148
- control a cell is ever given is the reference picker, and that is a document now
1149
- (`surfaces/reference-field.json`). What the cell host must never become is a second writer of
1150
- a node the document already owns. */
1409
+ /* A CELL's control is mounted into a host of the cell's own, exactly as a field's is: the
1410
+ reference picker is a document now (`surfaces/reference-field.json`), as the media field
1411
+ below is. What the cell host must never become is a second writer of a node the document
1412
+ already owns. */
1151
1413
  const reference = controlRegistry.get("reference");
1152
1414
  if (reference) {
1153
1415
  cell.kind = "control";
@@ -1160,13 +1422,26 @@ function deriveCell(
1160
1422
  return cell;
1161
1423
  }
1162
1424
  }
1163
- const enumValues = resolveFormEnum(cellSchema.enum, args.ctx, args.value);
1425
+ /* A picture cell (`format: "image"`, a gallery's item) is the media control a picture FIELD
1426
+ gets, mounted into the cell's host by the same dispatch. */
1427
+ const media = cellSchema.format === "image" ? controlRegistry.get("media") : undefined;
1428
+ if (media) {
1429
+ cell.kind = "control";
1430
+ plan.cellControls?.set(id, { control: media, key: cellKey, row: rowKey, schema: cellSchema });
1431
+ return cell;
1432
+ }
1433
+ // SAFETY: an item property's schema is read from JSON, so its `enum` is a JSON value.
1434
+ const enumValues = resolveFormEnum(
1435
+ cellSchema.enum as JsonValue | undefined,
1436
+ args.ctx,
1437
+ args.value,
1438
+ );
1164
1439
  if (enumValues) {
1165
1440
  cell.kind = "select";
1166
1441
  cell.value = held !== undefined ? String(held) : NONE;
1167
1442
  cell.options = [
1168
1443
  { label: "—", value: NONE },
1169
- ...enumValues.map((v: string): SchemaFormOption => ({ label: v, value: v })),
1444
+ ...enumValues.map((v: string): SurfaceOption => ({ label: v, value: v })),
1170
1445
  ];
1171
1446
  return cell;
1172
1447
  }