@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,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The selection SET — one vocabulary for `session.selection`, now that it is `JxPath[]` (§6.5).
|
|
3
|
+
*
|
|
4
|
+
* ## The invariant this module exists to hold
|
|
5
|
+
*
|
|
6
|
+
* **A selection of one behaves exactly as a selection did before it was a list.** Every surface
|
|
7
|
+
* that addresses a single node — the Inspector's three tabs, the block action bar, the status bar,
|
|
8
|
+
* the canvas overlay box, the context menu — reads {@link primarySelection} and nothing else. When
|
|
9
|
+
* `length === 1` that function returns the sole path, so those surfaces receive byte-identically
|
|
10
|
+
* what `session.selection` used to hand them. Nothing downstream of `primarySelection` can tell the
|
|
11
|
+
* difference, and that is what makes the widening shippable: the multi cases are additions beside
|
|
12
|
+
* the single case, never a rewrite of it.
|
|
13
|
+
*
|
|
14
|
+
* The corollary is a rule about writes: **replace the array, never mutate it in place.** Several
|
|
15
|
+
* render effects track the selection with a bare `void tab.session.selection` read, which
|
|
16
|
+
* subscribes to the property and not to the array's indices; an in-place `push` would move the
|
|
17
|
+
* selection without repainting the panel that draws it. Every helper here returns a NEW array.
|
|
18
|
+
*
|
|
19
|
+
* ## Ordering, and why two ends of the list have names
|
|
20
|
+
*
|
|
21
|
+
* The list is kept in the order the user built it.
|
|
22
|
+
*
|
|
23
|
+
* - {@link selectionAnchor} is `selection[0]` — where a shift-range extends FROM. It survives every
|
|
24
|
+
* range extension, so shift-clicking A then D then B gives A..D then A..B, which is what every
|
|
25
|
+
* list in every file manager does.
|
|
26
|
+
* - {@link primarySelection} is the LAST element — the most recently added path, and therefore the
|
|
27
|
+
* one the user just pointed at. Single-target surfaces address it.
|
|
28
|
+
*
|
|
29
|
+
* ## Structural batches
|
|
30
|
+
*
|
|
31
|
+
* A multi-node structural edit is one decision and must be one undo step, which `transactDoc`
|
|
32
|
+
* already gives for free — everything mutated inside one call is one history entry. What it does
|
|
33
|
+
* NOT give is index safety: removing `children/0` renumbers `children/1`, so a naive loop over the
|
|
34
|
+
* selection deletes the wrong nodes. {@link structuralBatch} answers that once — descendants
|
|
35
|
+
* dropped, then descending document order, so every splice happens below coordinates nothing later
|
|
36
|
+
* in the batch depends on.
|
|
37
|
+
*
|
|
38
|
+
* It also answers a second question the single-path world never had to ask: whether a selected path
|
|
39
|
+
* is a splice coordinate AT ALL. The Outline gives the document element, a repeater's map template
|
|
40
|
+
* and a `$switch` case rows of their own, and any of them can be ctrl-clicked into a selection
|
|
41
|
+
* beside an ordinary element. {@link isSpliceablePath} is the test, and it is the one thing
|
|
42
|
+
* standing between a mixed selection and a half-applied, unrecorded delete.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import type { JxPath } from "../state";
|
|
46
|
+
import { isAncestor, pathsEqual } from "../state";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The path single-target surfaces address — the most recently added, or `null` when empty.
|
|
50
|
+
*
|
|
51
|
+
* @param {readonly JxPath[] | null | undefined} selection
|
|
52
|
+
* @returns {JxPath | null}
|
|
53
|
+
*/
|
|
54
|
+
export function primarySelection(selection: readonly JxPath[] | null | undefined): JxPath | null {
|
|
55
|
+
return selection && selection.length > 0 ? (selection.at(-1) as JxPath) : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The path a shift-range extends from — the first in the list, or `null` when empty.
|
|
60
|
+
*
|
|
61
|
+
* @param {readonly JxPath[] | null | undefined} selection
|
|
62
|
+
* @returns {JxPath | null}
|
|
63
|
+
*/
|
|
64
|
+
export function selectionAnchor(selection: readonly JxPath[] | null | undefined): JxPath | null {
|
|
65
|
+
return selection && selection.length > 0 ? (selection[0] as JxPath) : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Whether `path` is one of the selected paths.
|
|
70
|
+
*
|
|
71
|
+
* @param {readonly JxPath[] | null | undefined} selection
|
|
72
|
+
* @param {JxPath | null} path
|
|
73
|
+
* @returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
export function isSelected(
|
|
76
|
+
selection: readonly JxPath[] | null | undefined,
|
|
77
|
+
path: JxPath | null,
|
|
78
|
+
): boolean {
|
|
79
|
+
if (!path || !selection) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return selection.some((p) => pathsEqual(p, path));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Copy a selection, so nothing can mutate one through the array it was handed.
|
|
87
|
+
*
|
|
88
|
+
* History entries and the collab awareness payload both take a copy for the same reason they always
|
|
89
|
+
* did: `session.selection` is a reactive proxy, and a stored reference to it would follow the live
|
|
90
|
+
* selection instead of recording where it was. (A third caller, the sub-document stack's frames,
|
|
91
|
+
* went with the stack — nothing pushes one any more.)
|
|
92
|
+
*
|
|
93
|
+
* @param {readonly JxPath[]} paths
|
|
94
|
+
* @returns {JxPath[]}
|
|
95
|
+
*/
|
|
96
|
+
export function cloneSelection(paths: readonly JxPath[]): JxPath[] {
|
|
97
|
+
return clonePaths(paths);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Copy a list of paths, so no caller can mutate a selection through the array it was handed. */
|
|
101
|
+
function clonePaths(paths: readonly JxPath[]): JxPath[] {
|
|
102
|
+
const out: JxPath[] = [];
|
|
103
|
+
for (const path of paths) {
|
|
104
|
+
out.push([...path]);
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Ctrl/Cmd-click: add the path when it is absent, remove it when it is present.
|
|
111
|
+
*
|
|
112
|
+
* Adding appends, so the newly clicked path becomes the primary and the anchor is untouched.
|
|
113
|
+
* Removing preserves the order of the survivors — including the anchor, unless the anchor is what
|
|
114
|
+
* was removed.
|
|
115
|
+
*
|
|
116
|
+
* @param {readonly JxPath[]} selection
|
|
117
|
+
* @param {JxPath} path
|
|
118
|
+
* @returns {JxPath[]}
|
|
119
|
+
*/
|
|
120
|
+
export function toggleSelected(selection: readonly JxPath[], path: JxPath): JxPath[] {
|
|
121
|
+
if (isSelected(selection, path)) {
|
|
122
|
+
return clonePaths(selection.filter((p) => !pathsEqual(p, path)));
|
|
123
|
+
}
|
|
124
|
+
return [...clonePaths(selection), [...path]];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Shift-click: the contiguous run of `rows` between the anchor and `target`, inclusive.
|
|
129
|
+
*
|
|
130
|
+
* `rows` is the surface's own visible order — the Outline's flattened, expansion-aware row list —
|
|
131
|
+
* because "the range between these two" is a question only the surface that draws them can answer.
|
|
132
|
+
* When the anchor is absent from `rows` (it was collapsed away, or nothing was selected) the range
|
|
133
|
+
* degenerates to `[target]`, which is a plain click.
|
|
134
|
+
*
|
|
135
|
+
* The returned list starts at the anchor end, so the anchor stays `selection[0]` and the target
|
|
136
|
+
* becomes the primary — a further shift-click re-extends from the same anchor.
|
|
137
|
+
*
|
|
138
|
+
* @param {readonly JxPath[]} rows Visible rows in display order.
|
|
139
|
+
* @param {JxPath | null} anchor
|
|
140
|
+
* @param {JxPath} target
|
|
141
|
+
* @returns {JxPath[]}
|
|
142
|
+
*/
|
|
143
|
+
export function rangeSelection(
|
|
144
|
+
rows: readonly JxPath[],
|
|
145
|
+
anchor: JxPath | null,
|
|
146
|
+
target: JxPath,
|
|
147
|
+
): JxPath[] {
|
|
148
|
+
const to = rows.findIndex((p) => pathsEqual(p, target));
|
|
149
|
+
const from = anchor ? rows.findIndex((p) => pathsEqual(p, anchor)) : -1;
|
|
150
|
+
if (to === -1 || from === -1) {
|
|
151
|
+
return [[...target]];
|
|
152
|
+
}
|
|
153
|
+
const slice = from <= to ? rows.slice(from, to + 1) : rows.slice(to, from + 1).toReversed();
|
|
154
|
+
return clonePaths(slice);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Drop every selected path that `removed` addresses or contains.
|
|
159
|
+
*
|
|
160
|
+
* This is `mutateRemoveNode`'s selection repair, widened: deleting a node used to clear the
|
|
161
|
+
* selection outright, and with a list it clears only the entries the deletion actually invalidated.
|
|
162
|
+
* A one-path selection therefore still ends up empty exactly when it used to.
|
|
163
|
+
*
|
|
164
|
+
* @param {readonly JxPath[]} selection
|
|
165
|
+
* @param {JxPath} removed
|
|
166
|
+
* @returns {JxPath[]}
|
|
167
|
+
*/
|
|
168
|
+
export function pruneSelection(selection: readonly JxPath[], removed: JxPath): JxPath[] {
|
|
169
|
+
return clonePaths(selection.filter((p) => !isAncestor(removed, p)));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Order two paths the way the document reads: parents before children, siblings by index.
|
|
174
|
+
*
|
|
175
|
+
* Segments are compared pairwise; numbers numerically (so `children/10` follows `children/9`), and
|
|
176
|
+
* anything else by string order. A prefix sorts before what extends it.
|
|
177
|
+
*
|
|
178
|
+
* @param {JxPath} a
|
|
179
|
+
* @param {JxPath} b
|
|
180
|
+
* @returns {number}
|
|
181
|
+
*/
|
|
182
|
+
export function comparePaths(a: JxPath, b: JxPath): number {
|
|
183
|
+
const len = Math.min(a.length, b.length);
|
|
184
|
+
for (let i = 0; i < len; i++) {
|
|
185
|
+
const x = a[i]!;
|
|
186
|
+
const y = b[i]!;
|
|
187
|
+
if (x === y) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (typeof x === "number" && typeof y === "number") {
|
|
191
|
+
return x - y;
|
|
192
|
+
}
|
|
193
|
+
return String(x) < String(y) ? -1 : 1;
|
|
194
|
+
}
|
|
195
|
+
return a.length - b.length;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Drop any path whose ancestor is also selected.
|
|
200
|
+
*
|
|
201
|
+
* Deleting a `<section>` and one of its own paragraphs is one deletion, not two: the paragraph goes
|
|
202
|
+
* with its parent, and a second splice into coordinates that no longer exist is how a batch
|
|
203
|
+
* corrupts a document.
|
|
204
|
+
*
|
|
205
|
+
* @param {readonly JxPath[]} selection
|
|
206
|
+
* @returns {JxPath[]}
|
|
207
|
+
*/
|
|
208
|
+
export function topLevelSelection(selection: readonly JxPath[]): JxPath[] {
|
|
209
|
+
return clonePaths(
|
|
210
|
+
selection.filter((p) => !selection.some((q) => !pathsEqual(q, p) && isAncestor(q, p))),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Whether `path` names a position a structural verb can splice — a tail of `"children"` + index.
|
|
216
|
+
*
|
|
217
|
+
* Every structural mutator (`mutateRemoveNode`, `mutateDuplicateNode`, `mutateWrapNode`) reaches
|
|
218
|
+
* its parent with `parentElementPath` — drop the last two segments — and its position with
|
|
219
|
+
* `childIndex` — take the last. That produces a splice coordinate for exactly one path shape, and
|
|
220
|
+
* the Outline emits three others as first-class rows: the document element (`[]`), a repeater's map
|
|
221
|
+
* template (`[…, "children", 1, "map"]`) and a `$switch` case (`[…, "cases", "warn"]`). For the
|
|
222
|
+
* template, `parentElementPath` resolves to the enclosing children ARRAY, whose `.children` is
|
|
223
|
+
* `undefined`, so the splice throws mid-transaction; for a case it splices at `NaN` and takes the
|
|
224
|
+
* wrong child.
|
|
225
|
+
*
|
|
226
|
+
* Selecting one of those beside an ordinary element is a single ctrl-click, so this is the
|
|
227
|
+
* invariant that keeps a batch from mutating the document and then throwing before anything is
|
|
228
|
+
* recorded.
|
|
229
|
+
*
|
|
230
|
+
* @param {JxPath} path
|
|
231
|
+
* @returns {boolean}
|
|
232
|
+
*/
|
|
233
|
+
export function isSpliceablePath(path: JxPath): boolean {
|
|
234
|
+
return path.at(-2) === "children" && typeof path.at(-1) === "number";
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The order a structural batch must run in: contained paths dropped, unspliceable paths dropped,
|
|
239
|
+
* then LAST node first.
|
|
240
|
+
*
|
|
241
|
+
* Descending document order is what makes a loop of splices safe. Removing or duplicating at index
|
|
242
|
+
* `n` renumbers every sibling after `n`, so a batch that starts at the end never touches a
|
|
243
|
+
* coordinate a later step still needs. It is also why duplicating a multi-selection inserts each
|
|
244
|
+
* clone directly after its own original instead of walking the whole run forward.
|
|
245
|
+
*
|
|
246
|
+
* Containment is decided BEFORE spliceability, on the selection the user actually made: a selected
|
|
247
|
+
* repeater template still shadows its own descendants, so selecting the template and something
|
|
248
|
+
* inside it yields nothing rather than quietly deleting the child the user never pointed at.
|
|
249
|
+
*
|
|
250
|
+
* @param {readonly JxPath[]} selection
|
|
251
|
+
* @returns {JxPath[]} Deepest/last first, every entry a splice coordinate.
|
|
252
|
+
*/
|
|
253
|
+
export function structuralBatch(selection: readonly JxPath[]): JxPath[] {
|
|
254
|
+
return topLevelSelection(selection)
|
|
255
|
+
.filter((path) => isSpliceablePath(path))
|
|
256
|
+
.toSorted((a, b) => comparePaths(b, a));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Deduplicate a list of paths, keeping the FIRST occurrence of each.
|
|
261
|
+
*
|
|
262
|
+
* Keeping the first is what makes `selection.setPaths` idempotent: passing the same list twice — or
|
|
263
|
+
* a list that names one node twice — always lands on the same selection, in the same order, with
|
|
264
|
+
* the same anchor and the same primary.
|
|
265
|
+
*
|
|
266
|
+
* @param {readonly JxPath[]} paths
|
|
267
|
+
* @returns {JxPath[]}
|
|
268
|
+
*/
|
|
269
|
+
export function uniquePaths(paths: readonly JxPath[]): JxPath[] {
|
|
270
|
+
const out: JxPath[] = [];
|
|
271
|
+
for (const path of paths) {
|
|
272
|
+
if (!out.some((p) => pathsEqual(p, path))) {
|
|
273
|
+
out.push([...path]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Whether two selections name the same paths in the same order.
|
|
281
|
+
*
|
|
282
|
+
* @param {readonly JxPath[] | null | undefined} a
|
|
283
|
+
* @param {readonly JxPath[] | null | undefined} b
|
|
284
|
+
* @returns {boolean}
|
|
285
|
+
*/
|
|
286
|
+
export function selectionsEqual(
|
|
287
|
+
a: readonly JxPath[] | null | undefined,
|
|
288
|
+
b: readonly JxPath[] | null | undefined,
|
|
289
|
+
): boolean {
|
|
290
|
+
const x = a ?? [];
|
|
291
|
+
const y = b ?? [];
|
|
292
|
+
return x.length === y.length && x.every((p, i) => pathsEqual(p, y[i] as JxPath));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Collapse one field's value across the selection into a single reading.
|
|
297
|
+
*
|
|
298
|
+
* `{ mixed: true }` is the answer the three inspector tabs render as the **Mixed** provenance
|
|
299
|
+
* state: the selected nodes disagree, so there is no one value to show and typing one would
|
|
300
|
+
* overwrite several different ones. `{ mixed: false, value }` is the answer when they agree — and
|
|
301
|
+
* when the selection is a single node it is ALWAYS that answer, which is why a single selection
|
|
302
|
+
* renders no Mixed state anywhere.
|
|
303
|
+
*
|
|
304
|
+
* Comparison is by JSON shape rather than reference: two nodes that both carry `{ $ref: "#/state/x"
|
|
305
|
+
* }` hold equal values written at different times.
|
|
306
|
+
*
|
|
307
|
+
* @template T
|
|
308
|
+
* @param {readonly T[]} values One per selected node, in selection order.
|
|
309
|
+
* @returns {{ mixed: boolean; value: T | undefined }}
|
|
310
|
+
*/
|
|
311
|
+
export function unifyValues<T>(values: readonly T[]): { mixed: boolean; value: T | undefined } {
|
|
312
|
+
if (values.length === 0) {
|
|
313
|
+
return { mixed: false, value: undefined };
|
|
314
|
+
}
|
|
315
|
+
const first = values[0] as T;
|
|
316
|
+
const key = JSON.stringify(first ?? null);
|
|
317
|
+
for (let i = 1; i < values.length; i++) {
|
|
318
|
+
if (JSON.stringify(values[i] ?? null) !== key) {
|
|
319
|
+
return { mixed: true, value: undefined };
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return { mixed: false, value: first };
|
|
323
|
+
}
|
package/src/tabs/tab.ts
CHANGED
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
import { effectScope, reactive } from "../reactivity";
|
|
3
3
|
import { formatByName, formatForPath } from "../format/format-host";
|
|
4
4
|
import { normalizeArrayChildren } from "../state";
|
|
5
|
-
import type {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
FunctionEditDef,
|
|
9
|
-
GitBranchesResult,
|
|
10
|
-
GitDiffState,
|
|
11
|
-
GitStatusResult,
|
|
12
|
-
InlineEditDef,
|
|
13
|
-
JsonValue,
|
|
14
|
-
} from "../types";
|
|
5
|
+
import type { FormulaEditDef, FunctionEditDef, InlineEditDef, JsonValue } from "../types";
|
|
6
|
+
import { editorKindForMode } from "../commands/context";
|
|
7
|
+
import type { EditorKind } from "../commands/context";
|
|
15
8
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
16
9
|
import type { JxDocOp, JxFmOp } from "./patch-ops";
|
|
17
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The project's configuration file, project-relative.
|
|
13
|
+
*
|
|
14
|
+
* Named here rather than at the four places that used to spell it, because it is a DOCUMENT PATH —
|
|
15
|
+
* `inferModes` answers `["stylebook", "source"]` for it (editor kind `config`), and
|
|
16
|
+
* `tabs/project-config.ts` binds the tab at this path as the configuration document.
|
|
17
|
+
*/
|
|
18
|
+
export const PROJECT_CONFIG_PATH = "project.json";
|
|
19
|
+
|
|
18
20
|
export interface TabUi {
|
|
19
21
|
rightTab: string;
|
|
20
22
|
canvasMode: string;
|
|
@@ -22,8 +24,6 @@ export interface TabUi {
|
|
|
22
24
|
preview: boolean;
|
|
23
25
|
/** Show elements inherited from the page's layout (pages with an effective layout only). */
|
|
24
26
|
showLayout: boolean;
|
|
25
|
-
/** Above-canvas frontmatter Properties accordion expanded (content-collection docs, edit mode). */
|
|
26
|
-
frontmatterOpen: boolean;
|
|
27
27
|
/** Chosen literal values for dynamic route params (e.g. { sku: "mini-trencher" }). */
|
|
28
28
|
previewParams: Record<string, string>;
|
|
29
29
|
/**
|
|
@@ -40,7 +40,7 @@ export interface TabUi {
|
|
|
40
40
|
activeMedia: string | null;
|
|
41
41
|
activeSelector: string | null;
|
|
42
42
|
editingFunction: FunctionEditDef | null;
|
|
43
|
-
/**
|
|
43
|
+
/** Logic-tab formula target ($expression editing); editingFunction wins if both are set. */
|
|
44
44
|
editingFormula: FormulaEditDef | null;
|
|
45
45
|
featureToggles: Record<string, boolean>;
|
|
46
46
|
/**
|
|
@@ -49,22 +49,40 @@ export interface TabUi {
|
|
|
49
49
|
* which scheme layer edits target.
|
|
50
50
|
*/
|
|
51
51
|
previewColorScheme: "auto" | "light" | "dark";
|
|
52
|
+
/**
|
|
53
|
+
* The locale this pane renders AS — the artboard's `lang` and `dir` (§13.4), never which file is
|
|
54
|
+
* open.
|
|
55
|
+
*
|
|
56
|
+
* Jx has no message catalogue: a translation is a different file in a different directory, so
|
|
57
|
+
* "show this page in French" is a navigation and belongs to the locale preset. This axis is the
|
|
58
|
+
* other half — the rendering context a document is _drawn_ under, which is how an author sees
|
|
59
|
+
* their layout mirror under an RTL locale without leaving the document they are editing.
|
|
60
|
+
*
|
|
61
|
+
* `null` is "the document's own language", resolved from its path at render time rather than
|
|
62
|
+
* baked in here: a file moved into `pages/fr/` must change what the pane draws, and a stored tag
|
|
63
|
+
* would go on claiming the language the file used to be in.
|
|
64
|
+
*/
|
|
65
|
+
previewLocale: string | null;
|
|
52
66
|
styleSections: Record<string, boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Which Data rows have their editor and value open, by state-entry name.
|
|
69
|
+
*
|
|
70
|
+
* PER TAB, and a set rather than a single name: comparing two entries means seeing both at once,
|
|
71
|
+
* and coming back to a tab means finding it as you left it. It was one module-global string
|
|
72
|
+
* (`expandedSignal`) plus one module-global Set (`expandedDataKeys`) — two answers to one
|
|
73
|
+
* question, both shared across every open document.
|
|
74
|
+
*/
|
|
75
|
+
dataRows: Record<string, boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* How far each truncation marker in a Data row's value tree has been opened, keyed by tree path.
|
|
78
|
+
*
|
|
79
|
+
* PER TAB, for the reason `dataRows` is: the paths are entry names, and a module-global record
|
|
80
|
+
* would have applied "show 50 more of `listings`" to a different document's `listings`.
|
|
81
|
+
*/
|
|
82
|
+
dataLimits: Record<string, number>;
|
|
53
83
|
inspectorSections: Record<string, boolean>;
|
|
54
84
|
styleShorthands: Record<string, boolean>;
|
|
55
85
|
styleFilter: string;
|
|
56
|
-
styleFilterActive: boolean;
|
|
57
|
-
stylebookSelection: string | null;
|
|
58
|
-
stylebookTab: string;
|
|
59
|
-
stylebookFilter: string;
|
|
60
|
-
stylebookCustomizedOnly: boolean;
|
|
61
|
-
settingsTab: string;
|
|
62
|
-
gitStatus: GitStatusResult | null;
|
|
63
|
-
gitBranches: GitBranchesResult | null;
|
|
64
|
-
gitCommitMessage: string;
|
|
65
|
-
gitLoading: boolean;
|
|
66
|
-
gitError: string | null;
|
|
67
|
-
gitDiffState: GitDiffState | null;
|
|
68
86
|
pendingInlineEdit: InlineEditDef | null;
|
|
69
87
|
}
|
|
70
88
|
|
|
@@ -83,10 +101,10 @@ export interface StoredLivePreview {
|
|
|
83
101
|
interface HistorySnapshot {
|
|
84
102
|
/** Full document at this state (checkpoint), or null when the ops describe the transition. */
|
|
85
103
|
document: Record<string, unknown> | null;
|
|
86
|
-
/** Selection after this state's transaction. */
|
|
87
|
-
selection: (string | number)[]
|
|
104
|
+
/** Selection after this state's transaction — the whole set, so a batch undoes back to it. */
|
|
105
|
+
selection: (string | number)[][];
|
|
88
106
|
/** Selection before this state's transaction (restored on surgical undo). */
|
|
89
|
-
selectionBefore?: (string | number)[]
|
|
107
|
+
selectionBefore?: (string | number)[][];
|
|
90
108
|
/** Replayable ops transforming the previous state into this one. */
|
|
91
109
|
forwardOps?: JxDocOp[] | null;
|
|
92
110
|
/** Replayable ops transforming this state back into the previous one. */
|
|
@@ -103,11 +121,34 @@ interface HistorySnapshot {
|
|
|
103
121
|
coalesceKey?: string | null;
|
|
104
122
|
}
|
|
105
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Where a tab was drilled in FROM — a relationship, not a navigation stack.
|
|
126
|
+
*
|
|
127
|
+
* Drilling into a component opens a real tab of its own (see `workspace/workspace.ts`), so the old
|
|
128
|
+
* "swap the document under the same tab id" breadcrumb is gone. What survives is this: the tab
|
|
129
|
+
* remembers which document sent the author here, and the tab strip prints it. Nothing restores from
|
|
130
|
+
* it, nothing pops it — closing the parent leaves the child perfectly usable.
|
|
131
|
+
*/
|
|
132
|
+
export interface TabOrigin {
|
|
133
|
+
/** Id of the tab the author drilled in from. */
|
|
134
|
+
tabId: string;
|
|
135
|
+
/** That tab's document path at the moment of the drill-in — what the strip prints. */
|
|
136
|
+
documentPath: string | null;
|
|
137
|
+
}
|
|
138
|
+
|
|
106
139
|
export interface Tab {
|
|
107
140
|
id: string;
|
|
108
141
|
documentPath: string | null;
|
|
109
142
|
fileHandle: FileSystemFileHandle | null;
|
|
110
143
|
capabilities: { modes: string[] };
|
|
144
|
+
/** Pinned tabs hold the head of their pane's strip, and a preview open never takes their slot. */
|
|
145
|
+
pinned: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* A PREVIEW tab is disposable: the next preview open in the same pane replaces it, and it renders
|
|
148
|
+
* italic to say so. It stops being one the moment the author commits to it — an edit, a pin, a
|
|
149
|
+
* double-click. The palette's `@`/`#` modes make browsing cheap, and browsing must not litter.
|
|
150
|
+
*/
|
|
151
|
+
preview: boolean;
|
|
111
152
|
scope: {
|
|
112
153
|
stop: () => void;
|
|
113
154
|
run: <T>(fn: () => T) => T | undefined;
|
|
@@ -122,13 +163,33 @@ export interface Tab {
|
|
|
122
163
|
dirty: boolean;
|
|
123
164
|
};
|
|
124
165
|
session: {
|
|
125
|
-
|
|
166
|
+
/**
|
|
167
|
+
* The selected document paths, in the order the user built them (§6.5).
|
|
168
|
+
*
|
|
169
|
+
* `[]` is "nothing selected" — there is no `null` state, because "no selection" and "a
|
|
170
|
+
* selection of nothing" were never two different things. `selection[0]` is the anchor a
|
|
171
|
+
* shift-range extends from; the LAST entry is the primary, which every single-target surface
|
|
172
|
+
* reads through `tabs/selection.ts`'s `primarySelection`. **Always assign a fresh array**:
|
|
173
|
+
* several render effects track this with a bare property read and would miss an in-place push.
|
|
174
|
+
*/
|
|
175
|
+
selection: (string | number)[][];
|
|
126
176
|
hover: (string | number)[] | null;
|
|
127
177
|
clipboard: JxMutableNode | null;
|
|
128
|
-
|
|
178
|
+
/** The document this tab was drilled in from, if any. Rendered by the tab strip. */
|
|
179
|
+
openedFrom: TabOrigin | null;
|
|
129
180
|
ui: TabUi;
|
|
130
181
|
canvas: {
|
|
131
182
|
status: string;
|
|
183
|
+
/**
|
|
184
|
+
* A Refresh is out and the snapshot below has not come back yet.
|
|
185
|
+
*
|
|
186
|
+
* The button used to guess: fire the re-render, then `setTimeout(…, 200)` and repaint,
|
|
187
|
+
* because nothing told the panel when the values had actually changed. A fetch slower than
|
|
188
|
+
* 200ms repainted the OLD values and looked like a Refresh that did nothing. The iframe posts
|
|
189
|
+
* `dataScope` when the render resolves, so the honest answer is to say "refreshing" until it
|
|
190
|
+
* arrives and let the arrival be the repaint.
|
|
191
|
+
*/
|
|
192
|
+
refreshing: boolean;
|
|
132
193
|
// A serializable snapshot of the iframe's resolved `$defs` (data-source values), posted over
|
|
133
194
|
// The bridge as a `dataScope` message and read by the data-explorer panel. Plain data now —
|
|
134
195
|
// The old live `EffectScope` (with `.stop()`) moved into the iframe realm with buildScope.
|
|
@@ -160,30 +221,20 @@ function createDefaultUi(canvasMode: string, preview = false) {
|
|
|
160
221
|
editingFormula: null,
|
|
161
222
|
editingFunction: null,
|
|
162
223
|
featureToggles: {},
|
|
163
|
-
frontmatterOpen: true,
|
|
164
|
-
gitBranches: null,
|
|
165
|
-
gitCommitMessage: "",
|
|
166
|
-
gitDiffState: null,
|
|
167
|
-
gitError: null,
|
|
168
|
-
gitLoading: false,
|
|
169
|
-
gitStatus: null,
|
|
170
224
|
inspectorSections: {},
|
|
171
225
|
pendingInlineEdit: null,
|
|
172
226
|
preview,
|
|
173
227
|
previewColorScheme: "auto" as const,
|
|
228
|
+
previewLocale: null as string | null,
|
|
174
229
|
previewParams: {},
|
|
175
230
|
previewProps: null,
|
|
176
231
|
rightTab: "properties",
|
|
177
|
-
settingsTab: "stylebook",
|
|
178
232
|
showLayout: true,
|
|
179
233
|
styleFilter: "",
|
|
180
|
-
styleFilterActive: false,
|
|
181
234
|
styleSections: {},
|
|
235
|
+
dataRows: {},
|
|
236
|
+
dataLimits: {},
|
|
182
237
|
styleShorthands: {},
|
|
183
|
-
stylebookCustomizedOnly: false,
|
|
184
|
-
stylebookFilter: "",
|
|
185
|
-
stylebookSelection: null,
|
|
186
|
-
stylebookTab: "elements",
|
|
187
238
|
zoom: 1,
|
|
188
239
|
};
|
|
189
240
|
}
|
|
@@ -201,6 +252,8 @@ const ALL_MODES = ["edit", "design", "preview", "source", "stylebook"];
|
|
|
201
252
|
* frontmatter?: Record<string, unknown>;
|
|
202
253
|
* sourceFormat?: string | null;
|
|
203
254
|
* capabilities?: { modes?: string[] };
|
|
255
|
+
* openedFrom?: TabOrigin | null;
|
|
256
|
+
* preview?: boolean;
|
|
204
257
|
* }} opts
|
|
205
258
|
* @returns {Tab}
|
|
206
259
|
*/
|
|
@@ -212,6 +265,8 @@ export function createTab({
|
|
|
212
265
|
frontmatter,
|
|
213
266
|
sourceFormat = null,
|
|
214
267
|
capabilities,
|
|
268
|
+
openedFrom = null,
|
|
269
|
+
preview: previewTab = false,
|
|
215
270
|
}: {
|
|
216
271
|
id: string;
|
|
217
272
|
documentPath?: string | null;
|
|
@@ -220,6 +275,8 @@ export function createTab({
|
|
|
220
275
|
frontmatter?: Record<string, unknown>;
|
|
221
276
|
sourceFormat?: string | null;
|
|
222
277
|
capabilities?: { modes?: string[] };
|
|
278
|
+
openedFrom?: TabOrigin | null;
|
|
279
|
+
preview?: boolean;
|
|
223
280
|
}) {
|
|
224
281
|
const scope = effectScope();
|
|
225
282
|
|
|
@@ -249,12 +306,15 @@ export function createTab({
|
|
|
249
306
|
fileHandle,
|
|
250
307
|
history: reactive({
|
|
251
308
|
index: 0,
|
|
252
|
-
snapshots: [{ document: structuredClone(document), selection:
|
|
309
|
+
snapshots: [{ document: structuredClone(document), selection: [] }],
|
|
253
310
|
}),
|
|
254
311
|
id,
|
|
312
|
+
pinned: false,
|
|
313
|
+
preview: previewTab,
|
|
255
314
|
scope,
|
|
256
315
|
session: reactive({
|
|
257
316
|
canvas: {
|
|
317
|
+
refreshing: false,
|
|
258
318
|
error: null,
|
|
259
319
|
livePreviews: null,
|
|
260
320
|
pendingInlineEdit: null,
|
|
@@ -262,9 +322,9 @@ export function createTab({
|
|
|
262
322
|
status: "idle",
|
|
263
323
|
},
|
|
264
324
|
clipboard: null,
|
|
265
|
-
documentStack: [],
|
|
266
325
|
hover: null,
|
|
267
|
-
|
|
326
|
+
openedFrom,
|
|
327
|
+
selection: [],
|
|
268
328
|
ui: createDefaultUi(initialCanvasMode, initialPreview),
|
|
269
329
|
}),
|
|
270
330
|
})) as unknown as Tab;
|
|
@@ -281,7 +341,7 @@ export function createTab({
|
|
|
281
341
|
* @returns {string[]}
|
|
282
342
|
*/
|
|
283
343
|
function inferModes(documentPath: string | null | undefined, sourceFormat: string | null) {
|
|
284
|
-
if (documentPath ===
|
|
344
|
+
if (documentPath === PROJECT_CONFIG_PATH) {
|
|
285
345
|
return ["stylebook", "source"];
|
|
286
346
|
}
|
|
287
347
|
const format = formatByName(sourceFormat) ?? formatForPath(documentPath);
|
|
@@ -307,6 +367,81 @@ function inferDocumentMode(documentPath: string | null | undefined, sourceFormat
|
|
|
307
367
|
return "component";
|
|
308
368
|
}
|
|
309
369
|
|
|
370
|
+
// ─── Editor kinds ─────────────────────────────────────────────────────────────
|
|
371
|
+
// §4.2's first axis. `canvasMode` conflates two orthogonal questions — WHICH EDITOR is open, and
|
|
372
|
+
// (for the Canvas editor only) WHICH VIEW of it. The pane context bar labels them separately, and
|
|
373
|
+
// The pane model needs the first one on its own: the second pane is capped to non-Canvas kinds
|
|
374
|
+
// Until P8's `canvas-patcher` fan-out lands, because a second live `@jxsuite/runtime` host is the
|
|
375
|
+
// Expensive part.
|
|
376
|
+
//
|
|
377
|
+
// The mode → kind map itself is `commands/context.ts`'s `editorKindForMode`. It was duplicated
|
|
378
|
+
// Here, and the copy that drifted is what let a settings document resolve into the canvas key
|
|
379
|
+
// Scope; the pane model and the command context now read the same table.
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* The editor kind a tab is currently showing. Reads the BASE mode: the preview toggle is a value on
|
|
383
|
+
* the Canvas view axis, not a different editor.
|
|
384
|
+
*
|
|
385
|
+
* @param {Tab} tab
|
|
386
|
+
* @returns {EditorKind}
|
|
387
|
+
*/
|
|
388
|
+
export function editorKindOf(tab: Tab): EditorKind {
|
|
389
|
+
return editorKindForMode(tab.session.ui.canvasMode);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Every editor kind this document supports, in the format's own mode order and deduplicated — the
|
|
394
|
+
* dropdown's entries, so it can never contain a permanently dead one (§4.2).
|
|
395
|
+
*
|
|
396
|
+
* `preview` contributes nothing: it is a Canvas VIEW, and the kind it would add is already there.
|
|
397
|
+
*
|
|
398
|
+
* @param {Tab} tab
|
|
399
|
+
* @returns {EditorKind[]}
|
|
400
|
+
*/
|
|
401
|
+
export function editorKindsOf(tab: Tab): EditorKind[] {
|
|
402
|
+
const kinds: EditorKind[] = [];
|
|
403
|
+
for (const mode of tab.capabilities.modes) {
|
|
404
|
+
if (mode === "preview") {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const kind = editorKindForMode(mode);
|
|
408
|
+
if (!kinds.includes(kind)) {
|
|
409
|
+
kinds.push(kind);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return kinds;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* The first mode this tab supports that renders `kind`, or `undefined` when it supports none.
|
|
417
|
+
*
|
|
418
|
+
* The inverse of {@link editorKindOf}: choosing an editor kind has to land on a real `canvasMode`,
|
|
419
|
+
* because that string is what the canvas render message carries.
|
|
420
|
+
*
|
|
421
|
+
* @param {Tab} tab
|
|
422
|
+
* @param {EditorKind} kind
|
|
423
|
+
* @returns {string | undefined}
|
|
424
|
+
*/
|
|
425
|
+
export function modeForEditorKind(tab: Tab, kind: EditorKind): string | undefined {
|
|
426
|
+
return tab.capabilities.modes.find(
|
|
427
|
+
(mode) => mode !== "preview" && editorKindForMode(mode) === kind,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ─── There is no sub-document stack ───────────────────────────────────────────
|
|
432
|
+
// A tab held one, and it was scaffolding for a navigation model the tab model replaced. `studio.md`
|
|
433
|
+
// §14.3 justified it for exactly two cases and both moved: a function body opens in the Bottom
|
|
434
|
+
// Dock's Logic tab (P8), and a `$map` template is a subtree of its parent document, selected in
|
|
435
|
+
// Place on the canvas rather than loaded as a document of its own. Everything with a file of its
|
|
436
|
+
// Own — a component, a layout — opens a REAL TAB with an `openedFrom` relationship (§14.1–2):
|
|
437
|
+
// {@link TabOrigin}, above, which nothing pops and nothing restores from.
|
|
438
|
+
//
|
|
439
|
+
// So `pushSubDocument` had no caller in `src/`, the stack was permanently `[]`, and every reader
|
|
440
|
+
// Below it — `popSubDocument`, `popToSubDocument`, the UI capture/restore pair, the pane-context
|
|
441
|
+
// Breadcrumb, the jump bar's `subdocument` segment, `document.setStackLevel`, collab's `drilled`
|
|
442
|
+
// Guard — was live code that could only ever take its empty branch. They are gone together: a
|
|
443
|
+
// Stack with no way in is not an unfinished feature, it is a shape the design moved past.
|
|
444
|
+
|
|
310
445
|
/**
|
|
311
446
|
* Dispose a tab — stops its effectScope, killing all effects created within it.
|
|
312
447
|
*
|