@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
@@ -1,6 +1,11 @@
1
1
  /**
2
- * The content-entry verbs: create one, open one as a form, mark one a draft, and choose whether
3
- * drafts are listed at all.
2
+ * The content-entry verbs: open one where it is written, mark one a draft, and choose whether
3
+ * drafts are listed at all — and {@link createEntry}, the New File tree's route into a collection
4
+ * folder.
5
+ *
6
+ * Creating an entry from anywhere else is Add new's (`file.new { kind: "entry", collection }`,
7
+ * `create/add-new-flow.ts`), which seeds through {@link entryFormatName} and `entryBody` exactly as
8
+ * {@link createEntry} does, so both routes write the same bytes.
4
9
  *
5
10
  * Each is a record in its owning module, so the palette row, the assistant's tool, the automation
6
11
  * step and (for the two that declare one) the context-menu item are renderings of the same
@@ -14,8 +19,6 @@ import {
14
19
  argsSchema,
15
20
  booleanArg,
16
21
  booleanProperty,
17
- derivedEnumProperty,
18
- enumArg,
19
22
  stringArg,
20
23
  stringProperty,
21
24
  } from "../commands/command-args";
@@ -32,48 +35,61 @@ import { serializeJson } from "@jxsuite/schema/json-layout";
32
35
  import { invalidateReferenceEntries } from "../ui/form-controls";
33
36
  import { reloadDraftAwareGrids } from "../grid/sources/content-source";
34
37
  import { setIncludeDrafts } from "./draft-state";
35
- import { collectionOfPath, entryCollection, entryCollections, seedEntry } from "./entry-model";
38
+ import { collectionOfPath, entryCollection } from "./entry-model";
39
+ import { entryBody } from "../create/add-new";
36
40
  import { collectionForDirectory } from "./collection-match";
37
41
  import { LOCALE_PLACEHOLDER } from "../canvas/asset-resolve";
38
- import { openEntryEditor, setEntryDraft } from "./entry-editor";
42
+ import { setEntryDraft } from "./entry-editor";
43
+ import { openEntry } from "./entry-open";
39
44
  import { errorMessage } from "@jxsuite/schema/parse";
40
45
  import type { EntryCollection } from "./entry-model";
41
46
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
42
47
  import type { Tab } from "../tabs/tab";
48
+ import type { JxMutableNode } from "@jxsuite/schema/types";
43
49
 
44
- /** Collection names a New Entry can be created in — the `enum` behind `content.newEntry`. */
45
- function creatableCollections(): string[] {
46
- return entryCollections().map((collection) => collection.name);
50
+ /**
51
+ * The format class that writes a collection's entries, or `null` for native JSON.
52
+ *
53
+ * `collectionInfo` derives `.json` exactly when no format class claimed the collection — the
54
+ * extension and the serializer name come off the same three lookups in the same order — so "the
55
+ * extension is .json" and "no format can write this" are one condition. Writing JSON into a `.md`
56
+ * file is therefore not a state a seed can reach.
57
+ */
58
+ export function entryFormatName(collection: Pick<EntryCollection, "def" | "ext">): string | null {
59
+ if (collection.ext === ".json") {
60
+ return null;
61
+ }
62
+ return (
63
+ (collection.def.format ? formatByName(collection.def.format)?.name : undefined) ??
64
+ formatForPath(`untitled${collection.ext}`)?.name ??
65
+ defaultContentFormat()?.name ??
66
+ null
67
+ );
47
68
  }
48
69
 
49
70
  /**
50
- * The source text a new entry starts as.
71
+ * The source text a new entry starts as: `create/add-new.ts`'s `entryBody`, serialized.
51
72
  *
52
73
  * A `json` collection is serialized here rather than through the format registry, because JSON is
53
74
  * the one native collection shape (site-architecture.md §6.2) and has no format class to ask.
54
- *
55
- * `collectionInfo` derives `.json` exactly when no format class claimed the collection — the
56
- * extension and the serializer name come off the same three lookups in the same order — so "the
57
- * extension is .json" and "no format can write this" are one condition, and the second is not a
58
- * separate failure to report. Writing JSON into a `.md` file is therefore not a state this can
59
- * reach.
60
75
  */
61
76
  async function seedText(collection: EntryCollection): Promise<string> {
62
- const seed = seedEntry(collection.schema);
63
- const formatName =
64
- (collection.def.format ? formatByName(collection.def.format)?.name : undefined) ??
65
- formatForPath(`untitled${collection.ext}`)?.name ??
66
- defaultContentFormat()?.name;
67
- if (collection.ext === ".json" || formatName === undefined) {
77
+ const body = entryBody({
78
+ ext: collection.ext,
79
+ formatName: entryFormatName(collection),
80
+ schema: collection.schema,
81
+ });
82
+ if (body.format === null) {
68
83
  // The save serializer with no layout (`@jxsuite/schema/json-layout`): a seed has no source text, and
69
84
  // This is what the formatter makes of one, newline included.
70
- return serializeJson(seed, null);
85
+ return serializeJson(body.doc, null);
71
86
  }
72
- return formatSerialize(
73
- formatName,
74
- { ...seed, children: [] },
75
- { frontmatter: Object.keys(seed).length > 0, mode: "roundtrip" },
76
- );
87
+ /* SAFETY: an entry body is `{ ...seed, children: [] }`, an element-shaped object, which is the
88
+ document a format's serializer reads. */
89
+ return formatSerialize(body.format, body.doc as JxMutableNode, {
90
+ frontmatter: body.frontmatter ?? false,
91
+ mode: "roundtrip",
92
+ });
77
93
  }
78
94
 
79
95
  /**
@@ -127,8 +143,8 @@ export async function createEntry(
127
143
  * Where the entry lands.
128
144
  *
129
145
  * A localized collection's `dir` is `content/exhibitions/{locale}` — a path nobody has. Creating
130
- * there makes a directory literally named `{locale}`, which is what `content.newEntry` from the
131
- * palette and the `new_content_entry` tool have been doing. There is no default locale to pick on
146
+ * there makes a directory literally named `{locale}`, which is what the palette's New Entry and
147
+ * the `new_content_entry` tool used to do. There is no default locale to pick on
132
148
  * the author's behalf (choosing one silently files the entry under a language), so this refuses
133
149
  * and names the gesture that works.
134
150
  */
@@ -162,7 +178,7 @@ export async function createEntry(
162
178
  }
163
179
  // The picker's choices just changed; a cached list would keep offering the old set.
164
180
  invalidateReferenceEntries(collection.name);
165
- await openEntryEditor(created);
181
+ await openEntry(created);
166
182
  return created;
167
183
  }
168
184
 
@@ -175,32 +191,6 @@ function activeEntryTab(): Tab | null {
175
191
  /** The content-entry command records. */
176
192
  export function contentCommands(): AnyCommand[] {
177
193
  return [
178
- {
179
- args: argsSchema({
180
- collection: derivedEnumProperty(
181
- creatableCollections,
182
- "The content collection the entry is created in.",
183
- ),
184
- }),
185
- category: "File",
186
- id: "content.newEntry",
187
- level: "project",
188
- menus: ["palette"],
189
- group: "1_file",
190
- requires: "a project with a directory-backed content collection",
191
- when: (ctx) => ctx.project.open,
192
- enablement: () => creatableCollections().length > 0,
193
- undo: "project",
194
- /* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `createEntry` awaits
195
- `createFileIn`, which awaits the New File prompt for the name; a cancel resolves with
196
- nothing thrown. An optional `name` argument that skips the prompt is the way back in, and
197
- is a UX call (issue 273). */
198
- run: async (_ctx, args) => {
199
- const names = creatableCollections();
200
- await createEntry(enumArg("content.newEntry", args, "collection", names));
201
- },
202
- title: "New Entry",
203
- },
204
194
  {
205
195
  args: argsSchema({
206
196
  path: stringProperty("Project-relative path of the entry file to open."),
@@ -213,11 +203,12 @@ export function contentCommands(): AnyCommand[] {
213
203
  requires: "an open project",
214
204
  when: (ctx) => ctx.project.open,
215
205
  /* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface;
216
- the model has `open_document`. */
206
+ the model has `open_document`. An entry with a body opens on the canvas in its writing
207
+ editor, inside its template's layout; a JSON entry opens in the form (§22.5). */
217
208
  run: async (_ctx, args) => {
218
- await openEntryEditor(stringArg("content.openEntry", args, "path"));
209
+ await openEntry(stringArg("content.openEntry", args, "path"));
219
210
  },
220
- title: "Open Entry Form",
211
+ title: "Open Entry",
221
212
  },
222
213
  {
223
214
  args: argsSchema({
@@ -3,11 +3,11 @@
3
3
  * The **Entry editor** (site-architecture.md §7.4): a content entry's fields, as a form, in a pane.
4
4
  *
5
5
  * Until now a markdown entry could be edited two ways and neither was its schema: the canvas edited
6
- * its BODY, and the Document Header card drew a field list from `panels/frontmatter-fields.ts`'s
7
- * own type→widget ladder, which is a second implementation of `ui/schema-form.ts` with no reference
8
- * branch, no validation and no value-source ladder. A JSON entry (`authors/ada.json`) had no field
9
- * editor at all — it opened as a component tree, so `bio` was a node's property and `links` was a
10
- * child array.
6
+ * its BODY, and the Document Header card (since removed) drew a field list from
7
+ * `panels/frontmatter-fields.ts`'s own type→widget ladder, which is a second implementation of
8
+ * `ui/schema-form.ts` with no reference branch, no validation and no value-source ladder. A JSON
9
+ * entry (`authors/ada.json`) had no field editor at all — it opened as a component tree, so `bio`
10
+ * was a node's property and `links` was a child array.
11
11
  *
12
12
  * This is one editor over the schema form, so every improvement to the engine reaches content
13
13
  * entries, settings and the inspector at once — and the `reference` control in particular arrives
@@ -25,7 +25,7 @@
25
25
  * it unshifts its mode onto the tab the file already has, so ⌘S, the dirty flag, the transaction
26
26
  * log and undo are the ordinary document verbs. Every field commits through
27
27
  * {@link mutateEntryField}, so an edit made here is undone by ⌘Z and replayed by a collaborator
28
- * exactly as one made in the Document Header card.
28
+ * exactly as one made in the Inspector's Page tab.
29
29
  *
30
30
  * **One editor, two storage shapes.** A markdown entry keeps its fields in frontmatter; a JSON
31
31
  * entry IS its fields. `content/entry-fields.ts` owns that single question, and this file never
@@ -52,16 +52,21 @@ import { activateTab, workspace } from "../workspace/workspace";
52
52
  import { commitEntryFields, entryFields, mutateEntryField } from "./entry-fields";
53
53
  import type { EntryFields } from "./entry-fields";
54
54
  import { DRAFT_FIELD, DRAFT_MEANING, hasDraftAxis, isDraftEntry } from "./draft-state";
55
- import { collectionOfPath, missingRequired } from "./entry-model";
55
+ import { collectionOfPath, missingRequired, recordCollectionOfPath } from "./entry-model";
56
+ import { ENTRY_MODE, isRecordTab, recordPlace, showRecord } from "./record-entry";
57
+ import { requestGridReveal } from "../grid/grid-reveal";
58
+ import { titleFieldOf } from "./entry-summaries";
56
59
  import type { EntryCollection } from "./entry-model";
57
60
  import type { EntryEditorSurfaceHandle, EntryEditorView } from "../surfaces/entry-editor";
58
61
  import type { JsonSchema, SchemaFormContext } from "../ui/schema-form";
59
62
  import type { Tab } from "../tabs/tab";
60
63
  import type { CanvasSurface } from "../canvas/canvas-surface";
61
- import type { JsonObject } from "@jxsuite/schema/types";
64
+ import type { ContentTypeSchema, JsonObject } from "@jxsuite/schema/types";
65
+ import { isString } from "@jxsuite/schema/guards";
66
+ import { fieldTitle } from "../browse/library-source";
62
67
 
63
- /** The `canvasMode` the entry form draws under. */
64
- export const ENTRY_MODE = "entry";
68
+ /** The `canvasMode` the entry form draws under (defined with the record a form may be over). */
69
+ export { ENTRY_MODE } from "./record-entry";
65
70
 
66
71
  /** What an entry tab's mode list becomes when the Entry editor opens it: the form leads. */
67
72
  const ENTRY_TAB_MODES = [ENTRY_MODE];
@@ -149,7 +154,7 @@ export interface DraftPill {
149
154
  * chip's `status` slot, and `.entry-pill`'s rules in `styles/overlays.css` are dead with it.
150
155
  */
151
156
  export function entryDraftPill(tab: Tab): DraftPill | null {
152
- const collection = collectionOfPath(tab.documentPath);
157
+ const collection = entryCollectionOf(tab);
153
158
  const fields = entryFields(tab);
154
159
  if (!collection || !hasDraftAxis(collection.schema, fields)) {
155
160
  return null;
@@ -164,8 +169,24 @@ export function entryDraftPill(tab: Tab): DraftPill | null {
164
169
 
165
170
  // ─── The form ────────────────────────────────────────────────────────────────
166
171
 
172
+ /**
173
+ * The words each field's row is titled with: the schema's own `title` where it states one, else the
174
+ * key in words (`publishedAt` → "Published at"), the spelling the Content home's columns use. A raw
175
+ * key is a storage name, and an author reads "Cover", not `cover`.
176
+ */
177
+ export function fieldLabels(
178
+ schema: ContentTypeSchema | null | undefined,
179
+ ): Record<string, { label: string }> {
180
+ return Object.fromEntries(
181
+ Object.entries(schema?.properties ?? {}).map(([name, field]) => [
182
+ name,
183
+ { label: isString(field.title) && field.title !== "" ? field.title : fieldTitle(name) },
184
+ ]),
185
+ );
186
+ }
187
+
167
188
  /** The form's host context: enum pointers resolve against this project's configuration. */
168
- function formContext(tab: Tab): SchemaFormContext {
189
+ export function formContext(tab: Tab): SchemaFormContext {
169
190
  return {
170
191
  fieldKeyPrefix: `entry:${tab.id}`,
171
192
  resolvePointer: (pointer, scope) =>
@@ -184,7 +205,7 @@ function formContext(tab: Tab): SchemaFormContext {
184
205
  * missing from the file is a fact about the document, and saying so is the whole reason the form
185
206
  * knows the schema.
186
207
  */
187
- function absentRequiredErrors(
208
+ export function absentRequiredErrors(
188
209
  collection: EntryCollection,
189
210
  fields: EntryFields,
190
211
  ): Record<string, string> {
@@ -196,6 +217,32 @@ function absentRequiredErrors(
196
217
  );
197
218
  }
198
219
 
220
+ /** The collection an entry tab's form is typed by: its file's, or for a record its file's records'. */
221
+ function entryCollectionOf(tab: Tab): EntryCollection | null {
222
+ return isRecordTab(tab)
223
+ ? recordCollectionOfPath(tab.documentPath)
224
+ : collectionOfPath(tab.documentPath);
225
+ }
226
+
227
+ /**
228
+ * The schema with the entry's title field moved to the top: what an entry is called is the first
229
+ * thing an author looks for, and a schema imported from a CMS lists its properties alphabetically,
230
+ * which put `title` after forty other fields.
231
+ */
232
+ export function titleFirst(
233
+ form: JsonSchema,
234
+ schema: ContentTypeSchema | null,
235
+ fields: EntryFields,
236
+ ): JsonSchema {
237
+ const title = titleFieldOf(schema, fields);
238
+ const properties = form.properties ?? {};
239
+ const held = title === null ? undefined : properties[title];
240
+ if (title === null || held === undefined) {
241
+ return form;
242
+ }
243
+ return { ...form, properties: { [title]: held, ...properties } };
244
+ }
245
+
199
246
  /** What the document says when the file belongs to no collection: the reason, then the fix. */
200
247
  function emptyLine(tab: Tab): string {
201
248
  return `${tab.documentPath ?? "This document"} is not an entry of any content collection, so there is no schema to draw a form from.`;
@@ -214,14 +261,20 @@ function entryView(paneId: string, tab: Tab, collection: EntryCollection | null)
214
261
  emptyLine: emptyLine(tab),
215
262
  fieldsRegion,
216
263
  name: "",
264
+ nextDisabled: true,
217
265
  note: "",
218
266
  noteState: "hidden",
267
+ place: "",
268
+ previousDisabled: true,
269
+ recordNav: "hidden",
219
270
  region,
220
271
  stage: "empty",
221
272
  };
222
273
  }
223
274
  const fields = entryFields(tab);
224
275
  const draft = isDraftEntry(fields);
276
+ const record = isRecordTab(tab);
277
+ const place = recordPlace(tab);
225
278
  return {
226
279
  collection: collection.name,
227
280
  draft,
@@ -229,14 +282,31 @@ function entryView(paneId: string, tab: Tab, collection: EntryCollection | null)
229
282
  draftHint: DRAFT_MEANING,
230
283
  emptyLine: "",
231
284
  fieldsRegion,
232
- name: tab.documentPath?.split("/").pop() ?? "Untitled",
285
+ // A record is called what the Content home calls it: its title field, else its row.
286
+ name: record
287
+ ? recordName(collection, fields, place.index)
288
+ : (tab.documentPath?.split("/").pop() ?? "Untitled"),
289
+ nextDisabled: place.next === null,
233
290
  note: DRAFT_MEANING,
234
291
  noteState: draft ? "shown" : "hidden",
292
+ place: place.index === -1 ? "" : `${place.index + 1} of ${place.total}`,
293
+ previousDisabled: place.previous === null,
294
+ recordNav: record ? "shown" : "hidden",
235
295
  region,
236
296
  stage: "entry",
237
297
  };
238
298
  }
239
299
 
300
+ /** A record's heading: its title field's text, else its first text, else "Row n". */
301
+ function recordName(collection: EntryCollection, fields: EntryFields, index: number): string {
302
+ const field = titleFieldOf(collection.schema, fields);
303
+ const named = field === null ? undefined : fields[field];
304
+ if (isString(named) && named.trim() !== "") {
305
+ return named.trim();
306
+ }
307
+ return index === -1 ? "Record" : `Row ${index + 1}`;
308
+ }
309
+
240
310
  /**
241
311
  * Mount the entry form into the pane.
242
312
  *
@@ -289,13 +359,14 @@ export function renderEntryMode(surface: CanvasSurface, tab: Tab): void {
289
359
  JSON text, so every value is JSON; a key an editor cleared reads as absent either way. */
290
360
  const form = mountSchemaForm(
291
361
  `entry:${paneId}`,
292
- collection.schema as JsonSchema,
362
+ titleFirst(collection.schema as JsonSchema, collection.schema, fields),
293
363
  fields as JsonObject,
294
364
  {
295
365
  context: formContext(tab),
296
366
  errors: absentRequiredErrors(collection, fields),
297
367
  onChange: (patch) => commitEntryFields(tab, patch),
298
368
  rerender: redraw,
369
+ ui: fieldLabels(collection.schema),
299
370
  },
300
371
  );
301
372
  if (form.parentNode !== formHost) {
@@ -304,7 +375,7 @@ export function renderEntryMode(surface: CanvasSurface, tab: Tab): void {
304
375
  };
305
376
 
306
377
  const draw = () => {
307
- const collection = collectionOfPath(tab.documentPath);
378
+ const collection = entryCollectionOf(tab);
308
379
  if (!collection) {
309
380
  /* The `fields` node goes with the case that held it, so the handle is dropped here rather
310
381
  than left pointing at a node the reconciler is about to remove. */
@@ -317,17 +388,37 @@ export function renderEntryMode(surface: CanvasSurface, tab: Tab): void {
317
388
  const scope = effectScope();
318
389
  const mounted = mountEntryEditorSurface(
319
390
  canvasWrap,
320
- entryView(paneId, tab, collectionOfPath(tab.documentPath)),
391
+ entryView(paneId, tab, entryCollectionOf(tab)),
321
392
  {
322
393
  openContentTypes: () => {
323
394
  void activeRegistry()?.run("settings.open", { section: "content" });
324
395
  },
396
+ openGrid: () => {
397
+ // The grid lands on the row this form was showing (`grid/grid-reveal.ts`).
398
+ const { index } = recordPlace(tab);
399
+ if (index !== -1 && tab.documentPath) {
400
+ requestGridReveal(tab.documentPath, index);
401
+ }
402
+ tab.session.ui.canvasMode = "grid";
403
+ },
325
404
  setDraft: (draft) => setEntryDraft(tab, draft),
405
+ showNext: () => {
406
+ const { next } = recordPlace(tab);
407
+ if (next !== null) {
408
+ showRecord(tab, next);
409
+ }
410
+ },
411
+ showPrevious: () => {
412
+ const { previous } = recordPlace(tab);
413
+ if (previous !== null) {
414
+ showRecord(tab, previous);
415
+ }
416
+ },
326
417
  },
327
418
  {
328
419
  fieldsSlot: (host) => {
329
420
  formHost = host;
330
- paintForm(collectionOfPath(tab.documentPath));
421
+ paintForm(entryCollectionOf(tab));
331
422
  },
332
423
  },
333
424
  );
@@ -346,6 +437,8 @@ export function renderEntryMode(surface: CanvasSurface, tab: Tab): void {
346
437
  void tab.doc.document;
347
438
  void tab.doc.content.frontmatter;
348
439
  void projectState?.projectConfig?.content;
440
+ // A record's fields are its grid's rows and pending cells, read through `entryFields`, which
441
+ // Tracks them. Which record is shown is tracked by `recordOf` the same way.
349
442
  draw();
350
443
  });
351
444
  });
@@ -32,6 +32,7 @@ import { cloneValue } from "@jxsuite/schema/doc-ops";
32
32
  import { notePreviewOverlayEdit } from "../preview/preview-overlay";
33
33
  import { recordDocOp } from "../tabs/patch-ops";
34
34
  import { mutateUpdateFrontmatter, transactDoc } from "../tabs/transact";
35
+ import { commitRecordFields, isRecordTab, recordFields } from "./record-entry";
35
36
  import type { JxDocumentValue } from "@jxsuite/schema/types";
36
37
  import type { Tab } from "../tabs/tab";
37
38
  import type { JsonValue } from "../types";
@@ -64,6 +65,10 @@ function fieldsAreDocument(tab: Tab): boolean {
64
65
  * `tab.doc.document` to see which store answered.
65
66
  */
66
67
  export function entryFields(tab: Tab): EntryFields {
68
+ // A record of a file-backed collection keeps its fields in a row of its file's grid.
69
+ if (isRecordTab(tab)) {
70
+ return recordFields(tab);
71
+ }
67
72
  return fieldsAreDocument(tab) ? tab.doc.document : tab.doc.content.frontmatter;
68
73
  }
69
74
 
@@ -105,7 +110,9 @@ function mutateDocumentField(tab: Tab, field: string, value?: JsonValue): void {
105
110
  * step.
106
111
  */
107
112
  export function mutateEntryField(tab: Tab, field: string, value?: JsonValue): void {
108
- if (fieldsAreDocument(tab)) {
113
+ if (isRecordTab(tab)) {
114
+ commitRecordFields(tab, { [field]: value });
115
+ } else if (fieldsAreDocument(tab)) {
109
116
  mutateDocumentField(tab, field, value);
110
117
  } else {
111
118
  mutateUpdateFrontmatter(tab, field, value);
@@ -119,6 +126,11 @@ export function mutateEntryField(tab: Tab, field: string, value?: JsonValue): vo
119
126
  * on the undo stack as several steps — and an author who changed one thing expects one ⌘Z.
120
127
  */
121
128
  export function commitEntryFields(tab: Tab, patch: Record<string, JsonValue | undefined>): void {
129
+ // A record's edit is the grid buffer's, whose own undo group is the one ⌘Z reverts.
130
+ if (isRecordTab(tab)) {
131
+ commitRecordFields(tab, patch);
132
+ return;
133
+ }
122
134
  transactDoc(tab, (t) => {
123
135
  for (const [field, value] of Object.entries(patch)) {
124
136
  mutateEntryField(t, field, value);