@jxsuite/studio 2.0.0 → 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.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +23711 -35185
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +34 -9
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +270 -262
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -120
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +75 -2
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +113 -0
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
- package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
- package/dist/chunks/files-02zn5y24.js +0 -50
- package/dist/chunks/files-02zn5y24.js.map +0 -9
- package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
- package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
- package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
- package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
- package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
- package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-568nx4t5.js +0 -469
- package/dist/chunks/studio-568nx4t5.js.map +0 -14
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-asvf0j9e.js +0 -429
- package/dist/chunks/studio-asvf0j9e.js.map +0 -13
- package/dist/chunks/studio-d77qm3pk.js +0 -3427
- package/dist/chunks/studio-d77qm3pk.js.map +0 -26
- package/dist/chunks/studio-j6gqyjf4.js +0 -1854
- package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
- package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-rq0vxb19.js +0 -3744
- package/dist/chunks/studio-rq0vxb19.js.map +0 -22
- package/dist/chunks/studio-wd6ewdvd.js +0 -853
- package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-ygzav7z5.js.map +0 -46
- package/dist/chunks/studio-zmy7241e.js +0 -399
- package/dist/chunks/studio-zmy7241e.js.map +0 -12
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /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`.
|