@jxsuite/studio 6.1.0 → 6.1.2
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/dist/chunks/2020-f2gkpy8d.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-4912g339.js +4 -0
- package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
- package/dist/chunks/cf-settings-br6105tr.js +4 -0
- package/dist/chunks/color-28ksk2qm.js +4 -0
- package/dist/chunks/color-area-0fj8a4ga.js +4 -0
- package/dist/chunks/color-field-xch8kx2g.js +4 -0
- package/dist/chunks/color-slider-jxd8v350.js +4 -0
- package/dist/chunks/combobox-p0efwjke.js +4 -0
- package/dist/chunks/components-db68vsn7.js +4 -0
- package/dist/chunks/content-source-1449qesq.js +4 -0
- package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-x9jn86a7.js +4 -0
- package/dist/chunks/entry-commands-may24cpt.js +4 -0
- package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
- package/dist/chunks/file-ops-x9v54pcj.js +4 -0
- package/dist/chunks/files-j3knqf0s.js +4 -0
- package/dist/chunks/format-host-tyre2trb.js +4 -0
- package/dist/chunks/fs-events-64ma9htc.js +4 -0
- package/dist/chunks/git-panel-84ps5dex.js +4 -0
- package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
- package/dist/chunks/icons-pnfz478q.js +4 -0
- package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
- package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
- package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
- package/dist/chunks/iframe-entry-zap785cw.js +5 -0
- package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
- package/dist/chunks/index-b8xw3vy9.js +4 -0
- package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
- package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
- package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
- package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
- package/dist/chunks/layers-h4xp1pss.js +4 -0
- package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
- package/dist/chunks/listbox-e74qjyq6.js +4 -0
- package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
- package/dist/chunks/media-picker-2cweexc5.js +4 -0
- package/dist/chunks/menu-n6yzswmy.js +4 -0
- package/dist/chunks/menu-ynw13y0s.js +4 -0
- package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
- package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
- package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
- package/dist/chunks/notify-cj5zbrs2.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-b7ddhr8m.js +4 -0
- package/dist/chunks/platform-3dfws9js.js +4 -0
- package/dist/chunks/popover-jt2gxmzs.js +4 -0
- package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
- package/dist/chunks/quick-search-0dajrwqg.js +4 -0
- package/dist/chunks/references-49qgt404.js +4 -0
- package/dist/chunks/right-panel-jm1bwe53.js +4 -0
- package/dist/chunks/section-registry-6kwc4fky.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/split-n2gfpm5m.js +4 -0
- package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
- package/dist/chunks/studio-0rt52vpq.js +5 -0
- package/dist/chunks/studio-18vgbhs5.js +5 -0
- package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
- package/dist/chunks/studio-24mccdrj.js +5 -0
- package/dist/chunks/studio-2eh507zk.js +9 -0
- package/dist/chunks/studio-2hcbccfv.js +5 -0
- package/dist/chunks/studio-2j1cb95x.js +5 -0
- package/dist/chunks/studio-2jbs3rxv.js +5 -0
- package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
- package/dist/chunks/studio-4h8k4dw9.js +5 -0
- package/dist/chunks/studio-5f6n18kx.js +5 -0
- package/dist/chunks/studio-5gthpky6.js +5 -0
- package/dist/chunks/studio-5ve6bbep.js +5 -0
- package/dist/chunks/studio-6ep3js6b.js +9 -0
- package/dist/chunks/studio-6wkmf3wz.js +9 -0
- package/dist/chunks/studio-841rf3cg.js +5 -0
- package/dist/chunks/studio-8gmwgheg.js +5 -0
- package/dist/chunks/studio-8qm0ep50.js +5 -0
- package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
- package/dist/chunks/studio-924p1tm1.js +6 -0
- package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
- package/dist/chunks/studio-a3shpz9y.js +5 -0
- package/dist/chunks/studio-amsbaaar.js +6 -0
- package/dist/chunks/studio-at5spjbc.js +7 -0
- package/dist/chunks/studio-b2xv945e.js +5 -0
- package/dist/chunks/studio-bn5nkafw.js +5 -0
- package/dist/chunks/studio-bw6q5xjf.js +9 -0
- package/dist/chunks/studio-c7q0t9x1.js +5 -0
- package/dist/chunks/studio-camnhc96.js +6 -0
- package/dist/chunks/studio-cffqvnzd.js +5 -0
- package/dist/chunks/studio-d81xfh1g.js +5 -0
- package/dist/chunks/studio-dgz8d0c1.js +5 -0
- package/dist/chunks/studio-efvfrsf8.js +5 -0
- package/dist/chunks/studio-er30bpcx.js +5 -0
- package/dist/chunks/studio-ezscgr64.js +5 -0
- package/dist/chunks/studio-ffrrncvz.js +5 -0
- package/dist/chunks/studio-fpphgn8y.js +10 -0
- package/dist/chunks/studio-j1kvhdjk.js +4 -0
- package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
- package/dist/chunks/studio-jjkg84nj.js +5 -0
- package/dist/chunks/studio-m0q32ars.js +4 -0
- package/dist/chunks/studio-m6bdst11.js +5 -0
- package/dist/chunks/studio-nv2cptd4.js +64 -0
- package/dist/chunks/studio-nwfrc98n.js +5 -0
- package/dist/chunks/studio-p1wgvp7r.js +5 -0
- package/dist/chunks/studio-pag2wncm.js +5 -0
- package/dist/chunks/studio-qvanvzfd.js +5 -0
- package/dist/chunks/studio-qwa64kt7.js +5 -0
- package/dist/chunks/studio-rk1zc4x3.js +928 -0
- package/dist/chunks/studio-se2r3ptc.js +5 -0
- package/dist/chunks/studio-sg2a0dh0.js +5 -0
- package/dist/chunks/studio-tjzjhe68.js +5 -0
- package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
- package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
- package/dist/chunks/studio-v2w7q8r1.js +7 -0
- package/dist/chunks/studio-v5vjq1h0.js +4 -0
- package/dist/chunks/studio-v8aga3vp.js +14 -0
- package/dist/chunks/studio-vfcdrfmv.js +5 -0
- package/dist/chunks/studio-vmfkgdjf.js +5 -0
- package/dist/chunks/studio-wt1816jj.js +5 -0
- package/dist/chunks/studio-wz73q5kq.js +4 -0
- package/dist/chunks/studio-y04qtxvp.js +7 -0
- package/dist/chunks/studio-y21g8zzg.js +5 -0
- package/dist/chunks/studio-y64hrt8p.js +12 -0
- package/dist/chunks/studio-ynn90f58.js +16 -0
- package/dist/chunks/studio-yxz682sx.js +5 -0
- package/dist/chunks/studio-zp7snvkq.js +5 -0
- package/dist/chunks/studio-zq4z6tm6.js +5 -0
- package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-c9fn075p.js +4 -0
- package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
- package/dist/chunks/tree-mdq3v5cw.js +4 -0
- package/dist/chunks/tsMode-sf49ee9x.js +14 -0
- package/dist/chunks/workspace-jtfahpee.js +4 -0
- package/dist/chunks/ws-client-nze0k6mv.js +4 -0
- package/dist/iframe-entry.js +16 -16
- package/dist/manifest.json +63 -63
- package/dist/studio.js +98 -98
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +11 -11
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/library-layouts.ts +8 -5
- package/src/browse/library-model.ts +18 -6
- package/src/browse/library-pane.ts +37 -21
- package/src/browse/library-preview.ts +14 -9
- package/src/browse/library-source.ts +1 -1
- package/src/canvas/asset-refs.ts +24 -9
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +44 -53
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +66 -42
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +163 -64
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +13 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +80 -63
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +203 -118
- package/src/canvas/iframe-inline-edit.ts +69 -32
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +37 -26
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +18 -15
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +15 -16
- package/src/canvas/iframe-render.ts +41 -36
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +6 -2
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +2 -1
- package/src/canvas/surface-registry.ts +21 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/budget.ts +3 -3
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +22 -20
- package/src/commands/defaults.ts +4 -1
- package/src/commands/keymap.ts +47 -43
- package/src/commands/levels.ts +3 -3
- package/src/commands/live-context.ts +10 -8
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +12 -10
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +5 -4
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +3 -2
- package/src/content/entry-editor.ts +29 -17
- package/src/content/entry-fields.ts +12 -7
- package/src/content/entry-model.ts +21 -12
- package/src/editor/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +11 -5
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +21 -22
- package/src/editor/inline-edit-apply.ts +35 -17
- package/src/editor/inline-edit.ts +66 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +87 -47
- package/src/editor/slash-menu.ts +1 -6
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +15 -10
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +77 -36
- package/src/files/files.ts +90 -95
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +6 -1
- package/src/files/serialize-document.ts +2 -2
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +76 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +19 -9
- package/src/github/github-publish.ts +24 -20
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +20 -22
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -6
- package/src/grid/grid-panel.ts +11 -4
- package/src/grid/grid-source.ts +8 -8
- package/src/grid/grid-view.ts +14 -17
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +25 -24
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +55 -34
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +1 -2
- package/src/media/media-pane.ts +4 -1
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +17 -9
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +46 -35
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +31 -24
- package/src/panels/data-explorer.ts +62 -25
- package/src/panels/data-grid.ts +14 -11
- package/src/panels/dnd.ts +108 -118
- package/src/panels/editors.ts +55 -22
- package/src/panels/elements-panel.ts +10 -3
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +76 -51
- package/src/panels/frontmatter-fields.ts +24 -19
- package/src/panels/frontmatter-panel.ts +44 -34
- package/src/panels/git-diff-open.ts +4 -4
- package/src/panels/git-panel.ts +49 -61
- package/src/panels/head-panel.ts +131 -111
- package/src/panels/i18n-panel.ts +10 -3
- package/src/panels/imports-panel.ts +23 -47
- package/src/panels/jump-bar.ts +48 -29
- package/src/panels/layers-panel.ts +97 -74
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/pane-context.ts +31 -22
- package/src/panels/pane-grid.ts +49 -20
- package/src/panels/panel-registry.ts +22 -37
- package/src/panels/properties-panel.ts +175 -121
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +3 -3
- package/src/panels/seo-modal.ts +13 -17
- package/src/panels/settings-menu.ts +15 -15
- package/src/panels/signals-panel.ts +153 -131
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +254 -216
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +57 -54
- package/src/panels/stylebook-layers-panel.ts +9 -9
- package/src/panels/stylebook-panel.ts +13 -17
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +36 -26
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +58 -30
- package/src/platforms/cloud.ts +345 -175
- package/src/platforms/default-platform.ts +10 -4
- package/src/platforms/devserver.ts +174 -127
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +8 -2
- package/src/publish/pages-service.ts +28 -13
- package/src/publish/publish-commands.ts +5 -4
- package/src/publish/publish-panel.ts +10 -6
- package/src/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +58 -31
- package/src/services/cem-export.ts +149 -58
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +18 -12
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +8 -7
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +79 -60
- package/src/settings/css-vars-editor.ts +37 -16
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +23 -13
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +11 -8
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +9 -6
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +1 -1
- package/src/settings/schema-field-ui.ts +9 -0
- package/src/settings/settings-document.ts +5 -5
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +104 -81
- package/src/site-context.ts +37 -22
- package/src/state.ts +41 -49
- package/src/store.ts +54 -34
- package/src/studio.ts +39 -77
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +6 -7
- package/src/style/token-ref.ts +5 -4
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +31 -36
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.ts +12 -11
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/commandbar.ts +14 -9
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/doc-header.ts +10 -19
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.ts +14 -11
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/git-panel.ts +7 -15
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.ts +13 -12
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.ts +25 -20
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.ts +11 -10
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/menu.ts +29 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.ts +20 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.ts +5 -6
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.ts +11 -18
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.ts +20 -34
- package/src/surfaces/panel-stylebook-layers.ts +5 -8
- package/src/surfaces/preferences.ts +21 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +126 -73
- package/src/surfaces/rail.ts +38 -12
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.ts +15 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.ts +14 -10
- package/src/surfaces/settings-css-vars.ts +5 -12
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.ts +8 -15
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.ts +5 -6
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.ts +9 -18
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/slash-menu.ts +19 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +17 -14
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +5 -7
- package/src/tabs/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +52 -41
- package/src/tabs/transact.ts +98 -53
- package/src/tabs/typing.ts +31 -0
- package/src/types.ts +32 -17
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +57 -48
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +44 -31
- package/src/ui/media-picker.ts +18 -9
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +113 -70
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +3 -2
- package/src/utils/base64.ts +3 -1
- package/src/utils/edit-display.ts +103 -74
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +10 -12
- package/src/workspace/session.ts +53 -43
- package/src/workspace/workspace.ts +47 -36
- package/dist/chunks/2020-nkxms0ay.js +0 -4
- package/dist/chunks/adapter-m948ab5f.js +0 -4
- package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
- package/dist/chunks/cf-settings-356xdtne.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-yk3t844e.js +0 -4
- package/dist/chunks/content-source-bawmyc09.js +0 -4
- package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-6sc8nacq.js +0 -4
- package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
- package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
- package/dist/chunks/file-ops-gye0qw56.js +0 -4
- package/dist/chunks/files-dmc2xvcq.js +0 -4
- package/dist/chunks/format-host-t76b53f8.js +0 -4
- package/dist/chunks/fs-events-cg4tpz06.js +0 -4
- package/dist/chunks/git-panel-yef7bshy.js +0 -4
- package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
- package/dist/chunks/icons-qbh8akb1.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
- package/dist/chunks/index-nag78a9h.js +0 -4
- package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
- package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
- package/dist/chunks/layers-fvz99859.js +0 -4
- package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-9agdspkt.js +0 -4
- package/dist/chunks/media-picker-rhjvyy00.js +0 -4
- package/dist/chunks/menu-2e4y9j7b.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
- package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
- package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
- package/dist/chunks/notify-h3www560.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-hz34wcd7.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
- package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
- package/dist/chunks/references-2cgdxnb8.js +0 -4
- package/dist/chunks/right-panel-jf856w5w.js +0 -4
- package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0f55h9ye.js +0 -5
- package/dist/chunks/studio-0sqdhnew.js +0 -12
- package/dist/chunks/studio-19x1c75w.js +0 -5
- package/dist/chunks/studio-2sqcndak.js +0 -5
- package/dist/chunks/studio-3aey7dd3.js +0 -5
- package/dist/chunks/studio-3bpdkq2s.js +0 -5
- package/dist/chunks/studio-47y6fbpf.js +0 -5
- package/dist/chunks/studio-4m3826v2.js +0 -5
- package/dist/chunks/studio-4nx2dj1g.js +0 -4
- package/dist/chunks/studio-4xv5s47r.js +0 -9
- package/dist/chunks/studio-5g4t8v6w.js +0 -5
- package/dist/chunks/studio-5py436sf.js +0 -5
- package/dist/chunks/studio-77kt594t.js +0 -5
- package/dist/chunks/studio-8f87n763.js +0 -10
- package/dist/chunks/studio-8mb00b84.js +0 -5
- package/dist/chunks/studio-8p51gq2h.js +0 -6
- package/dist/chunks/studio-954ds834.js +0 -5
- package/dist/chunks/studio-9ft45c83.js +0 -9
- package/dist/chunks/studio-a2138x5k.js +0 -7
- package/dist/chunks/studio-a9yzstqj.js +0 -5
- package/dist/chunks/studio-acdksxx6.js +0 -5
- package/dist/chunks/studio-ar8jcf2y.js +0 -5
- package/dist/chunks/studio-bmn4mn9j.js +0 -7
- package/dist/chunks/studio-e7xxa0sj.js +0 -5
- package/dist/chunks/studio-ecaz25vk.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-fzdywr6p.js +0 -9
- package/dist/chunks/studio-g5fmf0c1.js +0 -5
- package/dist/chunks/studio-g7nse7zb.js +0 -5
- package/dist/chunks/studio-geq1ea6k.js +0 -14
- package/dist/chunks/studio-ghkb32r8.js +0 -5
- package/dist/chunks/studio-ghrhy2y7.js +0 -5
- package/dist/chunks/studio-grawhey1.js +0 -5
- package/dist/chunks/studio-h0xgswew.js +0 -5
- package/dist/chunks/studio-h9c4p2tx.js +0 -5
- package/dist/chunks/studio-jyzj5cxs.js +0 -5
- package/dist/chunks/studio-mgx8yhnz.js +0 -64
- package/dist/chunks/studio-mpb04y1d.js +0 -6
- package/dist/chunks/studio-n17mty64.js +0 -5
- package/dist/chunks/studio-nwh2eqsk.js +0 -6
- package/dist/chunks/studio-q1h883bt.js +0 -16
- package/dist/chunks/studio-q4tv82h7.js +0 -9
- package/dist/chunks/studio-qpqa7vk3.js +0 -5
- package/dist/chunks/studio-qqz8e5gk.js +0 -5
- package/dist/chunks/studio-qvasen3f.js +0 -5
- package/dist/chunks/studio-rggdb3hm.js +0 -5
- package/dist/chunks/studio-sghy936h.js +0 -4
- package/dist/chunks/studio-skprc6ef.js +0 -5
- package/dist/chunks/studio-tt2nactf.js +0 -5
- package/dist/chunks/studio-tyasmc39.js +0 -5
- package/dist/chunks/studio-vk9ezads.js +0 -5
- package/dist/chunks/studio-vzacdfsc.js +0 -4
- package/dist/chunks/studio-w4c0xmrw.js +0 -5
- package/dist/chunks/studio-wfjqhhbk.js +0 -5
- package/dist/chunks/studio-wgh5kxpj.js +0 -5
- package/dist/chunks/studio-xasj0796.js +0 -5
- package/dist/chunks/studio-y78s8r2n.js +0 -5
- package/dist/chunks/studio-z8w183sh.js +0 -5
- package/dist/chunks/studio-zscd9ty4.js +0 -928
- package/dist/chunks/studio-zxp13sss.js +0 -7
- package/dist/chunks/studio-zygnmm01.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
- package/dist/chunks/workspace-m15qtcqp.js +0 -4
- package/dist/chunks/ws-client-nf61frr1.js +0 -4
package/src/editor/shortcuts.ts
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
* to the code that runs, so a chord and its behaviour cannot drift apart again.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
+
import { isFunction, isNonNullObject } from "@jxsuite/schema/guards";
|
|
33
34
|
import { childIndex, childList, getNodeAtPath, parentElementPath, projectState } from "../store";
|
|
34
35
|
import { activeTab, workspace } from "../workspace/workspace";
|
|
35
36
|
import {
|
|
@@ -45,22 +46,22 @@ import {
|
|
|
45
46
|
mutateDuplicateNodes,
|
|
46
47
|
mutateInsertNode,
|
|
47
48
|
mutateRemoveNodes,
|
|
48
|
-
redo
|
|
49
|
-
undo
|
|
49
|
+
redo,
|
|
50
|
+
undo,
|
|
50
51
|
transactDoc,
|
|
51
52
|
} from "../tabs/transact";
|
|
52
53
|
import {
|
|
53
54
|
applyEditZoom,
|
|
54
|
-
markExplicitZoom,
|
|
55
55
|
requestEditZoom,
|
|
56
56
|
setEditZoom,
|
|
57
|
+
setUserZoom,
|
|
58
|
+
stageZoom,
|
|
57
59
|
} from "../canvas/canvas-utils";
|
|
58
60
|
import { openQuickSearch } from "../panels/quick-search";
|
|
59
61
|
import { inspectorTab } from "../panels/right-panel";
|
|
60
62
|
import { requestClose } from "../panels/tab-strip";
|
|
61
63
|
import { layerHost } from "../ui/layers";
|
|
62
64
|
import { openDialogSurface } from "../surfaces/dialog";
|
|
63
|
-
import { rectOf } from "../utils/geometry";
|
|
64
65
|
import {
|
|
65
66
|
DOCK_IDS,
|
|
66
67
|
requireNavigatorPanelId,
|
|
@@ -78,7 +79,10 @@ import { hasElementSelection, hasSelection, inCanvas, keyScopeStack } from "../c
|
|
|
78
79
|
import { defaultCommands } from "../commands/defaults";
|
|
79
80
|
import { setActiveRegistry } from "../commands/active-registry";
|
|
80
81
|
import { runReported } from "../commands/run-reported";
|
|
82
|
+
import { pointerAnchor } from "../canvas/iframe-host";
|
|
83
|
+
import type { PointerAnchor } from "../canvas/iframe-host";
|
|
81
84
|
import type { CommandContext } from "../commands/context";
|
|
85
|
+
import type { CommandArgValues } from "../commands/command-args";
|
|
82
86
|
import type { DockId as CommandDockId } from "../commands/defaults";
|
|
83
87
|
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
84
88
|
import type { DockId, FocusRegion } from "../shell";
|
|
@@ -163,11 +167,14 @@ function navigateSelection(direction: -1 | 1): void {
|
|
|
163
167
|
tab.session.selection = [[]];
|
|
164
168
|
return;
|
|
165
169
|
}
|
|
166
|
-
|
|
170
|
+
// `parentElementPath` is null exactly when the path is the document element (length < 2).
|
|
171
|
+
const parentPath = parentElementPath(selected);
|
|
172
|
+
if (!parentPath) {
|
|
167
173
|
return;
|
|
168
174
|
}
|
|
169
|
-
const parentPath = parentElementPath(selected) as JxPath;
|
|
170
175
|
const parent = getNodeAtPath(tab.doc.document, parentPath);
|
|
176
|
+
// SAFETY: a selection path of length >= 2 addresses a child as `[..., "children", n]`, so its
|
|
177
|
+
// Last segment is the numeric index `n` (the same invariant `insertSiblingParagraph` relies on).
|
|
171
178
|
const newIndex = (childIndex(selected) as number) + direction;
|
|
172
179
|
if (newIndex >= 0 && newIndex < childList(parent).length) {
|
|
173
180
|
tab.session.selection = [[...parentPath, "children", newIndex]];
|
|
@@ -188,14 +195,10 @@ function selectSiblings(): void {
|
|
|
188
195
|
return;
|
|
189
196
|
}
|
|
190
197
|
const selected = primarySelection(tab.session.selection);
|
|
191
|
-
const parentPath = (
|
|
192
|
-
selected && selected.length >= 2 ? parentElementPath(selected) : []
|
|
193
|
-
) as JxPath;
|
|
198
|
+
const parentPath: JxPath = (selected ? parentElementPath(selected) : null) ?? [];
|
|
194
199
|
const parent = getNodeAtPath(tab.doc.document, parentPath);
|
|
195
200
|
const paths = childList(parent).flatMap((child, index) =>
|
|
196
|
-
|
|
197
|
-
? [[...parentPath, "children", index] as JxPath]
|
|
198
|
-
: [],
|
|
201
|
+
isNonNullObject(child) ? [[...parentPath, "children", index]] : [],
|
|
199
202
|
);
|
|
200
203
|
if (paths.length > 0) {
|
|
201
204
|
tab.session.selection = paths;
|
|
@@ -240,10 +243,16 @@ function selectParent(): void {
|
|
|
240
243
|
function insertSiblingParagraph(): void {
|
|
241
244
|
const tab = activeTab.value;
|
|
242
245
|
const selected = primarySelection(tab?.session.selection);
|
|
243
|
-
if (!tab || !selected
|
|
246
|
+
if (!tab || !selected) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Null exactly when the selection is the document element, which has no sibling slot.
|
|
250
|
+
const parentPath = parentElementPath(selected);
|
|
251
|
+
if (!parentPath) {
|
|
244
252
|
return;
|
|
245
253
|
}
|
|
246
|
-
|
|
254
|
+
// SAFETY: a selection path of length >= 2 addresses a child as `[..., "children", n]`, so its
|
|
255
|
+
// Last segment is the numeric child index `n`.
|
|
247
256
|
const index = childIndex(selected) as number;
|
|
248
257
|
const newPath = [...parentPath, "children", index + 1];
|
|
249
258
|
transactDoc(tab, (t) => {
|
|
@@ -301,24 +310,28 @@ function closeDocument(): void {
|
|
|
301
310
|
function undoDocument(): void {
|
|
302
311
|
const tab = activeTab.value;
|
|
303
312
|
if (tab) {
|
|
304
|
-
|
|
313
|
+
undo(tab);
|
|
305
314
|
}
|
|
306
315
|
}
|
|
307
316
|
|
|
308
317
|
function redoDocument(): void {
|
|
309
318
|
const tab = activeTab.value;
|
|
310
319
|
if (tab) {
|
|
311
|
-
|
|
320
|
+
redo(tab);
|
|
312
321
|
}
|
|
313
322
|
}
|
|
314
323
|
|
|
315
324
|
// ─── Canvas zoom ──────────────────────────────────────────────────────────────
|
|
316
325
|
|
|
317
|
-
/**
|
|
318
|
-
const ZOOM_MIN = 0.05;
|
|
319
|
-
const ZOOM_MAX = 5;
|
|
326
|
+
/** One chord step. Both zooms clamp inside `canvas-utils`. */
|
|
320
327
|
const ZOOM_STEP = 1.2;
|
|
321
328
|
|
|
329
|
+
/** How long after an Edit zoom step its anchor is measured again: the zoom's frame, then a reflow. */
|
|
330
|
+
const EDIT_ZOOM_SETTLE_MS = 34;
|
|
331
|
+
|
|
332
|
+
/** How long an Edit zoom burst must be idle before its anchor is let go. */
|
|
333
|
+
const EDIT_ZOOM_RELEASE_MS = 300;
|
|
334
|
+
|
|
322
335
|
/** Whether the zoom verbs address the reflowing content zoom rather than the artboard transform. */
|
|
323
336
|
function isContentZoom(ctx: CommandContext): boolean {
|
|
324
337
|
return ctx.canvas.view === "edit";
|
|
@@ -343,11 +356,11 @@ function zoomBy(ctx: CommandContext, factor: number, redraw: () => void): void {
|
|
|
343
356
|
return;
|
|
344
357
|
}
|
|
345
358
|
if (isContentZoom(ctx)) {
|
|
346
|
-
setEditZoom(
|
|
359
|
+
setEditZoom(tab.session.ui.editZoom * factor);
|
|
347
360
|
return;
|
|
348
361
|
}
|
|
349
|
-
|
|
350
|
-
|
|
362
|
+
// Around the stage's middle, like the zoom pod's buttons.
|
|
363
|
+
setUserZoom(stageZoom() * factor);
|
|
351
364
|
redraw();
|
|
352
365
|
}
|
|
353
366
|
|
|
@@ -391,7 +404,7 @@ function toggleShellDock(registry: CommandRegistry, dock: CommandDockId): void {
|
|
|
391
404
|
* a missing id must be inert rather than an exception thrown out of a keydown handler. A present
|
|
392
405
|
* one that refuses its arguments is not inert: `commands/run-reported.ts` files it in Problems.
|
|
393
406
|
*/
|
|
394
|
-
function runIfPresent(registry: CommandRegistry, id: string, args:
|
|
407
|
+
function runIfPresent(registry: CommandRegistry, id: string, args: CommandArgValues): void {
|
|
395
408
|
if (registry.get(id) && registry.isEnabled(id)) {
|
|
396
409
|
void runReported(registry, id, args, "Keyboard");
|
|
397
410
|
}
|
|
@@ -641,8 +654,9 @@ function askWhereToOpen(openName: string): Promise<ProjectOpenTarget | "cancel">
|
|
|
641
654
|
export async function openProjectFlow(hooks: StudioCommandHooks): Promise<void> {
|
|
642
655
|
const platform = hasPlatform() ? getPlatform() : null;
|
|
643
656
|
const canOpenElsewhere =
|
|
644
|
-
|
|
645
|
-
|
|
657
|
+
platform !== null &&
|
|
658
|
+
isFunction(platform.openProjectInNewWindow) &&
|
|
659
|
+
isFunction(platform.pickProject);
|
|
646
660
|
if (!projectState || !canOpenElsewhere) {
|
|
647
661
|
await hooks.openProject("thisWindow");
|
|
648
662
|
return;
|
|
@@ -953,7 +967,11 @@ export function initShortcuts(registry: CommandRegistry, stageContext: StageCont
|
|
|
953
967
|
document.addEventListener(
|
|
954
968
|
"wheel",
|
|
955
969
|
(e: WheelEvent) => {
|
|
956
|
-
|
|
970
|
+
const { target } = e;
|
|
971
|
+
if (
|
|
972
|
+
(e.ctrlKey || e.metaKey) &&
|
|
973
|
+
!(target instanceof Element && target.closest(STAGE_SELECTOR))
|
|
974
|
+
) {
|
|
957
975
|
e.preventDefault();
|
|
958
976
|
}
|
|
959
977
|
},
|
|
@@ -1016,7 +1034,7 @@ function wheelBelongsInside(
|
|
|
1016
1034
|
): boolean {
|
|
1017
1035
|
const { target } = e;
|
|
1018
1036
|
let el: Element | null =
|
|
1019
|
-
target instanceof Element ? target :
|
|
1037
|
+
target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
1020
1038
|
while (el && el !== stage) {
|
|
1021
1039
|
if (el instanceof HTMLElement && el !== pageScroller && canScrollBy(el, e.deltaX, e.deltaY)) {
|
|
1022
1040
|
return true;
|
|
@@ -1074,6 +1092,26 @@ let _stageContext: StageContext | null = null;
|
|
|
1074
1092
|
*/
|
|
1075
1093
|
export function installStageGestures(surface: CanvasSurface): () => void {
|
|
1076
1094
|
const canvasWrap = surface.wrap;
|
|
1095
|
+
/* An Edit zoom burst's anchor: the element under the cursor when the burst began. The frame
|
|
1096
|
+
reflows at every step, so after each one the element is measured again and the scroller takes
|
|
1097
|
+
back whatever it moved; the anchor is let go once the burst has been idle a while. */
|
|
1098
|
+
let zoomAnchor: PointerAnchor | null = null;
|
|
1099
|
+
let zoomRelease: ReturnType<typeof setTimeout> | undefined;
|
|
1100
|
+
let zoomCorrecting = false;
|
|
1101
|
+
const correctEditZoom = () => {
|
|
1102
|
+
const anchor = zoomAnchor;
|
|
1103
|
+
if (!anchor || zoomCorrecting) {
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
zoomCorrecting = true;
|
|
1107
|
+
void anchor.settle().then((top) => {
|
|
1108
|
+
zoomCorrecting = false;
|
|
1109
|
+
const sc = canvasWrap.querySelector<HTMLElement>('[part="edit-canvas"]');
|
|
1110
|
+
if (top !== null && sc) {
|
|
1111
|
+
sc.scrollTop += top - anchor.top;
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
};
|
|
1077
1115
|
const getContext = () => _stageContext?.(surface) ?? stageless();
|
|
1078
1116
|
const controller = new AbortController();
|
|
1079
1117
|
const { signal } = controller;
|
|
@@ -1093,7 +1131,16 @@ export function installStageGestures(surface: CanvasSurface): () => void {
|
|
|
1093
1131
|
if (e.ctrlKey || e.metaKey) {
|
|
1094
1132
|
e.preventDefault();
|
|
1095
1133
|
const editZoom = paneTab?.session.ui.editZoom ?? 1;
|
|
1096
|
-
|
|
1134
|
+
const canvasEl = surface.panels[0]?.canvas;
|
|
1135
|
+
zoomAnchor ??= canvasEl ? pointerAnchor(canvasEl) : null;
|
|
1136
|
+
requestEditZoom(editZoom * (1 + -e.deltaY * 0.005), surface, e.clientY);
|
|
1137
|
+
// Measured after the zoom's own frame has applied, and the frame has had one to reflow.
|
|
1138
|
+
setTimeout(correctEditZoom, EDIT_ZOOM_SETTLE_MS);
|
|
1139
|
+
clearTimeout(zoomRelease);
|
|
1140
|
+
zoomRelease = setTimeout(() => {
|
|
1141
|
+
correctEditZoom();
|
|
1142
|
+
zoomAnchor = null;
|
|
1143
|
+
}, EDIT_ZOOM_RELEASE_MS);
|
|
1097
1144
|
return;
|
|
1098
1145
|
}
|
|
1099
1146
|
/* The stage's own scroller, by the `part` the stage document draws it with — the same
|
|
@@ -1125,24 +1172,14 @@ export function installStageGestures(surface: CanvasSurface): () => void {
|
|
|
1125
1172
|
}
|
|
1126
1173
|
e.preventDefault();
|
|
1127
1174
|
if (e.ctrlKey || e.metaKey) {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
const newZoom = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, oldZoom * (1 + delta)));
|
|
1137
|
-
const ratio = newZoom / oldZoom;
|
|
1138
|
-
// Adjust pan so the point under cursor stays stationary
|
|
1139
|
-
setPan(cursorX - (cursorX - panX) * ratio, cursorY - (cursorY - panY) * ratio);
|
|
1140
|
-
if (paneTab) {
|
|
1141
|
-
paneTab.session.ui.zoom = newZoom;
|
|
1142
|
-
}
|
|
1143
|
-
// The author chose this zoom, so re-entering Design keeps it instead of auto-fitting.
|
|
1144
|
-
// On THIS stage: the declared fit is a fact about the document under the cursor.
|
|
1145
|
-
markExplicitZoom(surface);
|
|
1175
|
+
/* Zoom toward the cursor, on THIS stage (a lens pane carries its own scale). The author
|
|
1176
|
+
chose this zoom, so it is declared as the document's fit and re-entering Design keeps
|
|
1177
|
+
it instead of auto-fitting. */
|
|
1178
|
+
setUserZoom(stageZoom(surface) * (1 + -e.deltaY * 0.005), surface, {
|
|
1179
|
+
clientX: e.clientX,
|
|
1180
|
+
clientY: e.clientY,
|
|
1181
|
+
});
|
|
1182
|
+
return;
|
|
1146
1183
|
} else if (e.shiftKey) {
|
|
1147
1184
|
// Shift+scroll = horizontal pan
|
|
1148
1185
|
setPan(panX - e.deltaY, panY);
|
|
@@ -1206,7 +1243,10 @@ export function installStageGestures(surface: CanvasSurface): () => void {
|
|
|
1206
1243
|
{ signal },
|
|
1207
1244
|
);
|
|
1208
1245
|
|
|
1209
|
-
return () =>
|
|
1246
|
+
return () => {
|
|
1247
|
+
clearTimeout(zoomRelease);
|
|
1248
|
+
controller.abort();
|
|
1249
|
+
};
|
|
1210
1250
|
}
|
|
1211
1251
|
|
|
1212
1252
|
/** The context a stage answers with before the bootstrap has published a reader. */
|
package/src/editor/slash-menu.ts
CHANGED
|
@@ -29,12 +29,7 @@
|
|
|
29
29
|
import { openSlashMenuSurface } from "../surfaces/slash-menu";
|
|
30
30
|
import { rectOf } from "../utils/geometry";
|
|
31
31
|
import type { SlashMenuRow, SlashMenuSurface, SlashMenuView } from "../surfaces/slash-menu";
|
|
32
|
-
|
|
33
|
-
interface SlashCommand {
|
|
34
|
-
label: string;
|
|
35
|
-
tag: string;
|
|
36
|
-
description: string;
|
|
37
|
-
}
|
|
32
|
+
import type { SlashCommand } from "./inline-edit";
|
|
38
33
|
|
|
39
34
|
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
40
35
|
|
|
@@ -30,13 +30,14 @@
|
|
|
30
30
|
* paths only — a `.json` or `.md` file is never loaded by URL from the canvas, and leaving them out
|
|
31
31
|
* keeps that message as small as the media set.
|
|
32
32
|
*
|
|
33
|
-
* Pure module state — it imports nothing but path normalization
|
|
34
|
-
* the canvas host can import it without dragging in the file layer.
|
|
33
|
+
* Pure module state — it imports nothing but path normalization, the primitive guards and the
|
|
34
|
+
* reactivity re-export — so the canvas host can import it without dragging in the file layer.
|
|
35
35
|
*
|
|
36
36
|
* @docs extending/embedding/platform-adapter
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
import { normalizeProjectPath } from "@jxsuite/schema/asset-paths";
|
|
40
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
40
41
|
import { shallowRef } from "../reactivity";
|
|
41
42
|
import type { DirEntry } from "../types";
|
|
42
43
|
|
|
@@ -161,8 +162,7 @@ export function noteListing(entries: readonly DirEntry[], since: number): void {
|
|
|
161
162
|
if (path === "" || dirtiedSince(path, since)) {
|
|
162
163
|
continue;
|
|
163
164
|
}
|
|
164
|
-
const version =
|
|
165
|
-
typeof entry.version === "string" && entry.version !== "" ? entry.version : null;
|
|
165
|
+
const version = isString(entry.version) && entry.version !== "" ? entry.version : null;
|
|
166
166
|
const held = versions.get(path);
|
|
167
167
|
if (version === null) {
|
|
168
168
|
if (held === undefined) {
|
package/src/files/components.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { getPlatform } from "../platform";
|
|
|
4
4
|
import { projectState } from "../store";
|
|
5
5
|
import type { ComponentMeta } from "../types";
|
|
6
6
|
import { componentMetaFrom } from "@jxsuite/schema/component-meta";
|
|
7
|
-
import
|
|
7
|
+
import { isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
8
|
+
import type { JsonValue, JxMutableNode } from "@jxsuite/schema/types";
|
|
8
9
|
|
|
9
10
|
/** A discovered component: project components carry a file path; package components may not. */
|
|
10
11
|
export interface ComponentEntry extends Omit<ComponentMeta, "path"> {
|
|
@@ -40,15 +41,17 @@ export async function loadComponentRegistry() {
|
|
|
40
41
|
*
|
|
41
42
|
* @param {string | null} path - The saved document's project-relative path; `null` for an unsaved
|
|
42
43
|
* draft, which no scan would have seen either.
|
|
43
|
-
* @param {
|
|
44
|
+
* @param {JxMutableNode} doc - The saved document.
|
|
44
45
|
* @returns {boolean} Whether the registry changed, so a caller knows to repaint what reads it.
|
|
45
46
|
*/
|
|
46
|
-
export function noteComponentSaved(path: string | null, doc:
|
|
47
|
+
export function noteComponentSaved(path: string | null, doc: JxMutableNode): boolean {
|
|
47
48
|
if (!path) {
|
|
48
49
|
return false;
|
|
49
50
|
}
|
|
50
51
|
const index = componentRegistry.findIndex((c) => c.path === path);
|
|
51
|
-
|
|
52
|
+
/* SAFETY: a saved tab's document was parsed from JSON and has just been written back as JSON
|
|
53
|
+
(`serializeDocument`), so every value it holds is a JSON value — the model the extractor reads. */
|
|
54
|
+
const meta = componentMetaFrom(doc as JsonValue, path);
|
|
52
55
|
if (!meta) {
|
|
53
56
|
if (index === -1) {
|
|
54
57
|
return false;
|
|
@@ -56,6 +59,8 @@ export function noteComponentSaved(path: string | null, doc: unknown): boolean {
|
|
|
56
59
|
componentRegistry.splice(index, 1);
|
|
57
60
|
return true;
|
|
58
61
|
}
|
|
62
|
+
/* SAFETY: `componentMetaFrom` is the extractor every backend's `discoverComponents` scan runs to
|
|
63
|
+
Produce the registry's entries, so its output has the shape the registry already holds. */
|
|
59
64
|
const entry = meta as ComponentEntry;
|
|
60
65
|
if (index === -1) {
|
|
61
66
|
componentRegistry.push(entry);
|
|
@@ -84,7 +89,7 @@ export function buildComponentInstance(comp: ComponentEntry): JxMutableNode {
|
|
|
84
89
|
for (const child of structuredClone(slot.fallback ?? [])) {
|
|
85
90
|
if (!slot.name) {
|
|
86
91
|
children.push(child);
|
|
87
|
-
} else if (
|
|
92
|
+
} else if (isNonNullObject(child) && isString(child.tagName)) {
|
|
88
93
|
// Preserve an author-set slot attribute (slot forwarding inside fallback).
|
|
89
94
|
child.attributes = { slot: slot.name, ...child.attributes };
|
|
90
95
|
children.push(child);
|
|
@@ -94,11 +99,11 @@ export function buildComponentInstance(comp: ComponentEntry): JxMutableNode {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
const instance: JxMutableNode = { $props, tagName: comp.tagName };
|
|
103
|
+
if (children.length > 0) {
|
|
104
|
+
instance.children = children;
|
|
105
|
+
}
|
|
106
|
+
return instance;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
/**
|
package/src/files/elements.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* they must not differ on is WHICH entries the list should hold.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
23
24
|
import { computeRelativePath } from "./components";
|
|
24
25
|
import type { ComponentEntry } from "./components";
|
|
25
26
|
import type { JxElement } from "@jxsuite/schema/types";
|
|
@@ -29,9 +30,7 @@ export type ElementsEntry = string | JxElement | { $ref: string };
|
|
|
29
30
|
|
|
30
31
|
/** The `$ref` of an entry, when it has one. */
|
|
31
32
|
function refOf(entry: ElementsEntry): string | null {
|
|
32
|
-
return
|
|
33
|
-
? entry.$ref
|
|
34
|
-
: null;
|
|
33
|
+
return isNonNullObject(entry) && isString(entry.$ref) ? entry.$ref : null;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
/**
|
|
@@ -81,7 +80,7 @@ export function hasElement(
|
|
|
81
80
|
const specifier = npmSpecifier(comp);
|
|
82
81
|
if (specifier) {
|
|
83
82
|
return elements.some(
|
|
84
|
-
(entry) =>
|
|
83
|
+
(entry) => isString(entry) && (entry === specifier || entry === comp.package),
|
|
85
84
|
);
|
|
86
85
|
}
|
|
87
86
|
if (!comp.path) {
|
|
@@ -132,7 +131,7 @@ export function disableElement(
|
|
|
132
131
|
if (specifier) {
|
|
133
132
|
// Both spellings: a component ticked off must not stay imported through the package entry.
|
|
134
133
|
return elements.filter(
|
|
135
|
-
(entry) => !(
|
|
134
|
+
(entry) => !(isString(entry) && (entry === specifier || entry === comp.package)),
|
|
136
135
|
);
|
|
137
136
|
}
|
|
138
137
|
if (!comp.path) {
|
|
@@ -151,7 +150,7 @@ export function removePackageElements(
|
|
|
151
150
|
pkg: string,
|
|
152
151
|
): ElementsEntry[] {
|
|
153
152
|
return elements.filter(
|
|
154
|
-
(entry) =>
|
|
153
|
+
(entry) => !isString(entry) || !(entry === pkg || entry.startsWith(`${pkg}/`)),
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
|
package/src/files/file-ops.ts
CHANGED
|
@@ -28,6 +28,8 @@ import { showConfirmDialog } from "../ui/layers";
|
|
|
28
28
|
import { locateDocument } from "../services/code-services";
|
|
29
29
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
30
30
|
import { notify } from "../services/notify";
|
|
31
|
+
import type { NotifyOptions } from "../services/notify";
|
|
32
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
31
33
|
import { validateComponentSlots } from "../services/cem-export";
|
|
32
34
|
import { reportPopoverProblems } from "../services/popover-report";
|
|
33
35
|
import { getPlatform } from "../platform";
|
|
@@ -103,19 +105,66 @@ export async function parseSourceForPath(path: string, source: string) {
|
|
|
103
105
|
export const parseCollabSource: CollabParser = async (tab, text) => {
|
|
104
106
|
if (tab.documentPath && formatForPath(tab.documentPath)) {
|
|
105
107
|
const parsed = await parseSourceForPath(tab.documentPath, text);
|
|
106
|
-
return { document: parsed.document
|
|
108
|
+
return { document: parsed.document, frontmatter: parsed.frontmatter };
|
|
107
109
|
}
|
|
108
110
|
const parsed = parseJsonDocument(text);
|
|
109
111
|
tab.doc.layout = parsed.layout;
|
|
112
|
+
/* SAFETY: a co-edited path no format class claims is a `.json` Jx document (every other path
|
|
113
|
+
`ensureCollab` attaches to is a format file, handled above), and that file's schema makes its
|
|
114
|
+
Top-level object a node — the object `parseJsonDocument` already states it returns. */
|
|
110
115
|
return { document: parsed.document as JxMutableNode };
|
|
111
116
|
};
|
|
112
117
|
|
|
118
|
+
/** One `accept` group of a File System Access picker: media type → extensions, with a label. */
|
|
119
|
+
interface FilePickerAcceptType {
|
|
120
|
+
accept: Record<string, string[]>;
|
|
121
|
+
description: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The File System Access pickers (WICG), which TypeScript's DOM lib does not declare. Only what
|
|
126
|
+
* this module passes and reads is spelled out.
|
|
127
|
+
*/
|
|
128
|
+
interface FilePickerWindow {
|
|
129
|
+
showOpenFilePicker: (options: {
|
|
130
|
+
types: FilePickerAcceptType[];
|
|
131
|
+
}) => Promise<FileSystemFileHandle[]>;
|
|
132
|
+
/* Export's single extension is `format.extensions[0]`, absent for a format that declares none —
|
|
133
|
+
So the save picker is typed with the value it is actually handed. */
|
|
134
|
+
showSaveFilePicker: (options: {
|
|
135
|
+
suggestedName?: string | undefined;
|
|
136
|
+
types: { accept: Record<string, (string | undefined)[]>; description: string }[];
|
|
137
|
+
}) => Promise<FileSystemFileHandle>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Whether this browser offers `showOpenFilePicker` (Chromium does; Firefox and Safari do not). */
|
|
141
|
+
function hasOpenFilePicker(
|
|
142
|
+
win: Window,
|
|
143
|
+
): win is Window & Pick<FilePickerWindow, "showOpenFilePicker"> {
|
|
144
|
+
return "showOpenFilePicker" in win;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Whether this browser offers `showSaveFilePicker` (Chromium does; Firefox and Safari do not). */
|
|
148
|
+
function hasSaveFilePicker(
|
|
149
|
+
win: Window,
|
|
150
|
+
): win is Window & Pick<FilePickerWindow, "showSaveFilePicker"> {
|
|
151
|
+
return "showSaveFilePicker" in win;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Attach the tab's file to a notification's options, when it has one. */
|
|
155
|
+
function atTabPath(tab: Tab, options: NotifyOptions): NotifyOptions {
|
|
156
|
+
if (tab.documentPath !== null) {
|
|
157
|
+
options.path = tab.documentPath;
|
|
158
|
+
}
|
|
159
|
+
return options;
|
|
160
|
+
}
|
|
161
|
+
|
|
113
162
|
/** Open a file via the File System Access API (or fallback input). */
|
|
114
163
|
export async function openFile() {
|
|
115
164
|
try {
|
|
116
165
|
await loadFormats();
|
|
117
166
|
const formats = getFormats();
|
|
118
|
-
const pickerTypes = [
|
|
167
|
+
const pickerTypes: FilePickerAcceptType[] = [
|
|
119
168
|
{
|
|
120
169
|
accept: { "application/json": [".json"] },
|
|
121
170
|
description: "Jx Component",
|
|
@@ -160,12 +209,8 @@ export async function openFile() {
|
|
|
160
209
|
// Trail; it does not need a message that erases itself.
|
|
161
210
|
};
|
|
162
211
|
|
|
163
|
-
if (
|
|
164
|
-
const [handle] = await (
|
|
165
|
-
window as unknown as {
|
|
166
|
-
showOpenFilePicker: (options?: unknown) => Promise<FileSystemFileHandle[]>;
|
|
167
|
-
}
|
|
168
|
-
).showOpenFilePicker({ types: pickerTypes });
|
|
212
|
+
if (hasOpenFilePicker(window)) {
|
|
213
|
+
const [handle] = await window.showOpenFilePicker({ types: pickerTypes });
|
|
169
214
|
const file = await handle!.getFile();
|
|
170
215
|
await handleSource(handle!.name, await file.text(), handle!);
|
|
171
216
|
} else {
|
|
@@ -230,16 +275,16 @@ function reportSaved(tab: Tab) {
|
|
|
230
275
|
const doc = tab.doc.document;
|
|
231
276
|
_onDocumentSaved(tab.documentPath, doc);
|
|
232
277
|
const warning =
|
|
233
|
-
|
|
234
|
-
? validateComponentSlots(doc)
|
|
235
|
-
: null;
|
|
278
|
+
isString(doc.tagName) && doc.tagName.includes("-") ? validateComponentSlots(doc) : null;
|
|
236
279
|
if (warning) {
|
|
237
|
-
notify.warn(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
280
|
+
notify.warn(
|
|
281
|
+
warning,
|
|
282
|
+
atTabPath(tab, {
|
|
283
|
+
key: `slots:${tab.documentPath ?? tab.id}`,
|
|
284
|
+
source: "Components",
|
|
285
|
+
tier: "problem",
|
|
286
|
+
}),
|
|
287
|
+
);
|
|
243
288
|
}
|
|
244
289
|
/* Popover correctness, beside the slot check and for the same reason it is here: a successful
|
|
245
290
|
save is the one chokepoint every edit passes through, whichever surface made it. A render-time
|
|
@@ -311,12 +356,11 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
|
|
|
311
356
|
notify.warn(
|
|
312
357
|
`You have read access to this session — changes to ${tab.documentPath ?? "this document"} ` +
|
|
313
358
|
`stay in your browser and cannot be saved.`,
|
|
314
|
-
{
|
|
359
|
+
atTabPath(tab, {
|
|
315
360
|
action: "file.save",
|
|
316
361
|
key: `save.readOnly:${tab.documentPath ?? tab.id}`,
|
|
317
|
-
...(tab.documentPath === null ? {} : { path: tab.documentPath }),
|
|
318
362
|
source: "Collaboration",
|
|
319
|
-
},
|
|
363
|
+
}),
|
|
320
364
|
);
|
|
321
365
|
return false;
|
|
322
366
|
}
|
|
@@ -327,11 +371,10 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
|
|
|
327
371
|
if (!hasSerializableDocument(tab)) {
|
|
328
372
|
notify.warn(
|
|
329
373
|
`${tab.documentPath ?? "This file"} is a media file, so there is no document for Save to write.`,
|
|
330
|
-
{
|
|
374
|
+
atTabPath(tab, {
|
|
331
375
|
key: `save.notADocument:${tab.documentPath ?? tab.id}`,
|
|
332
|
-
...(tab.documentPath === null ? {} : { path: tab.documentPath }),
|
|
333
376
|
source: "Save",
|
|
334
|
-
},
|
|
377
|
+
}),
|
|
335
378
|
);
|
|
336
379
|
return false;
|
|
337
380
|
}
|
|
@@ -381,13 +424,15 @@ export async function saveFile(tab: Tab | null = activeTab.value): Promise<boole
|
|
|
381
424
|
notify.warn("This document has no save target — use Export.", { key: "save.noTarget" });
|
|
382
425
|
} catch (error) {
|
|
383
426
|
if (!(error instanceof Error && error.name === "AbortError")) {
|
|
384
|
-
notify.error(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
427
|
+
notify.error(
|
|
428
|
+
`Could not save ${tab.documentPath ?? tab.id}.`,
|
|
429
|
+
atTabPath(tab, {
|
|
430
|
+
action: "file.save",
|
|
431
|
+
detail: errorMessage(error),
|
|
432
|
+
key: `save:${tab.documentPath ?? tab.id}`,
|
|
433
|
+
source: "Save",
|
|
434
|
+
}),
|
|
435
|
+
);
|
|
391
436
|
}
|
|
392
437
|
}
|
|
393
438
|
return false;
|
|
@@ -418,13 +463,9 @@ export async function exportFile() {
|
|
|
418
463
|
const description = format ? format.name : "Jx Component";
|
|
419
464
|
const fallbackName = format ? `content${ext}` : "component.json";
|
|
420
465
|
|
|
421
|
-
if (
|
|
466
|
+
if (hasSaveFilePicker(window)) {
|
|
422
467
|
const suggestedName = tab.documentPath ? tab.documentPath.split("/").pop() : fallbackName;
|
|
423
|
-
const handle = await (
|
|
424
|
-
window as unknown as {
|
|
425
|
-
showSaveFilePicker: (options?: unknown) => Promise<FileSystemFileHandle>;
|
|
426
|
-
}
|
|
427
|
-
).showSaveFilePicker({
|
|
468
|
+
const handle = await window.showSaveFilePicker({
|
|
428
469
|
suggestedName,
|
|
429
470
|
types: [{ accept: { [mimeType]: [ext] }, description }],
|
|
430
471
|
});
|