@jxsuite/studio 6.1.2 → 8.0.1

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,327 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * The Styles panel — the Styles workspace's Navigator panel (`specs/studio.md` §7.1).
4
+ *
5
+ * The Styles workspace edits the project's styles in `project.json`, and this panel is the map of
6
+ * them, in the order a visit usually needs it:
7
+ *
8
+ * - **Variables.** Every CSS custom property in the root style block, by its real name, grouped as
9
+ * the Variables view groups them (`style/project-styles.ts` `groupTokens`: Colors, Fonts, Sizes &
10
+ * Spacing, and Other only when something is in it), each group with its count and each colour
11
+ * with a swatch of what it resolves to. A group heading or a property switches the pane to the
12
+ * Variables view and brings it on screen there (`style/variables-focus.ts`); **Add variable**
13
+ * focuses the view's own add row, so a variable is added the one way the editor adds one.
14
+ * - **Elements.** The element defaults, by tag name: the specimen catalogue's tags
15
+ * (`data/stylebook-meta.json`) and the project's components, a dot on each tag project.json
16
+ * already styles. A row switches the pane to the Elements view and selects the tag there
17
+ * (`selectStylebookTag`), with the Inspector open on Element › Style.
18
+ * - **Color schemes.** The schemes `$media` declares (`listTokenContexts`), and **Manage color
19
+ * schemes…**, which opens Project Settings › Contexts, where they are defined.
20
+ *
21
+ * It replaces the Outline as the Styles workspace's Navigator. The Outline still lists the element
22
+ * catalogue beside a document's Elements view (`panels/stylebook-layers-panel.ts`), which is how a
23
+ * page or a component styles its own element defaults in Design; the variables list it drew beside
24
+ * the Variables view moved here, beside the variables' groups, counts and swatches.
25
+ *
26
+ * Nothing here writes a style. Every edit happens in the view the row leads to, under that view's
27
+ * own save rule (`style/variables-view.ts` `VARIABLES_SAVING`).
28
+ *
29
+ * @docs studio/design/tokens
30
+ */
31
+
32
+ import { nothing } from "lit-html";
33
+ import { effect, effectScope } from "../reactivity";
34
+ import { projectState } from "../store";
35
+ import { setDockCollapsed, shell } from "../shell";
36
+ import { workspace } from "../workspace/workspace";
37
+ import { PROJECT_CONFIG_PATH } from "../tabs/tab";
38
+ import { componentRegistry } from "../files/components";
39
+ import { runActiveReported } from "../commands/run-reported";
40
+ import { showSettingsDocument } from "../settings/settings-document";
41
+ import { groupIdOfToken, groupTokens, listTokenContexts } from "../style/project-styles";
42
+ import { resolveTokenValue } from "../style/token-ref";
43
+ import { requestVariablesFocus } from "../style/variables-focus";
44
+ import { catalogueRows, hasTagStyle } from "./stylebook-doc";
45
+ import { selectStylebookTag, stylebookMeta } from "./stylebook-panel";
46
+ import { INDENT_BASE, INDENT_STEP } from "./stylebook-layers-panel";
47
+ import { mountStylesPanelSurface } from "../surfaces/styles-panel";
48
+ import { registerPanel } from "./panel-registry";
49
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
50
+ import type { EffectScope } from "@vue/reactivity";
51
+ import type { JxStyle } from "@jxsuite/schema/types";
52
+ import type { StylebookEntry } from "./stylebook-panel";
53
+ import type { TokenGroupId } from "../style/project-styles";
54
+ import type {
55
+ StylesElementGroup,
56
+ StylesElementRow,
57
+ StylesPanelActions,
58
+ StylesPanelSurfaceHandle,
59
+ StylesPanelValues,
60
+ StylesSchemeRow,
61
+ StylesVariableGroup,
62
+ } from "../surfaces/styles-panel";
63
+
64
+ /** The `source` every command run from here reports under. */
65
+ const SOURCE = "Styles";
66
+
67
+ /** The catalogue the Elements section lists: the specimen sections. */
68
+ export interface StylesCatalogue {
69
+ $sections: { label: string; elements: StylebookEntry[] }[];
70
+ }
71
+
72
+ /** What the panel is projected from. Injected so a test can hand in its own catalogue. */
73
+ export interface StylesPanelInput {
74
+ /** `project.json` as the panel reads it, or `null` with no project open. */
75
+ config: { style?: JxStyle; $media?: Record<string, string> } | null;
76
+ catalogue: StylesCatalogue;
77
+ /** The project's components, by tag name. */
78
+ components: readonly { tagName: string }[];
79
+ /** The tag the Elements view has selected (`shell.stylebook.selection`). */
80
+ selection: string | null;
81
+ /** The custom property the Variables view is pointed at (`shell.stylebook.variable`). */
82
+ variable: string | null;
83
+ }
84
+
85
+ /**
86
+ * `project.json` as the panel reads it: the open tab's document when the tab is open (so an edit
87
+ * that has not been saved yet is what the panel lists), else the configuration the project was
88
+ * opened with.
89
+ */
90
+ export function stylesConfig(): StylesPanelInput["config"] {
91
+ const tab = workspace.tabs.get(PROJECT_CONFIG_PATH);
92
+ return (tab ? tab.doc.document : projectState?.projectConfig) ?? null;
93
+ }
94
+
95
+ /** The input the live panel is drawn from. */
96
+ function liveInput(): StylesPanelInput {
97
+ return {
98
+ catalogue: stylebookMeta,
99
+ components: componentRegistry,
100
+ config: projectState ? stylesConfig() : null,
101
+ selection: shell.stylebook.selection,
102
+ variable: shell.stylebook.variable,
103
+ };
104
+ }
105
+
106
+ /** "1 variable", "6 variables". */
107
+ function counted(count: number, noun: string): string {
108
+ return `${count} ${noun}${count === 1 ? "" : "s"}`;
109
+ }
110
+
111
+ /** The variable groups, in the Variables view's order, the empty Other left out as it is there. */
112
+ function variableGroups(style: JxStyle, current: string | null): StylesVariableGroup[] {
113
+ return groupTokens(style)
114
+ .filter(({ group, tokens }) => group.id !== "other" || tokens.length > 0)
115
+ .map(({ group, tokens }) => ({
116
+ count: String(tokens.length),
117
+ countLabel: counted(tokens.length, "variable"),
118
+ id: group.id,
119
+ title: group.title,
120
+ variables: tokens.map((token) => {
121
+ const resolved = group.id === "color" ? resolveTokenValue(style, token.value) : undefined;
122
+ return {
123
+ name: token.name,
124
+ selected: token.name === current,
125
+ swatch: resolved === undefined ? "" : String(resolved),
126
+ swatchState: group.id === "color" ? ("swatch" as const) : ("none" as const),
127
+ value: String(token.value),
128
+ };
129
+ }),
130
+ }));
131
+ }
132
+
133
+ /**
134
+ * The Elements section: one group per catalogue section, then the project's components. The rows
135
+ * are the stylebook's own walk (`stylebook-doc.ts` `catalogueRows`, which the Outline's catalogue
136
+ * draws from too); the dot reads the nested tag paths Stylebook edits write.
137
+ */
138
+ function elementGroups(input: StylesPanelInput, style: JxStyle): StylesElementGroup[] {
139
+ const groups: StylesElementGroup[] = input.catalogue.$sections.map((section) => ({
140
+ key: section.label,
141
+ label: section.label,
142
+ rows: catalogueRows(section.elements, input.selection).map((row): StylesElementRow => ({
143
+ customized: hasTagStyle(style, row.path),
144
+ indent: `${INDENT_BASE + row.depth * INDENT_STEP}px`,
145
+ key: row.path,
146
+ selected: row.selected,
147
+ tag: row.tag,
148
+ })),
149
+ }));
150
+ if (input.components.length > 0) {
151
+ groups.push({
152
+ key: "components",
153
+ label: "Components",
154
+ rows: input.components.map((component) => ({
155
+ customized: hasTagStyle(style, component.tagName),
156
+ indent: `${INDENT_BASE}px`,
157
+ key: component.tagName,
158
+ selected: component.tagName === input.selection,
159
+ tag: component.tagName,
160
+ })),
161
+ });
162
+ }
163
+ return groups;
164
+ }
165
+
166
+ /** The color schemes `$media` declares, by name and by the query that selects each. */
167
+ function schemeRows(media: Record<string, string> | undefined): StylesSchemeRow[] {
168
+ return listTokenContexts(media)
169
+ .filter((context) => context.kind === "scheme")
170
+ .map((context) => {
171
+ const query = media?.[context.name];
172
+ return { key: context.name, label: context.label, query: isString(query) ? query : "" };
173
+ });
174
+ }
175
+
176
+ /**
177
+ * What the panel shows. Pure over its input: the configuration, the catalogue, the components and
178
+ * the two current rows.
179
+ *
180
+ * @param {StylesPanelInput} [input] Defaults to the live project.
181
+ * @returns {StylesPanelValues}
182
+ */
183
+ export function stylesPanelValues(input: StylesPanelInput = liveInput()): StylesPanelValues {
184
+ if (!input.config) {
185
+ return {
186
+ body: "none",
187
+ customizedCount: "0",
188
+ customizedLabel: "",
189
+ elementGroups: [],
190
+ groups: [],
191
+ schemes: [],
192
+ schemesState: "empty",
193
+ variableCount: "0",
194
+ variablesState: "empty",
195
+ };
196
+ }
197
+ const style: JxStyle = isNonNullObject(input.config.style) ? input.config.style : {};
198
+ const groups = variableGroups(style, input.variable);
199
+ const variableCount = groups.reduce((sum, group) => sum + group.variables.length, 0);
200
+ const elements = elementGroups(input, style);
201
+ const customized = elements.reduce(
202
+ (sum, group) => sum + group.rows.filter((row) => row.customized).length,
203
+ 0,
204
+ );
205
+ const schemes = schemeRows(input.config.$media);
206
+ return {
207
+ body: "styles",
208
+ customizedCount: `${customized} styled`,
209
+ customizedLabel: `${counted(customized, "tag")} styled`,
210
+ elementGroups: elements,
211
+ groups,
212
+ schemes,
213
+ schemesState: schemes.length > 0 ? "listed" : "empty",
214
+ variableCount: String(variableCount),
215
+ variablesState: variableCount > 0 ? "listed" : "empty",
216
+ };
217
+ }
218
+
219
+ // ─── Actions ─────────────────────────────────────────────────────────────────
220
+
221
+ /** Whether a string is a token group id. */
222
+ function isTokenGroupId(value: string): value is TokenGroupId {
223
+ return value === "color" || value === "font" || value === "size" || value === "other";
224
+ }
225
+
226
+ /** The group "Add variable" adds to: the current property's, or Colors. */
227
+ export function addTargetGroup(current: string | null = shell.stylebook.variable): TokenGroupId {
228
+ return current === null ? "color" : groupIdOfToken(current);
229
+ }
230
+
231
+ /**
232
+ * What the panel's controls do. Each one shows the view it leads to first, then asks that view to
233
+ * bring the row on screen, so a request made from Elements is served when Variables mounts.
234
+ */
235
+ export const STYLES_PANEL_ACTIONS: StylesPanelActions = {
236
+ addVariable: () => {
237
+ showSettingsDocument("tokens");
238
+ requestVariablesFocus({ add: true, group: addTargetGroup(), kind: "group" });
239
+ },
240
+ manageSchemes: () => {
241
+ void runActiveReported("settings.open", { section: "contexts" }, SOURCE);
242
+ },
243
+ selectElement: (path) => {
244
+ showSettingsDocument("stylebook");
245
+ selectStylebookTag(path, undefined, { panCanvas: true });
246
+ // `selectStylebookTag` puts the Inspector on Element › Style; the Inspector has to be open.
247
+ setDockCollapsed("right", false);
248
+ },
249
+ selectVariable: (name) => {
250
+ showSettingsDocument("tokens");
251
+ requestVariablesFocus({ kind: "variable", name });
252
+ },
253
+ showGroup: (group) => {
254
+ if (!isTokenGroupId(group)) {
255
+ return;
256
+ }
257
+ showSettingsDocument("tokens");
258
+ requestVariablesFocus({ add: false, group, kind: "group" });
259
+ },
260
+ };
261
+
262
+ // ─── Mounting ────────────────────────────────────────────────────────────────
263
+
264
+ interface StandingPanel {
265
+ host: HTMLElement;
266
+ handle: StylesPanelSurfaceHandle;
267
+ scope: EffectScope;
268
+ }
269
+
270
+ let _standing: StandingPanel | null = null;
271
+
272
+ /**
273
+ * Mount the surface into `host`, or bring the one already there up to date.
274
+ *
275
+ * The projection runs in an effect of its own, because the Navigator repaints on a document's
276
+ * IDENTITY and a variable's value is a write deep inside it: an edit in the Variables view, an undo
277
+ * or a Code edit re-projects the panel through what the effect read.
278
+ */
279
+ function mountInto(host: HTMLElement): void {
280
+ if (_standing && (_standing.host !== host || !_standing.handle.connected())) {
281
+ resetStylesPanel();
282
+ }
283
+ if (_standing) {
284
+ // A repaint of the Navigator: the component registry is not reactive, so it is read here.
285
+ _standing.handle.update(stylesPanelValues());
286
+ return;
287
+ }
288
+ const handle = mountStylesPanelSurface(host, stylesPanelValues(), STYLES_PANEL_ACTIONS);
289
+ const scope = effectScope();
290
+ scope.run(() => {
291
+ effect(() => {
292
+ handle.update(stylesPanelValues());
293
+ });
294
+ });
295
+ _standing = { handle, host, scope };
296
+ }
297
+
298
+ /** The Navigator's content area inside a panel body (`panels/collections-panel.ts` gives why). */
299
+ function contentArea(body: HTMLElement): HTMLElement {
300
+ return body.querySelector<HTMLElement>(".panel-content") ?? body;
301
+ }
302
+
303
+ /**
304
+ * Contribute the Styles panel: project level (it lists the project's styles), no rail button
305
+ * (Styles has no rail), the Styles workspace's Navigator.
306
+ */
307
+ export function registerStylesPanel(): void {
308
+ registerPanel({
309
+ id: "styles",
310
+ title: "Styles",
311
+ level: "project",
312
+ dock: "navigator",
313
+ icon: "paint-brush",
314
+ rail: false,
315
+ render: () => nothing,
316
+ afterRender: (_ctx, host) => {
317
+ mountInto(contentArea(host));
318
+ },
319
+ });
320
+ }
321
+
322
+ /** Forget the mounted panel: tests, a project switch, and a host the Navigator replaced. */
323
+ export function resetStylesPanel(): void {
324
+ _standing?.scope.stop();
325
+ _standing?.handle.dispose();
326
+ _standing = null;
327
+ }
@@ -54,6 +54,9 @@ import {
54
54
  workspace,
55
55
  } from "../workspace/workspace";
