@jxsuite/studio 6.1.2 → 8.0.1

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 (522) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  4. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  5. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  6. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  7. package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
  8. package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
  9. package/dist/chunks/color-m7r1vk54.js +4 -0
  10. package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
  11. package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
  12. package/dist/chunks/components-r22xca09.js +4 -0
  13. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  14. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  15. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  16. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  17. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  18. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  19. package/dist/chunks/files-rcn56qvm.js +4 -0
  20. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  21. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  22. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  23. package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
  24. package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
  25. package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
  26. package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
  27. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  28. package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
  29. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  30. package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
  31. package/dist/chunks/index-f0jn7nnp.js +4 -0
  32. package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
  33. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  34. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  35. package/dist/chunks/layers-bgyr11tr.js +4 -0
  36. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  37. package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
  38. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  39. package/dist/chunks/media-library-sq468wts.js +4 -0
  40. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  41. package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
  42. package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
  43. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  44. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  45. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  46. package/dist/chunks/parse-v77xtwv7.js +4 -0
  47. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  48. package/dist/chunks/popover-b89sfej7.js +4 -0
  49. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  50. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  51. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  52. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  53. package/dist/chunks/references-9547rg5s.js +4 -0
  54. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  55. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  56. package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
  57. package/dist/chunks/studio-03ct6yfv.js +9 -0
  58. package/dist/chunks/studio-07rcfje3.js +5 -0
  59. package/dist/chunks/studio-3e54qh39.js +7 -0
  60. package/dist/chunks/studio-3exxhz5g.js +5 -0
  61. package/dist/chunks/studio-3q40e3rj.js +5 -0
  62. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  63. package/dist/chunks/studio-3qqjeep5.js +6 -0
  64. package/dist/chunks/studio-43sd2mam.js +4 -0
  65. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  66. package/dist/chunks/studio-58xg6j2q.js +9 -0
  67. package/dist/chunks/studio-5g0rprdt.js +7 -0
  68. package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
  69. package/dist/chunks/studio-80jyh1xh.js +4 -0
  70. package/dist/chunks/studio-83mk4bgg.js +9 -0
  71. package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
  72. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  73. package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
  74. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  75. package/dist/chunks/studio-9tmebf0s.js +5 -0
  76. package/dist/chunks/studio-a2bvaptz.js +5 -0
  77. package/dist/chunks/studio-b7y5mr30.js +5 -0
  78. package/dist/chunks/studio-bavb31r0.js +5 -0
  79. package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
  80. package/dist/chunks/studio-c05wdnt3.js +5 -0
  81. package/dist/chunks/studio-ccv2svc6.js +5 -0
  82. package/dist/chunks/studio-d5grtb9e.js +16 -0
  83. package/dist/chunks/studio-df0baea9.js +5 -0
  84. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  85. package/dist/chunks/studio-e1g64q43.js +5 -0
  86. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  87. package/dist/chunks/studio-ed3xx40h.js +7 -0
  88. package/dist/chunks/studio-f14e1zdj.js +5 -0
  89. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  90. package/dist/chunks/studio-fyh0jc96.js +5 -0
  91. package/dist/chunks/studio-gcxk20n7.js +5 -0
  92. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  93. package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
  94. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  95. package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
  96. package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
  97. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  98. package/dist/chunks/studio-m8g16bgz.js +5 -0
  99. package/dist/chunks/studio-mn0476ag.js +5 -0
  100. package/dist/chunks/studio-mx1smyq0.js +5 -0
  101. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  102. package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
  103. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  104. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  105. package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
  106. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  107. package/dist/chunks/studio-ph84avkf.js +5 -0
  108. package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
  109. package/dist/chunks/studio-q0tccd43.js +5 -0
  110. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  111. package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
  112. package/dist/chunks/studio-qmn1xc24.js +5 -0
  113. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  114. package/dist/chunks/studio-r5qy30vx.js +5 -0
  115. package/dist/chunks/studio-rj9eamf8.js +5 -0
  116. package/dist/chunks/studio-rptgsk96.js +5 -0
  117. package/dist/chunks/studio-rthyg42z.js +928 -0
  118. package/dist/chunks/studio-s19tp1xr.js +5 -0
  119. package/dist/chunks/studio-s32578pn.js +5 -0
  120. package/dist/chunks/studio-svb7yyve.js +5 -0
  121. package/dist/chunks/studio-syreb644.js +5 -0
  122. package/dist/chunks/studio-tf9jryb1.js +10 -0
  123. package/dist/chunks/studio-tfkznv39.js +5 -0
  124. package/dist/chunks/studio-tft6r105.js +5 -0
  125. package/dist/chunks/studio-txf2kysx.js +5 -0
  126. package/dist/chunks/studio-v8867ddv.js +12 -0
  127. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  128. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  129. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  130. package/dist/chunks/studio-wc649wss.js +5 -0
  131. package/dist/chunks/studio-wys23mxz.js +5 -0
  132. package/dist/chunks/studio-x1x167jh.js +5 -0
  133. package/dist/chunks/studio-x9hsze61.js +5 -0
  134. package/dist/chunks/studio-y0n7yxea.js +9 -0
  135. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  136. package/dist/chunks/studio-z97c48fk.js +5 -0
  137. package/dist/chunks/studio-zat62m0c.js +5 -0
  138. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  139. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  140. package/dist/chunks/toast-1gv0h53h.js +4 -0
  141. package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
  142. package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
  143. package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
  144. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  145. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  146. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  147. package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
  148. package/dist/iframe-entry.js +20 -16
  149. package/dist/manifest.json +77 -63
  150. package/dist/studio.js +103 -104
  151. package/dist/workers/ts.worker.js +3 -3
  152. package/package.json +12 -11
  153. package/src/browse/component-examples.ts +272 -0
  154. package/src/browse/library-commands.ts +64 -104
  155. package/src/browse/library-layouts.ts +263 -49
  156. package/src/browse/library-model.ts +181 -133
  157. package/src/browse/library-pane.ts +738 -446
  158. package/src/browse/library-preview.ts +149 -19
  159. package/src/browse/library-source.ts +308 -41
  160. package/src/browse/preview-root.ts +78 -0
  161. package/src/browse/preview-style.ts +155 -0
  162. package/src/canvas/asset-refs.ts +16 -1
  163. package/src/canvas/canvas-live-render.ts +222 -30
  164. package/src/canvas/canvas-origin.ts +37 -12
  165. package/src/canvas/canvas-page-context.ts +112 -0
  166. package/src/canvas/canvas-render.ts +113 -107
  167. package/src/canvas/canvas-utils.ts +57 -12
  168. package/src/canvas/iframe-drop.ts +107 -0
  169. package/src/canvas/iframe-entry.ts +24 -12
  170. package/src/canvas/iframe-host.ts +134 -62
  171. package/src/canvas/iframe-keys.ts +11 -0
  172. package/src/canvas/iframe-patch.ts +8 -7
  173. package/src/canvas/iframe-protocol.ts +24 -5
  174. package/src/canvas/iframe-render.ts +48 -1
  175. package/src/canvas/iframe-subtree.ts +5 -2
  176. package/src/canvas/npm-modules.ts +22 -0
  177. package/src/canvas/preview-navigate.ts +16 -0
  178. package/src/canvas/repeater-sources.ts +200 -0
  179. package/src/canvas/stage-scrollbar.ts +5 -1
  180. package/src/canvas/surface-registry.ts +6 -0
  181. package/src/commands/app-commands.ts +16 -6
  182. package/src/commands/budget.ts +10 -8
  183. package/src/commands/context.ts +35 -10
  184. package/src/commands/defaults.ts +69 -45
  185. package/src/commands/keymap.ts +9 -0
  186. package/src/commands/levels.ts +11 -5
  187. package/src/commands/live-context.ts +2 -0
  188. package/src/commands/registry.ts +10 -1
  189. package/src/content/collection-match.ts +6 -5
  190. package/src/content/collection-pages.ts +412 -0
  191. package/src/content/content-collections.ts +270 -0
  192. package/src/content/entry-commands.ts +51 -60
  193. package/src/content/entry-editor.ts +111 -18
  194. package/src/content/entry-fields.ts +13 -1
  195. package/src/content/entry-inspector.ts +225 -0
  196. package/src/content/entry-model.ts +17 -3
  197. package/src/content/entry-open.ts +80 -0
  198. package/src/content/entry-summaries.ts +440 -0
  199. package/src/content/file-record-ids.ts +80 -0
  200. package/src/content/file-records.ts +125 -0
  201. package/src/content/page-summaries.ts +129 -0
  202. package/src/content/record-entry.ts +201 -0
  203. package/src/content/writing-banner.ts +177 -0
  204. package/src/create/add-new-commands.ts +185 -0
  205. package/src/create/add-new-flow.ts +1116 -0
  206. package/src/create/add-new.ts +1014 -0
  207. package/src/create/element-name.ts +121 -0
  208. package/src/editor/convert-to-component.ts +67 -43
  209. package/src/editor/file-drop-action.ts +9 -1
  210. package/src/editor/inline-edit-apply.ts +44 -0
  211. package/src/editor/inline-edit.ts +10 -0
  212. package/src/editor/insert-component.ts +91 -0
  213. package/src/editor/insert-zone-action.ts +13 -4
  214. package/src/editor/shortcuts.ts +44 -22
  215. package/src/editor/slash-menu.ts +51 -8
  216. package/src/files/components.ts +74 -10
  217. package/src/files/file-ops.ts +15 -5
  218. package/src/files/files.ts +164 -150
  219. package/src/files/fs-events.ts +18 -7
  220. package/src/files/media-meta.ts +95 -1
  221. package/src/files/media-types.ts +55 -0
  222. package/src/files/media-upload.ts +209 -52
  223. package/src/files/new-file-name.ts +156 -0
  224. package/src/files/serialize-document.ts +13 -3
  225. package/src/format/format-host.ts +15 -0
  226. package/src/github/github-auth.ts +2 -2
  227. package/src/github/github-publish.ts +4 -3
  228. package/src/grid/grid-controller.ts +5 -1
  229. package/src/grid/grid-open.ts +0 -27
  230. package/src/grid/grid-panel.ts +54 -2
  231. package/src/grid/grid-reveal.ts +34 -0
  232. package/src/grid/grid-source.ts +3 -25
  233. package/src/grid/grid-view.ts +31 -6
  234. package/src/grid/sources/content-source.ts +75 -7
  235. package/src/grid/tabulator-tables.d.ts +6 -0
  236. package/src/hosting/document.ts +2 -2
  237. package/src/i18n/i18n-commands.ts +2 -1
  238. package/src/media/media-commands.ts +181 -0
  239. package/src/media/media-library-model.ts +232 -0
  240. package/src/media/media-library.ts +1283 -0
  241. package/src/media/media-pane.ts +47 -19
  242. package/src/packages/pull-package-sync.ts +1 -1
  243. package/src/panels/activity-panel.ts +21 -5
  244. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  245. package/src/panels/block-action-bar.ts +11 -11
  246. package/src/panels/canvas-dnd-bridge.ts +5 -2
  247. package/src/panels/chat-panel.ts +6 -6
  248. package/src/panels/collections-panel.ts +306 -0
  249. package/src/panels/component-preview.ts +35 -13
  250. package/src/panels/data-explorer.ts +1 -1
  251. package/src/panels/data-grid.ts +4 -0
  252. package/src/panels/dnd.ts +17 -30
  253. package/src/panels/elements-panel.ts +9 -2
  254. package/src/panels/empty-state.ts +2 -2
  255. package/src/panels/formula-workspace.ts +2 -3
  256. package/src/panels/frontmatter-fields.ts +9 -9
  257. package/src/panels/git-diff-open.ts +9 -5
  258. package/src/panels/head-panel.ts +369 -103
  259. package/src/panels/i18n-panel.ts +11 -10
  260. package/src/panels/imports-panel.ts +2 -0
  261. package/src/panels/jump-bar.ts +27 -2
  262. package/src/panels/layers-panel.ts +36 -30
  263. package/src/panels/left-panel.ts +22 -8
  264. package/src/panels/navigator-panels.ts +23 -11
  265. package/src/panels/pane-context.ts +111 -29
  266. package/src/panels/pane-grid.ts +6 -6
  267. package/src/panels/panel-registry.ts +14 -9
  268. package/src/panels/properties-panel.ts +7 -3
  269. package/src/panels/right-panel.ts +199 -43
  270. package/src/panels/seo-modal.ts +41 -108
  271. package/src/panels/settings-menu.ts +52 -50
  272. package/src/panels/settings-pane.ts +268 -162
  273. package/src/panels/signals-panel.ts +3 -4
  274. package/src/panels/site-model.ts +367 -0
  275. package/src/panels/site-panel.ts +638 -0
  276. package/src/panels/style-panel.ts +37 -3
  277. package/src/panels/stylebook-doc.ts +142 -10
  278. package/src/panels/stylebook-layers-panel.ts +39 -80
  279. package/src/panels/stylebook-panel.ts +47 -10
  280. package/src/panels/styles-panel.ts +327 -0
  281. package/src/panels/tab-strip.ts +109 -25
  282. package/src/platform.ts +1 -1
  283. package/src/platforms/cloud.ts +28 -1
  284. package/src/platforms/default-platform.ts +4 -4
  285. package/src/platforms/devserver.ts +51 -25
  286. package/src/publish/deploy-checklist.ts +12 -7
  287. package/src/publish/pages-service.ts +38 -14
  288. package/src/publish/publish-changes.ts +491 -0
  289. package/src/publish/publish-commands.ts +83 -18
  290. package/src/publish/publish-ids.ts +49 -0
  291. package/src/publish/publish-quick.ts +148 -0
  292. package/src/publish/publish-workspace.ts +926 -0
  293. package/src/publish/source-control.ts +907 -0
  294. package/src/services/automation.ts +16 -20
  295. package/src/services/cf-settings.ts +4 -4
  296. package/src/services/connection.ts +2 -2
  297. package/src/services/directory-picker.ts +2 -2
  298. package/src/services/references.ts +0 -0
  299. package/src/services/render-critic.ts +21 -2
  300. package/src/services/settings/definitions.ts +25 -14
  301. package/src/settings/contributed-section.ts +49 -10
  302. package/src/settings/css-vars-editor.ts +93 -27
  303. package/src/settings/developer-panels.ts +43 -0
  304. package/src/settings/extension-sections.ts +20 -2
  305. package/src/settings/general-settings.ts +91 -21
  306. package/src/settings/preferences-dialog.ts +8 -1
  307. package/src/settings/project-sections.ts +27 -10
  308. package/src/settings/schema-field-ui.ts +3 -1
  309. package/src/settings/section-registry.ts +116 -11
  310. package/src/settings/settings-dialog.ts +192 -0
  311. package/src/settings/settings-document.ts +182 -162
  312. package/src/shell.ts +467 -431
  313. package/src/site-context.ts +64 -10
  314. package/src/state.ts +28 -9
  315. package/src/studio.ts +194 -41
  316. package/src/style/project-styles.ts +34 -0
  317. package/src/style/stylebook-specimens.ts +89 -0
  318. package/src/style/stylebook-target.ts +26 -0
  319. package/src/style/tag-inheritance.ts +105 -0
  320. package/src/style/variables-focus.ts +61 -0
  321. package/src/style/variables-view.ts +235 -0
  322. package/src/surfaces/add-new.json +1482 -0
  323. package/src/surfaces/add-new.ts +325 -0
  324. package/src/surfaces/ai-chat.ts +2 -2
  325. package/src/surfaces/boot-failure.json +4 -3
  326. package/src/surfaces/bottom-dock.json +1 -1
  327. package/src/surfaces/canvas-stage.json +30 -19
  328. package/src/surfaces/canvas-stage.ts +5 -5
  329. package/src/surfaces/collections-panel.json +615 -0
  330. package/src/surfaces/collections-panel.ts +168 -0
  331. package/src/surfaces/commandbar.json +241 -96
  332. package/src/surfaces/commandbar.ts +134 -99
  333. package/src/surfaces/empty-state.json +1 -1
  334. package/src/surfaces/entry-editor.json +136 -0
  335. package/src/surfaces/entry-editor.ts +21 -0
  336. package/src/surfaces/entry-inspector.json +371 -0
  337. package/src/surfaces/entry-inspector.ts +143 -0
  338. package/src/surfaces/inspector-dock.json +162 -14
  339. package/src/surfaces/inspector-dock.ts +46 -19
  340. package/src/surfaces/library-pane.json +670 -437
  341. package/src/surfaces/library-pane.ts +94 -59
  342. package/src/surfaces/media-browser.json +62 -6
  343. package/src/surfaces/media-browser.ts +15 -1
  344. package/src/surfaces/media-field.json +1 -1
  345. package/src/surfaces/media-library.json +1586 -0
  346. package/src/surfaces/media-library.ts +282 -0
  347. package/src/surfaces/media-pick-dialog.json +71 -0
  348. package/src/surfaces/media-pick-dialog.ts +132 -0
  349. package/src/surfaces/menu.ts +18 -0
  350. package/src/surfaces/pane-context.json +144 -77
  351. package/src/surfaces/pane-context.ts +24 -0
  352. package/src/surfaces/panel-deploy-checklist.json +12 -6
  353. package/src/surfaces/panel-deploy-checklist.ts +3 -1
  354. package/src/surfaces/panel-page.json +72 -2
  355. package/src/surfaces/panel-page.ts +38 -7
  356. package/src/surfaces/panel-signals.json +1 -1
  357. package/src/surfaces/panel-signals.ts +5 -5
  358. package/src/surfaces/panel-stylebook-layers.json +71 -204
  359. package/src/surfaces/panel-stylebook-layers.ts +0 -21
  360. package/src/surfaces/preferences.json +120 -48
  361. package/src/surfaces/preferences.ts +8 -0
  362. package/src/surfaces/publish-quick.json +428 -0
  363. package/src/surfaces/publish-quick.ts +165 -0
  364. package/src/surfaces/publish-workspace.json +2892 -0
  365. package/src/surfaces/publish-workspace.ts +391 -0
  366. package/src/surfaces/rail.json +1 -159
  367. package/src/surfaces/rail.ts +18 -75
  368. package/src/surfaces/schema-form.json +10 -2
  369. package/src/surfaces/schema-form.ts +2 -0
  370. package/src/surfaces/seo.json +1 -1
  371. package/src/surfaces/settings-contributed.json +5 -5
  372. package/src/surfaces/settings-contributed.ts +18 -2
  373. package/src/surfaces/settings-css-vars.json +44 -36
  374. package/src/surfaces/settings-css-vars.ts +77 -4
  375. package/src/surfaces/settings-deploy.json +2 -15
  376. package/src/surfaces/settings-deploy.ts +1 -1
  377. package/src/surfaces/settings-dialog.json +51 -0
  378. package/src/surfaces/settings-dialog.ts +169 -0
  379. package/src/surfaces/settings-overview.json +3 -3
  380. package/src/surfaces/settings-overview.ts +9 -2
  381. package/src/surfaces/settings-pane.json +269 -46
  382. package/src/surfaces/settings-pane.ts +85 -24
  383. package/src/surfaces/shell.json +2 -1
  384. package/src/surfaces/site-panel.json +1029 -0
  385. package/src/surfaces/site-panel.ts +233 -0
  386. package/src/surfaces/slash-menu.json +63 -21
  387. package/src/surfaces/slash-menu.ts +23 -0
  388. package/src/surfaces/statusbar.ts +39 -15
  389. package/src/surfaces/styles-panel.json +735 -0
  390. package/src/surfaces/styles-panel.ts +195 -0
  391. package/src/surfaces/styles-variables.json +149 -0
  392. package/src/surfaces/styles-variables.ts +145 -0
  393. package/src/surfaces/tab-strip.json +4 -4
  394. package/src/surfaces/welcome.ts +1 -1
  395. package/src/surfaces/writing-banner.json +94 -0
  396. package/src/surfaces/writing-banner.ts +80 -0
  397. package/src/tabs/bare-repeaters.ts +101 -0
  398. package/src/tabs/tab.ts +47 -7
  399. package/src/types.ts +21 -26
  400. package/src/ui/form-controls.ts +47 -8
  401. package/src/ui/layers.ts +13 -0
  402. package/src/ui/media-picker.ts +284 -40
  403. package/src/ui/regions.ts +7 -6
  404. package/src/ui/schema-form.ts +259 -27
  405. package/src/ui/virtual-window.ts +26 -1
  406. package/src/utils/base64.ts +3 -3
  407. package/src/utils/edit-display.ts +322 -67
  408. package/src/utils/local-day.ts +18 -0
  409. package/src/workspace/pane-derive.ts +4 -4
  410. package/src/workspace/session.ts +28 -7
  411. package/src/workspace/tab-workspace.ts +137 -0
  412. package/src/workspace/workspace-back.ts +189 -0
  413. package/src/workspace/workspace-home.ts +133 -0
  414. package/src/workspace/workspace-ids.ts +129 -0
  415. package/src/workspace/workspace-switch.ts +372 -0
  416. package/src/workspace/workspace.ts +125 -11
  417. package/styles/shell-frame.css +30 -7
  418. package/styles/shell-frame.json +15 -3
  419. package/dist/chunks/2020-f2gkpy8d.js +0 -4
  420. package/dist/chunks/adapter-4912g339.js +0 -4
  421. package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
  422. package/dist/chunks/cf-settings-br6105tr.js +0 -4
  423. package/dist/chunks/color-28ksk2qm.js +0 -4
  424. package/dist/chunks/components-db68vsn7.js +0 -4
  425. package/dist/chunks/content-source-1449qesq.js +0 -4
  426. package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
  427. package/dist/chunks/editor-x9jn86a7.js +0 -4
  428. package/dist/chunks/entry-commands-may24cpt.js +0 -4
  429. package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
  430. package/dist/chunks/file-ops-x9v54pcj.js +0 -4
  431. package/dist/chunks/files-j3knqf0s.js +0 -4
  432. package/dist/chunks/format-host-tyre2trb.js +0 -4
  433. package/dist/chunks/fs-events-64ma9htc.js +0 -4
  434. package/dist/chunks/git-panel-84ps5dex.js +0 -4
  435. package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
  436. package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
  437. package/dist/chunks/index-b8xw3vy9.js +0 -4
  438. package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
  439. package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
  440. package/dist/chunks/layers-h4xp1pss.js +0 -4
  441. package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
  442. package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
  443. package/dist/chunks/media-picker-2cweexc5.js +0 -4
  444. package/dist/chunks/menu-ynw13y0s.js +0 -4
  445. package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
  446. package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
  447. package/dist/chunks/notify-cj5zbrs2.js +0 -4
  448. package/dist/chunks/parse-b7ddhr8m.js +0 -4
  449. package/dist/chunks/platform-3dfws9js.js +0 -4
  450. package/dist/chunks/popover-jt2gxmzs.js +0 -4
  451. package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
  452. package/dist/chunks/quick-search-0dajrwqg.js +0 -4
  453. package/dist/chunks/references-49qgt404.js +0 -4
  454. package/dist/chunks/right-panel-jm1bwe53.js +0 -4
  455. package/dist/chunks/section-registry-6kwc4fky.js +0 -4
  456. package/dist/chunks/studio-0rt52vpq.js +0 -5
  457. package/dist/chunks/studio-18vgbhs5.js +0 -5
  458. package/dist/chunks/studio-24mccdrj.js +0 -5
  459. package/dist/chunks/studio-2eh507zk.js +0 -9
  460. package/dist/chunks/studio-2hcbccfv.js +0 -5
  461. package/dist/chunks/studio-2jbs3rxv.js +0 -5
  462. package/dist/chunks/studio-4h8k4dw9.js +0 -5
  463. package/dist/chunks/studio-5f6n18kx.js +0 -5
  464. package/dist/chunks/studio-5gthpky6.js +0 -5
  465. package/dist/chunks/studio-6ep3js6b.js +0 -9
  466. package/dist/chunks/studio-6wkmf3wz.js +0 -9
  467. package/dist/chunks/studio-841rf3cg.js +0 -5
  468. package/dist/chunks/studio-8gmwgheg.js +0 -5
  469. package/dist/chunks/studio-8qm0ep50.js +0 -5
  470. package/dist/chunks/studio-924p1tm1.js +0 -6
  471. package/dist/chunks/studio-a3shpz9y.js +0 -5
  472. package/dist/chunks/studio-amsbaaar.js +0 -6
  473. package/dist/chunks/studio-at5spjbc.js +0 -7
  474. package/dist/chunks/studio-b2xv945e.js +0 -5
  475. package/dist/chunks/studio-bn5nkafw.js +0 -5
  476. package/dist/chunks/studio-bw6q5xjf.js +0 -9
  477. package/dist/chunks/studio-c7q0t9x1.js +0 -5
  478. package/dist/chunks/studio-camnhc96.js +0 -6
  479. package/dist/chunks/studio-cffqvnzd.js +0 -5
  480. package/dist/chunks/studio-efvfrsf8.js +0 -5
  481. package/dist/chunks/studio-er30bpcx.js +0 -5
  482. package/dist/chunks/studio-ezscgr64.js +0 -5
  483. package/dist/chunks/studio-ffrrncvz.js +0 -5
  484. package/dist/chunks/studio-fpphgn8y.js +0 -10
  485. package/dist/chunks/studio-j1kvhdjk.js +0 -4
  486. package/dist/chunks/studio-j430n16g.js +0 -7
  487. package/dist/chunks/studio-jjkg84nj.js +0 -5
  488. package/dist/chunks/studio-m0q32ars.js +0 -4
  489. package/dist/chunks/studio-m6bdst11.js +0 -5
  490. package/dist/chunks/studio-nv2cptd4.js +0 -64
  491. package/dist/chunks/studio-nwfrc98n.js +0 -5
  492. package/dist/chunks/studio-p1wgvp7r.js +0 -5
  493. package/dist/chunks/studio-pag2wncm.js +0 -5
  494. package/dist/chunks/studio-qvanvzfd.js +0 -5
  495. package/dist/chunks/studio-qwa64kt7.js +0 -5
  496. package/dist/chunks/studio-rk1zc4x3.js +0 -928
  497. package/dist/chunks/studio-se2r3ptc.js +0 -5
  498. package/dist/chunks/studio-sg2a0dh0.js +0 -5
  499. package/dist/chunks/studio-tjzjhe68.js +0 -5
  500. package/dist/chunks/studio-v2w7q8r1.js +0 -7
  501. package/dist/chunks/studio-v5vjq1h0.js +0 -4
  502. package/dist/chunks/studio-v8aga3vp.js +0 -14
  503. package/dist/chunks/studio-vfcdrfmv.js +0 -5
  504. package/dist/chunks/studio-vmfkgdjf.js +0 -5
  505. package/dist/chunks/studio-wt1816jj.js +0 -5
  506. package/dist/chunks/studio-wz73q5kq.js +0 -4
  507. package/dist/chunks/studio-y04qtxvp.js +0 -7
  508. package/dist/chunks/studio-y21g8zzg.js +0 -5
  509. package/dist/chunks/studio-y64hrt8p.js +0 -12
  510. package/dist/chunks/studio-ynn90f58.js +0 -16
  511. package/dist/chunks/studio-yxz682sx.js +0 -5
  512. package/dist/chunks/studio-zp7snvkq.js +0 -5
  513. package/dist/chunks/studio-zq4z6tm6.js +0 -5
  514. package/dist/chunks/toast-c9fn075p.js +0 -4
  515. package/dist/chunks/tsMode-sf49ee9x.js +0 -14
  516. package/dist/chunks/workspace-jtfahpee.js +0 -4
  517. package/src/panels/frontmatter-panel.ts +0 -711
  518. package/src/panels/git-panel.ts +0 -1108
  519. package/src/surfaces/doc-header.json +0 -776
  520. package/src/surfaces/doc-header.ts +0 -222
  521. package/src/surfaces/git-panel.json +0 -1880
  522. package/src/surfaces/git-panel.ts +0 -264
