@jxsuite/studio 6.1.2 → 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 (522) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  4. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  5. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  6. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  7. package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
  8. package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
  9. package/dist/chunks/color-m7r1vk54.js +4 -0
  10. package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
  11. package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
  12. package/dist/chunks/components-r22xca09.js +4 -0
  13. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  14. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  15. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  16. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  17. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  18. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  19. package/dist/chunks/files-rcn56qvm.js +4 -0
  20. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  21. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  22. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  23. package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
  24. package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
  25. package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
  26. package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
  27. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  28. package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
  29. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  30. package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
  31. package/dist/chunks/index-f0jn7nnp.js +4 -0
  32. package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
  33. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  34. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  35. package/dist/chunks/layers-bgyr11tr.js +4 -0
  36. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  37. package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
  38. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  39. package/dist/chunks/media-library-sq468wts.js +4 -0
  40. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  41. package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
  42. package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
  43. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  44. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  45. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  46. package/dist/chunks/parse-v77xtwv7.js +4 -0
  47. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  48. package/dist/chunks/popover-b89sfej7.js +4 -0
  49. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  50. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  51. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  52. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  53. package/dist/chunks/references-9547rg5s.js +4 -0
  54. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  55. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  56. package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
  57. package/dist/chunks/studio-03ct6yfv.js +9 -0
  58. package/dist/chunks/studio-07rcfje3.js +5 -0
  59. package/dist/chunks/studio-3e54qh39.js +7 -0
  60. package/dist/chunks/studio-3exxhz5g.js +5 -0
  61. package/dist/chunks/studio-3q40e3rj.js +5 -0
  62. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  63. package/dist/chunks/studio-3qqjeep5.js +6 -0
  64. package/dist/chunks/studio-43sd2mam.js +4 -0
  65. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  66. package/dist/chunks/studio-58xg6j2q.js +9 -0
  67. package/dist/chunks/studio-5g0rprdt.js +7 -0
  68. package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
  69. package/dist/chunks/studio-80jyh1xh.js +4 -0
  70. package/dist/chunks/studio-83mk4bgg.js +9 -0
  71. package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
  72. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  73. package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
  74. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  75. package/dist/chunks/studio-9tmebf0s.js +5 -0
  76. package/dist/chunks/studio-a2bvaptz.js +5 -0
  77. package/dist/chunks/studio-b7y5mr30.js +5 -0
  78. package/dist/chunks/studio-bavb31r0.js +5 -0
  79. package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
  80. package/dist/chunks/studio-c05wdnt3.js +5 -0
  81. package/dist/chunks/studio-ccv2svc6.js +5 -0
  82. package/dist/chunks/studio-d5grtb9e.js +16 -0
  83. package/dist/chunks/studio-df0baea9.js +5 -0
  84. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  85. package/dist/chunks/studio-e1g64q43.js +5 -0
  86. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  87. package/dist/chunks/studio-ed3xx40h.js +7 -0
  88. package/dist/chunks/studio-f14e1zdj.js +5 -0
  89. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  90. package/dist/chunks/studio-fyh0jc96.js +5 -0
  91. package/dist/chunks/studio-gcxk20n7.js +5 -0
  92. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  93. package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
  94. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  95. package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
  96. package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
  97. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  98. package/dist/chunks/studio-m8g16bgz.js +5 -0
  99. package/dist/chunks/studio-mn0476ag.js +5 -0
  100. package/dist/chunks/studio-mx1smyq0.js +5 -0
  101. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  102. package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
  103. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  104. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  105. package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
  106. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  107. package/dist/chunks/studio-ph84avkf.js +5 -0
  108. package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
  109. package/dist/chunks/studio-q0tccd43.js +5 -0
  110. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  111. package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
  112. package/dist/chunks/studio-qmn1xc24.js +5 -0
  113. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  114. package/dist/chunks/studio-r5qy30vx.js +5 -0
  115. package/dist/chunks/studio-rj9eamf8.js +5 -0
  116. package/dist/chunks/studio-rptgsk96.js +5 -0
  117. package/dist/chunks/studio-rthyg42z.js +928 -0
  118. package/dist/chunks/studio-s19tp1xr.js +5 -0
  119. package/dist/chunks/studio-s32578pn.js +5 -0
  120. package/dist/chunks/studio-svb7yyve.js +5 -0
  121. package/dist/chunks/studio-syreb644.js +5 -0
  122. package/dist/chunks/studio-tf9jryb1.js +10 -0
  123. package/dist/chunks/studio-tfkznv39.js +5 -0
  124. package/dist/chunks/studio-tft6r105.js +5 -0
  125. package/dist/chunks/studio-txf2kysx.js +5 -0
  126. package/dist/chunks/studio-v8867ddv.js +12 -0
  127. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  128. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  129. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  130. package/dist/chunks/studio-wc649wss.js +5 -0
  131. package/dist/chunks/studio-wys23mxz.js +5 -0
  132. package/dist/chunks/studio-x1x167jh.js +5 -0
  133. package/dist/chunks/studio-x9hsze61.js +5 -0
  134. package/dist/chunks/studio-y0n7yxea.js +9 -0
  135. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  136. package/dist/chunks/studio-z97c48fk.js +5 -0
  137. package/dist/chunks/studio-zat62m0c.js +5 -0
  138. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  139. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  140. package/dist/chunks/toast-1gv0h53h.js +4 -0
  141. package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
  142. package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
  143. package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
  144. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  145. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  146. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  147. package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
  148. package/dist/iframe-entry.js +20 -16
  149. package/dist/manifest.json +77 -63
  150. package/dist/studio.js +103 -104
  151. package/dist/workers/ts.worker.js +3 -3
  152. package/package.json +12 -11
  153. package/src/browse/component-examples.ts +272 -0
  154. package/src/browse/library-commands.ts +64 -104
  155. package/src/browse/library-layouts.ts +263 -49
  156. package/src/browse/library-model.ts +181 -133
  157. package/src/browse/library-pane.ts +738 -446
  158. package/src/browse/library-preview.ts +149 -19
  159. package/src/browse/library-source.ts +308 -41
  160. package/src/browse/preview-root.ts +78 -0
  161. package/src/browse/preview-style.ts +155 -0
  162. package/src/canvas/asset-refs.ts +16 -1
  163. package/src/canvas/canvas-live-render.ts +222 -30
  164. package/src/canvas/canvas-origin.ts +37 -12
  165. package/src/canvas/canvas-page-context.ts +112 -0
  166. package/src/canvas/canvas-render.ts +113 -107
  167. package/src/canvas/canvas-utils.ts +57 -12
  168. package/src/canvas/iframe-drop.ts +107 -0
  169. package/src/canvas/iframe-entry.ts +24 -12
  170. package/src/canvas/iframe-host.ts +134 -62
  171. package/src/canvas/iframe-keys.ts +11 -0
  172. package/src/canvas/iframe-patch.ts +8 -7
  173. package/src/canvas/iframe-protocol.ts +24 -5
  174. package/src/canvas/iframe-render.ts +48 -1
  175. package/src/canvas/iframe-subtree.ts +5 -2
  176. package/src/canvas/npm-modules.ts +22 -0
  177. package/src/canvas/preview-navigate.ts +16 -0
  178. package/src/canvas/repeater-sources.ts +200 -0
  179. package/src/canvas/stage-scrollbar.ts +5 -1
  180. package/src/canvas/surface-registry.ts +6 -0
  181. package/src/commands/app-commands.ts +16 -6
  182. package/src/commands/budget.ts +10 -8
  183. package/src/commands/context.ts +35 -10
  184. package/src/commands/defaults.ts +69 -45
  185. package/src/commands/keymap.ts +9 -0
  186. package/src/commands/levels.ts +11 -5
  187. package/src/commands/live-context.ts +2 -0
  188. package/src/commands/registry.ts +10 -1
  189. package/src/content/collection-match.ts +6 -5
  190. package/src/content/collection-pages.ts +412 -0
  191. package/src/content/content-collections.ts +270 -0
  192. package/src/content/entry-commands.ts +51 -60
  193. package/src/content/entry-editor.ts +111 -18
  194. package/src/content/entry-fields.ts +13 -1
  195. package/src/content/entry-inspector.ts +225 -0
  196. package/src/content/entry-model.ts +17 -3
  197. package/src/content/entry-open.ts +80 -0
  198. package/src/content/entry-summaries.ts +440 -0
  199. package/src/content/file-record-ids.ts +80 -0
  200. package/src/content/file-records.ts +125 -0
  201. package/src/content/page-summaries.ts +129 -0
  202. package/src/content/record-entry.ts +201 -0
  203. package/src/content/writing-banner.ts +177 -0
  204. package/src/create/add-new-commands.ts +185 -0
  205. package/src/create/add-new-flow.ts +1116 -0
  206. package/src/create/add-new.ts +1014 -0
  207. package/src/create/element-name.ts +121 -0
  208. package/src/editor/convert-to-component.ts +67 -43
  209. package/src/editor/file-drop-action.ts +9 -1
  210. package/src/editor/inline-edit-apply.ts +44 -0
  211. package/src/editor/inline-edit.ts +10 -0
  212. package/src/editor/insert-component.ts +91 -0
  213. package/src/editor/insert-zone-action.ts +13 -4
  214. package/src/editor/shortcuts.ts +44 -22
  215. package/src/editor/slash-menu.ts +51 -8
  216. package/src/files/components.ts +74 -10
  217. package/src/files/file-ops.ts +15 -5
  218. package/src/files/files.ts +164 -150
  219. package/src/files/fs-events.ts +18 -7
  220. package/src/files/media-meta.ts +95 -1
  221. package/src/files/media-types.ts +55 -0
  222. package/src/files/media-upload.ts +209 -52
  223. package/src/files/new-file-name.ts +156 -0
  224. package/src/files/serialize-document.ts +13 -3
  225. package/src/format/format-host.ts +15 -0
  226. package/src/github/github-auth.ts +2 -2
  227. package/src/github/github-publish.ts +4 -3
  228. package/src/grid/grid-controller.ts +5 -1
  229. package/src/grid/grid-open.ts +0 -27
  230. package/src/grid/grid-panel.ts +54 -2
  231. package/src/grid/grid-reveal.ts +34 -0
  232. package/src/grid/grid-source.ts +3 -25
  233. package/src/grid/grid-view.ts +31 -6
  234. package/src/grid/sources/content-source.ts +75 -7
  235. package/src/grid/tabulator-tables.d.ts +6 -0
  236. package/src/hosting/document.ts +2 -2
  237. package/src/i18n/i18n-commands.ts +2 -1
  238. package/src/media/media-commands.ts +181 -0
  239. package/src/media/media-library-model.ts +232 -0
  240. package/src/media/media-library.ts +1283 -0
  241. package/src/media/media-pane.ts +47 -19
  242. package/src/packages/pull-package-sync.ts +1 -1
  243. package/src/panels/activity-panel.ts +21 -5
  244. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  245. package/src/panels/block-action-bar.ts +11 -11
  246. package/src/panels/canvas-dnd-bridge.ts +5 -2
  247. package/src/panels/chat-panel.ts +6 -6
  248. package/src/panels/collections-panel.ts +306 -0
  249. package/src/panels/component-preview.ts +35 -13
  250. package/src/panels/data-explorer.ts +1 -1
  251. package/src/panels/data-grid.ts +4 -0
  252. package/src/panels/dnd.ts +17 -30
  253. package/src/panels/elements-panel.ts +9 -2
  254. package/src/panels/empty-state.ts +2 -2
  255. package/src/panels/formula-workspace.ts +2 -3
  256. package/src/panels/frontmatter-fields.ts +9 -9
  257. package/src/panels/git-diff-open.ts +9 -5
  258. package/src/panels/head-panel.ts +369 -103
  259. package/src/panels/i18n-panel.ts +11 -10
  260. package/src/panels/imports-panel.ts +2 -0
  261. package/src/panels/jump-bar.ts +27 -2
  262. package/src/panels/layers-panel.ts +36 -30
  263. package/src/panels/left-panel.ts +22 -8
  264. package/src/panels/navigator-panels.ts +23 -11
  265. package/src/panels/pane-context.ts +111 -29
  266. package/src/panels/pane-grid.ts +6 -6
  267. package/src/panels/panel-registry.ts +14 -9
  268. package/src/panels/properties-panel.ts +7 -3
  269. package/src/panels/right-panel.ts +199 -43
  270. package/src/panels/seo-modal.ts +41 -108
  271. package/src/panels/settings-menu.ts +52 -50
  272. package/src/panels/settings-pane.ts +268 -162
  273. package/src/panels/signals-panel.ts +3 -4
  274. package/src/panels/site-model.ts +367 -0
  275. package/src/panels/site-panel.ts +638 -0
  276. package/src/panels/style-panel.ts +37 -3
  277. package/src/panels/stylebook-doc.ts +142 -10
  278. package/src/panels/stylebook-layers-panel.ts +39 -80
  279. package/src/panels/stylebook-panel.ts +47 -10
  280. package/src/panels/styles-panel.ts +327 -0
  281. package/src/panels/tab-strip.ts +109 -25
  282. package/src/platform.ts +1 -1
  283. package/src/platforms/cloud.ts +28 -1
  284. package/src/platforms/default-platform.ts +4 -4
  285. package/src/platforms/devserver.ts +51 -25
  286. package/src/publish/deploy-checklist.ts +12 -7
  287. package/src/publish/pages-service.ts +38 -14
  288. package/src/publish/publish-changes.ts +491 -0
  289. package/src/publish/publish-commands.ts +83 -18
  290. package/src/publish/publish-ids.ts +49 -0
  291. package/src/publish/publish-quick.ts +148 -0
  292. package/src/publish/publish-workspace.ts +926 -0
  293. package/src/publish/source-control.ts +907 -0
  294. package/src/services/automation.ts +16 -20
  295. package/src/services/cf-settings.ts +4 -4
  296. package/src/services/connection.ts +2 -2
  297. package/src/services/directory-picker.ts +2 -2
  298. package/src/services/references.ts +0 -0
  299. package/src/services/render-critic.ts +21 -2
  300. package/src/services/settings/definitions.ts +25 -14
  301. package/src/settings/contributed-section.ts +49 -10
  302. package/src/settings/css-vars-editor.ts +93 -27
  303. package/src/settings/developer-panels.ts +43 -0
  304. package/src/settings/extension-sections.ts +20 -2
  305. package/src/settings/general-settings.ts +91 -21
  306. package/src/settings/preferences-dialog.ts +8 -1
  307. package/src/settings/project-sections.ts +27 -10
  308. package/src/settings/schema-field-ui.ts +3 -1
  309. package/src/settings/section-registry.ts +116 -11
  310. package/src/settings/settings-dialog.ts +192 -0
  311. package/src/settings/settings-document.ts +182 -162
  312. package/src/shell.ts +467 -431
  313. package/src/site-context.ts +64 -10
  314. package/src/state.ts +28 -9
  315. package/src/studio.ts +194 -41
  316. package/src/style/project-styles.ts +34 -0
  317. package/src/style/stylebook-specimens.ts +89 -0
  318. package/src/style/stylebook-target.ts +26 -0
  319. package/src/style/tag-inheritance.ts +105 -0
  320. package/src/style/variables-focus.ts +61 -0
  321. package/src/style/variables-view.ts +235 -0
  322. package/src/surfaces/add-new.json +1482 -0
  323. package/src/surfaces/add-new.ts +325 -0
  324. package/src/surfaces/ai-chat.ts +2 -2
  325. package/src/surfaces/boot-failure.json +4 -3
  326. package/src/surfaces/bottom-dock.json +1 -1
  327. package/src/surfaces/canvas-stage.json +30 -19
  328. package/src/surfaces/canvas-stage.ts +5 -5
  329. package/src/surfaces/collections-panel.json +615 -0
  330. package/src/surfaces/collections-panel.ts +168 -0
  331. package/src/surfaces/commandbar.json +241 -96
  332. package/src/surfaces/commandbar.ts +134 -99
  333. package/src/surfaces/empty-state.json +1 -1
  334. package/src/surfaces/entry-editor.json +136 -0
  335. package/src/surfaces/entry-editor.ts +21 -0
  336. package/src/surfaces/entry-inspector.json +371 -0
  337. package/src/surfaces/entry-inspector.ts +143 -0
  338. package/src/surfaces/inspector-dock.json +162 -14
  339. package/src/surfaces/inspector-dock.ts +46 -19
  340. package/src/surfaces/library-pane.json +670 -437
  341. package/src/surfaces/library-pane.ts +94 -59
  342. package/src/surfaces/media-browser.json +62 -6
  343. package/src/surfaces/media-browser.ts +15 -1
  344. package/src/surfaces/media-field.json +1 -1
  345. package/src/surfaces/media-library.json +1586 -0
  346. package/src/surfaces/media-library.ts +282 -0
  347. package/src/surfaces/media-pick-dialog.json +71 -0
  348. package/src/surfaces/media-pick-dialog.ts +132 -0
  349. package/src/surfaces/menu.ts +18 -0
  350. package/src/surfaces/pane-context.json +144 -77
  351. package/src/surfaces/pane-context.ts +24 -0
  352. package/src/surfaces/panel-deploy-checklist.json +12 -6
  353. package/src/surfaces/panel-deploy-checklist.ts +3 -1
  354. package/src/surfaces/panel-page.json +72 -2
  355. package/src/surfaces/panel-page.ts +38 -7
  356. package/src/surfaces/panel-signals.json +1 -1
  357. package/src/surfaces/panel-signals.ts +5 -5
  358. package/src/surfaces/panel-stylebook-layers.json +71 -204
  359. package/src/surfaces/panel-stylebook-layers.ts +0 -21
  360. package/src/surfaces/preferences.json +120 -48
  361. package/src/surfaces/preferences.ts +8 -0
  362. package/src/surfaces/publish-quick.json +428 -0
  363. package/src/surfaces/publish-quick.ts +165 -0
  364. package/src/surfaces/publish-workspace.json +2892 -0
  365. package/src/surfaces/publish-workspace.ts +391 -0
  366. package/src/surfaces/rail.json +1 -159
  367. package/src/surfaces/rail.ts +18 -75
  368. package/src/surfaces/schema-form.json +10 -2
  369. package/src/surfaces/schema-form.ts +2 -0
  370. package/src/surfaces/seo.json +1 -1
  371. package/src/surfaces/settings-contributed.json +5 -5
  372. package/src/surfaces/settings-contributed.ts +18 -2
  373. package/src/surfaces/settings-css-vars.json +44 -36
  374. package/src/surfaces/settings-css-vars.ts +77 -4
  375. package/src/surfaces/settings-deploy.json +2 -15
  376. package/src/surfaces/settings-deploy.ts +1 -1
  377. package/src/surfaces/settings-dialog.json +51 -0
  378. package/src/surfaces/settings-dialog.ts +169 -0
  379. package/src/surfaces/settings-overview.json +3 -3
  380. package/src/surfaces/settings-overview.ts +9 -2
  381. package/src/surfaces/settings-pane.json +269 -46
  382. package/src/surfaces/settings-pane.ts +85 -24
  383. package/src/surfaces/shell.json +2 -1
  384. package/src/surfaces/site-panel.json +1029 -0
  385. package/src/surfaces/site-panel.ts +233 -0
  386. package/src/surfaces/slash-menu.json +63 -21
  387. package/src/surfaces/slash-menu.ts +23 -0
  388. package/src/surfaces/statusbar.ts +39 -15
  389. package/src/surfaces/styles-panel.json +735 -0
  390. package/src/surfaces/styles-panel.ts +195 -0
  391. package/src/surfaces/styles-variables.json +149 -0
  392. package/src/surfaces/styles-variables.ts +145 -0
  393. package/src/surfaces/tab-strip.json +4 -4
  394. package/src/surfaces/welcome.ts +1 -1
  395. package/src/surfaces/writing-banner.json +94 -0
  396. package/src/surfaces/writing-banner.ts +80 -0
  397. package/src/tabs/bare-repeaters.ts +101 -0
  398. package/src/tabs/tab.ts +47 -7
  399. package/src/types.ts +21 -26
  400. package/src/ui/form-controls.ts +47 -8
  401. package/src/ui/layers.ts +13 -0
  402. package/src/ui/media-picker.ts +284 -40
  403. package/src/ui/regions.ts +7 -6
  404. package/src/ui/schema-form.ts +259 -27
  405. package/src/ui/virtual-window.ts +26 -1
  406. package/src/utils/base64.ts +3 -3
  407. package/src/utils/edit-display.ts +322 -67
  408. package/src/utils/local-day.ts +18 -0
  409. package/src/workspace/pane-derive.ts +4 -4
  410. package/src/workspace/session.ts +28 -7
  411. package/src/workspace/tab-workspace.ts +137 -0
  412. package/src/workspace/workspace-back.ts +189 -0
  413. package/src/workspace/workspace-home.ts +133 -0
  414. package/src/workspace/workspace-ids.ts +129 -0
  415. package/src/workspace/workspace-switch.ts +372 -0
  416. package/src/workspace/workspace.ts +125 -11
  417. package/styles/shell-frame.css +30 -7
  418. package/styles/shell-frame.json +15 -3
  419. package/dist/chunks/2020-f2gkpy8d.js +0 -4
  420. package/dist/chunks/adapter-4912g339.js +0 -4
  421. package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
  422. package/dist/chunks/cf-settings-br6105tr.js +0 -4
  423. package/dist/chunks/color-28ksk2qm.js +0 -4
  424. package/dist/chunks/components-db68vsn7.js +0 -4
  425. package/dist/chunks/content-source-1449qesq.js +0 -4
  426. package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
  427. package/dist/chunks/editor-x9jn86a7.js +0 -4
  428. package/dist/chunks/entry-commands-may24cpt.js +0 -4
  429. package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
  430. package/dist/chunks/file-ops-x9v54pcj.js +0 -4
  431. package/dist/chunks/files-j3knqf0s.js +0 -4
  432. package/dist/chunks/format-host-tyre2trb.js +0 -4
  433. package/dist/chunks/fs-events-64ma9htc.js +0 -4
  434. package/dist/chunks/git-panel-84ps5dex.js +0 -4
  435. package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
  436. package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
  437. package/dist/chunks/index-b8xw3vy9.js +0 -4
  438. package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
  439. package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
  440. package/dist/chunks/layers-h4xp1pss.js +0 -4
  441. package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
  442. package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
  443. package/dist/chunks/media-picker-2cweexc5.js +0 -4
  444. package/dist/chunks/menu-ynw13y0s.js +0 -4
  445. package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
  446. package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
  447. package/dist/chunks/notify-cj5zbrs2.js +0 -4
  448. package/dist/chunks/parse-b7ddhr8m.js +0 -4
  449. package/dist/chunks/platform-3dfws9js.js +0 -4
  450. package/dist/chunks/popover-jt2gxmzs.js +0 -4
  451. package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
  452. package/dist/chunks/quick-search-0dajrwqg.js +0 -4
  453. package/dist/chunks/references-49qgt404.js +0 -4
  454. package/dist/chunks/right-panel-jm1bwe53.js +0 -4
  455. package/dist/chunks/section-registry-6kwc4fky.js +0 -4
  456. package/dist/chunks/studio-0rt52vpq.js +0 -5
  457. package/dist/chunks/studio-18vgbhs5.js +0 -5
  458. package/dist/chunks/studio-24mccdrj.js +0 -5
  459. package/dist/chunks/studio-2eh507zk.js +0 -9
  460. package/dist/chunks/studio-2hcbccfv.js +0 -5
  461. package/dist/chunks/studio-2jbs3rxv.js +0 -5
  462. package/dist/chunks/studio-4h8k4dw9.js +0 -5
  463. package/dist/chunks/studio-5f6n18kx.js +0 -5
  464. package/dist/chunks/studio-5gthpky6.js +0 -5
  465. package/dist/chunks/studio-6ep3js6b.js +0 -9
  466. package/dist/chunks/studio-6wkmf3wz.js +0 -9
  467. package/dist/chunks/studio-841rf3cg.js +0 -5
  468. package/dist/chunks/studio-8gmwgheg.js +0 -5
  469. package/dist/chunks/studio-8qm0ep50.js +0 -5
  470. package/dist/chunks/studio-924p1tm1.js +0 -6
  471. package/dist/chunks/studio-a3shpz9y.js +0 -5
  472. package/dist/chunks/studio-amsbaaar.js +0 -6
  473. package/dist/chunks/studio-at5spjbc.js +0 -7
  474. package/dist/chunks/studio-b2xv945e.js +0 -5
  475. package/dist/chunks/studio-bn5nkafw.js +0 -5
  476. package/dist/chunks/studio-bw6q5xjf.js +0 -9
  477. package/dist/chunks/studio-c7q0t9x1.js +0 -5
  478. package/dist/chunks/studio-camnhc96.js +0 -6
  479. package/dist/chunks/studio-cffqvnzd.js +0 -5
  480. package/dist/chunks/studio-efvfrsf8.js +0 -5
  481. package/dist/chunks/studio-er30bpcx.js +0 -5
  482. package/dist/chunks/studio-ezscgr64.js +0 -5
  483. package/dist/chunks/studio-ffrrncvz.js +0 -5
  484. package/dist/chunks/studio-fpphgn8y.js +0 -10
  485. package/dist/chunks/studio-j1kvhdjk.js +0 -4
  486. package/dist/chunks/studio-j430n16g.js +0 -7
  487. package/dist/chunks/studio-jjkg84nj.js +0 -5
  488. package/dist/chunks/studio-m0q32ars.js +0 -4
  489. package/dist/chunks/studio-m6bdst11.js +0 -5
  490. package/dist/chunks/studio-nv2cptd4.js +0 -64
  491. package/dist/chunks/studio-nwfrc98n.js +0 -5
  492. package/dist/chunks/studio-p1wgvp7r.js +0 -5
  493. package/dist/chunks/studio-pag2wncm.js +0 -5
  494. package/dist/chunks/studio-qvanvzfd.js +0 -5
  495. package/dist/chunks/studio-qwa64kt7.js +0 -5
  496. package/dist/chunks/studio-rk1zc4x3.js +0 -928
  497. package/dist/chunks/studio-se2r3ptc.js +0 -5
  498. package/dist/chunks/studio-sg2a0dh0.js +0 -5
  499. package/dist/chunks/studio-tjzjhe68.js +0 -5
  500. package/dist/chunks/studio-v2w7q8r1.js +0 -7
  501. package/dist/chunks/studio-v5vjq1h0.js +0 -4
  502. package/dist/chunks/studio-v8aga3vp.js +0 -14
  503. package/dist/chunks/studio-vfcdrfmv.js +0 -5
  504. package/dist/chunks/studio-vmfkgdjf.js +0 -5
  505. package/dist/chunks/studio-wt1816jj.js +0 -5
  506. package/dist/chunks/studio-wz73q5kq.js +0 -4
  507. package/dist/chunks/studio-y04qtxvp.js +0 -7
  508. package/dist/chunks/studio-y21g8zzg.js +0 -5
  509. package/dist/chunks/studio-y64hrt8p.js +0 -12
  510. package/dist/chunks/studio-ynn90f58.js +0 -16
  511. package/dist/chunks/studio-yxz682sx.js +0 -5
  512. package/dist/chunks/studio-zp7snvkq.js +0 -5
  513. package/dist/chunks/studio-zq4z6tm6.js +0 -5
  514. package/dist/chunks/toast-c9fn075p.js +0 -4
  515. package/dist/chunks/tsMode-sf49ee9x.js +0 -14
  516. package/dist/chunks/workspace-jtfahpee.js +0 -4
  517. package/src/panels/frontmatter-panel.ts +0 -711
  518. package/src/panels/git-panel.ts +0 -1108
  519. package/src/surfaces/doc-header.json +0 -776
  520. package/src/surfaces/doc-header.ts +0 -222
  521. package/src/surfaces/git-panel.json +0 -1880
  522. package/src/surfaces/git-panel.ts +0 -264
