@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,711 +0,0 @@
1
- /// <reference lib="dom" />
2
- /**
3
- * The Document Header card — the artefact's own header, drawn IN the stage.
4
- *
5
- * It replaces the old "Properties" bar, which was a fourth full-width band that **appeared and
6
- * vanished as a side effect of the canvas mode** with no control to summon it, and which showed
7
- * nothing at all unless `findContentTypeSchema` matched the document to a content collection — so
8
- * it never appeared on the default home page, the one document every new author opens first.
9
- *
10
- * Two gates are gone, and each was a lie about what the card is for:
11
- *
12
- * - The **collection gate** (`if (!fieldSet?.collection)`) — a page's `title` is frontmatter whether
13
- * or not a collection schema describes it;
14
- * - The **document-mode gate** (`doc.mode === "content"`) — a JSON page carries `title` and `$head`
15
- * directly on the root node, and it has a header for exactly the same reason.
16
- *
17
- * What it renders instead: **any** document with frontmatter or `$head`, in every named layout —
18
- * Title, Route, the layout picker, the schema-and-frontmatter field list, the door to Search
19
- * appearance and a "Raw head tags" disclosure. `hasDocumentHeader` is this module's whole
20
- * predicate, and it is a fact about the DOCUMENT.
21
- *
22
- * **The canvas mode is the STAGE's question, and this module still takes none.** The stage draws a
23
- * host for the card in Edit only (`wantsDocHeader` in `canvas/canvas-render.ts`): Design gives its
24
- * artboards the whole pane, and the Navigator's Page panel carries the same fields in every mode,
25
- * so nothing is out of reach in either. The old mode gate lived HERE, as a `getCanvasMode()` check
26
- * the card ran to decide whether to exist; the decision now has one owner, the frame that draws the
27
- * page, and this module draws into whatever host it is handed.
28
- *
29
- * **One reserved-key policy, one `collectFmFields` call.** The two field sets this card merges used
30
- * to disagree: this module passed an empty reserved set and `head-panel.ts` passed `{title}`, so
31
- * `title` could render twice with two different commit paths. `RESERVED_FM_KEYS` wins and is
32
- * imported, not restated — see the note on its declaration.
33
- *
34
- * **The card has no host of its own.** `#frontmatter-panel` — the grid row, the `hidden` div, the
35
- * `frontmatterPanelEl` ref and the 40vh cap that came with them — is deleted. The STAGE renders the
36
- * host now ({@link attachDocumentHeaderHost}, called from the stage document's `onNodeCreated` in
37
- * `canvas/canvas-render.ts`), so the card is docked above the page, as wide as the pane, rather
38
- * than in a band the shell drew above every stage.
39
- *
40
- * **The card is a Jx document now** (`src/surfaces/doc-header.json`), and this module is the flow
41
- * behind it: it decides which document a pane's card is drawn for, which rows that document has,
42
- * what each row commits into and where a media or reference row gets its choices, then hands the
43
- * surface a projection whose every field is already a string. Three things follow.
44
- *
45
- * **The focus-aware scheduler is gone, and nothing replaced it.** `panels/panel-scheduler.ts`
46
- * existed to withhold a repaint while a text input in the card had focus, because a lit re-render
47
- * rebuilt every control and truncated whatever was being typed into one. A document binds each
48
- * value on its own runtime effect and skips a write equal to what the control already holds
49
- * (specs/studio-ui-guidelines.md §9.3), so a projection that changed one field repaints one field
50
- * and a projection that changed nothing repaints nothing. There is no window left to withhold.
51
- *
52
- * **ONE row vocabulary.** Title, the Layout picker and every schema-driven frontmatter field are
53
- * the same row, told apart by which control they draw; what makes them different is what they
54
- * WRITE, and that is this module's business rather than the document's. {@link RowCommit} is that
55
- * table, rebuilt with each projection and reached by the row's `key` — which is why a row's key and
56
- * its `data-prop` are two different strings: a collection whose schema declares a `layout` property
57
- * would otherwise collide with the Layout picker.
58
- *
59
- * **Two widgets are borrowed as BEHAVIOUR rather than as markup.** The media browser
60
- * (`ui/media-picker.ts`) renders into the popover layer rather than into the field, and the entry
61
- * ids behind a `#/content/<type>` reference are a read (`ui/form-controls.ts`), so the card draws
62
- * its own control for each and calls the owner for the part that is not markup. Neither module's
63
- * lit template is interpolated here — a document and a lit template cannot share a container, and
64
- * studio-ui-guidelines.md §9.4 forbids the mix outright.
65
- *
66
- * @docs studio/editing/frontmatter
67
- */
68
-
69
- import { isString } from "@jxsuite/schema/guards";
70
- import { projectState } from "../store";
71
- import { workspace } from "../workspace/workspace";
72
- import { tabOfPane } from "../canvas/canvas-surface";
73
- import { paneRegion } from "../ui/regions";
74
- import { effect, effectScope } from "../reactivity";
75
- import { collectFmFields, projectFmField } from "./frontmatter-fields";
76
- import { LIVE_PREVIEW } from "../ui/timing";
77
- import { mutateUpdateFrontmatter, transact, transactDoc } from "../tabs/transact";
78
- import { pageRoute } from "./tab-strip";
79
- import {
80
- RESERVED_FM_KEYS,
81
- applyContentMutation,
82
- buildHeadDoc,
83
- entryLabel,
84
- entryValue,
85
- isPageDocument,
86
- isManagedEntry,
87
- layoutPickerEntries,
88
- } from "./head-panel";
89
- import { isGoogleFontEntry, isGoogleFontPreconnect } from "../utils/google-fonts";
90
- import { activeRegistry } from "../commands/active-registry";
91
- import { invalidateLayoutCache } from "../site-context";
92
- import { mountDocHeaderSurface } from "../surfaces/doc-header";
93
-
94
- import type { JsonValue, JxHeadEntry, JxMutableNode } from "@jxsuite/schema/types";
95
- import type { Tab } from "../tabs/tab";
96
- import type { FmSchemaEntry } from "./frontmatter-fields";
97
- import type * as MediaPickerModule from "../ui/media-picker";
98
- import type {
99
- DocHeaderActions,
100
- DocHeaderRawEntry,
101
- DocHeaderRow,
102
- DocHeaderSurface,
103
- DocHeaderView,
104
- } from "../surfaces/doc-header";
105
- import type { SurfaceOption } from "../ui/surface";
106
-
107
- /** What one row of the card writes. The document knows the control; this knows the document. */
108
- interface RowCommit {
109
- /** Remove the value this row shows. */
110
- clear: () => void;
111
- /** Commit what the control settled on — a string from every kind but the checkbox. */
112
- commit: (raw: string | boolean) => void;
113
- }
114
-
115
- /**
116
- * One pane's card: the node the stage gave it, the mounted surface, its commit table and the
117
- * actions the surface was handed.
118
- *
119
- * A single `_host` was the same singleton every other stage-content module had, and it produced a
120
- * subtler failure than most: the stage hands the host over from a lit `ref`, so with two stages
121
- * drawing a header the second `ref` to fire silently took the card away from the first, leaving one
122
- * pane's Document Header frozen on the frontmatter of the moment it lost the handle.
123
- */
124
- interface HeaderCard extends HeaderCardState {
125
- /** Handed to the surface once, when it is mounted; every one of them reads `commits`. */
126
- actions: DocHeaderActions;
127
- }
128
-
129
- /** Everything a card holds except its actions, which are built over this and read it lazily. */
130
- interface HeaderCardState {
131
- /** The pane this card is drawn for. Held rather than looked up: an action has to answer it. */
132
- paneId: string;
133
- el: HTMLElement;
134
- /** `null` until the pane's document first has a header to draw. */
135
- surface: DocHeaderSurface | null;
136
- /** This pane's rows, by key. Rebuilt with each projection. */
137
- commits: Map<string, RowCommit>;
138
- /** Text edits waiting out {@link LIVE_PREVIEW}, one per row key. */
139
- pending: Map<string, { commit: () => void; timer: ReturnType<typeof setTimeout> }>;
140
- }
141
-
142
- const _hosts = new Map<string, HeaderCard>();
143
- let _scope: { stop: () => void; run: <T>(fn: () => T) => T | undefined } | null = null;
144
-
145
- /** Per-document disclosure state, keyed by tab id — not stored on the document. */
146
- const _rawOpen = new Set<string>();
147
-
148
- /**
149
- * Whether each document's card is open, keyed by tab id, and fixed when the card is first drawn for
150
- * that document.
151
- *
152
- * The card is a band across the top of the pane, and on a short pane it can take half the page, so
153
- * the reader can fold it down to its bar. What they did LAST is the default for the next editor
154
- * they open ({@link DOC_HEADER_EXPANDED_KEY}), but it is not a broadcast: an editor already open
155
- * keeps the state it was drawn in, because a card that folded away under a document the reader was
156
- * not looking at would be a change nobody asked for.
157
- */
158
- const _expanded = new Map<string, boolean>();
159
-
160
- /** The reader's last open-or-close of any card. Absent means open — the card's first-run state. */
161
- export const DOC_HEADER_EXPANDED_KEY = "jx-studio-doc-header-expanded";
162
-
163
- /** The persisted default, tolerating absent, corrupt and unavailable storage. */
164
- function readExpandedDefault(): boolean {
165
- try {
166
- return localStorage.getItem(DOC_HEADER_EXPANDED_KEY) !== "false";
167
- } catch {
168
- return true;
169
- }
170
- }
171
-
172
- /** Whether `tabId`'s card is open, seeding it from the persisted default the first time it is asked. */
173
- function isExpanded(tabId: string): boolean {
174
- let open = _expanded.get(tabId);
175
- if (open === undefined) {
176
- open = readExpandedDefault();
177
- _expanded.set(tabId, open);
178
- }
179
- return open;
180
- }
181
-
182
- /**
183
- * The element the stage has made available for the card, or `null` while no stage hosts it.
184
- *
185
- * Called from a lit `ref` in `canvas/canvas-render.ts`, so the host's lifetime is the stage's: the
186
- * canvas creates it when it draws a document that has a header and drops it otherwise.
187
- *
188
- * @param {HTMLElement | null} el
189
- */
190
- export function attachDocumentHeaderHost(paneId: string, el: HTMLElement | null): void {
191
- const held = _hosts.get(paneId);
192
- if (held?.el === el) {
193
- return;
194
- }
195
- if (held) {
196
- takeDown(held);
197
- _hosts.delete(paneId);
198
- }
199
- if (!el) {
200
- return;
201
- }
202
- const state: HeaderCardState = {
203
- commits: new Map(),
204
- el,
205
- paneId,
206
- pending: new Map(),
207
- surface: null,
208
- };
209
- /* The same object, not a copy: the actions read `state.commits`, which a projection reassigns.
210
- `settle` runs only on a reader's toggle, long after `card` is bound. */
211
- const card: HeaderCard = Object.assign(state, {
212
- actions: makeActions(state, () => {
213
- settle(card);
214
- }),
215
- });
216
- _hosts.set(paneId, card);
217
- paint(paneId, card);
218
- }
219
-
220
- /* There is no `documentHeaderHost` getter any more, and its absence is the point.
221
- It existed for ONE caller: the stage's lit `ref`, which was told about a removal WITHOUT being
222
- told which node had gone, so it had to read the host back and ask whether it was still connected
223
- before deciding the report was about the host it held. `surfaces/canvas-stage.json` states the
224
- card's slot as a view, so a frame that draws no card simply announces none and `renderCanvasImpl`
225
- releases the slot in one place — there is nothing left to settle after the fact, and a getter
226
- whose only reader is gone is a fact about the module nobody is entitled to. */
227
-
228
- /**
229
- * Mount the Document Header card: subscribe to the tab / document / frontmatter reads it renders
230
- * from, so a change repaints the card without repainting the canvas around it.
231
- *
232
- * The card takes no context. It used to take `getCanvasMode()` purely to decide whether to exist,
233
- * and that predicate is the thing this change deletes.
234
- */
235
- export function mount() {
236
- _scope = effectScope();
237
- _scope.run(() => {
238
- effect(() => {
239
- // Every pane's tab, not the focused one's: two stages can each be drawing a header, and a
240
- // Card that only tracked `activeTab` stopped repainting the moment focus moved away from it.
241
- for (const tab of paneTabs()) {
242
- // Track everything the card reads: the document root (title / `$head` / `$layout` live
243
- // There for a JSON page) plus the frontmatter object AND its entries — field commits mutate
244
- // Keys in place while the source-mode round-trip swaps the whole object, and both must
245
- // Re-fire this effect.
246
- void tab.doc.mode;
247
- void tab.documentPath;
248
- void tab.doc.document;
249
- void tab.doc.document.title;
250
- void tab.doc.document.$head;
251
- void tab.doc.document.$layout;
252
- const fm = tab.doc.content.frontmatter;
253
- for (const key of Object.keys(fm)) {
254
- void fm[key];
255
- }
256
- }
257
- render();
258
- });
259
- });
260
- }
261
-
262
- export function unmount() {
263
- _scope?.stop();
264
- _scope = null;
265
- for (const card of _hosts.values()) {
266
- takeDown(card);
267
- }
268
- _hosts.clear();
269
- _rawOpen.clear();
270
- _expanded.clear();
271
- }
272
-
273
- /** Take one pane's card down: cancel its waiting edits and dispose the document it mounted. */
274
- function takeDown(card: HeaderCard): void {
275
- for (const { timer } of card.pending.values()) {
276
- clearTimeout(timer);
277
- }
278
- card.pending.clear();
279
- card.surface?.dispose();
280
- card.surface = null;
281
- card.commits.clear();
282
- }
283
-
284
- /** Each pane's tab, deduplicated — the set of documents a header could be drawn for. */
285
- function paneTabs(): Tab[] {
286
- const tabs: Tab[] = [];
287
- for (const pane of workspace.panes) {
288
- const tab = tabOfPane(pane.id);
289
- if (tab && !tabs.includes(tab)) {
290
- tabs.push(tab);
291
- }
292
- }
293
- return tabs;
294
- }
295
-
296
- /**
297
- * Repaint every card.
298
- *
299
- * Coalescing is the runtime's now: a projection assigns to a standing scope and each binding
300
- * re-runs only where the value it reads has changed, so calling this twice in one tick costs one
301
- * comparison per binding rather than two renders.
302
- */
303
- export function render() {
304
- for (const [paneId, card] of _hosts) {
305
- paint(paneId, card);
306
- }
307
- }
308
-
309
- /**
310
- * Whether a document has a header to show.
311
- *
312
- * The one remaining gate, and it is a fact about the document rather than about the view: a
313
- * component definition with no frontmatter, no title and no `$head` has no header, and printing an
314
- * empty card over its canvas would be chrome pretending to be content.
315
- *
316
- * @param {Tab} tab
317
- * @returns {boolean}
318
- */
319
- export function hasDocumentHeader(tab: Tab): boolean {
320
- const fm = tab.doc.content.frontmatter;
321
- const doc = tab.doc.document;
322
- if (Object.keys(fm).length > 0) {
323
- return true;
324
- }
325
- // `title` is typed a string, but a document read off disk may carry any JSON there.
326
- if (isString(doc.title) || (doc.$head?.length ?? 0) > 0) {
327
- return true;
328
- }
329
- // A page always has one, even an empty one: Title and Route are the two facts it must state.
330
- // THIS tab's page-ness. `isPageDocument()` was zero-argument and answered about the focused
331
- // Pane's document, so a predicate whose every other line reads `tab` finished by asking about a
332
- // Different one: a page in the side pane lost its header whenever a component was focused, and a
333
- // Bare component in the side pane grew one whenever a page was.
334
- return isPageDocument(tab);
335
- }
336
-
337
- /**
338
- * Draw (or take down) one pane's card.
339
- *
340
- * The surface is only ever mounted ONCE per host and assigned to afterwards. Rebuilding it on a
341
- * repaint would take a field out from under a reader mid-edit, which is the failure the scheduler
342
- * this conversion deletes was built to prevent; `connected()` answers the one case assignment
343
- * cannot, a stage that redrew and took the card's root away.
344
- */
345
- function paint(paneId: string, card: HeaderCard): void {
346
- const tab = tabOfPane(paneId);
347
- if (!tab || !hasDocumentHeader(tab)) {
348
- /* The stage decides whether the host exists; this only covers the window between a document
349
- losing its header and the canvas noticing. */
350
- takeDown(card);
351
- card.el.replaceChildren();
352
- card.el.hidden = true;
353
- return;
354
- }
355
- const view = viewFor(tab, paneId, card);
356
- card.el.hidden = false;
357
- if (card.surface?.connected()) {
358
- card.surface.update(view);
359
- return;
360
- }
361
- card.surface?.dispose();
362
- card.surface = mountDocHeaderSurface(card.el, view, card.actions);
363
- }
364
-
365
- // ─── The projection ──────────────────────────────────────────────────────────
366
-
367
- /**
368
- * Everything the card says about one document, and the commit table behind it.
369
- *
370
- * `tab`, not `activeTab` — the card is drawn for the pane that mounted it. Both branches of the
371
- * commit path resolved through FOCUS once, so with two panes the visible card's controls edited
372
- * whichever document happened to be focused: click "Clear title" on the card in the left pane and
373
- * the field disappeared from the right pane's document instead.
374
- *
375
- * @param {Tab} tab
376
- * @returns {DocHeaderView}
377
- */
378
- function viewFor(tab: Tab, paneId: string, card: HeaderCard): DocHeaderView {
379
- const isContent = tab.doc.mode === "content";
380
- const fm = tab.doc.content.frontmatter;
381
- // ONE view of the document's head material, whichever realm it lives in: frontmatter keys for a
382
- // Markdown page, root properties for a JSON one.
383
- const headDoc = isContent ? buildHeadDoc(tab.doc.document, fm) : tab.doc.document;
384
- const applyMutation = isContent
385
- ? (fn: (doc: JxMutableNode) => void) => applyContentMutation(tab, render, fn)
386
- : (fn: (doc: JxMutableNode) => void) => {
387
- transact(tab, fn);
388
- };
389
-
390
- const commits = new Map<string, RowCommit>();
391
- const rows: DocHeaderRow[] = [titleRow(headDoc, applyMutation, commits)];
392
- const layout = layoutRow(tab, headDoc, applyMutation, commits);
393
- if (layout) {
394
- rows.push(layout);
395
- }
396
-
397
- // ONE call. The old pair of surfaces made two, with two different reserved-key policies.
398
- const { collection, fields, requiredFields } = collectFmFields(
399
- tab,
400
- projectState?.projectConfig,
401
- RESERVED_FM_KEYS,
402
- );
403
- for (const f of fields) {
404
- rows.push(fieldRow(tab, f.field, f.entry, f.value, requiredFields, commits));
405
- }
406
- card.commits = commits;
407
-
408
- const route = tab.documentPath ? pageRoute(tab.documentPath) : null;
409
- const raw = rawEntries(headDoc.$head ?? []);
410
- return {
411
- collection: collection ? collection.name : "Document",
412
- expanded: isExpanded(tab.id),
413
- hasRoute: route !== null,
414
- rawEntries: raw,
415
- rawOpen: _rawOpen.has(tab.id),
416
- rawState: raw.length === 0 ? "empty" : "list",
417
- region: paneRegion(paneId, "frontmatter"),
418
- route: route ?? "",
419
- rows,
420
- };
421
- }
422
-
423
- /** A blank row, so every kind carries every field the document's bindings read. */
424
- function blankRow(key: string, prop: string, label: string): DocHeaderRow {
425
- return {
426
- checked: false,
427
- clearLabel: `Clear ${prop}`,
428
- hasNote: false,
429
- hasThumb: false,
430
- isSet: false,
431
- key,
432
- kind: "text",
433
- label,
434
- note: "",
435
- options: [],
436
- placeholder: "",
437
- prop,
438
- thumb: "",
439
- value: "",
440
- };
441
- }
442
-
443
- /** The one head value you type while writing, in both realms. */
444
- function titleRow(
445
- headDoc: JxMutableNode,
446
- applyMutation: (fn: (doc: JxMutableNode) => void) => void,
447
- commits: Map<string, RowCommit>,
448
- ): DocHeaderRow {
449
- const title = isString(headDoc.title) ? headDoc.title : "";
450
- commits.set("title", {
451
- clear: () =>
452
- applyMutation((d) => {
453
- delete d.title;
454
- }),
455
- commit: (raw) =>
456
- applyMutation((d) => {
457
- const val = String(raw).trim();
458
- if (val) {
459
- d.title = val;
460
- } else {
461
- delete d.title;
462
- }
463
- }),
464
- });
465
- return {
466
- ...blankRow("title", "title", "Title"),
467
- clearLabel: "Clear title",
468
- isSet: Boolean(title),
469
- placeholder: "Untitled",
470
- value: title,
471
- };
472
- }
473
-
474
- /**
475
- * The layout picker, or `null` when this document takes none — a component has no layout, and a
476
- * page whose layouts directory is still being listed has nothing to offer yet.
477
- *
478
- * The listing is `head-panel.ts`'s, asked for as data: the Page panel draws the same choices from
479
- * the same cache, so creating a layout invalidates one thing rather than two.
480
- */
481
- function layoutRow(
482
- tab: Tab,
483
- headDoc: JxMutableNode,
484
- applyMutation: (fn: (doc: JxMutableNode) => void) => void,
485
- commits: Map<string, RowCommit>,
486
- ): DocHeaderRow | null {
487
- if (!isPageDocument(tab)) {
488
- return null;
489
- }
490
- const entries = layoutPickerEntries();
491
- if (entries === null) {
492
- return null;
493
- }
494
- const current = headDoc.$layout;
495
- const defaultPath = projectState?.projectConfig?.defaults?.layout;
496
- const defaultLabel = defaultPath ? layoutName(defaultPath) : "";
497
- const options: SurfaceOption[] = [
498
- { label: defaultLabel ? `Default (${defaultLabel})` : "Default", value: "__default__" },
499
- { label: "None", value: "__none__" },
500
- ...entries.map((l) => ({ label: l.name, value: l.path })),
501
- ];
502
- commits.set("__layout", {
503
- clear: () =>
504
- applyMutation((d) => {
505
- delete d.$layout;
506
- }),
507
- commit: (raw) => {
508
- const val = String(raw);
509
- applyMutation((d) => {
510
- if (val === "__default__") {
511
- delete d.$layout;
512
- } else if (val === "__none__") {
513
- d.$layout = false;
514
- } else {
515
- d.$layout = val;
516
- }
517
- });
518
- invalidateLayoutCache();
519
- },
520
- });
521
- return {
522
- ...blankRow("__layout", "layout", "Layout"),
523
- isSet: current !== undefined,
524
- kind: "select",
525
- options,
526
- value: current === false ? "__none__" : current || "__default__",
527
- };
528
- }
529
-
530
- /** `./layouts/blog-post.json` → `Blog Post`. */
531
- function layoutName(path: string): string {
532
- return path
533
- .replace(/^\.\/layouts\//, "")
534
- .replace(/\.json$/, "")
535
- .replaceAll(/[-_]+/g, " ")
536
- .replaceAll(/\b\w/g, (c: string) => c.toUpperCase());
537
- }
538
-
539
- /**
540
- * One schema-driven frontmatter field, as the row that draws it and the write that commits it.
541
- *
542
- * **What the row LOOKS like is `panels/frontmatter-fields.ts`'s answer, not this module's.** The
543
- * Navigator's Page panel draws the same field set from the same schemas, and the two surfaces
544
- * deciding independently that a `$ref` is a picker, that `"uri-reference"` is a media format or
545
- * that an array is a comma-separated line is exactly how they came to disagree about `title`. What
546
- * stays here is what the card COMMITS INTO — this tab's frontmatter, through its transaction log.
547
- *
548
- * `tab` is a parameter because this used to commit to `activeTab.value` at each of seven widgets,
549
- * which is right for the Navigator's Document panel and wrong for a card drawn once per pane: a
550
- * collection field edited on the card in one pane wrote into whichever document had the keyboard.
551
- */
552
- function fieldRow(
553
- tab: Tab,
554
- field: string,
555
- entry: FmSchemaEntry,
556
- value: JsonValue | undefined,
557
- requiredFields: Set<string>,
558
- commits: Map<string, RowCommit>,
559
- ): DocHeaderRow {
560
- const key = `fm:${field}`;
561
- const { parse, row } = projectFmField(field, entry, value, requiredFields, { rerender: render });
562
- commits.set(key, {
563
- clear: () => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field)),
564
- commit: (raw) => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field, parse(raw))),
565
- });
566
- return { ...blankRow(key, field, row.label), ...row, clearLabel: `Clear ${field}` };
567
- }
568
-
569
- /**
570
- * The `$head` entries no structured control owns, listed read-only.
571
- *
572
- * Read-only on purpose: the card discloses what is there so the author is never surprised by a tag
573
- * they cannot see, and the Page panel remains the surface that adds and removes them.
574
- */
575
- function rawEntries(head: JxHeadEntry[]): DocHeaderRawEntry[] {
576
- const rows: DocHeaderRawEntry[] = [];
577
- for (const entry of head) {
578
- if (isManagedEntry(entry) || isGoogleFontEntry(entry) || isGoogleFontPreconnect(entry)) {
579
- continue;
580
- }
581
- // The key counts the LISTED entries, as the index of the filtered list it replaces did.
582
- rows.push({ key: `raw:${rows.length}`, label: entryLabel(entry), value: entryValue(entry) });
583
- }
584
- return rows;
585
- }
586
-
587
- // ─── The actions ─────────────────────────────────────────────────────────────
588
-
589
- /**
590
- * What the reader can do on one pane's card.
591
- *
592
- * Made once per host and handed to the surface at mount, so every one of them reads the CURRENT
593
- * commit table rather than closing over the projection that was standing when the card was drawn.
594
- * `settleCard` repaints the whole card, which needs these actions, so it is handed in.
595
- */
596
- function makeActions(card: HeaderCardState, settleCard: () => void): DocHeaderActions {
597
- const flush = (key: string): void => {
598
- const waiting = card.pending.get(key);
599
- if (waiting) {
600
- clearTimeout(waiting.timer);
601
- card.pending.delete(key);
602
- }
603
- };
604
- const now = (key: string, raw: string | boolean): void => {
605
- flush(key);
606
- card.commits.get(key)?.commit(raw);
607
- };
608
- return {
609
- browse: (key, anchor) => {
610
- flush(key);
611
- void mediaPicker().then((m) => {
612
- if (anchor instanceof HTMLElement) {
613
- m.showMediaPickerPopover(anchor, (val: string) => {
614
- card.commits.get(key)?.commit(val);
615
- });
616
- }
617
- });
618
- },
619
- clear: (key) => {
620
- flush(key);
621
- card.commits.get(key)?.clear();
622
- },
623
- commitText: (key, value) => now(key, value),
624
- /* Debounced, so the canvas follows the typing without a document write per keystroke. The
625
- control is NOT reset in the meantime: the projection this commit causes resolves to the text
626
- already in the field, and a document binding skips a write equal to what the element holds. */
627
- editText: (key, value) => {
628
- flush(key);
629
- const commit = () => {
630
- card.pending.delete(key);
631
- card.commits.get(key)?.commit(value);
632
- };
633
- card.pending.set(key, { commit, timer: setTimeout(commit, LIVE_PREVIEW) });
634
- },
635
- openSeo: () => {
636
- // The COMMAND, not a local open() — the Page panel offers the same door and neither of them
637
- // Owns it.
638
- void activeRegistry()?.run("document.openSeo");
639
- },
640
- setBoolean: (key, checked) => now(key, checked),
641
- setChoice: (key, value) => now(key, value),
642
- setExpanded: (open) => {
643
- // Per DOCUMENT, like the Raw head tags disclosure, and also the default for the next one:
644
- // The reader's last open-or-close is the state every editor opened after it starts in.
645
- const tab = tabOfPane(card.paneId);
646
- // The platform also fires `toggle` when the card is DRAWN open, so a toggle that agrees with
647
- // The state already held is the card's own projection coming back, not the reader. Taking it
648
- // As a choice would let merely looking at an older, open document reset the default.
649
- if (!tab || _expanded.get(tab.id) === open) {
650
- return;
651
- }
652
- _expanded.set(tab.id, open);
653
- try {
654
- localStorage.setItem(DOC_HEADER_EXPANDED_KEY, String(open));
655
- } catch {
656
- // Storage full or unavailable — this card still folds, the next one just opens.
657
- }
658
- settleCard();
659
- },
660
- setNumber: (key, value) => now(key, value),
661
- setRawOpen: (open) => {
662
- // Per DOCUMENT rather than per pane: the same file open in two stages discloses the same
663
- // Tags, and a flag on the pane would make the two cards disagree about one document.
664
- const tab = tabOfPane(card.paneId);
665
- if (!tab) {
666
- return;
667
- }
668
- if (open) {
669
- _rawOpen.add(tab.id);
670
- } else {
671
- _rawOpen.delete(tab.id);
672
- }
673
- settleCard();
674
- },
675
- upload: (key) => {
676
- flush(key);
677
- void mediaPicker().then((m) => {
678
- m.pickAndUpload((val: string) => {
679
- card.commits.get(key)?.commit(val);
680
- });
681
- });
682
- },
683
- };
684
- }
685
-
686
- /**
687
- * Bring a card's scope up to what the reader just did to one of its disclosures.
688
- *
689
- * A disclosure's `open` is two-way: the platform moves the element, and the scope that fed it still
690
- * holds the value it was drawn with. Left there, the next document whose state EQUALS that stale
691
- * value would project no change, the binding would not run, and the disclosure would stay as the
692
- * previous document left it.
693
- */
694
- function settle(card: HeaderCard): void {
695
- paint(card.paneId, card);
696
- }
697
-
698
- /**
699
- * The media picker's two behaviours, imported on the first press.
700
- *
701
- * ONE cached promise, deliberately: two dynamic imports of a module in flight at once is the shape
702
- * that loses its coverage record (see the note in the repository's agent guide), and the file also
703
- * pulls in the upload pipeline and the media metadata cache — neither of which a card that draws no
704
- * media field should ever load.
705
- */
706
- let _mediaPicker: Promise<typeof MediaPickerModule> | null = null;
707
-
708
- function mediaPicker(): Promise<typeof MediaPickerModule> {
709
- _mediaPicker ??= import("../ui/media-picker");
710
- return _mediaPicker;
711
- }