56
56
  import { gridTabLabel } from "../grid/grid-source";
57
+ import { workspaceTabOrder } from "../workspace/tab-workspace";
58
+ import { workspaceHomeLabel } from "../workspace/workspace-ids";
59
+ import { shell, workspaceDrawsTabStrip } from "../shell";
57
60
  import { entryDraftPill } from "../content/entry-editor";
58
61
  import { DRAFT_FIELD, isDraftEntry } from "../content/draft-state";
59
62
  import { entryFields } from "../content/entry-fields";
@@ -246,7 +249,11 @@ export function mount(host: HTMLElement) {
246
249
  so a fact about a pane it does not draw — or about a tab in another pane's strip — has
247
250
  no reader inside this effect. */
248
251
  }
252
+ // The strip draws the workspace on screen's tabs alone, so a switch repaints every strip.
253
+ void shell.workspace;
249
254
  for (const tab of workspace.tabs.values()) {
255
+ // A tab's workspace follows its editor (`project.json` is Styles' in its stylebook only).
256
+ void tab.session.ui.canvasMode;
250
257
  void tab.doc.dirty;
251
258
  void tab.documentPath;
252
259
  void tab.pinned;
@@ -265,6 +272,7 @@ export function mount(host: HTMLElement) {
265
272
  }
266
273
 
267
274
  export function unmount() {
275
+ cancelMeasures();
268
276
  dismissOverflowMenu();
269
277
  dismissTabContextMenu();
270
278
  _scope?.stop();
@@ -301,6 +309,14 @@ function releaseHostDnD(host: HTMLElement): void {
301
309
  }
302
310
 
303
311
  function render() {
312
+ /* A workspace that draws no strip (Media, Styles, Publish) has its strips out of the grid
313
+ (`TAB_STRIP_HIDDEN_CLASS`), so painting them would be work nobody sees, and measuring a strip
314
+ that is not laid out reads zeros that flip the overflow chevron on every switch. They are left
315
+ standing as they were and repainted on the way back: this effect tracks `shell.workspace`.
316
+ A DERIVED pane is the exception. It follows the author into every workspace, and its row is
317
+ its derivation chip there (no tab of its own is the workspace's), which the frame keeps drawn
318
+ because it names the pane and holds the ✕ that closes it. So it is painted everywhere. */
319
+ const strips = workspaceDrawsTabStrip();
304
320
  /* One host draws ONE pane. While the shell has a single strip, both panes resolve to the same
305
321
  div — and the one whose tabs are on screen is the focused one, so it wins the tie. Without
306
322
  that rule the answer was render order, which is how the strip came to mark a tab active in a
@@ -314,7 +330,10 @@ function render() {
314
330
  }
315
331
  const drawn = new Set<string>();
316
332
  for (const [host, pane] of claims) {
317
- paint(pane, host);
333
+ if (strips || pane.derived) {
334
+ paint(pane, host);
335
+ }
336
+ // Counted as drawn either way: a strip left standing is kept, not taken down below.
318
337
  _hosts.set(pane.id, host);
319
338
  drawn.add(pane.id);
320
339
  }
@@ -359,27 +378,81 @@ function paint(pane: Pane, host: HTMLElement): void {
359
378
 
360
379
  /* The strip is HELD — `surfaces/tab-strip.ts` takes it as the element is created — so this is an
361
380
  imperative USE of a node this module owns rather than a re-find of one it renders
362
- (studio-ui-guidelines.md §9.4). The chip is asked for by the state the KIT puts on it, which is
363
- the accessibility tree's own answer to "which tab is current".
381
+ (studio-ui-guidelines.md §9.4).
364
382
 
365
383
  THE REVEAL IS RECORDED ONLY WHEN THERE WAS A STRIP TO REVEAL IT IN. A mount is asynchronous,
366
384
  so the first paint into a fresh host has no document yet — and moving `_lastActive` there
367
385
  anyway would consume the transition and leave the chip off-screen with nothing left to notice.
368
386
  That is exactly the case a derived pane produces: its strip is created the moment its one tab
369
- comes back. */
387
+ comes back.
388
+
389
+ The DECISION is taken here, in the paint that saw the transition, and only the scroll waits
390
+ for the frame: several paints can land in one task (a derivation and its return), and the
391
+ frame sees only the last of them, which may name the very tab `_lastActive` already held. */
370
392
  const strip = _strips.get(host)?.strip();
371
393
  if (strip && pane.activeTabId !== _lastActive.get(pane.id)) {
372
394
  _lastActive.set(pane.id, pane.activeTabId);
395
+ _revealPending.add(host);
396
+ }
397
+ scheduleMeasure(host);
398
+ }
399
+
400
+ /**
401
+ * The frame each host's strip is next read in: one per host, however many paints ask for it.
402
+ *
403
+ * Both reads the strip owes after a paint (bringing the active chip into view, and whether the
404
+ * chevron is needed) need LAYOUT, and both used to run inline at the tail of {@link paint}. A paint
405
+ * is never the last write of its task: a workspace switch or a tab activation goes on to swap the
406
+ * stage, the docks and the Inspector, so an inline read paid for a style recalculation of the whole
407
+ * half-written document (10 to 27 ms each, on every tab or workspace change in the perf trace), and
408
+ * the frame then paid again once the rest of the task had dirtied it. Read in the next frame, the
409
+ * strip shares the one layout the frame does anyway. The chevron already tolerated a lag (see
410
+ * {@link syncOverflow}), and the reveal still lands before that frame paints.
411
+ */
412
+ const _measureFrames = new Map<HTMLElement, number>();
413
+
414
+ /** Hosts whose active chip changed since their last frame, so the frame scrolls it into view. */
415
+ const _revealPending = new Set<HTMLElement>();
416
+
417
+ function scheduleMeasure(host: HTMLElement): void {
418
+ if (_measureFrames.has(host)) {
419
+ return;
420
+ }
421
+ _measureFrames.set(
422
+ host,
423
+ requestAnimationFrame(() => {
424
+ _measureFrames.delete(host);
425
+ const pane = drawnPane(host);
426
+ if (pane && workspaceDrawsTabStrip()) {
427
+ measureStrip(pane, host);
428
+ }
429
+ _revealPending.delete(host);
430
+ }),
431
+ );
432
+ }
433
+
434
+ /** Drop every pending read: the strips they would measure are going away. */
435
+ function cancelMeasures(): void {
436
+ for (const frame of _measureFrames.values()) {
437
+ cancelAnimationFrame(frame);
438
+ }
439
+ _measureFrames.clear();
440
+ _revealPending.clear();
441
+ }
442
+
443
+ /** The reads {@link scheduleMeasure} runs for one host, in a frame of their own. */
444
+ function measureStrip(pane: Pane, host: HTMLElement): void {
445
+ const strip = _strips.get(host)?.strip();
446
+ if (strip && _revealPending.has(host)) {
373
447
  /* Found by the id the DOCUMENT stamped, not by `aria-selected`. The kit is the single writer
374
448
  of a tab's selected state and it writes it on a MutationObserver when the tab SET moved — a
375
- microtask later — so a strip whose one tab has just come back has no tab marked current at
376
- the instant this runs. The flow already knows which chip it wants; asking the tree instead
377
- is asking a question we have the answer to, and getting it one tick early. */
449
+ microtask later — so a strip whose one tab has just come back may have no tab marked current
450
+ yet. The flow already knows which chip it wants; asking the tree instead is asking a
451
+ question we have the answer to. */
378
452
  [...strip.children]
379
453
  .find((chip) => chip instanceof HTMLElement && chip.dataset.tab === pane.activeTabId)
380
454
  ?.scrollIntoView({ block: "nearest", inline: "nearest" });
381
455
  }
382
-
383
456
  syncOverflow(pane, host);
384
457
  }
385
458
 
@@ -518,23 +591,31 @@ function project(pane: Pane): TabStripValues {
518
591
  that could put one there (`moveTabToPane`, through `revealOpenTab`) is reached solely by
519
592
  `openFileInPane`, which the follow calls for COMPANIONS. So the second disjunct is already
520
593
  total over a lens and the first chose nothing. */
521
- if (derived && pane.tabOrder.length === 0) {
594
+ /* The tabs of the workspace on screen, in strip order. A pane's other tabs are another
595
+ workspace's: they keep their slots in `pane.tabOrder` and are simply not drawn. */
596
+ const visible = workspaceTabOrder(pane);
597
+ /* A derived pane none of whose tabs is in the workspace on screen draws its derivation chip too.
598
+ A COMPANION owns real tabs, and after a switch to Media or Publish the one it follows is
599
+ another workspace's: filtered away, it left a stage drawing a document under a blank row, with
600
+ no chip, no ✕ and no way out of the derivation. */
601
+ if (derived && visible.length === 0) {
522
602
  /* A COMPANION whose rule has not resolved reaches this too, and it has to. Its `tabOrder` is
523
603
  empty for a different reason than a lens's — the document it wants is not open YET, or the
524
604
  selection has nothing under it — and the branch below drew nothing: a pane with no chip,
525
605
  no ✕ and no way out, which `paneIsEmpty` will not collapse because the derivation counts as
526
606
  a subject. The chip is the pane's name and its exit.
527
607
  NO `_lastActive` / `_overflowing` RESET HERE, and both were, until each was shown to be a
528
- write nothing can read. `_overflowing` is measured by {@link syncOverflow} at the end of
529
- every ordinary render, inside the same synchronous call, so a stale `true` carried through a
530
- derivation is corrected before any frame sees it. `_lastActive` cannot survive the round trip
608
+ write nothing can read. `_overflowing` is measured by {@link syncOverflow} in the frame
609
+ after every ordinary render, before that frame paints, so a stale `true` carried through a
610
+ derivation is corrected before anybody sees it. `_lastActive` cannot survive the round trip
531
611
  either: a tab can only come back through `insertIntoPane` and then `activateTab`, which are
532
612
  two reactive writes and therefore two renders, and the first of them lands here with
533
613
  `tabOrder` full and `activeTabId` still `null` — which resets the field anyway. Both were
534
614
  written as bookkeeping and both were unfalsifiable; the branch below owns the answer. */
535
615
  return derivationValues(pane, derived);
536
616
  }
537
- if (pane.tabOrder.length === 0) {
617
+ // A non-derived pane whose every tab belongs elsewhere draws the same blank row an empty one does.
618
+ if (visible.length === 0) {
538
619
  /* An empty, non-derived pane WHILE A DRAG IS LIVE draws a `tabs` row with no chips instead of
539
620
  going blank: `blankValues` hides the row outright, and a hidden row has no `jx-tabs` element
540
621
  for `adoptStrip` to make a target of — so a tab dragged toward the empty primary beside a
@@ -569,7 +650,8 @@ function project(pane: Pane): TabStripValues {
569
650
  preset: "",
570
651
  stripLabel: stripLabel(pane),
571
652
  subject: "",
572
- tabs: pane.tabOrder.flatMap((id, index) => chipView(pane, id, index, labels)),
653
+ // The chip's index is its slot in the pane's FULL order, which is what a drop is measured in.
654
+ tabs: visible.flatMap((id) => chipView(pane, id, pane.tabOrder.indexOf(id), labels)),
573
655
  trailing: _overflowing.get(pane.id) === true,
574
656
  trailingGlyph: "⌄",
575
657
  // ONE accessible name (`studio-ui-guidelines.md` §10): the glyph is hidden, so `title` is both
@@ -758,11 +840,11 @@ function syncDrag(): void {
758
840
  /**
759
841
  * Re-measure a pane's strip and re-project once if the chevron's presence changed.
760
842
  *
761
- * Measurement can only happen after the document has written the DOM, so this runs at the tail of
762
- * {@link paint} and guards its own re-entry on the boolean actually flipping — the chevron cannot
763
- * oscillate. Before the mount resolves there is no strip to measure and nothing to correct: the
764
- * next repaint measures it, and a strip that overflows on its first frame has no hidden tab a
765
- * reader could be looking for yet.
843
+ * Measurement can only happen after the document has written the DOM, so this runs in the frame
844
+ * after a {@link paint} ({@link scheduleMeasure}) and guards its own re-entry on the boolean
845
+ * actually flipping — the chevron cannot oscillate. Before the mount resolves there is no strip to
846
+ * measure and nothing to correct: the next repaint measures it, and a strip that overflows on its
847
+ * first frame has no hidden tab a reader could be looking for yet.
766
848
  */
767
849
  function syncOverflow(pane: Pane, host: HTMLElement) {
768
850
  const surface = _strips.get(host);
@@ -837,11 +919,13 @@ export function hiddenTabIds(paneId: string = workspace.activePaneId): string[]
837
919
  const left = strip.scrollLeft;
838
920
  const right = left + strip.clientWidth;
839
921
  const hidden: string[] = [];
840
- /* Typed, not filtered: a chip's position is what pairs it with `pane.tabOrder[index]`, so dropping
841
- a node here would shift every later chip onto the wrong tab id. */
922
+ /* Typed, not filtered: a chip's position is what pairs it with the strip's drawn order, so dropping
923
+ a node here would shift every later chip onto the wrong tab id. The drawn order is the
924
+ workspace's tabs alone, which is what `project` drew. */
925
+ const drawn = workspaceTabOrder(pane);
842
926
  const chips = [...strip.querySelectorAll<HTMLElement>('[part="tab"]')];
843
927
  for (const [index, chip] of chips.entries()) {
844
- const id = pane.tabOrder[index];
928
+ const id = drawn[index];
845
929
  if (id && (chip.offsetLeft < left || chip.offsetLeft + chip.offsetWidth > right)) {
846
930
  hidden.push(id);
847
931
  }
@@ -877,7 +961,7 @@ export function dismissOverflowMenu() {
877
961
  function openOverflowMenu(pane: Pane, labels: Map<string, string>, anchorEl: HTMLElement | null) {
878
962
  dismissOverflowMenu();
879
963
  const hidden = hiddenTabIds(pane.id);
880
- const ids = hidden.length > 0 ? hidden : [...pane.tabOrder];
964
+ const ids = hidden.length > 0 ? hidden : workspaceTabOrder(pane);
881
965
  const anchor = rectOf(anchorEl ?? document.body);
882
966
  _overflowHandle = openMenu({
883
967
  /* The trigger says "Show hidden tabs" and this is the panel it opens, so it takes the same
@@ -1203,7 +1287,7 @@ function tabLabels(pane: Pane): Map<string, string> {
1203
1287
  ? [
1204
1288
  {
1205
1289
  documentPath: tab.documentPath,
1206
- fallback: gridTabLabel(tab.id) ?? "Untitled",
1290
+ fallback: gridTabLabel(tab.id) ?? workspaceHomeLabel(tab.id) ?? "Untitled",
1207
1291
  id,
1208
1292
  },
1209
1293
  ]
@@ -1219,7 +1303,7 @@ function tabLabels(pane: Pane): Map<string, string> {
1219
1303
  * @returns {string}
1220
1304
  */
1221
1305
  function tabTooltip(tab: Tab): string {
1222
- const base = tab.documentPath || gridTabLabel(tab.id) || "Untitled";
1306
+ const base = tab.documentPath || gridTabLabel(tab.id) || workspaceHomeLabel(tab.id) || "Untitled";
1223
1307
  const origin = tab.session.openedFrom;
1224
1308
  const withOrigin = origin?.documentPath ? `${base}\nOpened from ${origin.documentPath}` : base;
1225
1309
  return tab.preview ? `${withOrigin}\nPreview — double-click to keep open` : withOrigin;
package/src/platform.ts CHANGED
@@ -37,7 +37,7 @@ export interface LauncherBootError {
37
37
  * window ran the dev-server adapter against a `views://` origin with nothing behind it.
38
38
  */
39
39
  export interface LauncherSignal {
40
- /** Which launcher announced (`"electrobun"`, `"chromium"`), once its boot module's body ran. */
40
+ /** Which launcher announced (`"chromium"`), once its boot module's body ran. */
41
41
  launcher?: string | undefined;
42
42
  /** The first error the page raised during boot, or the adapter factory's own throw. */
43
43
  error?: LauncherBootError | undefined;
@@ -855,6 +855,21 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
855
855
  return okJson<ProjectInfoWire>(await api("/project-info"), "Failed to load project");
856
856
  }
857
857
 
858
+ /* The repository's default branch, asked once per session: it is what Send for review must never
859
+ commit to here, because a commit on this host lands on GitHub as it is made. A failed ask is
860
+ forgotten, so the next branch listing asks again. */
861
+ let defaultBranch: Promise<string> | null = null;
862
+ function repositoryDefaultBranch(): Promise<string> {
863
+ defaultBranch ??= projectInfo().then(
864
+ (info) => info.defaultBranch || "",
865
+ () => {
866
+ defaultBranch = null;
867
+ return "";
868
+ },
869
+ );
870
+ return defaultBranch;
871
+ }
872
+
858
873
  /** One file the old way: `GET /file`. What a single read, and the batch fallback, goes through. */
859
874
  async function readOne(path: string): Promise<string> {
860
875
  const data = await okJson<{ content: string }>(
@@ -953,6 +968,10 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
953
968
  const platform: StudioPlatform = {
954
969
  id: "cloud",
955
970
  projectRoot: root,
971
+ /* Commits land on GitHub as they are made (`gitCommit`), a push is a sync check, and a branch
972
+ is a sibling session (`gitCheckout`), which is what the Publish workspace says before it
973
+ switches one (studio.md §22.8). */
974
+ gitHosted: true,
956
975
  canvasUrl: "/canvas.html",
957
976
  /* The projectRoot here is the IDENTIFIER "owner/repo@branch", not a served path, so the canvas's
958
977
  default base — <origin>/<projectRoot>/ — addressed nothing. Every component $ref fetch landed
@@ -1504,7 +1523,15 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
1504
1523
  },
1505
1524
 
1506
1525
  async gitBranches() {
1507
- return okJson<GitBranchesResult>(await api("/git/branches"), "Failed to list branches");
1526
+ const listed = await okJson<GitBranchesResult>(
1527
+ await api("/git/branches"),
1528
+ "Failed to list branches",
1529
+ );
1530
+ if (listed.defaultBranch) {
1531
+ return listed;
1532
+ }
1533
+ const name = await repositoryDefaultBranch();
1534
+ return name ? { ...listed, defaultBranch: name } : listed;
1508
1535
  },
1509
1536
 
1510
1537
  async gitLog(limit?: number) {
@@ -82,10 +82,10 @@ export interface BootEnvironment {
82
82
  * the HTTP protocol reuses the stock dev-server adapter unchanged, and a third-party shell may well
83
83
  * serve it through a custom scheme — `tauri://localhost` proxies to a real server. Refusing every
84
84
  * scheme that is not `http:` would break that host to cover a case the meta and the launcher signal
85
- * already cover for every host this repository ships. `views:` is Electrobun's own bundle scheme
86
- * and `file:` is a document opened from disk; neither can be proxying anything. happy-dom's
87
- * `about:` is absent for the same reason, which is also what lets a test import the entry without
88
- * inventing a URL.
85
+ * already cover for every host this repository ships. `views:` is a custom bundle scheme and
86
+ * `file:` is a document opened from disk; neither can be proxying anything. happy-dom's `about:` is
87
+ * absent for the same reason, which is also what lets a test import the entry without inventing a
88
+ * URL.
89
89
  */
90
90
  const BACKENDLESS_SCHEMES: ReadonlySet<string> = new Set(["views:", "file:"]);
91
91