@@ -0,0 +1,282 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * The Media workspace's library, as a mounted document.
4
+ *
5
+ * This is the adapter. `media/media-library.ts` is the flow: which files a filter keeps, in what
6
+ * order, what each count may claim, which tile is selected, where an arrow lands and what Replace,
7
+ * Delete and an upload write. It hands this module one projection, and this module hands the
8
+ * document a scope and reports the nodes the flow needs to hold.
9
+ *
10
+ * **Four islands, all through `onNodeCreated`.** The flow needs four nodes the document creates:
11
+ * each tile (watched for viewport entry, so a thumbnail is requested only when it is looked at, and
12
+ * focused when the keyboard moves the selection onto it), the grid (measured, so ArrowDown lands on
13
+ * the tile drawn under the current one), and the two file inputs (opened by `media.upload` and
14
+ * `media.replace`). Each is announced as it is created, which is the one seam for a node a document
15
+ * made (`studio-ui-guidelines.md` §9.4); a node found by selector once would be detached DOM the
16
+ * moment a `$switch` moved.
17
+ *
18
+ * **The host is cleared in the pane and not in the dialog.** The pane's stage is handed to the mode
19
+ * that owns it whole, and emptying it is what stops two libraries stacking when a re-render lands
20
+ * before the first mount settled. The dialog's slot is this document's alone already.
21
+ *
22
+ * @docs studio/projects/media
23
+ */
24
+
25
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
26
+ import { reactive } from "../reactivity";
27
+ import { mountSurface, registerSurface } from "../ui/surface";
28
+ import mediaLibraryDoc from "./media-library.json";
29
+ import type { JxElement } from "@jxsuite/schema/types";
30
+ import type { JxScope } from "@jxsuite/runtime/types";
31
+ import type { SurfaceHandle } from "../ui/surface";
32
+ import type { MediaUsageRow } from "./media-pane";
33
+
34
+ registerSurface("media-library", mediaLibraryDoc);
35
+
36
+ /** One filter in the left column. */
37
+ export interface MediaFilterRow {
38
+ key: string;
39
+ label: string;
40
+ /** The count, already a string; `""` while it is not known (Unused before its sweep). */
41
+ count: string;
42
+ pressed: "true" | "false";
43
+ }
44
+
45
+ /** One tile in the grid. */
46
+ export interface MediaTileRow {
47
+ /** The row's identity across a filter or a sort: the file's path on disk. */
48
+ key: string;
49
+ file: string;
50
+ name: string;
51
+ /** "1200 × 800 · 84 KB", or the file's kind when nothing about it is measured yet. */
52
+ caption: string;
53
+ selected: "true" | "false";
54
+ /** The roving tab stop: `"0"` on exactly one tile, `"-1"` on every other. */
55
+ tabindex: "0" | "-1";
56
+ /** `pending` until the tile has scrolled into view, then `image`; a file with no picture: `glyph`. */
57
+ thumbState: "image" | "pending" | "glyph";
58
+ thumbSrc: string;
59
+ glyph: string;
60
+ }
61
+
62
+ /** Everything the document draws, as one value. */
63
+ export interface MediaLibraryView {
64
+ region: string;
65
+ mode: "manage" | "pick";
66
+ dropActive: "true" | "false";
67
+ filters: MediaFilterRow[];
68
+ title: string;
69
+ titleId: string;
70
+ query: string;
71
+ sort: string;
72
+ sortOptions: { label: string; value: string }[];
73
+ uploadAccept: string;
74
+ /** Where an upload lands, said before the files are chosen: "Upload into public/media/". */
75
+ uploadHint: string;
76
+ gridState: "loading" | "counting" | "empty" | "nomatch" | "listed";
77
+ countingLabel: string;
78
+ emptyTitle: string;
79
+ emptyDetail: string;
80
+ tiles: MediaTileRow[];
81
+ detailState: "none" | "shown";
82
+ detailHint: string;
83
+ selectedFile: string;
84
+ detailName: string;
85
+ detailFacts: string;
86
+ detailRef: string;
87
+ /**
88
+ * The viewer's stage for the file (`media/media-pane.ts`), minus the ones a side pane cannot
89
+ * hold.
90
+ */
91
+ previewKind: "image" | "video" | "audio" | "font" | "glyph";
92
+ previewSrc: string;
93
+ previewGlyph: string;
94
+ /** A font's scoped `@font-face`, the declaration naming its family, and the pangram; else `""`. */
95
+ previewFontFace: string;
96
+ previewSpecimenFamily: string;
97
+ previewSpecimen: string;
98
+ /** The Replace input's `accept`: the selected file's own format only. */
99
+ replaceAccept: string;
100
+ usageState: "hidden" | "shown";
101
+ usageHeadline: string;
102
+ usageFiles: MediaUsageRow[];
103
+ }
104
+
105
+ /** What a control asks the flow to do. */
106
+ export interface MediaLibraryActions {
107
+ setFilter: (key: string) => void;
108
+ setQuery: (value: string) => void;
109
+ setSort: (value: string) => void;
110
+ upload: (input: HTMLInputElement) => void;
111
+ dragOver: () => void;
112
+ dragOut: () => void;
113
+ drop: (files: FileList | null) => void;
114
+ select: (file: string) => void;
115
+ /** A tile received focus: selection follows it, so the first Enter acts on the tile in the ring. */
116
+ focusTile: (file: string) => void;
117
+ /** A double-click: open the file in its viewer, or in pick mode, use it. */
118
+ activate: (file: string) => void;
119
+ /** Enter on the grid: the same, for the selected file. */
120
+ activateSelected: () => void;
121
+ key: (key: string, ctrl: boolean) => void;
122
+ measure: (file: string, width: number, height: number) => void;
123
+ copyRef: () => void;
124
+ openDocument: (path: string) => void;
125
+ replace: (input: HTMLInputElement) => void;
126
+ remove: () => void;
127
+ openViewer: () => void;
128
+ reset: () => void;
129
+ /** A tile node was created for `file`. */
130
+ tileHost: (element: HTMLElement, file: string) => void;
131
+ /** The grid node was created. */
132
+ gridHost: (element: HTMLElement) => void;
133
+ /** A file input was created: the toolbar's Upload (`upload`) or the detail's Replace. */
134
+ inputHost: (element: HTMLInputElement, role: "upload" | "replace") => void;
135
+ }
136
+
137
+ export interface MediaLibrarySurfaceHandle {
138
+ ready: Promise<HTMLElement>;
139
+ /** Whether what was mounted is still inside the host (a mount still in flight counts). */
140
+ attached: () => boolean;
141
+ update: (view: MediaLibraryView) => void;
142
+ dispose: () => void;
143
+ }
144
+
145
+ /** The scope the document reads. */
146
+ interface MediaLibraryScope
147
+ extends MediaLibraryView, Omit<MediaLibraryActions, "tileHost" | "gridHost" | "inputHost"> {
148
+ hasUsageFiles: boolean;
149
+ }
150
+
151
+ /** An empty view: what a scope holds before the first projection. */
152
+ export function emptyMediaLibraryView(): MediaLibraryView {
153
+ return {
154
+ countingLabel: "",
155
+ detailFacts: "",
156
+ detailHint: "",
157
+ detailName: "",
158
+ detailRef: "",
159
+ detailState: "none",
160
+ dropActive: "false",
161
+ emptyDetail: "",
162
+ emptyTitle: "",
163
+ filters: [],
164
+ gridState: "loading",
165
+ mode: "manage",
166
+ previewFontFace: "",
167
+ previewGlyph: "",
168
+ previewKind: "glyph",
169
+ previewSpecimen: "",
170
+ previewSpecimenFamily: "",
171
+ previewSrc: "",
172
+ query: "",
173
+ region: "",
174
+ replaceAccept: "",
175
+ selectedFile: "",
176
+ sort: "",
177
+ sortOptions: [],
178
+ tiles: [],
179
+ title: "",
180
+ titleId: "",
181
+ uploadAccept: "",
182
+ uploadHint: "",
183
+ usageFiles: [],
184
+ usageHeadline: "",
185
+ usageState: "hidden",
186
+ };
187
+ }
188
+
189
+ function project(scope: MediaLibraryScope, view: MediaLibraryView): void {
190
+ Object.assign(scope, view);
191
+ scope.hasUsageFiles = view.usageFiles.length > 0;
192
+ }
193
+
194
+ /** The `part` a definition declares, or `""`. */
195
+ function partOf(def: JxElement | string): string {
196
+ const part = isString(def) ? undefined : def.attributes?.["part"];
197
+ return isString(part) ? part : "";
198
+ }
199
+
200
+ /** The file a mapped tile stands for, read off its `$map` item. */
201
+ function mappedFile(state: JxScope | undefined): string | null {
202
+ const map = state?.["$map"];
203
+ const item = isNonNullObject(map) && "item" in map ? map.item : undefined;
204
+ return isNonNullObject(item) && "file" in item && isString(item.file) ? item.file : null;
205
+ }
206
+
207
+ /**
208
+ * Mount the library into `host`.
209
+ *
210
+ * @param {HTMLElement} host - The pane's stage, or the pick dialog's slot
211
+ * @param {MediaLibraryView} view - What to draw right now
212
+ * @param {MediaLibraryActions} actions - What each control does
213
+ * @param {{ clear: boolean }} options - Whether the host is a stage to be emptied first
214
+ * @returns {MediaLibrarySurfaceHandle}
215
+ */
216
+ export function mountMediaLibrarySurface(
217
+ host: HTMLElement,
218
+ view: MediaLibraryView,
219
+ actions: MediaLibraryActions,
220
+ options: { clear: boolean },
221
+ ): MediaLibrarySurfaceHandle {
222
+ if (options.clear) {
223
+ host.replaceChildren();
224
+ }
225
+ const { tileHost, gridHost, inputHost, ...controls } = actions;
226
+ const scope = reactive<MediaLibraryScope>({
227
+ ...emptyMediaLibraryView(),
228
+ ...controls,
229
+ hasUsageFiles: false,
230
+ });
231
+ project(scope, view);
232
+
233
+ let mounted: SurfaceHandle | null = null;
234
+ let disposed = false;
235
+ const ready = mountSurface("media-library", scope, host, {
236
+ onNodeCreated: (element, _path, def, state) => {
237
+ // `disposed` first: nodes are still created while a mount that was taken down runs out.
238
+ if (disposed || !(element instanceof HTMLElement)) {
239
+ return;
240
+ }
241
+ const part = partOf(def);
242
+ if (part === "tile") {
243
+ const file = mappedFile(state);
244
+ if (file !== null) {
245
+ tileHost(element, file);
246
+ }
247
+ } else if (part === "grid") {
248
+ gridHost(element);
249
+ } else if (element instanceof HTMLInputElement && part === "upload-input") {
250
+ inputHost(element, "upload");
251
+ } else if (element instanceof HTMLInputElement && part === "replace-input") {
252
+ inputHost(element, "replace");
253
+ }
254
+ },
255
+ }).then((surface) => {
256
+ if (disposed) {
257
+ surface.dispose();
258
+ } else {
259
+ mounted = surface;
260
+ }
261
+ /* SAFETY: `media-library.json`'s root definition is a `div` element, so the runtime mounts an
262
+ HTMLElement; a `Text` root only comes from a document whose root is a bare string. */
263
+ return surface.root as HTMLElement;
264
+ });
265
+
266
+ return {
267
+ attached: () => {
268
+ if (disposed) {
269
+ return false;
270
+ }
271
+ const root = mounted?.root;
272
+ return root === undefined ? true : root instanceof HTMLElement && host.contains(root);
273
+ },
274
+ dispose() {
275
+ disposed = true;
276
+ mounted?.dispose();
277
+ mounted = null;
278
+ },
279
+ ready,
280
+ update: (next) => project(scope, next),
281
+ };
282
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "https://jxsuite.com/schema/v1",
3
+ "$id": "StudioMediaPickDialog",
4
+ "$description": "The full-size media picker (`specs/studio.md` §9.3): a `jx-dialog` whose body is the Media workspace's own library surface in pick mode, so the picker and the workspace are one surface at two sizes. The dialog owns modality, Escape, the backdrop and focus restoration, and its footer is the answer: Cancel, or Use <file>, disabled until a file is chosen. The body is an ISLAND: this document draws the slot and nothing in it, and `surfaces/media-pick-dialog.ts` mounts `media-library.json` there through `onNodeCreated`.",
5
+ "tagName": "jx-dialog",
6
+ "$props": {
7
+ "headline": {
8
+ "$ref": "#/state/headline"
9
+ },
10
+ "confirmLabel": {
11
+ "$ref": "#/state/confirmLabel"
12
+ },
13
+ "confirmDisabled": {
14
+ "$ref": "#/state/blocked"
15
+ },
16
+ "cancelLabel": "Cancel",
17
+ "dismissible": true,
18
+ "size": "xl"
19
+ },
20
+ "attributes": {
21
+ "part": "media-pick"
22
+ },
23
+ "onconfirm": {
24
+ "$prototype": "Function",
25
+ "body": [
26
+ {
27
+ "operator": "call",
28
+ "target": {
29
+ "$ref": "#/state/confirm"
30
+ },
31
+ "value": []
32
+ }
33
+ ]
34
+ },
35
+ "oncancel": {
36
+ "$prototype": "Function",
37
+ "body": [
38
+ {
39
+ "operator": "call",
40
+ "target": {
41
+ "$ref": "#/state/closed"
42
+ },
43
+ "value": []
44
+ }
45
+ ]
46
+ },
47
+ "onclose": {
48
+ "$prototype": "Function",
49
+ "body": [
50
+ {
51
+ "operator": "call",
52
+ "target": {
53
+ "$ref": "#/state/closed"
54
+ },
55
+ "value": []
56
+ }
57
+ ]
58
+ },
59
+ "children": [
60
+ {
61
+ "tagName": "div",
62
+ "attributes": {
63
+ "part": "library-slot"
64
+ },
65
+ "style": {
66
+ "$description": "The library's box in pick mode is its own (`media-library.json`, `data-mode=\"pick\"`); the slot only gives it the dialog body's width.",
67
+ "minWidth": "0"
68
+ }
69
+ }
70
+ ]
71
+ }
@@ -0,0 +1,132 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * The full-size media picker's dialog, as a mounted document.
4
+ *
5
+ * A `jx-dialog` in the dialog layer whose body is an island: `media-pick-dialog.json` draws the
6
+ * slot, and the flow (`media/media-library.ts`) mounts the Media workspace's own library into it in
7
+ * pick mode, through the `onNodeCreated` seam (`studio-ui-guidelines.md` §9.4). So the picker and
8
+ * the workspace are one surface at two sizes, and the dialog is only the frame and the answer:
9
+ * Cancel, or Use <file>.
10
+ *
11
+ * **Await the ELEMENT, not just the mount.** `mountSurface` resolving means the document rendered;
12
+ * a `jx-dialog`'s own template is one `connectedCallback` later, and `showModal` in between finds
13
+ * no `<dialog>` to open. `whenReady` is shared with `surfaces/dialog.ts`.
14
+ *
15
+ * @docs studio/projects/media
16
+ */
17
+
18
+ import { reactive } from "../reactivity";
19
+ import { mountSurface, registerSurface } from "../ui/surface";
20
+ import { overlayRegion, REGION_ATTR } from "../ui/regions";
21
+ import { close, showModal } from "@jxsuite/ui/behaviors/dialog";
22
+ import { whenReady } from "./dialog";
23
+ import pickDoc from "./media-pick-dialog.json";
24
+ import type { JxElement } from "@jxsuite/schema/types";
25
+ import type { DialogLayerHandle, SurfaceHandle } from "../ui/surface";
26
+ import { isString } from "@jxsuite/schema/guards";
27
+
28
+ registerSurface("media-pick-dialog", pickDoc);
29
+
30
+ /** The slot id, and so the dialog's region: `overlay.dialog:media-picker`. */
31
+ export const MEDIA_PICK_SLOT = "media-picker";
32
+
33
+ /** What the dialog's own chrome says. */
34
+ export interface MediaPickDialogView {
35
+ headline: string;
36
+ /** "Use hero.jpg", or "Use file" while nothing is chosen. */
37
+ confirmLabel: string;
38
+ /** No file is chosen, so there is nothing to use yet. */
39
+ blocked: boolean;
40
+ }
41
+
42
+ export interface MediaPickDialogOptions {
43
+ layer: HTMLElement;
44
+ view: MediaPickDialogView;
45
+ /** The body slot was created: where the flow mounts the library. */
46
+ body: (host: HTMLElement) => void;
47
+ confirm: () => void;
48
+ /** The dialog closed, for any reason, once. */
49
+ closed: () => void;
50
+ }
51
+
52
+ export interface MediaPickDialogHandle extends DialogLayerHandle {
53
+ update: (view: MediaPickDialogView) => void;
54
+ }
55
+
56
+ interface MediaPickScope extends MediaPickDialogView {
57
+ confirm: () => void;
58
+ closed: () => void;
59
+ }
60
+
61
+ function partOf(def: JxElement | string): string {
62
+ const part = isString(def) ? undefined : def.attributes?.["part"];
63
+ return isString(part) ? part : "";
64
+ }
65
+
66
+ /** Open the dialog. The handle's `ready` resolves once it is showing. */
67
+ export function openMediaPickDialogSurface(options: MediaPickDialogOptions): MediaPickDialogHandle {
68
+ const slot = document.createElement("div");
69
+ /* The layer is `pointer-events: none`; every slot turns them back on for its own content, or a
70
+ modal `<dialog>` in it is painted above everything and hit-tests to nothing (surfaces/add-new). */
71
+ slot.style.pointerEvents = "auto";
72
+ slot.setAttribute(REGION_ATTR, overlayRegion("dialog", MEDIA_PICK_SLOT));
73
+ options.layer.append(slot);
74
+
75
+ let closed = false;
76
+ const finish = (): void => {
77
+ if (closed) {
78
+ return;
79
+ }
80
+ closed = true;
81
+ options.closed();
82
+ };
83
+ /** Read through a call, so a check after an `await` is not narrowed to the value before it. */
84
+ const isClosed = (): boolean => closed;
85
+
86
+ const scope = reactive<MediaPickScope>({
87
+ ...options.view,
88
+ closed: finish,
89
+ confirm: options.confirm,
90
+ });
91
+
92
+ let mounted: SurfaceHandle | null = null;
93
+ const ready = mountSurface("media-pick-dialog", scope, slot, {
94
+ onNodeCreated: (element, _path, def) => {
95
+ if (!isClosed() && element instanceof HTMLElement && partOf(def) === "library-slot") {
96
+ options.body(element);
97
+ }
98
+ },
99
+ }).then(async (surface) => {
100
+ mounted = surface;
101
+ /* SAFETY: `media-pick-dialog.json`'s root definition is a `jx-dialog` element, so the runtime
102
+ mounts an HTMLElement. */
103
+ const element = surface.root as HTMLElement;
104
+ if (isClosed()) {
105
+ surface.dispose();
106
+ return element;
107
+ }
108
+ await whenReady(element);
109
+ if (!isClosed()) {
110
+ showModal(element);
111
+ }
112
+ return element;
113
+ });
114
+
115
+ return {
116
+ close() {
117
+ const element = mounted?.root;
118
+ if (element instanceof HTMLElement) {
119
+ close(element);
120
+ }
121
+ mounted?.dispose();
122
+ mounted = null;
123
+ slot.remove();
124
+ finish();
125
+ },
126
+ host: slot,
127
+ ready,
128
+ update(view) {
129
+ Object.assign(scope, view);
130
+ },
131
+ };
132
+ }
@@ -257,6 +257,7 @@ export function openMenu(options: OpenMenuOptions): MenuHandle {
257
257
  }