@@ -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
@@ -174,9 +174,10 @@ export interface RenderFormOptions {
174
174
  /**
175
175
  * Per-field overrides from `$studio.settings.entry.ui`: a registered control name, and/or an
176
176
  * `enum` source (choice list or `{ "$ref": "#/$context/<pointer>" }`) layered over the field
177
- * 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.
178
179
  */
179
- ui?: Record<string, { control?: string; enum?: unknown }> | undefined;
180
+ ui?: Record<string, { control?: string; enum?: unknown; label?: string }> | undefined;
180
181
  rerender?: (() => void) | undefined;
181
182
  /**
182
183
  * Externally-produced diagnostics, keyed by property name — §16.1's inline tier, sourced.
@@ -416,16 +417,28 @@ interface FieldPlan {
416
417
  itemProps?: Record<string, JsonSchema> | undefined;
417
418
  /** The rows currently held, so a cell edit can rebuild the array. */
418
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;
419
426
  /** The ladder, when this position offers one. */
420
427
  ladder?: { fieldKey: string; mode: SlotMode; offered: SlotMode[]; sources: SurfaceOption[] };
421
428
  /** A registered control owns the whole field; args are rebuilt for it on every repaint. */
422
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;
423
436
  /**
424
437
  * Registered controls owning one cell, keyed by the cell's host id.
425
438
  *
426
439
  * The same kind of entry a field's own control is, and reached by the same dispatch: a cell host
427
- * is a host like any other. The one control a cell is ever given is `reference` (see
428
- * {@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}).
429
442
  */
430
443
  cellControls?: Map<
431
444
  string,
@@ -574,11 +587,37 @@ function createController(): FormController {
574
587
  return;
575
588
  }
576
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
+ }
577
602
  patch(plan.prop, raw || undefined);
