@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,620 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* Preferences-dialog.ts — ⌘, the application-preferences surface Studio did not have.
|
|
4
|
+
*
|
|
5
|
+
* Plan §9.3 draws the line this file finally makes real. **Project Settings** configures a project
|
|
6
|
+
* and belongs to the project (breakpoints, definitions, deploy); **Preferences** configures the
|
|
7
|
+
* application and follows you between them. Studio shipped only the first, behind a gear in the
|
|
8
|
+
* rail — the slot every other editor spends on the second — and so had nowhere at all to put the
|
|
9
|
+
* chrome theme, the assistant's provider key, the keyboard, or the three credentials it holds.
|
|
10
|
+
*
|
|
11
|
+
* Four sections, and each one closes a hole that was named in the plan:
|
|
12
|
+
*
|
|
13
|
+
* - **Appearance** — the chrome theme. `shell.theme` and `view.setTheme` already existed; nothing
|
|
14
|
+
* rendered them, so the only way to change the theme was to run a command by hand.
|
|
15
|
+
* - **Assistant** — the provider key. It used to live in `Assistant: Settings…`, a dialog reachable
|
|
16
|
+
* only from inside the assistant panel, which meant a key had to be configured from the surface
|
|
17
|
+
* that was broken for want of one. That dialog is deleted; this is where it went.
|
|
18
|
+
* - **Accounts** — GitHub, the AI provider and Cloudflare, listed with a Disconnect each. Before
|
|
19
|
+
* this, `clearGithubToken()` had zero callers: signing out of GitHub was not expressible.
|
|
20
|
+
* - **Keyboard** — GENERATED from `commands/reference.ts`'s `shortcutReference()`, the same
|
|
21
|
+
* projection `docs/studio/interface/shortcuts.md` is built from. The registry is the one place a
|
|
22
|
+
* chord is declared, so the sheet cannot drift from the app or from the docs. Per §13.5 there is
|
|
23
|
+
* deliberately no screenshot of it — photographing generated content is a bug. It is searchable
|
|
24
|
+
* two ways, because there are two questions ("what is the shortcut for X" and "what did I just
|
|
25
|
+
* press"), and rebindable — as a LAYER over the registry (`settings/preferences-keymap.ts`), so
|
|
26
|
+
* the sheet stays a projection and the app's own record of a default is never edited.
|
|
27
|
+
*
|
|
28
|
+
* Modality: an `sp-dialog-wrapper` through {@link showDialog}, which is focus-managed and dismissed
|
|
29
|
+
* by Escape — not `openModal`'s `inset:40px` blackout. Preferences does not suspend the app.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { html, nothing, render as litRender } from "lit-html";
|
|
33
|
+
import { ref } from "lit-html/directives/ref.js";
|
|
34
|
+
import { CHROME_THEMES, setChromeTheme, shell } from "../shell";
|
|
35
|
+
import { showDialog } from "../ui/layers";
|
|
36
|
+
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
37
|
+
import { createManagedConnect } from "../ui/ai-managed-connect";
|
|
38
|
+
import { activeRegistry } from "../commands/active-registry";
|
|
39
|
+
import { shortcutReference, SCOPE_LABELS } from "../commands/reference";
|
|
40
|
+
import { chordFromEvent } from "../commands/keymap";
|
|
41
|
+
import { listAccounts, notifyCredentialsChanged, revokeAccount } from "./preferences-accounts";
|
|
42
|
+
import { applyKeybindingOverrides, rebindCommand, resetKeybinding } from "./preferences-keymap";
|
|
43
|
+
import { overlayRegion } from "../ui/regions";
|
|
44
|
+
|
|
45
|
+
import type { TemplateResult } from "lit-html";
|
|
46
|
+
import type { ChromeTheme } from "../shell";
|
|
47
|
+
import type { ShortcutRow } from "../commands/reference";
|
|
48
|
+
import type { RebindResult } from "./preferences-keymap";
|
|
49
|
+
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
50
|
+
|
|
51
|
+
/** One section of the sheet. The `id` is what `app.preferences { section }` accepts. */
|
|
52
|
+
export interface PreferencesSection {
|
|
53
|
+
id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
/** The one-line answer to "what is in here", shown under the heading. */
|
|
56
|
+
blurb: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The sections, in sheet order.
|
|
61
|
+
*
|
|
62
|
+
* §9.3 lists six for the finished surface (Editor behaviour and Updates/About are the other two).
|
|
63
|
+
* Four are built; a section is added here when it has something to configure, never before — an
|
|
64
|
+
* empty pane is the "declared but unbuilt" state the rail already refuses to render.
|
|
65
|
+
*/
|
|
66
|
+
export const PREFERENCES_SECTIONS: readonly PreferencesSection[] = [
|
|
67
|
+
{ id: "appearance", title: "Appearance", blurb: "How the Studio chrome looks." },
|
|
68
|
+
{
|
|
69
|
+
id: "assistant",
|
|
70
|
+
title: "Assistant",
|
|
71
|
+
blurb: "The AI provider the assistant talks to. Stored on this machine.",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "accounts",
|
|
75
|
+
title: "Accounts",
|
|
76
|
+
blurb: "Every credential Studio holds, and how to make it forget one.",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "keyboard",
|
|
80
|
+
title: "Keyboard",
|
|
81
|
+
blurb: "Generated from the command registry — the app's own record of every chord.",
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
/** The section the sheet opens on when none is named. */
|
|
86
|
+
export const DEFAULT_PREFERENCES_SECTION = PREFERENCES_SECTIONS[0]!.id;
|
|
87
|
+
|
|
88
|
+
/** Whether a string names a section. */
|
|
89
|
+
export function isPreferencesSection(id: unknown): boolean {
|
|
90
|
+
return PREFERENCES_SECTIONS.some((section) => section.id === id);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Open state ───────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
let _section = DEFAULT_PREFERENCES_SECTION;
|
|
96
|
+
|
|
97
|
+
/** Repaint the open sheet, if one is up. */
|
|
98
|
+
let _rerender: (() => void) | null = null;
|
|
99
|
+
|
|
100
|
+
/** Dismiss the open sheet, if one is up. */
|
|
101
|
+
let _close: (() => void) | null = null;
|
|
102
|
+
|
|
103
|
+
/** Whether Preferences is on screen. */
|
|
104
|
+
export function isPreferencesOpen(): boolean {
|
|
105
|
+
return _close !== null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** The section currently showing. Exposed for tests and for the `app.preferences` round-trip. */
|
|
109
|
+
export function preferencesSection(): string {
|
|
110
|
+
return _section;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function repaint(): void {
|
|
114
|
+
_rerender?.();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Save/revoke both change what other surfaces show, so they announce as well as repaint. */
|
|
118
|
+
function credentialsChanged(): void {
|
|
119
|
+
notifyCredentialsChanged();
|
|
120
|
+
repaint();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The shared credentials form — draft state lives inside the form's closure. */
|
|
124
|
+
const credsForm = createAiCredentialsForm({
|
|
125
|
+
intro: html`
|
|
126
|
+
Any OpenAI-compatible key works. Stored locally on this machine; sent only to the Studio proxy
|
|
127
|
+
(never to a third party except your chosen endpoint).
|
|
128
|
+
`,
|
|
129
|
+
// Both buttons keep the sheet open: Preferences is a place, not a wizard step, and the previous
|
|
130
|
+
// Dialog's habit of vanishing on Save is what made "did that take?" unanswerable.
|
|
131
|
+
onCancel: repaint,
|
|
132
|
+
onSaved: credentialsChanged,
|
|
133
|
+
requestRender: repaint,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
/** Shared with the New Project modal's gates — see ui/ai-managed-connect.ts. */
|
|
137
|
+
const managedConnect = createManagedConnect({ requestRender: credentialsChanged });
|
|
138
|
+
|
|
139
|
+
// ─── Sections ─────────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
function appearanceTpl(): TemplateResult {
|
|
142
|
+
return html`
|
|
143
|
+
<div class="prefs-field">
|
|
144
|
+
<span class="prefs-field-label">Theme</span>
|
|
145
|
+
<sp-action-group compact selects="single" size="s">
|
|
146
|
+
${CHROME_THEMES.map(
|
|
147
|
+
(theme) => html`
|
|
148
|
+
<sp-action-button
|
|
149
|
+
value=${theme}
|
|
150
|
+
?selected=${shell.theme === theme}
|
|
151
|
+
@click=${() => {
|
|
152
|
+
setChromeTheme(theme as ChromeTheme);
|
|
153
|
+
repaint();
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
${theme === "dark" ? "Dark" : "Light"}
|
|
157
|
+
</sp-action-button>
|
|
158
|
+
`,
|
|
159
|
+
)}
|
|
160
|
+
</sp-action-group>
|
|
161
|
+
</div>
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function assistantTpl(): TemplateResult {
|
|
166
|
+
managedConnect.ensureProbe();
|
|
167
|
+
return html`<div class="prefs-assistant">${managedConnect.render()} ${credsForm.render()}</div>`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function accountsTpl(): TemplateResult {
|
|
171
|
+
return html`
|
|
172
|
+
<div class="prefs-accounts">
|
|
173
|
+
${listAccounts().map(
|
|
174
|
+
(account) => html`
|
|
175
|
+
<div class="prefs-account" data-account=${account.id}>
|
|
176
|
+
<div class="prefs-account-text">
|
|
177
|
+
<span class="prefs-account-label">${account.label}</span>
|
|
178
|
+
<span class="prefs-account-detail">${account.detail}</span>
|
|
179
|
+
</div>
|
|
180
|
+
${
|
|
181
|
+
account.connected
|
|
182
|
+
? html`
|
|
183
|
+
<sp-button
|
|
184
|
+
size="s"
|
|
185
|
+
variant="negative"
|
|
186
|
+
treatment="outline"
|
|
187
|
+
@click=${() => {
|
|
188
|
+
revokeAccount(account.id);
|
|
189
|
+
repaint();
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
Disconnect
|
|
193
|
+
</sp-button>
|
|
194
|
+
`
|
|
195
|
+
: nothing
|
|
196
|
+
}
|
|
197
|
+
</div>
|
|
198
|
+
`,
|
|
199
|
+
)}
|
|
200
|
+
</div>
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ─── Keyboard ─────────────────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* What the sheet is showing, if not everything.
|
|
208
|
+
*
|
|
209
|
+
* Two kinds because there are two questions. `text` answers "what is the shortcut for Duplicate";
|
|
210
|
+
* `chord` answers "what did I just press", which is the one a list cannot answer by being read — a
|
|
211
|
+
* chord's printed form is not what a person searching for it would type.
|
|
212
|
+
*/
|
|
213
|
+
type KeyFilter = { kind: "text"; value: string } | { kind: "chord"; chord: string } | null;
|
|
214
|
+
|
|
215
|
+
/** The next chord goes to the search box, or onto a command. `null` while nothing is listening. */
|
|
216
|
+
type KeyCapture = { mode: "search" } | { mode: "rebind"; command: AnyCommand } | null;
|
|
217
|
+
|
|
218
|
+
/** Keydowns that are not a chord yet: a modifier held on its way to one. */
|
|
219
|
+
const MODIFIER_KEYS = new Set(["Meta", "Control", "Alt", "Shift", "CapsLock", "OS"]);
|
|
220
|
+
|
|
221
|
+
let _keyFilter: KeyFilter = null;
|
|
222
|
+
let _keyCapture: KeyCapture = null;
|
|
223
|
+
/** The last refusal, held until the author does something else. */
|
|
224
|
+
let _keyRefusal: (RebindResult & { ok: false }) | null = null;
|
|
225
|
+
|
|
226
|
+
/** Forget the Keyboard section's transient state. Opening the sheet should never resume a capture. */
|
|
227
|
+
function resetKeyboardState(): void {
|
|
228
|
+
_keyFilter = null;
|
|
229
|
+
_keyCapture = null;
|
|
230
|
+
_keyRefusal = null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Whether a row survives the current filter. `format` is injected so one platform decision holds. */
|
|
234
|
+
function keyRowMatches(row: ShortcutRow, format: (chord: string) => string): boolean {
|
|
235
|
+
if (!_keyFilter) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
if (_keyFilter.kind === "chord") {
|
|
239
|
+
return row.chord === _keyFilter.chord;
|
|
240
|
+
}
|
|
241
|
+
const query = _keyFilter.value.toLowerCase();
|
|
242
|
+
return (
|
|
243
|
+
row.title.toLowerCase().includes(query) ||
|
|
244
|
+
row.commandId.toLowerCase().includes(query) ||
|
|
245
|
+
format(row.chord).toLowerCase().includes(query)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* One keydown while the sheet is listening.
|
|
251
|
+
*
|
|
252
|
+
* `stopPropagation` is the load-bearing line: the dispatcher is a `document` listener and
|
|
253
|
+
* Preferences deliberately does not suspend the app (§15), so without it, capturing ⌘S would SAVE
|
|
254
|
+
* while the author was trying to bind it.
|
|
255
|
+
*/
|
|
256
|
+
function onKeyboardKeyDown(event: KeyboardEvent): void {
|
|
257
|
+
if (!_keyCapture || MODIFIER_KEYS.has(event.key)) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
event.preventDefault();
|
|
261
|
+
event.stopPropagation();
|
|
262
|
+
const capture = _keyCapture;
|
|
263
|
+
_keyCapture = null;
|
|
264
|
+
if (event.key === "Escape") {
|
|
265
|
+
_keyRefusal = null;
|
|
266
|
+
repaint();
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const registry = activeRegistry();
|
|
270
|
+
if (!registry) {
|
|
271
|
+
repaint();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const chord = chordFromEvent(event, registry.keymap.mac);
|
|
275
|
+
if (capture.mode === "search") {
|
|
276
|
+
_keyFilter = { kind: "chord", chord };
|
|
277
|
+
_keyRefusal = null;
|
|
278
|
+
} else {
|
|
279
|
+
const result = rebindCommand(registry, capture.command, chord);
|
|
280
|
+
_keyRefusal = result.ok ? null : result;
|
|
281
|
+
}
|
|
282
|
+
repaint();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** The refusal, and the one thing that can be done about it: go and look at the command holding it. */
|
|
286
|
+
function keyRefusalTpl(): TemplateResult | typeof nothing {
|
|
287
|
+
if (!_keyRefusal) {
|
|
288
|
+
return nothing;
|
|
289
|
+
}
|
|
290
|
+
const { conflict } = _keyRefusal;
|
|
291
|
+
return html`
|
|
292
|
+
<div class="prefs-field">
|
|
293
|
+
<sp-help-text variant="negative">${_keyRefusal.reason}</sp-help-text>
|
|
294
|
+
${
|
|
295
|
+
conflict
|
|
296
|
+
? html`
|
|
297
|
+
<sp-button
|
|
298
|
+
size="s"
|
|
299
|
+
treatment="outline"
|
|
300
|
+
@click=${() => {
|
|
301
|
+
_keyFilter = { kind: "text", value: conflict.title };
|
|
302
|
+
_keyRefusal = null;
|
|
303
|
+
repaint();
|
|
304
|
+
}}
|
|
305
|
+
>
|
|
306
|
+
Show ${conflict.title}
|
|
307
|
+
</sp-button>
|
|
308
|
+
`
|
|
309
|
+
: nothing
|
|
310
|
+
}
|
|
311
|
+
</div>
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* One binding.
|
|
317
|
+
*
|
|
318
|
+
* The record is passed in rather than looked up: the rows and the commands come from the same
|
|
319
|
+
* `registry.list()` call, so there is no window in which a row can name something the sheet cannot
|
|
320
|
+
* resolve, and no assertion pretending so.
|
|
321
|
+
*/
|
|
322
|
+
function keyRowTpl(
|
|
323
|
+
row: ShortcutRow,
|
|
324
|
+
command: AnyCommand,
|
|
325
|
+
registry: CommandRegistry,
|
|
326
|
+
): TemplateResult {
|
|
327
|
+
const capturing = _keyCapture?.mode === "rebind" && _keyCapture.command.id === row.commandId;
|
|
328
|
+
return html`
|
|
329
|
+
<div class="prefs-key" data-command=${row.commandId}>
|
|
330
|
+
<kbd class="prefs-key-chord">
|
|
331
|
+
${capturing ? "Press a shortcut…" : registry.keymap.format(row.chord)}
|
|
332
|
+
</kbd>
|
|
333
|
+
<span class="prefs-key-title">${row.title}${row.overridden ? " — changed" : ""}</span>
|
|
334
|
+
<sp-action-button
|
|
335
|
+
size="s"
|
|
336
|
+
quiet
|
|
337
|
+
?selected=${capturing}
|
|
338
|
+
aria-label=${capturing ? `Stop changing ${row.title}` : `Change the shortcut for ${row.title}`}
|
|
339
|
+
@click=${() => {
|
|
340
|
+
_keyCapture = capturing ? null : { mode: "rebind", command };
|
|
341
|
+
_keyRefusal = null;
|
|
342
|
+
repaint();
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
345
|
+
${capturing ? "Cancel" : "Change"}
|
|
346
|
+
</sp-action-button>
|
|
347
|
+
${
|
|
348
|
+
row.overridden
|
|
349
|
+
? html`
|
|
350
|
+
<sp-action-button
|
|
351
|
+
size="s"
|
|
352
|
+
quiet
|
|
353
|
+
aria-label=${`Reset the shortcut for ${row.title}`}
|
|
354
|
+
@click=${() => {
|
|
355
|
+
resetKeybinding(registry, row.commandId);
|
|
356
|
+
_keyRefusal = null;
|
|
357
|
+
repaint();
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
Reset
|
|
361
|
+
</sp-action-button>
|
|
362
|
+
`
|
|
363
|
+
: nothing
|
|
364
|
+
}
|
|
365
|
+
</div>
|
|
366
|
+
`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The keyboard sheet — every live binding, grouped by the scope it is live in.
|
|
371
|
+
*
|
|
372
|
+
* The rows come from the running registry through `shortcutReference`, so a command registered by
|
|
373
|
+
* an extension appears here without this file knowing it exists, and the user's layer is passed to
|
|
374
|
+
* the same projection rather than patched into its output.
|
|
375
|
+
*
|
|
376
|
+
* A command that declares two chords has two rows and rebinding either one leaves it with one — a
|
|
377
|
+
* user who asked for ⌥⌘Y is not also asking to keep ⌘Y, and Reset brings both back.
|
|
378
|
+
*/
|
|
379
|
+
function keyboardTpl(): TemplateResult {
|
|
380
|
+
const registry = activeRegistry();
|
|
381
|
+
const commands: readonly AnyCommand[] = registry ? [...registry.list()] : [];
|
|
382
|
+
const rows = registry ? shortcutReference(commands, registry.keymap.overrides()) : [];
|
|
383
|
+
if (!registry || rows.length === 0) {
|
|
384
|
+
return html`<p class="prefs-empty">No commands are registered in this window.</p>`;
|
|
385
|
+
}
|
|
386
|
+
const format = (chord: string) => registry.keymap.format(chord);
|
|
387
|
+
const byId = new Map(commands.map((command) => [command.id, command]));
|
|
388
|
+
const visible = rows.flatMap((row) => {
|
|
389
|
+
const command = byId.get(row.commandId);
|
|
390
|
+
return command && keyRowMatches(row, format) ? [{ command, row }] : [];
|
|
391
|
+
});
|
|
392
|
+
const scopes = [...new Set(visible.map(({ row }) => row.scope))];
|
|
393
|
+
const capturingSearch = _keyCapture?.mode === "search";
|
|
394
|
+
return html`
|
|
395
|
+
<div class="prefs-keys" @keydown=${onKeyboardKeyDown}>
|
|
396
|
+
<div class="prefs-field">
|
|
397
|
+
<sp-search
|
|
398
|
+
size="s"
|
|
399
|
+
placeholder="Find a shortcut…"
|
|
400
|
+
.value=${
|
|
401
|
+
_keyFilter === null
|
|
402
|
+
? ""
|
|
403
|
+
: _keyFilter.kind === "chord"
|
|
404
|
+
? format(_keyFilter.chord)
|
|
405
|
+
: _keyFilter.value
|
|
406
|
+
}
|
|
407
|
+
@input=${(event: Event) => {
|
|
408
|
+
const { value } = event.target as HTMLInputElement;
|
|
409
|
+
_keyFilter = value ? { kind: "text", value } : null;
|
|
410
|
+
_keyCapture = null;
|
|
411
|
+
repaint();
|
|
412
|
+
}}
|
|
413
|
+
@submit=${(event: Event) => event.preventDefault()}
|
|
414
|
+
></sp-search>
|
|
415
|
+
<sp-action-button
|
|
416
|
+
size="s"
|
|
417
|
+
?selected=${capturingSearch}
|
|
418
|
+
@click=${() => {
|
|
419
|
+
_keyCapture = capturingSearch ? null : { mode: "search" };
|
|
420
|
+
_keyRefusal = null;
|
|
421
|
+
repaint();
|
|
422
|
+
}}
|
|
423
|
+
>
|
|
424
|
+
${capturingSearch ? "Press it now" : "Search by keystroke"}
|
|
425
|
+
</sp-action-button>
|
|
426
|
+
</div>
|
|
427
|
+
${keyRefusalTpl()}
|
|
428
|
+
${
|
|
429
|
+
visible.length === 0
|
|
430
|
+
? html`<p class="prefs-empty">
|
|
431
|
+
${
|
|
432
|
+
_keyFilter?.kind === "chord"
|
|
433
|
+
? `Nothing is bound to ${format(_keyFilter.chord)}.`
|
|
434
|
+
: "No shortcut matches that."
|
|
435
|
+
}
|
|
436
|
+
</p>`
|
|
437
|
+
: scopes.map(
|
|
438
|
+
(scope) => html`
|
|
439
|
+
<h4 class="prefs-keys-scope">${SCOPE_LABELS[scope]}</h4>
|
|
440
|
+
${visible
|
|
441
|
+
.filter(({ row }) => row.scope === scope)
|
|
442
|
+
.map(({ command, row }) => keyRowTpl(row, command, registry))}
|
|
443
|
+
`,
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
</div>
|
|
447
|
+
`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function sectionBodyTpl(): TemplateResult {
|
|
451
|
+
if (_section === "assistant") {
|
|
452
|
+
return assistantTpl();
|
|
453
|
+
}
|
|
454
|
+
if (_section === "accounts") {
|
|
455
|
+
return accountsTpl();
|
|
456
|
+
}
|
|
457
|
+
if (_section === "keyboard") {
|
|
458
|
+
return keyboardTpl();
|
|
459
|
+
}
|
|
460
|
+
return appearanceTpl();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// ─── The sheet ────────────────────────────────────────────────────────────────
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Open Preferences, optionally on a named section. Resolves when it is dismissed.
|
|
467
|
+
*
|
|
468
|
+
* Re-opening while it is already up SELECTS the section instead of stacking a second sheet — which
|
|
469
|
+
* is what makes "Assistant: no provider connected → Preferences" land on the Assistant section from
|
|
470
|
+
* inside the assistant, rather than on top of itself.
|
|
471
|
+
*
|
|
472
|
+
* @param section One of {@link PREFERENCES_SECTIONS}' ids. An unknown id falls back to Appearance.
|
|
473
|
+
*/
|
|
474
|
+
export function openPreferences(section?: string): Promise<null> {
|
|
475
|
+
_section = section !== undefined && isPreferencesSection(section) ? section : _section;
|
|
476
|
+
if (_close) {
|
|
477
|
+
repaint();
|
|
478
|
+
return Promise.resolve(null);
|
|
479
|
+
}
|
|
480
|
+
_section =
|
|
481
|
+
section !== undefined && isPreferencesSection(section) ? section : DEFAULT_PREFERENCES_SECTION;
|
|
482
|
+
credsForm.startEdit();
|
|
483
|
+
resetKeyboardState();
|
|
484
|
+
return showDialog<null>(
|
|
485
|
+
(done) => {
|
|
486
|
+
let wrapperEl: HTMLElement | null = null;
|
|
487
|
+
|
|
488
|
+
function finish() {
|
|
489
|
+
_rerender = null;
|
|
490
|
+
_close = null;
|
|
491
|
+
done(null);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function build(): TemplateResult {
|
|
495
|
+
const active = PREFERENCES_SECTIONS.find((candidate) => candidate.id === _section);
|
|
496
|
+
return html`
|
|
497
|
+
<sp-dialog-wrapper
|
|
498
|
+
open
|
|
499
|
+
underlay
|
|
500
|
+
headline="Preferences"
|
|
501
|
+
cancel-label="Close"
|
|
502
|
+
size="l"
|
|
503
|
+
@cancel=${finish}
|
|
504
|
+
@close=${finish}
|
|
505
|
+
${ref((el?: Element) => {
|
|
506
|
+
if (el) {
|
|
507
|
+
wrapperEl = el as HTMLElement;
|
|
508
|
+
}
|
|
509
|
+
})}
|
|
510
|
+
>
|
|
511
|
+
<div class="prefs-sheet">
|
|
512
|
+
<nav class="prefs-nav" aria-label="Preferences sections">
|
|
513
|
+
${PREFERENCES_SECTIONS.map(
|
|
514
|
+
(candidate) => html`
|
|
515
|
+
<button
|
|
516
|
+
type="button"
|
|
517
|
+
class="prefs-nav-item ${candidate.id === _section ? "active" : ""}"
|
|
518
|
+
aria-current=${candidate.id === _section ? "true" : "false"}
|
|
519
|
+
@click=${() => {
|
|
520
|
+
_section = candidate.id;
|
|
521
|
+
// Leaving a section abandons what it was in the middle of: an armed key
|
|
522
|
+
// Capture whose listener is no longer mounted would otherwise swallow the
|
|
523
|
+
// First chord pressed on the author's NEXT visit.
|
|
524
|
+
resetKeyboardState();
|
|
525
|
+
repaint();
|
|
526
|
+
}}
|
|
527
|
+
>
|
|
528
|
+
${candidate.title}
|
|
529
|
+
</button>
|
|
530
|
+
`,
|
|
531
|
+
)}
|
|
532
|
+
</nav>
|
|
533
|
+
<section class="prefs-body">
|
|
534
|
+
<h3 class="prefs-title">${active?.title ?? ""}</h3>
|
|
535
|
+
<p class="prefs-blurb">${active?.blurb ?? ""}</p>
|
|
536
|
+
${sectionBodyTpl()}
|
|
537
|
+
</section>
|
|
538
|
+
</div>
|
|
539
|
+
</sp-dialog-wrapper>
|
|
540
|
+
`;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
_close = finish;
|
|
544
|
+
_rerender = () => {
|
|
545
|
+
// Resolved lazily: lit commits element refs before inserting the fragment, so the slot the
|
|
546
|
+
// Sheet was rendered into is only reachable once the first render has landed.
|
|
547
|
+
const host = wrapperEl?.parentElement;
|
|
548
|
+
if (host) {
|
|
549
|
+
litRender(build(), host);
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
return build();
|
|
553
|
+
},
|
|
554
|
+
{ region: overlayRegion("dialog", "preferences") },
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** Close Preferences if it is open. Tests, and the shell teardown. */
|
|
559
|
+
export function closePreferences(): void {
|
|
560
|
+
_close?.();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// ─── Command ──────────────────────────────────────────────────────────────────
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* `app.preferences` — ⌘, everywhere, with no precondition.
|
|
567
|
+
*
|
|
568
|
+
* Application level, and deliberately not gated on an open project: the theme, the provider key and
|
|
569
|
+
* the keyboard are all configurable from the welcome screen, which is exactly where a first-run
|
|
570
|
+
* user is when they need them.
|
|
571
|
+
*/
|
|
572
|
+
export function preferencesCommands(): AnyCommand[] {
|
|
573
|
+
return [
|
|
574
|
+
{
|
|
575
|
+
args: {
|
|
576
|
+
additionalProperties: false,
|
|
577
|
+
properties: {
|
|
578
|
+
section: {
|
|
579
|
+
type: "string",
|
|
580
|
+
enum: PREFERENCES_SECTIONS.map((section) => section.id),
|
|
581
|
+
description: "Which Preferences section to show. Defaults to Appearance.",
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
required: [],
|
|
585
|
+
type: "object",
|
|
586
|
+
},
|
|
587
|
+
category: "View",
|
|
588
|
+
id: "app.preferences",
|
|
589
|
+
level: "application",
|
|
590
|
+
keybinding: "mod+,",
|
|
591
|
+
menus: ["commandbar/overflow", "palette"],
|
|
592
|
+
group: "7_settings",
|
|
593
|
+
run: (_ctx, args) => {
|
|
594
|
+
const section = (args as { section?: unknown } | undefined)?.section;
|
|
595
|
+
if (section !== undefined && !isPreferencesSection(section)) {
|
|
596
|
+
throw new RangeError(
|
|
597
|
+
`command "app.preferences" argument "section": "${String(section)}" is not a ` +
|
|
598
|
+
`Preferences section — declared: ` +
|
|
599
|
+
`${PREFERENCES_SECTIONS.map((candidate) => candidate.id).join(", ")}`,
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
void openPreferences(section as string | undefined);
|
|
603
|
+
},
|
|
604
|
+
title: "Preferences…",
|
|
605
|
+
},
|
|
606
|
+
];
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Register the preferences verb, and apply the preferences that are already stored.
|
|
611
|
+
*
|
|
612
|
+
* The keyboard layer is applied HERE rather than at the end of the bootstrap because the keymap
|
|
613
|
+
* holds the layer itself: every record registered after this call — including the ones the
|
|
614
|
+
* bootstrap registers below it — is indexed against the author's overrides, so a rebinding survives
|
|
615
|
+
* a reload without anything having to run last.
|
|
616
|
+
*/
|
|
617
|
+
export function registerPreferencesCommands(registry: CommandRegistry): void {
|
|
618
|
+
registry.registerAll(preferencesCommands());
|
|
619
|
+
applyKeybindingOverrides(registry);
|
|
620
|
+
}
|