258
258
  // Run BEFORE closing: a command reads its target synchronously on entry, and closing the
259
259
  // Menu is what clears it.
260
+ handBackKeyboard(menu, options.opener ?? null);
260
261
  if (row.run) {
261
262
  row.run();
262
263
  } else {
@@ -367,6 +368,23 @@ export function openMenu(options: OpenMenuOptions): MenuHandle {
367
368
  return handle;
368
369
  }
369
370
 
371
+ /**
372
+ * Give the keyboard back to the opener BEFORE a chosen row runs, while the menu still holds it.
373
+ *
374
+ * A row that opens a modal dialog (Open Project Settings, a confirmation) calls `showModal()` from
375
+ * inside its run, and the platform records whatever is focused at that moment as the element to
376
+ * restore when the dialog closes. Left alone that is the menu ROW, which is gone by the time the
377
+ * dialog closes, so Escape dropped focus on `<body>` instead of the gear that opened the menu. The
378
+ * opener is where focus goes when the menu closes anyway ({@link restoreFocus}); doing it first
379
+ * only makes it the element the dialog remembers. Only when the menu holds focus, for the reason
380
+ * `restoreFocus` gives.
381
+ */
382
+ function handBackKeyboard(menu: MenuElement | null, opener: HTMLElement | null): void {
383
+ if (menu?.contains(document.activeElement) && opener?.isConnected && opener !== document.body) {
384
+ opener.focus({ preventScroll: true });
385
+ }
386
+ }
387
+
370
388
  /**
371
389
  * Hand the keyboard back to the opener, only when the menu still held it: an outside CLICK has
372
390
  * already moved focus somewhere the author chose, and yanking it back would fight them. In a