578
603
  }
579
604
  }
580
605
  };
581
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
+
582
621
  /** The field's items, each shallow-copied so a cell edit never writes through to the document. */
583
622
  const cellRows = (plan: FieldPlan): JsonObject[] => {
584
623
  const copies: JsonObject[] = [];
@@ -602,7 +641,7 @@ function createController(): FormController {
602
641
  seed[k] = v.default as JsonValue;
603
642
  }
604
643
  }
605
- patch(field, [...cellRows(plan), seed]);
644
+ patchRows(plan, [...cellRows(plan), seed]);
606
645
  opts.rerender?.();
607
646
  },
608
647
  commit: (key: string, raw: string) => {
@@ -644,8 +683,10 @@ function createController(): FormController {
644
683
  return;
645
684
  }
646
685
  const idx = Number(row);
647
- const kept = cellRows(plan).filter((_, i) => i !== idx);
648
- patch(field, kept.length > 0 ? kept : undefined);
686
+ patchRows(
687
+ plan,
688
+ cellRows(plan).filter((_, i) => i !== idx),
689
+ );
649
690
  opts.rerender?.();
650
691
  },
651
692
  };
@@ -669,7 +710,7 @@ function createController(): FormController {
669
710
  ...target,
670
711
  [cell]: coerceCell(cellSchema, next, plan.refCells?.has(`${field}/${row}/${cell}`) ?? false),
671
712
  } as JsonObject;
