@jxsuite/studio 6.1.1 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (785) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  4. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  5. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  6. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  7. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  8. package/dist/chunks/color-area-6rbra5dy.js +4 -0
  9. package/dist/chunks/color-field-gy56c94g.js +4 -0
  10. package/dist/chunks/color-m7r1vk54.js +4 -0
  11. package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
  12. package/dist/chunks/combobox-72h32ejk.js +4 -0
  13. package/dist/chunks/components-r22xca09.js +4 -0
  14. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  15. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  16. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  17. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  18. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  19. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  20. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  21. package/dist/chunks/files-rcn56qvm.js +4 -0
  22. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  23. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  24. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  25. package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
  26. package/dist/chunks/icons-63bjtbs7.js +4 -0
  27. package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
  28. package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
  29. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  30. package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
  31. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  32. package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
  33. package/dist/chunks/index-f0jn7nnp.js +4 -0
  34. package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
  35. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  36. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  37. package/dist/chunks/layers-bgyr11tr.js +4 -0
  38. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  39. package/dist/chunks/listbox-c421cf8c.js +4 -0
  40. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  41. package/dist/chunks/media-library-sq468wts.js +4 -0
  42. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  43. package/dist/chunks/menu-bdpzbfvs.js +4 -0
  44. package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
  45. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  46. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  47. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  48. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  49. package/dist/chunks/parse-v77xtwv7.js +4 -0
  50. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  51. package/dist/chunks/popover-b89sfej7.js +4 -0
  52. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  53. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  54. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  55. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  56. package/dist/chunks/references-9547rg5s.js +4 -0
  57. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  58. package/dist/chunks/select-rzds841e.js +4 -0
  59. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  60. package/dist/chunks/split-c9zfdgxf.js +4 -0
  61. package/dist/chunks/studio-03ct6yfv.js +9 -0
  62. package/dist/chunks/studio-07rcfje3.js +5 -0
  63. package/dist/chunks/studio-3e54qh39.js +7 -0
  64. package/dist/chunks/studio-3exxhz5g.js +5 -0
  65. package/dist/chunks/studio-3q40e3rj.js +5 -0
  66. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  67. package/dist/chunks/studio-3qqjeep5.js +6 -0
  68. package/dist/chunks/studio-43sd2mam.js +4 -0
  69. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  70. package/dist/chunks/studio-58xg6j2q.js +9 -0
  71. package/dist/chunks/studio-5g0rprdt.js +7 -0
  72. package/dist/chunks/studio-6m380wp7.js +5 -0
  73. package/dist/chunks/studio-80jyh1xh.js +4 -0
  74. package/dist/chunks/studio-83mk4bgg.js +9 -0
  75. package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
  76. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  77. package/dist/chunks/studio-8tr6cfrc.js +5 -0
  78. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  79. package/dist/chunks/studio-9tmebf0s.js +5 -0
  80. package/dist/chunks/studio-a2bvaptz.js +5 -0
  81. package/dist/chunks/studio-b7y5mr30.js +5 -0
  82. package/dist/chunks/studio-bavb31r0.js +5 -0
  83. package/dist/chunks/studio-bbe4c90a.js +5 -0
  84. package/dist/chunks/studio-c05wdnt3.js +5 -0
  85. package/dist/chunks/studio-ccv2svc6.js +5 -0
  86. package/dist/chunks/studio-d5grtb9e.js +16 -0
  87. package/dist/chunks/studio-df0baea9.js +5 -0
  88. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  89. package/dist/chunks/studio-e1g64q43.js +5 -0
  90. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  91. package/dist/chunks/studio-ed3xx40h.js +7 -0
  92. package/dist/chunks/studio-f14e1zdj.js +5 -0
  93. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  94. package/dist/chunks/studio-fyh0jc96.js +5 -0
  95. package/dist/chunks/studio-gcxk20n7.js +5 -0
  96. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  97. package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
  98. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  99. package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
  100. package/dist/chunks/studio-k7evxqh4.js +5 -0
  101. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  102. package/dist/chunks/studio-m8g16bgz.js +5 -0
  103. package/dist/chunks/studio-mn0476ag.js +5 -0
  104. package/dist/chunks/studio-mx1smyq0.js +5 -0
  105. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  106. package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
  107. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  108. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  109. package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
  110. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  111. package/dist/chunks/studio-ph84avkf.js +5 -0
  112. package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
  113. package/dist/chunks/studio-q0tccd43.js +5 -0
  114. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  115. package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
  116. package/dist/chunks/studio-qmn1xc24.js +5 -0
  117. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  118. package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
  119. package/dist/chunks/studio-rj9eamf8.js +5 -0
  120. package/dist/chunks/studio-rptgsk96.js +5 -0
  121. package/dist/chunks/studio-rthyg42z.js +928 -0
  122. package/dist/chunks/studio-s19tp1xr.js +5 -0
  123. package/dist/chunks/studio-s32578pn.js +5 -0
  124. package/dist/chunks/studio-svb7yyve.js +5 -0
  125. package/dist/chunks/studio-syreb644.js +5 -0
  126. package/dist/chunks/studio-tf9jryb1.js +10 -0
  127. package/dist/chunks/studio-tfkznv39.js +5 -0
  128. package/dist/chunks/studio-tft6r105.js +5 -0
  129. package/dist/chunks/studio-txf2kysx.js +5 -0
  130. package/dist/chunks/studio-v8867ddv.js +12 -0
  131. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  132. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  133. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  134. package/dist/chunks/studio-wc649wss.js +5 -0
  135. package/dist/chunks/studio-wys23mxz.js +5 -0
  136. package/dist/chunks/studio-x1x167jh.js +5 -0
  137. package/dist/chunks/studio-x9hsze61.js +5 -0
  138. package/dist/chunks/studio-y0n7yxea.js +9 -0
  139. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  140. package/dist/chunks/studio-z97c48fk.js +5 -0
  141. package/dist/chunks/studio-zat62m0c.js +5 -0
  142. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  143. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  144. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  145. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  146. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  147. package/dist/chunks/toast-1gv0h53h.js +4 -0
  148. package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
  149. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  150. package/dist/chunks/tooltip-yypz28gq.js +4 -0
  151. package/dist/chunks/tree-9xa4hm7n.js +4 -0
  152. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  153. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  154. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  155. package/dist/chunks/ws-client-bv552sfx.js +4 -0
  156. package/dist/iframe-entry.js +20 -16
  157. package/dist/manifest.json +77 -63
  158. package/dist/studio.js +106 -107
  159. package/dist/workers/ts.worker.js +3 -3
  160. package/package.json +17 -16
  161. package/src/about/about-modal.ts +4 -3
  162. package/src/account/action-flow.ts +45 -38
  163. package/src/account-status.ts +7 -2
  164. package/src/browse/component-examples.ts +272 -0
  165. package/src/browse/library-commands.ts +64 -104
  166. package/src/browse/library-layouts.ts +270 -53
  167. package/src/browse/library-model.ts +194 -134
  168. package/src/browse/library-pane.ts +748 -440
  169. package/src/browse/library-preview.ts +161 -26
  170. package/src/browse/library-source.ts +308 -41
  171. package/src/browse/preview-root.ts +78 -0
  172. package/src/browse/preview-style.ts +155 -0
  173. package/src/canvas/asset-refs.ts +40 -10
  174. package/src/canvas/asset-resolve.ts +19 -23
  175. package/src/canvas/canvas-helpers.ts +7 -6
  176. package/src/canvas/canvas-live-render.ts +260 -77
  177. package/src/canvas/canvas-origin.ts +37 -12
  178. package/src/canvas/canvas-page-context.ts +112 -0
  179. package/src/canvas/canvas-patcher.ts +30 -30
  180. package/src/canvas/canvas-perf.ts +11 -5
  181. package/src/canvas/canvas-render.ts +175 -148
  182. package/src/canvas/canvas-surface.ts +5 -3
  183. package/src/canvas/canvas-utils.ts +147 -61
  184. package/src/canvas/dialog-path.ts +9 -4
  185. package/src/canvas/dialog-state.ts +1 -2
  186. package/src/canvas/diff-marks.ts +9 -16
  187. package/src/canvas/diff-toolbar.ts +8 -7
  188. package/src/canvas/edit-width-drag.ts +4 -1
  189. package/src/canvas/edit-width.ts +1 -3
  190. package/src/canvas/iframe-channel.ts +27 -13
  191. package/src/canvas/iframe-drop.ts +120 -12
  192. package/src/canvas/iframe-editable-root.ts +29 -16
  193. package/src/canvas/iframe-entry.ts +104 -75
  194. package/src/canvas/iframe-eval.ts +73 -49
  195. package/src/canvas/iframe-host.ts +269 -158
  196. package/src/canvas/iframe-inline-edit.ts +49 -30
  197. package/src/canvas/iframe-insert.ts +5 -4
  198. package/src/canvas/iframe-interaction.ts +30 -25
  199. package/src/canvas/iframe-keys.ts +11 -0
  200. package/src/canvas/iframe-overlay.ts +1 -1
  201. package/src/canvas/iframe-patch.ts +25 -21
  202. package/src/canvas/iframe-position.ts +12 -6
  203. package/src/canvas/iframe-protocol.ts +36 -21
  204. package/src/canvas/iframe-render.ts +84 -35
  205. package/src/canvas/iframe-slash.ts +24 -11
  206. package/src/canvas/iframe-subtree.ts +10 -3
  207. package/src/canvas/npm-modules.ts +22 -0
  208. package/src/canvas/path-mapping.ts +19 -12
  209. package/src/canvas/popover-path.ts +7 -3
  210. package/src/canvas/popover-state.ts +1 -2
  211. package/src/canvas/preview-navigate.ts +16 -0
  212. package/src/canvas/repeater-sources.ts +200 -0
  213. package/src/canvas/serialize-scope.ts +13 -5
  214. package/src/canvas/stage-scrollbar.ts +7 -2
  215. package/src/canvas/surface-registry.ts +27 -3
  216. package/src/collab/collab-commands.ts +7 -2
  217. package/src/collab/collab-session.ts +84 -45
  218. package/src/collab/collab-state.ts +4 -3
  219. package/src/collab/monaco-binding.ts +16 -13
  220. package/src/collab/monaco-cursors.ts +5 -2
  221. package/src/commands/app-commands.ts +16 -6
  222. package/src/commands/budget.ts +13 -11
  223. package/src/commands/command-args.ts +103 -71
  224. package/src/commands/context.ts +55 -28
  225. package/src/commands/defaults.ts +69 -45
  226. package/src/commands/keymap.ts +56 -43
  227. package/src/commands/levels.ts +14 -8
  228. package/src/commands/live-context.ts +9 -7
  229. package/src/commands/reference.ts +2 -1
  230. package/src/commands/registry.ts +22 -11
  231. package/src/commands/run-reported.ts +15 -10
  232. package/src/component-props.ts +46 -30
  233. package/src/content/collection-match.ts +11 -9
  234. package/src/content/collection-pages.ts +412 -0
  235. package/src/content/content-collections.ts +270 -0
  236. package/src/content/draft-state.ts +4 -3
  237. package/src/content/entry-commands.ts +54 -62
  238. package/src/content/entry-editor.ts +137 -32
  239. package/src/content/entry-fields.ts +25 -8
  240. package/src/content/entry-inspector.ts +225 -0
  241. package/src/content/entry-model.ts +38 -15
  242. package/src/content/entry-open.ts +80 -0
  243. package/src/content/entry-summaries.ts +440 -0
  244. package/src/content/file-record-ids.ts +80 -0
  245. package/src/content/file-records.ts +125 -0
  246. package/src/content/page-summaries.ts +129 -0
  247. package/src/content/record-entry.ts +201 -0
  248. package/src/content/writing-banner.ts +177 -0
  249. package/src/create/add-new-commands.ts +185 -0
  250. package/src/create/add-new-flow.ts +1116 -0
  251. package/src/create/add-new.ts +1014 -0
  252. package/src/create/element-name.ts +121 -0
  253. package/src/editor/canvas-context-menu.ts +1 -2
  254. package/src/editor/canvas-slash-bridge.ts +3 -6
  255. package/src/editor/content-slice.ts +16 -14
  256. package/src/editor/context-menu.ts +35 -22
  257. package/src/editor/convert-targets.ts +30 -35
  258. package/src/editor/convert-to-component.ts +78 -48
  259. package/src/editor/convert-to-repeater.ts +34 -22
  260. package/src/editor/editable-tags.ts +17 -2
  261. package/src/editor/file-drop-action.ts +29 -22
  262. package/src/editor/inline-edit-apply.ts +79 -17
  263. package/src/editor/inline-edit.ts +76 -50
  264. package/src/editor/inline-format.ts +59 -56
  265. package/src/editor/inline-link.ts +40 -15
  266. package/src/editor/insert-component.ts +91 -0
  267. package/src/editor/insert-zone-action.ts +14 -5
  268. package/src/editor/merge-tags.ts +58 -19
  269. package/src/editor/repeater-scope.ts +39 -28
  270. package/src/editor/shortcuts.ts +76 -42
  271. package/src/editor/slash-menu.ts +52 -14
  272. package/src/files/asset-versions.ts +4 -4
  273. package/src/files/components.ts +89 -20
  274. package/src/files/elements.ts +5 -6
  275. package/src/files/file-ops.ts +92 -41
  276. package/src/files/files.ts +248 -239
  277. package/src/files/fs-events.ts +18 -7
  278. package/src/files/media-meta.ts +97 -2
  279. package/src/files/media-paths.ts +3 -0
  280. package/src/files/media-types.ts +55 -0
  281. package/src/files/media-upload.ts +209 -52
  282. package/src/files/new-file-name.ts +156 -0
  283. package/src/files/serialize-document.ts +15 -5
  284. package/src/format/constraints.ts +1 -1
  285. package/src/format/convert-file.ts +27 -13
  286. package/src/format/format-choices.ts +2 -1
  287. package/src/format/format-host.ts +91 -50
  288. package/src/github/github-auth-status.ts +27 -3
  289. package/src/github/github-auth.ts +21 -11
  290. package/src/github/github-publish.ts +28 -23
  291. package/src/grid/cell-editors.ts +46 -31
  292. package/src/grid/cell-popovers.ts +5 -3
  293. package/src/grid/edit-buffer.ts +10 -9
  294. package/src/grid/grid-controller.ts +25 -23
  295. package/src/grid/grid-layout.ts +21 -5
  296. package/src/grid/grid-open.ts +3 -33
  297. package/src/grid/grid-panel.ts +65 -6
  298. package/src/grid/grid-reveal.ts +34 -0
  299. package/src/grid/grid-source.ts +9 -31
  300. package/src/grid/grid-view.ts +45 -23
  301. package/src/grid/redirects-grid.ts +14 -5
  302. package/src/grid/redirects.ts +16 -14
  303. package/src/grid/schema-columns.ts +25 -19
  304. package/src/grid/sources/connector-source.ts +47 -20
  305. package/src/grid/sources/content-source.ts +100 -31
  306. package/src/grid/sources/csv-file-source.ts +2 -2
  307. package/src/grid/tabulator-tables.d.ts +61 -34
  308. package/src/hosting/document.ts +2 -2
  309. package/src/hosting/stage.ts +7 -7
  310. package/src/i18n/i18n-commands.ts +3 -3
  311. package/src/media/media-commands.ts +181 -0
  312. package/src/media/media-library-model.ts +232 -0
  313. package/src/media/media-library.ts +1283 -0
  314. package/src/media/media-pane.ts +51 -20
  315. package/src/new-project/add-repo-modal.ts +20 -19
  316. package/src/new-project/import-tab.ts +10 -14
  317. package/src/new-project/location-fields.ts +2 -1
  318. package/src/new-project/new-project-modal.ts +12 -9
  319. package/src/packages/jxsuite-update.ts +4 -3
  320. package/src/packages/pull-package-sync.ts +26 -25
  321. package/src/page-params.ts +97 -68
  322. package/src/panels/activity-panel.ts +38 -14
  323. package/src/panels/ai-chat/attached-context.ts +13 -7
  324. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  325. package/src/panels/ai-chat/chat-view.ts +80 -73
  326. package/src/panels/ai-chat/composer.ts +30 -33
  327. package/src/panels/ai-chat/sessions-view.ts +1 -2
  328. package/src/panels/ai-panel.ts +23 -20
  329. package/src/panels/block-action-bar.ts +57 -46
  330. package/src/panels/bottom-dock.ts +5 -3
  331. package/src/panels/canvas-dnd-bridge.ts +36 -26
  332. package/src/panels/chat-panel.ts +6 -6
  333. package/src/panels/collections-panel.ts +306 -0
  334. package/src/panels/component-preview.ts +35 -13
  335. package/src/panels/data-explorer.ts +63 -26
  336. package/src/panels/data-grid.ts +18 -11
  337. package/src/panels/dnd.ts +115 -138
  338. package/src/panels/editors.ts +52 -21
  339. package/src/panels/elements-panel.ts +19 -5
  340. package/src/panels/empty-state.ts +2 -2
  341. package/src/panels/events-panel.ts +84 -69
  342. package/src/panels/formula-workspace.ts +78 -54
  343. package/src/panels/frontmatter-fields.ts +33 -28
  344. package/src/panels/git-diff-open.ts +10 -6
  345. package/src/panels/head-panel.ts +488 -202
  346. package/src/panels/i18n-panel.ts +20 -12
  347. package/src/panels/imports-panel.ts +25 -47
  348. package/src/panels/jump-bar.ts +75 -31
  349. package/src/panels/layers-panel.ts +130 -101
  350. package/src/panels/left-panel.ts +25 -11
  351. package/src/panels/navigator-panels.ts +23 -11
  352. package/src/panels/pane-context.ts +140 -49
  353. package/src/panels/pane-grid.ts +55 -26
  354. package/src/panels/panel-registry.ts +36 -46
  355. package/src/panels/properties-panel.ts +182 -124
  356. package/src/panels/quick-search.ts +53 -31
  357. package/src/panels/right-panel.ts +201 -45
  358. package/src/panels/seo-modal.ts +54 -125
  359. package/src/panels/settings-menu.ts +63 -61
  360. package/src/panels/settings-pane.ts +268 -162
  361. package/src/panels/signals-panel.ts +156 -135
  362. package/src/panels/site-model.ts +367 -0
  363. package/src/panels/site-panel.ts +638 -0
  364. package/src/panels/statement-editor.ts +230 -140
  365. package/src/panels/style-panel.ts +253 -206
  366. package/src/panels/style-utils.ts +114 -51
  367. package/src/panels/stylebook-doc.ts +195 -60
  368. package/src/panels/stylebook-layers-panel.ts +48 -89
  369. package/src/panels/stylebook-panel.ts +60 -27
  370. package/src/panels/styles-panel.ts +327 -0
  371. package/src/panels/tab-drop.ts +27 -11
  372. package/src/panels/tab-strip.ts +143 -49
  373. package/src/platform-errors.ts +57 -43
  374. package/src/platform.ts +59 -31
  375. package/src/platforms/cloud.ts +373 -176
  376. package/src/platforms/default-platform.ts +14 -8
  377. package/src/platforms/devserver.ts +180 -142
  378. package/src/platforms/read-batcher.ts +16 -8
  379. package/src/project-list.ts +2 -1
  380. package/src/publish/deploy-checklist.ts +20 -9
  381. package/src/publish/pages-service.ts +66 -27
  382. package/src/publish/publish-changes.ts +491 -0
  383. package/src/publish/publish-commands.ts +88 -22
  384. package/src/publish/publish-ids.ts +49 -0
  385. package/src/publish/publish-panel.ts +10 -6
  386. package/src/publish/publish-quick.ts +148 -0
  387. package/src/publish/publish-workspace.ts +926 -0
  388. package/src/publish/source-control.ts +907 -0
  389. package/src/recent-projects.ts +15 -8
  390. package/src/resize-edges.ts +26 -36
  391. package/src/services/a11y-report.ts +26 -19
  392. package/src/services/agent-seed.ts +23 -11
  393. package/src/services/ai-ask.ts +9 -12
  394. package/src/services/ai-command-tools.ts +68 -62
  395. package/src/services/ai-import-tools.ts +80 -67
  396. package/src/services/ai-models.ts +17 -13
  397. package/src/services/ai-project-tools.ts +68 -32
  398. package/src/services/ai-session-store.ts +19 -10
  399. package/src/services/ai-system-prompt.ts +46 -20
  400. package/src/services/ai-tools.ts +71 -27
  401. package/src/services/ai-write-report.ts +20 -12
  402. package/src/services/ai-writes.ts +4 -4
  403. package/src/services/automation.ts +74 -51
  404. package/src/services/cem-export.ts +149 -58
  405. package/src/services/cf-settings.ts +4 -4
  406. package/src/services/clock.ts +6 -1
  407. package/src/services/code-services.ts +37 -31
  408. package/src/services/connection.ts +2 -2
  409. package/src/services/context-manager.ts +14 -10
  410. package/src/services/context-resolver.ts +20 -8
  411. package/src/services/data-service.ts +19 -15
  412. package/src/services/directory-picker.ts +20 -14
  413. package/src/services/document-assistant.ts +39 -19
  414. package/src/services/gated-registry.ts +10 -6
  415. package/src/services/harness/chat-reducer.ts +23 -1
  416. package/src/services/import-client.ts +91 -38
  417. package/src/services/import-seed.ts +8 -2
  418. package/src/services/jx-validate.ts +28 -31
  419. package/src/services/live-preview.ts +0 -0
  420. package/src/services/live-surfaces.ts +6 -3
  421. package/src/services/model-uri.ts +10 -2
  422. package/src/services/module-preloads.ts +12 -8
  423. package/src/services/monaco-buffer.ts +43 -24
  424. package/src/services/monaco-lazy.ts +7 -8
  425. package/src/services/monaco-setup.ts +23 -16
  426. package/src/services/notify.ts +44 -17
  427. package/src/services/popover-report.ts +25 -10
  428. package/src/services/preview-eval.ts +20 -8
  429. package/src/services/profile.ts +13 -6
  430. package/src/services/project-path.ts +13 -10
  431. package/src/services/references.ts +0 -0
  432. package/src/services/render-critic.ts +29 -9
  433. package/src/services/settings/definitions.ts +25 -14
  434. package/src/services/settings/kernel.ts +13 -4
  435. package/src/services/settings/write-queue.ts +9 -9
  436. package/src/services/token-lint.ts +12 -10
  437. package/src/services/tool-executor.ts +17 -5
  438. package/src/services/tool-outcomes.ts +44 -24
  439. package/src/services/trusted-types.ts +24 -7
  440. package/src/settings/contexts-section.ts +11 -8
  441. package/src/settings/contributed-section.ts +128 -70
  442. package/src/settings/css-vars-editor.ts +119 -32
  443. package/src/settings/defs-editor.ts +38 -35
  444. package/src/settings/developer-panels.ts +43 -0
  445. package/src/settings/extension-rows.ts +16 -8
  446. package/src/settings/extension-sections.ts +42 -14
  447. package/src/settings/extensions-section.ts +4 -1
  448. package/src/settings/general-settings.ts +101 -28
  449. package/src/settings/locales-section.ts +20 -12
  450. package/src/settings/preferences-dialog.ts +17 -7
  451. package/src/settings/preferences-keymap.ts +7 -5
  452. package/src/settings/preferences-sections.ts +11 -5
  453. package/src/settings/project-sections.ts +28 -11
  454. package/src/settings/schema-field-ui.ts +12 -1
  455. package/src/settings/section-registry.ts +116 -11
  456. package/src/settings/settings-dialog.ts +192 -0
  457. package/src/settings/settings-document.ts +186 -166
  458. package/src/shell/tree.ts +6 -5
  459. package/src/shell.ts +536 -477
  460. package/src/site-context.ts +101 -32
  461. package/src/state.ts +68 -57
  462. package/src/store.ts +54 -34
  463. package/src/studio.ts +219 -116
  464. package/src/style/live-preview.ts +1 -1
  465. package/src/style/project-styles.ts +40 -7
  466. package/src/style/stylebook-specimens.ts +89 -0
  467. package/src/style/stylebook-target.ts +26 -0
  468. package/src/style/tag-inheritance.ts +105 -0
  469. package/src/style/token-ref.ts +5 -4
  470. package/src/style/variables-focus.ts +61 -0
  471. package/src/style/variables-view.ts +235 -0
  472. package/src/surfaces/about.ts +18 -19
  473. package/src/surfaces/add-new.json +1482 -0
  474. package/src/surfaces/add-new.ts +325 -0
  475. package/src/surfaces/add-repo.ts +17 -19
  476. package/src/surfaces/ai-chat.ts +33 -38
  477. package/src/surfaces/ai-credentials-form.ts +6 -16
  478. package/src/surfaces/ai-managed-connect.ts +3 -4
  479. package/src/surfaces/ai-model-picker.ts +3 -5
  480. package/src/surfaces/block-action-bar.ts +22 -11
  481. package/src/surfaces/boot-failure.json +4 -3
  482. package/src/surfaces/boot-failure.ts +4 -5
  483. package/src/surfaces/bottom-dock.json +1 -1
  484. package/src/surfaces/bottom-dock.ts +9 -18
  485. package/src/surfaces/canvas-stage.json +30 -19
  486. package/src/surfaces/canvas-stage.ts +17 -16
  487. package/src/surfaces/cf-account-picker.ts +17 -18
  488. package/src/surfaces/collections-panel.json +615 -0
  489. package/src/surfaces/collections-panel.ts +168 -0
  490. package/src/surfaces/commandbar.json +241 -96
  491. package/src/surfaces/commandbar.ts +145 -105
  492. package/src/surfaces/convert-repeater.ts +17 -19
  493. package/src/surfaces/data-actions.ts +9 -7
  494. package/src/surfaces/dialog.ts +26 -28
  495. package/src/surfaces/diff-toolbar.ts +9 -7
  496. package/src/surfaces/empty-state.json +1 -1
  497. package/src/surfaces/empty-state.ts +7 -10
  498. package/src/surfaces/entry-editor.json +136 -0
  499. package/src/surfaces/entry-editor.ts +35 -11
  500. package/src/surfaces/entry-inspector.json +371 -0
  501. package/src/surfaces/entry-inspector.ts +143 -0
  502. package/src/surfaces/expression-editor.ts +11 -25
  503. package/src/surfaces/files-panel.ts +27 -14
  504. package/src/surfaces/formula-palette.ts +4 -5
  505. package/src/surfaces/github-auth.ts +16 -20
  506. package/src/surfaces/github-publish.ts +17 -22
  507. package/src/surfaces/grid-cell.ts +30 -31
  508. package/src/surfaces/grid-open.ts +10 -14
  509. package/src/surfaces/grid-panel.ts +13 -9
  510. package/src/surfaces/grid-replace.ts +13 -13
  511. package/src/surfaces/grid-views.ts +15 -18
  512. package/src/surfaces/inspector-dock.json +162 -14
  513. package/src/surfaces/inspector-dock.ts +59 -31
  514. package/src/surfaces/jump-bar.ts +5 -6
  515. package/src/surfaces/jxsuite-update.ts +16 -22
  516. package/src/surfaces/library-pane.json +670 -437
  517. package/src/surfaces/library-pane.ts +111 -77
  518. package/src/surfaces/logic-panel.ts +17 -30
  519. package/src/surfaces/logic-workspace.ts +13 -15
  520. package/src/surfaces/media-browser.json +62 -6
  521. package/src/surfaces/media-browser.ts +26 -11
  522. package/src/surfaces/media-field.json +1 -1
  523. package/src/surfaces/media-field.ts +4 -5
  524. package/src/surfaces/media-library.json +1586 -0
  525. package/src/surfaces/media-library.ts +282 -0
  526. package/src/surfaces/media-pane.ts +8 -7
  527. package/src/surfaces/media-pick-dialog.json +71 -0
  528. package/src/surfaces/media-pick-dialog.ts +132 -0
  529. package/src/surfaces/menu.ts +47 -23
  530. package/src/surfaces/navigator-dock.ts +11 -12
  531. package/src/surfaces/new-project.ts +27 -26
  532. package/src/surfaces/pane-context.json +144 -77
  533. package/src/surfaces/pane-context.ts +44 -25
  534. package/src/surfaces/pane-grid.ts +15 -10
  535. package/src/surfaces/panel-activity.ts +5 -6
  536. package/src/surfaces/panel-data.ts +3 -4
  537. package/src/surfaces/panel-deploy-checklist.json +12 -6
  538. package/src/surfaces/panel-deploy-checklist.ts +8 -7
  539. package/src/surfaces/panel-elements.ts +5 -7
  540. package/src/surfaces/panel-i18n.ts +5 -7
  541. package/src/surfaces/panel-imports.ts +6 -13
  542. package/src/surfaces/panel-outline.ts +25 -19
  543. package/src/surfaces/panel-page.json +72 -2
  544. package/src/surfaces/panel-page.ts +49 -25
  545. package/src/surfaces/panel-problems.ts +5 -7
  546. package/src/surfaces/panel-signals.json +1 -1
  547. package/src/surfaces/panel-signals.ts +25 -39
  548. package/src/surfaces/panel-stylebook-layers.json +71 -204
  549. package/src/surfaces/panel-stylebook-layers.ts +5 -29
  550. package/src/surfaces/preferences.json +120 -48
  551. package/src/surfaces/preferences.ts +29 -11
  552. package/src/surfaces/progress-modal.ts +15 -9
  553. package/src/surfaces/properties-panel.json +1 -1
  554. package/src/surfaces/properties-panel.ts +20 -42
  555. package/src/surfaces/publish-quick.json +428 -0
  556. package/src/surfaces/publish-quick.ts +165 -0
  557. package/src/surfaces/publish-workspace.json +2892 -0
  558. package/src/surfaces/publish-workspace.ts +391 -0
  559. package/src/surfaces/publish.ts +18 -18
  560. package/src/surfaces/push-plan.ts +7 -8
  561. package/src/surfaces/rail.json +1 -159
  562. package/src/surfaces/rail.ts +22 -79
  563. package/src/surfaces/reference-field.ts +11 -15
  564. package/src/surfaces/schema-builder.ts +16 -22
  565. package/src/surfaces/schema-form.json +10 -2
  566. package/src/surfaces/schema-form.ts +17 -25
  567. package/src/surfaces/secret-field.ts +9 -6
  568. package/src/surfaces/seo.json +1 -1
  569. package/src/surfaces/seo.ts +21 -15
  570. package/src/surfaces/settings-contexts.ts +9 -7
  571. package/src/surfaces/settings-contributed.json +5 -5
  572. package/src/surfaces/settings-contributed.ts +32 -12
  573. package/src/surfaces/settings-css-vars.json +44 -36
  574. package/src/surfaces/settings-css-vars.ts +82 -16
  575. package/src/surfaces/settings-defs.json +2 -2
  576. package/src/surfaces/settings-defs.ts +17 -21
  577. package/src/surfaces/settings-deploy.json +2 -15
  578. package/src/surfaces/settings-deploy.ts +9 -16
  579. package/src/surfaces/settings-dialog.json +51 -0
  580. package/src/surfaces/settings-dialog.ts +169 -0
  581. package/src/surfaces/settings-extensions.ts +5 -6
  582. package/src/surfaces/settings-head.ts +33 -39
  583. package/src/surfaces/settings-locales.ts +8 -20
  584. package/src/surfaces/settings-overview.json +3 -3
  585. package/src/surfaces/settings-overview.ts +14 -8
  586. package/src/surfaces/settings-packages.ts +8 -7
  587. package/src/surfaces/settings-pane.json +269 -46
  588. package/src/surfaces/settings-pane.ts +88 -36
  589. package/src/surfaces/settings-rawjson.ts +5 -6
  590. package/src/surfaces/shell.json +2 -1
  591. package/src/surfaces/shell.ts +1 -2
  592. package/src/surfaces/site-panel.json +1029 -0
  593. package/src/surfaces/site-panel.ts +233 -0
  594. package/src/surfaces/slash-menu.json +63 -21
  595. package/src/surfaces/slash-menu.ts +42 -9
  596. package/src/surfaces/statements.ts +13 -18
  597. package/src/surfaces/statusbar.ts +56 -29
  598. package/src/surfaces/style-panel.ts +18 -31
  599. package/src/surfaces/stylebook-chrome.ts +3 -5
  600. package/src/surfaces/styles-panel.json +735 -0
  601. package/src/surfaces/styles-panel.ts +195 -0
  602. package/src/surfaces/styles-variables.json +149 -0
  603. package/src/surfaces/styles-variables.ts +145 -0
  604. package/src/surfaces/tab-strip.json +4 -4
  605. package/src/surfaces/tab-strip.ts +14 -13
  606. package/src/surfaces/target-line.ts +6 -7
  607. package/src/surfaces/welcome.ts +6 -8
  608. package/src/surfaces/writing-banner.json +94 -0
  609. package/src/surfaces/writing-banner.ts +80 -0
  610. package/src/tabs/bare-repeaters.ts +101 -0
  611. package/src/tabs/patch-ops.ts +4 -3
  612. package/src/tabs/project-config.ts +32 -21
  613. package/src/tabs/selection.ts +36 -8
  614. package/src/tabs/tab.ts +99 -48
  615. package/src/tabs/transact.ts +98 -53
  616. package/src/types.ts +53 -43
  617. package/src/ui/ai-credentials-form.ts +10 -13
  618. package/src/ui/ai-model-picker.ts +3 -3
  619. package/src/ui/cf-account-picker.ts +7 -9
  620. package/src/ui/color-selector.ts +9 -5
  621. package/src/ui/dynamic-slot.ts +7 -8
  622. package/src/ui/expression-editor.ts +112 -105
  623. package/src/ui/form-controls.ts +104 -56
  624. package/src/ui/formula-catalog.ts +239 -230
  625. package/src/ui/formula-chips.ts +33 -18
  626. package/src/ui/layers.ts +57 -31
  627. package/src/ui/media-picker.ts +300 -47
  628. package/src/ui/popover-surface.ts +20 -12
  629. package/src/ui/progress-modal.ts +13 -8
  630. package/src/ui/regions.ts +14 -12
  631. package/src/ui/schema-form.ts +372 -97
  632. package/src/ui/surface.ts +71 -8
  633. package/src/ui/timing.ts +9 -0
  634. package/src/ui/value-source.ts +44 -31
  635. package/src/ui/virtual-window.ts +29 -3
  636. package/src/utils/base64.ts +6 -4
  637. package/src/utils/edit-display.ts +366 -111
  638. package/src/utils/element-selectors.ts +3 -2
  639. package/src/utils/google-fonts.ts +15 -14
  640. package/src/utils/inherited-style.ts +18 -20
  641. package/src/utils/link-target.ts +1 -1
  642. package/src/utils/local-day.ts +18 -0
  643. package/src/utils/preview-format.ts +25 -3
  644. package/src/utils/strip-events.ts +49 -22
  645. package/src/utils/studio-utils.ts +29 -14
  646. package/src/view.ts +2 -3
  647. package/src/workspace/pane-derive.ts +14 -16
  648. package/src/workspace/session.ts +81 -50
  649. package/src/workspace/tab-workspace.ts +137 -0
  650. package/src/workspace/workspace-back.ts +189 -0
  651. package/src/workspace/workspace-home.ts +133 -0
  652. package/src/workspace/workspace-ids.ts +129 -0
  653. package/src/workspace/workspace-switch.ts +372 -0
  654. package/src/workspace/workspace.ts +165 -47
  655. package/styles/shell-frame.css +30 -7
  656. package/styles/shell-frame.json +15 -3
  657. package/dist/chunks/2020-va2wwra4.js +0 -4
  658. package/dist/chunks/adapter-f93pafd7.js +0 -4
  659. package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
  660. package/dist/chunks/cf-settings-125tdm0w.js +0 -4
  661. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  662. package/dist/chunks/color-field-embq5ctg.js +0 -4
  663. package/dist/chunks/color-fpezvnkt.js +0 -4
  664. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  665. package/dist/chunks/combobox-773hdzyj.js +0 -4
  666. package/dist/chunks/components-ax2f1fnn.js +0 -4
  667. package/dist/chunks/content-source-108aqtk1.js +0 -4
  668. package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
  669. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  670. package/dist/chunks/editor-pfgdmkb0.js +0 -4
  671. package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
  672. package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
  673. package/dist/chunks/file-ops-meej5mqf.js +0 -4
  674. package/dist/chunks/files-44vp8a2s.js +0 -4
  675. package/dist/chunks/format-host-7q1petb9.js +0 -4
  676. package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
  677. package/dist/chunks/git-panel-zngbymvd.js +0 -4
  678. package/dist/chunks/grid-view-sx9vynsp.js +0 -51
  679. package/dist/chunks/icons-p44xhjf0.js +0 -4
  680. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  681. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  682. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  683. package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
  684. package/dist/chunks/index-wkyfjeqz.js +0 -4
  685. package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
  686. package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
  687. package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
  688. package/dist/chunks/layers-xd92fg8d.js +0 -4
  689. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  690. package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
  691. package/dist/chunks/media-picker-0svzkdyb.js +0 -4
  692. package/dist/chunks/menu-37d07z9m.js +0 -4
  693. package/dist/chunks/menu-5c55ea3d.js +0 -4
  694. package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
  695. package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
  696. package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
  697. package/dist/chunks/notify-0xgtn8q1.js +0 -4
  698. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  699. package/dist/chunks/parse-897fvqah.js +0 -4
  700. package/dist/chunks/platform-v1qctbe6.js +0 -4
  701. package/dist/chunks/popover-8htra4er.js +0 -4
  702. package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
  703. package/dist/chunks/quick-search-a54e6t5n.js +0 -4
  704. package/dist/chunks/references-gmqp82fs.js +0 -4
  705. package/dist/chunks/right-panel-v7t9awbk.js +0 -4
  706. package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
  707. package/dist/chunks/select-n3v7gwas.js +0 -4
  708. package/dist/chunks/split-pff8f3ze.js +0 -4
  709. package/dist/chunks/studio-0bhx5hz6.js +0 -5
  710. package/dist/chunks/studio-0k1ddnyy.js +0 -6
  711. package/dist/chunks/studio-1b04pd0j.js +0 -64
  712. package/dist/chunks/studio-4dwbj6gb.js +0 -5
  713. package/dist/chunks/studio-4tanh828.js +0 -5
  714. package/dist/chunks/studio-55h4mstj.js +0 -4
  715. package/dist/chunks/studio-5tnvjkz4.js +0 -5
  716. package/dist/chunks/studio-60dqgb0c.js +0 -5
  717. package/dist/chunks/studio-61dp09qg.js +0 -9
  718. package/dist/chunks/studio-63epcrj2.js +0 -5
  719. package/dist/chunks/studio-74k29dy9.js +0 -5
  720. package/dist/chunks/studio-7vg6jcd3.js +0 -5
  721. package/dist/chunks/studio-7zx31knw.js +0 -9
  722. package/dist/chunks/studio-8bxk97km.js +0 -5
  723. package/dist/chunks/studio-933e30n4.js +0 -5
  724. package/dist/chunks/studio-98wnwhbg.js +0 -5
  725. package/dist/chunks/studio-9mccjwjh.js +0 -14
  726. package/dist/chunks/studio-a2ke1e4t.js +0 -5
  727. package/dist/chunks/studio-e3a2a6v3.js +0 -4
  728. package/dist/chunks/studio-e81q1vb9.js +0 -5
  729. package/dist/chunks/studio-epgrmqqm.js +0 -5
  730. package/dist/chunks/studio-ery42sqr.js +0 -4
  731. package/dist/chunks/studio-g1shz58g.js +0 -5
  732. package/dist/chunks/studio-gf0fz03c.js +0 -5
  733. package/dist/chunks/studio-gjtpe62q.js +0 -6
  734. package/dist/chunks/studio-gkskhg7m.js +0 -5
  735. package/dist/chunks/studio-gx4dnjzd.js +0 -5
  736. package/dist/chunks/studio-j03zga3y.js +0 -9
  737. package/dist/chunks/studio-jhpxeckz.js +0 -5
  738. package/dist/chunks/studio-k01r7ykp.js +0 -5
  739. package/dist/chunks/studio-kk7h30ne.js +0 -7
  740. package/dist/chunks/studio-kt1zqney.js +0 -5
  741. package/dist/chunks/studio-m3cwhvye.js +0 -5
  742. package/dist/chunks/studio-mcayt6hz.js +0 -5
  743. package/dist/chunks/studio-myjcghv3.js +0 -5
  744. package/dist/chunks/studio-n8bxwc3y.js +0 -4
  745. package/dist/chunks/studio-ngm8gvpb.js +0 -5
  746. package/dist/chunks/studio-nj5a01jy.js +0 -928
  747. package/dist/chunks/studio-pcgz8heb.js +0 -5
  748. package/dist/chunks/studio-qcsq0t15.js +0 -5
  749. package/dist/chunks/studio-qkstvve9.js +0 -5
  750. package/dist/chunks/studio-qv1pwd3c.js +0 -5
  751. package/dist/chunks/studio-rc6dvxjb.js +0 -7
  752. package/dist/chunks/studio-s8dmmz66.js +0 -5
  753. package/dist/chunks/studio-sp5xzbj4.js +0 -6
  754. package/dist/chunks/studio-szsjbj0g.js +0 -5
  755. package/dist/chunks/studio-t1xzawhr.js +0 -16
  756. package/dist/chunks/studio-tdcprbqb.js +0 -5
  757. package/dist/chunks/studio-vrmcjf9g.js +0 -7
  758. package/dist/chunks/studio-vyc0b4he.js +0 -10
  759. package/dist/chunks/studio-w0cgf6jg.js +0 -5
  760. package/dist/chunks/studio-w3hskzqk.js +0 -5
  761. package/dist/chunks/studio-xgrgcdyh.js +0 -9
  762. package/dist/chunks/studio-xz2yxfcb.js +0 -5
  763. package/dist/chunks/studio-y6n42tgs.js +0 -5
  764. package/dist/chunks/studio-yb560vxr.js +0 -5
  765. package/dist/chunks/studio-yn9f8vtx.js +0 -5
  766. package/dist/chunks/studio-yw05w8f0.js +0 -7
  767. package/dist/chunks/studio-z16sgavc.js +0 -5
  768. package/dist/chunks/studio-zey7zsdw.js +0 -12
  769. package/dist/chunks/studio-zyqn40w4.js +0 -5
  770. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  771. package/dist/chunks/tabs-jwthg40w.js +0 -4
  772. package/dist/chunks/textfield-spy3hc77.js +0 -4
  773. package/dist/chunks/toast-4d35zd64.js +0 -4
  774. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  775. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  776. package/dist/chunks/tree-h19v1jfz.js +0 -4
  777. package/dist/chunks/tsMode-2frah6h1.js +0 -14
  778. package/dist/chunks/workspace-zt81g1ms.js +0 -4
  779. package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
  780. package/src/panels/frontmatter-panel.ts +0 -701
  781. package/src/panels/git-panel.ts +0 -1120
  782. package/src/surfaces/doc-header.json +0 -776
  783. package/src/surfaces/doc-header.ts +0 -231
  784. package/src/surfaces/git-panel.json +0 -1880
  785. package/src/surfaces/git-panel.ts +0 -272
