@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
@@ -14,9 +14,9 @@
14
14
  * fill in and "absent" is a validation failure they did not cause.
15
15
  * 2. **Where the entry files are** is `collectionInfo`'s answer, imported rather than recomputed.
16
16
  * Three copies of "which collection owns this path, and what extension do its entries carry"
17
- * already exist (`utils/studio-utils.ts`'s `findContentTypeSchema`, `grid/sources/content-
18
- * source.ts`'s `collectionInfo`, `browse/library-model.ts`'s `contentTypeFor`); this module adds
19
- * no fourth and calls the two that are exported.
17
+ * existed when this was written (`utils/studio-utils.ts`'s `findContentTypeSchema`,
18
+ * `grid/sources/content-source.ts`'s `collectionInfo`, and `browse/library-model.ts`'s
19
+ * `contentTypeFor`, since deleted); this module adds no fourth and calls the exported ones.
20
20
  *
21
21
  * **The draft axis is NOT here.** `content/draft-state.ts` owns what a draft is and whether drafts
22
22
  * are listed, because this module imports `content-source.ts` and the grid source must be able to
@@ -27,7 +27,15 @@ import { collectionInfo } from "../grid/sources/content-source";
27
27
  import { projectState } from "../store";
28
28
  import { findContentTypeSchema } from "../utils/studio-utils";
29
29
  import type { ContentSectionEntry } from "../types";
30
- import type { ContentTypeSchema, ContentTypeSchemaField } from "@jxsuite/schema/types";
30
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
31
+ import type {
32
+ ContentTypeSchema,
33
+ ContentTypeSchemaField,
34
+ ContentTypeSchemaValue,
35
+ JsonObject,
36
+ JsonValue,
37
+ } from "@jxsuite/schema/types";
38
+ import type { EntryFields } from "./entry-fields";
31
39
 
32
40
  // ─── Collections ─────────────────────────────────────────────────────────────
33
41
 
@@ -44,7 +52,7 @@ export interface EntryCollection {
44
52
 
45
53
  /** Every content type the project declares, in declaration order. */
46
54
  export function collectionNames(): string[] {
47
- return Object.keys((projectState?.projectConfig?.content ?? {}) as Record<string, unknown>);
55
+ return Object.keys(projectState?.projectConfig?.content ?? {});
48
56
  }
49
57
 
50
58
  /**
@@ -91,15 +99,30 @@ export function collectionOfPath(path: string | null): EntryCollection | null {
91
99
  return matched ? entryCollection(matched.name) : null;
92
100
  }
93
101
 
102
+ /**
103
+ * The collection a file-backed collection's FILE holds the records of (`content/projects.csv`), or
104
+ * null. {@link entryCollection} refuses one, rightly, for everything that makes a new entry FILE; a
105
+ * record's form only reads its schema and its name, and `dir` is the file itself.
106
+ */
107
+ export function recordCollectionOfPath(path: string | null): EntryCollection | null {
108
+ const matched = findContentTypeSchema(path ?? null, projectState?.projectConfig);
109
+ const info = matched ? collectionInfo(matched.name) : null;
110
+ if (!matched || !info) {
111
+ return null;
112
+ }
113
+ return { def: info.def, dir: info.dir, ext: info.ext, name: info.name, schema: matched.schema };
114
+ }
115
+
94
116
  // ─── Seeding a new entry ─────────────────────────────────────────────────────
95
117
 
96
118
  /** Deep copy of a schema `default`, so two entries seeded from one schema never share an object. */
97
- function cloneDefault(value: unknown): unknown {
98
- if (value === null || typeof value !== "object") {
119
+ function cloneDefault(value: ContentTypeSchemaValue): JsonValue {
120
+ if (value === null || !isNonNullObject(value)) {
99
121
  return value;
100
122
  }
123
+ // SAFETY: `JSON.parse` of what `JSON.stringify` just wrote is JSON by construction.
101
124
  // oxlint-disable-next-line unicorn/prefer-structured-clone
102
- return JSON.parse(JSON.stringify(value)) as unknown;
125
+ return JSON.parse(JSON.stringify(value)) as JsonValue;
103
126
  }
104
127
 
105
128
  /**
@@ -109,8 +132,8 @@ function cloneDefault(value: unknown): unknown {
109
132
  * and picking an arbitrary entry of the target collection on the author's behalf would be inventing
110
133
  * a relationship they never stated.
111
134
  */
112
- function emptyForField(field: ContentTypeSchemaField): unknown {
113
- if (typeof field.$ref === "string") {
135
+ function emptyForField(field: ContentTypeSchemaField): JsonValue {
136
+ if (isString(field.$ref)) {
114
137
  return "";
115
138
  }
116
139
  switch (field.type) {
@@ -125,7 +148,7 @@ function emptyForField(field: ContentTypeSchemaField): unknown {
125
148
  return [];
126
149
  }
127
150
  case "object": {
128
- return seedEntry(field as ContentTypeSchema);
151
+ return seedEntry(field);
129
152
  }
130
153
  default: {
131
154
  return "";
@@ -145,13 +168,13 @@ function emptyForField(field: ContentTypeSchemaField): unknown {
145
168
  * author's file full of keys they never asked for, and "the schema mentions it" is not a reason for
146
169
  * it to exist on disk — the form still draws a row for it, because the form draws the SCHEMA.
147
170
  */
148
- export function seedEntry(schema: ContentTypeSchema | null | undefined): Record<string, unknown> {
171
+ export function seedEntry(schema: ContentTypeSchema | null | undefined): JsonObject {
149
172
  const properties = schema?.properties;
150
173
  if (!properties) {
151
174
  return {};
152
175
  }
153
- const required = new Set(Array.isArray(schema?.required) ? schema.required : []);
154
- const seed: Record<string, unknown> = {};
176
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
177
+ const seed: JsonObject = {};
155
178
  for (const [name, field] of Object.entries(properties)) {
156
179
  if (field.default !== undefined) {
157
180
  seed[name] = cloneDefault(field.default);
@@ -168,7 +191,7 @@ export function seedEntry(schema: ContentTypeSchema | null | undefined): Record<
168
191
  */
169
192
  export function missingRequired(
170
193
  schema: ContentTypeSchema | null | undefined,
171
- value: Record<string, unknown>,
194
+ value: EntryFields,
172
195
  ): string[] {
173
196
  const required = Array.isArray(schema?.required) ? schema.required : [];
174
197
  return required.filter((name) => value[name] === undefined);
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Opening a content entry: on the canvas in its writing editor, or in the form when it has no body.
3
+ *
4
+ * `specs/studio.md` §22.5: an entry is written on the canvas, inside its template's layout. Opening
5
+ * one opens the entry's OWN file as an ordinary tab — same id, history and dirty flag as a click in
6
+ * any file list — in its writing editor (`edit`), which the Content workspace owns (§22.1), so the
7
+ * Inspector's Entry tab and the writing-mode banner come with it. Every door into an entry goes
8
+ * through {@link openEntry}: a row in the Content home, an entry in the Collections panel,
9
+ * `content.openEntry`, and the entry Add new just made.
10
+ *
11
+ * The form-only `entry` editor (`content/entry-editor.ts`) stays as the fallback for an entry the
12
+ * canvas cannot write: a JSON entry IS its fields and has no body, and a file-backed collection's
13
+ * entries are rows of one file, which open in the grid.
14
+ *
15
+ * @docs studio/projects/content-types
16
+ */
17
+
18
+ import { activateTab, workspace } from "../workspace/workspace";
19
+ import { collectionForFile } from "./collection-match";
20
+ import { writesEntryOnCanvas } from "./content-collections";
21
+ import { openEntryEditor } from "./entry-editor";
22
+ import type { Tab } from "../tabs/tab";
23
+
24
+ /** The editor an entry is written in on the canvas. */
25
+ export const WRITING_MODE = "edit";
26
+
27
+ /** The editors a tab already writes on the canvas in, which an open leaves alone. */
28
+ const CANVAS_MODES: ReadonlySet<string> = new Set(["edit", "design"]);
29
+
30
+ /**
31
+ * The open tab for a path, if any (a document tab's id is its path, but a renamed one keeps its
32
+ * id).
33
+ */
34
+ function tabFor(path: string): Tab | null {
35
+ for (const tab of workspace.tabs.values()) {
36
+ if (tab.documentPath === path) {
37
+ return tab;
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+
43
+ /**
44
+ * Open a content entry where it is written.
45
+ *
46
+ * - An entry with a body opens on the canvas in `edit`. A tab already writing it on the canvas
47
+ * (`edit` or `design`) keeps its view; a tab showing its form is switched back to writing.
48
+ * - A JSON entry opens in the form editor.
49
+ * - Any other file opens as `openFileInTab` would open it.
50
+ *
51
+ * @returns The tab, or `null` when the file could not be opened.
52
+ */
53
+ export async function openEntry(path: string): Promise<Tab | null> {
54
+ if (!writesEntryOnCanvas(path)) {
55
+ const match = collectionForFile(path);
56
+ if (match && !match.fileBacked) {
57
+ return openEntryEditor(path);
58
+ }
59
+ /* Dynamic for the reason `entry-editor.ts` gives: `files/files.ts` reaches the platform, the
60
+ format registry and the packages layer. */
61
+ const { openFileInTab } = await import("../files/files");
62
+ await openFileInTab(path);
63
+ return tabFor(path);
64
+ }
65
+ const { openFileInTab } = await import("../files/files");
66
+ await openFileInTab(path);
67
+ const tab = tabFor(path);
68
+ if (!tab) {
69
+ return null;
70
+ }
71
+ if (
72
+ !CANVAS_MODES.has(tab.session.ui.canvasMode) &&
73
+ tab.capabilities.modes.includes(WRITING_MODE)
74
+ ) {
75
+ tab.session.ui.canvasMode = WRITING_MODE;
76
+ tab.session.ui.preview = false;
77
+ }
78
+ activateTab(tab.id);
79
+ return tab;
80
+ }
@@ -0,0 +1,440 @@
1
+ /**
2
+ * What the Collections panel says about each entry while one is being written: its title, its
3
+ * status and a thumbnail (`specs/studio.md` §22.5, the Content-Entry board's list).
4
+ *
5
+ * The scan behind the Content home knows each entry's FILE (`browse/library-model.ts`); a title and
6
+ * a draft flag are inside it. So this reads each entry once — a JSON entry's root, a Markdown
7
+ * entry's frontmatter, through the same parse the editor uses — and keeps the answer until a file
8
+ * event drops it ({@link invalidateEntrySummaries}, wired beside the scan's own invalidation in
9
+ * `studio.ts`). A collection is read when its list is first shown, not before: the panel lists one
10
+ * collection's entries at a time.
11
+ *
12
+ * The read never rejects. An entry that cannot be read is listed under its file name with no
13
+ * status, which is what the file list would have said about it anyway.
14
+ *
15
+ * @docs studio/projects/browse
16
+ */
17
+
18
+ import {
19
+ isBoolean,
20
+ isJsonObject,
21
+ isNonNullObject,
22
+ isNumber,
23
+ isString,
24
+ } from "@jxsuite/schema/guards";
25
+ import { getPlatform, hasPlatform } from "../platform";
26
+ import { isImage } from "../files/media-upload";
27
+ import { previewFileSrc } from "../files/media-paths";
28
+ import { hasDraftAxis, isDraftEntry } from "./draft-state";
29
+ import { entryCollection } from "./entry-model";
30
+ import { PAGES_COLLECTION, collectionKeyOfPath } from "./content-collections";
31
+ import type { EntryFields } from "./entry-fields";
32
+ import type { ContentTypeSchema, ContentTypeSchemaField } from "@jxsuite/schema/types";
33
+
34
+ /** One entry, as the Collections panel lists it. */
35
+ export interface EntrySummary {
36
+ path: string;
37
+ /** The entry's `title`, or its file name without the extension. */
38
+ title: string;
39
+ /** "Draft", "Published", or "" for a collection with no draft workflow. */
40
+ status: string;
41
+ /** A preview URL for the entry's first image field, or "" for none. */
42
+ thumb: string;
43
+ /** The entry's own date as `YYYY-MM-DD`, from its schema's date field, or "" for none. */
44
+ date: string;
45
+ /**
46
+ * Each field the collection's schema declares and the entry holds, as the text a list cell shows.
47
+ * Absent from a summary the read did not reach.
48
+ */
49
+ fields?: EntryFieldTexts;
50
+ }
51
+
52
+ /** An entry's declared fields as list text, keyed by field name. */
53
+ export type EntryFieldTexts = Readonly<Record<string, string>>;
54
+
55
+ /** Field names that mean "what this entry is called", in the order they are preferred. */
56
+ const TITLE_FIELD_NAMES = ["title", "name", "label", "heading"];
57
+
58
+ /**
59
+ * The field an entry is called by: `title` where there is one, else the first conventionally named
60
+ * field (`name`, `label`, `heading`) the schema declares or the entry holds. A menu item with a
61
+ * `name` and no `title` is "Espresso Tiramisu", not `tiramisu`.
62
+ */
63
+ export function titleFieldOf(
64
+ schema: ContentTypeSchema | null | undefined,
65
+ fields: EntryFields = {},
66
+ ): string | null {
67
+ // Whatever its capitalisation: a CSV's header row is often `Title`, and it is still the title.
68
+ const named = (keys: readonly string[]): string | null => {
69
+ for (const wanted of TITLE_FIELD_NAMES) {
70
+ const key = keys.find((candidate) => candidate.toLowerCase() === wanted);
71
+ if (key !== undefined) {
72
+ return key;
73
+ }
74
+ }
75
+ return null;
76
+ };
77
+ return (
78
+ named(Object.keys(schema?.properties ?? {})) ??
79
+ named(Object.keys(fields).filter((key) => isString(fields[key])))
80
+ );
81
+ }
82
+
83
+ /** A field value as list text: a scalar as written, a list of scalars joined, anything else "". */
84
+ export function fieldText(value: EntryFields[string] | Date | undefined): string {
85
+ if (value instanceof Date) {
86
+ return entryDay(value);
87
+ }
88
+ if (isString(value)) {
89
+ return value;
90
+ }
91
+ if (isNumber(value) || isBoolean(value)) {
92
+ return String(value);
93
+ }
94
+ if (Array.isArray(value)) {
95
+ return value
96
+ .filter((item) => isString(item) || isNumber(item))
97
+ .map(String)
98
+ .join(", ");
99
+ }
100
+ return "";
101
+ }
102
+
103
+ /** The text of every field the schema declares and the entry holds. */
104
+ function fieldTexts(
105
+ schema: ContentTypeSchema | null | undefined,
106
+ fields: EntryFields,
107
+ ): EntryFieldTexts {
108
+ return Object.fromEntries(
109
+ Object.keys(schema?.properties ?? {})
110
+ .filter((name) => name in fields)
111
+ .map((name) => [name, fieldText(fields[name])]),
112
+ );
113
+ }
114
+
115
+ /** Field names that mean "when this entry is dated" when the schema types no field as a date. */
116
+ const DATE_FIELD_NAMES = ["date", "published", "publishedAt", "pubDate", "publishDate"];
117
+
118
+ /**
119
+ * The field an entry is dated by: the first schema property typed `format: date` or `date-time`,
120
+ * else the first conventionally named one present in the entry.
121
+ */
122
+ export function dateFieldOf(
123
+ schema: ContentTypeSchema | null | undefined,
124
+ fields: EntryFields,
125
+ ): string | null {
126
+ for (const [name, field] of Object.entries(schema?.properties ?? {})) {
127
+ if (field.format === "date" || field.format === "date-time") {
128
+ return name;
129
+ }
130
+ }
131
+ return DATE_FIELD_NAMES.find((name) => name in fields) ?? null;
132
+ }
133
+
134
+ /**
135
+ * The field a collection's SCHEMA says its entries are dated by, before any entry is read: the
136
+ * first property typed `format: date` or `date-time`, else the first conventionally named property
137
+ * it declares (a `date` with no format is still the date). The Table draws that field in its Date
138
+ * column, so it is the one field column it must not draw a second time.
139
+ */
140
+ export function declaredDateField(schema: ContentTypeSchema | null | undefined): string | null {
141
+ const properties = schema?.properties ?? {};
142
+ return dateFieldOf(schema, Object.fromEntries(Object.keys(properties).map((name) => [name, ""])));
143
+ }
144
+
145
+ /**
146
+ * A date value as `YYYY-MM-DD`, or "". A value that already starts with a calendar date is taken as
147
+ * written, so a date is never shifted a day by a time zone; anything else must parse.
148
+ */
149
+ export function entryDay(value: EntryFields[string] | Date): string {
150
+ if (value instanceof Date) {
151
+ return Number.isNaN(value.getTime()) ? "" : value.toISOString().slice(0, 10);
152
+ }
153
+ if (!isString(value)) {
154
+ return "";
155
+ }
156
+ const written = /^(\d{4}-\d{2}-\d{2})/.exec(value.trim());
157
+ if (written) {
158
+ return written[1]!;
159
+ }
160
+ const parsed = new Date(value);
161
+ if (value.trim() === "" || Number.isNaN(parsed.getTime())) {
162
+ return "";
163
+ }
164
+ if (!value.includes(":")) {
165
+ /* A date with no time of day (`6/3/2026`, `March 4, 2026`) parses as LOCAL midnight, so its
166
+ UTC day is the day before anywhere east of Greenwich: the day is read where it was parsed. */
167
+ const month = String(parsed.getMonth() + 1).padStart(2, "0");
168
+ const day = String(parsed.getDate()).padStart(2, "0");
169
+ return `${parsed.getFullYear()}-${month}-${day}`;
170
+ }
171
+ return parsed.toISOString().slice(0, 10);
172
+ }
173
+
174
+ /** The file name without its extension: `content/posts/hello.md` → `hello`. */
175
+ export function entryStem(path: string): string {
176
+ const base = path.split("/").pop() ?? path;
177
+ const dot = base.lastIndexOf(".");
178
+ return dot > 0 ? base.slice(0, dot) : base;
179
+ }
180
+
181
+ /**
182
+ * The project path an image field names, resolved the way the entry's own page resolves it: a
183
+ * root-relative URL is served from `public/`, anything else is relative to the entry's folder.
184
+ */
185
+ export function imageFieldPath(entryPath: string, value: string): string {
186
+ if (value.startsWith("/")) {
187
+ return `public${value}`;
188
+ }
189
+ const dir = entryPath.includes("/") ? entryPath.slice(0, entryPath.lastIndexOf("/")) : "";
190
+ const parts = [...(dir === "" ? [] : dir.split("/")), ...value.split("/")];
191
+ const out: string[] = [];
192
+ for (const part of parts) {
193
+ if (part === "" || part === ".") {
194
+ continue;
195
+ }
196
+ if (part === "..") {
197
+ out.pop();
198
+ } else {
199
+ out.push(part);
200
+ }
201
+ }
202
+ return out.join("/");
203
+ }
204
+
205
+ /** A URL with a scheme (`https://…`, `data:…`): a picture somewhere else, shown as it is. */
206
+ const ABSOLUTE_URL = /^[a-z][\d+.a-z-]*:/i;
207
+
208
+ /** An image field's value as the URL a thumbnail is drawn from, or "" for no picture. */
209
+ function thumbSrc(entryPath: string, value: string): string {
210
+ const trimmed = value.trim();
211
+ if (trimmed === "") {
212
+ return "";
213
+ }
214
+ return ABSOLUTE_URL.test(trimmed) ? trimmed : previewFileSrc(imageFieldPath(entryPath, trimmed));
215
+ }
216
+
217
+ /**
218
+ * The picture a field holds, when it is one: an image path, an image object's `src`
219
+ * (`featuredImage: { src, alt }`), or a list of them (its first).
220
+ */
221
+ function pictureIn(value: EntryFields[string]): string {
222
+ if (isString(value)) {
223
+ // A CSV keeps a gallery as one cell, its URLs separated by commas.
224
+ return value.split(",")[0]?.trim() ?? "";
225
+ }
226
+ if (Array.isArray(value)) {
227
+ const [first] = value;
228
+ return first === undefined ? "" : pictureIn(first);
229
+ }
230
+ if (isJsonObject(value)) {
231
+ const { src } = value;
232
+ return isString(src) ? src : "";
233
+ }
234
+ return "";
235
+ }
236
+
237
+ /** Whether a schema property holds a picture: `format: image`, an image object, or a list of either. */
238
+ function isPictureField(field: ContentTypeSchemaField): boolean {
239
+ if (field.format === "image") {
240
+ return true;
241
+ }
242
+ const src = field.properties?.["src"];
243
+ if (field.type === "object" && src?.type === "string") {
244
+ return true;
245
+ }
246
+ return field.type === "array" && field.items !== undefined && isPictureField(field.items);
247
+ }
248
+
249
+ /**
250
+ * An entry's thumbnail: the first field its SCHEMA declares as a picture that holds one, so a post
251
+ * is shown by its `cover` and not by whatever image path happens to come first; else the first
252
+ * field whose value is an image file. A preview URL, or "" for none.
253
+ */
254
+ export function entryThumb(
255
+ entryPath: string,
256
+ fields: EntryFields,
257
+ schema: ContentTypeSchema | null | undefined,
258
+ ): string {
259
+ for (const [name, field] of Object.entries(schema?.properties ?? {})) {
260
+ if (isPictureField(field)) {
261
+ const src = thumbSrc(entryPath, pictureIn(fields[name]));
262
+ if (src !== "") {
263
+ return src;
264
+ }
265
+ }
266
+ }
267
+ for (const value of Object.values(fields)) {
268
+ if (!isString(value) || ABSOLUTE_URL.test(value)) {
269
+ continue;
270
+ }
271
+ const dot = value.lastIndexOf(".");
272
+ if (dot > 0 && isImage(value.slice(dot))) {
273
+ return previewFileSrc(imageFieldPath(entryPath, value));
274
+ }
275
+ }
276
+ return "";
277
+ }
278
+
279
+ /** One entry's summary, from its fields. Pure. */
280
+ export function summarize(path: string, collection: string, fields: EntryFields): EntrySummary {
281
+ const schema = entryCollection(collection)?.schema ?? null;
282
+ const titleField = titleFieldOf(schema, fields);
283
+ const title = titleField === null ? undefined : fields[titleField];
284
+ const draft = isDraftEntry(fields);
285
+ const dateField = dateFieldOf(schema, fields);
286
+ return {
287
+ date: dateField === null ? "" : entryDay(fields[dateField]),
288
+ fields: fieldTexts(schema, fields),
289
+ path,
290
+ status: hasDraftAxis(schema, fields) ? (draft ? "Draft" : "Published") : "",
291
+ thumb: entryThumb(path, fields, schema),
292
+ title: isString(title) && title.trim() !== "" ? title : entryStem(path),
293
+ };
294
+ }
295
+
296
+ /** Read one entry's fields: a JSON entry's root, any other entry's frontmatter. */
297
+ async function readFields(path: string): Promise<EntryFields> {
298
+ try {
299
+ const source = await getPlatform().readFile(path);
300
+ if (path.endsWith(".json")) {
301
+ const parsed: unknown = JSON.parse(source);
302
+ /* SAFETY: a JSON entry is an object of fields (its collection's schema says so); a value
303
+ that is not an object has no fields, which is what the fallback below says. */
304
+ return isNonNullObject(parsed) && !Array.isArray(parsed) ? (parsed as EntryFields) : {};
305
+ }
306
+ const { parseSourceForPath } = await import("../files/file-ops");
307
+ const parsed = await parseSourceForPath(path, source);
308
+ return parsed.frontmatter;
309
+ } catch {
310
+ return {};
311
+ }
312
+ }
313
+
314
+ // ─── The cache ───────────────────────────────────────────────────────────────
315
+
316
+ /** Entries read, keyed by collection and then by the paths listed, so a changed list re-reads. */
317
+ const _cache = new Map<string, { key: string; entries: EntrySummary[] }>();
318
+ const _loading = new Map<string, Promise<EntrySummary[]>>();
319
+ let _epoch = 0;
320
+ const _listeners = new Set<() => void>();
321
+
322
+ /** At most this many entries are read for one list; the rest are listed by file name. */
323
+ export const SUMMARY_READ_LIMIT = 200;
324
+
325
+ /** Read a collection's entries. */
326
+ async function readSummaries(
327
+ collection: string,
328
+ paths: readonly string[],
329
+ ): Promise<EntrySummary[]> {
330
+ const read = paths.slice(0, SUMMARY_READ_LIMIT);
331
+ const summaries = await Promise.all(
332
+ read.map(async (path) => summarize(path, collection, await readFields(path))),
333
+ );
334
+ const rest = paths.slice(SUMMARY_READ_LIMIT).map((path): EntrySummary => ({
335
+ date: "",
336
+ path,
337
+ status: "",
338
+ thumb: "",
339
+ title: entryStem(path),
340
+ }));
341
+ return [...summaries, ...rest];
342
+ }
343
+
344
+ /**
345
+ * A collection's entries as they stand: the summaries, or `null` while they are being read (which
346
+ * starts the read; listeners are told when it lands).
347
+ *
348
+ * @param collection - The collection's name.
349
+ * @param paths - Its entry files, in the order to list them.
350
+ */
351
+ export function peekEntrySummaries(
352
+ collection: string,
353
+ paths: readonly string[],
354
+ ): EntrySummary[] | null {
355
+ const key = paths.join("\n");
356
+ const cached = _cache.get(collection);
357
+ if (cached?.key === key) {
358
+ return cached.entries;
359
+ }
360
+ if (!hasPlatform()) {
361
+ return paths.map((path) => ({ date: "", path, status: "", thumb: "", title: entryStem(path) }));
362
+ }
363
+ const inFlight = `${collection}\n${key}`;
364
+ if (!_loading.has(inFlight)) {
365
+ const epoch = _epoch;
366
+ const read: Promise<EntrySummary[]> = readSummaries(collection, paths).then((entries) => {
367
+ /* Only this read's own record: an invalidation in between may have handed the key to a newer
368
+ read, and deleting THAT record would let the next peek start a duplicate of it. */
369
+ if (_loading.get(inFlight) === read) {
370
+ _loading.delete(inFlight);
371
+ }
372
+ if (epoch === _epoch) {
373
+ _cache.set(collection, { entries, key });
374
+ for (const listener of _listeners) {
375
+ listener();
376
+ }
377
+ }
378
+ return entries;
379
+ });
380
+ _loading.set(inFlight, read);
381
+ }
382
+ return null;
383
+ }
384
+
385
+ /**
386
+ * Restate one entry from the fields Studio just saved, without reading the file back.
387
+ *
388
+ * A save is Studio's own write, so the fields it wrote are the answer, and re-reading them is both
389
+ * slower and wrong: the dev server lets a file read be cached for five seconds, and its watcher
390
+ * skips some trees outright, so the list kept the old title after an author renamed an entry and
391
+ * pressed Save. An entry no cached list holds is left to that list's own first read.
392
+ *
393
+ * @returns Whether a cached list held the entry and now states the saved fields.
394
+ */
395
+ export function noteEntrySaved(path: string, collection: string, fields: EntryFields): boolean {
396
+ const cached = _cache.get(collection);
397
+ const index = cached?.entries.findIndex((entry) => entry.path === path) ?? -1;
398
+ if (!cached || index === -1) {
399
+ return false;
400
+ }
401
+ const entries = cached.entries.with(index, summarize(path, collection, fields));
402
+ _cache.set(collection, { entries, key: cached.key });
403
+ for (const listener of _listeners) {
404
+ listener();
405
+ }
406
+ return true;
407
+ }
408
+
409
+ /**
410
+ * After a document saved: restate its entry, when it is one, from the fields it saved.
411
+ *
412
+ * The caller says where the fields live (`entryFields(tab)`, the live record, not a copy), which
413
+ * keeps the editor's field store out of this data module's graph.
414
+ *
415
+ * @param path The saved document's path, or `null` for one with no file.
416
+ * @param fields The saved document's fields: a JSON entry's root, any other entry's frontmatter.
417
+ * @returns Whether a cached list changed, so the caller knows a repaint is due.
418
+ */
419
+ export function noteSavedEntry(path: string | null, fields: EntryFields): boolean {
420
+ const collection = collectionKeyOfPath(path);
421
+ if (path === null || collection === null || collection === PAGES_COLLECTION) {
422
+ return false;
423
+ }
424
+ return noteEntrySaved(path, collection, fields);
425
+ }
426
+
427
+ /** Forget every summary. The next list re-reads its entries. */
428
+ export function invalidateEntrySummaries(): void {
429
+ _epoch += 1;
430
+ _cache.clear();
431
+ _loading.clear();
432
+ }
433
+
434
+ /** Be told when a read lands. Returns the function that stops it. */
435
+ export function onEntrySummariesRead(listener: () => void): () => void {
436
+ _listeners.add(listener);
437
+ return () => {
438
+ _listeners.delete(listener);
439
+ };
440
+ }