@jxsuite/studio 2.0.1 → 2.1.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 (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +21080 -32585
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +7 -0
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +221 -245
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -53
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +30 -1
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +7 -1
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
  363. package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
  364. package/dist/chunks/files-j8a1t06k.js +0 -50
  365. package/dist/chunks/files-j8a1t06k.js.map +0 -9
  366. package/dist/chunks/git-panel-xtq5z81x.js +0 -28
  367. package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
  368. package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
  369. package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
  370. package/dist/chunks/settings-modal-17ttr96g.js +0 -29
  371. package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-0xgs7xrs.js +0 -429
  381. package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
  382. package/dist/chunks/studio-4d8hzcz5.js +0 -3427
  383. package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
  384. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  385. package/dist/chunks/studio-9smfzqhc.js +0 -19
  386. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  387. package/dist/chunks/studio-jm0z592w.js.map +0 -115
  388. package/dist/chunks/studio-m2t4mdg5.js +0 -1854
  389. package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
  390. package/dist/chunks/studio-n4p11dfy.js +0 -853
  391. package/dist/chunks/studio-n4p11dfy.js.map +0 -12
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-sjh1wt1a.js +0 -3744
  394. package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
  395. package/dist/chunks/studio-v7jkjqng.js.map +0 -46
  396. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  397. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  398. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  399. package/dist/chunks/studio-yfcstdzy.js +0 -399
  400. package/dist/chunks/studio-yfcstdzy.js.map +0 -12
  401. package/dist/chunks/studio-zp7jncs8.js +0 -469
  402. package/dist/chunks/studio-zp7jncs8.js.map +0 -14
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -0,0 +1,584 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * ⑥ The jump bar — the pane's address, and every place you can go from it.
4
+ *
5
+ * **The two half-breadcrumbs this replaces.** Studio grew two trails, neither of which could say
6
+ * where you were:
7
+ *
8
+ * 1. `panels/pane-context.ts`'s `navTpl()` (the old `#tab-bar` breadcrumb, plan §3.2 ⑥ names it as
9
+ * `tab-bar.ts:129-185`) — a `Back` button plus one span per `session.documentStack` frame. It
10
+ * appeared ONLY while you were inside a sub-document, printed the frame's file basename (which
11
+ * is the SAME basename for a `$map` template, so it read `index.json › index.json`), and knew
12
+ * nothing about the project above it or the selection below it. It is deleted, and so is the
13
+ * stack it walked: nothing ever pushed a frame, so it could only ever draw its empty branch.
14
+ * 2. `panels/statusbar.ts`'s selection field — a clickable ancestor trail, `selection.set` per crumb.
15
+ * It appeared ONLY while something was selected, and knew nothing about the document it was
16
+ * inside.
17
+ *
18
+ * Between them they never rendered at the same time as each other and never rendered the whole
19
+ * address, so neither one was a place to look. **This bar is the whole chain**, always:
20
+ *
21
+ * ```text
22
+ * ◈ Site › pages/blog/[slug].json › article › h1 ⌄
23
+ * project file selection ancestors
24
+ * ```
25
+ *
26
+ * **The status bar keeps only what an address cannot say.** Plan §3.2 ⑫ and `studio.md` §16.2 give
27
+ * the bar AMBIENT STATE, and an ancestor trail in a second place is exactly the duplication the
28
+ * shell redesign exists to remove — three breadcrumbs would be worse than the two we started with.
29
+ * So the trail moves here whole, and `statusbar/selection` keeps the two facts this bar cannot
30
+ * state: HOW MANY things are selected (a count is not a path) and which Stylebook rule the Style
31
+ * panel is editing (a selector is not a node).
32
+ *
33
+ * **Every interactive item is a command, resolved from the registry.** There is no click handler in
34
+ * this file that names behaviour: a segment names a command id and its args, and the registry
35
+ * supplies the title, the chord, the enablement and the run. Three ids carry the whole bar —
36
+ * `project.openRecent`, `palette.openFiles` and `selection.set` — and this file declares none of
37
+ * them. It did declare a fourth, `document.setStackLevel`, for the sub-document stack; the stack
38
+ * had no way in and both are gone.
39
+ *
40
+ * **A segment whose command the registry does not have becomes a readout, it does not disappear.**
41
+ * That is the one place this bar deliberately differs from the status bar, where an unavailable
42
+ * item vanishes. An address with a hole in it is a lie about containment; a readout is merely a
43
+ * step you cannot take.
44
+ */
45
+
46
+ import { html, render as litRender, nothing } from "lit-html";
47
+ import { displayTagName } from "@jxsuite/schema/guards";
48
+ import { childList, getNodeAtPath, nodeLabel, pathsEqual, projectState } from "../store";
49
+ import { effect, effectScope } from "../reactivity";
50
+ import { PRIMARY_PANE, workspace } from "../workspace/workspace";
51
+ import { derivationOfPane, tabOfPane } from "../canvas/canvas-surface";
52
+ import { paneRegion } from "../ui/regions";
53
+ import { primarySelection } from "../tabs/selection";
54
+ import { activeRegistry } from "../commands/active-registry";
55
+ import { renderPopover } from "../ui/layers";
56
+ import { rectOf } from "../utils/geometry";
57
+ import type { CommandArgs, CommandRegistry } from "../commands/registry";
58
+ import type { FormulaEditDef, FunctionEditDef } from "../types";
59
+ import type { JxPath } from "../state";
60
+ import type { Tab } from "../tabs/tab";
61
+ import type { PaneDerivation } from "../workspace/workspace";
62
+ import type { EffectScope } from "@vue/reactivity";
63
+ import type { TemplateResult } from "lit-html";
64
+
65
+ /** The CSS variable the stage is offset by while the jump bar is on screen. */
66
+ export const JUMP_BAR_VAR = "--jump-bar-h";
67
+
68
+ /** The bar's height. Declared here because the offset projection and the stylesheet must agree. */
69
+ const JUMP_BAR_HEIGHT = 24;
70
+
71
+ // ─── The model ───────────────────────────────────────────────────────────────
72
+
73
+ /**
74
+ * What a segment addresses. The kind is stamped on the element so a test — and a shot — can name a
75
+ * step of the address without matching its rendered text, which is derived (§13 R1).
76
+ */
77
+ export type JumpSegmentKind = "project" | "file" | "editor" | "node";
78
+
79
+ /** One alternative in a segment's dropdown. Each is a command, exactly like the segment itself. */
80
+ export interface JumpChoice {
81
+ label: string;
82
+ command: string;
83
+ args?: CommandArgs;
84
+ /** The choice you are already on. Marked, never hidden — a menu that omits it loses its place. */
85
+ current?: boolean;
86
+ }
87
+
88
+ /** One step of the address. */
89
+ export interface JumpSegment {
90
+ kind: JumpSegmentKind;
91
+ label: string;
92
+ /** Extra tooltip context. The command's own title and chord are appended to it. */
93
+ title?: string;
94
+ /** The command that MOVES you here, or `null` when you are already here. */
95
+ command: string | null;
96
+ args?: CommandArgs;
97
+ /** Where else this step could go. Fewer than two is not a choice, and renders no control. */
98
+ choices: readonly JumpChoice[];
99
+ }
100
+
101
+ // ─── Labels ──────────────────────────────────────────────────────────────────
102
+
103
+ /**
104
+ * The document's path with the project root taken off — the root is the segment before it.
105
+ *
106
+ * Lives here rather than in `statusbar.ts`, where it started: the jump bar is the surface whose
107
+ * whole job is naming the containment chain, and the status bar's DOCUMENT field is a second reader
108
+ * of the same fact. Having the reader own it also kept `mock.module("panels/statusbar")` — which
109
+ * six bootstrap tests do — from deciding whether the jump bar can name a file.
110
+ */
111
+ export function documentLabel(path: string | null): string {
112
+ if (!path) {
113
+ return "Untitled";
114
+ }
115
+ const root = projectState?.projectRoot;
116
+ return root && path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
117
+ }
118
+
119
+ // ─── The selection trail (moved here from statusbar.ts) ──────────────────────
120
+
121
+ /** One crumb of the ancestor trail: what to call the node, and the path that selects it. */
122
+ export interface SelectionCrumb {
123
+ label: string;
124
+ path: JxPath;
125
+ }
126
+
127
+ /**
128
+ * Walk the selection path one STRUCTURAL step at a time.
129
+ *
130
+ * Most steps are `["children", index]` or `["cases", name]` pairs, but a repeater template is
131
+ * reached by a lone `"map"` segment — so the step width varies. Emitting a crumb per node keeps the
132
+ * array pseudo-element ("Repeater") and its template both visible instead of collapsing the array
133
+ * into a bare `[index]`.
134
+ */
135
+ export function selectionCrumbs(document: unknown, selection: JxPath): SelectionCrumb[] {
136
+ const crumbs: SelectionCrumb[] = [];
137
+ for (let i = 0; i < selection.length;) {
138
+ const seg = selection[i];
139
+ const step = seg === "map" ? 1 : 2;
140
+ const path = selection.slice(0, i + step) as JxPath;
141
+ const node = getNodeAtPath(document as never, path);
142
+ const fallbackTag = node?.tag;
143
+ const label =
144
+ node?.$prototype === "Array"
145
+ ? "Repeater"
146
+ : displayTagName(node?.tagName) ||
147
+ (typeof fallbackTag === "string" ? fallbackTag : "") ||
148
+ (seg === "cases" ? String(selection[i + 1]) : `[${selection[i + 1]}]`);
149
+ crumbs.push({ label, path });
150
+ i += step;
151
+ }
152
+ return crumbs;
153
+ }
154
+
155
+ /**
156
+ * The siblings of one crumb, as choices — the dropdown that makes a segment a way to MOVE.
157
+ *
158
+ * Labels are `nodeLabel()`, the SAME strings the Outline prints, because a menu of alternatives is
159
+ * a list of rows and the reader has already learned those words there. The crumb itself keeps its
160
+ * compact tag label: a crumb is an address, a row is a choice.
161
+ *
162
+ * A `map` step has no siblings (a repeater holds exactly one template), and a text child is not
163
+ * addressable, so both drop out and the segment renders no control at all.
164
+ */
165
+ export function crumbSiblings(
166
+ document: unknown,
167
+ crumbs: readonly SelectionCrumb[],
168
+ index: number,
169
+ ): JumpChoice[] {
170
+ const crumb = crumbs[index];
171
+ if (!crumb) {
172
+ return [];
173
+ }
174
+ const parentPath = (index === 0 ? [] : crumbs[index - 1]!.path) as JxPath;
175
+ const parent = getNodeAtPath(document as never, parentPath);
176
+ const key = crumb.path.at(-2);
177
+ const own = crumb.path;
178
+ if (key === "cases") {
179
+ const cases = parent?.cases;
180
+ if (!cases || typeof cases !== "object") {
181
+ return [];
182
+ }
183
+ return Object.keys(cases).map((name) => {
184
+ const path = [...parentPath, "cases", name] as JxPath;
185
+ return choiceFor(document, path, name, own);
186
+ });
187
+ }
188
+ if (key !== "children") {
189
+ return [];
190
+ }
191
+ const choices: JumpChoice[] = [];
192
+ for (const [i, child] of childList(parent).entries()) {
193
+ if (typeof child === "string") {
194
+ continue;
195
+ }
196
+ const path = [...parentPath, "children", i] as JxPath;
197
+ choices.push(choiceFor(document, path, nodeLabel(child), own));
198
+ }
199
+ return choices;
200
+ }
201
+
202
+ function choiceFor(document: unknown, path: JxPath, fallback: string, own: JxPath): JumpChoice {
203
+ const node = getNodeAtPath(document as never, path);
204
+ const label = node ? nodeLabel(node) : fallback;
205
+ const choice: JumpChoice = { args: { path }, command: "selection.set", label };
206
+ // `pathsEqual`, not a joined key: a separator is a guess about what a segment cannot contain,
207
+ // And the one this reached for was a literal NUL byte that made the whole file read as binary.
208
+ return pathsEqual(path, own) ? { ...choice, current: true } : choice;
209
+ }
210
+
211
+ // ─── Building the address ────────────────────────────────────────────────────
212
+
213
+ /**
214
+ * The whole address, as data. Pure: no registry, no DOM — the template decides what is renderable.
215
+ *
216
+ * Order is containment order, outermost first, which is the same left-to-right order the status bar
217
+ * puts its three fields in. Nothing here reads the registry, so a segment is produced whether or
218
+ * not its command happens to be registered; {@link segmentTpl} is where that difference shows.
219
+ */
220
+ export function jumpSegments(
221
+ tab: Tab | null,
222
+ derived: PaneDerivation | null = null,
223
+ ): JumpSegment[] {
224
+ if (!tab) {
225
+ return [];
226
+ }
227
+ const segments: JumpSegment[] = [];
228
+ const project = projectState;
229
+ if (project) {
230
+ segments.push({
231
+ choices: [],
232
+ command: "project.openRecent",
233
+ kind: "project",
234
+ label: project.name,
235
+ title: project.projectRoot,
236
+ });
237
+ }
238
+
239
+ // ONE document per tab. This used to walk `session.documentStack` and emit a `subdocument`
240
+ // Segment per frame, each one a `document.setStackLevel` you could click back to — but nothing
241
+ // In `src/` ever pushed a frame, so the loop had exactly one iteration in the shipped app and the
242
+ // Address it drew was always this line. A tab holds a document; drilling in opens another tab.
243
+ /* In a DERIVED pane the leading verb is Keep, not Open.
244
+ The address is still the document — a lens draws the source pane's, a companion its own — but
245
+ the question an author has about a pane that is following something is "can I stop it
246
+ following and just keep this open". `pane.pin` answers it, and answers it with a REFUSAL for a
247
+ lens: `segmentTpl` already renders a crumb whose command is disabled as a disabled button with
248
+ `disabledReason` in the tooltip, so the sentence explaining why Code, Diff and breakpoint views
249
+ cannot be pinned arrives for free. */
250
+ segments.push({
251
+ choices: [],
252
+ command: derived ? "pane.pin" : "palette.openFiles",
253
+ kind: "file",
254
+ label: documentLabel(tab.documentPath),
255
+ title: tab.documentPath ?? "Not saved to disk yet",
256
+ });
257
+
258
+ // A logic editor is the leaf of the address, and it has no selection under it: the Monaco buffer
259
+ // And the formula workspace are editing a definition, not a node of the document tree.
260
+ const editingFunction = tab.session.ui.editingFunction as FunctionEditDef | null;
261
+ const editingFormula = tab.session.ui.editingFormula as FormulaEditDef | null;
262
+ if (editingFunction) {
263
+ segments.push(editorSegment("ƒ", editingFunction));
264
+ return segments;
265
+ }
266
+ if (editingFormula) {
267
+ segments.push(editorSegment("fx", editingFormula));
268
+ return segments;
269
+ }
270
+
271
+ const selection = primarySelection(tab.session.selection);
272
+ if (selection && selection.length > 0) {
273
+ const crumbs = selectionCrumbs(tab.doc.document, selection);
274
+ for (const [i, crumb] of crumbs.entries()) {
275
+ const node = getNodeAtPath(tab.doc.document, crumb.path);
276
+ segments.push({
277
+ args: { path: crumb.path },
278
+ choices: crumbSiblings(tab.doc.document, crumbs, i),
279
+ // The leaf prints the Outline's label — the `$title` / `$id` an author gave the node — and
280
+ // An ancestor prints its compact tag, so a deep address stays readable at 24px.
281
+ command: "selection.set",
282
+ kind: "node",
283
+ label: i === crumbs.length - 1 && node ? nodeLabel(node) : crumb.label,
284
+ title: crumb.path.join(" / "),
285
+ });
286
+ }
287
+ }
288
+ return segments;
289
+ }
290
+
291
+ function editorSegment(sigil: string, def: FunctionEditDef | FormulaEditDef): JumpSegment {
292
+ return {
293
+ choices: [],
294
+ // No command, and none is missing: the Logic tab's own header carries the Close (P8.5), which
295
+ // Is where a reader looking at the editor already is. A second exit up here would be a button
296
+ // Beside the address that means "stop being at this address" — and the pane context bar drew
297
+ // Exactly that, a Back of its own, until this excision removed it.
298
+ command: null,
299
+ kind: "editor",
300
+ label: `${sigil} ${def.defName ?? def.eventKey ?? "editor"}`,
301
+ };
302
+ }
303
+
304
+ // ─── Rendering ───────────────────────────────────────────────────────────────
305
+
306
+ /**
307
+ * Where each pane's bar renders. One entry per drawn cell.
308
+ *
309
+ * A Map rather than a `let _host`, because the bar addresses a PANE: it prints where you are, and
310
+ * with two panes on screen there are two answers. `panels/pane-grid.ts` attaches a cell's
311
+ * `.pane-jump` as the cell is built and detaches it as the cell is disposed, which is the same
312
+ * hand-over `panels/frontmatter-panel.ts` takes from the stage.
313
+ */
314
+ const _hosts = new Map<string, HTMLElement>();
315
+
316
+ let _scope: EffectScope | null = null;
317
+
318
+ let _menu: { dismiss: () => void } | null = null;
319
+
320
+ /** Close the open segment menu, if any. Idempotent. */
321
+ export function dismissJumpMenu(): void {
322
+ _menu?.dismiss();
323
+ _menu = null;
324
+ }
325
+
326
+ /** Whether the registry can actually run this id right now. */
327
+ function runnable(registry: CommandRegistry | null, id: string | null): id is string {
328
+ return id !== null && Boolean(registry?.get(id)) && registry!.isVisible(id);
329
+ }
330
+
331
+ /** The tooltip: the segment's own context, then the command's title and chord. */
332
+ function segmentTitle(registry: CommandRegistry, segment: JumpSegment, id: string): string {
333
+ const command = registry.get(id)!;
334
+ const reason = registry.disabledReason(id);
335
+ const chord = registry.keymap.formatBinding(id);
336
+ const suffix = reason
337
+ ? `${command.title} — requires ${reason}`
338
+ : chord
339
+ ? `${command.title} (${chord})`
340
+ : command.title;
341
+ return segment.title ? `${segment.title} · ${suffix}` : suffix;
342
+ }
343
+
344
+ /**
345
+ * Open a segment's alternatives.
346
+ *
347
+ * The menu is built from the segment's choices, and every row runs a command — the same command the
348
+ * segment itself names, with a different path. Nothing here decides what selecting means.
349
+ */
350
+ function openChoices(event: MouseEvent, registry: CommandRegistry, segment: JumpSegment): void {
351
+ event.preventDefault();
352
+ event.stopPropagation();
353
+ dismissJumpMenu();
354
+ const anchor = rectOf(event.currentTarget as HTMLElement);
355
+ const left = Math.round(Math.min(anchor.left, window.innerWidth - 4));
356
+ const top = Math.round(anchor.bottom);
357
+ _menu = renderPopover(
358
+ html`<sp-popover open style="position:fixed;z-index:10000;left:${left}px;top:${top}px">
359
+ <sp-menu role="menu" aria-label=${`Go to a sibling of ${segment.label}`}>
360
+ ${segment.choices.map(
361
+ (choice) => html`<sp-menu-item
362
+ role="menuitem"
363
+ aria-current=${choice.current === true ? "true" : nothing}
364
+ @click=${() => {
365
+ dismissJumpMenu();
366
+ void registry.run(choice.command, choice.args);
367
+ }}
368
+ >${choice.label}</sp-menu-item
369
+ >`,
370
+ )}
371
+ </sp-menu>
372
+ </sp-popover>`,
373
+ {
374
+ dismissOnOutsideClick: true,
375
+ onDismiss: () => {
376
+ _menu = null;
377
+ },
378
+ region: "jump-bar",
379
+ },
380
+ );
381
+ }
382
+
383
+ /** One step of the address, plus its alternatives control when it has any. */
384
+ function segmentTpl(
385
+ registry: CommandRegistry | null,
386
+ segment: JumpSegment,
387
+ last: boolean,
388
+ ): TemplateResult {
389
+ const id = segment.command;
390
+ const live = runnable(registry, id);
391
+ const crumb = live
392
+ ? html`<button
393
+ class="jb-crumb"
394
+ ?disabled=${registry!.disabledReason(id!) !== undefined}
395
+ aria-current=${last ? "true" : nothing}
396
+ title=${segmentTitle(registry!, segment, id!)}
397
+ @click=${() => {
398
+ void registry!.run(id!, segment.args);
399
+ }}
400
+ >
401
+ ${segment.label}
402
+ </button>`
403
+ : html`<span
404
+ class="jb-crumb jb-crumb--static"
405
+ aria-current=${last ? "true" : nothing}
406
+ title=${segment.title ?? segment.label}
407
+ >${segment.label}</span
408
+ >`;
409
+ // One alternative is not a choice — the same judgement the pane context bar's editor-kind axis
410
+ // Makes. Rendering a chevron that opens a menu of one is a control that cannot move.
411
+ const alternatives =
412
+ registry && segment.choices.length > 1
413
+ ? html`<button
414
+ class="jb-alts"
415
+ aria-haspopup="menu"
416
+ aria-label=${`Siblings of ${segment.label}`}
417
+ title=${`Siblings of ${segment.label}`}
418
+ @click=${(event: MouseEvent) => {
419
+ openChoices(event, registry, segment);
420
+ }}
421
+ >
422
+ ⌄
423
+ </button>`
424
+ : nothing;
425
+ return html`<span class="jb-seg" data-jump-kind=${segment.kind}>${crumb}${alternatives}</span>`;
426
+ }
427
+
428
+ /**
429
+ * The whole bar, as one template. There is no second variant for the empty states.
430
+ *
431
+ * @param {string} [paneId] Whose address to print. Defaults to the focused pane, which is what the
432
+ * answer was when the shell had one bar.
433
+ */
434
+ export function jumpBarTemplate(
435
+ paneId: string = workspace.activePaneId,
436
+ ): TemplateResult | typeof nothing {
437
+ const segments = jumpSegments(tabOfPane(paneId), derivationOfPane(paneId));
438
+ if (segments.length === 0) {
439
+ return nothing;
440
+ }
441
+ const registry = activeRegistry();
442
+ return html`<nav
443
+ class="jump-bar"
444
+ data-jx-region=${paneRegion(paneId, "jump")}
445
+ aria-label="Location"
446
+ >
447
+ ${segments.map(
448
+ (segment, i) =>
449
+ html`${i === 0 ? nothing : html`<span class="jb-sep" aria-hidden="true">›</span>`}${segmentTpl(
450
+ registry,
451
+ segment,
452
+ i === segments.length - 1,
453
+ )}`,
454
+ )}
455
+ </nav>`;
456
+ }
457
+
458
+ /**
459
+ * Keep the stage clear of the bar.
460
+ *
461
+ * The same one-projection-one-variable shape `pane-context.ts` uses for its own band, and for the
462
+ * same reason: the stage's offset is the SUM of the two, so a pane with no tab open (no bar) costs
463
+ * the welcome screen no dead band.
464
+ *
465
+ * **The variable is written on the PANE, not on `:root`** — when there is a pane to write it on.
466
+ * Two cells have two bars and two stages, and one document-level number would offset both by
467
+ * whichever pane painted last: a side pane showing a document would push the primary's welcome
468
+ * screen down by 24px, and closing the last tab in one pane would lift the other's document under
469
+ * its own bar. `.pane-stage` reads it from its cell by cascade. A host outside a cell (the tests,
470
+ * and the bare offset callers) still writes the root, which is exactly what it meant before.
471
+ *
472
+ * @param {number} height Bar height in px. `0` when the pane has no address to print.
473
+ * @param {HTMLElement | null} [host] The bar's host. Its cell takes the variable when it has one.
474
+ */
475
+ export function applyJumpBarOffset(height: number, host?: HTMLElement | null): void {
476
+ const target = host?.closest<HTMLElement>(".pane") ?? document.documentElement;
477
+ target.style.setProperty(JUMP_BAR_VAR, `${height}px`);
478
+ }
479
+
480
+ /**
481
+ * Paint one pane's bar. Exported because the bootstrap paints once before mounting the effect.
482
+ *
483
+ * @param {string} [paneId] Defaults to every attached pane — what "render the jump bar" means when
484
+ * the caller is a lifecycle rather than a pane.
485
+ */
486
+ export function renderJumpBar(paneId?: string): void {
487
+ if (_hosts.size === 0) {
488
+ return;
489
+ }
490
+ // The address changed, so an open menu is describing a place that may no longer be on the bar.
491
+ // Repaints happen only when tracked state moves, so this cannot close a menu you are reading.
492
+ dismissJumpMenu();
493
+ for (const [id, host] of _hosts) {
494
+ if (paneId !== undefined && id !== paneId) {
495
+ continue;
496
+ }
497
+ const template = jumpBarTemplate(id);
498
+ litRender(template, host);
499
+ applyJumpBarOffset(template === nothing ? 0 : JUMP_BAR_HEIGHT, host);
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Give a pane's bar somewhere to paint, or take it away.
505
+ *
506
+ * Called by `panels/pane-grid.ts` as a cell is built and as it is disposed. Detaching blanks the
507
+ * host first: a cell being removed still has this bar's DOM in it, and the lit part that owns that
508
+ * DOM is about to be unreachable.
509
+ *
510
+ * @param {string} paneId
511
+ * @param {HTMLElement | null} host
512
+ */
513
+ export function attachJumpBarHost(paneId: string, host: HTMLElement | null): void {
514
+ const previous = _hosts.get(paneId);
515
+ if (previous === host) {
516
+ return;
517
+ }
518
+ if (previous) {
519
+ litRender(nothing, previous);
520
+ applyJumpBarOffset(0, previous);
521
+ }
522
+ if (host) {
523
+ _hosts.set(paneId, host);
524
+ renderJumpBar(paneId);
525
+ } else {
526
+ _hosts.delete(paneId);
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Subscribe the bar to the state it renders. Idempotent.
532
+ *
533
+ * `host` is the PRIMARY pane's, the same bargain `panels/tab-strip.ts`'s `mount` makes: the
534
+ * bootstrap holds the primary's cell and hands it over, and every other pane's host arrives from
535
+ * the grid through {@link attachJumpBarHost}.
536
+ *
537
+ * @param {HTMLElement} host
538
+ */
539
+ export function mountJumpBar(host: HTMLElement): void {
540
+ unmountJumpBar();
541
+ attachJumpBarHost(PRIMARY_PANE, host);
542
+ _scope = effectScope();
543
+ _scope.run(() => {
544
+ effect(() => {
545
+ // The registry is composed AFTER the bootstrap mounts this, and it is a reactive holder —
546
+ // Reading it here is what repaints the bar from a skeleton into the real thing.
547
+ void activeRegistry();
548
+ void projectState?.name;
549
+ /* EVERY pane's tab, not the focused one's. Two bars print two addresses, and the side pane's
550
+ has to repaint when its own document moves — an effect that tracked `activeTab` alone left
551
+ the unfocused bar frozen on whatever it last said. */
552
+ for (const pane of workspace.panes) {
553
+ const tab = tabOfPane(pane.id);
554
+ if (!tab) {
555
+ continue;
556
+ }
557
+ void tab.doc.document;
558
+ void tab.documentPath;
559
+ void tab.session.selection.map((path) => path.join("/")).join("|");
560
+ void tab.session.ui.editingFormula;
561
+ void tab.session.ui.editingFunction;
562
+ }
563
+ renderJumpBar();
564
+ });
565
+ });
566
+ }
567
+
568
+ export function unmountJumpBar(): void {
569
+ dismissJumpMenu();
570
+ _scope?.stop();
571
+ _scope = null;
572
+ for (const host of _hosts.values()) {
573
+ applyJumpBarOffset(0, host);
574
+ }
575
+ _hosts.clear();
576
+ applyJumpBarOffset(0);
577
+ }
578
+
579
+ // ─── This bar contributes no commands ────────────────────────────────────────
580
+ // It declared one, `document.setStackLevel` — "leave a sub-document by naming the level you want to
581
+ // Be at". Its `enablement` read `session.documentStack.length > 0`, a stack nothing could ever push
582
+ // To, so the command was permanently disabled and its palette entry permanently unreachable. Every
583
+ // Id the bar renders now belongs to the surface that owns the behaviour: `project.openRecent`,
584
+ // `palette.openFiles`, `selection.set`.