@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
@@ -22,18 +22,28 @@
22
22
  import {
23
23
  buildScope,
24
24
  renderNode,
25
+ runScoped,
25
26
  setCanvasAssetResolver,
27
+ setNpmModuleResolver,
28
+ setResolveToken,
26
29
  setSkipServerFunctions,
30
+ setTemplateErrorHandler,
27
31
  } from "@jxsuite/runtime";
32
+ import { isFunction, isNonNullObject } from "@jxsuite/schema/guards";
28
33
  import { assetContextFor, hostAssetDeclarations, resolveAssetRef } from "../canvas/asset-refs";
34
+ import { canvasBaseOrigin, documentBase, hostResolveToken } from "../canvas/canvas-origin";
35
+ import { npmModuleUrl } from "../canvas/npm-modules";
36
+ import { projectState } from "../store";
29
37
  import { assetVersionsSnapshot } from "../files/asset-versions";
30
38
  import { componentRegistry } from "../files/components";
31
39
  import { getPlatform } from "../platform";
32
40
  import { loadFormats, formatForPath } from "../format/format-host";
33
41
  import { parseSourceForPath } from "../files/file-ops";
34
- import { renderComponentPreview } from "../panels/component-preview";
42
+ import { defineComponent, renderComponentPreview } from "../panels/component-preview";
43
+ import { componentExampleProps, componentSampleRow } from "./component-examples";
44
+ import { loadProjectPreviewSheets } from "./preview-style";
35
45
  import type { ComponentEntry } from "../files/components";
36
- import type { JxDocument } from "@jxsuite/schema/types";
46
+ import type { JsonValue, JxDocument } from "@jxsuite/schema/types";
37
47
 
38
48
  /**
39
49
  * How many rendered previews stay alive at once.
@@ -74,12 +84,13 @@ export function createPreviewCache(limit: number = PREVIEW_CACHE_LIMIT): Preview
74
84
  const entries = new Map<string, HTMLElement>();
75
85
 
76
86
  function evict() {
77
- // `size > limit` guarantees a first key, so the iterator result is never `done` here.
78
- while (entries.size > limit) {
79
- const oldest = entries.keys().next().value as string;
80
- const stale = entries.get(oldest);
87
+ // Insertion order is LRU order, and deleting the entry being visited is safe mid-iteration.
88
+ for (const [oldest, stale] of entries) {
89
+ if (entries.size <= limit) {
90
+ break;
91
+ }
81
92
  entries.delete(oldest);
82
- stale?.remove();
93
+ stale.remove();
83
94
  }
84
95
  }
85
96
 
@@ -111,6 +122,16 @@ export function createPreviewCache(limit: number = PREVIEW_CACHE_LIMIT): Preview
111
122
 
112
123
  // ─── Rendering one preview ───────────────────────────────────────────────────
113
124
 
125
+ /**
126
+ * The URL a previewed document's relative refs resolve against: the file's own URL under the
127
+ * project, as the canvas spells it. A shell with an opaque origin (a custom-scheme shell such as
128
+ * `views://`) has no such URL to build, and keeps the shell's own address.
129
+ */
130
+ function previewBase(filePath: string): string {
131
+ const base = documentBase(projectState?.projectRoot);
132
+ return URL.canParse(base) ? new URL(filePath, base).href : location.href;
133
+ }
134
+
114
135
  /**
115
136
  * Render a page/layout/content document to a detached element, or null when it cannot be rendered.
116
137
  *
@@ -127,30 +148,137 @@ export async function renderDocPreview(filePath: string): Promise<HTMLElement |
127
148
  let document_: JxDocument;
128
149
  if (formatForPath(filePath)) {
129
150
  const parsed = await parseSourceForPath(filePath, content);
151
+ /* SAFETY: a format class's parser returns its file as a Jx element tree (the format contract),
152
+ and the split hands that same tree back as `document`; a tree renderNode cannot draw throws
153
+ into the catch below, which is "no preview". */
130
154
  document_ = parsed.document as JxDocument;