@@ -59,6 +59,7 @@ import {
59
59
  dropTargetForElements,
60
60
  monitorForElements,
61
61
  } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
62
+ import type { ElementDragPayload } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
62
63
  import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
63
64
  import {
64
65
  PRIMARY_PANE,
@@ -79,6 +80,7 @@ import { runActiveReported, runReported } from "../commands/run-reported";
79
80
  import { collectionOfPath } from "../content/entry-model";
80
81
  import { confirmFileDelete, parseSourceForPath, renamePromptMessage } from "./file-ops";
81
82
  import { parseJsonDocument } from "@jxsuite/schema/json-layout";
83
+ import { normalizeDocument } from "../tabs/bare-repeaters";
82
84
  // The pure half of the differ: order-insensitive equality with no Yjs behind it.
83
85
  import { deepEqual } from "@jxsuite/collab/diff-core";
84
86
  import type { JsonLayout } from "@jxsuite/schema/json-layout";
@@ -93,15 +95,31 @@ import {
93
95
  refreshFormats,
94
96
  } from "../format/format-host";
95
97
  import { convertTargets, creationFormats, knownDocumentExtensions } from "../format/format-choices";
98
+ import {
99
+ composeNewFileName,
100
+ extensionOfName,
101
+ OTHER_FORMAT,
102
+ validateNewFileName,
103
+ } from "./new-file-name";
104
+ import type { FormatChoice, NewFileNameCheck } from "./new-file-name";
96
105
  import { collectionForDirectory } from "../content/collection-match";
97
- import { markSessionRestored, persistedSession, resetProjectShell, setActivityTab } from "../shell";
106
+ import {
107
+ markSessionRestored,
108
+ persistedSession,
109
+ persistedWorkspace,
110
+ resetProjectShell,
111
+ } from "../shell";
112
+ import type { WorkspaceId } from "../workspace/workspace-ids";
98
113
  import { restoreSession } from "../workspace/session";
99
- import { cleanupGitPanel } from "../panels/git-panel";
114
+ import { cleanupSourceControl } from "../publish/source-control";
100
115
  import { addRecentProject, trackRecentFile } from "../recent-projects";
101
116
  import { listWindow, revealListRow, watchListWindow } from "../ui/virtual-window";
102
- import type { JxMutableNode } from "@jxsuite/schema/types";
117
+ import type { JsonObject, JxMutableNode } from "@jxsuite/schema/types";
118
+ import { isString } from "@jxsuite/schema/guards";
119
+ import type { CommandArgValues } from "../commands/command-args";
120
+ import type { FormatFrontmatter } from "../format/format-host";
103
121
  import type { ResolvedI18n } from "@jxsuite/schema/locale";
104
- import type { ChoiceOption } from "../ui/layers";
122
+ import type { ChoiceOption, PromptDialogOptions } from "../ui/layers";
105
123
  import { emptyFilesPanelValues, mountFilesPanelSurface } from "../surfaces/files-panel";
106
124
  import { openMenu } from "../surfaces/menu";
107
125
  import type {
@@ -136,6 +154,65 @@ export async function loadDirectory(dirPath: string) {
136
154
  }
137
155
  }
138
156
 
157
+ /** The project directories the Library scans and the tree opens expanded, when present. */
158
+ const CONVENTIONAL_DIRS = new Set([
159
+ "pages",
160
+ "layouts",
161
+ "components",
162
+ "content",
163
+ "data",
164
+ "public",
165
+ "styles",
166
+ ]);
167
+
168
+ /**
169
+ * Load the project root, expand and load each conventional directory it holds, and record them as
170
+ * `projectDirs` — the list the Library scans.
171
+ *
172
+ * One function because there are four doors into a project (the folder picker, a recent project,
173
+ * the `?project=` boot and the root probe a fresh window runs), and each used to carry its own copy
174
+ * of this walk. Two of the copies expanded the directories without recording them, so on desktop
175
+ * the file tree was full and the Library said the project had no files.
176
+ */
177
+ export async function loadProjectDirectories(): Promise<void> {
178
+ if (!projectState) {
179
+ return;
180
+ }
181
+ await loadDirectory(".");
182
+ const found: string[] = [];
183
+ for (const entry of projectState.dirs.get(".") ?? []) {
184
+ if (entry.type === "directory" && CONVENTIONAL_DIRS.has(entry.name)) {
185
+ found.push(entry.name);
186
+ projectState.expanded.add(entry.path || entry.name);
187
+ await loadDirectory(entry.path || entry.name);
188
+ }
189
+ }
190
+ projectState.projectDirs = found;
191
+ }
192
+
193
+ /**
194
+ * Re-read the project's directories when a write created a conventional one the list lacks.
195
+ *
196
+ * The list is read as the project opens, so a project that had no `pages/` or `content/` then does
197
+ * not grow one in the list when Add new writes its first page or collection, and the Content scan
198
+ * walks only what the list names. Resolves `true` when the list was re-read, so the caller knows a
199
+ * repaint is due; `false` (and no listing at all) when every written path was already covered.
200
+ *
201
+ * @param paths Project-relative paths just written.
202
+ */
203
+ export async function refreshProjectDirectoriesFor(paths: readonly string[]): Promise<boolean> {
204
+ const known = new Set(projectState?.projectDirs);
205
+ const missing = paths.some((path) => {
206
+ const top = path.replaceAll("\\", "/").replace(/^\.\//, "").split("/")[0] ?? "";
207
+ return path.includes("/") && CONVENTIONAL_DIRS.has(top) && !known.has(top);
208
+ });
209
+ if (!missing) {
210
+ return false;
211
+ }
212
+ await loadProjectDirectories();
213
+ return true;
214
+ }
215
+
139
216
  /**
140
217
  * Whether the tree currently draws the files `.gitignore` masks.
141
218
  *
@@ -196,7 +273,7 @@ export async function loadProject() {
196
273
  await loadFormats();
197
274
  refreshExtensionUi(platform);
198
275
  }
199
- await loadDirectory(".");
276
+ await loadProjectDirectories();
200
277
  await loadComponentRegistry();
201
278
  await openLastSessionOrHome();
202
279
  void maybePromptJxsuiteUpdate(meta.root);
@@ -216,13 +293,19 @@ export async function loadProject() {
216
293
  * the window on the project it already had, and the caller announces the outcome — "Opening the
217
294
  * project…" over a dialog the user just dismissed is a report of something that did not happen.
218
295
  *
219
- * @param {{ renderLeftPanel: () => void }} ctx
296
+ * @param ctx.renderLeftPanel Repaint the Navigator.
297
+ * @param ctx.resetProjectCaches Drop the caches panels above this module keep for the project being
298
+ * left (the Site panel's index, the media listing). Injected for the reason `fs-events.ts` takes
299
+ * `invalidateDerivedCaches`: those panels import from the file layer, so reaching up is a cycle,
300
+ * and `studio.ts`'s `openRecentProject` runs the same reset.
220
301
  * @returns {Promise<boolean>} Whether the window changed project.
221
302
  */
222
303
  export async function openProject({
223
304
  renderLeftPanel,
305
+ resetProjectCaches,
224
306
  }: {
225
307
  renderLeftPanel: () => void;
308
+ resetProjectCaches?: () => void;
226
309
  }): Promise<boolean> {
227
310
  try {
228
311
  const platform = getPlatform();
@@ -268,35 +351,17 @@ export async function openProject({
268
351
  await loadFormats();
269
352
  refreshExtensionUi(platform);
270
353
  }
271
- await loadDirectory(".");
354
+ await loadProjectDirectories();
272
355
  await loadComponentRegistry();
273
356
 
274
- // Auto-expand key directories and populate projectDirs for Browse view
275
- const conventionalDirs = new Set([
276
- "pages",
277
- "layouts",
278
- "components",
279
- "content",
280
- "data",
281
- "public",
282
- "styles",
283
- ]);
284
- const entries = requireProjectState().dirs.get(".") || [];
285
- const foundDirs = [];
286
- for (const e of entries) {
287
- if (e.type === "directory" && conventionalDirs.has(e.name)) {
288
- foundDirs.push(e.name);
289
- requireProjectState().expanded.add(e.path || e.name);
290
- await loadDirectory(e.path || e.name);
291
- }
292
- }
293
- requireProjectState().projectDirs = foundDirs;
294
-
295
357
  // Source control, the stylebook selection and the settings tab describe the project being
296
- // Left behind. The poll timer goes with them; the panel re-arms it on its next render.
297
- cleanupGitPanel();
358
+ // Left behind. The poll timer goes with them; the Publish workspace re-arms it on its next mount.
359
+ cleanupSourceControl();
298
360
  resetProjectShell();
299
- setActivityTab("files");
361
+ resetProjectCaches?.();
362
+ /* The Navigator's panel is the workspace frame's, applied as the project opened (§22.3): Design
363
+ opens on the Site panel. Forcing Files here put a developer panel with no rail button on
364
+ screen and re-opened a Navigator the frame had hidden. */
300
365
  addRecentProject(requireProjectState().name, requireProjectState().projectRoot);
301
366
  renderLeftPanel();
302
367
  // The project's name is permanent state in the status bar's PROJECT field now.
@@ -405,6 +470,31 @@ export async function openLastSessionOrHome(): Promise<boolean> {
405
470
  // `projectState.projectRoot`, the recent-list entry. One reader of one field cannot disagree with
406
471
  // The writer; three callers passing three spellings silently restore nothing.
407
472
  const session = persistedSession(workspace.projectRoot);
473
+ /* The workspace it was left in, read BEFORE anything opens: every tab the restore activates
474
+ enters its own workspace, and that entry is persisted over the stored one. */
475
+ const left = persistedWorkspace(workspace.projectRoot);
476
+ const restored = await restoreSessionOrHome(session);
477
+ _showWorkspace?.(left);
478
+ return restored;
479
+ }
480
+
481
+ /**
482
+ * How a project open shows the workspace it was left in, once its documents are open. Installed by
483
+ * the bootstrap (`workspace/workspace-switch.ts`'s `switchWorkspace`), because the switch opens
484
+ * homes this module must not import; unset, the restore leaves the workspace wherever its tabs
485
+ * did.
486
+ */
487
+ let _showWorkspace: ((id: WorkspaceId) => void) | null = null;
488
+
489
+ /** Install (or with `null`, remove) what {@link openLastSessionOrHome} shows the workspace with. */
490
+ export function setSessionWorkspaceShow(show: ((id: WorkspaceId) => void) | null): void {
491
+ _showWorkspace = show;
492
+ }
493
+
494
+ /** The body of {@link openLastSessionOrHome}: the session, or the home page. */
495
+ async function restoreSessionOrHome(
496
+ session: ReturnType<typeof persistedSession>,
497
+ ): Promise<boolean> {
408
498
  // Read first, THEN allow writes: the persist effect fires the moment `workspace.projectRoot` is
409
499
  // Set, and an empty workspace captured at that instant would overwrite the very record this line
410
500
  // Reads. See `markSessionRestored`.
@@ -460,35 +550,6 @@ function fileIconName(name: string, type: string, expanded: boolean): string {
460
550
  }
461
551
  }
462
552
 
463
- /**
464
- * The Navigator no longer draws this panel with lit.
465
- *
466
- * The record below returns `nothing` and mounts `surfaces/files-panel.json` in `afterRender`, so
467
- * this is a stub: it survives only because `NavigatorPanelDeps` still declares the injection and
468
- * `studio.ts` still passes it. Both go in the change that deletes this.
469
- *
470
- * @deprecated The panel is `surfaces/files-panel.json`; call {@link mountFilesPanel}.
471
- */
472
- export function renderFilesTemplate(): typeof nothing {
473
- return nothing;
474
- }
475
-
476
- /**
477
- * Drag-and-drop is registered against the row elements the DOCUMENT creates, as they are created.
478
- *
479
- * The pass this replaced ran on a `requestAnimationFrame` after every repaint, found the tree and
480
- * its rows by class, and re-registered every one of them — which is exactly the acquisition
481
- * `studio-ui-guidelines.md` §9.4 objects to, and which a WINDOWED list makes wrong rather than
482
- * merely wasteful: the rows are re-used for different files as the window slides, so a pass that
483
- * arrives one frame late hands a file's drag source to whichever file is standing in its place.
484
- * {@link mountFilesPanel} adopts each row through `onNodeCreated` instead.
485
- *
486
- * @deprecated Registration is `onNodeCreated`; this exists for the deps entry alone.
487
- */
488
- export function registerFileTreeDnD(_ctx: { renderLeftPanel: () => void }): void {
489
- // Intentionally nothing: see the note above.
490
- }
491
-
492
553
  // ─── The row model, and the window onto it ───────────────────────────────────
493
554
 
494
555
  /**
@@ -1183,10 +1244,9 @@ export function canMoveInto(srcPath: string, targetDir: string): boolean {
1183
1244
  }
1184
1245
 
1185
1246
  /** {@link canMoveInto} for a ROW: only a directory has an inside to move something into. */
1186
- function acceptsDrop(srcPath: unknown, targetPath: string, targetType: string): boolean {
1187
- return (
1188
- targetType === "directory" && typeof srcPath === "string" && canMoveInto(srcPath, targetPath)
1189
- );
1247
+ function acceptsDrop(source: ElementDragPayload, targetPath: string, targetType: string): boolean {
1248
+ const srcPath = source.data.path;
1249
+ return targetType === "directory" && isString(srcPath) && canMoveInto(srcPath, targetPath);
1190
1250
  }
1191
1251
 
1192
1252
  /**
@@ -1310,15 +1370,15 @@ function adoptFileRow(element: HTMLElement, path: string, type: string): void {
1310
1370
  },
1311
1371
  element,
1312
1372
  getData({ source }) {
1313
- return acceptsDrop(source.data.path, path, type)
1373
+ return acceptsDrop(source, path, type)
1314
1374
  ? { targetDir: path, type: "file-tree-target" }
1315
1375
  : { type: "file-tree-refused" };
1316
1376
  },
1317
1377
  onDrag({ source }) {
1318
- setRowUnderDrag(path, acceptsDrop(source.data.path, path, type));
1378
+ setRowUnderDrag(path, acceptsDrop(source, path, type));
1319
1379
  },
1320
1380
  onDragEnter({ source }) {
1321
- setRowUnderDrag(path, acceptsDrop(source.data.path, path, type));
1381
+ setRowUnderDrag(path, acceptsDrop(source, path, type));
1322
1382
  },
1323
1383
  onDragLeave() {
1324
1384
  setRowUnderDrag("", false);
@@ -1361,7 +1421,8 @@ function adoptFileTreeElement(element: HTMLElement): void {
1361
1421
  pointer — {@link syncRootDrop} — because the row is what the drop will reach. */
1362
1422
  const rootCleanup = dropTargetForElements({
1363
1423
  canDrop({ source }) {
1364
- return source.data.type === "file-tree" && canMoveInto(source.data.path as string, ".");
1424
+ const srcPath = source.data.path;
1425
+ return source.data.type === "file-tree" && isString(srcPath) && canMoveInto(srcPath, ".");
1365
1426
  },
1366
1427
  element,
1367
1428
  getData() {
@@ -1393,9 +1454,11 @@ function adoptFileTreeElement(element: HTMLElement): void {
1393
1454
  return;
1394
1455
  }
1395
1456
 
1396
- const srcPath = source.data.path as string;
1397
- const targetDirPath = target.data.targetDir as string;
1398
- if (!canMoveInto(srcPath, targetDirPath)) {
1457
+ // A file-tree row's drag source always carries its string `path`, and an accepting row's
1458
+ // Target its string `targetDir` (see `adoptFileRow`); anything else is not a move.
1459
+ const srcPath = source.data.path;
1460
+ const targetDirPath = target.data.targetDir;
1461
+ if (!isString(srcPath) || !isString(targetDirPath) || !canMoveInto(srcPath, targetDirPath)) {
1399
1462
  return;
1400
1463
  }
1401
1464
  const fileName = srcPath.split("/").pop();
@@ -1520,8 +1583,8 @@ function dismissFileContextMenu(): void {
1520
1583
  * Entry Form" is not offered on it. A command whose required arguments this row cannot answer is
1521
1584
  * skipped — never rendered into a refusal the author cannot act on.
1522
1585
  */
1523
- function fileRowFacts(entry: { path: string; type: string }): Record<string, unknown> {
1524
- const facts: Record<string, unknown> = {};
1586
+ function fileRowFacts(entry: { path: string; type: string }): CommandArgValues {
1587
+ const facts: CommandArgValues = {};
1525
1588
  if (entry.type === "directory") {
1526
1589
  // The collection's own SOURCE ROOT, not any directory beneath it: "Edit Collection in Grid"
1527
1590
  // Opens the whole collection, so offering it on `content/posts/2026` would be a row whose label
@@ -1579,13 +1642,11 @@ function placedFileRows(entry: { path: string; type: string }): MenuRowProjectio
1579
1642
  const facts = fileRowFacts(entry);
1580
1643
  const rows: MenuRowProjection[] = [];
1581
1644
  for (const command of registry.forPlacement("context/file")) {
1582
- const schema = command.args as
1583
- | { properties?: Record<string, unknown>; required?: readonly string[] }
1584
- | undefined;
1645
+ const schema = command.args;
1585
1646
  if (!(schema?.required ?? []).every((key) => key in facts)) {
1586
1647
  continue;
1587
1648
  }
1588
- const args: Record<string, unknown> = {};
1649
+ const args: CommandArgValues = {};
1589
1650
  for (const key of Object.keys(schema?.properties ?? {})) {
1590
1651
  if (key in facts) {
1591
1652
  args[key] = facts[key];
@@ -1708,29 +1769,6 @@ const BLANK_DOCUMENT = JSON.stringify(
1708
1769
  2,
1709
1770
  );
1710
1771
 
1711
- /**
1712
- * The picker row meaning "I will type the whole name myself".
1713
- *
1714
- * It is what keeps the format picker from being a cage. `New File…` is the only generic
1715
- * file-creation affordance in Studio and both backends create intermediate directories on write, so
1716
- * without this row `styles/main.css`, `public/robots.txt`, `.gitignore` and a `credits.txt` beside
1717
- * a collection's images all become uncreatable — and the picker would have taken away more than it
1718
- * gave. The picker stays the authority on the extension; this is one of its answers.
1719
- */
1720
- export const OTHER_FORMAT = "__other__";
1721
-
1722
- /** How the extension of a new file is settled. */
1723
- export type FormatChoice =
1724
- /** Picker over every creatable format, plus Other…. The field is a NAME, taken verbatim. */
1725
- | { kind: "choose"; defaultExt?: string; docKind?: "page" | "component" | "content" }
1726
- /**
1727
- * Picker holding ONE format, plus Other… — the collection's own extension. The field is a NAME.
1728
- * `because` is the sentence a refusal quotes when Other… would smuggle a foreign document in.
1729
- */
1730
- | { kind: "locked"; ext: string; because: string }
1731
- /** No picker. The field is a DISPLAY NAME, slugified, and `ext` is appended. */
1732
- | { kind: "fixed"; ext: string };
1733
-
1734
1772
  /**
1735
1773
  * One creation, named.
1736
1774
  *
@@ -1752,34 +1790,12 @@ export interface NewFileRequest {
1752
1790
  * (`i18n.createTranslation` composes `about.json` from the file it is translating).
1753
1791
  */
1754
1792
  format?: FormatChoice;
1755
- /**
1756
- * Body to write. A function is called with the extension the reader settled on and the composed
1757
- * file name, which is the only way a caller can seed a body whose FORMAT — or whose own tag name
1758
- * — it does not know until the dialog resolves. Defaults to the resolved format's
1759
- * `newFileTemplate`.
1760
- */
1761
- content?:
1762
- | string
1763
- | ((ext: string, fileName: string) => string | undefined | Promise<string | undefined>);
1793
+ /** Body to write. Defaults to the resolved format's `newFileTemplate`. */
1794
+ content?: string;
1764
1795
  /** Who is creating, for the Problem's `source` line. Defaults to "Files". */
1765
1796
  source?: string;
1766
1797
  }
1767
1798
 
1768
- /** A display name, reduced to a file stem. Lowercase by design: this is a slug. */
1769
- function slugify(input: string): string {
1770
- return input
1771
- .trim()
1772
- .toLowerCase()
1773
- .replaceAll(/\s+/g, "-")
1774
- .replaceAll(/[^a-z\d-]/g, "");
1775
- }
1776
-
1777
- /** The extension of a file name, including the dot, or `""`. */
1778
- function extensionOfName(name: string): string {
1779
- const dot = name.lastIndexOf(".");
1780
- return dot > 0 ? name.slice(dot) : "";
1781
- }
1782
-
1783
1799
  /** The two picker modes — the ones where the field asks for a NAME and the picker owns the suffix. */
1784
1800
  type PickerChoice = Extract<FormatChoice, { kind: "choose" } | { kind: "locked" }>;
1785
1801
 
@@ -1841,14 +1857,7 @@ export async function createFileIn(request: NewFileRequest): Promise<string | nu
1841
1857
  await loadFormats();
1842
1858
 
1843
1859
  // One listing, before the field opens: the names it must refuse are known while typing.
1844
- let taken = new Set<string>();
1845
- try {
1846
- const listing = await getPlatform().listDirectory(dir);
1847
- taken = new Set(listing.map((entry) => entry.name.toLowerCase()));
1848
- } catch {
1849
- // A directory that cannot be listed is usually one that does not exist yet — the write below
1850
- // Is the authority on whether that is a problem, and it reports with the real reason.
1851
- }
1860
+ const taken = await listTakenNames(dir);
1852
1861
 
1853
1862
  const picker = choice !== undefined && choice.kind !== "fixed" ? choice : null;
1854
1863
  const rows = picker === null ? null : formatRowsFor(picker);
@@ -1857,108 +1866,40 @@ export async function createFileIn(request: NewFileRequest): Promise<string | nu
1857
1866
  ? ""
1858
1867
  : initialPickFor(picker, rows, request.suggestedName ?? "");
1859
1868
 
1860
- /**
1861
- * The file name a field value and a pick compose to — three modes, not two.
1862
- *
1863
- * The verbatim STEM mode is not a convenience. The slugifier lowercases and strips everything
1864
- * outside `[a-z0-9-]`, which turns `[slug]` into `slug` — and eight shipped starters carry
1865
- * `pages/[slug].json`, `[sku].json`, `[...slug].json`. A picker that slugified would make a
1866
- * dynamic route uncreatable and would say nothing about it.
1867
- */
1868
- const fileNameFor = (input: string, picked: string) => {
1869
- const trimmed = input.trim();
1870
- if (choice === undefined || picked === OTHER_FORMAT) {
1871
- return trimmed;
1872
- }
1873
- if (choice.kind === "fixed") {
1874
- const slug = slugify(trimmed);
1875
- return slug === "" ? "" : `${slug}${choice.ext}`;
1876
- }
1877
- return trimmed.toLowerCase().endsWith(picked.toLowerCase()) ? trimmed : `${trimmed}${picked}`;
1878
- };
1879
-
1880
- const known = knownDocumentExtensions();
1881
-
1882
- const validate = (value: string, picked: string) => {
1883
- const trimmed = value.trim();
1884
- if (!trimmed) {
1885
- return choice?.kind === "fixed" ? "Enter a name." : "Enter a file name.";
1886
- }
1887
- if (choice?.kind === "fixed" && slugify(trimmed) === "") {
1888
- return "Enter at least one letter or number.";
1889
- }
1890
- const normalized = trimmed.replaceAll("\\", "/");
1891
- if (normalized.startsWith("/") || normalized.endsWith("/")) {
1892
- return "Enter a name, not a path that starts or ends with a slash.";
1893
- }
1894
- if (normalized.split("/").includes("..")) {
1895
- return "A name cannot step outside the destination folder.";
1896
- }
1897
- // A slash is the tree's ONLY way to make a directory — both backends create them on write — so
1898
- // It is allowed exactly where the field is a whole file name, and refused where it is a name.
1899
- if (normalized.includes("/") && choice !== undefined && picked !== OTHER_FORMAT) {
1900
- return `Pick Other… to create a file in a subfolder of ${dir === "." ? "the project root" : dir}.`;
1901
- }
1902
- /* A name whose extension MATCHES the pick is fine and is composed once, never doubled;
1903
- refusing every trailing extension would reject this dialog's own `untitled.json` default.
1904
- A name ending in an extension no format claims is a stem that happens to have a dot. */
1905
- const typedExt = extensionOfName(normalized);
1906
- if (
1907
- picked !== "" &&
1908
- picked !== OTHER_FORMAT &&
1909
- typedExt !== "" &&
1910
- typedExt.toLowerCase() !== picked.toLowerCase() &&
1911
- known.has(typedExt.toLowerCase())
1912
- ) {
1913
- const label = rows?.find((row) => row.value === picked)?.label ?? picked;
1914
- return `You picked ${label}; this name ends in ${typedExt}.`;
1915
- }
1916
- if (choice?.kind === "locked" && picked === OTHER_FORMAT) {
1917
- const foreign = typedExt !== "" && typedExt.toLowerCase() !== choice.ext.toLowerCase();
1918
- if (foreign && known.has(typedExt.toLowerCase())) {
1919
- return choice.because;
1920
- }
1921
- }
1922
- /* No emptiness check here: every way `fileNameFor` can answer "" is already refused above — a
1923
- blank field by the first rule, a display name that slugifies to nothing by the second. */
1924
- const candidate = fileNameFor(value, picked);
1925
- return taken.has(candidate.toLowerCase()) ? `${candidate} already exists in ${dir}/.` : "";
1926
- };
1869
+ const check: NewFileNameCheck = { choice, dir, known: knownDocumentExtensions(), rows, taken };
1870
+ const validate = (value: string, picked: string) => validateNewFileName(value, picked, check);
1927
1871
 
1928
1872
  let picked = initialPick;
1929
- const entered = await showPromptDialog(request.title ?? "New File", {
1930
- ...(rows === null
1931
- ? {}
1932
- : {
1933
- choice: {
1934
- initial: initialPick,
1935
- label: "Format",
1936
- onChange: (next: string) => {
1937
- picked = next;
1938
- },
1939
- options: () => rows,
1940
- },
1941
- }),
1873
+ const promptOptions: PromptDialogOptions = {
1942
1874
  confirmLabel: "Create",
1943
1875
  message: dir === "." ? "Creating in the project root." : `Creating in ${dir}/`,
1944
- ...(request.suggestedName === undefined ? {} : { placeholder: request.suggestedName }),
1945
1876
  // With a picker there is no extension in the field to preserve, so the whole name is the stem.
1946
1877
  select: rows === null ? "stem" : "all",
1947
1878
  validate,
1948
1879
  value: request.suggestedName ?? "untitled.json",
1949
- });
1880
+ };
1881
+ if (rows !== null) {
1882
+ promptOptions.choice = {
1883
+ initial: initialPick,
1884
+ label: "Format",
1885
+ onChange: (next: string) => {
1886
+ picked = next;
1887
+ },
1888
+ options: () => rows,
1889
+ };
1890
+ }
1891
+ if (request.suggestedName !== undefined) {
1892
+ promptOptions.placeholder = request.suggestedName;
1893
+ }
1894
+ const entered = await showPromptDialog(request.title ?? "New File", promptOptions);
1950
1895
  if (!entered) {
1951
1896
  return null;
1952
1897
  }
1953
1898
 
1954
- const fileName = fileNameFor(entered, picked);
1899
+ const fileName = composeNewFileName(entered, picked, choice);
1955
1900
  const path = dir === "." ? fileName : `${dir}/${fileName}`;
1956
- markLocalMutation(path);
1957
1901
  const format = formatForPath(fileName);
1958
- const suppliedBody =
1959
- typeof request.content === "function"
1960
- ? await request.content(extensionOfName(fileName), fileName)
1961
- : request.content;
1902
+ const suppliedBody = request.content;
1962
1903
  /*
1963
1904
  * What a new file starts as, in precedence order.
1964
1905
  *
@@ -1978,16 +1919,59 @@ export async function createFileIn(request: NewFileRequest): Promise<string | nu
1978
1919
  ? BLANK_DOCUMENT
1979
1920
  : "{}\n"
1980
1921
  : "");
1922
+ return writeNewFile(path, content, { dir, source });
1923
+ }
1924
+
1925
+ /**
1926
+ * The names already in `dir`, lower-cased — what a new name there must not collide with.
1927
+ *
1928
+ * A directory that cannot be listed answers empty: it is usually one that does not exist yet, and
1929
+ * the write that follows is the authority on whether that is a problem, reporting with the real
1930
+ * reason.
1931
+ */
1932
+ export async function listTakenNames(dir: string): Promise<Set<string>> {
1933
+ try {
1934
+ const listing = await getPlatform().listDirectory(dir);
1935
+ return new Set(listing.map((entry) => entry.name.toLowerCase()));
1936
+ } catch {
1937
+ return new Set();
1938
+ }
1939
+ }
1940
+
1941
+ /**
1942
+ * Write one new file: the second half of every creation flow, after its name has been judged.
1943
+ *
1944
+ * The local mutation is marked first, so the watcher's echo of this write is not mistaken for an
1945
+ * edit made outside Studio. The destination is re-listed so the tree shows the file, the success is
1946
+ * a toast, and a failure is a Problem carrying the path, since the thing the author must do next is
1947
+ * about that path. It does NOT open the file: what a new file opens in is the caller's to say.
1948
+ *
1949
+ * @param path Project-relative path of the file to create.
1950
+ * @param content Its first bytes.
1951
+ * @param opts `dir` is re-listed afterwards (defaults to the path's parent); `source` names the
1952
+ * flow in the Problem; `quiet` skips the success toast for a write that is one step of a larger
1953
+ * creation that reports once for all of them.
1954
+ * @returns The path, or `null` when the write failed.
1955
+ */
1956
+ export async function writeNewFile(
1957
+ path: string,
1958
+ content: string,
1959
+ opts: { dir?: string; source?: string; quiet?: boolean } = {},
1960
+ ): Promise<string | null> {
1961
+ const dir = opts.dir ?? (path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : ".");
1962
+ markLocalMutation(path);
1981
1963
  try {
1982
1964
  await getPlatform().writeFile(path, content);
1983
1965
  await loadDirectory(dir);
1984
- notify.success(`Created ${path}`);
1966
+ if (opts.quiet !== true) {
1967
+ notify.success(`Created ${path}`);
1968
+ }
1985
1969
  return path;
1986
1970
  } catch (error) {
1987
1971
  notify.error(`Could not create ${path}.`, {
1988
1972
  detail: errorMessage(error),
1989
1973
  path,
1990
- source,
1974
+ source: opts.source ?? "Files",
1991
1975
  });
1992
1976
  return null;
1993
1977
  }
@@ -2069,13 +2053,16 @@ async function createNewFile(dirPath: string, renderLeftPanel: () => void) {
2069
2053
  */
2070
2054
  async function showRenameFileDialog(currentName: string, path: string): Promise<string | null> {
2071
2055
  const message = await renamePromptMessage(path);
2072
- return showPromptDialog("Rename", {
2056
+ const promptOptions: PromptDialogOptions = {
2073
2057
  confirmLabel: "Rename",
2074
- ...(message === undefined ? {} : { message }),
2075
2058
  select: "stem",
2076
2059
  validate: (v) => (v.trim() ? "" : "Enter a file name."),
2077
2060
  value: currentName,
2078
- });
2061
+ };
2062
+ if (message !== undefined) {
2063
+ promptOptions.message = message;
2064
+ }
2065
+ return showPromptDialog("Rename", promptOptions);
2079
2066
  }
2080
2067
 
2081
2068
  /** Build the status-bar message for a rename, summarising any reference/tag rewrites. */
@@ -2248,6 +2235,13 @@ export interface OpenFileOpts {
2248
2235
  preview?: boolean;
2249
2236
  /** False leaves the keyboard where it is. Defaults to true. */
2250
2237
  focus?: boolean;
2238
+ /**
2239
+ * The canvas mode the tab is in when it becomes active, for an open that is not an edit: a
2240
+ * comparison opens straight into `git-diff`. Set BEFORE activation, because a tab's mode decides
2241
+ * which workspace it belongs to (`workspace/tab-workspace.ts`) and activation enters that
2242
+ * workspace; a mode set afterwards would visit the edit mode's workspace on the way.
2243
+ */
2244
+ canvasMode?: string;
2251
2245
  }
2252
2246
 
2253
2247
  /**
@@ -2300,6 +2294,9 @@ export async function openFileInTab(path: string, opts: OpenFileOpts = {}) {
2300
2294
  const follows = opts.focus !== false;
2301
2295
  for (const [id, tab] of workspace.tabs.entries()) {
2302
2296
  if (tab.documentPath === path) {
2297
+ if (opts.canvasMode !== undefined) {
2298
+ tab.session.ui.canvasMode = opts.canvasMode;
2299
+ }
2303
2300
  revealOpenTab(id, opts);
2304
2301
  // The tree's cursor answers "where is the author", so a side-open that deliberately left the
2305
2302
  // Keyboard behind must not move it.
@@ -2376,8 +2373,8 @@ export async function openFileInTab(path: string, opts: OpenFileOpts = {}) {
2376
2373
  }
2377
2374
 
2378
2375
  await loadFormats();
2379
- let document: Record<string, unknown>;
2380
- let frontmatter: Record<string, unknown> | undefined;
2376
+ let document: JxMutableNode | JsonObject;
2377
+ let frontmatter: FormatFrontmatter | undefined;
2381
2378
  // The layout the JSON was written in, so a save reproduces it (`json-layout.ts`, issue 308). A
2382
2379
  // Format-class file has none: its serializer owns its layout.
2383
2380
  let layout: JsonLayout | null = null;
@@ -2399,10 +2396,12 @@ export async function openFileInTab(path: string, opts: OpenFileOpts = {}) {
2399
2396
  document,
2400
2397
  ...(frontmatter != null && { frontmatter }),
2401
2398
  layout,
2399
+ source: format ? content : null,
2402
2400
  sourceFormat: format?.name ?? null,
2403
2401
  ...(opts.paneId !== undefined && { paneId: opts.paneId }),
2404
2402
  ...(opts.preview === true && { preview: true }),
2405
2403
  ...(opts.focus === false && { focus: false }),
2404
+ ...(opts.canvasMode !== undefined && { canvasMode: opts.canvasMode }),
2406
2405
  });
2407
2406
  if (follows) {
2408
2407
  requireProjectState().selectedPath = path;
@@ -2515,14 +2514,21 @@ export async function reloadFileInTab(path: string, opts: { onlyIfChanged?: bool
2515
2514
  }
2516
2515
  tab.doc.document = document;
2517
2516
  tab.doc.content.frontmatter = frontmatter;
2517
+ tab.doc.source = content;
2518
2518
  } else if (path.endsWith(".json")) {
2519
2519
  // The file changed under the tab, so its layout is whatever the new text says.
2520
2520
  const parsed = parseJsonDocument(content);
2521
2521
  tab.doc.layout = parsed.layout;
2522
- if (opts.onlyIfChanged && deepEqual(parsed.document, tab.doc.document)) {
2522
+ /* SAFETY: this tab was opened on this `.json` path as a Jx document, and the file's schema
2523
+ Makes its top-level object a node — the object `parseJsonDocument` states it returns. */
2524
+ const document = parsed.document as JxMutableNode;
2525
+ // The same member form the tab was opened in, so the comparison and every edit after it
2526
+ // Read one shape, and the record of what the file wrote is the new text's.
2527
+ tab.doc.bareRepeaters = normalizeDocument(document);
2528
+ if (opts.onlyIfChanged && deepEqual(document, tab.doc.document)) {
2523
2529
  return;
2524
2530
  }
2525
- tab.doc.document = parsed.document as JxMutableNode;
2531
+ tab.doc.document = document;
2526
2532
  }
2527
2533
  tab.doc.dirty = false;
2528
2534
  } catch (error) {
@@ -2553,6 +2559,10 @@ export function registerFilesPanel(): void {
2553
2559
  level: "project",
2554
2560
  dock: "navigator",
2555
2561
  icon: "folder",
2562
+ /* A developer panel (§5.1): the Site panel lists the project by what its files ARE, so the tree
2563
+ of where they are stored is on the Design rail only with **Show developer panels** on. With it
2564
+ off the panel is still `view.setActivity { tab: "files" }` and a palette row away. */
2565
+ rail: "developer",
2556
2566
  // The body is a document, so lit draws nothing and the mount happens against the painted DOM.
2557
2567
  // `afterRender` runs on every repaint; {@link mountFilesPanel} is idempotent.
2558
2568
  render: () => nothing,
@@ -2608,16 +2618,15 @@ let _lastValues: FilesPanelValues | null = null;
2608
2618
  * Draw the panel — mounting the document the first time, and re-projecting into it every time
2609
2619
  * after.
2610
2620
  *
2611
- * The document goes into `.panel-content`, not into the `.panel-body` this is handed, for the
2612
- * reason `panels/git-panel.ts` states: only one of them is the node lit renders this panel's body
2613
- * into, and appending to the other would leave the panel drawn under whatever the Navigator paints
2614
- * next.
2621
+ * The document goes into `.panel-content`, not into the `.panel-body` this is handed, because only
2622
+ * one of them is the node lit renders this panel's body into, and appending to the other would
2623
+ * leave the panel drawn under whatever the Navigator paints next.
2615
2624
  *
2616
- * The repaint stays the NAVIGATOR'S. Source Control owns an `effect()` because its inputs are the
2617
- * reactive `shell.git` record; the tree's inputs are a `Map` of directory listings, a `Set` of
2618
- * expanded paths and a roaming setting, none of which is reactive — so `ctx.rerender` is what this
2619
- * surface has always been redrawn by, and it stays that way rather than growing a second scheduler
2620
- * that could disagree with it.
2625
+ * The repaint stays the NAVIGATOR'S. The Publish workspace owns an `effect()` because its inputs
2626
+ * are the reactive `shell.git` record; the tree's inputs are a `Map` of directory listings, a `Set`
2627
+ * of expanded paths and a roaming setting, none of which is reactive — so `ctx.rerender` is what
2628
+ * this surface has always been redrawn by, and it stays that way rather than growing a second
2629
+ * scheduler that could disagree with it.
2621
2630
  *
2622
2631
  * @param host - The painted `.panel-body`
2623
2632
  * @param rerender - The Navigator's repaint
@@ -2652,7 +2661,7 @@ export function mountFilesPanel(host: HTMLElement, rerender: () => void): void {
2652
2661
  * Take the panel down: the document, the drag registrations, the scroll watch and the row handles.
2653
2662
  *
2654
2663
  * Exported because a project close has to reach it — the tree it is showing belongs to the project
2655
- * being left behind, exactly as `cleanupGitPanel` is for the working tree.
2664
+ * being left behind, exactly as `cleanupSourceControl` is for the working tree.
2656
2665
  */
2657
2666
  export function unmountFilesPanel(): void {
2658
2667
  dismissFileContextMenu();