@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
@@ -55,7 +55,8 @@
55
55
  import { errorMessage } from "@jxsuite/schema/parse";
56
56
  import { notify } from "../services/notify";
57
57
  import { activeRegistry } from "./active-registry";
58
- import type { CommandArgs, CommandRegistry } from "./registry";
58
+ import type { CommandArgValues } from "./command-args";
59
+ import type { CommandRegistry } from "./registry";
59
60
 
60
61
  /**
61
62
  * Whether an error is one of the two REFUSAL shapes, whose message is written to be read whole.
@@ -64,10 +65,10 @@ import type { CommandArgs, CommandRegistry } from "./registry";
64
65
  * `handleKeyEvent`, and a value import back would close a cycle for one class whose constructor
65
66
  * sets exactly this name. `RangeError` is the shape `coerceArgs` and a `run` body refuse with.
66
67
  */
67
- function isRefusal(error: unknown): boolean {
68
+ function isRefusal(cause: unknown): boolean {
68
69
  return (
69
- error instanceof RangeError ||
70
- (error instanceof Error && error.name === "CommandUnavailableError")
70
+ cause instanceof RangeError ||
71
+ (cause instanceof Error && cause.name === "CommandUnavailableError")
71
72
  );
72
73
  }
73
74
 
@@ -86,15 +87,15 @@ function isRefusal(error: unknown): boolean {
86
87
  export function runReported(
87
88
  registry: CommandRegistry,
88
89
  id: string,
89
- args?: CommandArgs,
90
+ args?: CommandArgValues,
90
91
  source: string = id,
91
92
  ): Promise<void> {
92
- const report = (error: unknown) => {
93
- if (!isRefusal(error)) {
93
+ const report = (cause: unknown) => {
94
+ if (!isRefusal(cause)) {
94
95
  // A crash, not a refusal: the row below carries the sentence, the console keeps the stack.
95
- console.error(`${source}: command "${id}" failed`, error);
96
+ console.error(`${source}: command "${id}" failed`, cause);
96
97
  }
97
- notify.error(errorMessage(error), { key: `command.run:${id}`, source });
98
+ notify.error(errorMessage(cause), { key: `command.run:${id}`, source });
98
99
  };
99
100
  let result: void | Promise<void>;
100
101
  try {
@@ -114,7 +115,11 @@ export function runReported(
114
115
  * registry to refuse it, so there is no refusal to file. The resolved promise keeps the caller's
115
116
  * `void` honest either way.
116
117
  */
117
- export function runActiveReported(id: string, args?: CommandArgs, source?: string): Promise<void> {
118
+ export function runActiveReported(
119
+ id: string,
120
+ args?: CommandArgValues,
121
+ source?: string,
122
+ ): Promise<void> {
118
123
  const registry = activeRegistry();
119
124
  return registry ? runReported(registry, id, args, source) : Promise.resolve();
120
125
  }
@@ -11,8 +11,13 @@
11
11
  */
12
12
 
13
13
  import type { JsonValue } from "./types";
14
- import type { JxMutableNode } from "@jxsuite/schema/types";
15
- import { isPrivateStateKey } from "@jxsuite/schema/guards";
14
+ import type {
15
+ JsonPrimitive,
16
+ JxMutableNode,
17
+ JxStateDefinition,
18
+ JxStateObject,
19
+ } from "@jxsuite/schema/types";
20
+ import { isNonNullObject, isPrivateStateKey, isString } from "@jxsuite/schema/guards";
16
21
 
17
22
  /** One editable prop row: the state key and its current default value (undefined = none). */
18
23
  export interface ComponentPropEntry {
@@ -22,7 +27,16 @@ export interface ComponentPropEntry {
22
27
 
23
28
  /** Whether the doc is a component definition (a custom-element root) rather than a page. */
24
29
  export function isComponentDoc(doc: JxMutableNode | null | undefined): boolean {
25
- return typeof doc?.tagName === "string" && doc.tagName.includes("-");
30
+ const tagName = doc?.tagName;
31
+ return isString(tagName) && tagName.includes("-");
32
+ }
33
+
34
+ /** The object shapes a state entry can take: every `JxStateDefinition` but a primitive or array. */
35
+ type StateEntryObject = Exclude<JxStateDefinition, JsonPrimitive | JsonValue[]>;
36
+
37
+ /** Whether a state entry is one of its object shapes — a signal, a typed def, a naked object. */
38
+ function isStateEntryObject(def: JxStateDefinition | undefined): def is StateEntryObject {
39
+ return isNonNullObject(def) && !Array.isArray(def);
26
40
  }
27
41
 
28
42
  /**
@@ -31,26 +45,20 @@ export function isComponentDoc(doc: JxMutableNode | null | undefined): boolean {
31
45
  * templates, or $prototype data sources (overriding those would clobber behavior, the boundPropKey
32
46
  * rule).
33
47
  */
34
- function propShape(def: unknown): "literal" | "signal" | null {
35
- if (def === null || typeof def === "number" || typeof def === "boolean") {
36
- return "literal";
37
- }
38
- if (typeof def === "string") {
39
- return def.includes("${") ? null : "literal"; // Template strings render computed values.
40
- }
41
- if (Array.isArray(def)) {
42
- return "literal";
48
+ function propKind(def: JxStateDefinition | undefined): "literal" | "signal" | null {
49
+ if (def === undefined) {
50
+ return null;
43
51
  }
44
- if (typeof def === "object") {
45
- const d = def as Record<string, unknown>;
46
- if (d.$expression || d.$compute || d.$prototype || d.$handler) {
52
+ if (isStateEntryObject(def)) {
53
+ if (def.$expression || def.$compute || def.$prototype || def.$handler) {
47
54
  return null;
48
55
  }
49
56
  // An expanded signal ({default}) or a typed prop def ({type}/schema keywords) seeds through
50
57
  // Its `default`; any other plain object is a Shape-1 naked value.
51
- return "default" in d || "type" in d ? "signal" : "literal";
58
+ return "default" in def || "type" in def ? "signal" : "literal";
52
59
  }
53
- return null;
60
+ // Null, numbers, booleans and arrays are naked literals. Template strings render computed values.
61
+ return isString(def) && def.includes("${") ? null : "literal";
54
62
  }
55
63
 
56
64
  /**
@@ -58,20 +66,20 @@ function propShape(def: unknown): "literal" | "signal" | null {
58
66
  * entries with their current default values (the CEM-export "field" subset).
59
67
  */
60
68
  export function componentPropEntries(doc: JxMutableNode | null | undefined): ComponentPropEntry[] {
61
- const state = (doc?.state ?? {}) as Record<string, unknown>;
69
+ const state: Record<string, JxStateDefinition> = doc?.state ?? {};
62
70
  const out: ComponentPropEntry[] = [];
63
71
  for (const [name, def] of Object.entries(state)) {
64
72
  if (isPrivateStateKey(name)) {
65
73
  continue; // Private entries are not props (spec.md §5.6).
66
74
  }
67
- const shape = propShape(def);
68
- if (!shape) {
75
+ const kind = propKind(def);
76
+ if (!kind) {
69
77
  continue;
70
78
  }
71
- const value =
72
- shape === "signal"
73
- ? ((def as { default?: JsonValue }).default as JsonValue | undefined)
74
- : (def as JsonValue);
79
+ /* SAFETY: `propKind` refused every behavioral shape (expressions, computeds, `$prototype`
80
+ sources, handlers, template strings), so what is left is the document's plain data: a
81
+ literal entry IS the JSON value, and a signal entry is an object whose `default` is one. */
82
+ const value = kind === "signal" ? (def as { default?: JsonValue }).default : (def as JsonValue);
75
83
  out.push({ name, value });
76
84
  }
77
85
  return out;
@@ -87,19 +95,27 @@ export function substitutePreviewProps(
87
95
  renderDoc: JxMutableNode,
88
96
  props: Record<string, JsonValue>,
89
97
  ): JxMutableNode {
90
- const state = { ...((renderDoc.state ?? {}) as Record<string, unknown>) };
98
+ const state = { ...renderDoc.state };
91
99
  let seeded = false;
92
100
  for (const [name, value] of Object.entries(props)) {
93
- const shape = propShape(state[name]);
94
- if (!shape) {
101
+ const current = state[name];
102
+ const kind = propKind(current);
103
+ if (!kind) {
95
104
  continue; // Unknown/behavioral entries are never overridden by a stale test value.
96
105
  }
97
- state[name] =
98
- shape === "signal" ? { ...(state[name] as Record<string, unknown>), default: value } : value;
106
+ /* SAFETY: `propKind` answers "signal" only for an object that carries `default` or `type` and
107
+ none of the behavioral keys (`$expression`, `$compute`, `$prototype`, `$handler`) — the
108
+ expanded-signal / typed-def shape `JxStateObject` describes. A literal is replaced by the
109
+ JSON test value itself, which is a Shape-1 naked entry; `JxStateDefinition` spells that
110
+ shape as `JxStateObject`, whose typed keys neither a `JsonObject` nor a spread copy can prove
111
+ statically (the spread drops the index signature its typed keys are checked against). */
112
+ state[name] = (
113
+ kind === "signal" ? { ...(current as JxStateObject), default: value } : value
114
+ ) as JxStateDefinition;
99
115
  seeded = true;
100
116
  }
101
117
  if (!seeded) {
102
118
  return renderDoc;
103
119
  }
104
- return { ...renderDoc, state } as JxMutableNode;
120
+ return { ...renderDoc, state };
105
121
  }
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Collection-match — the ONE answer to "which content collection owns this path".
3
3
  *
4
- * Three matchers already existed and disagreed: `utils/studio-utils.ts`'s `findContentTypeSchema`,
4
+ * Three matchers existed and disagreed: `utils/studio-utils.ts`'s `findContentTypeSchema`,
5
5
  * `grid/sources/content-source.ts`'s `collectionInfo` and `browse/library-model.ts`'s
6
- * `contentTypeFor`. Each was right about the question it was written for and wrong about the
7
- * others', which was tolerable while the consumers were a form and a grid. It stopped being
8
- * tolerable when the Files tree began asking, because a mismatch there does not draw the wrong
9
- * field — it CONSTRAINS or REROUTES a creation, and both are wrong answers the author cannot see.
6
+ * `contentTypeFor` (since deleted: the Content workspace asks this module instead). Each was right
7
+ * about the question it was written for and wrong about the others', which was tolerable while the
8
+ * consumers were a form and a grid. It stopped being tolerable when the Files tree began asking,
9
+ * because a mismatch there does not draw the wrong field — it CONSTRAINS or REROUTES a creation,
10
+ * and both are wrong answers the author cannot see.
10
11
  *
11
12
  * Four things this states that no predecessor did:
12
13
  *
@@ -32,12 +33,10 @@
32
33
  import { defaultContentFormat, formatByName } from "../format/format-host";
33
34
  import { projectState } from "../store";
34
35
  import { resolveI18n } from "@jxsuite/schema/locale";
36
+ import { LOCALE_PLACEHOLDER } from "../canvas/asset-resolve";
35
37
  import type { ContentSectionEntry } from "../types";
36
38
  import type { ProjectConfig } from "@jxsuite/schema/types";
37
39
 
38
- /** The placeholder a localized `source` carries, standing for one directory per declared locale. */
39
- export const LOCALE_PLACEHOLDER = "{locale}";
40
-
41
40
  /** What a path's collection is, and everything a caller needs in order to act on it. */
42
41
  export interface CollectionMatch {
43
42
  name: string;
@@ -69,11 +68,14 @@ function normalize(path: string): string {
69
68
 
70
69
  /** The config a lookup reads: the caller's, or the open project's. */
71
70
  function configOf(config: ProjectConfig | null | undefined): ProjectConfig | null {
72
- return config ?? (projectState?.projectConfig as ProjectConfig | null | undefined) ?? null;
71
+ return config ?? projectState?.projectConfig ?? null;
73
72
  }
74
73
 
75
74
  /** The `content` section of a config, or an empty one. */
76
75
  function contentSection(config: ProjectConfig | null): Record<string, ContentSectionEntry> {
76
+ /* SAFETY: `content` is the parser extension's section — collection name → entry object, its
77
+ project fragment schema the source of truth. `ContentSectionEntry` names only the fields Studio
78
+ reads, every one optional, and each reader below tests `source` before using it. */
77
79
  return (config?.content ?? {}) as Record<string, ContentSectionEntry>;
78
80
  }
79
81
 
@@ -0,0 +1,412 @@
1
+ /**
2
+ * Which page each collection's entries are published at — read from the pages, never stored.
3
+ *
4
+ * `project.json` records no URL pattern and no template for a collection. The route lives in the
5
+ * template PAGE: a dynamic file under `pages/` whose `$paths.contentType` names the collection
6
+ * (`pages/blog/[slug].json`, `$paths: { contentType: "posts", param: "slug" }`), or whose
7
+ * `$paths.values` enumerate the ids of a `ContentEntry` it reads by its route parameter (a taxonomy
8
+ * page, `pages/author/[slug].json`), and the layout an entry is drawn in is that page's `$layout`.
9
+ * A second record of either in `project.json` would be free to disagree with the router, so the
10
+ * Content workspace's header line ("Each post has a page at `/blog/:slug` using Post") and the
11
+ * canvas's entry wrapping (`canvas/canvas-live-render.ts`) both read this index (`specs/studio.md`
12
+ * §22.5).
13
+ *
14
+ * One read per invalidation: a walk of `pages/`, then a parse of each dynamic page, cached until a
15
+ * file event drops it ({@link invalidateCollectionPages}, wired beside the Site panel's index in
16
+ * `studio.ts`). The read never rejects; a page that cannot be read or parsed is a page with no
17
+ * collection.
18
+ *
19
+ * @docs studio/projects/browse
20
+ */
21
+
22
+ import { isJsonObject, isNumber, isString } from "@jxsuite/schema/guards";
23
+ import { fileToRoute, isRoutedPageFile } from "@jxsuite/site/routes";
24
+ import {
25
+ canonicalizeLocale,
26
+ localeOfPath,
27
+ resolveI18n,
28
+ servedLocaleOfPath,
29
+ } from "@jxsuite/schema/locale";
30
+ import { getPlatform, hasPlatform } from "../platform";
31
+ import { projectState } from "../store";
32
+ import { pagePathsDef } from "../page-params";
33
+ import type { FormatFrontmatter } from "../format/format-host";
34
+ import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
35
+ import type { EntryFields } from "./entry-fields";
36
+ import type { DirEntry } from "../types";
37
+
38
+ /** What a page under `pages/` says about collections and layouts. */
39
+ export interface PageFacts {
40
+ /** The collection its `$paths` expands over, or `null` for a page of its own. */
41
+ contentType: string | null;
42
+ /** The route parameter an entry fills (`slug`), when `$paths` names one. */
43
+ param: string | null;
44
+ /** The entry field that fills it (`sku`), when `$paths` names one other than `id`. */
45
+ field: string | null;
46
+ /** Its `$layout`: a path, `false` (no layout), or `undefined` (the project's default). */
47
+ layout: string | false | undefined;
48
+ /**
49
+ * The ids a `$paths.values` page enumerates (`["chad-beiler", "kris-bucher"]`): the only entries
50
+ * it publishes a URL for. `null` for a `$paths.contentType` page, which publishes every entry,
51
+ * and for a `values` that is not a list of ids written in the page.
52
+ */
53
+ values?: readonly string[] | null;
54
+ }
55
+
56
+ /** A collection's template page. */
57
+ export interface CollectionPage {
58
+ /** The page file, project-relative (`pages/blog/[slug].json`). */
59
+ path: string;
60
+ /** Its URL pattern (`/blog/:slug`). */
61
+ pattern: string;
62
+ /** The parameter an entry's id fills, or `null` when the page names none. */
63
+ param: string | null;
64
+ /** The entry field the parameter is read from, as {@link PageFacts.field}. */
65
+ field: string | null;
66
+ /** The page's `$layout`, as {@link PageFacts.layout}. */
67
+ layout: string | false | undefined;
68
+ /** The only entry ids it publishes, as {@link PageFacts.values}; null or absent for every one. */
69
+ values?: readonly string[] | null;
70
+ /**
71
+ * The language the page is served in (`pages/ar/exhibitions/[slug].json` → `ar`), or `null` in a
72
+ * project without `i18n` and for a page outside every locale tree.
73
+ */
74
+ locale: string | null;
75
+ }
76
+
77
+ /**
78
+ * The collection a page enumerating its own `$paths.values` publishes one entry of per URL: the
79
+ * `contentType` of its `ContentEntry` state entry whose `id` is the route parameter (`{ "$ref":
80
+ * "#/$params/slug" }`). A taxonomy page (`pages/author/[slug].json`, listing the author slugs and
81
+ * reading `state.author` from the `author` collection by that slug) states its collection that way
82
+ * rather than with `$paths.contentType`, and is the collection's page all the same.
83
+ */
84
+ function entryCollectionOf(
85
+ document: JxMutableNode | null,
86
+ frontmatter: FormatFrontmatter | null,
87
+ param: string,
88
+ ): string | null {
89
+ const state = document?.state ?? frontmatter?.state;
90
+ const target = `#/$params/${param}`;
91
+ for (const entry of Object.values(isJsonObject(state) ? state : {})) {
92
+ if (!isJsonObject(entry) || entry.$prototype !== "ContentEntry") {
93
+ continue;
94
+ }
95
+ const { contentType, id } = entry;
96
+ if (isJsonObject(id) && id.$ref === target && isString(contentType) && contentType !== "") {
97
+ return contentType;
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+
103
+ /** The facts a page document states, from its parsed tree and (for a format page) frontmatter. */
104
+ export function pageFactsOf(
105
+ document: JxMutableNode | null,
106
+ frontmatter: FormatFrontmatter | null,
107
+ ): PageFacts {
108
+ const paths = pagePathsDef({ document, frontmatter });
109
+ let contentType: string | null = null;
110
+ let param: string | null = null;
111
+ let field: string | null = null;
112
+ let values: string[] | null = null;
113
+ if (paths && !Array.isArray(paths) && "contentType" in paths) {
114
+ const type = paths.contentType;
115
+ contentType = isString(type) && type !== "" ? type : null;
116
+ const named = "param" in paths ? paths.param : undefined;
117
+ param = isString(named) && named !== "" ? named : null;
118
+ const from = "field" in paths ? paths.field : undefined;
119
+ field = isString(from) && from !== "" && from !== "id" ? from : null;
120
+ } else if (paths && !Array.isArray(paths) && "values" in paths) {
121
+ const named = "param" in paths ? paths.param : undefined;
122
+ const enumerated = isString(named) && named !== "" ? named : null;
123
+ contentType = enumerated === null ? null : entryCollectionOf(document, frontmatter, enumerated);
124
+ param = contentType === null ? null : enumerated;
125
+ // The ids it lists are the entries it publishes; any other entry of the collection has no page.
126
+ const listed = paths.values;
127
+ values =
128
+ contentType !== null && Array.isArray(listed)
129
+ ? listed.flatMap((value) => {
130
+ const id = segmentOf(value);
131
+ return id === null ? [] : [id];
132
+ })
133
+ : null;
134
+ }
135
+ const own = document?.$layout ?? frontmatter?.$layout;
136
+ const layout = isString(own) || own === false ? own : undefined;
137
+ return { contentType, field, layout, param, ...(values !== null && { values }) };
138
+ }
139
+
140
+ /**
141
+ * Read one page's facts from disk. A file that cannot be read or parsed states none.
142
+ *
143
+ * @param path - Project-relative page path.
144
+ */
145
+ export async function readPageFacts(path: string): Promise<PageFacts> {
146
+ const none: PageFacts = { contentType: null, field: null, layout: undefined, param: null };
147
+ try {
148
+ const source = await getPlatform().readFile(path);
149
+ if (path.endsWith(".json")) {
150
+ /* SAFETY: a `.json` file under `pages/` is a page document by the project layout; a file
151
+ that does not parse throws into the catch below, which is "no facts". */
152
+ return pageFactsOf(JSON.parse(source) as JxMutableNode, null);
153
+ }
154
+ const { parseSourceForPath } = await import("../files/file-ops");
155
+ const parsed = await parseSourceForPath(path, source);
156
+ /* SAFETY: a format class's parser returns its file as a Jx element tree (the format
157
+ contract); `pageFactsOf` reads `$paths` and `$layout` off it and nothing else. */
158
+ return pageFactsOf(parsed.document as JxMutableNode, parsed.frontmatter);
159
+ } catch {
160
+ return none;
161
+ }
162
+ }
163
+
164
+ // ─── The index ───────────────────────────────────────────────────────────────
165
+
166
+ /** Every template page of each collection, in path order. A multilingual site has one per language. */
167
+ type CollectionPageIndex = Map<string, CollectionPage[]>;
168
+
169
+ let _index: CollectionPageIndex | null = null;
170
+ let _loading: Promise<CollectionPageIndex> | null = null;
171
+ /** Bumped by every invalidation, so a read that started before one cannot land after it. */
172
+ let _epoch = 0;
173
+ /** Told when a read lands, so a surface showing a stale answer can repaint. */
174
+ const _listeners = new Set<() => void>();
175
+
176
+ /** Every file under `pages/`, recursively. An unreadable directory contributes nothing. */
177
+ async function listPages(dir: string, out: string[]): Promise<void> {
178
+ let entries: DirEntry[];
179
+ try {
180
+ entries = await getPlatform().listDirectory(dir);
181
+ } catch {
182
+ return;
183
+ }
184
+ await Promise.all(
185
+ entries.map(async (entry) => {
186
+ if (entry.type === "directory") {
187
+ await listPages(entry.path, out);
188
+ } else {
189
+ out.push(entry.path);
190
+ }
191
+ }),
192
+ );
193
+ }
194
+
195
+ /** One walk of `pages/`, then the facts of every dynamic page in it. */
196
+ async function readIndex(): Promise<CollectionPageIndex> {
197
+ const files: string[] = [];
198
+ await listPages("pages", files);
199
+ /* Only routed pages: an underscore-prefixed file or folder is private to its directory and
200
+ publishes nothing, and it would otherwise win the path-order tie below (`_` sorts first). */
201
+ const dynamic = files.filter((path) => path.includes("[") && isRoutedPageFile(path)).toSorted();
202
+ const facts = await Promise.all(
203
+ dynamic.map(async (path) => [path, await readPageFacts(path)] as const),
204
+ );
205
+ const { i18n } = resolveI18n(projectState?.projectConfig ?? {});
206
+ const index: CollectionPageIndex = new Map();
207
+ for (const [path, fact] of facts) {
208
+ if (fact.contentType) {
209
+ const page: CollectionPage = {
210
+ field: fact.field,
211
+ layout: fact.layout,
212
+ locale: servedLocaleOfPath(path, i18n),
213
+ param: fact.param,
214
+ path,
215
+ pattern: fileToRoute(path).urlPattern,
216
+ ...(fact.values && { values: fact.values }),
217
+ };
218
+ index.set(fact.contentType, [...(index.get(fact.contentType) ?? []), page]);
219
+ }
220
+ }
221
+ return index;
222
+ }
223
+
224
+ /**
225
+ * The index, read once per invalidation.
226
+ *
227
+ * With no platform or no project there is nothing to read, and the answer is an empty map rather
228
+ * than a rejection.
229
+ */
230
+ export function collectionPages(): Promise<CollectionPageIndex> {
231
+ if (_index) {
232
+ return Promise.resolve(_index);
233
+ }
234
+ if (!hasPlatform() || !projectState) {
235
+ return Promise.resolve(new Map());
236
+ }
237
+ if (!_loading) {
238
+ const epoch = _epoch;
239
+ _loading = readIndex().then((index) => {
240
+ if (epoch === _epoch) {
241
+ _index = index;
242
+ _loading = null;
243
+ for (const listener of _listeners) {
244
+ listener();
245
+ }
246
+ }
247
+ return index;
248
+ });
249
+ }
250
+ return _loading;
251
+ }
252
+
253
+ /**
254
+ * The one of a collection's template pages that serves `locale`.
255
+ *
256
+ * A multilingual site gives a collection one template page per language
257
+ * (`pages/exhibitions/[slug].json`, `pages/ar/exhibitions/[slug].json`, …), and "the" page is the
258
+ * one in the language asked about: an Arabic entry is drawn in the Arabic page's layout, and the
259
+ * header for the English view names the English URL. With no language asked, or none of the pages
260
+ * in it, the answer is the site's default language's page, then a page outside every locale tree,
261
+ * then the first in path order, so two pages over one collection still answer deterministically.
262
+ */
263
+ export function pageForLocale(
264
+ pages: readonly CollectionPage[] | undefined,
265
+ locale: string | null | undefined,
266
+ ): CollectionPage | null {
267
+ if (!pages || pages.length === 0) {
268
+ return null;
269
+ }
270
+ const wanted = canonicalizeLocale(locale);
271
+ const fallback = resolveI18n(projectState?.projectConfig ?? {}).i18n?.defaultLocale ?? null;
272
+ return (
273
+ (wanted === null ? undefined : pages.find((page) => page.locale === wanted)) ??
274
+ (fallback === null ? undefined : pages.find((page) => page.locale === fallback)) ??
275
+ pages.find((page) => page.locale === null) ??
276
+ pages[0]!
277
+ );
278
+ }
279
+
280
+ /** The language a collection entry is written in, read from its path (`content/x/ar/a.md` → `ar`). */
281
+ export function entryLocale(path: string | null | undefined): string | null {
282
+ if (!path) {
283
+ return null;
284
+ }
285
+ return localeOfPath(path, resolveI18n(projectState?.projectConfig ?? {}).i18n);
286
+ }
287
+
288
+ /**
289
+ * A collection's template page as the index stands: the page, `null` when the collection has none,
290
+ * or `undefined` while the index has not been read yet (which starts the read).
291
+ *
292
+ * @param locale - The language asked about, as {@link pageForLocale} reads it.
293
+ */
294
+ export function peekCollectionPage(
295
+ name: string,
296
+ locale?: string | null,
297
+ ): CollectionPage | null | undefined {
298
+ if (!_index) {
299
+ void collectionPages();
300
+ return undefined;
301
+ }
302
+ return pageForLocale(_index.get(name), locale);
303
+ }
304
+
305
+ /**
306
+ * Every template page of a collection, one per language in a multilingual site, as the index
307
+ * stands: `[]` for none, `undefined` while the index has not been read (which starts the read).
308
+ */
309
+ export function peekCollectionPages(name: string): readonly CollectionPage[] | undefined {
310
+ if (!_index) {
311
+ void collectionPages();
312
+ return undefined;
313
+ }
314
+ return _index.get(name) ?? [];
315
+ }
316
+
317
+ /** A collection's template page for a language, reading the index if it has to. */
318
+ export async function collectionPage(
319
+ name: string,
320
+ locale?: string | null,
321
+ ): Promise<CollectionPage | null> {
322
+ const index = await collectionPages();
323
+ return pageForLocale(index.get(name), locale);
324
+ }
325
+
326
+ /** Forget the index. The next read walks `pages/` again. */
327
+ export function invalidateCollectionPages(): void {
328
+ _epoch += 1;
329
+ _index = null;
330
+ _loading = null;
331
+ }
332
+
333
+ /** Be told when a read of the index lands. Returns the function that stops it. */
334
+ export function onCollectionPagesRead(listener: () => void): () => void {
335
+ _listeners.add(listener);
336
+ return () => {
337
+ _listeners.delete(listener);
338
+ };
339
+ }
340
+
341
+ /** A field value as a route segment: text or a number, else nothing. */
342
+ function segmentOf(value: JxDocumentValue | undefined): string | null {
343
+ if (isString(value) && value !== "") {
344
+ return value;
345
+ }
346
+ return isNumber(value) && Number.isFinite(value) ? String(value) : null;
347
+ }
348
+
349
+ /**
350
+ * The URL one entry opens at, from its collection's page pattern, filled as the build fills it
351
+ * (`Content.resolvePaths`): the page's `$paths.field` read from the entry's fields when it names
352
+ * one (`/products/:sku` with the entry's `sku`), else the entry's id (a JSON entry's `id` field,
353
+ * else its file stem). `null` when the collection has no page, or when its page enumerates the ids
354
+ * it publishes (`$paths.values`) and this entry is not among them.
355
+ *
356
+ * @param fields - The entry's fields (frontmatter, or a JSON entry's root), when the caller has
357
+ * them.
358
+ */
359
+ export function entryUrl(
360
+ page: CollectionPage | null,
361
+ entryPath: string,
362
+ fields?: Readonly<EntryFields> | null,
363
+ ): string | null {
364
+ if (!page) {
365
+ return null;
366
+ }
367
+ const base = entryPath.split("/").pop() ?? entryPath;
368
+ const dot = base.lastIndexOf(".");
369
+ const stem = dot > 0 ? base.slice(0, dot) : base;
370
+ const own = page.field === null ? null : segmentOf(fields?.[page.field]);
371
+ // Only a JSON entry's own `id` names it (the loader's `jsonEntry`); a Markdown entry is its file.
372
+ const named = entryPath.endsWith(".json") ? segmentOf(fields?.id) : null;
373
+ const id = own ?? named ?? stem;
374
+ // A page that lists the ids it publishes has no URL for an entry it does not list.
375
+ if (page.values && !page.values.includes(id)) {
376
+ return null;
377
+ }
378
+ if (page.param) {
379
+ return page.pattern.replace(`:${page.param}`, id);
380
+ }
381
+ return page.pattern.replace(/:[A-Za-z_]\w*/, id);
382
+ }
383
+
384
+ /**
385
+ * The layout an entry is drawn in (§22.5): its own `$layout`, else its collection's template page's
386
+ * `$layout`, else the project's `defaults.layout`. `null` when none applies, or when the first of
387
+ * them to speak says `false`.
388
+ */
389
+ export function entryLayoutPath(
390
+ own: string | false | undefined,
391
+ page: CollectionPage | null,
392
+ ): string | null {
393
+ if (own === false) {
394
+ return null;
395
+ }
396
+ if (isString(own) && own !== "") {
397
+ return own;
398
+ }
399
+ if (page?.layout === false) {
400
+ return null;
401
+ }
402
+ if (isString(page?.layout) && page.layout !== "") {
403
+ return page.layout;
404
+ }
405
+ return projectState?.projectConfig?.defaults?.layout ?? null;
406
+ }
407
+
408
+ /** Forget everything — tests, and a project switch. */
409
+ export function resetCollectionPages(): void {
410
+ invalidateCollectionPages();
411
+ _listeners.clear();
412
+ }