131
155
  } else {
156
+ /* SAFETY: a `.json` file in the Library is a project document by the project layout; malformed
157
+ JSON or a shape renderNode cannot draw throws into the catch below, which is "no preview". */
132
158
  document_ = JSON.parse(content) as JxDocument;
133
159
  }
134
- const scope = await buildScope(document_, {}, location.href);
135
- /* This render lands in the PARENT document, so an `<img src="/hero.jpg">` inside it resolves
136
- against `index.html` — which is the shell, not the site. Same hook the canvas installs, same
137
- context, restored afterwards because the next preview is a different document and a stale
138
- `documentDir` would resolve its relative refs against the wrong entry. The version map is
139
- read as the render starts, after the reads above: the Library is the many-images screen,
140
- and a versioned src is what lets its cards repaint from the browser cache. */
141
- const assets = context && { ...context, versions: assetVersionsSnapshot() };
142
- setCanvasAssetResolver((value) => resolveAssetRef(value, assets));
143
- try {
144
- const element = renderNode(document_, scope);
145
- return element instanceof HTMLElement ? element : null;
146
- } finally {
147
- setCanvasAssetResolver(null);
148
- }
160
+ return await renderDocument(document_, filePath, context);
161
+ } catch {
162
+ return null;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Render a document as the file `filePath` holds it would be drawn: its refs resolved from that
168
+ * file's URL, its media through the canvas's resolver. Throws what the render throws.
169
+ */
170
+ async function renderDocument(
171
+ document_: JxDocument,
172
+ filePath: string,
173
+ context = assetContextFor(filePath, hostAssetDeclarations()),
174
+ ): Promise<HTMLElement | null> {
175
+ setSkipServerFunctions(true);
176
+ /* The document's own URL, as the canvas spells it, and the canvas's dev-proxy token. With the
177
+ shell's `location.href` as base, a page's `"$src": "../../scripts/x.class.json"` resolved
178
+ against `/__studio__/`, and without the token the proxy refused it before reading it. */
179
+ setResolveToken(hostResolveToken());
180
+ const scope = await buildScope(document_, {}, previewBase(filePath));
181
+ /* This render lands in the PARENT document, so an `<img src="/hero.jpg">` inside it resolves
182
+ against `index.html` — which is the shell, not the site. Same hook the canvas installs, same
183
+ context, restored afterwards because the next preview is a different document and a stale
184
+ `documentDir` would resolve its relative refs against the wrong entry. The version map is
185
+ read as the render starts, after the reads above: the Library is the many-images screen,
186
+ and a versioned src is what lets its cards repaint from the browser cache. */
187
+ const assets = context && { ...context, versions: assetVersionsSnapshot() };
188
+ setCanvasAssetResolver((value) => resolveAssetRef(value, assets));
189
+ try {
190
+ const element = renderNode(document_, scope);
191
+ return element instanceof HTMLElement ? element : null;
192
+ } finally {
193
+ setCanvasAssetResolver(null);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * A project component's preview: an instance given its sample props when it renders with them, else
199
+ * the first row of a list that draws it (`component-examples.ts`), else none.
200
+ */
201
+ async function projectComponentPreview(
202
+ component: ComponentEntry,
203
+ path: string,
204
+ ): Promise<HTMLElement | null> {
205
+ const definition = await readDefinition(path);
206
+ if (!definition) {
207
+ return null;
208
+ }
209
+ const props = await componentExampleProps(definition, path);
210
+ if (props.size > 0 && (await rendersWith(definition, path, props))) {
211
+ return renderComponentPreview(component, props);
212
+ }
213
+ const sample = await componentSampleRow(definition, path);
214
+ if (sample && (await defineComponent(component))) {
215
+ return renderDocument(sample.doc, sample.file);
216
+ }
217
+ return (await rendersWith(definition, path, props))
218
+ ? renderComponentPreview(component, props)
219
+ : null;
220
+ }
221
+
222
+ /** A project component's definition, or null when its file is not one. */
223
+ export async function readDefinition(path: string): Promise<JxDocument | null> {
224
+ try {
225
+ const parsed: unknown = JSON.parse(await getPlatform().readFile(path));
226
+ /* SAFETY: a project component's `.json` is its definition, a Jx element document; a shape
227
+ renderNode cannot draw throws into `rendersWith`'s catch, which is "does not render". */
228
+ return isNonNullObject(parsed) && !Array.isArray(parsed) ? (parsed as JxDocument) : null;
149
229
  } catch {
150
230
  return null;
151
231
  }
152
232
  }
153
233
 
234
+ /**
235
+ * Whether `definition` renders given `props` (its sample props, `component-examples.ts`), tried on
236
+ * a detached copy before a live instance is made.
237
+ *
238
+ * A definition may not render with the values it is given: the museum starter's
239
+ * `<mu-exhibition-card>` formats a `date` that defaults to `""`, and `Intl/formatDate` of an empty
240
+ * date is a `RangeError`, exactly as `new Intl.DateTimeFormat().format(new Date(""))` is (`spec.md`
241
+ * §19.4c). An instance renders in its own async `connectedCallback`, where the throw is reported on
242
+ * the console once per card per paint. The same render, made here synchronously into an element
243
+ * nobody sees, can be caught, and a definition that cannot render gets no instance preview.
244
+ */
245
+ export async function rendersWith(
246
+ definition: JxDocument,
247
+ path: string,
248
+ props: ReadonlyMap<string, JsonValue>,
249
+ ): Promise<boolean> {
250
+ let stopRender: (() => void) | null = null;
251
+ try {
252
+ setSkipServerFunctions(true);
253
+ setResolveToken(hostResolveToken());
254
+ const scope = await buildScope(definition, {}, previewBase(path));
255
+ for (const [name, value] of props) {
256
+ scope[name] = value;
257
+ }
258
+ /* A template binding that throws no longer unwinds the render (spec.md §6.1): it draws nothing
259
+ and waits for its data. The trial still has to see it, so the throw is collected for the one
260
+ synchronous render, as the render critic collects it. */
261
+ let bindingThrew = false;
262
+ setTemplateErrorHandler(() => {
263
+ bindingThrew = true;
264
+ });
265
+ // Its own tag would make an instance, and the instance's render is the one that cannot be caught.
266
+ const { stop } = runScoped(() => renderNode({ ...definition, tagName: "div" }, scope));
267
+ stopRender = stop;
268
+ return !bindingThrew;
269
+ } catch {
270
+ return false;
271
+ } finally {
272
+ setTemplateErrorHandler(null);
273
+ stopRender?.();
274
+ }
275
+ }
276
+
277
+ /** A component whose definition is a JSON file in the project, which is what can be tried first. */
278
+ function isProjectDefinition(component: ComponentEntry): boolean {
279
+ return component.source !== "npm" && (component.path?.endsWith(".json") ?? false);
280
+ }
281
+
154
282
  /**
155
283
  * The preview for one file — a registered component's own preview when there is one, the document
156
284
  * render otherwise. Cached; a cache hit does no work at all.
@@ -165,10 +293,17 @@ export async function previewFor(
165
293
  }
166
294
  let rendered: HTMLElement | null | undefined;
167
295
  try {
296
+ /* A component's `npm:` sidecar, from where the project's packages are served: a preview is a
297
+ live render in this window, and the runtime would otherwise hand `import()` the `npm:` URL. */
298
+ setNpmModuleResolver((specifier) => npmModuleUrl(specifier, `${canvasBaseOrigin()}/`));
299
+ // The project's stylesheet, ready for the box this preview is shown in (`preview-style.ts`).
300
+ await loadProjectPreviewSheets();
168
301
  const component = componentRegistry.find((c: ComponentEntry) => c.path === path);
169
- rendered = component
170
- ? ((await renderComponentPreview(component)) as HTMLElement | undefined)
171
- : await renderDocPreview(path);
302
+ if (component && isProjectDefinition(component)) {
303
+ rendered = await projectComponentPreview(component, path);
304
+ } else {
305
+ rendered = component ? await renderComponentPreview(component) : await renderDocPreview(path);
306
+ }
172
307
  } catch {
173
308
  return undefined;
174
309
  }
@@ -219,7 +354,7 @@ export interface PreviewObserver {
219
354
  * retained on that path, so there is nothing for the sweep to find.
220
355
  */
221
356
  export function createPreviewObserver(onVisible: (element: Element) => void): PreviewObserver {
222
- if (typeof IntersectionObserver !== "function") {
357
+ if (!isFunction(globalThis.IntersectionObserver)) {
223
358
  return {
224
359
  destroy() {
225
360
  /* Nothing to disconnect. */
@@ -1,11 +1,11 @@
1
1
  /**
2
- * The Library as a {@link GridSource}.
2
+ * The Content home's scan, as a {@link GridSource}.
3
3
  *
4
- * The Library is one more source over the same contract the CSV, collection, pages and connector
5
- * grids already use, which is what makes Table a real grid rather than a fifth hand-written table:
6
- * columns come from {@link libraryColumns}, rows are the scan, and every layout — Cards, Media,
7
- * Calendar, Board — draws the SAME rows through a different arrangement. A layout switch never
8
- * re-reads the project.
4
+ * The scan is one more source over the same contract the CSV, collection, pages and connector grids
5
+ * already use: columns come from {@link libraryColumns}, rows are the scan, and every view (Table,
6
+ * Cards, Calendar, Board) draws the SAME rows through a different arrangement. A view switch never
7
+ * re-reads the project, and neither does showing another collection: the scan covers the project
8
+ * once, and each collection is a filter over it.
9
9
  *
10
10
  * It is a **read-only** source, and says so rather than pretending. Renaming, duplicating and
11
11
  * deleting a file are real operations with real consequences (a rename rewrites references; a
@@ -16,8 +16,17 @@
16
16
 
17
17
  import { getPlatform } from "../platform";
18
18
  import { projectState } from "../store";
19
- import { makeGridTabId } from "../grid/grid-source";
20
- import { scanLibrary } from "./library-model";
19
+ import { workspaceHomeTabId } from "../workspace/workspace-ids";
20
+ import { PAGES_COLLECTION, capitalise, humanName } from "../content/content-collections";
21
+ import { fileToRoute } from "@jxsuite/site/routes";
22
+ import { libraryScanDirs, scanLibrary } from "./library-model";
23
+ import { routedPageExtensions } from "../format/format-host";
24
+ import { DRAFT_FIELD } from "../content/draft-state";
25
+ import { isString } from "@jxsuite/schema/guards";
26
+ import { collectionForFile } from "../content/collection-match";
27
+ import { fileRecords, recordKey } from "../content/file-records";
28
+ import type { ContentTypeSchema } from "@jxsuite/schema/types";
29
+ import type { FileRecord } from "../content/file-records";
21
30
  import type { LibraryFile, LibraryScan, ScanFailure } from "./library-model";
22
31
  import type {
23
32
  CommitResult,
@@ -30,44 +39,283 @@ import type {
30
39
 
31
40
  /** Why a cell edit is refused — printed by the grid, so the author is told where to go instead. */
32
41
  export const LIBRARY_READ_ONLY =
33
- "The Library lists files; it does not edit them. Rename, duplicate or delete from the file's " +
34
- "context menu, or open the file to edit it.";
35
-
36
- /** The Table layout's columns. `path` is the row key and is never editable. */
37
- export function libraryColumns(): GridColumn[] {
38
- return [
39
- { editable: false, field: "name", kind: "string", pk: true, title: "Name", widthHint: 260 },
40
- { editable: false, field: "category", kind: "string", title: "Category", widthHint: 120 },
41
- { editable: false, field: "locale", kind: "string", title: "Locale", widthHint: 90 },
42
- { editable: false, field: "type", kind: "string", title: "Type", widthHint: 120 },
43
- { editable: false, field: "size", kind: "number", title: "Size", widthHint: 90 },
42
+ "The Content workspace lists files; it does not edit them in the list. Rename, duplicate or " +
43
+ "delete from the file's context menu, or open the file to edit it.";
44
+
45
+ /** Which of an entry's own facts a collection's entries carry, so the Table draws a column for each. */
46
+ export interface EntryColumnFacts {
47
+ /** Some entry says Draft or Published: the collection has a draft workflow. */
48
+ status: boolean;
49
+ /** Some entry is dated by a field of its own. */
50
+ date: boolean;
51
+ /** The files are in more than one language (the Pages table draws a Language column). */
52
+ locale?: boolean;
53
+ /** The collection's own fields, each drawn as a column after Title, Status and Date. */
54
+ fields?: readonly EntryFieldColumn[];
55
+ }
56
+
57
+ /** One schema field the Table draws as a column of its own. */
58
+ export interface EntryFieldColumn {
59
+ /** The field's name in the entry. */
60
+ name: string;
61
+ /** The column heading. */
62
+ title: string;
63
+ /**
64
+ * The field holds a list (`tags: [Patios, Stone]`), which its list text joins with commas. A
65
+ * Board grouped by it puts an entry under each value, and the Filter matches any one of them.
66
+ */
67
+ list?: boolean;
68
+ /**
69
+ * A field whose values are measures, not categories: a number (`works: 90`) or a date (`until`).
70
+ * Translations of one entry repeat them, which is not a grouping, so a Board never groups by
71
+ * one.
72
+ */
73
+ measure?: boolean;
74
+ }
75
+
76
+ /** The grid field a schema field's column is keyed by, kept apart from the file facts' names. */
77
+ export function entryFieldKey(name: string): string {
78
+ return `field:${name}`;
79
+ }
80
+
81
+ /** The schema field a column key names, or null for a column that is no schema field. */
82
+ export function entryFieldOfKey(key: string): string | null {
83
+ return key.startsWith("field:") ? key.slice("field:".length) : null;
84
+ }
85
+
86
+ /** At most this many schema fields become columns; the rest are one Edit in grid away. */
87
+ export const ENTRY_FIELD_COLUMN_LIMIT = 6;
88
+
89
+ /** Formats a list cell cannot show as text: an image is the Cards view's, a body is the editor's. */
90
+ const UNLISTED_FORMATS = new Set(["image", "markdown", "html", "richtext"]);
91
+
92
+ /** "publishedAt" → "Published at", "course" → "Course". */
93
+ export function fieldTitle(name: string): string {
94
+ return capitalise(humanName(name));
95
+ }
96
+
97
+ /**
98
+ * The schema fields a collection's Table draws, in declaration order: every scalar field except the
99
+ * ones the Table already names some other way (the title, the date, the draft flag) and the ones
100
+ * whose value is not text to read in a row (an image, a body, an object).
101
+ *
102
+ * @param schema The collection's schema.
103
+ * @param skip Field names drawn already: the title field and the date field.
104
+ */
105
+ export function entryFieldColumns(
106
+ schema: ContentTypeSchema | null | undefined,
107
+ skip: ReadonlySet<string>,
108
+ ): EntryFieldColumn[] {
109
+ return Object.entries(schema?.properties ?? {})
110
+ .filter(([name, field]) => {
111
+ if (skip.has(name) || name === DRAFT_FIELD) {
112
+ return false;
113
+ }
114
+ if (
115
+ field.type === "object" ||
116
+ (isString(field.format) && UNLISTED_FORMATS.has(field.format))
117
+ ) {
118
+ return false;
119
+ }
120
+ // A list of images is a gallery, which no more reads as row text than one image does.
121
+ const itemFormat = field.items?.format;
122
+ return (
123
+ field.type !== "array" ||
124
+ (field.items?.type === "string" &&
125
+ !(isString(itemFormat) && UNLISTED_FORMATS.has(itemFormat)))
126
+ );
127
+ })
128
+ .slice(0, ENTRY_FIELD_COLUMN_LIMIT)
129
+ .map(([name, field]): EntryFieldColumn => {
130
+ const column: EntryFieldColumn = { name, title: fieldTitle(name) };
131
+ if (field.type === "array") {
132
+ column.list = true;
133
+ }
134
+ if (
135
+ field.type === "number" ||
136
+ field.type === "integer" ||
137
+ field.format === "date" ||
138
+ field.format === "date-time"
139
+ ) {
140
+ column.measure = true;
141
+ }
142
+ return column;
143
+ });
144
+ }
145
+
146
+ /**
147
+ * The Pages table's columns (the Content-Pages board): **Title** (the name the route gives the
148
+ * page, as the Site panel names it), **URL**, **Template**, **Status** when some page is marked a
149
+ * draft, **Language** when the pages are in more than one, and **Edited**. No file name and no
150
+ * path: two pages are both `index.json`, and the URL already says where each one is.
151
+ */
152
+ function pageColumns(facts?: EntryColumnFacts): GridColumn[] {
153
+ const columns: GridColumn[] = [
154
+ { editable: false, field: "title", kind: "string", title: "Title", widthHint: 240 },
155
+ // The URL is what tells two pages apart: no two routed files publish the same one.
156
+ { editable: false, field: "url", kind: "string", pk: true, title: "URL", widthHint: 200 },
157
+ { editable: false, field: "template", kind: "string", title: "Template", widthHint: 140 },
158
+ ];
159
+ if (facts?.status) {
160
+ columns.push({
161
+ editable: false,
162
+ field: "status",
163
+ kind: "string",
164
+ title: "Status",
165
+ widthHint: 100,
166
+ });
167
+ }
168
+ if (facts?.locale) {
169
+ columns.push({
170
+ editable: false,
171
+ field: "locale",
172
+ kind: "string",
173
+ title: "Language",
174
+ widthHint: 110,
175
+ });
176
+ }
177
+ columns.push({
178
+ editable: false,
179
+ field: "modified",
180
+ kind: "date",
181
+ title: "Edited",
182
+ widthHint: 120,
183
+ });
184
+ return columns;
185
+ }
186
+
187
+ /**
188
+ * The Table view's columns for a collection. `path` is the row key and is never editable.
189
+ *
190
+ * Pages are listed by what an author calls them and where they are published ({@link pageColumns}).
191
+ * A declared collection leads with what an entry is called and where it stands (its **Title**, then
192
+ * its **Status** and **Date** when its entries have them), with the file it is stored in after: a
193
+ * post is "Hello world, Draft", not `hello-world.md`.
194
+ */
195
+ export function libraryColumns(
196
+ collection: string = PAGES_COLLECTION,
197
+ facts?: EntryColumnFacts,
198
+ ): GridColumn[] {
199
+ // The Locale column only when the entries are in more than one language: a column that is empty
200
+ // On every row of a one-language project is width taken from the Title for nothing.
201
+ const fileFacts: GridColumn[] = [
202
+ ...(facts?.locale
203
+ ? [
204
+ {
205
+ editable: false,
206
+ field: "locale",
207
+ kind: "string",
208
+ title: "Locale",
209
+ widthHint: 90,
210
+ } as const,
211
+ ]
212
+ : []),
44
213
  { editable: false, field: "modified", kind: "date", title: "Modified", widthHint: 160 },
45
214
  { editable: false, field: "path", kind: "readonly", title: "Path", widthHint: 320 },
46
215
  ];
216
+ if (collection === PAGES_COLLECTION) {
217
+ return pageColumns(facts);
218
+ }
219
+ const entry: GridColumn[] = [
220
+ { editable: false, field: "title", kind: "string", title: "Title", widthHint: 260 },
221
+ ];
222
+ if (facts?.status) {
223
+ entry.push({
224
+ editable: false,
225
+ field: "status",
226
+ kind: "string",
227
+ title: "Status",
228
+ widthHint: 100,
229
+ });
230
+ }
231
+ if (facts?.date) {
232
+ entry.push({ editable: false, field: "date", kind: "date", title: "Date", widthHint: 120 });
233
+ }
234
+ for (const field of facts?.fields ?? []) {
235
+ entry.push({
236
+ editable: false,
237
+ field: entryFieldKey(field.name),
238
+ kind: "string",
239
+ title: field.title,
240
+ widthHint: 140,
241
+ });
242
+ }
243
+ // The Path names the file, so a File column beside it would say the same thing twice.
244
+ return [...entry, ...fileFacts];
47
245
  }
48
246
 
49
247
  /** One scanned file as a grid row. */
50
248
  export function libraryRow(file: LibraryFile): GridRow {
51
249
  return {
52
250
  cells: {
53
- category: file.category,
54
251
  // Null, not "": the platform reported no locale directory for this file, and a grid cell
55
252
  // Distinguishes "no value" from "the empty string" everywhere else in this contract.
56
253
  locale: file.locale ?? null,
57
254
  modified: file.modified ?? null,
58
- name: file.name,
59
- path: file.path,
60
- size: file.size ?? null,
61
- type: file.type,
255
+ // The scan reads no file, so a status, a template and a title are the Content home's to add.
256
+ status: null,
257
+ template: null,
258
+ title: file.name,
259
+ // A page's own URL; an entry's is its collection page's, which the scan does not read.
260
+ url: file.collection === PAGES_COLLECTION ? fileToRoute(file.path).urlPattern : null,
62
261
  },
63
262
  key: file.path,
64
263
  };
65
264
  }
66
265
 
67
266
  /**
68
- * A Library source, plus the two questions a grid source cannot ask but the Library must answer:
69
- * what the scan could not read, and the files behind the rows (the non-table layouts want the typed
70
- * record, not a cell bag).
267
+ * A file-backed collection's file, replaced by its records (`content/file-records.ts`): a CSV of
268
+ * fifteen prices is fifteen entries of its collection, which is what the counts and the Content
269
+ * home list. The file is read once per scan. One that cannot be read, or whose kind holds no
270
+ * records Studio reads, stays listed as the file it is.
271
+ */
272
+ export async function expandFileRecords(
273
+ files: readonly LibraryFile[],
274
+ readFile: (path: string) => Promise<string>,
275
+ ): Promise<LibraryFile[]> {
276
+ const expanded = await Promise.all(
277
+ files.map(async (file): Promise<LibraryFile[]> => {
278
+ const match = file.collection === null ? null : collectionForFile(file.path);
279
+ if (!match?.fileBacked) {
280
+ return [file];
281
+ }
282
+ let text: string;
283
+ try {
284
+ text = await readFile(file.path);
285
+ } catch {
286
+ return [file];
287
+ }
288
+ const records = fileRecords(file.path, text, match.def.schema);
289
+ if (records === null) {
290
+ return [file];
291
+ }
292
+ return records.map((record) => recordRow(file, record));
293
+ }),
294
+ );
295
+ return expanded.flat();
296
+ }
297
+
298
+ /** One record of `file`, listed as a row of its own. */
299
+ function recordRow(file: LibraryFile, record: FileRecord): LibraryFile {
300
+ return {
301
+ ...file,
302
+ name: record.title,
303
+ path: recordKey(file.path, record.index),
304
+ record: { fields: record.fields, row: record.row, source: file.path },
305
+ };
306
+ }
307
+
308
+ /** {@link expandFileRecords} over a whole scan, reading through the platform. */
309
+ async function withRecords(scan: LibraryScan): Promise<LibraryScan> {
310
+ const platform = getPlatform();
311
+ const files = await expandFileRecords(scan.files, (path) => platform.readFile(path));
312
+ return { ...scan, files };
313
+ }
314
+
315
+ /**
316
+ * The scan's source, plus the two questions a grid source cannot ask but the Content home must
317
+ * answer: what the scan could not read, and the files behind the rows (the non-table layouts want
318
+ * the typed record, not a cell bag).
71
319
  */
72
320
  export interface LibrarySource extends GridSource {
73
321
  /** The scanned files, in path order. Empty before the first {@link GridSource.rows} call. */
@@ -76,15 +324,19 @@ export interface LibrarySource extends GridSource {
76
324
  failures: () => readonly ScanFailure[];
77
325
  /** Whether a scan has completed at least once — "not loaded yet" is not "empty". */
78
326
  scanned: () => boolean;
79
- }
80
-
81
- /** The Library's tab id. One Library per window; category and layout are view state, not identity. */
82
- export function libraryTabId(): string {
83
- return makeGridTabId({ kind: "library" });
327
+ /**
328
+ * Whether the completed scan walked a different directory list than the project has now.
329
+ *
330
+ * The list is read when the project's directories load and grows when a collection is declared,
331
+ * and either can happen after a scan already finished: a window restored straight into Content
332
+ * asks for its rows before the project's directories have loaded, and the walk of none is an
333
+ * answer of none. A stale scan is not an empty project, so its owner discards it.
334
+ */
335
+ stale: () => boolean;
84
336
  }
85
337
 
86
338
  /**
87
- * Build the Library source. The scan is lazy: nothing is read until the first `rows()`.
339
+ * Build the scan's source. The scan is lazy: nothing is read until the first `rows()`.
88
340
  *
89
341
  * @param {() => readonly string[]} [dirs] Project directories to scan, injectable for tests and for
90
342
  * the perf measurement; defaults to the open project's own list.
@@ -92,8 +344,12 @@ export function libraryTabId(): string {
92
344
  export function createLibrarySource(dirs?: () => readonly string[]): LibrarySource {
93
345
  let scan: LibraryScan | null = null;
94
346
  let inFlight: Promise<LibraryScan> | null = null;
347
+ /** The directory list the cached scan walked, joined: the key {@link LibrarySource.stale} tests. */
348
+ let scannedKey: string | null = null;
95
349
 
96
- const projectDirs = dirs ?? (() => (projectState?.projectDirs ?? []) as readonly string[]);
350
+ const projectDirs =
351
+ dirs ??
352
+ (() => libraryScanDirs(projectState?.projectDirs ?? [], projectState?.projectConfig ?? null));
97
353
 
98
354
  async function ensureScan(): Promise<LibraryScan> {
99
355
  if (scan) {
@@ -101,11 +357,21 @@ export function createLibrarySource(dirs?: () => readonly string[]): LibrarySour
101
357
  }
102
358
  // Coalesce: five layouts and a command can all ask at once on the first paint, and the answer
103
359
  // Is one walk of the project, not six.
104
- inFlight ??= scanLibrary(projectDirs(), getPlatform()).then((result) => {
105
- scan = result;
106
- inFlight = null;
107
- return result;
108
- });
360
+ const walked = projectDirs();
361
+ /* A collection source the project's own list does not hold may not exist yet (a collection
362
+ declared before its first entry): its absence is an empty collection, never a failure. */
363
+ const conventional = new Set(dirs ? walked : (projectState?.projectDirs ?? []));
364
+ const optional = new Set(walked.filter((dir) => !conventional.has(dir)));
365
+ // The extensions first: a page is the file the build routes, and that is a fact of the formats.
366
+ inFlight ??= routedPageExtensions()
367
+ .then((pageExtensions) => scanLibrary(walked, getPlatform(), optional, pageExtensions))
368
+ .then(withRecords)
369
+ .then((result) => {
370
+ scan = result;
371
+ scannedKey = walked.join("\n");
372
+ inFlight = null;
373
+ return result;
374
+ });
109
375
  return inFlight;
110
376
  }
111
377
 
@@ -134,8 +400,8 @@ export function createLibrarySource(dirs?: () => readonly string[]): LibrarySour
134
400
  },
135
401
  failures: () => scan?.failures ?? [],
136
402
  files: () => scan?.files ?? [],
137
- id: libraryTabId(),
138
- label: "Library",
403
+ id: workspaceHomeTabId("content"),
404
+ label: "Content",
139
405
  async refresh() {
140
406
  scan = null;
141
407
  inFlight = null;
@@ -146,5 +412,6 @@ export function createLibrarySource(dirs?: () => readonly string[]): LibrarySour
146
412
  return { rows: result.files.map((file) => libraryRow(file)), total: result.files.length };
147
413
  },
148
414
  scanned: () => scan !== null,
415
+ stale: () => scan !== null && scannedKey !== projectDirs().join("\n"),
149
416
  };
150
417
  }