672
- patch(field, rows);
713
+ patchRows(plan, rows);
673
714
  }
674
715
 
675
716
  /** A cell's committed string, as the item property's declared type. */
@@ -887,18 +928,93 @@ function deriveFields(
887
928
  ): SchemaFormFieldView[] {
888
929
  const required = new Set(schema.required);
889
930
  const sources = refSourcesFor(ctx);
890
- return Object.entries(schema.properties ?? {}).map(([prop, ps]) =>
891
- deriveField(prop, ps, {
892
- ctx,
893
- opts,
894
- plans,
895
- required: required.has(prop),
896
- sources,
897
- value,
898
- }),
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))
899
961
  );
900
962
  }
901
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
+
902
1018
  interface DeriveArgs {
903
1019
  ctx: SchemaFormContext;
904
1020
  opts: RenderFormOptions;
@@ -941,11 +1057,12 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
941
1057
  invalid: error !== "",
942
1058
  key: prop,
943
1059
  kind: "text",
944
- label: prop,
1060
+ label: opts.ui?.[prop]?.label ?? prop,
945
1061
  max: "",
946
1062
  min: "",
947
1063
  mono: false,
948
1064
  multiline: false,
1065
+ inputType: "text",
949
1066
  options: [],
950
1067
  placeholder: "",
951
1068
  prop: ps.name || prop,
@@ -1032,6 +1149,29 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1032
1149
  }
