@jxsuite/studio 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/data/elements-meta.json +5 -15
- package/data/html-meta.json +51 -6
- package/dist/chunks/{2020-xp8vnwma.js → 2020-g79n01v9.js} +14 -14
- package/dist/chunks/action-group-sp6tna8v.js +118 -0
- package/dist/chunks/adapter-nj7tnjfn.js +13 -0
- package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
- package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
- package/dist/chunks/color-area-v17df7b8.js +154 -0
- package/dist/chunks/color-field-anwybnkn.js +208 -0
- package/dist/chunks/color-slider-44ez96fc.js +79 -0
- package/dist/chunks/color-xgg3kfw7.js +35 -0
- package/dist/chunks/combobox-5e7jev23.js +236 -0
- package/dist/chunks/components-2w1f35qs.js +18 -0
- package/dist/chunks/content-source-3wqeas45.js +46 -0
- package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
- package/dist/chunks/dialog-s890b918.js +85 -0
- package/dist/chunks/editor-3qhbg51x.js +35 -0
- package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
- package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
- package/dist/chunks/file-ops-3btj6st0.js +47 -0
- package/dist/chunks/files-ef8fgs3w.js +72 -0
- package/dist/chunks/format-host-3c33nwr8.js +40 -0
- package/dist/chunks/fs-events-13tj6sex.js +18 -0
- package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
- package/dist/chunks/icons-yy10wk9r.js +402 -0
- package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
- package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
- package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
- package/dist/chunks/iframe-host-jgesd924.js +115 -0
- package/dist/chunks/{index-nj44jpzj.js → index-mdmyx6s2.js} +11 -11
- package/dist/chunks/index-n4j7qxyr.js +109 -0
- package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
- package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
- package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
- package/dist/chunks/layers-1nq5evsh.js +29 -0
- package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
- package/dist/chunks/listbox-6v2ac08j.js +44 -0
- package/dist/chunks/lit-html-m244w9nh.js +17 -0
- package/dist/chunks/media-picker-2qbetq73.js +33 -0
- package/dist/chunks/menu-q99sy9rf.js +285 -0
- package/dist/chunks/menu-rf7n72mf.js +14 -0
- package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
- package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
- package/dist/chunks/{monaco-setup-rws7k4br.js → monaco-setup-8r62fj6y.js} +27 -37
- package/dist/chunks/notify-628t0anh.js +21 -0
- package/dist/chunks/number-field-5cndyft8.js +72 -0
- package/dist/chunks/parse-0zx14y15.js +10 -0
- package/dist/chunks/platform-ts9cg1a4.js +15 -0
- package/dist/chunks/popover-47z3ytva.js +25 -0
- package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
- package/dist/chunks/quick-search-srzz83k2.js +45 -0
- package/dist/chunks/references-n553f0e1.js +26 -0
- package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
- package/dist/chunks/section-registry-5pq32t0q.js +25 -0
- package/dist/chunks/select-2r16ez41.js +49 -0
- package/dist/chunks/split-g7nm1rgb.js +191 -0
- package/dist/chunks/studio-0hqbpbd0.js +62 -0
- package/dist/chunks/studio-18avnhjp.js +2430 -0
- package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
- package/dist/chunks/{studio-hbtp0eh1.js → studio-25hkdrkw.js} +356 -85
- package/dist/chunks/studio-26d7myd1.js +258 -0
- package/dist/chunks/{studio-p8j86wag.js → studio-38emantv.js} +22 -5
- package/dist/chunks/studio-3gxv60tn.js +422 -0
- package/dist/chunks/{studio-8swrjbny.js → studio-3hxkd92t.js} +275 -163
- package/dist/chunks/studio-4m0haseg.js +185 -0
- package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
- package/dist/chunks/{studio-gv8vvshc.js → studio-5523bpzt.js} +11 -11
- package/dist/chunks/{studio-5q69gfag.js → studio-57mf66w2.js} +1753 -2484
- package/dist/chunks/studio-5jy81t3s.js +17463 -0
- package/dist/chunks/studio-5rt7sqa0.js +1168 -0
- package/dist/chunks/studio-5te5tqng.js +81 -0
- package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
- package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
- package/dist/chunks/studio-6xa21ej9.js +28 -0
- package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
- package/dist/chunks/{studio-eenfkt4e.js → studio-79y5sz51.js} +52 -38
- package/dist/chunks/{studio-4q0wznzf.js → studio-7e11jpa9.js} +461 -145
- package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
- package/dist/chunks/studio-7xptrg0j.js +954 -0
- package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
- package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
- package/dist/chunks/studio-8qtrpzr3.js +839 -0
- package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
- package/dist/chunks/studio-9xxz1q69.js +1356 -0
- package/dist/chunks/studio-akbww0j5.js +13615 -0
- package/dist/chunks/studio-arfpe389.js +195 -0
- package/dist/chunks/{studio-2zkz8evn.js → studio-az3zd49t.js} +473 -281
- package/dist/chunks/studio-cpvb2ed1.js +1171 -0
- package/dist/chunks/{studio-9r6j5ev1.js → studio-d0300636.js} +5078 -19
- package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
- package/dist/chunks/studio-d1ja2x9r.js +362 -0
- package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
- package/dist/chunks/{studio-4pqqxbrt.js → studio-em9nw8eh.js} +301 -112
- package/dist/chunks/studio-erdatzvp.js +1190 -0
- package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
- package/dist/chunks/studio-fabxk6r9.js +2811 -0
- package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
- package/dist/chunks/studio-hhvs4sdg.js +195 -0
- package/dist/chunks/{studio-68n67094.js → studio-kcgff4r0.js} +15 -18
- package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
- package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
- package/dist/chunks/studio-pm6hgy7r.js +4763 -0
- package/dist/chunks/studio-q0a3yk4n.js +33 -0
- package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
- package/dist/chunks/studio-qahxvnan.js +111 -0
- package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
- package/dist/chunks/{studio-kjjsjak4.js → studio-rkstz940.js} +3661 -6136
- package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
- package/dist/chunks/studio-rpyah2ew.js +2805 -0
- package/dist/chunks/studio-rs76k67r.js +12 -0
- package/dist/chunks/{studio-yxrkyv8a.js → studio-s6z853aq.js} +12108 -11766
- package/dist/chunks/{studio-sf7zjgv1.js → studio-sgdc5pfc.js} +8 -8
- package/dist/chunks/studio-tb3ev01j.js +763 -0
- package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
- package/dist/chunks/studio-vhv5tgxm.js +51 -0
- package/dist/chunks/{studio-htsf0w6m.js → studio-vz68yn9e.js} +31 -154
- package/dist/chunks/studio-wqpngpsk.js +174 -0
- package/dist/chunks/{studio-eesa1myv.js → studio-x3rty6tr.js} +58 -58
- package/dist/chunks/studio-xsykpvsh.js +8448 -0
- package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
- package/dist/chunks/studio-yxa81f45.js +12 -0
- package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
- package/dist/chunks/tabs-wbp1cdws.js +156 -0
- package/dist/chunks/textfield-abk6qyee.js +73 -0
- package/dist/chunks/toast-780pvfbv.js +27 -0
- package/dist/chunks/toast-host-3sqv46sn.js +116 -0
- package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
- package/dist/chunks/tooltip-eptb614w.js +369 -0
- package/dist/chunks/tree-a73p0pqm.js +367 -0
- package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
- package/dist/chunks/workspace-wrew8zk4.js +69 -0
- package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
- package/dist/iframe-entry.js +1812 -698
- package/dist/manifest.json +7 -0
- package/dist/studio.js +52900 -36573
- package/dist/workers/editor.worker.js +1040 -1085
- package/dist/workers/json.worker.js +1946 -1991
- package/dist/workers/ts.worker.js +4960 -5005
- package/favicon.ico +0 -0
- package/index.html +2 -0
- package/package.json +22 -55
- package/src/about/about-modal.ts +73 -123
- package/src/browse/library-commands.ts +20 -49
- package/src/browse/library-layouts.ts +87 -218
- package/src/browse/library-pane.ts +406 -438
- package/src/canvas/canvas-helpers.ts +0 -49
- package/src/canvas/canvas-live-render.ts +25 -2
- package/src/canvas/canvas-render.ts +666 -231
- package/src/canvas/canvas-surface.ts +0 -1
- package/src/canvas/canvas-utils.ts +310 -117
- package/src/canvas/dialog-path.ts +76 -0
- package/src/canvas/dialog-state.ts +67 -0
- package/src/canvas/diff-marks.ts +252 -0
- package/src/canvas/diff-toolbar.ts +349 -0
- package/src/canvas/diff-view.ts +123 -0
- package/src/canvas/edit-width-drag.ts +187 -0
- package/src/canvas/edit-width.ts +150 -0
- package/src/canvas/iframe-entry.ts +125 -8
- package/src/canvas/iframe-host.ts +271 -15
- package/src/canvas/iframe-interaction.ts +133 -13
- package/src/canvas/iframe-patch.ts +7 -1
- package/src/canvas/iframe-position.ts +5 -6
- package/src/canvas/iframe-protocol.ts +106 -5
- package/src/canvas/iframe-render.ts +373 -5
- package/src/canvas/iframe-slash.ts +2 -2
- package/src/canvas/iframe-subtree.ts +5 -8
- package/src/canvas/path-mapping.ts +25 -3
- package/src/canvas/popover-path.ts +106 -0
- package/src/canvas/popover-state.ts +155 -0
- package/src/canvas/surface-registry.ts +21 -10
- package/src/collab/presence-chips.ts +51 -73
- package/src/commands/app-commands.ts +10 -0
- package/src/commands/budget.ts +12 -0
- package/src/commands/command-args.ts +369 -6
- package/src/commands/defaults.ts +44 -14
- package/src/commands/live-context.ts +11 -5
- package/src/commands/reference.ts +12 -2
- package/src/commands/registry.ts +165 -8
- package/src/content/entry-commands.ts +16 -23
- package/src/content/entry-editor.ts +144 -101
- package/src/editor/canvas-slash-bridge.ts +2 -2
- package/src/editor/context-menu.ts +49 -200
- package/src/editor/convert-to-component.ts +42 -82
- package/src/editor/convert-to-repeater.ts +132 -173
- package/src/editor/inline-edit.ts +11 -0
- package/src/editor/shortcuts.ts +65 -26
- package/src/editor/slash-menu.ts +150 -157
- package/src/files/file-ops.ts +117 -11
- package/src/files/files.ts +949 -664
- package/src/files/json-layout.ts +474 -0
- package/src/files/media-paths.ts +13 -42
- package/src/files/media-usage.ts +41 -131
- package/src/files/serialize-document.ts +8 -1
- package/src/format/convert-file.ts +16 -10
- package/src/format/format-host.ts +50 -1
- package/src/github/github-auth.ts +71 -29
- package/src/github/github-publish.ts +57 -65
- package/src/grid/cell-editors.ts +46 -4
- package/src/grid/cell-popovers.ts +65 -62
- package/src/grid/grid-open.ts +86 -64
- package/src/grid/grid-panel.ts +390 -469
- package/src/grid/redirects-grid.ts +40 -44
- package/src/hosting/document.ts +2 -0
- package/src/hosting/layout.ts +10 -0
- package/src/i18n/i18n-commands.ts +127 -62
- package/src/media/media-pane.ts +83 -133
- package/src/new-project/add-repo-modal.ts +125 -176
- package/src/new-project/import-tab.ts +201 -250
- package/src/new-project/location-fields.ts +101 -165
- package/src/new-project/new-project-modal.ts +376 -367
- package/src/packages/jxsuite-update.ts +76 -18
- package/src/panels/activity-panel.ts +137 -104
- package/src/panels/ai-chat/chat-markdown.ts +15 -13
- package/src/panels/ai-chat/chat-view.ts +307 -472
- package/src/panels/ai-chat/composer.ts +175 -153
- package/src/panels/ai-chat/sessions-view.ts +31 -62
- package/src/panels/ai-panel.ts +210 -185
- package/src/panels/block-action-bar.ts +437 -643
- package/src/panels/bottom-dock.ts +112 -47
- package/src/panels/chat-panel.ts +19 -14
- package/src/panels/data-explorer.ts +141 -102
- package/src/panels/data-grid.ts +183 -150
- package/src/panels/dnd.ts +75 -20
- package/src/panels/editors.ts +26 -19
- package/src/panels/elements-panel.ts +243 -186
- package/src/panels/empty-state.ts +26 -42
- package/src/panels/events-panel.ts +950 -729
- package/src/panels/formula-workspace.ts +434 -207
- package/src/panels/frontmatter-fields.ts +185 -153
- package/src/panels/frontmatter-panel.ts +411 -187
- package/src/panels/git-diff-open.ts +148 -0
- package/src/panels/git-panel.ts +679 -605
- package/src/panels/head-panel.ts +617 -435
- package/src/panels/i18n-panel.ts +153 -133
- package/src/panels/imports-panel.ts +388 -414
- package/src/panels/jump-bar.ts +174 -147
- package/src/panels/layers-panel.ts +785 -671
- package/src/panels/left-panel.ts +166 -94
- package/src/panels/navigator-panels.ts +1 -1
- package/src/panels/pane-context.ts +529 -677
- package/src/panels/pane-grid.ts +265 -241
- package/src/panels/panel-registry.ts +15 -4
- package/src/panels/problems-panel.ts +177 -99
- package/src/panels/properties-panel.ts +1525 -966
- package/src/panels/provenance.ts +31 -113
- package/src/panels/quick-search.ts +217 -172
- package/src/panels/right-panel.ts +135 -169
- package/src/panels/seo-modal.ts +346 -167
- package/src/panels/settings-menu.ts +109 -646
- package/src/panels/settings-pane.ts +102 -86
- package/src/panels/signals-panel.ts +1318 -1172
- package/src/panels/statement-editor.ts +556 -428
- package/src/panels/style-panel.ts +1367 -630
- package/src/panels/style-utils.ts +36 -32
- package/src/panels/stylebook-doc.ts +30 -73
- package/src/panels/stylebook-layers-panel.ts +202 -109
- package/src/panels/stylebook-panel.ts +124 -88
- package/src/panels/tab-strip.ts +385 -287
- package/src/platforms/cloud.ts +347 -86
- package/src/platforms/devserver.ts +13 -0
- package/src/publish/deploy-checklist.ts +124 -78
- package/src/publish/publish-commands.ts +4 -12
- package/src/publish/publish-panel.ts +165 -299
- package/src/services/a11y-report.ts +100 -43
- package/src/services/ai-command-tools.ts +468 -0
- package/src/services/ai-import-tools.ts +50 -12
- package/src/services/ai-models.ts +108 -1
- package/src/services/ai-session-store.ts +6 -0
- package/src/services/ai-system-prompt.ts +110 -18
- package/src/services/ai-tools.ts +28 -143
- package/src/services/ai-write-report.ts +174 -0
- package/src/services/context-manager.ts +12 -1
- package/src/services/document-assistant.ts +50 -2
- package/src/services/idle.ts +16 -14
- package/src/services/live-surfaces.ts +237 -0
- package/src/services/model-uri.ts +75 -0
- package/src/services/notify.ts +63 -6
- package/src/services/popover-report.ts +325 -0
- package/src/services/surface-registry.ts +56 -0
- package/src/services/tool-executor.ts +17 -0
- package/src/settings/contexts-section.ts +301 -299
- package/src/settings/contributed-section.ts +361 -222
- package/src/settings/css-vars-editor.ts +320 -325
- package/src/settings/defs-editor.ts +572 -535
- package/src/settings/dependencies-editor.ts +79 -107
- package/src/settings/extension-commands.ts +379 -0
- package/src/settings/extension-rows.ts +113 -0
- package/src/settings/extensions-section.ts +287 -0
- package/src/settings/general-settings.ts +130 -181
- package/src/settings/head-editor.ts +10 -305
- package/src/settings/locales-section.ts +146 -196
- package/src/settings/preferences-accounts.ts +193 -12
- package/src/settings/preferences-dialog.ts +384 -307
- package/src/settings/project-sections.ts +108 -181
- package/src/settings/schema-field-ui.ts +11 -399
- package/src/settings/section-registry.ts +8 -1
- package/src/settings/settings-document.ts +31 -29
- package/src/shell/tree.ts +42 -87
- package/src/shell.ts +48 -36
- package/src/studio.ts +90 -67
- package/src/style/token-ref.ts +0 -39
- package/src/surfaces/about.json +263 -0
- package/src/surfaces/about.ts +163 -0
- package/src/surfaces/add-repo.json +486 -0
- package/src/surfaces/add-repo.ts +236 -0
- package/src/surfaces/ai-chat.json +2185 -0
- package/src/surfaces/ai-chat.ts +549 -0
- package/src/surfaces/ai-credentials-form.json +332 -0
- package/src/surfaces/ai-credentials-form.ts +151 -0
- package/src/surfaces/ai-managed-connect.json +108 -0
- package/src/surfaces/ai-managed-connect.ts +123 -0
- package/src/surfaces/ai-model-picker.json +114 -0
- package/src/surfaces/ai-model-picker.ts +139 -0
- package/src/surfaces/block-action-bar.json +640 -0
- package/src/surfaces/block-action-bar.ts +368 -0
- package/src/surfaces/bottom-dock.json +154 -0
- package/src/surfaces/bottom-dock.ts +125 -0
- package/src/surfaces/canvas-stage.json +444 -0
- package/src/surfaces/canvas-stage.ts +253 -0
- package/src/surfaces/cf-account-picker.json +300 -0
- package/src/surfaces/cf-account-picker.ts +214 -0
- package/src/surfaces/commandbar.json +984 -0
- package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
- package/src/surfaces/convert-repeater.json +309 -0
- package/src/surfaces/convert-repeater.ts +276 -0
- package/src/surfaces/data-actions.json +157 -0
- package/src/surfaces/data-actions.ts +115 -0
- package/src/surfaces/dialog.json +289 -0
- package/src/surfaces/dialog.ts +343 -0
- package/src/surfaces/diff-toolbar.json +266 -0
- package/src/surfaces/diff-toolbar.ts +139 -0
- package/src/surfaces/doc-header.json +739 -0
- package/src/surfaces/doc-header.ts +223 -0
- package/src/surfaces/empty-state.json +152 -0
- package/src/surfaces/empty-state.ts +173 -0
- package/src/surfaces/entry-editor.json +281 -0
- package/src/surfaces/entry-editor.ts +191 -0
- package/src/surfaces/expression-editor.json +977 -0
- package/src/surfaces/expression-editor.ts +266 -0
- package/src/surfaces/files-panel.json +592 -0
- package/src/surfaces/files-panel.ts +301 -0
- package/src/surfaces/formula-palette.json +364 -0
- package/src/surfaces/formula-palette.ts +340 -0
- package/src/surfaces/git-panel.json +1822 -0
- package/src/surfaces/git-panel.ts +272 -0
- package/src/surfaces/github-auth.json +112 -0
- package/src/surfaces/github-auth.ts +139 -0
- package/src/surfaces/github-publish.json +206 -0
- package/src/surfaces/github-publish.ts +169 -0
- package/src/surfaces/grid-cell.json +218 -0
- package/src/surfaces/grid-cell.ts +120 -0
- package/src/surfaces/grid-open.json +147 -0
- package/src/surfaces/grid-open.ts +87 -0
- package/src/surfaces/grid-panel.json +706 -0
- package/src/surfaces/grid-panel.ts +206 -0
- package/src/surfaces/grid-replace.json +179 -0
- package/src/surfaces/grid-replace.ts +89 -0
- package/src/surfaces/grid-views.json +446 -0
- package/src/surfaces/grid-views.ts +172 -0
- package/src/surfaces/inspector-dock.json +187 -0
- package/src/surfaces/inspector-dock.ts +161 -0
- package/src/surfaces/jump-bar.json +243 -0
- package/src/surfaces/jump-bar.ts +129 -0
- package/src/surfaces/jxsuite-update.json +146 -0
- package/src/surfaces/jxsuite-update.ts +149 -0
- package/src/surfaces/library-pane.json +1509 -0
- package/src/surfaces/library-pane.ts +363 -0
- package/src/surfaces/logic-panel.json +1949 -0
- package/src/surfaces/logic-panel.ts +369 -0
- package/src/surfaces/logic-workspace.json +685 -0
- package/src/surfaces/logic-workspace.ts +238 -0
- package/src/surfaces/media-browser.json +303 -0
- package/src/surfaces/media-browser.ts +145 -0
- package/src/surfaces/media-field.json +163 -0
- package/src/surfaces/media-field.ts +116 -0
- package/src/surfaces/media-pane.json +513 -0
- package/src/surfaces/media-pane.ts +197 -0
- package/src/surfaces/menu.json +232 -0
- package/src/surfaces/menu.ts +375 -0
- package/src/surfaces/navigator-dock.json +113 -0
- package/src/surfaces/navigator-dock.ts +130 -0
- package/src/surfaces/new-project.json +1654 -0
- package/src/surfaces/new-project.ts +411 -0
- package/src/surfaces/palette.json +535 -0
- package/src/surfaces/pane-context.json +1497 -0
- package/src/surfaces/pane-context.ts +513 -0
- package/src/surfaces/pane-grid.json +188 -0
- package/src/surfaces/pane-grid.ts +250 -0
- package/src/surfaces/panel-activity.json +563 -0
- package/src/surfaces/panel-activity.ts +187 -0
- package/src/surfaces/panel-data.json +141 -0
- package/src/surfaces/panel-data.ts +156 -0
- package/src/surfaces/panel-deploy-checklist.json +283 -0
- package/src/surfaces/panel-deploy-checklist.ts +175 -0
- package/src/surfaces/panel-elements.json +367 -0
- package/src/surfaces/panel-elements.ts +175 -0
- package/src/surfaces/panel-i18n.json +569 -0
- package/src/surfaces/panel-i18n.ts +212 -0
- package/src/surfaces/panel-imports.json +780 -0
- package/src/surfaces/panel-imports.ts +209 -0
- package/src/surfaces/panel-outline.json +734 -0
- package/src/surfaces/panel-outline.ts +326 -0
- package/src/surfaces/panel-page.json +1017 -0
- package/src/surfaces/panel-page.ts +240 -0
- package/src/surfaces/panel-problems.json +497 -0
- package/src/surfaces/panel-problems.ts +157 -0
- package/src/surfaces/panel-signals.json +1973 -0
- package/src/surfaces/panel-signals.ts +436 -0
- package/src/surfaces/panel-stylebook-layers.json +317 -0
- package/src/surfaces/panel-stylebook-layers.ts +155 -0
- package/src/surfaces/preferences.json +850 -0
- package/src/surfaces/preferences.ts +332 -0
- package/src/surfaces/progress-modal.json +110 -0
- package/src/surfaces/progress-modal.ts +150 -0
- package/src/surfaces/properties-panel.json +1578 -0
- package/src/surfaces/properties-panel.ts +337 -0
- package/src/surfaces/publish.json +945 -0
- package/src/surfaces/publish.ts +392 -0
- package/src/surfaces/push-plan.json +110 -0
- package/src/surfaces/push-plan.ts +87 -0
- package/src/surfaces/rail.json +255 -0
- package/src/surfaces/rail.ts +206 -0
- package/src/surfaces/reference-field.json +191 -0
- package/src/surfaces/reference-field.ts +168 -0
- package/src/surfaces/schema-builder.json +1011 -0
- package/src/surfaces/schema-builder.ts +181 -0
- package/src/surfaces/schema-form.json +1013 -0
- package/src/surfaces/schema-form.ts +287 -0
- package/src/surfaces/secret-field.json +60 -0
- package/src/surfaces/secret-field.ts +146 -0
- package/src/surfaces/seo.json +932 -0
- package/src/surfaces/seo.ts +334 -0
- package/src/surfaces/settings-contexts.json +538 -0
- package/src/surfaces/settings-contexts.ts +196 -0
- package/src/surfaces/settings-contributed.json +489 -0
- package/src/surfaces/settings-contributed.ts +199 -0
- package/src/surfaces/settings-css-vars.json +820 -0
- package/src/surfaces/settings-css-vars.ts +199 -0
- package/src/surfaces/settings-defs.json +1363 -0
- package/src/surfaces/settings-defs.ts +232 -0
- package/src/surfaces/settings-deploy.json +108 -0
- package/src/surfaces/settings-deploy.ts +135 -0
- package/src/surfaces/settings-extensions.json +486 -0
- package/src/surfaces/settings-extensions.ts +201 -0
- package/src/surfaces/settings-head.json +779 -0
- package/src/surfaces/settings-head.ts +397 -0
- package/src/surfaces/settings-locales.json +420 -0
- package/src/surfaces/settings-locales.ts +137 -0
- package/src/surfaces/settings-overview.json +423 -0
- package/src/surfaces/settings-overview.ts +218 -0
- package/src/surfaces/settings-packages.json +549 -0
- package/src/surfaces/settings-packages.ts +158 -0
- package/src/surfaces/settings-pane.json +147 -0
- package/src/surfaces/settings-pane.ts +150 -0
- package/src/surfaces/settings-rawjson.json +104 -0
- package/src/surfaces/settings-rawjson.ts +107 -0
- package/src/surfaces/shell.json +99 -0
- package/src/surfaces/shell.ts +30 -0
- package/src/surfaces/slash-menu.json +180 -0
- package/src/surfaces/slash-menu.ts +272 -0
- package/src/surfaces/statements.json +607 -0
- package/src/surfaces/statements.ts +238 -0
- package/src/surfaces/statusbar.json +94 -0
- package/src/{panels → surfaces}/statusbar.ts +163 -90
- package/src/surfaces/style-panel.json +1643 -0
- package/src/surfaces/style-panel.ts +338 -0
- package/src/surfaces/stylebook-chrome.json +122 -0
- package/src/surfaces/stylebook-chrome.ts +122 -0
- package/src/surfaces/tab-strip.json +448 -0
- package/src/surfaces/tab-strip.ts +200 -0
- package/src/surfaces/target-line.json +419 -0
- package/src/surfaces/target-line.ts +349 -0
- package/src/surfaces/toasts.json +189 -0
- package/src/surfaces/welcome.json +571 -0
- package/src/surfaces/welcome.ts +338 -0
- package/src/tabs/project-config.ts +71 -15
- package/src/tabs/tab.ts +52 -1
- package/src/types.ts +49 -3
- package/src/ui/ai-credentials-form.ts +104 -100
- package/src/ui/ai-managed-connect.ts +116 -49
- package/src/ui/ai-model-picker.ts +102 -47
- package/src/ui/cf-account-picker.ts +135 -0
- package/src/ui/color-selector.ts +80 -301
- package/src/ui/dynamic-slot.ts +43 -283
- package/src/ui/expression-editor.ts +797 -576
- package/src/ui/field-input.ts +8 -181
- package/src/ui/form-controls.ts +838 -366
- package/src/ui/formula-chips.ts +80 -85
- package/src/ui/kit.ts +33 -0
- package/src/ui/layers.ts +293 -593
- package/src/ui/media-picker.ts +203 -284
- package/src/ui/panel-resize.ts +251 -64
- package/src/ui/popover-surface.ts +153 -0
- package/src/ui/progress-modal.ts +22 -60
- package/src/ui/regions.ts +13 -7
- package/src/ui/schema-form.ts +906 -440
- package/src/ui/surface.ts +122 -0
- package/src/ui/unit-selector.ts +15 -131
- package/src/ui/value-source.ts +14 -0
- package/src/ui/virtual-window.ts +88 -9
- package/src/utils/canvas-media.ts +72 -0
- package/src/utils/edit-display.ts +7 -2
- package/src/utils/element-selectors.ts +69 -0
- package/src/utils/link-target.ts +2 -2
- package/src/utils/studio-utils.ts +0 -10
- package/src/view.ts +15 -0
- package/src/workspace/pane-derive.ts +36 -14
- package/src/workspace/workspace.ts +15 -6
- package/styles/canvas.css +72 -467
- package/styles/forced-colors.css +48 -82
- package/styles/forced-colors.json +41 -0
- package/styles/inspector.css +2 -1301
- package/styles/overlays.css +96 -2823
- package/styles/panels.css +6 -1423
- package/styles/shell-frame.css +272 -0
- package/styles/shell-frame.json +227 -0
- package/styles/shell.css +0 -1532
- package/styles/tokens.css +65 -136
- package/styles/tokens.json +84 -0
- package/dist/chunks/Overlay.dev-723bv0df.js +0 -23
- package/dist/chunks/adapter-jkcyhgtr.js +0 -14
- package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
- package/dist/chunks/components-zmx10t62.js +0 -21
- package/dist/chunks/content-source-t88vb2dr.js +0 -49
- package/dist/chunks/convert-to-repeater-dhw1nrz9.js +0 -268
- package/dist/chunks/editor-cptq5jp1.js +0 -37
- package/dist/chunks/entry-commands-6z6bhxg0.js +0 -46
- package/dist/chunks/extension-sections-3ydgjbdy.js +0 -311
- package/dist/chunks/file-ops-rskmhxyq.js +0 -48
- package/dist/chunks/files-0cratsr0.js +0 -92
- package/dist/chunks/flow-qbfgrpeh.js +0 -634
- package/dist/chunks/focus-trap.esm-ggawf1hy.js +0 -1024
- package/dist/chunks/focus-visible-6eg70z18.js +0 -167
- package/dist/chunks/format-host-tgcmfs4p.js +0 -43
- package/dist/chunks/fs-events-hrrg328g.js +0 -21
- package/dist/chunks/git-panel-0yywyk76.js +0 -58
- package/dist/chunks/index-zqxmqxmh.js +0 -109
- package/dist/chunks/jx-validate-8q2g05x1.js +0 -19
- package/dist/chunks/layers-panel-z3tqe5cd.js +0 -67
- package/dist/chunks/layers-q75tj2mf.js +0 -45
- package/dist/chunks/lit-html-j055mkh8.js +0 -22
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
- package/dist/chunks/notify-yjm79n4s.js +0 -30
- package/dist/chunks/parse-24d0gay3.js +0 -19
- package/dist/chunks/platform-ba1j1gbh.js +0 -16
- package/dist/chunks/publish-panel-54jvhskq.js +0 -28
- package/dist/chunks/quick-search-cgfmjwq5.js +0 -65
- package/dist/chunks/references-3qx8fkyp.js +0 -29
- package/dist/chunks/right-panel-cqp8bc4v.js +0 -46
- package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
- package/dist/chunks/sp-overlay.dev-yztmtrs1.js +0 -18
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
- package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +0 -15
- package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
- package/dist/chunks/studio-0a5qrh01.js +0 -3
- package/dist/chunks/studio-18j3bmcz.js +0 -14
- package/dist/chunks/studio-1hbqnt19.js +0 -1823
- package/dist/chunks/studio-4rzyrtjz.js +0 -426
- package/dist/chunks/studio-5rywrkxz.js +0 -1903
- package/dist/chunks/studio-7afd21nw.js +0 -67
- package/dist/chunks/studio-7nte2hj4.js +0 -613
- package/dist/chunks/studio-8jpzqk5s.js +0 -128
- package/dist/chunks/studio-8q517dfr.js +0 -24
- package/dist/chunks/studio-9c4k4vhv.js +0 -357
- package/dist/chunks/studio-9n4mrmnb.js +0 -184
- package/dist/chunks/studio-a0tswy0w.js +0 -58
- package/dist/chunks/studio-ahjfdy6e.js +0 -387
- package/dist/chunks/studio-ahnzd9rg.js +0 -23
- package/dist/chunks/studio-bw5dz6km.js +0 -608
- package/dist/chunks/studio-cb12yz9w.js +0 -15055
- package/dist/chunks/studio-d1ks410h.js +0 -175
- package/dist/chunks/studio-eqq1w638.js +0 -113
- package/dist/chunks/studio-ex8zyp98.js +0 -1813
- package/dist/chunks/studio-h4rxscfc.js +0 -10
- package/dist/chunks/studio-kyh9avvv.js +0 -28
- package/dist/chunks/studio-kyk2v92a.js +0 -659
- package/dist/chunks/studio-m3hwn7y1.js +0 -120
- package/dist/chunks/studio-mmv72a27.js +0 -4344
- package/dist/chunks/studio-n8b9wqwy.js +0 -291
- package/dist/chunks/studio-pdfjntbk.js +0 -6939
- package/dist/chunks/studio-qq6jym04.js +0 -53
- package/dist/chunks/studio-r1r7afxx.js +0 -1066
- package/dist/chunks/studio-rdx8jcxy.js +0 -83
- package/dist/chunks/studio-rn9ta2mz.js +0 -111
- package/dist/chunks/studio-t7qb9db8.js +0 -665
- package/dist/chunks/studio-tmc5emrw.js +0 -8
- package/dist/chunks/studio-txwkm6p9.js +0 -12
- package/dist/chunks/studio-v38hmvx1.js +0 -390
- package/dist/chunks/studio-vadzgkrz.js +0 -318
- package/dist/chunks/studio-wx5609xd.js +0 -341
- package/dist/chunks/studio-z6nw2ek2.js +0 -18
- package/dist/chunks/studio-zczps70q.js +0 -378
- package/dist/chunks/workspace-xpres40v.js +0 -89
- package/src/panels/activity-bar.ts +0 -251
- package/src/panels/panel-scheduler.ts +0 -219
- package/src/panels/style-inputs.ts +0 -237
- package/src/panels/target-line.ts +0 -274
- package/src/panels/welcome-screen.ts +0 -346
- package/src/ui/button-group.ts +0 -102
- package/src/ui/choice-field.ts +0 -72
- package/src/ui/field-row.ts +0 -249
- package/src/ui/formula-palette.ts +0 -213
- package/src/ui/icons.ts +0 -52
- package/src/ui/jx-theme.ts +0 -130
- package/src/ui/spectrum.ts +0 -340
- package/src/ui/value-selector.ts +0 -174
- package/src/ui/widgets.ts +0 -172
- /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
- /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
- /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
- /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* The Command Bar — region ① of
|
|
3
|
+
* The Command Bar — region ① of studio-ui-guidelines §6, rendered FROM the registry, as a document.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* `surfaces/commandbar.json` is the band; this module is its adapter. Every control in the band is
|
|
6
|
+
* a command, so what the document is handed is a PROJECTION of the registry rather than a list of
|
|
7
|
+
* buttons: `primary` is `forPlacement("commandbar/primary")` (capped at five by
|
|
8
|
+
* `scripts/check-chrome-budget.ts`), `docks` is the three dock records with the shell's state
|
|
9
|
+
* beside them, `layouts` is the project's own layout record, and the ⬢ Studio menu is
|
|
10
|
+
* `forPlacement("commandbar/overflow")` opened on the `menu` surface. With no project open the same
|
|
11
|
+
* document renders; the records' own `when` clauses empty it (§2 principle 4: enablement is a
|
|
12
|
+
* predicate with a sentence, never a second template).
|
|
11
13
|
*
|
|
12
|
-
* What is
|
|
14
|
+
* What is decided here, and nowhere in the document:
|
|
13
15
|
*
|
|
14
|
-
* - {@link
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* it is off — so no control is ever permanently dead with no explanation.
|
|
18
|
-
* - The primary verb cluster is `forPlacement("commandbar/primary")`, capped at five by
|
|
19
|
-
* `scripts/check-chrome-budget.ts`; the ⬢ menu is `forPlacement("commandbar/overflow")`.
|
|
16
|
+
* - {@link commandTooltip}: the title, plus its chord formatted for THIS platform by `keymap.format`,
|
|
17
|
+
* or plus the `requires` sentence when the record is off — so no control is ever permanently dead
|
|
18
|
+
* with no explanation.
|
|
20
19
|
* - The **Command Center pill** (①a) is the app's address bar: `◈ project › document › selection`,
|
|
21
|
-
* right-aligned ⌘K, each segment opening the palette pre-scoped. It
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* - The window controls, which are the one thing in here that is not an action.
|
|
20
|
+
* right-aligned ⌘K, each segment opening the palette pre-scoped. It gives Studio a persistent
|
|
21
|
+
* project name — the desktop titlebar is `titleBarStyle:"hidden"`.
|
|
22
|
+
* - The window controls, which are the one thing in the band that is not an action, and whose ORDER
|
|
23
|
+
* is the platform's.
|
|
26
24
|
*
|
|
27
|
-
* **Retired
|
|
28
|
-
*
|
|
29
|
-
* the `Publish:` family; `Sync Project` → Source Control. The five-mode switcher
|
|
30
|
-
*
|
|
31
|
-
*
|
|
25
|
+
* **Retired, with a name, a chord and a residue** (§2 principle 9): Open Project + New Project +
|
|
26
|
+
* recents → the pill and `Project: Open Recent…`; `Manage` → `File: Browse Library`; `Publish` →
|
|
27
|
+
* the `Publish:` family; `Sync Project` → Source Control. The five-mode switcher lives in the pane
|
|
28
|
+
* context bar and is reachable as `View: Set Canvas Mode` in the palette.
|
|
29
|
+
*
|
|
30
|
+
* @docs studio/interface
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import { effect, effectScope } from "../reactivity";
|
|
33
|
+
import { presenceProjection } from "../collab/presence-chips";
|
|
34
|
+
import { effect, effectScope, reactive } from "../reactivity";
|
|
37
35
|
import { activeTab } from "../workspace/workspace";
|
|
38
36
|
import { primarySelection } from "../tabs/selection";
|
|
39
37
|
import { shell } from "../shell";
|
|
40
|
-
import { openQuickSearch } from "
|
|
38
|
+
import { openQuickSearch } from "../panels/quick-search";
|
|
41
39
|
import { showPromptDialog } from "../ui/layers";
|
|
42
40
|
import { getPlatform, hasPlatform } from "../platform";
|
|
43
41
|
import { getPreviewNavigateHandler } from "../canvas/preview-navigate";
|
|
@@ -46,19 +44,29 @@ import { documentUrlPattern, dynamicRouteParams } from "../page-params";
|
|
|
46
44
|
import { getNodeAtPath, nodeLabel, projectState } from "../store";
|
|
47
45
|
import { activeRegistry } from "../commands/active-registry";
|
|
48
46
|
import { notify } from "../services/notify";
|
|
47
|
+
import { mountSurface, registerSurface } from "../ui/surface";
|
|
48
|
+
import { rectOf } from "../utils/geometry";
|
|
49
|
+
import { openMenu } from "./menu";
|
|
50
|
+
import commandbarDoc from "./commandbar.json";
|
|
51
|
+
import type { PresenceProjection } from "../collab/presence-chips";
|
|
52
|
+
import type { MenuHandle, MenuRowProjection } from "./menu";
|
|
53
|
+
import type { SurfaceHandle } from "../ui/surface";
|
|
49
54
|
import type { Tab } from "../tabs/tab";
|
|
50
55
|
import type { SiteBuildResult, SitePreviewResult, StudioPlatform } from "../types";
|
|
51
56
|
import type { CommandRegistry } from "../commands/registry";
|
|
52
57
|
import type { EffectScope } from "@vue/reactivity";
|
|
53
|
-
import type {
|
|
58
|
+
import type { JxDocument } from "@jxsuite/schema/types";
|
|
59
|
+
|
|
60
|
+
registerSurface("commandbar", commandbarDoc as unknown as JxDocument);
|
|
54
61
|
|
|
55
62
|
/**
|
|
56
63
|
* What the Command Bar is handed at mount.
|
|
57
64
|
*
|
|
58
65
|
* HANDOFF: **nothing here is read any more** — every control in the band is a command, so the bar
|
|
59
66
|
* asks the registry rather than the bootstrap. The fields stay declared, and optional, so
|
|
60
|
-
* `studio.ts`'s `toolbarPanel.mount(toolbarEl, { … })` object literal keeps type-checking
|
|
61
|
-
*
|
|
67
|
+
* `studio.ts`'s `toolbarPanel.mount(toolbarEl, { … })` object literal keeps type-checking, and the
|
|
68
|
+
* shell tests keep driving the canvas-mode seam through it; deleting them is one edit in that
|
|
69
|
+
* file.
|
|
62
70
|
*/
|
|
63
71
|
export interface ToolbarCtx {
|
|
64
72
|
openProject?: () => void;
|
|
@@ -72,8 +80,6 @@ export interface ToolbarCtx {
|
|
|
72
80
|
closeFunctionEditor?: () => void;
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
let _rootEl: HTMLElement | null = null;
|
|
76
|
-
|
|
77
83
|
/** Test override for the mac CSD layout — happy-dom forbids redefining navigator.platform. */
|
|
78
84
|
let _isMacOverride: boolean | null = null;
|
|
79
85
|
|
|
@@ -87,34 +93,114 @@ function isMacPlatform(): boolean {
|
|
|
87
93
|
return _isMacOverride ?? navigator.platform.startsWith("Mac");
|
|
88
94
|
}
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
// ─── The projections ──────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
/** One command of the primary cluster, as the document draws it. */
|
|
99
|
+
export interface PrimaryProjection {
|
|
100
|
+
id: string;
|
|
101
|
+
title: string;
|
|
102
|
+
/** {@link commandTooltip}: the name with its chord, or with why it is off. */
|
|
103
|
+
tooltip: string;
|
|
104
|
+
/** The record's glyph, by its name in the kit's manifest; empty for a labelled button. */
|
|
105
|
+
icon: string;
|
|
106
|
+
hasIcon: boolean;
|
|
107
|
+
disabled: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** One dock toggle: the record, with the dock's state beside it. */
|
|
111
|
+
export interface DockProjection {
|
|
112
|
+
id: string;
|
|
113
|
+
title: string;
|
|
114
|
+
tooltip: string;
|
|
115
|
+
icon: string;
|
|
116
|
+
/** The right-hand dock draws the left-hand glyph mirrored: one shipped shape, two sides. */
|
|
117
|
+
mirror: boolean;
|
|
118
|
+
/** Pressed while the dock is open. */
|
|
119
|
+
selected: boolean;
|
|
120
|
+
disabled: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** One layout tab. */
|
|
124
|
+
export interface LayoutTabProjection {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
active: boolean;
|
|
128
|
+
title: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** One segment of the address bar. */
|
|
132
|
+
export interface SegmentProjection {
|
|
133
|
+
key: "project" | "document" | "selection";
|
|
134
|
+
label: string;
|
|
135
|
+
title: string;
|
|
136
|
+
/** Every segment but the first is preceded by `›`. */
|
|
137
|
+
sepBefore: boolean;
|
|
138
|
+
}
|
|
91
139
|
|
|
92
140
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* The RECORD names the icon; this map only knows how to draw one. Keys are the record's vocabulary
|
|
96
|
-
* ("save", "undo"), not Spectrum tag names, so swapping the icon set is a change here and nowhere
|
|
97
|
-
* else — and a record that names an icon this bar cannot draw renders as a labelled button rather
|
|
98
|
-
* than as an empty one.
|
|
141
|
+
* Which window-control layout the band draws: none in a browser, mac leading, everything else
|
|
142
|
+
* trailing.
|
|
99
143
|
*/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
144
|
+
export type WindowControlLayout = "none" | "mac" | "other";
|
|
145
|
+
|
|
146
|
+
/** The document's scope: the projections, and the host functions its handlers `call`. */
|
|
147
|
+
interface CommandBarScope extends Record<string, unknown> {
|
|
148
|
+
csd: WindowControlLayout;
|
|
149
|
+
menuVisible: boolean;
|
|
150
|
+
menuOpen: boolean;
|
|
151
|
+
layoutsVisible: boolean;
|
|
152
|
+
layouts: LayoutTabProjection[];
|
|
153
|
+
segments: SegmentProjection[];
|
|
154
|
+
chord: string;
|
|
155
|
+
hasChord: boolean;
|
|
156
|
+
primary: PrimaryProjection[];
|
|
157
|
+
presenceVisible: boolean;
|
|
158
|
+
presence: PresenceProjection;
|
|
159
|
+
docks: DockProjection[];
|
|
160
|
+
run: (id: string) => void;
|
|
161
|
+
openSegment: (key: SegmentProjection["key"]) => void;
|
|
162
|
+
openPicker: () => void;
|
|
163
|
+
setLayout: (id: string) => void;
|
|
164
|
+
renameLayout: (id: string) => void;
|
|
165
|
+
saveLayout: () => void;
|
|
166
|
+
openStudioMenu: (opener: HTMLElement) => void;
|
|
167
|
+
windowControl: (action: keyof WindowControls) => void;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** What the presence cluster holds while there is nothing to say — the `$switch` hides it. */
|
|
171
|
+
const NO_PRESENCE: PresenceProjection = {
|
|
172
|
+
frozen: false,
|
|
173
|
+
label: "",
|
|
174
|
+
peers: [],
|
|
175
|
+
readOnly: false,
|
|
176
|
+
status: "unavailable",
|
|
177
|
+
title: "",
|
|
105
178
|
};
|
|
106
179
|
|
|
107
|
-
|
|
180
|
+
/* The window, with THIS dock's rail marked — one shipped glyph per side.
|
|
108
181
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
182
|
+
The pair these replace was `rail-right-open`/`close` under `scaleX(-1)`, because the left-hand
|
|
183
|
+
pair looked absent. Spectrum's two right-hand glyphs were exact mirror images OF EACH OTHER, so
|
|
184
|
+
flipping the wrong member of the pair landed on the other member's appearance — a real, crisp
|
|
185
|
+
arrow pointing the wrong way, looking entirely deliberate. It shipped crossed and nothing could
|
|
186
|
+
see it. Here the glyph is one shape and `mirror` is one boolean, asserted by name.
|
|
187
|
+
|
|
188
|
+
State stays where it already was and where it is already asserted: `selected` on the button. */
|
|
189
|
+
const DOCKS = [
|
|
190
|
+
{ dock: "left", icon: "sidebar-simple", id: "view.toggleNavigator", mirror: false },
|
|
191
|
+
{ dock: "right", icon: "sidebar-simple", id: "view.toggleInspector", mirror: true },
|
|
192
|
+
{ dock: "bottom", icon: "rows", id: "view.toggleBottomDock", mirror: false },
|
|
193
|
+
] as const;
|
|
194
|
+
|
|
195
|
+
/** The palette mode each segment of the address opens. */
|
|
196
|
+
const SEGMENT_MODES = { document: "files", project: "projects", selection: "nodes" } as const;
|
|
197
|
+
|
|
198
|
+
let _rootEl: HTMLElement | null = null;
|
|
199
|
+
let _scope: EffectScope | null = null;
|
|
200
|
+
let _state: CommandBarScope | null = null;
|
|
201
|
+
let _mount: Promise<SurfaceHandle> | null = null;
|
|
202
|
+
let _handle: SurfaceHandle | null = null;
|
|
203
|
+
let _menu: MenuHandle | null = null;
|
|
118
204
|
|
|
119
205
|
/**
|
|
120
206
|
* The tooltip a control shows: the action's name, plus its chord, or plus WHY it is off.
|
|
@@ -136,38 +222,6 @@ export function commandTooltip(registry: CommandRegistry, id: string): string {
|
|
|
136
222
|
return chord ? `${command.title} (${chord})` : command.title;
|
|
137
223
|
}
|
|
138
224
|
|
|
139
|
-
/**
|
|
140
|
-
* Render one command as a Command Bar button, or `nothing` when its `when` hides it.
|
|
141
|
-
*
|
|
142
|
-
* This is the whole of §5.5's first row: label, icon, tooltip, chord, disabled state and disabled
|
|
143
|
-
* reason all come off the record, so the bar cannot disagree with the palette, the keymap or the
|
|
144
|
-
* agent about any of them.
|
|
145
|
-
*/
|
|
146
|
-
export function tbCmd(registry: CommandRegistry, id: string, options: TbCmdOptions = {}) {
|
|
147
|
-
const command = registry.get(id);
|
|
148
|
-
if (!command || !registry.isVisible(id)) {
|
|
149
|
-
return nothing;
|
|
150
|
-
}
|
|
151
|
-
const enabled = registry.isEnabled(id);
|
|
152
|
-
const icon = options.icon ?? (command.icon ? COMMAND_ICONS[command.icon] : undefined);
|
|
153
|
-
return html`
|
|
154
|
-
<sp-action-button
|
|
155
|
-
size="s"
|
|
156
|
-
?quiet=${options.compact === true}
|
|
157
|
-
?selected=${options.selected === true}
|
|
158
|
-
title=${commandTooltip(registry, id)}
|
|
159
|
-
aria-label=${command.title}
|
|
160
|
-
?disabled=${!enabled}
|
|
161
|
-
@click=${() => {
|
|
162
|
-
void registry.run(id);
|
|
163
|
-
}}
|
|
164
|
-
>
|
|
165
|
-
${icon ?? nothing}
|
|
166
|
-
${options.compact ? nothing : html`<span class="tb-label">${command.title}</span>`}
|
|
167
|
-
</sp-action-button>
|
|
168
|
-
`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
225
|
// ─── View: Open in Browser ───────────────────────────────────────────────────
|
|
172
226
|
|
|
173
227
|
/**
|
|
@@ -430,16 +484,6 @@ function errorText(error: unknown): string {
|
|
|
430
484
|
return error instanceof Error ? error.message : String(error);
|
|
431
485
|
}
|
|
432
486
|
|
|
433
|
-
// ─── ①a The Command Center pill ──────────────────────────────────────────────
|
|
434
|
-
|
|
435
|
-
/** One segment of the address, and the palette mode it opens. */
|
|
436
|
-
interface PillSegment {
|
|
437
|
-
key: string;
|
|
438
|
-
label: string;
|
|
439
|
-
title: string;
|
|
440
|
-
onClick: () => void;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
487
|
/** The document's label: its path without the project root, which is already segment one. */
|
|
444
488
|
export function documentSegmentLabel(tab: Tab | null): string {
|
|
445
489
|
const path = tab?.documentPath;
|
|
@@ -469,124 +513,6 @@ export function selectionSegmentLabel(tab: Tab | null): string {
|
|
|
469
513
|
return nodeLabel(getNodeAtPath(tab.doc.document, selection));
|
|
470
514
|
}
|
|
471
515
|
|
|
472
|
-
/**
|
|
473
|
-
* `◈ project › document › selection`, right-aligned ⌘K.
|
|
474
|
-
*
|
|
475
|
-
* Four facts about where you are, in non-collapsible chrome (§4.4), each one click-through to the
|
|
476
|
-
* surface that owns it. The empty space between the segments opens the mode picker, which is what
|
|
477
|
-
* makes the pill an address bar rather than three buttons.
|
|
478
|
-
*/
|
|
479
|
-
function commandCenterTpl(registry: CommandRegistry | null) {
|
|
480
|
-
const tab = activeTab.value ?? null;
|
|
481
|
-
const chord = registry?.keymap.formatBinding("palette.open") ?? "";
|
|
482
|
-
const selection = selectionSegmentLabel(tab);
|
|
483
|
-
const segments: PillSegment[] = [
|
|
484
|
-
{
|
|
485
|
-
key: "project",
|
|
486
|
-
label: projectState?.name ?? "No project",
|
|
487
|
-
title: "Switch project — opens Project: Open Recent…",
|
|
488
|
-
onClick: () => openQuickSearch("projects"),
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
key: "document",
|
|
492
|
-
label: documentSegmentLabel(tab),
|
|
493
|
-
title: "Go to a file",
|
|
494
|
-
onClick: () => openQuickSearch("files"),
|
|
495
|
-
},
|
|
496
|
-
];
|
|
497
|
-
if (selection) {
|
|
498
|
-
segments.push({
|
|
499
|
-
key: "selection",
|
|
500
|
-
label: selection,
|
|
501
|
-
title: "Go to an element in this document",
|
|
502
|
-
onClick: () => openQuickSearch("nodes"),
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
return html`
|
|
506
|
-
<div
|
|
507
|
-
class="tb-center"
|
|
508
|
-
role="group"
|
|
509
|
-
aria-label="Command Center"
|
|
510
|
-
@click=${() => openQuickSearch("picker")}
|
|
511
|
-
>
|
|
512
|
-
<span class="tb-center-mark" aria-hidden="true">◈</span>
|
|
513
|
-
${segments.map(
|
|
514
|
-
(segment, index) => html`
|
|
515
|
-
${index > 0 ? html`<span class="tb-center-sep" aria-hidden="true">›</span>` : nothing}
|
|
516
|
-
<button
|
|
517
|
-
class="tb-center-seg"
|
|
518
|
-
type="button"
|
|
519
|
-
title=${segment.title}
|
|
520
|
-
@click=${(e: Event) => {
|
|
521
|
-
e.stopPropagation();
|
|
522
|
-
segment.onClick();
|
|
523
|
-
}}
|
|
524
|
-
>
|
|
525
|
-
${segment.label}
|
|
526
|
-
</button>
|
|
527
|
-
`,
|
|
528
|
-
)}
|
|
529
|
-
${chord ? html`<kbd class="tb-center-chord">${chord}</kbd>` : nothing}
|
|
530
|
-
</div>
|
|
531
|
-
`;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// ─── ①b Layout tabs ──────────────────────────────────────────────────────────
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* `Write · Design · Build · Ship · +` — named arrangements, as plain-text tabs.
|
|
538
|
-
*
|
|
539
|
-
* The 80% of a workspace switcher that costs a segmented control and none of the re-architecture
|
|
540
|
-
* (§3.2 ①b). Each tab RUNS `view.setLayout`, so the click, the palette row and an agent all take
|
|
541
|
-
* the same path; double-clicking one renames it, and `+` saves whatever is on screen now.
|
|
542
|
-
*
|
|
543
|
-
* **A layout reconfigures; it never removes.** Nothing here hides a panel: every one stays on the
|
|
544
|
-
* rail, on its chord and in the palette after any layout is applied — §13 is explicit that
|
|
545
|
-
* workspaces which gate features hand the non-technical user the affordance they are least likely
|
|
546
|
-
* to reach for.
|
|
547
|
-
*/
|
|
548
|
-
function layoutTabsTpl(registry: CommandRegistry) {
|
|
549
|
-
// `get` first, like {@link tbCmd}: a registry that has not been handed the shell's records yet
|
|
550
|
-
// (the skeleton the bar paints before the bootstrap composes them) has no verb to ask about.
|
|
551
|
-
if (!registry.get("view.setLayout") || !registry.isEnabled("view.setLayout")) {
|
|
552
|
-
return nothing;
|
|
553
|
-
}
|
|
554
|
-
return html`
|
|
555
|
-
<div class="tb-layouts" role="tablist" aria-label="Layouts">
|
|
556
|
-
${shell.layouts.map(
|
|
557
|
-
(preset) => html`
|
|
558
|
-
<button
|
|
559
|
-
class=${preset.id === shell.layout ? "tb-layout active" : "tb-layout"}
|
|
560
|
-
type="button"
|
|
561
|
-
role="tab"
|
|
562
|
-
aria-selected=${preset.id === shell.layout ? "true" : "false"}
|
|
563
|
-
title=${`${preset.name} layout — double-click to rename`}
|
|
564
|
-
@click=${() => {
|
|
565
|
-
void registry.run("view.setLayout", { layout: preset.id });
|
|
566
|
-
}}
|
|
567
|
-
@dblclick=${() => {
|
|
568
|
-
void renameLayoutPrompt(registry, preset.id, preset.name);
|
|
569
|
-
}}
|
|
570
|
-
>
|
|
571
|
-
${preset.name}
|
|
572
|
-
</button>
|
|
573
|
-
`,
|
|
574
|
-
)}
|
|
575
|
-
<button
|
|
576
|
-
class="tb-layout-add"
|
|
577
|
-
type="button"
|
|
578
|
-
title="Save the current arrangement as a layout"
|
|
579
|
-
aria-label="Save layout"
|
|
580
|
-
@click=${() => {
|
|
581
|
-
void saveLayoutPrompt(registry);
|
|
582
|
-
}}
|
|
583
|
-
>
|
|
584
|
-
+
|
|
585
|
-
</button>
|
|
586
|
-
</div>
|
|
587
|
-
`;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
516
|
/** Ask for a name, then run the command. Exported for the same reason `runOpenInBrowser` is. */
|
|
591
517
|
export async function saveLayoutPrompt(registry: CommandRegistry): Promise<void> {
|
|
592
518
|
const name = await showPromptDialog("Save layout", {
|
|
@@ -611,50 +537,6 @@ export async function renameLayoutPrompt(
|
|
|
611
537
|
}
|
|
612
538
|
}
|
|
613
539
|
|
|
614
|
-
// ─── The ⬢ app menu (commandbar/overflow) ────────────────────────────────────
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* Everything that declared `commandbar/overflow` — the chrome's residue for retired controls.
|
|
618
|
-
*
|
|
619
|
-
* Rendered as a menu of the records themselves, so a command that moves from the primary cluster to
|
|
620
|
-
* the overflow keeps its name, its chord and its gate, and the move is one edit to its `menus`.
|
|
621
|
-
*/
|
|
622
|
-
function appMenuTpl(registry: CommandRegistry) {
|
|
623
|
-
const commands = registry.forPlacement("commandbar/overflow");
|
|
624
|
-
return html`
|
|
625
|
-
<overlay-trigger placement="bottom-start" triggered-by="click">
|
|
626
|
-
<sp-action-button size="s" quiet slot="trigger" title="Studio menu" aria-label="Studio menu">
|
|
627
|
-
<sp-icon-show-menu slot="icon"></sp-icon-show-menu>
|
|
628
|
-
</sp-action-button>
|
|
629
|
-
<sp-popover slot="click-content" tip>
|
|
630
|
-
<sp-menu
|
|
631
|
-
@change=${(e: Event) => {
|
|
632
|
-
const id = (e.target as unknown as HTMLInputElement).value;
|
|
633
|
-
if (registry.isEnabled(id)) {
|
|
634
|
-
void registry.run(id);
|
|
635
|
-
}
|
|
636
|
-
}}
|
|
637
|
-
>
|
|
638
|
-
${commands.map(
|
|
639
|
-
(command) => html`
|
|
640
|
-
<sp-menu-item
|
|
641
|
-
value=${command.id}
|
|
642
|
-
?disabled=${!registry.isEnabled(command.id)}
|
|
643
|
-
title=${commandTooltip(registry, command.id)}
|
|
644
|
-
>
|
|
645
|
-
${command.title}
|
|
646
|
-
<span slot="value">${registry.keymap.formatBinding(command.id) ?? ""}</span>
|
|
647
|
-
</sp-menu-item>
|
|
648
|
-
`,
|
|
649
|
-
)}
|
|
650
|
-
</sp-menu>
|
|
651
|
-
</sp-popover>
|
|
652
|
-
</overlay-trigger>
|
|
653
|
-
`;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// ─── Window controls ──────────────────────────────────────────────────────────
|
|
657
|
-
|
|
658
540
|
interface WindowControls {
|
|
659
541
|
minimize: () => void;
|
|
660
542
|
maximize: () => void;
|
|
@@ -666,97 +548,254 @@ function windowControls(): WindowControls | undefined {
|
|
|
666
548
|
.__jxPlatform?.windowControls;
|
|
667
549
|
}
|
|
668
550
|
|
|
669
|
-
|
|
670
|
-
function csdTpl(controls: WindowControls, mac: boolean) {
|
|
671
|
-
const minimize = html`
|
|
672
|
-
<sp-action-button
|
|
673
|
-
quiet
|
|
674
|
-
size="s"
|
|
675
|
-
title="Minimize"
|
|
676
|
-
class="csd-minimize"
|
|
677
|
-
@click=${() => controls.minimize()}
|
|
678
|
-
>
|
|
679
|
-
<sp-icon-remove slot="icon"></sp-icon-remove>
|
|
680
|
-
</sp-action-button>
|
|
681
|
-
`;
|
|
682
|
-
const maximize = html`
|
|
683
|
-
<sp-action-button
|
|
684
|
-
quiet
|
|
685
|
-
size="s"
|
|
686
|
-
title="Maximize"
|
|
687
|
-
class="csd-maximize"
|
|
688
|
-
@click=${() => controls.maximize()}
|
|
689
|
-
>
|
|
690
|
-
<sp-icon-rectangle slot="icon"></sp-icon-rectangle>
|
|
691
|
-
</sp-action-button>
|
|
692
|
-
`;
|
|
693
|
-
const close = html`
|
|
694
|
-
<sp-action-button
|
|
695
|
-
quiet
|
|
696
|
-
size="s"
|
|
697
|
-
title="Close"
|
|
698
|
-
class="csd-close"
|
|
699
|
-
@click=${() => controls.close()}
|
|
700
|
-
>
|
|
701
|
-
<sp-icon-close slot="icon"></sp-icon-close>
|
|
702
|
-
</sp-action-button>
|
|
703
|
-
`;
|
|
704
|
-
return mac
|
|
705
|
-
? html`<sp-action-group class="window-controls mac" size="s">
|
|
706
|
-
${close}${minimize}${maximize}
|
|
707
|
-
</sp-action-group>`
|
|
708
|
-
: html`<sp-action-group class="window-controls" size="s">
|
|
709
|
-
${minimize}${maximize}${close}
|
|
710
|
-
</sp-action-group>`;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
// ─── The three dock toggles ───────────────────────────────────────────────────
|
|
714
|
-
|
|
715
|
-
/* The window, with THIS dock's rail marked — one shipped glyph per region.
|
|
551
|
+
// ─── The Command Center pill, the layout tabs and the docks, projected ───────
|
|
716
552
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
553
|
+
/**
|
|
554
|
+
* `◈ project › document › selection`: four facts about where you are, in non-collapsible chrome
|
|
555
|
+
* (§4.4).
|
|
556
|
+
*/
|
|
557
|
+
function projectSegments(tab: Tab | null): SegmentProjection[] {
|
|
558
|
+
const segments: SegmentProjection[] = [
|
|
559
|
+
{
|
|
560
|
+
key: "project",
|
|
561
|
+
label: projectState?.name ?? "No project",
|
|
562
|
+
sepBefore: false,
|
|
563
|
+
title: "Switch project — opens Project: Open Recent…",
|
|
564
|
+
},
|
|
565
|
+
{ key: "document", label: documentSegmentLabel(tab), sepBefore: true, title: "Go to a file" },
|
|
566
|
+
];
|
|
567
|
+
const selection = selectionSegmentLabel(tab);
|
|
568
|
+
if (selection) {
|
|
569
|
+
segments.push({
|
|
570
|
+
key: "selection",
|
|
571
|
+
label: selection,
|
|
572
|
+
sepBefore: true,
|
|
573
|
+
title: "Go to an element in this document",
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
return segments;
|
|
577
|
+
}
|
|
734
578
|
|
|
735
579
|
/**
|
|
736
|
-
*
|
|
580
|
+
* `Write · Design · Build · Ship · +` — named arrangements, as plain-text tabs.
|
|
737
581
|
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
582
|
+
* Each tab RUNS `view.setLayout`, so the click, the palette row and an agent all take the same
|
|
583
|
+
* path; double-clicking one renames it, and `+` saves whatever is on screen now. **A layout
|
|
584
|
+
* reconfigures; it never removes**: every panel stays on the rail, on its chord and in the palette
|
|
585
|
+
* after any layout is applied.
|
|
586
|
+
*/
|
|
587
|
+
function projectLayouts(registry: CommandRegistry | null): LayoutTabProjection[] {
|
|
588
|
+
// `get` first: a registry that has not been handed the shell's records yet (the skeleton the bar
|
|
589
|
+
// Paints before the bootstrap composes them) has no verb to ask about.
|
|
590
|
+
if (!registry?.get("view.setLayout") || !registry.isEnabled("view.setLayout")) {
|
|
591
|
+
return [];
|
|
592
|
+
}
|
|
593
|
+
return shell.layouts.map((preset) => ({
|
|
594
|
+
active: preset.id === shell.layout,
|
|
595
|
+
id: preset.id,
|
|
596
|
+
name: preset.name,
|
|
597
|
+
title: `${preset.name} layout — double-click to rename`,
|
|
598
|
+
}));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/** The primary verb cluster: exactly what declared `commandbar/primary`, in the registry's order. */
|
|
602
|
+
function projectPrimary(registry: CommandRegistry | null): PrimaryProjection[] {
|
|
603
|
+
if (!registry) {
|
|
604
|
+
return [];
|
|
605
|
+
}
|
|
606
|
+
return registry
|
|
607
|
+
.forPlacement("commandbar/primary")
|
|
608
|
+
.filter((command) => registry.isVisible(command.id))
|
|
609
|
+
.map((command) => ({
|
|
610
|
+
disabled: !registry.isEnabled(command.id),
|
|
611
|
+
hasIcon: Boolean(command.icon),
|
|
612
|
+
icon: command.icon ?? "",
|
|
613
|
+
id: command.id,
|
|
614
|
+
title: command.title,
|
|
615
|
+
tooltip: commandTooltip(registry, command.id),
|
|
616
|
+
}));
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* ▤▥▦ — the three docks, each projected from its own record.
|
|
621
|
+
*
|
|
622
|
+
* The glyph names the region and `selected` reports its state, so the control says which way it
|
|
623
|
+
* will go; the NAME and the chord still come from the record, which is why ⌘B and this button
|
|
740
624
|
* cannot drift apart the way ⌘W and the tab strip's × did.
|
|
741
625
|
*/
|
|
742
|
-
function
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
626
|
+
function projectDocks(registry: CommandRegistry | null): DockProjection[] {
|
|
627
|
+
if (!registry) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
return DOCKS.flatMap((dock) => {
|
|
631
|
+
const command = registry.get(dock.id);
|
|
632
|
+
if (!command || !registry.isVisible(dock.id)) {
|
|
633
|
+
return [];
|
|
634
|
+
}
|
|
635
|
+
return [
|
|
636
|
+
{
|
|
637
|
+
disabled: !registry.isEnabled(dock.id),
|
|
638
|
+
icon: dock.icon,
|
|
639
|
+
id: dock.id,
|
|
640
|
+
mirror: dock.mirror,
|
|
641
|
+
selected: !shell.docks[dock.dock].collapsed,
|
|
642
|
+
title: command.title,
|
|
643
|
+
tooltip: commandTooltip(registry, dock.id),
|
|
644
|
+
},
|
|
645
|
+
];
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// ─── The ⬢ Studio menu (commandbar/overflow) ─────────────────────────────────
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Everything that declared `commandbar/overflow` — the chrome's residue for retired controls —
|
|
653
|
+
* projected as rows for the `menu` surface, so a command that moves from the primary cluster to the
|
|
654
|
+
* overflow keeps its name, its chord and its gate, and the move is one edit to its `menus`.
|
|
655
|
+
*/
|
|
656
|
+
function overflowRows(registry: CommandRegistry): MenuRowProjection[] {
|
|
657
|
+
let group: string | undefined;
|
|
658
|
+
return registry.forPlacement("commandbar/overflow").map((command, index) => {
|
|
659
|
+
const dividerAbove = index > 0 && command.group !== group;
|
|
660
|
+
({ group } = command);
|
|
661
|
+
const enabled = registry.isEnabled(command.id);
|
|
662
|
+
const chord = registry.keymap.formatBinding(command.id);
|
|
663
|
+
const reason = enabled ? undefined : registry.disabledReason(command.id);
|
|
664
|
+
const row: MenuRowProjection = {
|
|
665
|
+
destructive: command.destructive === true,
|
|
666
|
+
disabled: !enabled,
|
|
667
|
+
dividerAbove,
|
|
668
|
+
id: command.id,
|
|
669
|
+
title: command.title,
|
|
670
|
+
};
|
|
671
|
+
if (chord) {
|
|
672
|
+
row.chord = chord;
|
|
673
|
+
}
|
|
674
|
+
if (reason) {
|
|
675
|
+
row.requires = reason;
|
|
676
|
+
}
|
|
677
|
+
return row;
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/** Open the Studio menu under its button, or close the one that is up: the button is a toggle. */
|
|
682
|
+
function openStudioMenu(opener: HTMLElement): void {
|
|
683
|
+
if (_menu) {
|
|
684
|
+
_menu.close();
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const registry = activeRegistry();
|
|
688
|
+
if (!registry) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const scope = state();
|
|
692
|
+
const handle = openMenu({
|
|
693
|
+
label: "Studio menu",
|
|
694
|
+
onClosed: (closed) => {
|
|
695
|
+
if (_menu !== closed) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
_menu = null;
|
|
699
|
+
scope.menuOpen = false;
|
|
700
|
+
},
|
|
701
|
+
opener,
|
|
702
|
+
place: () => {
|
|
703
|
+
const box = rectOf(opener);
|
|
704
|
+
return { x: box.left, y: box.bottom + 4 };
|
|
705
|
+
},
|
|
706
|
+
region: "studio",
|
|
707
|
+
rows: overflowRows(registry),
|
|
708
|
+
run: (id) => {
|
|
709
|
+
if (registry.isEnabled(id)) {
|
|
710
|
+
void registry.run(id);
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
_menu = handle;
|
|
715
|
+
scope.menuOpen = true;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// ─── The scope ────────────────────────────────────────────────────────────────
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* The one reactive scope the document is mounted over: rebuilt on mount, re-projected by the
|
|
722
|
+
* effect.
|
|
723
|
+
*/
|
|
724
|
+
function state(): CommandBarScope {
|
|
725
|
+
_state ??= reactive<CommandBarScope>({
|
|
726
|
+
chord: "",
|
|
727
|
+
csd: "none",
|
|
728
|
+
docks: [],
|
|
729
|
+
hasChord: false,
|
|
730
|
+
layouts: [],
|
|
731
|
+
layoutsVisible: false,
|
|
732
|
+
menuOpen: false,
|
|
733
|
+
menuVisible: false,
|
|
734
|
+
openPicker: () => {
|
|
735
|
+
openQuickSearch("picker");
|
|
736
|
+
},
|
|
737
|
+
openSegment: (key) => {
|
|
738
|
+
openQuickSearch(SEGMENT_MODES[key]);
|
|
739
|
+
},
|
|
740
|
+
openStudioMenu,
|
|
741
|
+
presence: NO_PRESENCE,
|
|
742
|
+
presenceVisible: false,
|
|
743
|
+
primary: [],
|
|
744
|
+
renameLayout: (id) => {
|
|
745
|
+
const registry = activeRegistry();
|
|
746
|
+
const preset = shell.layouts.find((layout) => layout.id === id);
|
|
747
|
+
if (registry && preset) {
|
|
748
|
+
void renameLayoutPrompt(registry, id, preset.name);
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
run: (id) => {
|
|
752
|
+
const registry = activeRegistry();
|
|
753
|
+
if (registry?.isEnabled(id)) {
|
|
754
|
+
void registry.run(id);
|
|
755
|
+
}
|
|
756
|
+
},
|
|
757
|
+
saveLayout: () => {
|
|
758
|
+
const registry = activeRegistry();
|
|
759
|
+
if (registry) {
|
|
760
|
+
void saveLayoutPrompt(registry);
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
segments: [],
|
|
764
|
+
setLayout: (id) => {
|
|
765
|
+
void activeRegistry()?.run("view.setLayout", { layout: id });
|
|
766
|
+
},
|
|
767
|
+
windowControl: (action) => {
|
|
768
|
+
windowControls()?.[action]();
|
|
769
|
+
},
|
|
770
|
+
}) as CommandBarScope;
|
|
771
|
+
return _state;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Re-project the registry, the shell and the tab onto the scope. Every write is keyed, so the DOM
|
|
776
|
+
* reconciles in place.
|
|
777
|
+
*/
|
|
778
|
+
function project(): void {
|
|
779
|
+
const scope = state();
|
|
780
|
+
const registry = activeRegistry();
|
|
781
|
+
const tab = activeTab.value ?? null;
|
|
782
|
+
const controls = windowControls();
|
|
783
|
+
scope.csd = controls ? (isMacPlatform() ? "mac" : "other") : "none";
|
|
784
|
+
scope.menuVisible = registry !== null;
|
|
785
|
+
scope.layouts = projectLayouts(registry);
|
|
786
|
+
scope.layoutsVisible = scope.layouts.length > 0;
|
|
787
|
+
scope.segments = projectSegments(tab);
|
|
788
|
+
scope.chord = registry?.keymap.formatBinding("palette.open") ?? "";
|
|
789
|
+
scope.hasChord = scope.chord !== "";
|
|
790
|
+
scope.primary = projectPrimary(registry);
|
|
791
|
+
const presence = presenceProjection(tab);
|
|
792
|
+
// The object before the flag, so the case that reads it never renders against the empty one.
|
|
793
|
+
scope.presence = presence ?? NO_PRESENCE;
|
|
794
|
+
scope.presenceVisible = presence !== null;
|
|
795
|
+
scope.docks = projectDocks(registry);
|
|
796
|
+
if (_menu && registry) {
|
|
797
|
+
_menu.setRows(overflowRows(registry));
|
|
798
|
+
}
|
|
760
799
|
}
|
|
761
800
|
|
|
762
801
|
// ─── Mount ────────────────────────────────────────────────────────────────────
|
|
@@ -767,7 +806,8 @@ function dockTogglesTpl(registry: CommandRegistry) {
|
|
|
767
806
|
* @param rootEl The `#toolbar` host, stamped `commandbar` by the frame (`shell/tree.ts`).
|
|
768
807
|
* @param _ctx Ignored — see {@link ToolbarCtx}.
|
|
769
808
|
*/
|
|
770
|
-
export function mount(rootEl: HTMLElement, _ctx: ToolbarCtx = {}) {
|
|
809
|
+
export function mount(rootEl: HTMLElement, _ctx: ToolbarCtx = {}): void {
|
|
810
|
+
unmount();
|
|
771
811
|
_rootEl = rootEl;
|
|
772
812
|
if (windowControls()) {
|
|
773
813
|
rootEl.classList.add("electrobun-webkit-app-region-drag");
|
|
@@ -777,14 +817,14 @@ export function mount(rootEl: HTMLElement, _ctx: ToolbarCtx = {}) {
|
|
|
777
817
|
effect(() => {
|
|
778
818
|
// Dock visibility, source control and the project are shell state, tracked here so the band
|
|
779
819
|
// Follows a flip made from anywhere — the automation runner, the New Project agent hand-off,
|
|
780
|
-
// The boot-time restore — not just this
|
|
820
|
+
// The boot-time restore — not just this document's handlers.
|
|
781
821
|
void shell.docks.left.collapsed;
|
|
782
822
|
void shell.docks.right.collapsed;
|
|
783
823
|
void shell.docks.bottom.collapsed;
|
|
784
824
|
void shell.git.status;
|
|
785
825
|
void shell.layoutSelection;
|
|
786
|
-
// The layout tabs are a rendering of the project's own record
|
|
787
|
-
//
|
|
826
|
+
// The layout tabs are a rendering of the project's own record, so the band repaints when a
|
|
827
|
+
// Layout is saved, renamed or deleted from anywhere.
|
|
788
828
|
void shell.layout;
|
|
789
829
|
void shell.layouts;
|
|
790
830
|
// The registry itself is reactive state: it is composed AFTER this mount runs, and reading it
|
|
@@ -804,56 +844,41 @@ export function mount(rootEl: HTMLElement, _ctx: ToolbarCtx = {}) {
|
|
|
804
844
|
void tab.history.index;
|
|
805
845
|
void tab.history.snapshots.length;
|
|
806
846
|
}
|
|
807
|
-
|
|
847
|
+
try {
|
|
848
|
+
project();
|
|
849
|
+
} catch (error) {
|
|
850
|
+
console.error("command bar projection error:", error);
|
|
851
|
+
}
|
|
808
852
|
});
|
|
809
853
|
});
|
|
854
|
+
_mount = mountSurface("commandbar", state(), rootEl);
|
|
855
|
+
void _mount.then((handle) => {
|
|
856
|
+
_handle = handle;
|
|
857
|
+
});
|
|
810
858
|
}
|
|
811
859
|
|
|
812
|
-
export function unmount() {
|
|
860
|
+
export function unmount(): void {
|
|
861
|
+
_menu?.close();
|
|
813
862
|
_scope?.stop();
|
|
814
863
|
_scope = null;
|
|
864
|
+
const pending = _mount;
|
|
865
|
+
_mount = null;
|
|
866
|
+
if (_handle) {
|
|
867
|
+
_handle.dispose();
|
|
868
|
+
_handle = null;
|
|
869
|
+
} else if (pending) {
|
|
870
|
+
void pending.then((handle) => handle.dispose());
|
|
871
|
+
}
|
|
872
|
+
_state = null;
|
|
815
873
|
_rootEl = null;
|
|
816
874
|
}
|
|
817
875
|
|
|
818
|
-
export function render() {
|
|
819
|
-
if (!_rootEl) {
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
try {
|
|
823
|
-
litRender(toolbarTemplate(), _rootEl);
|
|
824
|
-
} catch (error) {
|
|
825
|
-
console.error("toolbar render error:", error);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
876
|
/**
|
|
830
|
-
* The
|
|
831
|
-
*
|
|
832
|
-
* ONE template for every state. With no project open the records' `when` clauses empty the primary
|
|
833
|
-
* cluster and the pill reads "No project"; there is no second variant to keep in step.
|
|
877
|
+
* Re-project now. The effect does this on its own; the bootstrap calls it after a store it does not
|
|
878
|
+
* track hydrates.
|
|
834
879
|
*/
|
|
835
|
-
function
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const csd = controls ? csdTpl(controls, mac) : nothing;
|
|
840
|
-
const tab = activeTab.value ?? null;
|
|
841
|
-
return html`
|
|
842
|
-
${mac ? csd : nothing} ${registry ? appMenuTpl(registry) : nothing}
|
|
843
|
-
${registry ? layoutTabsTpl(registry) : nothing}
|
|
844
|
-
<div class="tb-spacer"></div>
|
|
845
|
-
${commandCenterTpl(registry)}
|
|
846
|
-
<div class="tb-spacer"></div>
|
|
847
|
-
${
|
|
848
|
-
registry
|
|
849
|
-
? html`<sp-action-group compact size="s">
|
|
850
|
-
${registry
|
|
851
|
-
.forPlacement("commandbar/primary")
|
|
852
|
-
.map((command) => tbCmd(registry, command.id))}
|
|
853
|
-
</sp-action-group>`
|
|
854
|
-
: nothing
|
|
855
|
-
}
|
|
856
|
-
${tab ? presenceChipsTemplate(tab) : nothing} ${registry ? dockTogglesTpl(registry) : nothing}
|
|
857
|
-
${mac ? nothing : csd}
|
|
858
|
-
`;
|
|
880
|
+
export function render(): void {
|
|
881
|
+
if (_rootEl) {
|
|
882
|
+
project();
|
|
883
|
+
}
|
|
859
884
|
}
|