1033
1150
  }
1034
1151
 
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
+
1035
1175
  /* SAFETY: both sources are read from JSON — the descriptor's `$studio.settings.entry.ui` and the
1036
1176
  field schema — so whichever `enum` is present is a JSON value. */
1037
1177
  const enumSource = (opts.ui?.[prop]?.enum ?? ps.enum) as JsonValue | undefined;
@@ -1081,6 +1221,9 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1081
1221
  if (ps.type === "array" && ps.items?.type === "object" && ps.items.properties) {
1082
1222
  return arrayOfObjects(prop, ps.items.properties, args, plan, row);
1083
1223
  }
1224
+ if (ps.type === "array" && isSingleValueSchema(ps.items)) {
1225
+ return arrayOfSingleValues(prop, ps.items, args, plan, row);
1226
+ }
1084
1227
  /* A union with an object or a list in it (`alerts` is an object of types or `false`) is JSON too:
1085
1228
  a text box would store what is typed as a string, which is none of the members. */
1086
1229
  const types = Array.isArray(ps.type) ? ps.type : [ps.type];
@@ -1095,9 +1238,27 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
1095
1238
  row.kind = "text";
1096
1239
  row.value = asText(current);
1097
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
+ }
1098
1248
  return row;
1099
1249
  }
1100
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
+
1101
1262
  /** The property chips above a JSON-Schema field: what shape is in there right now. */
1102
1263
  function schemaPropertyChips(current: JsonValue | undefined): { key: string; label: string }[] {
1103
1264
  // An array names no `properties`, so it has no chips either.
@@ -1137,6 +1298,69 @@ function arrayOfObjects(
1137
1298
  return row;
1138
1299
  }
1139
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
+
1140
1364
  function deriveRow(
1141
1365
  prop: string,
1142
1366
  key: string,
@@ -1182,10 +1406,10 @@ function deriveCell(
1182
1406
  return cell;
1183
1407
  }
1184
1408
  if (referenceTarget(cellSchema) !== null) {
1185
- /* A CELL's control is mounted into a host of the cell's own, exactly as a field's is: the one
1186
- control a cell is ever given is the reference picker, and that is a document now
1187
- (`surfaces/reference-field.json`). What the cell host must never become is a second writer of
1188
- 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. */
1189
1413
  const reference = controlRegistry.get("reference");
1190
1414
  if (reference) {
1191
1415
  cell.kind = "control";
@@ -1198,6 +1422,14 @@ function deriveCell(
1198
1422
  return cell;
1199
1423
  }
1200
1424
  }
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
+ }
1201
1433
  // SAFETY: an item property's schema is read from JSON, so its `enum` is a JSON value.
1202
1434
  const enumValues = resolveFormEnum(
1203
1435
  cellSchema.enum as JsonValue | undefined,
@@ -330,7 +330,7 @@ export function scrollerFor(list: HTMLElement): HTMLElement | null {
330
330
  if (cached && cached.isConnected && list.isConnected && cached.contains(list)) {
331
331
  return cached;
332
332
  }
333
- const found = nearestScroller(list);
333
+ const found = declaredScroller(list) ?? nearestScroller(list);
334
334
  if (found) {
335
335
  scrollerCache.set(list, found);
336
336
  } else {
@@ -339,6 +339,31 @@ export function scrollerFor(list: HTMLElement): HTMLElement | null {
339
339
  return found;
340
340
  }
341
341
 
342
+ /**
343
+ * The attribute a host stamps on the element it KNOWS scrolls the lists drawn inside it.
344
+ *
345
+ * `#left-panel` is the one scroller every Navigator panel draws in (its dock's root is `display:
346
+ * contents`), and the shell says so in `surfaces/shell.json`.
347
+ */
348
+ export const SCROLLER_ATTR = "data-jx-scroller";
349
+
350
+ /**
351
+ * The scroller a host declared for `list`, found by a node walk that reads no layout, or null.
352
+ *
353
+ * {@link nearestScroller}'s walk reads `scrollHeight`, `clientHeight` and computed overflow on every
354
+ * ancestor, and the moment a list is bound is the moment its panel has just been drawn, so the
355
+ * first read pays a style recalculation of the whole half-written document. The cache cannot help
356
+ * there: the Files tree and the Outline are new elements each time their panel is shown again, so
357
+ * every show of either one walked (12 to 32 ms a show in the perf trace). A declared scroller
358
+ * answers by identity. It carries the memoized answer's one residue: it is the scroller whether or
359
+ * not its content overflows right now, and a list that fits is windowed to the whole list, which is
360
+ * what {@link computeWindow} answers for it anyway. Only a CONNECTED list asks: a list still being
361
+ * built is not inside its scroller yet.
362
+ */
363
+ function declaredScroller(list: HTMLElement): HTMLElement | null {
364
+ return list.isConnected ? list.closest<HTMLElement>(`[${SCROLLER_ATTR}]`) : null;
365
+ }
366
+
342
367
  /**
343
368
  * How far `list`'s first row has scrolled above the top of `scroller`'s viewport.
344
369
  *
@@ -3,9 +3,9 @@
3
3
  * Base64 encoding for binary payloads that cross an RPC boundary.
4
4
  *
5
5
  * `StudioPlatform.uploadFile` accepts `string | File | Blob | ArrayBuffer`, but the RPC platforms
6
- * (electrobun, chromium) JSON-serialize their params — a `File`/`Blob` becomes `{}` on the wire.
7
- * Those platforms encode here before the call; the HTTP platforms (dev server, cloud) post the
8
- * binary body directly and must NOT use this.
6
+ * (the chromium desktop shell) JSON-serialize their params — a `File`/`Blob` becomes `{}` on the
7
+ * wire. Those platforms encode here before the call; the HTTP platforms (dev server, cloud) post
8
+ * the binary body directly and must NOT use this.
9
9
  *
10
10
  * {@link base64ToBytes} is the same boundary in the other direction, for `readFileBytes`: the RPC
11
11
  * backends answer a base64 string for the same reason they accept one, and the caller wants bytes.