@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,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../schema/src/ijson.ts", "../../schema/src/parse.ts", "../../schema/src/locale.ts", "../../../node_modules/@vue/shared/dist/shared.esm-bundler.js", "../../../node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js", "../src/services/clock.ts", "../src/ui/regions.ts", "../src/services/announce.ts", "../src/services/notify.ts", "../src/view.ts", "../src/canvas/surface-registry.ts", "../src/services/monaco-buffer.ts", "../src/tabs/selection.ts", "../src/utils/studio-utils.ts", "../src/tabs/patch-ops.ts", "../src/tabs/transact.ts", "../src/commands/active-registry.ts", "../src/ui/layers.ts", "../src/collab/collab-state.ts", "../src/commands/context.ts", "../src/tabs/tab.ts", "../src/collab/collab-session.ts", "../src/commands/command-args.ts", "../src/workspace/workspace.ts", "../src/workspace/session.ts", "../src/services/profile.ts", "../src/shell.ts", "../src/tabs/project-config.ts", "../src/site-context.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * I-JSON (RFC 7493): the two ways a JSON document can parse cleanly and still mean something other\n * than what it says.\n *\n * Both matter here more than they would elsewhere, because a Jx document does not stay JSON. It\n * round-trips through markdown frontmatter and through a Yjs CRDT, and each crossing rebuilds the\n * object from the parsed value — so anything `JSON.parse` quietly discarded is discarded for good,\n * and the file the author reopens is not the file they wrote.\n *\n * - **Duplicate names** (§2.3). `JSON.parse` keeps the last and says nothing. In a hand-edited\n * document — two `state` keys after a bad merge, say — the first one's contents simply vanish.\n * - **Numbers outside the IEEE 754 double range** (§2.2). `9007199254740993` parses to\n * `9007199254740992`, and the next serialization writes the wrong number back to disk.\n *\n * Implemented as a scan of the source text rather than a `JSON.parse` reviver, because by the time\n * a reviver runs the duplicate is already gone. The scanner is deliberately small: it only needs to\n * know where strings and object keys are, so it does not build a tree or validate the grammar —\n * `JSON.parse` has already done that by the time this is called.\n *\n * @docs framework/agents/authoring-rules\n */\n\n/** One I-JSON violation, located by the path of the object that contains it. */\nexport interface IJsonProblem {\n kind: \"duplicate-key\" | \"unsafe-number\";\n /** Dotted path to the containing object, `\"\"` at the root. */\n path: string;\n /** The duplicated key, or the number literal as written. */\n detail: string;\n}\n\nconst WHITESPACE = new Set([\" \", \"\\t\", \"\\n\", \"\\r\"]);\n\n/**\n * Find I-JSON violations in already-valid JSON text.\n *\n * @param {string} text - JSON source that `JSON.parse` accepts\n * @returns {IJsonProblem[]} Empty when the document is I-JSON\n */\nexport function findIJsonProblems(text: string): IJsonProblem[] {\n const problems: IJsonProblem[] = [];\n /**\n * One frame per open `{` or `[`. Arrays carry a path too, so an object inside one is reported\n * under the key that names the array rather than under whatever enclosed it.\n */\n const stack: { kind: \"object\" | \"array\"; path: string; keys?: Set<string> }[] = [];\n /** The key most recently read, naming the value that follows it. */\n let pendingKey: string | null = null;\n let index = 0;\n\n const currentPath = () => stack.at(-1)?.path ?? \"\";\n const childPath = () =>\n pendingKey === null ? currentPath() : joinPath(currentPath(), pendingKey);\n\n const readString = (): string => {\n // Assumes text[index] === '\"'; returns the decoded value and leaves index past the closer.\n index += 1;\n let out = \"\";\n while (index < text.length) {\n const char = text[index]!;\n if (char === \"\\\\\") {\n const next = text[index + 1] ?? \"\";\n // Only `\\uXXXX` needs decoding to compare keys correctly; the rest map one-to-one.\n if (next === \"u\") {\n out += String.fromCodePoint(Number.parseInt(text.slice(index + 2, index + 6), 16));\n index += 6;\n } else {\n out += ESCAPES[next] ?? next;\n index += 2;\n }\n continue;\n }\n if (char === '\"') {\n index += 1;\n return out;\n }\n out += char;\n index += 1;\n }\n return out;\n };\n\n while (index < text.length) {\n const char = text[index]!;\n\n if (WHITESPACE.has(char) || char === \",\" || char === \":\") {\n index += 1;\n continue;\n }\n\n if (char === \"{\" || char === \"[\") {\n stack.push(\n char === \"{\"\n ? { keys: new Set(), kind: \"object\", path: childPath() }\n : { kind: \"array\", path: childPath() },\n );\n pendingKey = null;\n index += 1;\n continue;\n }\n if (char === \"}\" || char === \"]\") {\n stack.pop();\n pendingKey = null;\n index += 1;\n continue;\n }\n\n if (char === '\"') {\n const value = readString();\n /*\n * A string is a key when it sits directly inside an object and a `:` follows. Inside an\n * array it is an element, and the same text on the right of a `:` is a value.\n */\n const frame = stack.at(-1);\n if (frame?.kind === \"object\" && nextMeaningful(text, index) === \":\") {\n if (frame.keys!.has(value)) {\n problems.push({ detail: value, kind: \"duplicate-key\", path: frame.path });\n }\n frame.keys!.add(value);\n pendingKey = value;\n } else {\n pendingKey = null;\n }\n continue;\n }\n\n if (char === \"-\" || (char >= \"0\" && char <= \"9\")) {\n const start = index;\n while (index < text.length && /[\\d+.eE-]/.test(text[index]!)) {\n index += 1;\n }\n const literal = text.slice(start, index);\n if (!isSafeJsonNumber(literal)) {\n problems.push({ detail: literal, kind: \"unsafe-number\", path: childPath() });\n }\n pendingKey = null;\n continue;\n }\n\n // `true`, `false`, `null`. The grammar is already known good, so a run of letters is enough.\n const before = index;\n while (index < text.length && /[A-Za-z]/.test(text[index]!)) {\n index += 1;\n }\n if (index === before) {\n index += 1;\n }\n pendingKey = null;\n }\n\n return problems;\n}\n\nconst ESCAPES: Record<string, string> = {\n b: \"\\b\",\n f: \"\\f\",\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n};\n\n/** The next non-whitespace character at or after `from`, or \"\" at the end. */\nfunction nextMeaningful(text: string, from: number): string {\n let index = from;\n while (index < text.length && WHITESPACE.has(text[index]!)) {\n index += 1;\n }\n return text[index] ?? \"\";\n}\n\nfunction joinPath(parent: string, key: string): string {\n return parent === \"\" ? key : `${parent}.${key}`;\n}\n\n/**\n * True when a number literal survives a round trip through a double.\n *\n * Only integers are judged. A fractional literal is _always_ approximate in binary floating point —\n * `0.1` is not representable either — so flagging those would flag most real documents and say\n * nothing about whether the author's value survived.\n *\n * @param {string} literal\n * @returns {boolean}\n */\nexport function isSafeJsonNumber(literal: string): boolean {\n if (/[.eE]/.test(literal)) {\n return true;\n }\n const value = Number(literal);\n if (!Number.isFinite(value)) {\n return false;\n }\n // The literal is an integer, so `String(Number(x))` reproduces it exactly when nothing was lost.\n return String(value) === literal.replace(/^\\+/, \"\");\n}\n\n/** A one-line description of a problem, for a build error or a warning. */\nexport function describeIJsonProblem(problem: IJsonProblem): string {\n const where = problem.path === \"\" ? \"the document root\" : `\"${problem.path}\"`;\n return problem.kind === \"duplicate-key\"\n ? `duplicate key \"${problem.detail}\" in ${where} — JSON.parse keeps the last one and ` +\n \"silently discards the first (RFC 7493 §2.3)\"\n : `number ${problem.detail} in ${where} cannot be represented exactly and will change when ` +\n \"the document is written back (RFC 7493 §2.2)\";\n}\n",
|
|
6
|
+
"/**\n * Typed parse boundary for Jx documents and configs.\n *\n * Raw `JSON.parse()` returns `any`, which silently disables checking for everything downstream.\n * These helpers are the single sanctioned crossing point: they parse, structurally verify, and\n * return the domain type — failures carry the source path.\n *\n * Being the single crossing point is also what makes it the right place to enforce I-JSON (RFC\n * 7493). `JSON.parse` accepts documents that mean something other than what they say — a repeated\n * key whose first value it discards, an integer it rounds — and a Jx document does not stay JSON:\n * it round-trips through markdown frontmatter and a CRDT, each rebuilding the object from the\n * parsed value. Whatever was dropped here is dropped for good.\n *\n * It is also where identifiers are normalized (UAX #31 §R4), for the same reason: a name that means\n * one thing on one keyboard and another thing on another is a defect nothing downstream can see.\n */\n\nimport type { JxClassDef, JxDocument, ProjectConfig } from \"../types\";\nimport { isJsonObject } from \"./guards\";\nimport { describeIJsonProblem, findIJsonProblems } from \"./ijson\";\n\n// ─── Error helpers ──────────────────────────────────────────────────────────────\n\n/** Extract a human-readable message from a caught `unknown`. */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/** Coerce a caught `unknown` to an Error without losing the original. */\nexport function toError(e: unknown): Error {\n return e instanceof Error ? e : new Error(String(e));\n}\n\n// ─── Unicode normalization ──────────────────────────────────────────────────────\n\n/**\n * Text outside ASCII, which is the only text whose normalization form can differ. Testing for it\n * first keeps this walk close to free on the pure-ASCII documents that are almost all of them.\n */\nconst NON_ASCII = /[^\\p{ASCII}]/u;\n\n/**\n * Recursively put every key and every string value into Normalization Form C.\n *\n * **The defect this fixes.** A state name is an identifier: `\"état\"` declared in `state`,\n * referenced as `${state.état}` in a template and as `#/state/état` in a `$ref`. Typed on macOS it\n * arrives decomposed (`e` + U+0301); typed on Windows or pasted from most of the web it arrives\n * precomposed (U+00E9). Those are two different JavaScript property names, so a document whose\n * declaration and reference were typed on different machines builds cleanly, emits a valid bundle,\n * and renders nothing — `state.état` is simply `undefined`. There is no error to see and no symptom\n * to search for. UAX #31 §R4 exists for exactly this, and NFC is the form the web platform assumes\n * everywhere else.\n *\n * **Why values are normalized too, and why that is not a content change.** Two canonically\n * equivalent strings are, by the definition in UAX #15, the same text: a conforming renderer must\n * display them identically, and no process may distinguish them. So normalizing a `textContent` is\n * a no-op for meaning. It is also unavoidable, because Jx has no syntactic boundary between content\n * and code — `\"Café ${state.été}\"` is one string carrying both, and normalizing only \"identifier\n * positions\" would mean parsing every template to find them.\n *\n * **Why here and not on the source text.** `\"état\"` is pure ASCII until `JSON.parse` turns the\n * escape into a combining mark, so normalizing the raw text would miss exactly the documents a\n * generator wrote.\n *\n * @param {unknown} value - Any parsed JSON value\n * @returns {unknown} The same shape, with all text in NFC\n */\nfunction normalizeIdentifiers(value: unknown): unknown {\n if (typeof value === \"string\") {\n return NON_ASCII.test(value) ? value.normalize(\"NFC\") : value;\n }\n if (Array.isArray(value)) {\n return value.map((item) => normalizeIdentifiers(item));\n }\n if (isJsonObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n /*\n * A later key wins on collision, matching what `JSON.parse` does with a literal duplicate.\n * It cannot happen through this boundary — I-JSON already rejected duplicate keys, and two\n * keys differing only by normalization form are not duplicates to `JSON.parse` — so this is\n * a statement about which is authoritative rather than a branch anything reaches.\n */\n out[NON_ASCII.test(key) ? key.normalize(\"NFC\") : key] = normalizeIdentifiers(entry);\n }\n return out;\n }\n return value;\n}\n\n// ─── Parse helpers ──────────────────────────────────────────────────────────────\n\nfunction parseObject(text: string, sourcePath: string, what: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n throw new Error(`Failed to parse ${what} at ${sourcePath}: ${errorMessage(error)}`, {\n cause: error,\n });\n }\n if (!isJsonObject(parsed)) {\n throw new Error(`Invalid ${what} at ${sourcePath}: expected a JSON object`);\n }\n /*\n * An error rather than a warning, because both problems are silent data loss and neither has a\n * reading under which the author got what they wrote. The whole repository — 375 documents —\n * was already clean when this landed, so this rejects mistakes rather than existing work.\n */\n const problems = findIJsonProblems(text);\n if (problems.length > 0) {\n const described = problems.map((problem) => describeIJsonProblem(problem)).join(\"; \");\n throw new Error(`Invalid ${what} at ${sourcePath}: ${described}`);\n }\n return normalizeIdentifiers(parsed) as Record<string, unknown>;\n}\n\n/** Parse a Jx document (.json page/layout/component source). */\nexport function parseJxDocument(text: string, sourcePath: string): JxDocument {\n return parseObject(text, sourcePath, \"Jx document\") as JxDocument;\n}\n\n/** Parse a project.json site configuration. */\nexport function parseProjectConfig(text: string, sourcePath: string): ProjectConfig {\n return parseObject(text, sourcePath, \"project config\") as ProjectConfig;\n}\n\n/**\n * Parse a .class.json schema-defined class. Note: `$prototype: \"Class\"` is the canonical\n * discriminator but is not required — existing class files omit it.\n */\nexport function parseClassDef(text: string, sourcePath: string): JxClassDef {\n return parseObject(text, sourcePath, \"class definition\") as unknown as JxClassDef;\n}\n",
|
|
7
|
+
"/**\n * BCP 47 language tags: well-formedness, canonical case, and writing direction.\n *\n * One implementation for the repo — `i18n.locales`, a document's `$lang`, and anything else that\n * accepts a language tag all come through here, so a tag that builds in one place cannot fail in\n * another.\n *\n * The grammar and the case conventions come from `Intl.Locale`, which is ECMA-402's parser for\n * exactly this and is already in every runtime Jx targets. Note what that does and does not buy:\n * `Intl.Locale` enforces the RFC 5646 **grammar**, so `en_US` and `en--US` are rejected, but it\n * does not consult the IANA registry, so `zz` and `xx-YY` are well-formed tags for languages that\n * do not exist. Registry membership is not checked here either; a typo'd region is the author's to\n * catch.\n *\n * Pure string math and `Intl` — no node imports — so browser hosts can import this module.\n *\n * @docs framework/site/i18n\n */\n\n/* Type-only, so this module still imports nothing at runtime and a browser host can load it. */\nimport type { ProjectConfig } from \"../types.ts\";\n\n/**\n * Scripts written right to left (ISO 15924, per UAX #9).\n *\n * Direction is decided by **script**, not by language, and not by `Intl.Locale`'s own\n * `getTextInfo()`. That method answers from the language's CLDR entry, which gets two ordinary\n * cases wrong: `dv` (Dhivehi, written in Thaana) reports `ltr` where an ICU build lacks its data,\n * and `az-Arab` — Azerbaijani deliberately written in the Arabic script — reports `ltr` because the\n * language's default script is Latin. Maximizing the tag and reading the script is right in both.\n */\nconst RTL_SCRIPTS = new Set([\n \"Adlm\",\n \"Arab\",\n \"Aran\",\n \"Armi\",\n \"Avst\",\n \"Cprt\",\n \"Egyd\",\n \"Egyh\",\n \"Elym\",\n \"Gara\",\n \"Hatr\",\n \"Hebr\",\n \"Hluw\",\n \"Hung\",\n \"Khar\",\n \"Lydi\",\n \"Mand\",\n \"Mani\",\n \"Mend\",\n \"Merc\",\n \"Mero\",\n \"Narb\",\n \"Nbat\",\n \"Nkoo\",\n \"Orkh\",\n \"Palm\",\n \"Phli\",\n \"Phlp\",\n \"Phnx\",\n \"Prti\",\n \"Rohg\",\n \"Samr\",\n \"Sarb\",\n \"Sogd\",\n \"Sogo\",\n \"Syrc\",\n \"Thaa\",\n \"Todr\",\n \"Yezi\",\n]);\n\n/** Writing direction of a language tag's text. */\nexport type TextDirection = \"ltr\" | \"rtl\";\n\n/**\n * The shape of a language tag, as a regular expression a JSON Schema `pattern` can hold.\n *\n * Deliberately **looser** than {@link canonicalizeLocale}, and deliberately not RFC 5646's grammar.\n * That grammar distinguishes subtags by length _and_ position, and admits grandfathered and\n * private-use forms (`i-klingon`, `x-whatever`); a regex encoding all of it would be unreadable and\n * still wrong at the edges. What this catches is the class of mistake an author actually makes — an\n * underscore where a hyphen belongs (`en_US`), an empty subtag (`en--US`, `en-US-`), a one-letter\n * primary language, a subtag past eight characters.\n *\n * The direction of the inequality is the contract: this accepts **every** tag `Intl.Locale`\n * accepts, so a value the build canonicalizes can never fail `jx validate`. The reverse is allowed\n * and expected — `zh-min-nan` matches here and throws there — because the build stays the authority\n * on well-formedness. This only closes the case where author-time accepted a value build-time was\n * certain to reject.\n */\nexport const LANGUAGE_TAG_PATTERN = \"^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$\";\n\n/**\n * The canonical spelling of a well-formed language tag, or null when the tag is malformed.\n *\n * Canonical case is BCP 47's: language lowercase, script titlecase, region uppercase. `EN-us`\n * becomes `en-US`, which matters because a tag is compared as a string in a route table and in a\n * `hreflang` attribute.\n *\n * @param {unknown} tag\n * @returns {string | null}\n */\nexport function canonicalizeLocale(tag: unknown): string | null {\n if (typeof tag !== \"string\" || tag.trim() === \"\") {\n return null;\n }\n try {\n return new Intl.Locale(tag.trim()).toString();\n } catch {\n return null;\n }\n}\n\n/** True when the tag is a well-formed BCP 47 language tag. */\nexport function isWellFormedLocale(tag: unknown): boolean {\n return canonicalizeLocale(tag) !== null;\n}\n\n/**\n * The writing direction a tag's text is set in.\n *\n * A malformed tag is `\"ltr\"` rather than an error: this is called while rendering, where the\n * validation has already happened at config load, and guessing left-to-right is what every browser\n * does with an unusable `lang`.\n *\n * @param {unknown} tag\n * @returns {TextDirection}\n */\nexport function localeDirection(tag: unknown): TextDirection {\n const canonical = canonicalizeLocale(tag);\n if (canonical === null) {\n return \"ltr\";\n }\n // No try/catch: `canonicalizeLocale` already constructed this exact tag, so the constructor\n // Cannot throw here and a guard would be an untestable branch pretending otherwise.\n const locale = new Intl.Locale(canonical);\n // An explicit script wins; otherwise CLDR's likely-subtags (UTS #35) supplies one.\n const script = locale.script ?? locale.maximize().script;\n return script !== undefined && RTL_SCRIPTS.has(script) ? \"rtl\" : \"ltr\";\n}\n\n/**\n * A locale's name **in its own language**: `français` for `fr`, `العربية` for `ar`.\n *\n * The autonym, not the name in the site's language, because that is what a reader looking for their\n * own language scans a switcher for — a menu that says \"French\" is unreadable to precisely the\n * person it exists for.\n *\n * Resolved here rather than left to `Intl/displayName` in the document, because a switcher is a\n * mapped array and a map template interpolates scope values rather than evaluating expressions:\n * without this the only label available to an author is one they typed themselves, which is the\n * hand-kept table CLDR exists to replace.\n *\n * Falls back to the tag. `Intl.DisplayNames` answers with the code itself for a language it has no\n * name for, which is the same answer and a better one than an empty menu entry.\n *\n * No try/catch, for the reason {@link localeDirection} gives: the tag has already been through\n * `Intl.Locale` here, so neither the constructor nor `of` can reject it, and a guard would be an\n * untestable branch pretending otherwise.\n *\n * @param {unknown} tag\n * @returns {string}\n */\nexport function localeLabel(tag: unknown): string {\n const canonical = canonicalizeLocale(tag);\n if (canonical === null) {\n return typeof tag === \"string\" ? tag : \"\";\n }\n return new Intl.DisplayNames([canonical], { type: \"language\" }).of(canonical) ?? canonical;\n}\n\n/** How locales appear in URLs. */\nexport type LocaleRouting = \"prefix-except-default\" | \"prefix-always\";\n\n/** A project's `i18n` block after validation, or null when the project declares none. */\nexport interface ResolvedI18n {\n defaultLocale: string;\n /** Canonical tags, default first, in declaration order. */\n locales: string[];\n routing: LocaleRouting;\n}\n\nconst DEFAULT_ROUTING: LocaleRouting = \"prefix-except-default\";\n\n/**\n * Validate and canonicalize a project's `i18n` block.\n *\n * A malformed tag is a **build error**, not a warning. A locale is a URL prefix, an `hreflang`\n * value and an `<html lang>` all at once, so a typo does not degrade — it produces a site whose\n * every page claims a language that does not exist, and nothing downstream can tell.\n *\n * @param {ProjectConfig} projectConfig\n * @returns {{ i18n: ResolvedI18n | null; errors: string[] }}\n */\nexport function resolveI18n(projectConfig: ProjectConfig): {\n i18n: ResolvedI18n | null;\n errors: string[];\n} {\n const raw = projectConfig.i18n;\n const errors: string[] = [];\n if (!raw || typeof raw !== \"object\") {\n return { errors, i18n: null };\n }\n\n const declared = Array.isArray(raw.locales) ? raw.locales : [];\n const locales: string[] = [];\n for (const tag of declared) {\n const canonical = canonicalizeLocale(tag);\n if (canonical === null) {\n errors.push(`i18n.locales: \"${String(tag)}\" is not a well-formed BCP 47 language tag.`);\n continue;\n }\n if (!locales.includes(canonical)) {\n locales.push(canonical);\n }\n }\n\n const defaultLocale = canonicalizeLocale(raw.defaultLocale) ?? locales[0] ?? null;\n if (raw.defaultLocale !== undefined && canonicalizeLocale(raw.defaultLocale) === null) {\n errors.push(\n `i18n.defaultLocale: \"${String(raw.defaultLocale)}\" is not a well-formed BCP 47 language tag.`,\n );\n }\n if (defaultLocale === null) {\n errors.push(\"i18n is declared with no usable locale — set `defaultLocale` or `locales`.\");\n return { errors, i18n: null };\n }\n if (!locales.includes(defaultLocale)) {\n // A default outside the list is a config the author cannot have meant either way round, so it\n // Joins the list rather than being rejected: the pages under it exist regardless.\n locales.unshift(defaultLocale);\n }\n\n const routing: LocaleRouting =\n raw.routing === \"prefix-always\" || raw.routing === \"prefix-except-default\"\n ? raw.routing\n : DEFAULT_ROUTING;\n\n return { errors, i18n: { defaultLocale, locales, routing } };\n}\n\n/**\n * The URL prefix a locale's pages carry: `/fr-ca`, or `\"\"` for a locale that is not prefixed.\n *\n * The one rule `routing` expresses, in the one form every URL-shaped consumer needs. Under\n * `prefix-except-default` the default locale owns the unprefixed URL space; under `prefix-always`\n * every locale is named, including the default. An extension that spells this itself is how a\n * search result or a feed entry comes to link at the default locale's URL for a French post.\n *\n * Lowercase, matching the directory the build reads (see {@link translationPathFor}).\n *\n * @param {string | null | undefined} locale\n * @param {ResolvedI18n | null} i18n\n * @returns {string} `\"\"` or `/<tag>`\n */\nexport function localeUrlPrefix(\n locale: string | null | undefined,\n i18n: ResolvedI18n | null,\n): string {\n if (i18n === null) {\n return \"\";\n }\n const canonical = canonicalizeLocale(locale);\n if (canonical === null || !i18n.locales.includes(canonical)) {\n return \"\";\n }\n if (canonical === i18n.defaultLocale && i18n.routing === \"prefix-except-default\") {\n return \"\";\n }\n return `/${canonical.toLowerCase()}`;\n}\n\n/**\n * The locale a project **file** belongs to: the first path segment that canonicalizes to a declared\n * locale, or null when no segment does.\n *\n * One rule for both layouts §13 defines — `pages/fr/about.json` and `content/blog/fr/hello.md` —\n * because the locale is a directory in both and its position is not the same in the two.\n *\n * `null` for `pages/about.json` is the honest answer rather than the default locale: under\n * `prefix-except-default` that file is the default locale's copy, and under `prefix-always` it is a\n * page outside the locale tree. Which of those it is depends on `routing`, which is the caller's\n * question, not this function's.\n *\n * @param {string} path - Project-relative, `/`-separated\n * @param {ResolvedI18n | null} i18n\n * @returns {string | null}\n */\nexport function localeOfPath(path: string, i18n: ResolvedI18n | null): string | null {\n const index = localeSegment(pathSegments(path), i18n);\n if (index === -1 || i18n === null) {\n return null;\n }\n return canonicalizeLocale(pathSegments(path)[index]);\n}\n\n/**\n * The locale a **page** is served as, which is {@link localeOfPath} plus the one thing routing\n * says.\n *\n * `localeOfPath` answers null for `pages/about.json` because the path alone cannot tell you whether\n * that file is the default locale's copy or a page outside the locale tree — `routing` decides, and\n * that is the caller's question. This is the caller that has it: under `prefix-except-default` the\n * unprefixed page **is** the default locale's, and a surface that could filter to French and Arabic\n * but never to English is a language filter that cannot answer the question it is most often\n * asked.\n *\n * Scoped to `pages/` deliberately. An unlocalized **collection** expands under every locale's route\n * (§13.3), so calling its entries the default language would be a claim about content that is in\n * none — and a layout is shared by every locale rather than belonging to one.\n *\n * @param {string} path - Project-relative\n * @param {ResolvedI18n | null} i18n\n * @returns {string | null}\n */\nexport function servedLocaleOfPath(path: string, i18n: ResolvedI18n | null): string | null {\n const own = localeOfPath(path, i18n);\n if (own !== null || i18n === null || i18n.routing !== \"prefix-except-default\") {\n return own;\n }\n return pathSegments(path)[0] === \"pages\" ? i18n.defaultLocale : null;\n}\n\n/**\n * A file's identity across languages: its path with the locale segment removed.\n *\n * `pages/fr/about.json` and `pages/about.json` share the key `pages/about.json`. The file-shaped\n * sibling of the compiler's route-shaped `translationKey`, and the same idea: what makes two\n * documents the same page is that they agree once the language is taken out.\n *\n * @param {string} path\n * @param {ResolvedI18n | null} i18n\n * @returns {string}\n */\nexport function translationKeyOfPath(path: string, i18n: ResolvedI18n | null): string {\n const segments = pathSegments(path);\n const index = localeSegment(segments, i18n);\n return index === -1 ? segments.join(\"/\") : segments.filter((_, i) => i !== index).join(\"/\");\n}\n\n/**\n * Where this file's copy in `locale` lives — the inverse of {@link translationKeyOfPath}.\n *\n * **`routing` decides whether the default locale is prefixed**, and that asymmetry is its whole\n * meaning: under `prefix-except-default` the default locale's copy is the unprefixed path, under\n * `prefix-always` it is prefixed like every other. A caller that ignores it creates the file in a\n * place nothing serves.\n *\n * Null when the project declares no locales, when the tag is not one of them, or when the path\n * cannot carry a locale at all — a layout, a component, a bare file at the project root. Inventing\n * a location for those would put a translation somewhere no router looks.\n *\n * @param {string} path\n * @param {string} locale\n * @param {ResolvedI18n | null} i18n\n * @returns {string | null}\n */\nexport function translationPathFor(\n path: string,\n locale: string,\n i18n: ResolvedI18n | null,\n): string | null {\n if (i18n === null) {\n return null;\n }\n const canonical = canonicalizeLocale(locale);\n if (canonical === null || !i18n.locales.includes(canonical)) {\n return null;\n }\n const segments = pathSegments(path);\n const existing = localeSegment(segments, i18n);\n const slot = existing === -1 ? localeSlot(segments) : existing;\n if (slot === -1) {\n return null;\n }\n const bare = existing === -1 ? segments : segments.filter((_, i) => i !== existing);\n if (canonical === i18n.defaultLocale && i18n.routing === \"prefix-except-default\") {\n return bare.join(\"/\");\n }\n /*\n * Lowercase on disk. The build matches a directory to a locale case-insensitively, so `fr-CA/`\n * would work — but the URL it produces would carry the capitals, and the warning the build\n * already gives an author with a mismatched directory tells them to write the lowercase form.\n * One spelling, and it is the one the site's own URLs use.\n */\n return bare.toSpliced(slot, 0, canonical.toLowerCase()).join(\"/\");\n}\n\n/** Project-relative segments, tolerating a leading `./`. */\nfunction pathSegments(path: string): string[] {\n return path.replace(/^\\.\\//, \"\").split(\"/\").filter(Boolean);\n}\n\n/** The index of the segment naming a declared locale, or -1. */\nfunction localeSegment(segments: readonly string[], i18n: ResolvedI18n | null): number {\n if (i18n === null) {\n return -1;\n }\n return segments.findIndex((segment) => {\n const canonical = canonicalizeLocale(segment);\n return canonical !== null && i18n.locales.includes(canonical);\n });\n}\n\n/**\n * Where a locale segment would go in a path that has none, or -1 when it could not have one.\n *\n * Immediately below the routing root: `pages/<locale>/…` and `content/<type>/<locale>/…`, which is\n * where §13.1 puts a locale directory and where §13.3's `source: \"./blog/{locale}/\"` expands to. A\n * file that is neither is not addressable per language — a layout is shared by every locale, and a\n * component has no URL to be a translation of.\n */\nfunction localeSlot(segments: readonly string[]): number {\n if (segments[0] === \"pages\" && segments.length > 1) {\n return 1;\n }\n if (segments[0] === \"content\" && segments.length > 2) {\n return 2;\n }\n return -1;\n}\n\n/** The primary language subtag of a tag: `en` for `en-GB`, `zh` for `zh-Hant-TW`. */\nexport function primaryLanguage(tag: unknown): string | null {\n const canonical = canonicalizeLocale(tag);\n return canonical === null ? null : (canonical.split(\"-\")[0] ?? null);\n}\n",
|
|
8
|
+
"/**\n* @vue/shared v3.5.41\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\n// @__NO_SIDE_EFFECTS__\nfunction makeMap(str) {\n const map = /* @__PURE__ */ Object.create(null);\n for (const key of str.split(\",\")) map[key] = 1;\n return (val) => val in map;\n}\n\nconst EMPTY_OBJ = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze({}) : {};\nconst EMPTY_ARR = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze([]) : [];\nconst NOOP = () => {\n};\nconst NO = () => false;\nconst isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter\n(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97);\nconst isModelListener = (key) => key.startsWith(\"onUpdate:\");\nconst extend = Object.assign;\nconst remove = (arr, el) => {\n const i = arr.indexOf(el);\n if (i > -1) {\n arr.splice(i, 1);\n }\n};\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst isArray = Array.isArray;\nconst isMap = (val) => toTypeString(val) === \"[object Map]\";\nconst isSet = (val) => toTypeString(val) === \"[object Set]\";\nconst isDate = (val) => toTypeString(val) === \"[object Date]\";\nconst isRegExp = (val) => toTypeString(val) === \"[object RegExp]\";\nconst isFunction = (val) => typeof val === \"function\";\nconst isString = (val) => typeof val === \"string\";\nconst isSymbol = (val) => typeof val === \"symbol\";\nconst isObject = (val) => val !== null && typeof val === \"object\";\nconst isPromise = (val) => {\n return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch);\n};\nconst objectToString = Object.prototype.toString;\nconst toTypeString = (value) => objectToString.call(value);\nconst toRawType = (value) => {\n return toTypeString(value).slice(8, -1);\n};\nconst isPlainObject = (val) => toTypeString(val) === \"[object Object]\";\nconst isIntegerKey = (key) => isString(key) && key !== \"NaN\" && key[0] !== \"-\" && \"\" + parseInt(key, 10) === key;\nconst isReservedProp = /* @__PURE__ */ makeMap(\n // the leading comma is intentional so empty string \"\" is also included\n \",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted\"\n);\nconst isBuiltInDirective = /* @__PURE__ */ makeMap(\n \"bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo\"\n);\nconst cacheStringFunction = (fn) => {\n const cache = /* @__PURE__ */ Object.create(null);\n return ((str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n });\n};\nconst camelizeRE = /-\\w/g;\nconst camelize = cacheStringFunction(\n (str) => {\n return str.replace(camelizeRE, (c) => c.slice(1).toUpperCase());\n }\n);\nconst hyphenateRE = /\\B([A-Z])/g;\nconst hyphenate = cacheStringFunction(\n (str) => str.replace(hyphenateRE, \"-$1\").toLowerCase()\n);\nconst capitalize = cacheStringFunction((str) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n});\nconst toHandlerKey = cacheStringFunction(\n (str) => {\n const s = str ? `on${capitalize(str)}` : ``;\n return s;\n }\n);\nconst hasChanged = (value, oldValue) => !Object.is(value, oldValue);\nconst invokeArrayFns = (fns, ...arg) => {\n for (let i = 0; i < fns.length; i++) {\n fns[i](...arg);\n }\n};\nconst def = (obj, key, value, writable = false) => {\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: false,\n writable,\n value\n });\n};\nconst looseToNumber = (val) => {\n const n = parseFloat(val);\n return isNaN(n) ? val : n;\n};\nconst toNumber = (val) => {\n const n = isString(val) ? Number(val) : NaN;\n return isNaN(n) ? val : n;\n};\nlet _globalThis;\nconst getGlobalThis = () => {\n return _globalThis || (_globalThis = typeof globalThis !== \"undefined\" ? globalThis : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : typeof global !== \"undefined\" ? global : {});\n};\nconst identRE = /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*$/;\nfunction genPropsAccessExp(name) {\n return identRE.test(name) ? `__props.${name}` : `__props[${JSON.stringify(name)}]`;\n}\nfunction genCacheKey(source, options) {\n return source + JSON.stringify(\n options,\n (_, val) => typeof val === \"function\" ? val.toString() : val\n );\n}\n\nconst PatchFlags = {\n \"TEXT\": 1,\n \"1\": \"TEXT\",\n \"CLASS\": 2,\n \"2\": \"CLASS\",\n \"STYLE\": 4,\n \"4\": \"STYLE\",\n \"PROPS\": 8,\n \"8\": \"PROPS\",\n \"FULL_PROPS\": 16,\n \"16\": \"FULL_PROPS\",\n \"NEED_HYDRATION\": 32,\n \"32\": \"NEED_HYDRATION\",\n \"STABLE_FRAGMENT\": 64,\n \"64\": \"STABLE_FRAGMENT\",\n \"KEYED_FRAGMENT\": 128,\n \"128\": \"KEYED_FRAGMENT\",\n \"UNKEYED_FRAGMENT\": 256,\n \"256\": \"UNKEYED_FRAGMENT\",\n \"NEED_PATCH\": 512,\n \"512\": \"NEED_PATCH\",\n \"DYNAMIC_SLOTS\": 1024,\n \"1024\": \"DYNAMIC_SLOTS\",\n \"DEV_ROOT_FRAGMENT\": 2048,\n \"2048\": \"DEV_ROOT_FRAGMENT\",\n \"CACHED\": -1,\n \"-1\": \"CACHED\",\n \"BAIL\": -2,\n \"-2\": \"BAIL\"\n};\nconst PatchFlagNames = {\n [1]: `TEXT`,\n [2]: `CLASS`,\n [4]: `STYLE`,\n [8]: `PROPS`,\n [16]: `FULL_PROPS`,\n [32]: `NEED_HYDRATION`,\n [64]: `STABLE_FRAGMENT`,\n [128]: `KEYED_FRAGMENT`,\n [256]: `UNKEYED_FRAGMENT`,\n [512]: `NEED_PATCH`,\n [1024]: `DYNAMIC_SLOTS`,\n [2048]: `DEV_ROOT_FRAGMENT`,\n [-1]: `CACHED`,\n [-2]: `BAIL`\n};\n\nconst ShapeFlags = {\n \"ELEMENT\": 1,\n \"1\": \"ELEMENT\",\n \"FUNCTIONAL_COMPONENT\": 2,\n \"2\": \"FUNCTIONAL_COMPONENT\",\n \"STATEFUL_COMPONENT\": 4,\n \"4\": \"STATEFUL_COMPONENT\",\n \"TEXT_CHILDREN\": 8,\n \"8\": \"TEXT_CHILDREN\",\n \"ARRAY_CHILDREN\": 16,\n \"16\": \"ARRAY_CHILDREN\",\n \"SLOTS_CHILDREN\": 32,\n \"32\": \"SLOTS_CHILDREN\",\n \"TELEPORT\": 64,\n \"64\": \"TELEPORT\",\n \"SUSPENSE\": 128,\n \"128\": \"SUSPENSE\",\n \"COMPONENT_SHOULD_KEEP_ALIVE\": 256,\n \"256\": \"COMPONENT_SHOULD_KEEP_ALIVE\",\n \"COMPONENT_KEPT_ALIVE\": 512,\n \"512\": \"COMPONENT_KEPT_ALIVE\",\n \"COMPONENT\": 6,\n \"6\": \"COMPONENT\"\n};\n\nconst SlotFlags = {\n \"STABLE\": 1,\n \"1\": \"STABLE\",\n \"DYNAMIC\": 2,\n \"2\": \"DYNAMIC\",\n \"FORWARDED\": 3,\n \"3\": \"FORWARDED\"\n};\nconst slotFlagsText = {\n [1]: \"STABLE\",\n [2]: \"DYNAMIC\",\n [3]: \"FORWARDED\"\n};\n\nconst GLOBALS_ALLOWED = \"Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol\";\nconst isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED);\nconst isGloballyWhitelisted = isGloballyAllowed;\n\nconst range = 2;\nfunction generateCodeFrame(source, start = 0, end = source.length) {\n start = Math.max(0, Math.min(start, source.length));\n end = Math.max(0, Math.min(end, source.length));\n if (start > end) return \"\";\n let lines = source.split(/(\\r?\\n)/);\n const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);\n lines = lines.filter((_, idx) => idx % 2 === 0);\n let count = 0;\n const res = [];\n for (let i = 0; i < lines.length; i++) {\n count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0);\n if (count >= start) {\n for (let j = i - range; j <= i + range || end > count; j++) {\n if (j < 0 || j >= lines.length) continue;\n const line = j + 1;\n res.push(\n `${line}${\" \".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`\n );\n const lineLength = lines[j].length;\n const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0;\n if (j === i) {\n const pad = start - (count - (lineLength + newLineSeqLength));\n const length = Math.max(\n 1,\n end > count ? lineLength - pad : end - start\n );\n res.push(` | ` + \" \".repeat(pad) + \"^\".repeat(length));\n } else if (j > i) {\n if (end > count) {\n const length = Math.max(Math.min(end - count, lineLength), 1);\n res.push(` | ` + \"^\".repeat(length));\n }\n count += lineLength + newLineSeqLength;\n }\n }\n break;\n }\n }\n return res.join(\"\\n\");\n}\n\nfunction normalizeStyle(value) {\n if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n } else if (isString(value) || isObject(value)) {\n return value;\n }\n}\nconst listDelimiterRE = /;(?![^(]*\\))/g;\nconst propertyDelimiterRE = /:([^]+)/;\nconst styleCommentRE = /\\/\\*[^]*?\\*\\//g;\nfunction parseStringStyle(cssText) {\n const ret = {};\n cssText.replace(styleCommentRE, \"\").split(listDelimiterRE).forEach((item) => {\n if (item) {\n const tmp = item.split(propertyDelimiterRE);\n tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());\n }\n });\n return ret;\n}\nfunction stringifyStyle(styles) {\n if (!styles) return \"\";\n if (isString(styles)) return styles;\n let ret = \"\";\n for (const key in styles) {\n const value = styles[key];\n if (isString(value) || typeof value === \"number\") {\n const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key);\n ret += `${normalizedKey}:${value};`;\n }\n }\n return ret;\n}\nfunction normalizeClass(value) {\n let res = \"\";\n if (isString(value)) {\n res = value;\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + \" \";\n }\n }\n } else if (isObject(value)) {\n for (const name in value) {\n if (value[name]) {\n res += name + \" \";\n }\n }\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props) return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nconst HTML_TAGS = \"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot\";\nconst SVG_TAGS = \"svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view\";\nconst MATH_TAGS = \"annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics\";\nconst VOID_TAGS = \"area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr\";\nconst isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS);\nconst isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS);\nconst isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS);\nconst isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS);\n\nconst specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;\nconst isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs);\nconst isBooleanAttr = /* @__PURE__ */ makeMap(\n specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`\n);\nfunction includeBooleanAttr(value) {\n return !!value || value === \"\";\n}\nconst unsafeAttrCharRE = /[>/=\"'\\u0009\\u000a\\u000c\\u0020]/;\nconst attrValidationCache = {};\nfunction isSSRSafeAttrName(name) {\n if (attrValidationCache.hasOwnProperty(name)) {\n return attrValidationCache[name];\n }\n const isUnsafe = unsafeAttrCharRE.test(name);\n if (isUnsafe) {\n console.error(`unsafe attribute name: ${name}`);\n }\n return attrValidationCache[name] = !isUnsafe;\n}\nconst propsToAttrMap = {\n acceptCharset: \"accept-charset\",\n className: \"class\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\"\n};\nconst isKnownHtmlAttr = /* @__PURE__ */ makeMap(\n `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap`\n);\nconst isKnownSvgAttr = /* @__PURE__ */ makeMap(\n `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`\n);\nconst isKnownMathMLAttr = /* @__PURE__ */ makeMap(\n `accent,accentunder,actiontype,align,alignmentscope,altimg,altimg-height,altimg-valign,altimg-width,alttext,bevelled,close,columnsalign,columnlines,columnspan,denomalign,depth,dir,display,displaystyle,encoding,equalcolumns,equalrows,fence,fontstyle,fontweight,form,frame,framespacing,groupalign,height,href,id,indentalign,indentalignfirst,indentalignlast,indentshift,indentshiftfirst,indentshiftlast,indextype,justify,largetop,largeop,lquote,lspace,mathbackground,mathcolor,mathsize,mathvariant,maxsize,minlabelspacing,mode,other,overflow,position,rowalign,rowlines,rowspan,rquote,rspace,scriptlevel,scriptminsize,scriptsizemultiplier,selection,separator,separators,shift,side,src,stackalign,stretchy,subscriptshift,superscriptshift,symmetric,voffset,width,widths,xlink:href,xlink:show,xlink:type,xmlns`\n);\nfunction isRenderableAttrValue(value) {\n if (value == null) {\n return false;\n }\n const type = typeof value;\n return type === \"string\" || type === \"number\" || type === \"boolean\";\n}\n\nconst escapeRE = /[\"'&<>]/;\nfunction escapeHtml(string) {\n const str = \"\" + string;\n const match = escapeRE.exec(str);\n if (!match) {\n return str;\n }\n let html = \"\";\n let escaped;\n let index;\n let lastIndex = 0;\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34:\n escaped = \""\";\n break;\n case 38:\n escaped = \"&\";\n break;\n case 39:\n escaped = \"'\";\n break;\n case 60:\n escaped = \"<\";\n break;\n case 62:\n escaped = \">\";\n break;\n default:\n continue;\n }\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n lastIndex = index + 1;\n html += escaped;\n }\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n}\nconst commentStripRE = /^(?:-?>)+|<!--|-->|--!>|<!-$/g;\nfunction escapeHtmlComment(src) {\n let prev;\n do {\n prev = src;\n src = src.replace(commentStripRE, \"\");\n } while (src !== prev);\n return src;\n}\nconst cssVarNameEscapeSymbolsRE = /[ !\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~]/g;\nfunction getEscapedCssVarName(key, doubleEscape) {\n return key.replace(\n cssVarNameEscapeSymbolsRE,\n (s) => doubleEscape ? s === '\"' ? '\\\\\\\\\\\\\"' : `\\\\\\\\${s}` : `\\\\${s}`\n );\n}\n\nfunction looseCompareArrays(a, b) {\n if (a.length !== b.length) return false;\n let equal = true;\n for (let i = 0; equal && i < a.length; i++) {\n equal = looseEqual(a[i], b[i]);\n }\n return equal;\n}\nfunction looseEqual(a, b) {\n if (a === b) return true;\n let aValidType = isDate(a);\n let bValidType = isDate(b);\n if (aValidType || bValidType) {\n return aValidType && bValidType ? a.getTime() === b.getTime() : false;\n }\n aValidType = isSymbol(a);\n bValidType = isSymbol(b);\n if (aValidType || bValidType) {\n return a === b;\n }\n aValidType = isArray(a);\n bValidType = isArray(b);\n if (aValidType || bValidType) {\n return aValidType && bValidType ? looseCompareArrays(a, b) : false;\n }\n aValidType = isObject(a);\n bValidType = isObject(b);\n if (aValidType || bValidType) {\n if (!aValidType || !bValidType) {\n return false;\n }\n const aKeysCount = Object.keys(a).length;\n const bKeysCount = Object.keys(b).length;\n if (aKeysCount !== bKeysCount) {\n return false;\n }\n for (const key in a) {\n const aHasKey = a.hasOwnProperty(key);\n const bHasKey = b.hasOwnProperty(key);\n if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {\n return false;\n }\n }\n }\n return String(a) === String(b);\n}\nfunction looseIndexOf(arr, val) {\n return arr.findIndex((item) => looseEqual(item, val));\n}\n\nconst isRef = (val) => {\n return !!(val && val[\"__v_isRef\"] === true);\n};\nconst toDisplayString = (val) => {\n return isString(val) ? val : val == null ? \"\" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? isRef(val) ? toDisplayString(val.value) : JSON.stringify(val, replacer, 2) : String(val);\n};\nconst replacer = (_key, val) => {\n if (isRef(val)) {\n return replacer(_key, val.value);\n } else if (isMap(val)) {\n return {\n [`Map(${val.size})`]: [...val.entries()].reduce(\n (entries, [key, val2], i) => {\n entries[stringifySymbol(key, i) + \" =>\"] = val2;\n return entries;\n },\n {}\n )\n };\n } else if (isSet(val)) {\n return {\n [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v))\n };\n } else if (isSymbol(val)) {\n return stringifySymbol(val);\n } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {\n return String(val);\n }\n return val;\n};\nconst stringifySymbol = (v, i = \"\") => {\n var _a;\n return (\n // Symbol.description in es2019+ so we need to cast here to pass\n // the lib: es2016 check\n isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v\n );\n};\n\nfunction normalizeCssVarValue(value) {\n if (value == null) {\n return \"initial\";\n }\n if (typeof value === \"string\") {\n return value === \"\" ? \" \" : value;\n }\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n console.warn(\n \"[Vue warn] Invalid value used for CSS binding. Expected a string or a finite number but received:\",\n value\n );\n }\n }\n return String(value);\n}\n\nexport { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, PatchFlags, ShapeFlags, SlotFlags, camelize, capitalize, cssVarNameEscapeSymbolsRE, def, escapeHtml, escapeHtmlComment, extend, genCacheKey, genPropsAccessExp, generateCodeFrame, getEscapedCssVarName, getGlobalThis, hasChanged, hasOwn, hyphenate, includeBooleanAttr, invokeArrayFns, isArray, isBooleanAttr, isBuiltInDirective, isDate, isFunction, isGloballyAllowed, isGloballyWhitelisted, isHTMLTag, isIntegerKey, isKnownHtmlAttr, isKnownMathMLAttr, isKnownSvgAttr, isMap, isMathMLTag, isModelListener, isObject, isOn, isPlainObject, isPromise, isRegExp, isRenderableAttrValue, isReservedProp, isSSRSafeAttrName, isSVGTag, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, looseToNumber, makeMap, normalizeClass, normalizeCssVarValue, normalizeProps, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, slotFlagsText, stringifyStyle, toDisplayString, toHandlerKey, toNumber, toRawType, toTypeString };\n",
|
|
9
|
+
"/**\n* @vue/reactivity v3.5.41\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nimport { extend, hasChanged, isArray, isIntegerKey, isSymbol, isMap, hasOwn, isObject, makeMap, capitalize, toRawType, def, isFunction, EMPTY_OBJ, isSet, isPlainObject, remove, NOOP } from '@vue/shared';\n\nfunction warn(msg, ...args) {\n console.warn(`[Vue warn] ${msg}`, ...args);\n}\n\nlet activeEffectScope;\nclass EffectScope {\n // TODO isolatedDeclarations \"__v_skip\"\n constructor(detached = false) {\n this.detached = detached;\n /**\n * @internal\n */\n this._active = true;\n /**\n * @internal track `on` calls, allow `on` call multiple times\n */\n this._on = 0;\n /**\n * @internal\n */\n this.effects = [];\n /**\n * @internal\n */\n this.cleanups = [];\n this._isPaused = false;\n this._warnOnRun = true;\n this.__v_skip = true;\n if (!detached && activeEffectScope) {\n if (activeEffectScope.active) {\n this.parent = activeEffectScope;\n this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(\n this\n ) - 1;\n } else {\n this._active = false;\n this._warnOnRun = false;\n }\n }\n }\n get active() {\n return this._active;\n }\n pause() {\n if (this._active) {\n this._isPaused = true;\n let i, l;\n if (this.scopes) {\n const scopes = this.scopes.slice();\n for (i = 0, l = scopes.length; i < l; i++) {\n scopes[i].pause();\n }\n }\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].pause();\n }\n }\n }\n /**\n * Resumes the effect scope, including all child scopes and effects.\n */\n resume() {\n if (this._active) {\n if (this._isPaused) {\n this._isPaused = false;\n let i, l;\n if (this.scopes) {\n const scopes = this.scopes.slice();\n for (i = 0, l = scopes.length; i < l; i++) {\n scopes[i].resume();\n }\n }\n const effects = this.effects.slice();\n for (i = 0, l = effects.length; i < l; i++) {\n effects[i].resume();\n }\n }\n }\n }\n run(fn) {\n if (this._active) {\n const currentEffectScope = activeEffectScope;\n try {\n activeEffectScope = this;\n return fn();\n } finally {\n activeEffectScope = currentEffectScope;\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && this._warnOnRun) {\n warn(`cannot run an inactive effect scope.`);\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n on() {\n if (++this._on === 1) {\n this.prevScope = activeEffectScope;\n activeEffectScope = this;\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n off() {\n if (this._on > 0 && --this._on === 0) {\n if (activeEffectScope === this) {\n activeEffectScope = this.prevScope;\n } else {\n let current = activeEffectScope;\n while (current) {\n if (current.prevScope === this) {\n current.prevScope = this.prevScope;\n break;\n }\n current = current.prevScope;\n }\n }\n this.prevScope = void 0;\n }\n }\n stop(fromParent) {\n if (this._active) {\n this._active = false;\n let i, l;\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].stop();\n }\n this.effects.length = 0;\n for (i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n this.cleanups.length = 0;\n if (this.scopes) {\n const scopes = this.scopes.slice();\n for (i = 0, l = scopes.length; i < l; i++) {\n scopes[i].stop(true);\n }\n this.scopes.length = 0;\n }\n if (!this.detached && this.parent && !fromParent) {\n const last = this.parent.scopes.pop();\n if (last && last !== this) {\n this.parent.scopes[this.index] = last;\n last.index = this.index;\n }\n }\n this.parent = void 0;\n }\n }\n}\nfunction effectScope(detached) {\n return new EffectScope(detached);\n}\nfunction getCurrentScope() {\n return activeEffectScope;\n}\nfunction onScopeDispose(fn, failSilently = false) {\n if (activeEffectScope) {\n activeEffectScope.cleanups.push(fn);\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onScopeDispose() is called when there is no active effect scope to be associated with.`\n );\n }\n}\n\nlet activeSub;\nconst EffectFlags = {\n \"ACTIVE\": 1,\n \"1\": \"ACTIVE\",\n \"RUNNING\": 2,\n \"2\": \"RUNNING\",\n \"TRACKING\": 4,\n \"4\": \"TRACKING\",\n \"NOTIFIED\": 8,\n \"8\": \"NOTIFIED\",\n \"DIRTY\": 16,\n \"16\": \"DIRTY\",\n \"ALLOW_RECURSE\": 32,\n \"32\": \"ALLOW_RECURSE\",\n \"PAUSED\": 64,\n \"64\": \"PAUSED\",\n \"EVALUATED\": 128,\n \"128\": \"EVALUATED\"\n};\nconst pausedQueueEffects = /* @__PURE__ */ new WeakSet();\nclass ReactiveEffect {\n constructor(fn) {\n this.fn = fn;\n /**\n * @internal\n */\n this.deps = void 0;\n /**\n * @internal\n */\n this.depsTail = void 0;\n /**\n * @internal\n */\n this.flags = 1 | 4;\n /**\n * @internal\n */\n this.next = void 0;\n /**\n * @internal\n */\n this.cleanup = void 0;\n this.scheduler = void 0;\n if (activeEffectScope) {\n if (activeEffectScope.active) {\n activeEffectScope.effects.push(this);\n } else {\n this.flags &= -2;\n }\n }\n }\n pause() {\n this.flags |= 64;\n }\n resume() {\n if (this.flags & 64) {\n this.flags &= -65;\n if (pausedQueueEffects.has(this)) {\n pausedQueueEffects.delete(this);\n this.trigger();\n }\n }\n }\n /**\n * @internal\n */\n notify() {\n if (this.flags & 2 && !(this.flags & 32)) {\n return;\n }\n if (!(this.flags & 8)) {\n batch(this);\n }\n }\n run() {\n if (!(this.flags & 1)) {\n return this.fn();\n }\n this.flags |= 2;\n cleanupEffect(this);\n prepareDeps(this);\n const prevEffect = activeSub;\n const prevShouldTrack = shouldTrack;\n activeSub = this;\n shouldTrack = true;\n try {\n return this.fn();\n } finally {\n if (!!(process.env.NODE_ENV !== \"production\") && activeSub !== this) {\n warn(\n \"Active effect was not restored correctly - this is likely a Vue internal bug.\"\n );\n }\n cleanupDeps(this);\n activeSub = prevEffect;\n shouldTrack = prevShouldTrack;\n this.flags &= -3;\n }\n }\n stop() {\n if (this.flags & 1) {\n for (let link = this.deps; link; link = link.nextDep) {\n removeSub(link);\n }\n this.deps = this.depsTail = void 0;\n cleanupEffect(this);\n this.onStop && this.onStop();\n this.flags &= -2;\n }\n }\n trigger() {\n if (this.flags & 64) {\n pausedQueueEffects.add(this);\n } else if (this.scheduler) {\n this.scheduler();\n } else {\n this.runIfDirty();\n }\n }\n /**\n * @internal\n */\n runIfDirty() {\n if (isDirty(this)) {\n this.run();\n }\n }\n get dirty() {\n return isDirty(this);\n }\n}\nlet batchDepth = 0;\nlet batchedSub;\nlet batchedComputed;\nfunction batch(sub, isComputed = false) {\n sub.flags |= 8;\n if (isComputed) {\n sub.next = batchedComputed;\n batchedComputed = sub;\n return;\n }\n sub.next = batchedSub;\n batchedSub = sub;\n}\nfunction startBatch() {\n batchDepth++;\n}\nfunction endBatch() {\n if (--batchDepth > 0) {\n return;\n }\n if (batchedComputed) {\n let e = batchedComputed;\n batchedComputed = void 0;\n while (e) {\n const next = e.next;\n e.next = void 0;\n e.flags &= -9;\n e = next;\n }\n }\n let error;\n while (batchedSub) {\n let e = batchedSub;\n batchedSub = void 0;\n while (e) {\n const next = e.next;\n e.next = void 0;\n e.flags &= -9;\n if (e.flags & 1) {\n try {\n ;\n e.trigger();\n } catch (err) {\n if (!error) error = err;\n }\n }\n e = next;\n }\n }\n if (error) throw error;\n}\nfunction prepareDeps(sub) {\n for (let link = sub.deps; link; link = link.nextDep) {\n link.version = -1;\n link.prevActiveLink = link.dep.activeLink;\n link.dep.activeLink = link;\n }\n}\nfunction cleanupDeps(sub) {\n let head;\n let tail = sub.depsTail;\n let link = tail;\n while (link) {\n const prev = link.prevDep;\n if (link.version === -1) {\n if (link === tail) tail = prev;\n removeSub(link);\n removeDep(link);\n } else {\n head = link;\n }\n link.dep.activeLink = link.prevActiveLink;\n link.prevActiveLink = void 0;\n link = prev;\n }\n sub.deps = head;\n sub.depsTail = tail;\n}\nfunction isDirty(sub) {\n for (let link = sub.deps; link; link = link.nextDep) {\n if (link.dep.version !== link.version || link.dep.computed && (refreshComputed(link.dep.computed) || link.dep.version !== link.version)) {\n return true;\n }\n }\n if (sub._dirty) {\n return true;\n }\n return false;\n}\nfunction refreshComputed(computed) {\n if (computed.flags & 4 && !(computed.flags & 16)) {\n return;\n }\n computed.flags &= -17;\n if (computed.globalVersion === globalVersion) {\n return;\n }\n computed.globalVersion = globalVersion;\n if (!computed.isSSR && computed.flags & 128 && (!computed.deps && !computed._dirty || !isDirty(computed))) {\n return;\n }\n computed.flags |= 2;\n const dep = computed.dep;\n const prevSub = activeSub;\n const prevShouldTrack = shouldTrack;\n activeSub = computed;\n shouldTrack = true;\n try {\n prepareDeps(computed);\n const value = computed.fn(computed._value);\n if (dep.version === 0 || hasChanged(value, computed._value)) {\n computed.flags |= 128;\n computed._value = value;\n dep.version++;\n }\n } catch (err) {\n dep.version++;\n throw err;\n } finally {\n activeSub = prevSub;\n shouldTrack = prevShouldTrack;\n cleanupDeps(computed);\n computed.flags &= -3;\n }\n}\nfunction removeSub(link, soft = false) {\n const { dep, prevSub, nextSub } = link;\n if (prevSub) {\n prevSub.nextSub = nextSub;\n link.prevSub = void 0;\n }\n if (nextSub) {\n nextSub.prevSub = prevSub;\n link.nextSub = void 0;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && dep.subsHead === link) {\n dep.subsHead = nextSub;\n }\n if (dep.subs === link) {\n dep.subs = prevSub;\n if (!prevSub && dep.computed) {\n dep.computed.flags &= -5;\n for (let l = dep.computed.deps; l; l = l.nextDep) {\n removeSub(l, true);\n }\n }\n }\n if (!soft && !--dep.sc && dep.map) {\n dep.map.delete(dep.key);\n }\n}\nfunction removeDep(link) {\n const { prevDep, nextDep } = link;\n if (prevDep) {\n prevDep.nextDep = nextDep;\n link.prevDep = void 0;\n }\n if (nextDep) {\n nextDep.prevDep = prevDep;\n link.nextDep = void 0;\n }\n}\nfunction effect(fn, options) {\n if (fn.effect instanceof ReactiveEffect) {\n fn = fn.effect.fn;\n }\n const e = new ReactiveEffect(fn);\n if (options) {\n extend(e, options);\n }\n try {\n e.run();\n } catch (err) {\n e.stop();\n throw err;\n }\n const runner = e.run.bind(e);\n runner.effect = e;\n return runner;\n}\nfunction stop(runner) {\n runner.effect.stop();\n}\nlet shouldTrack = true;\nconst trackStack = [];\nfunction pauseTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\nfunction enableTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = true;\n}\nfunction resetTracking() {\n const last = trackStack.pop();\n shouldTrack = last === void 0 ? true : last;\n}\nfunction onEffectCleanup(fn, failSilently = false) {\n if (activeSub instanceof ReactiveEffect) {\n activeSub.cleanup = fn;\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onEffectCleanup() was called when there was no active effect to associate with.`\n );\n }\n}\nfunction cleanupEffect(e) {\n const { cleanup } = e;\n e.cleanup = void 0;\n if (cleanup) {\n const prevSub = activeSub;\n activeSub = void 0;\n try {\n cleanup();\n } finally {\n activeSub = prevSub;\n }\n }\n}\n\nlet globalVersion = 0;\nclass Link {\n constructor(sub, dep) {\n this.sub = sub;\n this.dep = dep;\n this.version = dep.version;\n this.nextDep = this.prevDep = this.nextSub = this.prevSub = this.prevActiveLink = void 0;\n }\n}\nclass Dep {\n // TODO isolatedDeclarations \"__v_skip\"\n constructor(computed) {\n this.computed = computed;\n this.version = 0;\n /**\n * Link between this dep and the current active effect\n */\n this.activeLink = void 0;\n /**\n * Doubly linked list representing the subscribing effects (tail)\n */\n this.subs = void 0;\n /**\n * For object property deps cleanup\n */\n this.map = void 0;\n this.key = void 0;\n /**\n * Subscriber counter\n */\n this.sc = 0;\n /**\n * @internal\n */\n this.__v_skip = true;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.subsHead = void 0;\n }\n }\n track(debugInfo) {\n if (!activeSub || !shouldTrack || activeSub === this.computed) {\n return;\n }\n let link = this.activeLink;\n if (link === void 0 || link.sub !== activeSub) {\n link = this.activeLink = new Link(activeSub, this);\n if (!activeSub.deps) {\n activeSub.deps = activeSub.depsTail = link;\n } else {\n link.prevDep = activeSub.depsTail;\n activeSub.depsTail.nextDep = link;\n activeSub.depsTail = link;\n }\n addSub(link);\n } else if (link.version === -1) {\n link.version = this.version;\n if (link.nextDep) {\n const next = link.nextDep;\n next.prevDep = link.prevDep;\n if (link.prevDep) {\n link.prevDep.nextDep = next;\n }\n link.prevDep = activeSub.depsTail;\n link.nextDep = void 0;\n activeSub.depsTail.nextDep = link;\n activeSub.depsTail = link;\n if (activeSub.deps === link) {\n activeSub.deps = next;\n }\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") && activeSub.onTrack) {\n activeSub.onTrack(\n extend(\n {\n effect: activeSub\n },\n debugInfo\n )\n );\n }\n return link;\n }\n trigger(debugInfo) {\n this.version++;\n globalVersion++;\n this.notify(debugInfo);\n }\n notify(debugInfo) {\n startBatch();\n try {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n for (let head = this.subsHead; head; head = head.nextSub) {\n if (head.sub.onTrigger && !(head.sub.flags & 8)) {\n head.sub.onTrigger(\n extend(\n {\n effect: head.sub\n },\n debugInfo\n )\n );\n }\n }\n }\n for (let link = this.subs; link; link = link.prevSub) {\n if (link.sub.notify()) {\n ;\n link.sub.dep.notify();\n }\n }\n } finally {\n endBatch();\n }\n }\n}\nfunction addSub(link) {\n link.dep.sc++;\n if (link.sub.flags & 4) {\n const computed = link.dep.computed;\n if (computed && !link.dep.subs) {\n computed.flags |= 4 | 16;\n for (let l = computed.deps; l; l = l.nextDep) {\n addSub(l);\n }\n }\n const currentTail = link.dep.subs;\n if (currentTail !== link) {\n link.prevSub = currentTail;\n if (currentTail) currentTail.nextSub = link;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && link.dep.subsHead === void 0) {\n link.dep.subsHead = link;\n }\n link.dep.subs = link;\n }\n}\nconst targetMap = /* @__PURE__ */ new WeakMap();\nconst ITERATE_KEY = /* @__PURE__ */ Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Object iterate\" : \"\"\n);\nconst MAP_KEY_ITERATE_KEY = /* @__PURE__ */ Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Map keys iterate\" : \"\"\n);\nconst ARRAY_ITERATE_KEY = /* @__PURE__ */ Symbol(\n !!(process.env.NODE_ENV !== \"production\") ? \"Array iterate\" : \"\"\n);\nfunction track(target, type, key) {\n if (shouldTrack && activeSub) {\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, depsMap = /* @__PURE__ */ new Map());\n }\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, dep = new Dep());\n dep.map = depsMap;\n dep.key = key;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n dep.track({\n target,\n type,\n key\n });\n } else {\n dep.track();\n }\n }\n}\nfunction trigger(target, type, key, newValue, oldValue, oldTarget) {\n const depsMap = targetMap.get(target);\n if (!depsMap) {\n globalVersion++;\n return;\n }\n const run = (dep) => {\n if (dep) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n dep.trigger({\n target,\n type,\n key,\n newValue,\n oldValue,\n oldTarget\n });\n } else {\n dep.trigger();\n }\n }\n };\n startBatch();\n if (type === \"clear\") {\n depsMap.forEach(run);\n } else {\n const targetIsArray = isArray(target);\n const isArrayIndex = targetIsArray && isIntegerKey(key);\n if (targetIsArray && key === \"length\") {\n const newLength = Number(newValue);\n depsMap.forEach((dep, key2) => {\n if (key2 === \"length\" || key2 === ARRAY_ITERATE_KEY || !isSymbol(key2) && key2 >= newLength) {\n run(dep);\n }\n });\n } else {\n if (key !== void 0 || depsMap.has(void 0)) {\n run(depsMap.get(key));\n }\n if (isArrayIndex) {\n run(depsMap.get(ARRAY_ITERATE_KEY));\n }\n switch (type) {\n case \"add\":\n if (!targetIsArray) {\n run(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n run(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n } else if (isArrayIndex) {\n run(depsMap.get(\"length\"));\n }\n break;\n case \"delete\":\n if (!targetIsArray) {\n run(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n run(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n }\n break;\n case \"set\":\n if (isMap(target)) {\n run(depsMap.get(ITERATE_KEY));\n }\n break;\n }\n }\n }\n endBatch();\n}\nfunction getDepFromReactive(object, key) {\n const depMap = targetMap.get(object);\n return depMap && depMap.get(key);\n}\n\nfunction reactiveReadArray(array) {\n const raw = toRaw(array);\n if (raw === array) return raw;\n track(raw, \"iterate\", ARRAY_ITERATE_KEY);\n return isShallow(array) ? raw : raw.map(toReactive);\n}\nfunction shallowReadArray(arr) {\n track(arr = toRaw(arr), \"iterate\", ARRAY_ITERATE_KEY);\n return arr;\n}\nfunction toWrapped(target, item) {\n if (isReadonly(target)) {\n return isReactive(target) ? toReadonly(toReactive(item)) : toReadonly(item);\n }\n return toReactive(item);\n}\nconst arrayInstrumentations = {\n __proto__: null,\n [Symbol.iterator]() {\n return iterator(this, Symbol.iterator, (item) => toWrapped(this, item));\n },\n concat(...args) {\n return reactiveReadArray(this).concat(\n ...args.map((x) => isArray(x) ? reactiveReadArray(x) : x)\n );\n },\n entries() {\n return iterator(this, \"entries\", (value) => {\n value[1] = toWrapped(this, value[1]);\n return value;\n });\n },\n every(fn, thisArg) {\n return apply(this, \"every\", fn, thisArg, void 0, arguments);\n },\n filter(fn, thisArg) {\n return apply(\n this,\n \"filter\",\n fn,\n thisArg,\n (v) => v.map((item) => toWrapped(this, item)),\n arguments\n );\n },\n find(fn, thisArg) {\n return apply(\n this,\n \"find\",\n fn,\n thisArg,\n (item) => toWrapped(this, item),\n arguments\n );\n },\n findIndex(fn, thisArg) {\n return apply(this, \"findIndex\", fn, thisArg, void 0, arguments);\n },\n findLast(fn, thisArg) {\n return apply(\n this,\n \"findLast\",\n fn,\n thisArg,\n (item) => toWrapped(this, item),\n arguments\n );\n },\n findLastIndex(fn, thisArg) {\n return apply(this, \"findLastIndex\", fn, thisArg, void 0, arguments);\n },\n // flat, flatMap could benefit from ARRAY_ITERATE but are not straight-forward to implement\n forEach(fn, thisArg) {\n return apply(this, \"forEach\", fn, thisArg, void 0, arguments);\n },\n includes(...args) {\n return searchProxy(this, \"includes\", args);\n },\n indexOf(...args) {\n return searchProxy(this, \"indexOf\", args);\n },\n join(separator) {\n return reactiveReadArray(this).join(separator);\n },\n // keys() iterator only reads `length`, no optimization required\n lastIndexOf(...args) {\n return searchProxy(this, \"lastIndexOf\", args);\n },\n map(fn, thisArg) {\n return apply(this, \"map\", fn, thisArg, void 0, arguments);\n },\n pop() {\n return noTracking(this, \"pop\");\n },\n push(...args) {\n return noTracking(this, \"push\", args);\n },\n reduce(fn, ...args) {\n return reduce(this, \"reduce\", fn, args);\n },\n reduceRight(fn, ...args) {\n return reduce(this, \"reduceRight\", fn, args);\n },\n shift() {\n return noTracking(this, \"shift\");\n },\n // slice could use ARRAY_ITERATE but also seems to beg for range tracking\n some(fn, thisArg) {\n return apply(this, \"some\", fn, thisArg, void 0, arguments);\n },\n splice(...args) {\n return noTracking(this, \"splice\", args);\n },\n toReversed() {\n return reactiveReadArray(this).toReversed();\n },\n toSorted(comparer) {\n return reactiveReadArray(this).toSorted(comparer);\n },\n toSpliced(...args) {\n return reactiveReadArray(this).toSpliced(...args);\n },\n unshift(...args) {\n return noTracking(this, \"unshift\", args);\n },\n values() {\n return iterator(this, \"values\", (item) => toWrapped(this, item));\n }\n};\nfunction iterator(self, method, wrapValue) {\n const arr = shallowReadArray(self);\n const iter = arr[method]();\n if (arr !== self && !isShallow(self)) {\n iter._next = iter.next;\n iter.next = () => {\n const result = iter._next();\n if (!result.done) {\n result.value = wrapValue(result.value);\n }\n return result;\n };\n }\n return iter;\n}\nconst arrayProto = Array.prototype;\nfunction apply(self, method, fn, thisArg, wrappedRetFn, args) {\n const arr = shallowReadArray(self);\n const needsWrap = arr !== self && !isShallow(self);\n const methodFn = arr[method];\n if (methodFn !== arrayProto[method]) {\n const result2 = methodFn.apply(self, args);\n return needsWrap ? toReactive(result2) : result2;\n }\n let wrappedFn = fn;\n if (arr !== self) {\n if (needsWrap) {\n wrappedFn = function(item, index) {\n return fn.call(this, toWrapped(self, item), index, self);\n };\n } else if (fn.length > 2) {\n wrappedFn = function(item, index) {\n return fn.call(this, item, index, self);\n };\n }\n }\n const result = methodFn.call(arr, wrappedFn, thisArg);\n return needsWrap && wrappedRetFn ? wrappedRetFn(result) : result;\n}\nfunction reduce(self, method, fn, args) {\n const arr = shallowReadArray(self);\n const needsWrap = arr !== self && !isShallow(self);\n let wrappedFn = fn;\n let wrapInitialAccumulator = false;\n if (arr !== self) {\n if (needsWrap) {\n wrapInitialAccumulator = args.length === 0;\n wrappedFn = function(acc, item, index) {\n if (wrapInitialAccumulator) {\n wrapInitialAccumulator = false;\n acc = toWrapped(self, acc);\n }\n return fn.call(this, acc, toWrapped(self, item), index, self);\n };\n } else if (fn.length > 3) {\n wrappedFn = function(acc, item, index) {\n return fn.call(this, acc, item, index, self);\n };\n }\n }\n const result = arr[method](wrappedFn, ...args);\n return wrapInitialAccumulator ? toWrapped(self, result) : result;\n}\nfunction searchProxy(self, method, args) {\n const arr = toRaw(self);\n track(arr, \"iterate\", ARRAY_ITERATE_KEY);\n const res = arr[method](...args);\n if ((res === -1 || res === false) && isProxy(args[0])) {\n args[0] = toRaw(args[0]);\n return arr[method](...args);\n }\n return res;\n}\nfunction noTracking(self, method, args = []) {\n pauseTracking();\n startBatch();\n const res = toRaw(self)[method].apply(self, args);\n endBatch();\n resetTracking();\n return res;\n}\n\nconst isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);\nconst builtInSymbols = new Set(\n /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== \"arguments\" && key !== \"caller\").map((key) => Symbol[key]).filter(isSymbol)\n);\nfunction hasOwnProperty(key) {\n if (!isSymbol(key)) key = String(key);\n const obj = toRaw(this);\n track(obj, \"has\", key);\n return obj.hasOwnProperty(key);\n}\nclass BaseReactiveHandler {\n constructor(_isReadonly = false, _isShallow = false) {\n this._isReadonly = _isReadonly;\n this._isShallow = _isShallow;\n }\n get(target, key, receiver) {\n if (key === \"__v_skip\") return target[\"__v_skip\"];\n const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_isShallow\") {\n return isShallow2;\n } else if (key === \"__v_raw\") {\n if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype\n // this means the receiver is a user proxy of the reactive proxy\n Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {\n return target;\n }\n return;\n }\n const targetIsArray = isArray(target);\n if (!isReadonly2) {\n let fn;\n if (targetIsArray && (fn = arrayInstrumentations[key])) {\n return fn;\n }\n if (key === \"hasOwnProperty\") {\n return hasOwnProperty;\n }\n }\n const res = Reflect.get(\n target,\n key,\n // if this is a proxy wrapping a ref, return methods using the raw ref\n // as receiver so that we don't have to call `toRaw` on the ref in all\n // its class methods\n isRef(target) ? target : receiver\n );\n if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {\n return res;\n }\n if (!isReadonly2) {\n track(target, \"get\", key);\n }\n if (isShallow2) {\n return res;\n }\n if (isRef(res)) {\n const value = targetIsArray && isIntegerKey(key) ? res : res.value;\n return isReadonly2 && isObject(value) ? readonly(value) : value;\n }\n if (isObject(res)) {\n return isReadonly2 ? readonly(res) : reactive(res);\n }\n return res;\n }\n}\nclass MutableReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(false, isShallow2);\n }\n set(target, key, value, receiver) {\n let oldValue = target[key];\n const isArrayWithIntegerKey = isArray(target) && isIntegerKey(key);\n if (!this._isShallow) {\n const isOldValueReadonly = isReadonly(oldValue);\n if (!isShallow(value) && !isReadonly(value)) {\n oldValue = toRaw(oldValue);\n value = toRaw(value);\n }\n if (!isArrayWithIntegerKey && isRef(oldValue) && !isRef(value)) {\n if (isOldValueReadonly) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target[key]\n );\n }\n return true;\n } else {\n oldValue.value = value;\n return true;\n }\n }\n }\n const hadKey = isArrayWithIntegerKey ? Number(key) < target.length : hasOwn(target, key);\n const result = Reflect.set(\n target,\n key,\n value,\n isRef(target) ? target : receiver\n );\n if (target === toRaw(receiver) && result) {\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n }\n return result;\n }\n deleteProperty(target, key) {\n const hadKey = hasOwn(target, key);\n const oldValue = target[key];\n const result = Reflect.deleteProperty(target, key);\n if (result && hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n }\n has(target, key) {\n const result = Reflect.has(target, key);\n if (!isSymbol(key) || !builtInSymbols.has(key)) {\n track(target, \"has\", key);\n }\n return result;\n }\n ownKeys(target) {\n track(\n target,\n \"iterate\",\n isArray(target) ? \"length\" : ITERATE_KEY\n );\n return Reflect.ownKeys(target);\n }\n}\nclass ReadonlyReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(true, isShallow2);\n }\n set(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n deleteProperty(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `Delete operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n}\nconst mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();\nconst readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();\nconst shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);\nconst shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);\n\nconst toShallow = (value) => value;\nconst getProto = (v) => Reflect.getPrototypeOf(v);\nfunction createIterableMethod(method, isReadonly2, isShallow2) {\n return function(...args) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const targetIsMap = isMap(rawTarget);\n const isPair = method === \"entries\" || method === Symbol.iterator && targetIsMap;\n const isKeyOnly = method === \"keys\" && targetIsMap;\n const innerIterator = target[method](...args);\n const wrap = isShallow2 ? toShallow : isReadonly2 ? toReadonly : toReactive;\n !isReadonly2 && track(\n rawTarget,\n \"iterate\",\n isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY\n );\n return extend(\n // inheriting all iterator properties\n Object.create(innerIterator),\n {\n // iterator protocol\n next() {\n const { value, done } = innerIterator.next();\n return done ? { value, done } : {\n value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),\n done\n };\n }\n }\n );\n };\n}\nfunction createReadonlyMethod(type) {\n return function(...args) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const key = args[0] ? `on key \"${args[0]}\" ` : ``;\n warn(\n `${capitalize(type)} operation ${key}failed: target is readonly.`,\n toRaw(this)\n );\n }\n return type === \"delete\" ? false : type === \"clear\" ? void 0 : this;\n };\n}\nfunction createInstrumentations(readonly, shallow) {\n const instrumentations = {\n get(key) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!readonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"get\", key);\n }\n track(rawTarget, \"get\", rawKey);\n }\n const { has } = getProto(rawTarget);\n const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;\n if (has.call(rawTarget, key)) {\n return wrap(target.get(key));\n } else if (has.call(rawTarget, rawKey)) {\n return wrap(target.get(rawKey));\n } else if (target !== rawTarget) {\n target.get(key);\n }\n },\n get size() {\n const target = this[\"__v_raw\"];\n !readonly && track(toRaw(target), \"iterate\", ITERATE_KEY);\n return target.size;\n },\n has(key) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!readonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"has\", key);\n }\n track(rawTarget, \"has\", rawKey);\n }\n return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);\n },\n forEach(callback, thisArg) {\n const observed = this;\n const target = observed[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive;\n !readonly && track(rawTarget, \"iterate\", ITERATE_KEY);\n return target.forEach((value, key) => {\n return callback.call(thisArg, wrap(value), wrap(key), observed);\n });\n }\n };\n extend(\n instrumentations,\n readonly ? {\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\")\n } : {\n add(value) {\n const target = toRaw(this);\n const proto = getProto(target);\n const rawValue = toRaw(value);\n const valueToAdd = !shallow && !isShallow(value) && !isReadonly(value) ? rawValue : value;\n const hadKey = proto.has.call(target, valueToAdd) || hasChanged(value, valueToAdd) && proto.has.call(target, value) || hasChanged(rawValue, valueToAdd) && proto.has.call(target, rawValue);\n if (!hadKey) {\n target.add(valueToAdd);\n trigger(target, \"add\", valueToAdd, valueToAdd);\n }\n return this;\n },\n set(key, value) {\n if (!shallow && !isShallow(value) && !isReadonly(value)) {\n value = toRaw(value);\n }\n const target = toRaw(this);\n const { has, get } = getProto(target);\n let hadKey = has.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has, key);\n }\n const oldValue = get.call(target, key);\n target.set(key, value);\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n return this;\n },\n delete(key) {\n const target = toRaw(this);\n const { has, get } = getProto(target);\n let hadKey = has.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has, key);\n }\n const oldValue = get ? get.call(target, key) : void 0;\n const result = target.delete(key);\n if (hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n },\n clear() {\n const target = toRaw(this);\n const hadItems = target.size !== 0;\n const oldTarget = !!(process.env.NODE_ENV !== \"production\") ? isMap(target) ? new Map(target) : new Set(target) : void 0;\n const result = target.clear();\n if (hadItems) {\n trigger(\n target,\n \"clear\",\n void 0,\n void 0,\n oldTarget\n );\n }\n return result;\n }\n }\n );\n const iteratorMethods = [\n \"keys\",\n \"values\",\n \"entries\",\n Symbol.iterator\n ];\n iteratorMethods.forEach((method) => {\n instrumentations[method] = createIterableMethod(method, readonly, shallow);\n });\n return instrumentations;\n}\nfunction createInstrumentationGetter(isReadonly2, shallow) {\n const instrumentations = createInstrumentations(isReadonly2, shallow);\n return (target, key, receiver) => {\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_raw\") {\n return target;\n }\n return Reflect.get(\n hasOwn(instrumentations, key) && key in target ? instrumentations : target,\n key,\n receiver\n );\n };\n}\nconst mutableCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, false)\n};\nconst shallowCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, true)\n};\nconst readonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, false)\n};\nconst shallowReadonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, true)\n};\nfunction checkIdentityKeys(target, has, key) {\n const rawKey = toRaw(key);\n if (rawKey !== key && has.call(target, rawKey)) {\n const type = toRawType(target);\n warn(\n `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`\n );\n }\n}\n\nconst reactiveMap = /* @__PURE__ */ new WeakMap();\nconst shallowReactiveMap = /* @__PURE__ */ new WeakMap();\nconst readonlyMap = /* @__PURE__ */ new WeakMap();\nconst shallowReadonlyMap = /* @__PURE__ */ new WeakMap();\nfunction targetTypeMap(rawType) {\n switch (rawType) {\n case \"Object\":\n case \"Array\":\n return 1 /* COMMON */;\n case \"Map\":\n case \"Set\":\n case \"WeakMap\":\n case \"WeakSet\":\n return 2 /* COLLECTION */;\n default:\n return 0 /* INVALID */;\n }\n}\n// @__NO_SIDE_EFFECTS__\nfunction reactive(target) {\n if (/* @__PURE__ */ isReadonly(target)) {\n return target;\n }\n return createReactiveObject(\n target,\n false,\n mutableHandlers,\n mutableCollectionHandlers,\n reactiveMap\n );\n}\n// @__NO_SIDE_EFFECTS__\nfunction shallowReactive(target) {\n return createReactiveObject(\n target,\n false,\n shallowReactiveHandlers,\n shallowCollectionHandlers,\n shallowReactiveMap\n );\n}\n// @__NO_SIDE_EFFECTS__\nfunction readonly(target) {\n return createReactiveObject(\n target,\n true,\n readonlyHandlers,\n readonlyCollectionHandlers,\n readonlyMap\n );\n}\n// @__NO_SIDE_EFFECTS__\nfunction shallowReadonly(target) {\n return createReactiveObject(\n target,\n true,\n shallowReadonlyHandlers,\n shallowReadonlyCollectionHandlers,\n shallowReadonlyMap\n );\n}\nfunction createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {\n if (!isObject(target)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\n `value cannot be made ${isReadonly2 ? \"readonly\" : \"reactive\"}: ${String(\n target\n )}`\n );\n }\n return target;\n }\n if (target[\"__v_raw\"] && !(isReadonly2 && target[\"__v_isReactive\"])) {\n return target;\n }\n if (target[\"__v_skip\"] || !Object.isExtensible(target)) {\n return target;\n }\n const existingProxy = proxyMap.get(target);\n if (existingProxy) {\n return existingProxy;\n }\n const targetType = targetTypeMap(toRawType(target));\n if (targetType === 0 /* INVALID */) {\n return target;\n }\n const proxy = new Proxy(\n target,\n targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers\n );\n proxyMap.set(target, proxy);\n return proxy;\n}\n// @__NO_SIDE_EFFECTS__\nfunction isReactive(value) {\n if (/* @__PURE__ */ isReadonly(value)) {\n return /* @__PURE__ */ isReactive(value[\"__v_raw\"]);\n }\n return !!(value && value[\"__v_isReactive\"]);\n}\n// @__NO_SIDE_EFFECTS__\nfunction isReadonly(value) {\n return !!(value && value[\"__v_isReadonly\"]);\n}\n// @__NO_SIDE_EFFECTS__\nfunction isShallow(value) {\n return !!(value && value[\"__v_isShallow\"]);\n}\n// @__NO_SIDE_EFFECTS__\nfunction isProxy(value) {\n return value ? !!value[\"__v_raw\"] : false;\n}\n// @__NO_SIDE_EFFECTS__\nfunction toRaw(observed) {\n const raw = observed && observed[\"__v_raw\"];\n return raw ? /* @__PURE__ */ toRaw(raw) : observed;\n}\nfunction markRaw(value) {\n if (!hasOwn(value, \"__v_skip\") && Object.isExtensible(value)) {\n def(value, \"__v_skip\", true);\n }\n return value;\n}\nconst toReactive = (value) => isObject(value) ? /* @__PURE__ */ reactive(value) : value;\nconst toReadonly = (value) => isObject(value) ? /* @__PURE__ */ readonly(value) : value;\n\n// @__NO_SIDE_EFFECTS__\nfunction isRef(r) {\n return r ? r[\"__v_isRef\"] === true : false;\n}\n// @__NO_SIDE_EFFECTS__\nfunction ref(value) {\n return createRef(value, false);\n}\n// @__NO_SIDE_EFFECTS__\nfunction shallowRef(value) {\n return createRef(value, true);\n}\nfunction createRef(rawValue, shallow) {\n if (/* @__PURE__ */ isRef(rawValue)) {\n return rawValue;\n }\n return new RefImpl(rawValue, shallow);\n}\nclass RefImpl {\n constructor(value, isShallow2) {\n this.dep = new Dep();\n this[\"__v_isRef\"] = true;\n this[\"__v_isShallow\"] = false;\n this._rawValue = isShallow2 ? value : toRaw(value);\n this._value = isShallow2 ? value : toReactive(value);\n this[\"__v_isShallow\"] = isShallow2;\n }\n get value() {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.dep.track({\n target: this,\n type: \"get\",\n key: \"value\"\n });\n } else {\n this.dep.track();\n }\n return this._value;\n }\n set value(newValue) {\n const oldValue = this._rawValue;\n const useDirectValue = this[\"__v_isShallow\"] || isShallow(newValue) || isReadonly(newValue);\n newValue = useDirectValue ? newValue : toRaw(newValue);\n if (hasChanged(newValue, oldValue)) {\n this._rawValue = newValue;\n this._value = useDirectValue ? newValue : toReactive(newValue);\n if (!!(process.env.NODE_ENV !== \"production\")) {\n this.dep.trigger({\n target: this,\n type: \"set\",\n key: \"value\",\n newValue,\n oldValue\n });\n } else {\n this.dep.trigger();\n }\n }\n }\n}\nfunction triggerRef(ref2) {\n if (ref2.dep) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n ref2.dep.trigger({\n target: ref2,\n type: \"set\",\n key: \"value\",\n newValue: ref2._value\n });\n } else {\n ref2.dep.trigger();\n }\n }\n}\nfunction unref(ref2) {\n return /* @__PURE__ */ isRef(ref2) ? ref2.value : ref2;\n}\nfunction toValue(source) {\n return isFunction(source) ? source() : unref(source);\n}\nconst shallowUnwrapHandlers = {\n get: (target, key, receiver) => key === \"__v_raw\" ? target : unref(Reflect.get(target, key, receiver)),\n set: (target, key, value, receiver) => {\n const oldValue = target[key];\n if (/* @__PURE__ */ isRef(oldValue) && !/* @__PURE__ */ isRef(value)) {\n oldValue.value = value;\n return true;\n } else {\n return Reflect.set(target, key, value, receiver);\n }\n }\n};\nfunction proxyRefs(objectWithRefs) {\n return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);\n}\nclass CustomRefImpl {\n constructor(factory) {\n this[\"__v_isRef\"] = true;\n this._value = void 0;\n const dep = this.dep = new Dep();\n const { get, set } = factory(dep.track.bind(dep), dep.trigger.bind(dep));\n this._get = get;\n this._set = set;\n }\n get value() {\n return this._value = this._get();\n }\n set value(newVal) {\n this._set(newVal);\n }\n}\nfunction customRef(factory) {\n return new CustomRefImpl(factory);\n}\n// @__NO_SIDE_EFFECTS__\nfunction toRefs(object) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isProxy(object)) {\n warn(`toRefs() expects a reactive object but received a plain one.`);\n }\n const ret = isArray(object) ? new Array(object.length) : {};\n for (const key in object) {\n ret[key] = propertyToRef(object, key);\n }\n return ret;\n}\nclass ObjectRefImpl {\n constructor(_object, key, _defaultValue) {\n this._object = _object;\n this._defaultValue = _defaultValue;\n this[\"__v_isRef\"] = true;\n this._value = void 0;\n this._key = isSymbol(key) ? key : String(key);\n this._raw = toRaw(_object);\n let shallow = true;\n let obj = _object;\n if (!isArray(_object) || isSymbol(this._key) || !isIntegerKey(this._key)) {\n do {\n shallow = !isProxy(obj) || isShallow(obj);\n } while (shallow && (obj = obj[\"__v_raw\"]));\n }\n this._shallow = shallow;\n }\n get value() {\n let val = this._object[this._key];\n if (this._shallow) {\n val = unref(val);\n }\n return this._value = val === void 0 ? this._defaultValue : val;\n }\n set value(newVal) {\n if (this._shallow && /* @__PURE__ */ isRef(this._raw[this._key])) {\n const nestedRef = this._object[this._key];\n if (/* @__PURE__ */ isRef(nestedRef)) {\n nestedRef.value = newVal;\n return;\n }\n }\n this._object[this._key] = newVal;\n }\n get dep() {\n return getDepFromReactive(this._raw, this._key);\n }\n}\nclass GetterRefImpl {\n constructor(_getter) {\n this._getter = _getter;\n this[\"__v_isRef\"] = true;\n this[\"__v_isReadonly\"] = true;\n this._value = void 0;\n }\n get value() {\n return this._value = this._getter();\n }\n}\n// @__NO_SIDE_EFFECTS__\nfunction toRef(source, key, defaultValue) {\n if (/* @__PURE__ */ isRef(source)) {\n return source;\n } else if (isFunction(source)) {\n return new GetterRefImpl(source);\n } else if (isObject(source) && arguments.length > 1) {\n return propertyToRef(source, key, defaultValue);\n } else {\n return /* @__PURE__ */ ref(source);\n }\n}\nfunction propertyToRef(source, key, defaultValue) {\n return new ObjectRefImpl(source, key, defaultValue);\n}\n\nclass ComputedRefImpl {\n constructor(fn, setter, isSSR) {\n this.fn = fn;\n this.setter = setter;\n /**\n * @internal\n */\n this._value = void 0;\n /**\n * @internal\n */\n this.dep = new Dep(this);\n /**\n * @internal\n */\n this.__v_isRef = true;\n // TODO isolatedDeclarations \"__v_isReadonly\"\n // A computed is also a subscriber that tracks other deps\n /**\n * @internal\n */\n this.deps = void 0;\n /**\n * @internal\n */\n this.depsTail = void 0;\n /**\n * @internal\n */\n this.flags = 16;\n /**\n * @internal\n */\n this.globalVersion = globalVersion - 1;\n /**\n * @internal\n */\n this.next = void 0;\n // for backwards compat\n this.effect = this;\n this[\"__v_isReadonly\"] = !setter;\n this.isSSR = isSSR;\n }\n /**\n * @internal\n */\n notify() {\n this.flags |= 16;\n if (!(this.flags & 8) && // avoid infinite self recursion\n activeSub !== this) {\n batch(this, true);\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\")) ;\n }\n get value() {\n const link = !!(process.env.NODE_ENV !== \"production\") ? this.dep.track({\n target: this,\n type: \"get\",\n key: \"value\"\n }) : this.dep.track();\n refreshComputed(this);\n if (link) {\n link.version = this.dep.version;\n }\n return this._value;\n }\n set value(newValue) {\n if (this.setter) {\n this.setter(newValue);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn(\"Write operation failed: computed value is readonly\");\n }\n }\n}\n// @__NO_SIDE_EFFECTS__\nfunction computed(getterOrOptions, debugOptions, isSSR = false) {\n let getter;\n let setter;\n if (isFunction(getterOrOptions)) {\n getter = getterOrOptions;\n } else {\n getter = getterOrOptions.get;\n setter = getterOrOptions.set;\n }\n const cRef = new ComputedRefImpl(getter, setter, isSSR);\n if (!!(process.env.NODE_ENV !== \"production\") && debugOptions && !isSSR) {\n cRef.onTrack = debugOptions.onTrack;\n cRef.onTrigger = debugOptions.onTrigger;\n }\n return cRef;\n}\n\nconst TrackOpTypes = {\n \"GET\": \"get\",\n \"HAS\": \"has\",\n \"ITERATE\": \"iterate\"\n};\nconst TriggerOpTypes = {\n \"SET\": \"set\",\n \"ADD\": \"add\",\n \"DELETE\": \"delete\",\n \"CLEAR\": \"clear\"\n};\nconst ReactiveFlags = {\n \"SKIP\": \"__v_skip\",\n \"IS_REACTIVE\": \"__v_isReactive\",\n \"IS_READONLY\": \"__v_isReadonly\",\n \"IS_SHALLOW\": \"__v_isShallow\",\n \"RAW\": \"__v_raw\",\n \"IS_REF\": \"__v_isRef\"\n};\n\nconst WatchErrorCodes = {\n \"WATCH_GETTER\": 2,\n \"2\": \"WATCH_GETTER\",\n \"WATCH_CALLBACK\": 3,\n \"3\": \"WATCH_CALLBACK\",\n \"WATCH_CLEANUP\": 4,\n \"4\": \"WATCH_CLEANUP\"\n};\nconst INITIAL_WATCHER_VALUE = {};\nconst cleanupMap = /* @__PURE__ */ new WeakMap();\nlet activeWatcher = void 0;\nfunction getCurrentWatcher() {\n return activeWatcher;\n}\nfunction onWatcherCleanup(cleanupFn, failSilently = false, owner = activeWatcher) {\n if (owner) {\n let cleanups = cleanupMap.get(owner);\n if (!cleanups) cleanupMap.set(owner, cleanups = []);\n cleanups.push(cleanupFn);\n } else if (!!(process.env.NODE_ENV !== \"production\") && !failSilently) {\n warn(\n `onWatcherCleanup() was called when there was no active watcher to associate with.`\n );\n }\n}\nfunction watch(source, cb, options = EMPTY_OBJ) {\n const { immediate, deep, once, scheduler, augmentJob, call } = options;\n const warnInvalidSource = (s) => {\n (options.onWarn || warn)(\n `Invalid watch source: `,\n s,\n `A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.`\n );\n };\n const reactiveGetter = (source2) => {\n if (deep) return source2;\n if (isShallow(source2) || deep === false || deep === 0)\n return traverse(source2, 1);\n return traverse(source2);\n };\n let effect;\n let getter;\n let cleanup;\n let boundCleanup;\n let forceTrigger = false;\n let isMultiSource = false;\n if (isRef(source)) {\n getter = () => source.value;\n forceTrigger = isShallow(source);\n } else if (isReactive(source)) {\n getter = () => reactiveGetter(source);\n forceTrigger = true;\n } else if (isArray(source)) {\n isMultiSource = true;\n forceTrigger = source.some((s) => isReactive(s) || isShallow(s));\n getter = () => source.map((s) => {\n if (isRef(s)) {\n return s.value;\n } else if (isReactive(s)) {\n return reactiveGetter(s);\n } else if (isFunction(s)) {\n return call ? call(s, 2) : s();\n } else {\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(s);\n }\n });\n } else if (isFunction(source)) {\n if (cb) {\n getter = call ? () => call(source, 2) : source;\n } else {\n getter = () => {\n if (cleanup) {\n pauseTracking();\n try {\n cleanup();\n } finally {\n resetTracking();\n }\n }\n const currentEffect = activeWatcher;\n activeWatcher = effect;\n try {\n return call ? call(source, 3, [boundCleanup]) : source(boundCleanup);\n } finally {\n activeWatcher = currentEffect;\n }\n };\n }\n } else {\n getter = NOOP;\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(source);\n }\n if (cb && deep) {\n const baseGetter = getter;\n const depth = deep === true ? Infinity : deep;\n getter = () => traverse(baseGetter(), depth);\n }\n const scope = getCurrentScope();\n const watchHandle = () => {\n effect.stop();\n if (scope && scope.active) {\n remove(scope.effects, effect);\n }\n };\n if (once && cb) {\n const _cb = cb;\n cb = (...args) => {\n const res = _cb(...args);\n watchHandle();\n return res;\n };\n }\n let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;\n const job = (immediateFirstRun) => {\n if (!(effect.flags & 1) || !effect.dirty && !immediateFirstRun) {\n return;\n }\n if (cb) {\n const newValue = effect.run();\n if (immediateFirstRun || deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue))) {\n if (cleanup) {\n cleanup();\n }\n const currentWatcher = activeWatcher;\n activeWatcher = effect;\n try {\n const args = [\n newValue,\n // pass undefined as the old value when it's changed for the first time\n oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue,\n boundCleanup\n ];\n oldValue = newValue;\n call ? call(cb, 3, args) : (\n // @ts-expect-error\n cb(...args)\n );\n } finally {\n activeWatcher = currentWatcher;\n }\n }\n } else {\n effect.run();\n }\n };\n if (augmentJob) {\n augmentJob(job);\n }\n effect = new ReactiveEffect(getter);\n effect.scheduler = scheduler ? () => scheduler(job, false) : job;\n boundCleanup = (fn) => onWatcherCleanup(fn, false, effect);\n cleanup = effect.onStop = () => {\n const cleanups = cleanupMap.get(effect);\n if (cleanups) {\n if (call) {\n call(cleanups, 4);\n } else {\n for (const cleanup2 of cleanups) cleanup2();\n }\n cleanupMap.delete(effect);\n }\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n effect.onTrack = options.onTrack;\n effect.onTrigger = options.onTrigger;\n }\n if (cb) {\n if (immediate) {\n job(true);\n } else {\n oldValue = effect.run();\n }\n } else if (scheduler) {\n scheduler(job.bind(null, true), true);\n } else {\n effect.run();\n }\n watchHandle.pause = effect.pause.bind(effect);\n watchHandle.resume = effect.resume.bind(effect);\n watchHandle.stop = watchHandle;\n return watchHandle;\n}\nfunction traverse(value, depth = Infinity, seen) {\n if (depth <= 0 || !isObject(value) || value[\"__v_skip\"]) {\n return value;\n }\n seen = seen || /* @__PURE__ */ new Map();\n if ((seen.get(value) || 0) >= depth) {\n return value;\n }\n seen.set(value, depth);\n depth--;\n if (isRef(value)) {\n traverse(value.value, depth, seen);\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n traverse(value[i], depth, seen);\n }\n } else if (isSet(value) || isMap(value)) {\n value.forEach((v) => {\n traverse(v, depth, seen);\n });\n } else if (isPlainObject(value)) {\n for (const key in value) {\n traverse(value[key], depth, seen);\n }\n for (const key of Object.getOwnPropertySymbols(value)) {\n if (Object.prototype.propertyIsEnumerable.call(value, key)) {\n traverse(value[key], depth, seen);\n }\n }\n }\n return value;\n}\n\nexport { ARRAY_ITERATE_KEY, EffectFlags, EffectScope, ITERATE_KEY, MAP_KEY_ITERATE_KEY, ReactiveEffect, ReactiveFlags, TrackOpTypes, TriggerOpTypes, WatchErrorCodes, computed, customRef, effect, effectScope, enableTracking, getCurrentScope, getCurrentWatcher, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, onEffectCleanup, onScopeDispose, onWatcherCleanup, pauseTracking, proxyRefs, reactive, reactiveReadArray, readonly, ref, resetTracking, shallowReactive, shallowReadArray, shallowReadonly, shallowRef, stop, toRaw, toReactive, toReadonly, toRef, toRefs, toValue, track, traverse, trigger, triggerRef, unref, watch };\n",
|
|
10
|
+
"/**\n * Clock — the one seam every _relative_ time in Studio reads \"now\" through.\n *\n * Four surfaces render a duration rather than an instant: the Source Control panel's commit ages\n * and \"last refreshed\", the Start pane's \"last opened\", the chat session list's row times, and the\n * recents list those two read from. Each of them called `Date.now()` inline, which had two costs:\n *\n * 1. **They were untestable.** A formatter that reads the wall clock can only be asserted against an\n * offset from the real present, so \"yesterday\" and \"over a year ago\" were never covered.\n * 2. **They drift.** Two captures of the same state minutes apart legitimately read `01:59 PM` and\n * `02:04 PM` (UX-REDESIGN-PLAN §13.4 measured exactly that on the git-panel shot).\n *\n * This is deliberately NOT a global `Date.now` override. Monaco, every `setTimeout`, the collab\n * clock and the transaction log all read the real clock and must keep reading it — pinning time for\n * the whole realm hangs the editor. Four imports, four honest readers.\n *\n * `pinClock` is also what makes session restore's \"last opened\" honest: the value written is the\n * value the formatter reads back.\n */\n\n/** Epoch milliseconds the clock is pinned to, or `null` while it follows the real clock. */\nlet _pinned: number | null = null;\n\n/**\n * The current time in epoch milliseconds — pinned when {@link pinClock} has been called, otherwise\n * the wall clock.\n *\n * Frozen rather than offset while pinned: a shot, a test and a bug report all want the SAME answer\n * on the tenth read as on the first, and a ticking pin reintroduces exactly the drift it exists to\n * remove.\n */\nexport function now(): number {\n return _pinned ?? Date.now();\n}\n\n/**\n * Pin the clock to a fixed instant. Accepts epoch milliseconds, a `Date`, or anything `Date` parses\n * (the `2026-01-15T09:30:00Z` an `open.clock` field carries).\n *\n * @returns The pinned instant, in epoch milliseconds.\n * @throws {TypeError} When the value cannot be read as a time — a silently-ignored pin would\n * photograph the wall clock and the capture would be accepted.\n */\nexport function pinClock(at: number | string | Date): number {\n const ms = at instanceof Date ? at.getTime() : typeof at === \"number\" ? at : Date.parse(at);\n if (!Number.isFinite(ms)) {\n throw new TypeError(`clock: cannot pin to ${JSON.stringify(at)}`);\n }\n _pinned = ms;\n return ms;\n}\n\n/** Release the pin; {@link now} follows the wall clock again. */\nexport function unpinClock(): void {\n _pinned = null;\n}\n\n/** Whether the clock is currently pinned. Read by `probe.state()` and by the tests. */\nexport function isClockPinned(): boolean {\n return _pinned !== null;\n}\n",
|
|
11
|
+
"/// <reference lib=\"dom\" />\n/**\n * Regions — the shell's addressable surfaces, in one id space.\n *\n * `shell.ts` declares `FocusRegion = \"rail\" | \"navigator\" | \"pane\" | \"inspector\" | \"dock\" |\n * \"status\"` and has done since the shell record landed. It is an enum with **no DOM counterpart**:\n * nothing can be asked where the Navigator _is_, so nothing can move focus into it, cycle to the\n * next one, or measure it. Three consumers want exactly that map — F6 region cycling, focus\n * restoration after a toast or a Problems jump, and the screenshot pipeline, which today addresses\n * the shell through sixteen CSS selectors, seven of which name nodes the shell redesign deletes.\n *\n * **The grammar** (UX-REDESIGN-PLAN §13.2) is `<surface>[.<instance>][/<part>]`:\n *\n * ```text\n * navigator the Navigator dock\n * navigator/panel:git the Source Control panel inside it\n * navigator/panel:git/commit a leaf within that panel\n * inspector/tab:style the Style tab's body\n * inspector/field:href a field row (ui/field-row.ts already emits `data-prop`)\n * pane.primary/tabs the primary pane's own tab strip\n * overlay.dialog:settings a named overlay slot\n * ```\n *\n * **Ids are DERIVED, not authored**, which is the property that makes them survive a rename. The\n * panel host stamps `navigator/panel:${id}` once and every panel gets a region for free; the\n * inspector stamps `inspector/tab:${key}` from its own tab records; `getLayerSlot()` stamps\n * `overlay.<kind>:<id>` from the key it already builds. A panel rename then propagates to the\n * region automatically, and a stale id fails the shot contract instead of photographing the wrong\n * box. Only leaves — `navigator/panel:git/commit` — are hand-stamped, and those are counted.\n *\n * Resolution reads the live DOM rather than a registration table, for the same reason\n * {@link import(\"./layers\").isModalOpen} does: whatever is on screen is the answer, and there is no\n * bookkeeping for a new surface to forget.\n */\n\nimport type { FocusRegion } from \"../shell\";\n\n/** The attribute every region carries. One attribute, one grammar, one resolver. */\nexport const REGION_ATTR = \"data-jx-region\";\n\n/** The eight surfaces §13.2 declares. A region id always begins with one of these. */\nexport const REGION_SURFACES = [\n \"rail\",\n \"navigator\",\n \"inspector\",\n \"pane\",\n \"dock.bottom\",\n \"statusbar\",\n \"commandbar\",\n \"overlay\",\n] as const;\n\nexport type RegionSurface = (typeof REGION_SURFACES)[number];\n\n/** A parsed region id. `instance` and `part` are absent for a bare surface. */\nexport interface ParsedRegionId {\n surface: RegionSurface;\n /** `primary` in `pane.primary`, `dialog` in `overlay.dialog:settings`. */\n instance?: string;\n /** Everything after the first `/` — `panel:git/commit` in `navigator/panel:git/commit`. */\n part?: string;\n}\n\n/**\n * `dock.bottom` is the one surface whose name contains the instance separator, so the split is\n * longest-prefix rather than \"up to the first dot\".\n */\nconst DOTTED_SURFACES = new Set<string>([\"dock.bottom\"]);\n\n/**\n * Parse a region id, or return `null` when it is not one.\n *\n * Rejecting is the point: the resolver never falls back to `querySelector(id)`, so a CSS selector\n * that slips into a manifest resolves to nothing instead of quietly working.\n */\nexport function parseRegionId(id: string): ParsedRegionId | null {\n const slash = id.indexOf(\"/\");\n const head = slash === -1 ? id : id.slice(0, slash);\n const part = slash === -1 ? undefined : id.slice(slash + 1);\n if (part === \"\" || head === \"\") {\n return null;\n }\n\n let surface = head;\n let instance: string | undefined;\n if (!DOTTED_SURFACES.has(head)) {\n const dot = head.indexOf(\".\");\n if (dot !== -1) {\n surface = head.slice(0, dot);\n instance = head.slice(dot + 1);\n if (instance === \"\") {\n return null;\n }\n }\n }\n if (!(REGION_SURFACES as readonly string[]).includes(surface)) {\n return null;\n }\n return instance === undefined\n ? part === undefined\n ? { surface: surface as RegionSurface }\n : { part, surface: surface as RegionSurface }\n : part === undefined\n ? { instance, surface: surface as RegionSurface }\n : { instance, part, surface: surface as RegionSurface };\n}\n\n/** Whether a string is a well-formed region id. */\nexport function isRegionId(id: string): boolean {\n return parseRegionId(id) !== null;\n}\n\n/**\n * `pane` names the primary pane.\n *\n * The second pane arrives with the pane grid, and every id minted before it should keep meaning\n * what it meant — so the alias is declared here once rather than at each call site.\n */\nfunction canonicalRegionId(id: string): string {\n if (id === \"pane\") {\n return \"pane.primary\";\n }\n return id.startsWith(\"pane/\") ? `pane.primary/${id.slice(5)}` : id;\n}\n\n/** Where the search runs. Injectable so a test can resolve inside a detached tree. */\ntype RegionRoot = Pick<ParentNode, \"querySelectorAll\">;\n\nfunction regionRoot(root?: RegionRoot): RegionRoot {\n return root ?? document;\n}\n\n/**\n * Ids answered by an attribute the app ALREADY emits, rather than by a `data-jx-region` stamp.\n *\n * `ui/field-row.ts` has emitted `data-prop=${prop}` on every inspector row since it landed, and the\n * screenshot manifest has been addressing `#right-panel [data-prop='href']` through it for as long.\n * Restamping several hundred rows with a second attribute saying the same thing would be pure\n * duplication, so the grammar reads the existing one — `inspector/field:href` is the id, and the\n * precedent is the reason that part of the grammar was specified the way it was.\n */\nconst DERIVED_RESOLVERS: readonly {\n pattern: RegExp;\n locate: (match: RegExpMatchArray, root: RegionRoot) => HTMLElement[];\n}[] = [\n /*\n * The Browse control of an Inspector field — ORDER MATTERS, it must precede the bare field rule,\n * which would otherwise claim `image/browse` as a prop named \"image/browse\".\n *\n * `ui/media-picker.ts` used to STAMP this id on the button itself, and the id was a lie about\n * where the button is: the same picker draws the Document Header card's Icon and og:image fields,\n * and that card is rendered inside a PANE's stage. So `inspector/field:icon/browse` resolved to\n * two elements the moment the grid split — one per pane, neither of them in the Inspector — and\n * `resolveRegion` takes the LAST, which is the side pane's. `paneRegion` could never have reached\n * it: an `inspector/…` id on an element outside the Inspector is not a pane-scoping problem, it\n * is a wrong id.\n *\n * Deriving it fixes both halves at once. The id now MEANS \"the Browse control of the Inspector's\n * field `<prop>`\", the search is scoped to the one Inspector, and the card's own pickers answer\n * to nothing — correctly, because they are not in the Inspector. Nothing addresses them today;\n * when something does, the id is `pane.<id>/field:<prop>/browse` and it is derived from the pane\n * like every other stage-content id.\n */\n {\n locate: ([, prop], root) => {\n const row = resolveRegion(`inspector/field:${prop!}`, root);\n const browse = row?.querySelector<HTMLElement>(\".media-picker-browse\");\n return browse ? [browse] : [];\n },\n pattern: /^inspector\\/field:(.+)\\/browse$/,\n },\n {\n locate: ([, prop], root) => {\n const inspector = resolveRegion(\"inspector\", root);\n return inspector\n ? [...inspector.querySelectorAll<HTMLElement>(`[data-prop=\"${CSS.escape(prop!)}\"]`)]\n : [];\n },\n pattern: /^inspector\\/field:(.+)$/,\n },\n];\n\n/**\n * Every element currently carrying `id`, in document order.\n *\n * Plural because overlays legitimately stack: two popovers open at once both used to match\n * `sp-popover[open]`, and the shot cropped whichever the DOM happened to list first. An id that\n * addresses several elements is answerable — `resolve` takes the last, which is the topmost.\n */\nexport function resolveAllRegions(id: string, root?: RegionRoot): HTMLElement[] {\n const canonical = canonicalRegionId(id);\n if (!isRegionId(canonical)) {\n return [];\n }\n const stamped = [\n ...regionRoot(root).querySelectorAll<HTMLElement>(\n `[${REGION_ATTR}=\"${CSS.escape(canonical)}\"]`,\n ),\n ];\n if (stamped.length > 0) {\n return stamped;\n }\n for (const resolver of DERIVED_RESOLVERS) {\n const match = canonical.match(resolver.pattern);\n if (match) {\n return resolver.locate(match, regionRoot(root));\n }\n }\n return [];\n}\n\n/**\n * The element a region id addresses right now, or `null`.\n *\n * The LAST match wins, because the only ids that repeat are overlay slots and the last one appended\n * is the one on top.\n */\nexport function resolveRegion(id: string, root?: RegionRoot): HTMLElement | null {\n const all = resolveAllRegions(id, root);\n return all.at(-1) ?? null;\n}\n\n/** Every region id present in the DOM, deduplicated and sorted — the map, enumerated. */\nexport function listRegions(root?: RegionRoot): string[] {\n const ids = new Set<string>();\n for (const el of regionRoot(root).querySelectorAll<HTMLElement>(`[${REGION_ATTR}]`)) {\n const id = el.getAttribute(REGION_ATTR);\n if (id && isRegionId(id)) {\n ids.add(id);\n }\n }\n return [...ids].toSorted();\n}\n\n/** The region id nearest ancestor-or-self of `el` declares, or `null`. */\nexport function regionIdOf(el: Element | null): string | null {\n const host = el?.closest(`[${REGION_ATTR}]`);\n const id = host?.getAttribute(REGION_ATTR) ?? null;\n return id && isRegionId(id) ? id : null;\n}\n\n// ─── The FocusRegion ↔ region-id map ─────────────────────────────────────────\n\n/**\n * `shell.focusRegion`'s six values, as region ids.\n *\n * This is the map that made the enum inert: the shell could say which region had focus and nothing\n * could act on it. With it, \"focus the Navigator\" is `resolveRegion(REGION_FOR_FOCUS.navigator)`,\n * and F6 is a walk over `Object.keys`.\n */\nexport const REGION_FOR_FOCUS: Readonly<Record<FocusRegion, string>> = {\n dock: \"dock.bottom\",\n inspector: \"inspector\",\n navigator: \"navigator\",\n pane: \"pane.primary\",\n rail: \"rail\",\n status: \"statusbar\",\n};\n\nconst FOCUS_FOR_SURFACE: Readonly<Record<string, FocusRegion>> = {\n \"dock.bottom\": \"dock\",\n inspector: \"inspector\",\n navigator: \"navigator\",\n pane: \"pane\",\n rail: \"rail\",\n statusbar: \"status\",\n};\n\n/**\n * Which `shell.focusRegion` an element sits in, or `null` when it is outside every region (an\n * overlay, or a node nobody has stamped).\n *\n * The inverse direction matters as much as the forward one: focus moves for reasons the shell did\n * not initiate — a click, a toast dismissal, restoring the caret after a dialog — and the record\n * has to be able to catch up from the DOM.\n */\nexport function focusRegionOf(el: Element | null): FocusRegion | null {\n const id = regionIdOf(el);\n if (!id) {\n return null;\n }\n const parsed = parseRegionId(id);\n return parsed ? (FOCUS_FOR_SURFACE[parsed.surface] ?? null) : null;\n}\n\n// ─── Stamping ─────────────────────────────────────────────────────────────────\n\n/**\n * The shell's fixed hosts, declared once.\n *\n * These live in `index.html` as bare `<div id>`s, so they cannot stamp themselves the way a panel\n * or an overlay slot does. The table is the shell's own layout stated in region terms, and it is\n * the only place a surface id is written down by hand.\n *\n * `#tab-strip` is addressed as `pane.primary/tabs` deliberately: the region names the PANE's strip,\n * so the id survives the node. The assistant is the case that has now happened twice over:\n * `inspector.assistant` was minted while the chat was a fifth grid column, survived the column\n * being deleted, and survives the `#chat-panel` DIV being deleted too — it is stamped by\n * `panels/chat-panel.ts` on whatever container hosts the assistant, which is now the Inspector's\n * fourth tab body. That is the whole argument for naming the role rather than the div, and the\n * reason this table lost a row without any shot losing its subject.\n *\n * `pane.primary/frontmatter` left the table for the same reason. It named `#frontmatter-panel`, a\n * grid row; the Document Header card is now drawn INSIDE the stage, so\n * `panels/frontmatter-panel.ts` stamps the id on the card's own `<section>` wherever the stage puts\n * it. Two rows gone, no shot re-pointed.\n *\n * `pane.primary` and `pane.primary/tabs` are the third and fourth to leave, and the clearest case\n * yet: they named `#canvas-wrap` and `#tab-strip`, two flat siblings of an APPLICATION grid that\n * were only ever the primary pane's stage and strip. `panels/pane-grid.ts` builds a cell per pane\n * and stamps {@link paneRegion} on each, so the id is derived from the pane rather than from a div\n * that could only ever be one of them. Four rows gone, not one shot re-pointed.\n */\nexport const SHELL_REGION_HOSTS: Readonly<Record<string, string>> = {\n \"#activity-bar\": \"rail\",\n // The fourth overlay layer. It is here rather than stamped by `ui/layers.ts` for the same reason\n // Every other row is: it is a bare `<div id>` in index.html, so it cannot stamp itself, and the\n // Id has to resolve whether or not a toast has ever been raised — a region that only exists once\n // Something has gone wrong is a region a shot cannot address and focus cannot be moved into.\n \"#layer-toast\": \"overlay.toasts\",\n \"#left-panel\": \"navigator\",\n \"#right-panel\": \"inspector\",\n \"#statusbar\": \"statusbar\",\n \"#toolbar\": \"commandbar\",\n};\n\n/**\n * Stamp the shell hosts. Idempotent, and safe to call before the DOM exists (an absent host is\n * simply not stamped — the desktop shell and the tests both boot partial trees).\n */\nexport function stampShellRegions(root: ParentNode = document): void {\n for (const [selector, id] of Object.entries(SHELL_REGION_HOSTS)) {\n root.querySelector(selector)?.setAttribute(REGION_ATTR, id);\n }\n}\n\n/**\n * Region id for a pane, or for a part inside one — derived from the pane's own id.\n *\n * The fourth member of the derived-region family, and the one that had to exist before a second\n * pane could be drawn. Twelve surfaces used to emit the literal `pane.primary/…` because the shell\n * had exactly one pane to be; the moment two cells are on screen, every one of those ids resolves\n * to two elements and `resolveRegion` takes the LAST — so a shot cropping `pane.primary/library`\n * would silently photograph the SIDE pane's library. For the primary this produces byte-identical\n * strings, which is why the manifest needed no edit.\n *\n * @param {string} paneId\n * @param {string} [part]\n * @returns {string}\n */\nexport function paneRegion(paneId: string, part?: string): string {\n return part ? `pane.${paneId}/${part}` : `pane.${paneId}`;\n}\n\n/** Region id of a pane's tab strip. One spelling, derived like every other. */\nexport function paneStripRegion(paneId: string): string {\n return paneRegion(paneId, \"tabs\");\n}\n\n/** Region id for a Navigator panel, derived from the panel's own id. */\nexport function navigatorPanelRegion(panelId: string): string {\n return `navigator/panel:${panelId}`;\n}\n\n/** Region id for an Inspector tab, derived from the tab record's value. */\nexport function inspectorTabRegion(tabId: string): string {\n return `inspector/tab:${tabId}`;\n}\n\n/**\n * The statement editor has TWO hosts, so the id names the host and not the control.\n *\n * `panels/statement-editor.ts` hard-stamped `navigator/statements` on itself. It is drawn by the\n * Navigator's State panel AND by the Inspector's Events tab, both openable at once, and\n * {@link resolveRegion} takes the LAST match in document order — `#right-panel` follows\n * `#left-panel` — so the id addressed the INSPECTOR's editor under a name that says Navigator, and\n * the shot cropping it cropped a control in the wrong dock.\n *\n * These two constants are the fix, and their shape is the general rule: a shared control cannot\n * know where it is, so its region id is a REQUIRED argument its host supplies (see\n * {@link import(\"../panels/statement-editor\").StatementEditorOpts}). A third host cannot be added\n * without naming itself.\n */\nexport const NAVIGATOR_STATEMENTS_REGION = \"navigator/statements\";\n\n/**\n * The Inspector's statement editor, named by the HANDLER it edits.\n *\n * A constant was only half the fix. `panels/events-panel.ts` draws this editor inside\n * `eventEntries.map(...)` — one per structured handler on the selected node — so a node with\n * `onClick` and `onInput` stamped `inspector/statements` on two elements and `resolveRegion` took\n * the second. That is the same defect the Navigator/Inspector split was made to close, one level\n * down: an id that is unique because of what happens to be on screen is not unique.\n *\n * The Navigator's stays a constant because its host has ONE slot (`expandedSignal`), and deriving\n * an id there would be inventing a distinction the surface does not have.\n *\n * @param {string} eventKey The handler's property key — `onClick`, `onInput`.\n * @returns {string}\n */\nexport function inspectorStatementsRegion(eventKey: string): string {\n return `inspector/statements:${eventKey}`;\n}\n\n/**\n * Region id for a Bottom dock tab, derived from the panel's own id.\n *\n * The third member of the derived-region family, and the one that shows the grammar was worth\n * specifying before the surface existed: `dock.bottom` has parsed since P3 (it is the only surface\n * whose NAME contains the instance separator, which is why {@link DOTTED_SURFACES} exists) and\n * resolved to nothing, because nothing hosted it. `panels/bottom-dock.ts` stamps this once, from\n * the same id `view.setBottomTab` accepts, so the dock's four tabs are addressable without anyone\n * authoring an id — and the host itself carries the bare `dock.bottom` only while it is open, so a\n * closed dock resolves to nothing rather than to an invisible box.\n */\nexport function bottomPanelRegion(panelId: string): string {\n return `dock.bottom/panel:${panelId}`;\n}\n\n/**\n * The overlay instance each layer host contributes: a modal IS a dialog, a popover IS a menu.\n *\n * `toast` is plural because the host is the STACK, not one notification: `overlay.toasts` addresses\n * the whole live region, which is what a shot crops and what a focus move lands in. An individual\n * toast is a row inside it and is addressed by nothing — it is not a surface a user navigates to.\n */\nexport const OVERLAY_INSTANCE: Readonly<Record<\"popover\" | \"modal\" | \"dialog\" | \"toast\", string>> =\n {\n dialog: \"dialog\",\n modal: \"dialog\",\n popover: \"menu\",\n toast: \"toasts\",\n };\n\n/**\n * Region id for an overlay slot.\n *\n * With an `id` this is `overlay.dialog:settings` — derived from the key `getLayerSlot` already\n * builds, so naming a slot names its region. Without one it is the bare instance, which resolves to\n * the topmost open overlay of that kind.\n */\nexport function overlayRegion(\n layer: \"popover\" | \"modal\" | \"dialog\" | \"toast\",\n id?: string,\n): string {\n const instance = OVERLAY_INSTANCE[layer];\n return id ? `overlay.${instance}:${id}` : `overlay.${instance}`;\n}\n\n/**\n * `regions` — the namespace §13.3 names, gathered so a consumer imports one thing.\n *\n * `probe.regions` is a projection of this; nothing here knows the camera exists.\n */\nexport const regions = {\n focusRegionOf,\n idOf: regionIdOf,\n list: listRegions,\n parse: parseRegionId,\n resolve: resolveRegion,\n resolveAll: resolveAllRegions,\n} as const;\n",
|
|
12
|
+
"/**\n * The app's live region: one element, one call site, everything the app says out loud.\n *\n * **Why this exists.** `notify.ts` is the app's only way to say what happened, and its default tier\n * routes **error ⇒ problem**. But the `role=\"status\"` region lived on the _toast_ host, and the\n * Problems panel had none at all — so a **failure reached no live region whatsoever**. The app\n * would post \"Save failed\", show it in a panel, and a screen-reader user would be told nothing. A\n * panel-local region would not have fixed it either: the Problems list lives in the Bottom dock,\n * and a region inside a hidden tab announces nothing.\n *\n * So the announcer is not a panel's concern. It is called from {@link notify} itself — one call\n * site, so a record cannot be posted without being announced, and a future host gets announcements\n * for free rather than having to remember.\n *\n * **Two regions, because politeness is not a style choice** (WAI-ARIA §5.2.9). `assertive`\n * interrupts whatever the reader is listening to, which is right for a failure and rude for a save.\n * `polite` waits for a pause. Mixing both in one region does not work — the attribute is read when\n * the region is created, not when the text changes — so there are two, and the severity picks.\n *\n * **The text is cleared, then set on a later frame.** A live region announces a _change_; writing\n * the same string twice is not one, so a repeated failure would be silent. Clearing first makes\n * every post a change.\n *\n * @docs studio/interface/problems-and-progress\n */\n\n/** How urgently a message interrupts. Errors interrupt; everything else waits for a pause. */\nexport type Politeness = \"assertive\" | \"polite\";\n\nconst REGION_ID: Readonly<Record<Politeness, string>> = {\n assertive: \"jx-live-assertive\",\n polite: \"jx-live-polite\",\n};\n\n/**\n * Find (or create) a live region.\n *\n * It is appended to `<body>` rather than to any panel, and it is visually hidden with the clip-rect\n * idiom rather than `display: none` — a display-none region is removed from the accessibility tree\n * entirely and announces nothing, which is the classic way to ship a live region that does not\n * work.\n */\nfunction region(politeness: Politeness): HTMLElement | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const id = REGION_ID[politeness];\n const existing = document.querySelector<HTMLElement>(`#${id}`);\n if (existing) {\n return existing;\n }\n const node = document.createElement(\"div\");\n node.id = id;\n node.setAttribute(\"aria-live\", politeness);\n /* `status` for polite and `alert` for assertive: the implicit roles, so an assistive technology\n that reads roles rather than the attribute agrees with one that does the opposite. */\n node.setAttribute(\"role\", politeness === \"assertive\" ? \"alert\" : \"status\");\n node.setAttribute(\"aria-atomic\", \"true\");\n node.style.cssText =\n \"position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;\" +\n \"clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0\";\n document.body.append(node);\n return node;\n}\n\n/**\n * Say something out loud.\n *\n * @param {string} message What to announce. Empty strings are ignored — a live region that receives\n * one announces nothing, so posting it only hides a caller's bug.\n * @param {Politeness} [politeness] Defaults to `polite`.\n */\nexport function announce(message: string, politeness: Politeness = \"polite\"): void {\n if (message === \"\") {\n return;\n }\n const node = region(politeness);\n if (!node) {\n return;\n }\n node.textContent = \"\";\n /* A live region announces a CHANGE. Writing the same string twice is not one, so a second\n identical failure would be silent without the clear-then-set on a later turn. */\n setTimeout(() => {\n node.textContent = message;\n }, 0);\n}\n\n/** Remove both regions. Tests only — a leaked region makes the next test's assertions ambiguous. */\nexport function resetAnnouncer(): void {\n if (typeof document === \"undefined\") {\n return;\n }\n for (const id of Object.values(REGION_ID)) {\n document.querySelector(`#${id}`)?.remove();\n }\n}\n",
|
|
13
|
+
"/**\n * Notify.ts — the third record type (plan §1), and the app's only way to say what happened.\n *\n * What this replaces: 78 `statusMessage()` call sites — 26 failures and 52 successes — rendered in\n * identical 11px grey text in a 24px strip and destroyed after 3000 ms. A failure and a save looked\n * the same, neither could be acted on, and both were gone before a reader who had looked away could\n * read them. `statusMessage` is deleted, not wrapped; `scripts/check-styles.ts` bans the name from\n * `src/` so it cannot regrow.\n *\n * **A notification is a record, and its lifetime is chosen by the action it requires** (§7.1):\n *\n * | Tier | Host | Lifetime | Use when |\n * | --------- | -------------------------- | ------------------ | ------------------------------ |\n * | `toast` | the fourth overlay layer | timed, dismissible | reversible, or needs no action |\n * | `problem` | the Bottom dock's Problems | until it is fixed | it must be fixed |\n *\n * §7.1 names a third tier — **inline**, the `error` slot on `ui/field-row.ts`'s `renderFieldRow`.\n * It is deliberately NOT a member of {@link NotificationTier}: an inline error is a value a control\n * renders next to the field the user is editing, not a record the app posts to a host, and it has\n * no store to live in. Declaring a tier here whose only possible outcome is being dropped on the\n * floor would be exactly the silence this module exists to end, so the union has two members and\n * the third tier arrives as `renderFieldRow`'s own parameter (P4.4).\n *\n * **Recovery is a command id, not a per-call-site closure.** `notify.error(\"Save failed\", { action:\n * \"file.save\" })` gives the toast and the Problems row a Retry button whose label, availability,\n * disabled reason and keyboard chord all come off the command record — which is why this lives\n * beside the registry rather than inside any one surface. A call site that wanted a Retry used to\n * have to invent a button; now it names a capability that already exists.\n *\n * Nothing here renders. `ui/layers.ts` hosts the toasts and the Bottom dock hosts the Problems\n * list; both read the two reactive arrays below, so a new surface can render notifications without\n * this module learning it exists.\n */\n\nimport { reactive } from \"../reactivity\";\nimport { announce } from \"./announce\";\nimport { now } from \"./clock\";\n\n/** How bad it is. Chooses the icon, the colour, and the default tier. */\nexport const SEVERITIES = [\"success\", \"info\", \"warn\", \"error\"] as const;\n\nexport type Severity = (typeof SEVERITIES)[number];\n\n/**\n * The two hosted lifetimes.\n *\n * A tier is a HOST, not a rendering preference: a record whose tier is `problem` is one the app\n * promises to keep until somebody fixes it, and a record whose tier is `toast` is one it promises\n * to take away. See the module doc for why `inline` is not here.\n */\nexport const TIERS = [\"toast\", \"problem\"] as const;\n\nexport type NotificationTier = (typeof TIERS)[number];\n\n/** The default tier per severity. A failure must be fixed; everything else may be taken away. */\nconst DEFAULT_TIER: Readonly<Record<Severity, NotificationTier>> = {\n error: \"problem\",\n info: \"toast\",\n success: \"toast\",\n warn: \"toast\",\n};\n\n/**\n * How long a toast rests before it is taken away, by severity.\n *\n * §7.1 caps the band at 4–8s. A warning that nobody has to act on still deserves the long end of\n * it, because it is the one a reader is most likely to have looked away from.\n */\nexport const TOAST_LIFETIME_MS: Readonly<Record<Severity, number>> = {\n error: 8000,\n info: 4000,\n success: 4000,\n warn: 8000,\n};\n\n/** What a caller may say about an outcome beyond its severity and its one line. */\nexport interface NotifyOptions {\n /**\n * Command id offering recovery — the Retry / Fix button.\n *\n * A command id rather than a callback so the button's LABEL is the command's title, its enabled\n * state is the command's `enablement`, and its refusal sentence is the command's `requires`. Four\n * facts a closure could carry none of.\n */\n action?: string;\n /** Args passed to {@link NotifyOptions.action} when it runs. */\n actionArgs?: Record<string, unknown>;\n /** The long form — a stack, a captured log, a validator's output. Rendered in Problems only. */\n detail?: string;\n /** Who reported it: \"Save\", \"Source Control\", \"Canvas\", \"Assistant\". Groups the Problems list. */\n source?: string;\n /** The file or document the outcome is about, so Problems can click through to it. */\n path?: string;\n /** Override the tier {@link DEFAULT_TIER} would pick — a warning that MUST be fixed. */\n tier?: NotificationTier;\n /**\n * Deduplication key. A second notification with the same key REPLACES the first rather than\n * stacking beside it — the file watcher that fails once a second is one problem, not sixty.\n */\n key?: string;\n /** Override the toast's rest time. Ignored for the `problem` tier, which has no timer. */\n timeoutMs?: number;\n}\n\n/** One outcome, as recorded. Frozen: a host renders it, nothing edits it after the fact. */\nexport interface Notification {\n readonly id: string;\n readonly severity: Severity;\n readonly message: string;\n readonly tier: NotificationTier;\n /** Epoch ms from {@link now}, so a pinned clock pins the \"2m ago\" a Problems row renders. */\n readonly at: number;\n readonly action?: string;\n readonly actionArgs?: Record<string, unknown>;\n readonly detail?: string;\n readonly source?: string;\n readonly path?: string;\n readonly key?: string;\n /** Rest time for a toast; `0` means \"hold until dismissed\". Absent on a problem. */\n readonly timeoutMs?: number;\n}\n\nlet _seq = 0;\n\n/** Monotonic within a page load, and stable enough to be a lit `repeat` key. */\nfunction nextId(): string {\n _seq += 1;\n return `n${_seq}`;\n}\n\n/**\n * The live toast stack, oldest first. Reactive, so the host repaints by reading it.\n *\n * Exported as the array rather than behind a getter because that is what makes it trackable: a lit\n * render effect that reads `toasts.length` re-runs when one arrives, with no subscription to\n * remember to release.\n */\nexport const toasts: Notification[] = reactive([]);\n\n/**\n * Everything that must be fixed, oldest first — what the Bottom dock's Problems tab renders and\n * what the rail badge and the status bar count.\n *\n * The shape is the contract for that surface: each entry has an `id` to key on, a `severity` to\n * sort and colour by, a `source` to group by, a `path` to click through to, an optional `detail`\n * for the expanded row, and an optional `action` command id for its Fix / Retry button.\n */\nexport const problems: Notification[] = reactive([]);\n\n/** The most toasts on screen at once; the oldest is retired to make room. */\nexport const MAX_TOASTS = 4;\n\n/** Which array a tier lives in. */\nfunction storeFor(tier: NotificationTier): Notification[] {\n return tier === \"problem\" ? problems : toasts;\n}\n\n/**\n * Record an outcome and return it.\n *\n * The record is returned so a caller that owns the outcome's life — an operation that retries and\n * succeeds — can {@link dismiss} its own problem instead of leaving a fixed thing on the list.\n */\nexport function notify(\n severity: Severity,\n message: string,\n options: NotifyOptions = {},\n): Notification {\n const tier = options.tier ?? DEFAULT_TIER[severity];\n const record: Notification = {\n at: now(),\n id: nextId(),\n message,\n severity,\n tier,\n ...(options.action === undefined ? {} : { action: options.action }),\n ...(options.actionArgs === undefined ? {} : { actionArgs: options.actionArgs }),\n ...(options.detail === undefined ? {} : { detail: options.detail }),\n ...(options.source === undefined ? {} : { source: options.source }),\n ...(options.path === undefined ? {} : { path: options.path }),\n ...(options.key === undefined ? {} : { key: options.key }),\n ...(tier === \"toast\" ? { timeoutMs: options.timeoutMs ?? TOAST_LIFETIME_MS[severity] } : {}),\n };\n\n const store = storeFor(tier);\n if (record.key !== undefined) {\n const at = store.findIndex((existing) => existing.key === record.key);\n if (at !== -1) {\n store.splice(at, 1);\n }\n }\n store.push(record);\n if (tier === \"toast\") {\n while (toasts.length > MAX_TOASTS) {\n toasts.shift();\n }\n }\n /*\n * Announce from HERE, not from a host.\n *\n * The `role=\"status\"` region lived on the toast host, and `error` defaults to the `problem` tier —\n * so a failure reached no live region at all, and a Problems-panel region would still announce\n * nothing while another Bottom-dock tab was showing. One call site is what makes \"posted\" and\n * \"announced\" the same event: a new host gets announcements without knowing this module exists.\n *\n * `source` is included because a screen-reader user has no visual grouping to tell them where the\n * message came from, which is exactly what the panel's own column shows everyone else.\n */\n announce(\n record.source === undefined ? record.message : `${record.source}: ${record.message}`,\n severity === \"error\" ? \"assertive\" : \"polite\",\n );\n return record;\n}\n\n/** `notify.success(msg, opts)` and its three siblings — the shape §7.1 names. */\nfunction severityHelper(severity: Severity) {\n return (message: string, options: NotifyOptions = {}) => notify(severity, message, options);\n}\n\nnotify.success = severityHelper(\"success\");\nnotify.info = severityHelper(\"info\");\nnotify.warn = severityHelper(\"warn\");\nnotify.error = severityHelper(\"error\");\n\n/**\n * Take one notification off whichever list holds it. Returns whether it was there.\n *\n * One function for both stores because a caller holding a record should not have to remember which\n * tier it landed in — the record says so.\n */\nexport function dismiss(id: string): boolean {\n for (const store of [toasts, problems]) {\n const at = store.findIndex((record) => record.id === id);\n if (at !== -1) {\n store.splice(at, 1);\n return true;\n }\n }\n return false;\n}\n\n/**\n * Drop every problem a predicate accepts (all of them with no predicate). Returns how many went.\n *\n * The predicate form is what lets an operation clear its own previous failures when it starts again\n * — `clearProblems((p) => p.source === \"Save\")` — so a fixed problem stops being listed without the\n * fixer having kept the record's id.\n */\nexport function clearProblems(match?: (record: Notification) => boolean): number {\n const kept = match ? problems.filter((record) => !match(record)) : [];\n const removed = problems.length - kept.length;\n problems.splice(0, problems.length, ...kept);\n return removed;\n}\n\n/** How many problems are outstanding, optionally of one severity — the badge and the status bar. */\nexport function problemCount(severity?: Severity): number {\n return severity === undefined\n ? problems.length\n : problems.filter((record) => record.severity === severity).length;\n}\n\n/**\n * Clear both stores. For tests and for the \"close project\" path — a problem is about a project, and\n * carrying one across a project switch would attribute it to the wrong repository.\n */\nexport function resetNotifications(): void {\n toasts.splice(0);\n problems.splice(0);\n}\n",
|
|
14
|
+
"/// <reference lib=\"dom\" />\n/**\n * View.js — Transient view state for Jx Studio\n *\n * Holds DOM references, editor instances, cleanup functions, and other mutable state that is the\n * OUTPUT of renderers (not the input). Separating this from persistent app state (in S via\n * store.js) makes renderer dependencies explicit.\n *\n * Deliberately NOT reactive, and deliberately narrow: a Monaco instance, a live `ResizeObserver`\n * and detached DOM nodes must never be wrapped in a reactive proxy. UI _inputs_ — which panel a\n * dock shows, whether a dock is open, the layout selection — live on the reactive `shell` record in\n * `./shell`, where a renderer can track them by reading them.\n */\n\nimport type { editor } from \"monaco-editor\";\nimport type { BufferWrites } from \"./services/monaco-buffer\";\nimport type { Tab } from \"./tabs/tab\";\n\n/**\n * What both of Studio's Monaco surfaces hang off their editor instance.\n *\n * ONE shape, because there is one rule. The source view and the function editor are mounted by\n * different modules, torn down by different events and written into by different continuations —\n * and each of those differences used to justify its own spelling of the same two ideas (\"ignore the\n * change my own `setValue` is about to fire\" and \"cancel the work armed over this buffer\"). The\n * function editor got a canceller in P8 and the source view did not, which is exactly how a 600ms\n * timer survived three disposal sites and stayed able to replace a page with an empty parse.\n * `services/monaco-buffer.ts` owns the rule; this is the storage it needs.\n */\nexport type MonacoSurface = editor.IStandaloneCodeEditor & {\n _ignoreNextChange?: boolean;\n /** The debounced work armed over this buffer, with this editor's exact lifetime. */\n _writes?: BufferWrites;\n /**\n * The tab this buffer was mounted for. ONE spelling for both surfaces, because \"whose buffer is\n * this?\" is a question the close path asks of a tab, not of an editor it happens to know about.\n *\n * It was the function editor's alone, and the source view kept the same fact in a closure inside\n * `mountSourceEditor` — reachable from nowhere. `services/monaco-buffer.ts`'s `commitTabBuffers`\n * and `tabBufferUnsaved` have to ask both, and a question only one surface can answer is the\n * reason ⌘W could close a source tab over the last 600ms of typing without a word.\n */\n _editingTab?: Tab | null;\n};\n\n/**\n * App-wide transient view state.\n *\n * **Nothing per-STAGE lives here any more.** The pan/zoom wrap, the centering observer, the pan\n * offsets, the source-view Monaco and the render generation were all fields of \"the canvas\" — a\n * singular that stopped existing when the shell grew a pane grid. They are fields of a\n * {@link import(\"./canvas/canvas-surface\").CanvasSurface} now, one record per pane, and\n * `scripts/check-pane-singletons.ts` fails the build if one grows back: the index signature below\n * means `view.panX` is not a type error, only a silently-`unknown` read.\n */\ninterface ViewState {\n /**\n * The dock's code editor, plus what it was mounted FOR.\n *\n * The target string alone was not an answer. `{\"eventKey\":\"onclick\",\"path\":[\"children\",0],\"type\":\n * \"event\"}` is the SAME string for the first button on any two pages, so a re-sync could match\n * across a tab switch and hand one document's buffer to another. `_editingTab` (on every Monaco\n * surface, above) is the missing half, held by identity rather than by id so a commit can ask\n * `tabIsLive` whether the document it was promised to still exists.\n *\n * `_commitBody` is the one writer for both of them: a closure built at mount over that tab and\n * that target, so the debounce and the Close cannot disagree about where a body goes — and\n * neither can resolve it through whichever tab happens to be focused when they run.\n *\n * **It answers whether the body LANDED.** `transactDoc` can refuse a write outright (the collab\n * source-canonical freeze pauses structural edits for everyone, the lock holder included), and a\n * writer that reported nothing let the Close dispose an editor whose text had gone nowhere. The\n * boolean is what lets the caller keep the surface up instead.\n */\n functionEditor:\n | (MonacoSurface & {\n _editingTarget?: string | null;\n _commitBody?: (body: string) => boolean;\n })\n | null;\n blockActionBarEl: HTMLElement | null;\n selDragCleanup: (() => void) | null;\n dndCleanups: (() => void)[];\n elementsCollapsed: Set<string>;\n elementsFilter: string;\n _currentDropTargetRow: HTMLElement | null;\n layerDragSourceHeight: number;\n _completionRegistered: boolean;\n _layersCollapsed: Set<string> | null;\n [key: string]: unknown;\n}\n\nexport const view: ViewState = {\n // Editor instances\n functionEditor: null,\n\n // Floating UI containers\n blockActionBarEl: null,\n\n // Selection & drag\n selDragCleanup: null,\n\n // Cleanup arrays (reset on each render cycle)\n dndCleanups: [],\n\n // Left panel / elements UI\n elementsCollapsed: new Set(),\n elementsFilter: \"\",\n\n // Drag interaction\n _currentDropTargetRow: null,\n layerDragSourceHeight: 0,\n\n // Editor state\n _completionRegistered: false,\n\n // Canvas / stylebook\n\n // Layers panel collapsed state\n _layersCollapsed: null,\n};\n",
|
|
15
|
+
"/// <reference lib=\"dom\" />\n/**\n * The surface REGISTRY — one stage record per pane, and nothing that knows what a pane contains.\n *\n * A pane is the unit of split, focus and zoom (§4.1), so it is also the unit of RENDER. The panels\n * a pass mounted, the host element they mounted into, the mode that pass was drawn in and the full\n * render a failed patch escalates to are all facts about ONE pane; they were app-level singletons\n * only because the shell had a single stage.\n *\n * They could not stay that way. `classifyOps` gated a patch on `canvasPanels.every(p => p.ready)`\n * and on one `getCanvasMode()`, and `escalateToFullRender` scheduled the one global render — so the\n * moment a second stage exists, an edit typed into one pane would be refused because the OTHER\n * pane's canvas was still mounting, and every escalation would re-render both. That is a\n * correctness bug, not a performance one, which is why this lands before the second host rather\n * than with it.\n *\n * A surface is addressed by pane id and nothing else. `panels/pane-grid.ts` builds a cell per pane\n * and registers its stage as it goes.\n *\n * **Split from `canvas-surface.ts` for one reason: the WORKSPACE.** The helpers that answer \"which\n * tab is this pane showing\" need `workspace/workspace.ts`, and `workspace.ts` needs\n * `services/monaco-buffer.ts` — which in turn has to enumerate every stage's source buffer, because\n * a close gate that asked only \"the\" Monaco would miss whichever pane it was not holding. That is a\n * cycle. The store of records has no opinion about tabs, so it is the half that comes out.\n */\n\nimport type { CanvasPanel } from \"../types\";\nimport type { MonacoSurface } from \"../view\";\n\n/**\n * The class name every pane's stage element carries.\n *\n * Declared here rather than in the grid because it is what the two genuinely document-level\n * gestures test with `closest()` — \"is this event over SOME stage\" is a question about surfaces,\n * not about the reconciler that happens to build them.\n */\nexport const STAGE_CLASS = \"pane-stage\";\n\n/** One pane's stage: where it renders, what it mounted there, and what it last drew. */\nexport interface CanvasSurface {\n /** The pane this stage belongs to. Stable for the life of the pane. */\n readonly paneId: string;\n /**\n * The element the pane's stage renders into.\n *\n * Typed non-null and initialised null, exactly as the shell refs in `store.ts` are: a surface is\n * addressable before its host exists in the DOM, and every renderer runs after `initShellRefs`.\n */\n wrap: HTMLElement;\n /** The panels the last pass mounted here. Mutated in place by the render, never reassigned. */\n readonly panels: CanvasPanel[];\n /**\n * The effective canvas mode this stage last drew, or null before its first pass.\n *\n * Per-surface because it decides a TEARDOWN: a mode transition rebuilds the panel structure, and\n * one pane switching from Design to Code must not make the other pane's next pass believe its own\n * structure is stale.\n */\n prevCanvasMode: string | null;\n /**\n * The transformed element the pan/zoom modes draw into, or null in the modes that render none.\n *\n * Per-surface because it IS the stage's content. `view.panzoomWrap` held whichever pane painted\n * last, so a fit computed for one pane wrote a transform onto the other's artboards.\n */\n panzoomWrap: HTMLElement | null;\n /** The observer that re-centres this stage until the author pans it. One per stage. */\n centerObserver: ResizeObserver | null;\n /** Whether this stage still wants re-centring — cleared by the first deliberate pan. */\n needsCenter: boolean;\n panX: number;\n panY: number;\n /** The source view's Monaco, mounted into THIS stage. Two Code panes are two models. */\n monacoEditor: MonacoSurface | null;\n /**\n * The Stylebook filter and Customized flag THIS stage's catalogue was last built for.\n *\n * A one-slot module cache, until two panes started evicting each other from it.\n * `shell.stylebook.filter` is a render input for every pane, so both stages render in the same\n * frame: the first stored the new filter and rebuilt, the second compared against a slot the\n * first had already advanced, found \"nothing changed\", and returned through the cheap\n * `postStyleUpdateToStylebookHosts` path with its catalogue still listing the previous filter's\n * specimens. Which pane lost was decided by render order, and it stayed wrong until a mode\n * change. `null` means \"this stage has never drawn a catalogue\", which is not the same as \"drew\n * one for the empty filter\" — the first pass must always rebuild.\n */\n prevStylebookFilter: string | null;\n prevStylebookCustomizedOnly: boolean | null;\n /** Teardown for this stage's source-mode collab binding (unbind + release the lock). */\n sourceCollabCleanup: (() => void) | null;\n /**\n * The generation of the last render pass this stage opened.\n *\n * Per-surface because it is a STALENESS comparison within one pane: a deferred artboard asks \"is\n * the pass I belong to still the current one HERE\". While it was app-wide, pane A opening a pass\n * invalidated pane B's in-flight one, so B's artboards 1..n never reached `ready` and every edit\n * in B escalated to a full render, permanently. The VALUES are still globally unique — see\n * {@link nextRenderGeneration} — because the iframe host caches a pass's resolved document by\n * generation identity.\n */\n renderGeneration: number;\n}\n\n/**\n * The next render generation, monotonic across every surface.\n *\n * Unique across panes even though the comparison is per-pane: `iframe-host.ts`'s\n * `preparePassRender` caches the resolved+serialized document on `byDoc` keyed by the generation's\n * identity, so two surfaces reusing the number would thrash that cache — and the frame's own\n * `latestGen` drop rule would start discarding the other pane's live renders.\n */\nlet _nextGen = 0;\n\n/** Take the next globally-unique render generation. */\nexport function nextRenderGeneration(): number {\n _nextGen += 1;\n return _nextGen;\n}\n\nconst _surfaces = new Map<string, CanvasSurface>();\n\n/**\n * The surface record for a pane, created on first mention.\n *\n * Created rather than looked up so every reader has an answer before the host is attached — the\n * same contract `store.ts`'s shell refs have, and what keeps `activeCanvasSurface()` non-nullable.\n *\n * @param {string} paneId\n * @returns {CanvasSurface}\n */\nexport function surfaceForPane(paneId: string): CanvasSurface {\n let surface = _surfaces.get(paneId);\n if (!surface) {\n surface = freshSurface(paneId);\n _surfaces.set(paneId, surface);\n }\n return surface;\n}\n\n/** A surface record with nothing in it. One place the per-stage defaults are written down. */\nfunction freshSurface(paneId: string): CanvasSurface {\n return {\n centerObserver: null,\n monacoEditor: null,\n needsCenter: true,\n panX: 0,\n panY: 0,\n panels: [],\n paneId,\n panzoomWrap: null,\n prevCanvasMode: null,\n prevStylebookCustomizedOnly: null,\n prevStylebookFilter: null,\n renderGeneration: 0,\n sourceCollabCleanup: null,\n wrap: null as unknown as HTMLElement,\n };\n}\n\n/**\n * Every registered surface, in registration order. The grid's inventory, and the tests'.\n *\n * @returns {CanvasSurface[]}\n */\nexport function allCanvasSurfaces(): CanvasSurface[] {\n return [..._surfaces.values()];\n}\n\n/**\n * The stage `node` sits inside, or null when it is outside every one of them.\n *\n * The N-stage replacement for `canvasWrap.contains(target)`. Two document-level gestures — the\n * browser-zoom block and the wheel forwarded out of a frame — need \"which stage is this in\", and\n * with one stage they were allowed to spell it as \"is it in THE stage\".\n *\n * @param {Node | null} node\n * @returns {CanvasSurface | null}\n */\nexport function stageContaining(node: Node | null): CanvasSurface | null {\n if (!node) {\n return null;\n }\n for (const surface of _surfaces.values()) {\n if (surface.wrap?.contains(node)) {\n return surface;\n }\n }\n return null;\n}\n\n/**\n * Forget everything a surface's last pass mounted.\n *\n * Dropping the panel records is not enough: each artboard owns a render `EffectScope` (and the\n * surgical-subtree scopes nested inside it) that goes on reacting to the document until it is\n * stopped. The render path has always stopped them before emptying the array; a surface whose HOST\n * changes hands has to do exactly the same, or every handover leaks one live scope per artboard —\n * scopes that then repaint DOM belonging to a stage this pane no longer has.\n */\nexport function releaseMountedPanels(surface: CanvasSurface): void {\n for (const panel of surface.panels) {\n panel.renderScope?.stop();\n panel.renderScope = null;\n }\n surface.panels.length = 0;\n surface.prevCanvasMode = null;\n}\n\n/**\n * Attach a pane's stage element. Called once per host that exists in the shell.\n *\n * A fresh host carries nothing over: the panels named by the previous one are detached DOM and the\n * mode it last drew describes a structure that is gone, so both are cleared here rather than by\n * each caller remembering to.\n *\n * @param {string} paneId\n * @param {HTMLElement} wrap\n * @returns {CanvasSurface}\n */\nexport function registerCanvasSurface(paneId: string, wrap: HTMLElement): CanvasSurface {\n const surface = surfaceForPane(paneId);\n surface.wrap = wrap;\n releaseMountedPanels(surface);\n return surface;\n}\n\n/* There is no `moveCanvasStage`, and there is no handover.\n §18.3 handed the shell's ONE stage to whichever pane had focus, because there was one stage. The\n grid gives every pane its own, registered by `panels/pane-grid.ts` when the cell is built and\n released when it is removed, so nothing moves and no pane is ever left describing DOM it does\n not own. The rule that survives is {@link releaseMountedPanels}: a surface that loses its host\n has to stop the render scope of every artboard it mounted, or each goes on repainting a stage\n that is not there. */\n\n/**\n * Build a pane's surface record from scratch, replacing anything a previous pane of that id left.\n *\n * The grid calls this as it builds a cell, BEFORE the stage element exists — a pane is complete\n * before it is published (§18.1 rule 1), and that includes the record every renderer resolves\n * through.\n *\n * @param {string} paneId\n * @returns {CanvasSurface}\n */\nexport function createPaneSurface(paneId: string): CanvasSurface {\n const existing = _surfaces.get(paneId);\n if (existing) {\n disposePaneSurface(paneId);\n }\n const surface = freshSurface(paneId);\n _surfaces.set(paneId, surface);\n return surface;\n}\n\n/**\n * How a surface releases the editors and observers its renders created.\n *\n * Injected, because the teardown lives in `canvas/canvas-render.ts` — which imports this module —\n * and a surface record must stay reachable from the dependency-light half of the graph. Same idiom\n * as `setIframePatchEscalation`.\n */\nlet _teardown: ((surface: CanvasSurface) => void) | null = null;\n\n/** Register the per-surface teardown. Called once, at import time, by `canvas-render.ts`. */\nexport function setSurfaceTeardown(fn: ((surface: CanvasSurface) => void) | null): void {\n _teardown = fn;\n}\n\n/**\n * Release everything a pane's stage owns and forget the record.\n *\n * Ordered: the render-owned surfaces first (through the injected teardown — Monaco, the collab\n * binding, the centering observer), then the artboards' render scopes, then the record. The DOM is\n * the caller's: `pane-grid.ts` removes the cell, and `iframe-host.ts`'s `releaseCanvasHosts` tears\n * the frames down BEFORE the removal, while they are still reachable from the stage.\n *\n * @param {string} paneId\n */\nexport function disposePaneSurface(paneId: string): void {\n const surface = _surfaces.get(paneId);\n if (!surface) {\n return;\n }\n _teardown?.(surface);\n releaseMountedPanels(surface);\n unregisterCanvasSurface(paneId);\n}\n\n/** Forget a pane's surface record without releasing anything. Tests, and the app reset. */\nexport function unregisterCanvasSurface(paneId: string): void {\n _surfaces.delete(paneId);\n}\n",
|
|
16
|
+
"/// <reference lib=\"dom\" />\n/**\n * The one question every write into a Monaco buffer has to ask: **may I write into this buffer?**\n *\n * Studio has two Monaco surfaces — the source view on the canvas stage (`view.monacoEditor`,\n * mounted by `canvas/canvas-render.ts`) and the function body in the Bottom dock's Logic tab\n * (`view.functionEditor`, mounted by `panels/editors.ts`).\n *\n * **The count in this file is of WRITE SITES — places that put text INTO a buffer** — because a\n * write into a buffer is the only thing that has to ask this module's question. (Writes OUT are\n * counted nowhere: there are two, one per surface, they are the debounced commits, and they ask\n * `bufferIsLive` instead. See the note at the end of this header.) There are four, and none of them\n * can see the keyboard:\n *\n * 1. **the serializer resolving with the file's contents**, at mount — `canvas-render.ts`'s\n * `mountSourceEditor`;\n * 2. **a repaint pushing the document's text in** — `canvas-render.ts`'s source fast path;\n * 3. **the dock's re-sync**, showing an edit that arrived from somewhere else — `editors.ts`'s\n * `syncFunctionEditor`;\n * 4. **a code-service round trip landing with a formatted body** — `editors.ts`'s format-on-open.\n *\n * Every one of those writes is computed from a buffer state that may be several keystrokes old by\n * the time it arrives, and `setValue` does not merge — it replaces, and takes the user's unsaved\n * work with it.\n *\n * **And on a co-edited tab there is a FIFTH writer, which is not in that list because it never\n * calls anything here.** y-monaco binds the source model to a shared `Y.Text`, so every peer's\n * keystrokes arrive in the buffer directly and say nothing to anyone. It is also the only writer\n * whose text reaches other people's machines: the binding is two-way, so a local `setValue` over a\n * bound model is a whole-document replace PUBLISHED to every peer. A buffer in that state declares\n * itself with {@link BufferWrites.markShared} and clause 5 refuses every write into it.\n *\n * The rule was already discovered once, in one branch of one fast path:\n *\n * ```js\n * if (!editor.hasTextFocus() && editor.getValue() !== newVal) { … }\n * ```\n *\n * …and it was never given a name, so the other three write sites each invented a different guard.\n * All three asked **identity** — \"is this still the same editor object?\" — which answers a real\n * question (a retarget must not write A's body into B) and is not the same question. An editor can\n * keep its identity for minutes while its buffer moves on with every keypress. Identity is\n * necessary and never sufficient.\n *\n * {@link bufferMovedOn} is that rule's one home. A write must be dropped when any of these is true\n * — the first four are \"the buffer moved on\", and the fifth is the one the co-edited surface\n * added:\n *\n * 1. **It is gone.** `dispose()` detaches the model, and `CodeEditorWidget.getValue()` opens with `if\n * (!this._modelData) return \"\";` — so a dead editor answers the empty string and a write into it\n * lands nowhere.\n * 2. **The user is in it.** `hasTextFocus()` means their next keystroke is newer than your value.\n * 3. **It holds text the document has not been given.** A repaint that resolves a buffer/document\n * difference in the document's favour discards whatever put the difference there.\n *\n * This clause was first written as `pending()` — \"a commit is armed\" — which is the same thing for\n * a KEYSTROKE and a different thing for every other write. A programmatic write sets\n * `_ignoreNextChange`, so the change handler returns before it can arm anything: the buffer is\n * ahead with nothing pending, and a timer-shaped clause reported \"settled\". That is exactly the\n * state format-on-open leaves — it pretty-prints into the buffer and deliberately never commits —\n * so the next repaint reverted it, and **\"Format on open\" visibly un-formatted itself** within\n * seconds of every open, now that the dock repaints on the Problems badge, on Activity and on a\n * 30-second git poll.\n *\n * So it is a FACT the buffer carries ({@link BufferWrites.ahead}), not an inference from a timer.\n * Whoever writes into a buffer says which side the text came from: text that did not come from the\n * document marks it {@link BufferWrites.markAhead}, and the document taking the buffer's text — or\n * the buffer taking the document's — marks it {@link BufferWrites.markSettled}. A keystroke marks\n * ahead and arms its commit; the commit marks settled.\n * 4. **It is not what the write was computed from.** A caller that read the buffer before an `await`\n * passes what it read as `expected`; a mismatch means the round trip lost the race.\n * 5. **It is not this process's buffer to replace.** The one clause that is not \"the buffer moved on\"\n * — it is \"the buffer is not yours\". A co-edited source buffer is bound to a shared `Y.Text` and\n * the CRDT is the source of truth for that text while the source lock is held: the structure\n * tree is DERIVED from it by the source reconciler (`collab/collab-session.ts`'s\n * `sourceParseNow` parses the shared text back into the tree). A repaint serializing that tree\n * over the buffer is therefore a rendering of the text asserting itself over the text — and\n * because the model is bound, it is published to every peer, on every repaint, for every round\n * trip that is not byte-stable. There is no direction in which a co-edited buffer wants the\n * document's serialized text, so this fact is set once at bind ({@link BufferWrites.markShared})\n * and never cleared: a future writer's `markSettled` must not be able to unlock it, which is why\n * it is its own fact and not a use of clause 3.\n *\n * **Ahead is not the same as unsaved, and the gates that warn about lost work need the narrower\n * fact.** Format-on-open leaves a buffer ahead deliberately and never commits — and since\n * `closeFunctionEditor` writes a MINIFIED body, the pretty-printed buffer differs from the document\n * for as long as the editor is open. Counting THAT as unsaved work would put \"you have unsaved\n * changes\" in front of every author who merely opened a handler. So a keystroke says\n * {@link BufferWrites.markTyped} — ahead, and the text is the user's own — and the two gates that\n * destroy a tab ({@link commitTabBuffers}'s callers) read {@link BufferWrites.typed}, which is\n * exactly the text a close would take with it.\n *\n * {@link commitBufferWrites} reads the same fact from the other end. A gate asks it BEFORE the\n * destruction, to decide whether to prompt; a disposer asks it AFTER its own flush, when the answer\n * can only be \"I have just deleted this\" — and is the last thing in a position to say so, because\n * the next line detaches the model and `buffersForTab` stops finding the buffer at all.\n *\n * Writes OUT of a buffer — a debounce reading `getValue()` into the document — ask `bufferIsLive`\n * instead, which is clause 1 alone. Deliberately, and it is the only kind of call site in the\n * codebase entitled to a subset: clauses 2 and 3 describe a buffer that is AHEAD of the document,\n * which is the precondition for committing rather than a reason to refuse, and clause 4 has no\n * meaning for a writer whose whole input is the buffer.\n *\n * @docs studio/logic/code\n */\n\nimport { toRaw } from \"../reactivity\";\nimport { notify } from \"./notify\";\nimport type { Tab } from \"../tabs/tab\";\nimport { view } from \"../view\";\nimport { allCanvasSurfaces } from \"../canvas/surface-registry\";\n\n/** The slice of a Monaco editor this module needs. Both of Studio's Monacos satisfy it. */\nexport interface MonacoBuffer {\n getValue: () => string;\n getModel: () => unknown;\n hasTextFocus: () => boolean;\n /** The debounced work armed over THIS buffer. Installed by {@link bufferWrites}. */\n _writes?: BufferWrites;\n /**\n * The tab this buffer was mounted for — **whose buffer this is**, and both surfaces answer it the\n * same way.\n *\n * Only the dock's editor used to carry it. The source editor named its tab in a closure inside\n * `mountSourceEditor`, which is unreachable from outside — so a caller holding a `Tab` could ask\n * the dock \"is this yours?\" and had no way at all to ask the source view. Every question about a\n * tab's buffers ({@link commitTabBuffers}, {@link tabBufferUnsaved}) needs both answers, and a\n * question that can only be asked of one of two surfaces is answered wrong half the time.\n */\n _editingTab?: Tab | null;\n}\n\n/**\n * The debounced work armed over one buffer, with that buffer's exact lifetime.\n *\n * It hangs off the editor rather than off `view` or a module variable because those two spellings\n * are what the two surfaces had: the dock's canceller was an editor property, the canvas's timer\n * was a closure variable inside `mountSourceEditor` that nothing outside could reach — so of the\n * two, only one teardown could cancel, and the canvas's three disposal sites cancelled nothing at\n * all. Whoever disposes an editor now has its canceller in their hand by construction.\n */\nexport interface BufferWrites {\n /**\n * (Re)arm the timer called `key`, replacing whatever was armed under that key.\n *\n * The work may be async — the source view's commit parses through the format host — and\n * {@link BufferWrites.flush} hands that promise back, because a caller that flushes in order to\n * ASK A QUESTION about the result (has this tab unsaved work now?) has to wait for it.\n */\n arm: (key: string, ms: number, run: () => void | Promise<void>) => void;\n /** Cancel every armed timer. The disposer calls this; see {@link cancelBufferWrites}. */\n cancel: () => void;\n /**\n * Run the work armed under `key` NOW, and drop its timer. A no-op when nothing is armed there.\n *\n * The teardown's half of {@link commitBufferWrites}: the debounce is the only thing that carries\n * the last half-second of typing into the document, so a disposer that merely cancels it deletes\n * that typing — silently, because the document is never marked dirty for work it never received.\n *\n * Returns whatever the work returned, so an async commit can be awaited. The disposers ignore it\n * on purpose: they flush precisely because they are about to detach the model, and every commit\n * reads `getValue()` before its own first `await`.\n *\n * **A commit that already fired counts as armed.** The timer drops its key before running, so a\n * flush arriving mid-run would otherwise find nothing and read that as \"there was nothing to\n * carry\" — which for the source view, whose commit awaits an IPC round trip to the format host,\n * is a window of tens of milliseconds starting the moment the author stops typing. Exactly when\n * they click another tab. The in-flight promise is returned instead, so the caller waits for the\n * answer rather than inventing one.\n */\n flush: (key: string) => void | Promise<void>;\n /** Clause 3, as a fact: the buffer holds text the document has not been given. */\n ahead: () => boolean;\n /** Declare that the buffer just took text which did NOT come from the document. */\n markAhead: () => void;\n /**\n * Clause 3, narrowed to the text a close would DESTROY: the user's own keystrokes, not yet in the\n * document. See the header — `ahead` is also true of format-on-open, whose text nobody loses.\n */\n typed: () => boolean;\n /** Declare a keystroke: {@link BufferWrites.markAhead}, and the text is the user's own. */\n markTyped: () => void;\n /** Declare that buffer and document now hold the same text, whichever way it travelled. */\n markSettled: () => void;\n /** Clause 5, as a fact: this buffer is bound to a shared text that this process does not own. */\n shared: () => boolean;\n /** Declare that the buffer is now bound to a shared text. Permanent — see clause 5. */\n markShared: () => void;\n}\n\n/**\n * The key both surfaces arm their document-commit under.\n *\n * A shared constant rather than each surface's own string, because {@link commitBufferWrites} has to\n * be able to flush THE COMMIT and only the commit. A buffer also arms a lint (`\"lint\"`), and firing\n * a lint request at a buffer that is being disposed is work for an editor that will not exist when\n * the answer arrives.\n */\nexport const BUFFER_COMMIT = \"commit\";\n\n/**\n * Install (and return) the debounce holder for `buffer`.\n *\n * Called once per mount, right after the editor is created, so that the very first keystroke arms\n * its commit through a canceller the teardown can already see.\n *\n * @param {MonacoBuffer} buffer The freshly created editor.\n * @returns {BufferWrites}\n */\nexport function bufferWrites(buffer: MonacoBuffer): BufferWrites {\n const timers = new Map<string, ReturnType<typeof setTimeout>>();\n const runs = new Map<string, () => void | Promise<void>>();\n /** Runs that have started and not yet answered. See {@link BufferWrites.flush}. */\n const inFlight = new Map<string, Promise<void>>();\n let isAhead = false;\n let isTyped = false;\n let isShared = false;\n /**\n * Remember a run while it is answering, so a flush arriving mid-run returns its promise rather\n * than the `undefined` that means \"nothing was armed\". Self-clearing, and it never rejects — the\n * caller inspects the settled state through `typed()`, and a rejection is the commit's own to\n * report.\n */\n function track(key: string, result: void | Promise<void>): void | Promise<void> {\n if (typeof (result as Promise<void> | undefined)?.then !== \"function\") {\n return result;\n }\n const promise = (result as Promise<void>).finally(() => {\n if (inFlight.get(key) === promise) {\n inFlight.delete(key);\n }\n });\n inFlight.set(key, promise);\n return promise;\n }\n const writes: BufferWrites = {\n arm(key, ms, run) {\n clearTimeout(timers.get(key));\n runs.set(key, run);\n timers.set(\n key,\n setTimeout(() => {\n // Dropped BEFORE the body runs: a callback that re-arms its own key must not have that\n // Arm cleared out from under it, and a flush of a key already executing must find nothing.\n timers.delete(key);\n runs.delete(key);\n /* Discarded deliberately: a timer that fires on its own has no caller to answer to.\n `track` has already put the promise in `inFlight`, which is where a flush arriving\n mid-run collects it — and per the contract above, `run` reports its own failures. */\n void track(key, run());\n }, ms),\n );\n },\n cancel() {\n for (const timer of timers.values()) {\n clearTimeout(timer);\n }\n timers.clear();\n runs.clear();\n },\n flush(key) {\n const run = runs.get(key);\n if (!run) {\n // Nothing armed — but something may be RUNNING. Its answer is the honest one.\n return inFlight.get(key);\n }\n clearTimeout(timers.get(key));\n timers.delete(key);\n runs.delete(key);\n return track(key, run());\n },\n ahead: () => isAhead,\n markAhead() {\n isAhead = true;\n },\n typed: () => isTyped,\n markTyped() {\n isAhead = true;\n isTyped = true;\n },\n markSettled() {\n isAhead = false;\n isTyped = false;\n },\n shared: () => isShared,\n markShared() {\n isShared = true;\n },\n };\n buffer._writes = writes;\n return writes;\n}\n\n/**\n * The two Monaco surfaces, named so a teardown that loses text can say what the author was looking\n * at when it went. Both spellings are this module's, not the caller's, because the sentence has to\n * read the same whichever disposer produced it.\n */\nexport type BufferSurface = \"logic\" | \"source\";\n\nconst SURFACE: Record<BufferSurface, { holds: string; reached: string; source: string }> = {\n logic: { holds: \"The handler you were typing\", reached: \"written into\", source: \"Logic\" },\n source: { holds: \"The source you were typing\", reached: \"parsed into\", source: \"Editor\" },\n};\n\n/**\n * Say that a teardown destroyed the author's typing, and answer whether it did.\n *\n * Called once per {@link commitBufferWrites}, at the moment the answer is known — synchronously for\n * the dock's body write, and from the promise's continuation for the source view's parse, which\n * cannot answer before the disposer has returned.\n *\n * **A toast rather than a Problem, and the difference is whether anything can be done.** A commit\n * that THREW leaves the text in the buffer, so {@link commitTabBuffers} files a Problem — the\n * author can still go and rescue it, minutes later. Here the buffer is being detached in the same\n * breath: there is nothing left to fix, and a record the app promises to keep until somebody fixes\n * it is the wrong host for a loss that is already final.\n *\n * **It does not ask whether a gate already said this.** A close that destroys the TAB runs\n * `commitTabBuffers` and its dialog first, so an author who chose \"Close Without Saving\" hears it\n * twice; \"is that tab still open?\" is `workspace`'s to answer, and `workspace` imports this module.\n * One extra keyed toast confirming a choice the author just made is the cheaper of the two costs.\n *\n * @param {MonacoBuffer} buffer\n * @param {BufferSurface} surface\n * @param {{ error: unknown } | null} failure What the commit threw, BOXED — a commit is free to\n * throw `undefined`, and \"did it throw\" must not become \"was what it threw interesting\".\n * @returns {boolean} True when there was nothing to lose.\n */\nfunction reportDiscarded(\n buffer: MonacoBuffer,\n surface: BufferSurface,\n failure: { error: unknown } | null,\n): boolean {\n const writes = buffer._writes;\n if (writes?.typed() !== true) {\n return true;\n }\n const tab = buffer._editingTab ?? null;\n const where = tab?.documentPath ?? \"Untitled\";\n const { holds, reached, source } = SURFACE[surface];\n notify.warn(`${holds} was discarded — it was never ${reached} \"${where}\".`, {\n ...(failure ? { detail: describeCommitFailure(failure.error) } : {}),\n key: `buffer-discarded:${surface}:${tab?.id ?? \"none\"}`,\n source,\n ...(tab?.documentPath ? { path: tab.documentPath } : {}),\n });\n return false;\n}\n\n/** What a failed commit is worth showing: the stack when there is one, the value otherwise. */\nfunction describeCommitFailure(error: unknown): string {\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\n/**\n * Carry what the buffer is holding into the document, then drop everything armed over it.\n *\n * **The teardown's obligation, and it is two obligations rather than one.** A disposer that only\n * cancels stops a dead buffer from writing `\"\"` over a handler — the round-3 defect — by throwing\n * away the last half-second of typing instead. That is still lost work, and it is worse in one\n * respect: `doc.dirty` stays `false`, so nothing on screen says anything went missing. Five ways\n * out of the code surface lost an edit that way (switch dock tab, open another target, open a\n * formula through `openLogicTarget`, collapse the dock, switch to a tab whose target string\n * matches), and each measured as \"the pre-typing body, quietly\".\n *\n * **Two more ways out are not a disposer's to fix, and this function cannot reach them.** ⌘W / the\n * tab × and quitting DESTROY THE TAB: `closeTab` deletes it from `workspace.tabs` before anything\n * disposes an editor, so by the time a dock repaint reaches `disposeFunctionEditor` the commit\n * flushed here finds `tabIsLive(tab) === false` and writes nothing. Seven ways out, and the last\n * two are fixed where the decision is made — {@link commitTabBuffers} runs the commit before the\n * gate reads the tab, and {@link tabBufferUnsaved} is what the gate reads when the commit could not\n * land it.\n *\n * The order is the whole point: flush WHILE THE BUFFER IS STILL ALIVE, then cancel, then dispose.\n * Reversed, or deferred by so much as a microtask, the flush reads the empty string off a detached\n * model and writes that — which is the defect this replaces, not a fix for it. The flushed callback\n * must therefore read `getValue()` before its own first `await`, which both surfaces' commits do.\n *\n * Cancel-without-flush ({@link cancelBufferWrites}) stays correct in exactly one place, and only\n * because the commit has already happened by other means: `closeFunctionEditor` reads the buffer\n * itself and writes a MINIFIED body through the same writer, so the armed commit holds nothing but\n * a raw copy of what was just written, and replaying it afterwards would undo the minify. Every\n * other disposal path — `disposeFunctionEditor`, `disposeSourceEditor` and therefore\n * `resetCanvasView`, the model-URI swap and the mode transition — flushes.\n *\n * **AND THE FLUSH IS ALLOWED TO FAIL, which is what the answer is for.** `bodyWriter` returns\n * whether the body reached the document, and it returns `false` whenever the collab gate refuses\n * the write, the tab is gone, or the element the handler hangs off has been deleted; the source\n * view's parse simply declines to settle when the text does not parse. Throwing that answer away\n * here made five exits — dock tab switch, dock collapse, ⌘, opening another Logic target, switching\n * to another tab, plus the source view's model-URI swap and its mode transition — into silent\n * deletions: the buffer holding the only copy is detached on the next line, and with it goes\n * `buffersForTab`'s knowledge that it ever existed, so {@link tabBufferUnsaved} and every gate\n * built on it go back to answering \"nothing to lose\" about text that has just been destroyed.\n *\n * `closeFunctionEditor` shows the other shape — a refused write keeps the surface, so the text\n * stays on screen and the author can act. **A disposer has no such option.** Every one of its call\n * sites is a repaint or a mode transition that has already replaced the container, and refusing\n * would leave a live Monaco bound to detached DOM, which is the leak this module's teardown exists\n * to prevent. So the disposers all choose the other answer: they cannot keep the text, and they say\n * that it is gone ({@link reportDiscarded}).\n *\n * **The source view's commit answers late, and the report goes with it.** Its parse is an `await`,\n * so the disposer is long finished by the time \"did it land\" has a value; the promise's\n * continuation reports, and the synchronous return says only what is known at return time. A\n * `false` therefore always means the loss is certain and has been announced.\n *\n * @param {MonacoBuffer | null | undefined} buffer\n * @param {BufferSurface} surface Which editor is being destroyed — names the toast.\n * @returns {boolean} True when the teardown carried everything the author typed, or there was\n * nothing of theirs to carry. False when it destroyed the author's text, which is reported.\n */\nexport function commitBufferWrites(\n buffer: MonacoBuffer | null | undefined,\n surface: BufferSurface,\n): boolean {\n const writes = buffer?._writes;\n if (!buffer || !writes) {\n return true;\n }\n /* THE FLUSH IS GUARDED AND ITS TWIN'S WAS NOT, which is the whole difference between a failed\n commit and a broken repaint. `bodyWriter`'s event branch resolves `editing.path` in the live\n tree, and a collaborator's delete — or a local undo — makes that path resolve to nothing. The\n throw escaped into `disposeFunctionEditor`, into `syncFunctionEditor`, and out of the dock\n panel's `afterRender`: the repaint aborted mid-way, `cancel()` never ran, `dispose()` never\n ran, and a live 500ms timer was left over an editor whose container lit was about to replace.\n A timer reading `\"\"` off a detached model is the exact defect this module was created to\n prevent, so the teardown below must happen whatever the commit does. */\n let pending: Promise<void> | undefined;\n try {\n // Fire-and-forget on purpose: the disposer is synchronous, and the commit read `getValue()`\n // Before its own first `await`. What is left to await is the write INTO the document, which\n // Does not need this editor to still exist.\n pending = writes.flush(BUFFER_COMMIT) as Promise<void> | undefined;\n } catch (error) {\n writes.cancel();\n return reportDiscarded(buffer, surface, { error });\n }\n writes.cancel();\n if (typeof pending?.then === \"function\") {\n void pending.then(\n () => reportDiscarded(buffer, surface, null),\n (error: unknown) => reportDiscarded(buffer, surface, { error }),\n );\n return true;\n }\n return reportDiscarded(buffer, surface, null);\n}\n\n/**\n * Cancel the debounced work armed over `buffer`. Safe on null, and on a buffer that never armed any\n * — which is why every disposal site can call it unconditionally.\n *\n * **This is not housekeeping, it is the correctness of the teardown.** A surviving timer reads\n * `getValue()` off a disposed editor, gets `\"\"`, and writes that into the document: for the dock it\n * deletes a handler half a second after the surface closed, and for the source view it replaces a\n * whole page body with an empty parse 600ms after the user left Code view.\n *\n * @param {MonacoBuffer | null | undefined} buffer\n */\nexport function cancelBufferWrites(buffer: MonacoBuffer | null | undefined): void {\n buffer?._writes?.cancel();\n}\n\n/**\n * Whether `buffer` still has a model — i.e. whether there is a buffer at all.\n *\n * The question a write OUT of the buffer asks. `dispose()` runs `_detachModel()`, so this is false\n * for a disposed editor and its `getValue()` is the empty string rather than the text it held.\n *\n * @param {MonacoBuffer | null | undefined} buffer\n * @returns {boolean}\n */\nexport function bufferIsLive(buffer: MonacoBuffer | null | undefined): boolean {\n return Boolean(buffer?.getModel());\n}\n\n/**\n * Whether this write must be dropped — the buffer moved on, or was never this write's to make. The\n * five clauses are stated in this module's header.\n *\n * @param {MonacoBuffer} buffer The editor about to be written into.\n * @param {string} [expected] What the caller read out of the buffer before its `await`, when it\n * made one. Omitted by callers that computed their value from the DOCUMENT rather than from the\n * buffer, for which clauses 1–3 and 5 are the whole question.\n * @returns {boolean} True when the write must be dropped.\n */\nexport function bufferMovedOn(buffer: MonacoBuffer, expected?: string): boolean {\n if (\n !bufferIsLive(buffer) ||\n buffer.hasTextFocus() ||\n buffer._writes?.ahead() ||\n buffer._writes?.shared()\n ) {\n return true;\n }\n return expected !== undefined && buffer.getValue() !== expected;\n}\n\n/**\n * The Monaco buffers Studio currently has mounted for `tab`, and nothing else.\n *\n * Both surfaces are asked the same question through `_editingTab`, and both are asked clause 1\n * first: a buffer whose model is detached answers `\"\"` to everything and has no work left to hold.\n *\n * **The order is the SOURCE view first and the dock second, and it is load-bearing** — see\n * {@link commitTabBuffers}, which commits them in this order one at a time.\n *\n * @param {Tab} tab\n * @returns {MonacoBuffer[]}\n */\nfunction buffersForTab(tab: Tab): MonacoBuffer[] {\n const raw = toRaw(tab as object);\n /* Every stage's source buffer, plus the dock's one function editor.\n The source view is per-PANE now: two Code panes are two Monaco instances over two documents,\n and a close gate that asked only \"the\" source editor would have missed whichever one it was\n not holding — which is the same half-answer that let ⌘W close a tab over unprompted typing. */\n const mounted: (MonacoBuffer | null)[] = [\n ...allCanvasSurfaces().map((surface) => surface.monacoEditor as MonacoBuffer | null),\n view.functionEditor,\n ];\n return mounted.filter(\n (buffer): buffer is MonacoBuffer =>\n buffer != null &&\n buffer._editingTab != null &&\n toRaw(buffer._editingTab as object) === raw &&\n bufferIsLive(buffer),\n );\n}\n\n/**\n * Carry what `tab`'s buffers are holding into the document, leaving the buffers standing.\n *\n * **The close path is a WRITE before it is a question.** `shouldWarnOnClose` and `hasUnsavedTabs`\n * both read `tab.doc.dirty`, and nothing makes a buffer's armed commit dirty a document it has not\n * reached yet — so typing the last character of a handler and pressing ⌘W closed the tab with no\n * prompt at all and took the last 500ms (dock) / 600ms (source) with it. No disposer can cover\n * this: `closeTab` deletes the tab first, and every commit checks `tabIsLive` precisely so that it\n * will not write into a tab nobody can read. The flush therefore has to happen while the tab is\n * still open, which is here, before the gate.\n *\n * **The two commits run ONE AT A TIME, source first, because they are not independent.** Both\n * surfaces can be open on one tab — the dock's Logic editor is not a canvas mode, so a handler body\n * and the page source are editable side by side — and their two commits write at different\n * granularities. The dock's writes ONE body at `editing.path`; the source view's parses the whole\n * buffer and assigns a whole new `tab.doc.document`. Started together, the dock's synchronous write\n * lands first and the source's post-await assign — computed from buffer text that predates it —\n * replaces the entire tree on top of it, so the body the author just typed is gone with no trace.\n *\n * Reversed, both survive: `bodyWriter` re-reads `tab.doc.document` and re-resolves `editing.path`\n * at call time, so the dock's targeted write applies to whatever tree is there when it runs. The\n * whole-document assign is the destructive direction and therefore goes first; the body write goes\n * last and is the only one that can be the last word. (Two independent timers could already race\n * this either way — but a race that used to be a coin toss is not a licence to make the losing side\n * certain.)\n *\n * **It is always a promise, and callers `await` it.** It used to return `Promise<void> | void` so\n * that a tab with nothing armed closed without spending a microtask. Nothing a user can perceive\n * distinguishes zero microtasks from one; the entire cost was five synchronous assertions in\n * `tests/shortcuts.test.ts`, and the entire price was a three-line `const committing = …; if\n * (committing) await committing;` dance in every present and future caller — which is exactly the\n * shape that let {@link commitTabBuffers}'s one existing caller forget to re-check its tab across\n * the await.\n *\n * Deliberately NOT {@link commitBufferWrites}: that one cancels afterwards, which is right for a\n * disposer and wrong here. The tab may well survive this call — the author can press Cancel on the\n * dialog the flush just caused to appear — and its buffers must still have their lint armed.\n *\n * **AND IT NEVER REJECTS, because its callers are gestures.** `requestClose` awaits this before it\n * asks anything, and a rejection there propagated out of an `async` function nobody awaits: ⌘W did\n * nothing — no prompt, no close, no message, an unhandled rejection in the console. The other two\n * callers (`openTab`'s preview replacement, the project switch) do not even await it, so a\n * rejection is invisible by construction. A commit is also not all-or-nothing: the source view's\n * commit and the dock's write to DIFFERENT places, so the first one throwing must not cost the\n * second its turn — which is why the guard is per buffer rather than around the loop.\n *\n * What a failed commit leaves behind is the honest state, not a lost one: `markSettled` never ran,\n * so the buffer is still `typed()`, {@link tabBufferUnsaved} still answers yes, and the gate above\n * the close still prompts. This function's remaining job is to make sure somebody is told, which is\n * a problem rather than a toast: an author who reads it minutes later still needs to know that one\n * document's editor holds text the file does not.\n *\n * @param {Tab} tab\n * @returns {Promise<void>} Resolves when every commit this flush started has finished or failed.\n */\nexport async function commitTabBuffers(tab: Tab): Promise<void> {\n for (const buffer of buffersForTab(tab)) {\n /* Clause 1, RE-ASKED, because the list was taken before the previous commit's await. Assigning\n a new document repaints the dock, and a repaint can dispose the function editor — whose\n `getValue()` then answers `\"\"`. Committing that is the deletion this module exists to\n prevent. (The ordinary teardown already flushed and cancelled, so this usually finds nothing\n armed; \"usually\" is not a guard.) */\n if (!bufferIsLive(buffer)) {\n continue;\n }\n try {\n await buffer._writes?.flush(BUFFER_COMMIT);\n } catch (error) {\n notify.error(\n `Could not save the editor's contents into \"${tab.documentPath ?? \"Untitled\"}\".`,\n {\n detail: error instanceof Error ? (error.stack ?? error.message) : String(error),\n key: `buffer-commit:${tab.id}`,\n source: \"Editor\",\n ...(tab.documentPath ? { path: tab.documentPath } : {}),\n },\n );\n }\n }\n}\n\n/**\n * Whether a buffer of `tab`'s holds the user's own typing that the document has not been given.\n *\n * What the unsaved-work gates ask AFTER {@link commitTabBuffers}, because a commit is allowed to\n * fail to land: unparseable source deliberately leaves the buffer ahead rather than resyncing over\n * a half-typed heading, and that text exists nowhere but the buffer. `typed()` rather than\n * `ahead()` — the header says why counting format-on-open as unsaved work would warn every author\n * who merely opened a handler.\n *\n * @param {Tab} tab\n * @returns {boolean}\n */\nexport function tabBufferUnsaved(tab: Tab): boolean {\n return buffersForTab(tab).some((buffer) => buffer._writes?.typed() === true);\n}\n",
|
|
17
|
+
"/**\n * The selection SET — one vocabulary for `session.selection`, now that it is `JxPath[]` (§6.5).\n *\n * ## The invariant this module exists to hold\n *\n * **A selection of one behaves exactly as a selection did before it was a list.** Every surface\n * that addresses a single node — the Inspector's three tabs, the block action bar, the status bar,\n * the canvas overlay box, the context menu — reads {@link primarySelection} and nothing else. When\n * `length === 1` that function returns the sole path, so those surfaces receive byte-identically\n * what `session.selection` used to hand them. Nothing downstream of `primarySelection` can tell the\n * difference, and that is what makes the widening shippable: the multi cases are additions beside\n * the single case, never a rewrite of it.\n *\n * The corollary is a rule about writes: **replace the array, never mutate it in place.** Several\n * render effects track the selection with a bare `void tab.session.selection` read, which\n * subscribes to the property and not to the array's indices; an in-place `push` would move the\n * selection without repainting the panel that draws it. Every helper here returns a NEW array.\n *\n * ## Ordering, and why two ends of the list have names\n *\n * The list is kept in the order the user built it.\n *\n * - {@link selectionAnchor} is `selection[0]` — where a shift-range extends FROM. It survives every\n * range extension, so shift-clicking A then D then B gives A..D then A..B, which is what every\n * list in every file manager does.\n * - {@link primarySelection} is the LAST element — the most recently added path, and therefore the\n * one the user just pointed at. Single-target surfaces address it.\n *\n * ## Structural batches\n *\n * A multi-node structural edit is one decision and must be one undo step, which `transactDoc`\n * already gives for free — everything mutated inside one call is one history entry. What it does\n * NOT give is index safety: removing `children/0` renumbers `children/1`, so a naive loop over the\n * selection deletes the wrong nodes. {@link structuralBatch} answers that once — descendants\n * dropped, then descending document order, so every splice happens below coordinates nothing later\n * in the batch depends on.\n *\n * It also answers a second question the single-path world never had to ask: whether a selected path\n * is a splice coordinate AT ALL. The Outline gives the document element, a repeater's map template\n * and a `$switch` case rows of their own, and any of them can be ctrl-clicked into a selection\n * beside an ordinary element. {@link isSpliceablePath} is the test, and it is the one thing\n * standing between a mixed selection and a half-applied, unrecorded delete.\n */\n\nimport type { JxPath } from \"../state\";\nimport { isAncestor, pathsEqual } from \"../state\";\n\n/**\n * The path single-target surfaces address — the most recently added, or `null` when empty.\n *\n * @param {readonly JxPath[] | null | undefined} selection\n * @returns {JxPath | null}\n */\nexport function primarySelection(selection: readonly JxPath[] | null | undefined): JxPath | null {\n return selection && selection.length > 0 ? (selection.at(-1) as JxPath) : null;\n}\n\n/**\n * The path a shift-range extends from — the first in the list, or `null` when empty.\n *\n * @param {readonly JxPath[] | null | undefined} selection\n * @returns {JxPath | null}\n */\nexport function selectionAnchor(selection: readonly JxPath[] | null | undefined): JxPath | null {\n return selection && selection.length > 0 ? (selection[0] as JxPath) : null;\n}\n\n/**\n * Whether `path` is one of the selected paths.\n *\n * @param {readonly JxPath[] | null | undefined} selection\n * @param {JxPath | null} path\n * @returns {boolean}\n */\nexport function isSelected(\n selection: readonly JxPath[] | null | undefined,\n path: JxPath | null,\n): boolean {\n if (!path || !selection) {\n return false;\n }\n return selection.some((p) => pathsEqual(p, path));\n}\n\n/**\n * Copy a selection, so nothing can mutate one through the array it was handed.\n *\n * History entries and the collab awareness payload both take a copy for the same reason they always\n * did: `session.selection` is a reactive proxy, and a stored reference to it would follow the live\n * selection instead of recording where it was. (A third caller, the sub-document stack's frames,\n * went with the stack — nothing pushes one any more.)\n *\n * @param {readonly JxPath[]} paths\n * @returns {JxPath[]}\n */\nexport function cloneSelection(paths: readonly JxPath[]): JxPath[] {\n return clonePaths(paths);\n}\n\n/** Copy a list of paths, so no caller can mutate a selection through the array it was handed. */\nfunction clonePaths(paths: readonly JxPath[]): JxPath[] {\n const out: JxPath[] = [];\n for (const path of paths) {\n out.push([...path]);\n }\n return out;\n}\n\n/**\n * Ctrl/Cmd-click: add the path when it is absent, remove it when it is present.\n *\n * Adding appends, so the newly clicked path becomes the primary and the anchor is untouched.\n * Removing preserves the order of the survivors — including the anchor, unless the anchor is what\n * was removed.\n *\n * @param {readonly JxPath[]} selection\n * @param {JxPath} path\n * @returns {JxPath[]}\n */\nexport function toggleSelected(selection: readonly JxPath[], path: JxPath): JxPath[] {\n if (isSelected(selection, path)) {\n return clonePaths(selection.filter((p) => !pathsEqual(p, path)));\n }\n return [...clonePaths(selection), [...path]];\n}\n\n/**\n * Shift-click: the contiguous run of `rows` between the anchor and `target`, inclusive.\n *\n * `rows` is the surface's own visible order — the Outline's flattened, expansion-aware row list —\n * because \"the range between these two\" is a question only the surface that draws them can answer.\n * When the anchor is absent from `rows` (it was collapsed away, or nothing was selected) the range\n * degenerates to `[target]`, which is a plain click.\n *\n * The returned list starts at the anchor end, so the anchor stays `selection[0]` and the target\n * becomes the primary — a further shift-click re-extends from the same anchor.\n *\n * @param {readonly JxPath[]} rows Visible rows in display order.\n * @param {JxPath | null} anchor\n * @param {JxPath} target\n * @returns {JxPath[]}\n */\nexport function rangeSelection(\n rows: readonly JxPath[],\n anchor: JxPath | null,\n target: JxPath,\n): JxPath[] {\n const to = rows.findIndex((p) => pathsEqual(p, target));\n const from = anchor ? rows.findIndex((p) => pathsEqual(p, anchor)) : -1;\n if (to === -1 || from === -1) {\n return [[...target]];\n }\n const slice = from <= to ? rows.slice(from, to + 1) : rows.slice(to, from + 1).toReversed();\n return clonePaths(slice);\n}\n\n/**\n * Drop every selected path that `removed` addresses or contains.\n *\n * This is `mutateRemoveNode`'s selection repair, widened: deleting a node used to clear the\n * selection outright, and with a list it clears only the entries the deletion actually invalidated.\n * A one-path selection therefore still ends up empty exactly when it used to.\n *\n * @param {readonly JxPath[]} selection\n * @param {JxPath} removed\n * @returns {JxPath[]}\n */\nexport function pruneSelection(selection: readonly JxPath[], removed: JxPath): JxPath[] {\n return clonePaths(selection.filter((p) => !isAncestor(removed, p)));\n}\n\n/**\n * Order two paths the way the document reads: parents before children, siblings by index.\n *\n * Segments are compared pairwise; numbers numerically (so `children/10` follows `children/9`), and\n * anything else by string order. A prefix sorts before what extends it.\n *\n * @param {JxPath} a\n * @param {JxPath} b\n * @returns {number}\n */\nexport function comparePaths(a: JxPath, b: JxPath): number {\n const len = Math.min(a.length, b.length);\n for (let i = 0; i < len; i++) {\n const x = a[i]!;\n const y = b[i]!;\n if (x === y) {\n continue;\n }\n if (typeof x === \"number\" && typeof y === \"number\") {\n return x - y;\n }\n return String(x) < String(y) ? -1 : 1;\n }\n return a.length - b.length;\n}\n\n/**\n * Drop any path whose ancestor is also selected.\n *\n * Deleting a `<section>` and one of its own paragraphs is one deletion, not two: the paragraph goes\n * with its parent, and a second splice into coordinates that no longer exist is how a batch\n * corrupts a document.\n *\n * @param {readonly JxPath[]} selection\n * @returns {JxPath[]}\n */\nexport function topLevelSelection(selection: readonly JxPath[]): JxPath[] {\n return clonePaths(\n selection.filter((p) => !selection.some((q) => !pathsEqual(q, p) && isAncestor(q, p))),\n );\n}\n\n/**\n * Whether `path` names a position a structural verb can splice — a tail of `\"children\"` + index.\n *\n * Every structural mutator (`mutateRemoveNode`, `mutateDuplicateNode`, `mutateWrapNode`) reaches\n * its parent with `parentElementPath` — drop the last two segments — and its position with\n * `childIndex` — take the last. That produces a splice coordinate for exactly one path shape, and\n * the Outline emits three others as first-class rows: the document element (`[]`), a repeater's map\n * template (`[…, \"children\", 1, \"map\"]`) and a `$switch` case (`[…, \"cases\", \"warn\"]`). For the\n * template, `parentElementPath` resolves to the enclosing children ARRAY, whose `.children` is\n * `undefined`, so the splice throws mid-transaction; for a case it splices at `NaN` and takes the\n * wrong child.\n *\n * Selecting one of those beside an ordinary element is a single ctrl-click, so this is the\n * invariant that keeps a batch from mutating the document and then throwing before anything is\n * recorded.\n *\n * @param {JxPath} path\n * @returns {boolean}\n */\nexport function isSpliceablePath(path: JxPath): boolean {\n return path.at(-2) === \"children\" && typeof path.at(-1) === \"number\";\n}\n\n/**\n * The order a structural batch must run in: contained paths dropped, unspliceable paths dropped,\n * then LAST node first.\n *\n * Descending document order is what makes a loop of splices safe. Removing or duplicating at index\n * `n` renumbers every sibling after `n`, so a batch that starts at the end never touches a\n * coordinate a later step still needs. It is also why duplicating a multi-selection inserts each\n * clone directly after its own original instead of walking the whole run forward.\n *\n * Containment is decided BEFORE spliceability, on the selection the user actually made: a selected\n * repeater template still shadows its own descendants, so selecting the template and something\n * inside it yields nothing rather than quietly deleting the child the user never pointed at.\n *\n * @param {readonly JxPath[]} selection\n * @returns {JxPath[]} Deepest/last first, every entry a splice coordinate.\n */\nexport function structuralBatch(selection: readonly JxPath[]): JxPath[] {\n return topLevelSelection(selection)\n .filter((path) => isSpliceablePath(path))\n .toSorted((a, b) => comparePaths(b, a));\n}\n\n/**\n * Deduplicate a list of paths, keeping the FIRST occurrence of each.\n *\n * Keeping the first is what makes `selection.setPaths` idempotent: passing the same list twice — or\n * a list that names one node twice — always lands on the same selection, in the same order, with\n * the same anchor and the same primary.\n *\n * @param {readonly JxPath[]} paths\n * @returns {JxPath[]}\n */\nexport function uniquePaths(paths: readonly JxPath[]): JxPath[] {\n const out: JxPath[] = [];\n for (const path of paths) {\n if (!out.some((p) => pathsEqual(p, path))) {\n out.push([...path]);\n }\n }\n return out;\n}\n\n/**\n * Whether two selections name the same paths in the same order.\n *\n * @param {readonly JxPath[] | null | undefined} a\n * @param {readonly JxPath[] | null | undefined} b\n * @returns {boolean}\n */\nexport function selectionsEqual(\n a: readonly JxPath[] | null | undefined,\n b: readonly JxPath[] | null | undefined,\n): boolean {\n const x = a ?? [];\n const y = b ?? [];\n return x.length === y.length && x.every((p, i) => pathsEqual(p, y[i] as JxPath));\n}\n\n/**\n * Collapse one field's value across the selection into a single reading.\n *\n * `{ mixed: true }` is the answer the three inspector tabs render as the **Mixed** provenance\n * state: the selected nodes disagree, so there is no one value to show and typing one would\n * overwrite several different ones. `{ mixed: false, value }` is the answer when they agree — and\n * when the selection is a single node it is ALWAYS that answer, which is why a single selection\n * renders no Mixed state anywhere.\n *\n * Comparison is by JSON shape rather than reference: two nodes that both carry `{ $ref: \"#/state/x\"\n * }` hold equal values written at different times.\n *\n * @template T\n * @param {readonly T[]} values One per selected node, in selection order.\n * @returns {{ mixed: boolean; value: T | undefined }}\n */\nexport function unifyValues<T>(values: readonly T[]): { mixed: boolean; value: T | undefined } {\n if (values.length === 0) {\n return { mixed: false, value: undefined };\n }\n const first = values[0] as T;\n const key = JSON.stringify(first ?? null);\n for (let i = 1; i < values.length; i++) {\n if (JSON.stringify(values[i] ?? null) !== key) {\n return { mixed: true, value: undefined };\n }\n }\n return { mixed: false, value: first };\n}\n",
|
|
18
|
+
"/**\n * Studio-utils.js — Pure utility functions extracted from studio.js\n *\n * These are all side-effect-free functions used by style/properties/events panels.\n */\n\nimport { defaultContentFormat, formatByName } from \"../format/format-host\";\nimport type { ContentSectionEntry } from \"../types\";\nimport type { ProjectConfig } from \"@jxsuite/schema/types\";\n\n/**\n * CamelCase → kebab-case for inline style attributes\n *\n * @param {string} str\n * @returns {string}\n */\nexport function camelToKebab(str: string) {\n return str.replaceAll(/[A-Z]/g, (c: string) => `-${c.toLowerCase()}`);\n}\n\n/**\n * Convert camelCase property name to \"Title Case\" label (e.g. \"backgroundColor\" → \"Background\n * Color\")\n *\n * @param {string} prop\n * @returns {string}\n */\nexport function camelToLabel(prop: string) {\n return prop.replaceAll(/([A-Z])/g, \" $1\").replace(/^./, (c: string) => c.toUpperCase());\n}\n\nexport function toCamelCase(str: string): string {\n return str\n .replaceAll(/[^a-zA-Z0-9]+(.)?/g, (_, c: string | undefined) => (c ? c.toUpperCase() : \"\"))\n .replace(/^[A-Z]/, (c) => c.toLowerCase());\n}\n\n/**\n * Convert a kebab-case CSS value to Title Case for picker display (e.g. \"border-box\" → \"Border\n * Box\")\n *\n * @param {string} val\n * @returns {string}\n */\nexport function kebabToLabel(val: string) {\n return val.replaceAll(\n /(^|-)(\\w)/g,\n (_: string, sep: string, c: string) => (sep ? \" \" : \"\") + c.toUpperCase(),\n );\n}\n\n/**\n * Get display label from metadata entry or prop name\n *\n * @param {{ $label?: string; [key: string]: unknown } | null | undefined} entry\n * @param {string} prop\n * @returns {string}\n */\nexport function propLabel(\n entry: { $label?: string; [key: string]: unknown } | null | undefined,\n prop: string,\n) {\n return entry?.$label || camelToLabel(prop);\n}\n\n/**\n * Label for HTML attributes — handles kebab-case (aria-label → \"Aria Label\")\n *\n * @param {{ $label?: string; [key: string]: unknown } | null | undefined} entry\n * @param {string} attr\n * @returns {string}\n */\nexport function attrLabel(\n entry: { $label?: string; [key: string]: unknown } | null | undefined,\n attr: string,\n) {\n if (entry?.$label) {\n return entry.$label;\n }\n if (attr.includes(\"-\")) {\n return attr.replaceAll(\n /(^|-)(\\w)/g,\n (_: string, sep: string, c: string) => (sep ? \" \" : \"\") + c.toUpperCase(),\n );\n }\n return camelToLabel(attr);\n}\n\n/**\n * Abbreviate a CSS value for button-group display\n *\n * @param {string} val\n * @returns {string}\n */\nexport function abbreviateValue(val: string) {\n const map: Record<string, string> = {\n baseline: \"base\",\n column: \"col\",\n \"column-reverse\": \"col-r\",\n contents: \"cnt\",\n \"flex-end\": \"end\",\n \"flex-start\": \"start\",\n \"flow-root\": \"flow\",\n inline: \"inl\",\n \"inline-block\": \"i-blk\",\n \"inline-flex\": \"i-flx\",\n \"inline-grid\": \"i-grd\",\n normal: \"norm\",\n nowrap: \"no-wr\",\n \"row-reverse\": \"row-r\",\n \"space-around\": \"arnd\",\n \"space-between\": \"betw\",\n \"space-evenly\": \"even\",\n stretch: \"str\",\n \"wrap-reverse\": \"wr-rev\",\n };\n return map[val] || val;\n}\n\n/**\n * Determine input widget type from a css-meta entry\n *\n * @param {Record<string, unknown>} entry\n * @returns {string}\n */\nexport function inferInputType(entry: Record<string, unknown>) {\n if (entry.$shorthand === true) {\n return \"shorthand\";\n }\n if (entry.$input === \"button-group\") {\n return \"button-group\";\n }\n if (entry.$input === \"media\") {\n return \"media\";\n }\n if (entry.format === \"color\") {\n return \"color\";\n }\n if (entry.format === \"uri-reference\") {\n return \"media\";\n }\n if (entry.$units !== undefined) {\n return \"number-unit\";\n }\n if (entry.type === \"number\") {\n return \"number\";\n }\n if (Array.isArray(entry.enum)) {\n return \"select\";\n }\n if (Array.isArray(entry.examples) || Array.isArray(entry.presets)) {\n return \"combobox\";\n }\n return \"text\";\n}\n\n/**\n * Match a document path to a content type and return its schema. Compares the content type's\n * `source` directory against the document path prefix, using `format` for extension matching.\n *\n * @param {string | null} documentPath — project-relative path (e.g. \"content/products/widget.md\")\n * @param {ProjectConfig | null | undefined} projectConfig — parsed project.json\n * @returns {{ name: string; schema: ContentTypeSchema } | null}\n */\nexport function findContentTypeSchema(\n documentPath: string | null,\n projectConfig: ProjectConfig | null | undefined,\n) {\n if (!documentPath || !projectConfig?.content) {\n return null;\n }\n // Content-type `source` prefixes are always forward-slash. The desktop platform can hand us\n // OS-native backslash paths on Windows, so normalize before prefix matching.\n const docPath = documentPath.replaceAll(\"\\\\\", \"/\");\n for (const [name, def] of Object.entries(\n projectConfig.content as Record<string, ContentSectionEntry>,\n )) {\n if (!def.source || !def.schema) {\n continue;\n }\n const src = def.source.replace(/^\\.\\//, \"\").replace(/\\/$/, \"\");\n const hasExt = src.includes(\".\") && !src.endsWith(\"/\");\n if (hasExt) {\n if (docPath === src || docPath.endsWith(`/${src}`)) {\n return { name, schema: def.schema };\n }\n } else {\n const ext =\n def.format === \"json\"\n ? \".json\"\n : (formatByName(def.format)?.extensions[0] ??\n defaultContentFormat()?.extensions[0] ??\n \".json\");\n if (docPath.startsWith(`${src}/`) && docPath.endsWith(ext)) {\n return { name, schema: def.schema };\n }\n }\n }\n return null;\n}\n\n/**\n * Convert a human-readable name to a CSS variable name. E.g. \"Geometric Humanist\" →\n * \"--font-geometric-humanist\"\n *\n * @param {string} name\n * @param {string} prefix - E.g. \"--font-\"\n * @returns {string}\n */\nexport function friendlyNameToVar(name: string, prefix: string) {\n const slug = name\n .trim()\n .toLowerCase()\n .replaceAll(/[^a-z0-9\\s-]/g, \"\")\n .replaceAll(/\\s+/g, \"-\")\n .replaceAll(/-+/g, \"-\")\n .replaceAll(/^-|-$/g, \"\");\n if (!slug) {\n return \"\";\n }\n return `${prefix}${slug}`;\n}\n\n/**\n * Convert a CSS variable name back to a display name. E.g. \"--font-geometric-humanist\" with prefix\n * \"--font-\" → \"Geometric Humanist\"\n *\n * @param {string} varName\n * @param {string} prefix\n * @returns {string}\n */\nexport function varDisplayName(varName: string, prefix: string) {\n return (\n varName\n .replace(new RegExp(`^${prefix.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`)}`), \"\")\n .replace(/^--/, \"\")\n .replaceAll(\"-\", \" \")\n .replaceAll(/\\b\\w/g, (c: string) => c.toUpperCase()) || varName\n );\n}\n\n/**\n * Parse a CEM type.text string into a structured descriptor.\n *\n * @param {string | undefined | null} typeText\n * @returns {{ kind: \"combobox\"; options: string[] }\n * | { kind: \"boolean\" }\n * | { kind: \"number\" }\n * | { kind: \"text\" }}\n */\nexport function parseCemType(typeText: string | undefined | null) {\n if (!typeText) {\n return { kind: \"text\" };\n }\n const t = typeText\n .trim()\n .replaceAll(/\\s*\\|\\s*undefined\\b/g, \"\")\n .trim();\n if (t === \"boolean\") {\n return { kind: \"boolean\" };\n }\n if (t === \"number\") {\n return { kind: \"number\" };\n }\n // Detect enum: \"'a' | 'b' | 'c'\" — pipe-separated quoted literals\n const enumMatch = t.match(/^'[^']*'(\\s*\\|\\s*'[^']*')+$/);\n if (enumMatch) {\n const options = [...t.matchAll(/'([^']*)'/g)].map((m) => m[1]);\n return { kind: \"combobox\", options };\n }\n return { kind: \"text\" };\n}\n\n/**\n * Clone a (possibly reactive) document tree via JSON round-trip. Unlike structuredClone, this works\n * on Vue reactive proxies and JSON-normalizes the tree (drops undefined values and functions) —\n * both required for document snapshots and clipboard payloads.\n */\nexport function jsonClone<T>(value: T): T {\n // oxlint-disable-next-line unicorn/prefer-structured-clone -- structuredClone throws on reactive proxies; JSON normalization is the point\n return JSON.parse(JSON.stringify(value)) as T;\n}\n",
|
|
19
|
+
"/**\n * Patch ops — typed descriptors of document mutations, recorded by the mutators in transact.ts\n * during a transaction. The canvas patcher consumes them to update the live canvas DOM surgically\n * instead of re-rendering everything. Ops carry paths, not values: consumers read the post-mutation\n * document as the single source of truth.\n */\n\n// oxlint-disable-next-line unicorn/prefer-export-from -- JxDocOpPair is also used locally (TransactionRecord)\nimport type { JxDocOpPair } from \"@jxsuite/collab/ops\";\nimport type { JxPath } from \"../state\";\nimport type { Tab } from \"./tab.js\";\n\nexport type JxPatchOp =\n /** The node's style changed (any depth: base prop, @media block, nested selector). */\n | { op: \"set-style\"; path: JxPath }\n /** The node's textContent changed. */\n | { op: \"set-text\"; path: JxPath }\n /** A non-style, non-text node property changed (key = property name). */\n | { op: \"set-prop\"; path: JxPath; key: string; isEvent?: boolean }\n /** The node's attributes[attr] changed. */\n | { op: \"set-attr\"; path: JxPath; attr: string }\n /** A node was inserted at parentPath.children[index]. */\n | { op: \"insert\"; parentPath: JxPath; index: number }\n /** The node at path was removed. */\n | { op: \"remove\"; path: JxPath }\n /** The node moved between/within children arrays (indices are post-mutation document truth). */\n | { op: \"move\"; fromPath: JxPath; toParentPath: JxPath; toIndex: number }\n /** The node at path was structurally replaced (wrap, tagName change, $props edit). */\n | { op: \"replace\"; path: JxPath }\n /** A document-level key changed (state/$media/$head/$elements/imports/$layout) — escalates. */\n | { op: \"doc-meta\"; key: string };\n\n/**\n * Value-carrying document mutation, replayable in either direction. Mutators record a\n * forward/inverse pair per change; history applies them for surgical undo/redo and for\n * materializing states from checkpoints — without whole-document snapshots per edit. The definition\n * is canonical in `@jxsuite/collab/ops` (the collab bridge mirrors the same ops into a shared\n * Y.Doc); re-exported here so studio call sites keep their import path.\n */\nexport type { JxDocOp } from \"@jxsuite/collab/ops\";\nexport type { JxDocOpPair };\n\n/**\n * A frontmatter key change, replayable in either direction. Frontmatter lives outside the document\n * tree (`tab.doc.content.frontmatter`, split off by the format host), so these are studio-local and\n * never enter the shared `JxDocOp` vocabulary the collab bridge and canvas iframe mirror.\n * `undefined` means the key was/becomes absent.\n */\nexport interface JxFmOp {\n field: string;\n before?: unknown;\n after?: unknown;\n}\n\n/** Everything recorded during one transaction. */\nexport interface TransactionRecord {\n /** Canvas patch ops (path-only) for surgical DOM updates. */\n ops: JxPatchOp[];\n /** Replayable forward/inverse document ops for patch-based history. */\n docOps: JxDocOpPair[];\n /** Replayable frontmatter key changes (content-mode docs) for history undo/redo. */\n fmOps: JxFmOp[];\n /**\n * False when some mutation in the transaction could not produce a guaranteed-correct inverse\n * (e.g. a move whose parents' paths interact) — history falls back to a checkpoint snapshot.\n */\n invertible: boolean;\n}\n\n/**\n * The canvas-side consumer of patch batches. Registered by the canvas patcher at studio init;\n * absent in headless tests, where every transaction falls back to the full-render path.\n */\nexport interface PatchConsumer {\n /** Decide whether this batch can be applied surgically in the current canvas state. */\n classify: (tab: Tab, ops: JxPatchOp[]) => { patchable: boolean; reason: string };\n /**\n * Mark a document root reference as surgically consumed, in every pane the patch will reach.\n *\n * `tab` is what decides those panes — one pane owns it, and a derived pane may be projecting that\n * pane — and each pane's canvas doc-effect clears only its own mark. A single mark per reference\n * was consumed by whichever pane's effect ran first, so the second full-rendered every patched\n * edit while the skip counter reported one skip.\n */\n markConsumed: (docRef: object, tab: Tab) => void;\n /**\n * Apply the batch to all ready canvas panels. Throws on any failure (caller escalates). `record`\n * carries the value-carrying `docOps` the iframe consumer posts across the frame boundary; the\n * legacy (parent-DOM) consumer ignores it and reads the post-mutation reactive doc instead.\n */\n apply: (tab: Tab, ops: JxPatchOp[], record?: TransactionRecord) => void;\n /**\n * Schedule a full canvas render as the fallback path, recording the reason.\n *\n * `tab` names the document that failed to patch, and so the PANE whose stage must be rebuilt: a\n * stage that is not showing this document is not out of date and must not be re-rendered.\n */\n escalate: (reason: string, tab: Tab) => void;\n}\n\nlet _consumer: PatchConsumer | null = null;\n\nexport function setPatchConsumer(consumer: PatchConsumer | null) {\n _consumer = consumer;\n}\n\nexport function getPatchConsumer(): PatchConsumer | null {\n return _consumer;\n}\n\n// ─── Recording ───────────────────────────────────────────────────────────────\n\nlet _recording: JxPatchOp[] | null = null;\nlet _docOps: JxDocOpPair[] | null = null;\nlet _fmOps: JxFmOp[] | null = null;\nlet _invertible = true;\n\n/** Begin recording patch ops for a transaction. */\nexport function beginRecording() {\n _recording = [];\n _docOps = [];\n _fmOps = [];\n _invertible = true;\n}\n\n/** Record a patch op describing an in-place mutation. No-op outside a transaction. */\nexport function recordPatch(op: JxPatchOp) {\n if (_recording) {\n _recording.push(op);\n }\n}\n\n/** Record a replayable forward/inverse document-op pair. No-op outside a transaction. */\nexport function recordDocOp(pair: JxDocOpPair) {\n if (_docOps) {\n _docOps.push(pair);\n }\n}\n\n/** Record a replayable frontmatter key change. No-op outside a transaction. */\nexport function recordFmOp(op: JxFmOp) {\n if (_fmOps) {\n _fmOps.push(op);\n }\n}\n\n/** Mark the current transaction as non-invertible — history stores a checkpoint instead. */\nexport function markNonInvertible() {\n _invertible = false;\n}\n\n/**\n * End recording and return everything recorded. An empty ops array means the mutation ran without\n * instrumentation (unknown change shape) — callers must treat that as not patchable.\n */\nexport function endRecording(): TransactionRecord {\n const record: TransactionRecord = {\n docOps: _docOps ?? [],\n fmOps: _fmOps ?? [],\n invertible: _invertible,\n ops: _recording ?? [],\n };\n _recording = null;\n _docOps = null;\n _fmOps = null;\n _invertible = true;\n return record;\n}\n",
|
|
20
|
+
"/// <reference lib=\"dom\" />\nimport { toRaw } from \"../reactivity\";\nimport { jsonClone } from \"../utils/studio-utils\";\nimport { childIndex, getNodeAtPath, parentElementPath, pathsEqual } from \"../state\";\nimport {\n cloneSelection,\n isSpliceablePath,\n primarySelection,\n pruneSelection,\n structuralBatch,\n} from \"./selection\";\nimport { applyDocOpToDoc, childArray, cloneValue } from \"./doc-op-apply\";\nimport {\n beginRecording,\n endRecording,\n getPatchConsumer,\n recordDocOp,\n recordFmOp,\n recordPatch,\n} from \"./patch-ops\";\n\nimport type { JxDocOp, JxDocOpPair, JxFmOp, TransactionRecord } from \"./patch-ops\";\n\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxPath } from \"../state\";\n\nimport type { JsonValue } from \"../types\";\nimport type {\n JxAttributeValue,\n JxEventBinding,\n JxMutableNode,\n JxStateObject,\n JxStyle,\n} from \"@jxsuite/schema/types\";\nimport { ensureNestedStyle, getNestedStyle, isEventBinding } from \"@jxsuite/schema/guards\";\n\nconst HISTORY_LIMIT = 100;\n\n/** Every Nth history entry stores a full snapshot so states can be materialized by replay. */\nconst CHECKPOINT_INTERVAL = 20;\n\n/** Opt-out flag for patch-based history (forces full-snapshot-per-edit legacy behavior). */\nfunction patchHistoryEnabled() {\n try {\n return typeof localStorage === \"undefined\" || !localStorage.getItem(\"jx-legacy-history\");\n } catch {\n return true;\n }\n}\n\n/** Forward/inverse pair for a single-key change on the node at path. */\nfunction setKeyPair(path: JxPath, key: string, before: unknown, after: unknown): JxDocOpPair {\n return {\n forward: { key, op: \"set-key\", path, value: after },\n inverse: { key, op: \"set-key\", path, value: before },\n };\n}\n\n/**\n * Translate `path` into post-splice coordinates when it descends through `parentPath`'s children at\n * or beyond the spliced index: a removal (delta -1) at fromIndex shifts deeper paths down; an\n * insertion (delta +1, inclusive) shifts them up. Returns `path` unchanged when the splice doesn't\n * affect it. Used to express a move's inverse in post-mutation coordinates.\n */\nfunction shiftPrefixedIndex(\n parentPath: JxPath,\n path: JxPath,\n spliceIndex: number,\n delta: number,\n inclusive: boolean,\n): JxPath {\n const d = parentPath.length;\n const isProperPrefix = d < path.length && parentPath.every((seg, i) => seg === path[i]);\n if (!isProperPrefix || path[d] !== \"children\" || typeof path[d + 1] !== \"number\") {\n return path;\n }\n const idx = path[d + 1] as number;\n if (inclusive ? idx < spliceIndex : idx <= spliceIndex) {\n return path;\n }\n const shifted = [...path];\n shifted[d + 1] = idx + delta;\n return shifted;\n}\n\n/** Any value that can sit at a document node key (undefined/null/\"\" deletes it). */\nexport type JxNodeValue =\n | JsonValue\n | JxMutableNode\n | (JxMutableNode | string)[]\n | JxEventBinding\n | undefined;\n\n// ─── Transactional layer ─────────────────────────────────────────────────────\n\n/**\n * Where a transaction came from: a direct user/tool edit, the undo/redo machinery replaying\n * recorded ops, or a remote collaborator's ops applied locally. Observers use this to avoid\n * republishing what they themselves applied.\n */\nexport type TransactOrigin = \"user\" | \"history\" | \"remote\";\n\n/**\n * Module-level hook invoked at the end of every transactDoc (after the canvas patch apply and the\n * dirty mark). Registered by the collab layer to mirror local edits into a shared document; at most\n * one observer exists. `record.docOps` may be empty for un-instrumented mutations — observers must\n * handle that (e.g. by diffing).\n */\nexport type TransactObserver = (\n tab: Tab,\n record: TransactionRecord,\n origin: TransactOrigin,\n) => void;\n\nlet _transactObserver: TransactObserver | null = null;\n\nexport function setTransactObserver(fn: TransactObserver | null) {\n _transactObserver = fn;\n}\n\n/**\n * Module-level gate consulted at transactDoc entry: return a refusal reason to block the mutation\n * (the collab layer soft-freezes structural editing while a peer holds source-canonical), or null\n * to proceed. Remote-origin transactions always pass — they ARE the frozen representation's\n * mirror.\n */\nexport type TransactGate = (tab: Tab, origin: TransactOrigin) => string | null;\n\nlet _transactGate: TransactGate | null = null;\n\nexport function setTransactGate(fn: TransactGate | null) {\n _transactGate = fn;\n}\n\n/**\n * Undo a transaction that threw part-way through, using the pairs it managed to record.\n *\n * **Why the inverses are enough.** Every mutator records its op AFTER its splice or assignment\n * succeeds, so `record.docOps` describes exactly the changes that landed — no more, no less.\n * Replaying their inverses in reverse is the same replay `undo` performs on a committed entry, run\n * against a document that never got a history entry. A mutator that changed the document WITHOUT\n * recording is already broken for undo; this is no weaker a guarantee than the one history gives.\n *\n * The document root reference is replaced so every effect re-reads, and nothing is marked consumed\n * — the canvas takes the full-render path, because the patch ops recorded for the half-applied\n * state describe changes that no longer exist.\n */\nfunction rollbackFailedTransaction(\n tab: Tab,\n record: TransactionRecord,\n selectionBefore: JxPath[],\n dirtyBefore: boolean,\n) {\n for (let i = record.docOps.length - 1; i >= 0; i--) {\n applyDocOpToDoc(tab.doc.document, toRaw(record.docOps[i]!.inverse) as JxDocOp);\n }\n for (let i = record.fmOps.length - 1; i >= 0; i--) {\n const op = record.fmOps[i]!;\n applyFmState(tab, op.field, op.before);\n }\n tab.doc.document = { ...toRaw(tab.doc.document) };\n // Mutators repair the selection as they go (`pruneSelection`, \"select the clone\"); rolling their\n // Edits back and leaving the selection pointing at coordinates that no longer exist would be its\n // Own corruption.\n tab.session.selection = selectionBefore;\n // `mutateUpdateFrontmatter` marks the tab dirty itself, mid-mutation. Rolling its write back and\n // Leaving the mark standing would report unsaved changes that no longer exist; restoring the\n // Captured value is right in both directions, since nothing but this transaction could have\n // Moved it.\n tab.doc.dirty = dirtyBefore;\n}\n\n/**\n * Apply a document mutation transactionally: push to history and mark dirty. The mutationFn\n * receives the tab and should mutate tab.doc.document in place.\n *\n * **All of it or none of it.** A mutationFn that throws part-way — a batch whose third splice hits\n * a coordinate that is not one — used to leave the earlier splices standing in the live reactive\n * tree while the throw skipped the new document reference, the history entry, the dirty mark and\n * the collab observer: the document was changed on screen, unreachable by undo, and invisible to\n * Save. The exception now rolls the applied ops back ({@link rollbackFailedTransaction}) and only\n * then rethrows, so a failed transaction is indistinguishable from one that never ran.\n *\n * **AND IT SAYS WHETHER IT WROTE**, because {@link setTransactGate} made \"returned normally\" and\n * \"changed the document\" two different facts and nothing downstream could tell them apart. Under\n * the source-canonical freeze the dock's body commit is refused here — and its caller went on to\n * mark the buffer settled, so `tabBufferUnsaved`, `shouldWarnOnClose` and `hasUnsavedTabs` all\n * reported \"nothing to lose\" about text that only existed in the buffer. Every close then took it\n * with no prompt. A refusal is not an exception (it is an ordinary, expected state of the room), so\n * it is a return value: `false` means the document is exactly as it was.\n *\n * @param {Tab | null} tab\n * @param {(tab: Tab) => void} mutationFn\n * @param {{ skipHistory?: boolean; origin?: TransactOrigin }} [opts]\n * @returns {boolean} True when the mutation was applied; false when there was no tab, or the gate\n * refused it.\n */\nexport function transactDoc(\n tab: Tab | null,\n mutationFn: (tab: Tab) => void,\n {\n skipHistory = false,\n origin = \"user\",\n coalesceKey = null,\n }: { skipHistory?: boolean; origin?: TransactOrigin; coalesceKey?: string | null } = {},\n): boolean {\n if (!tab) {\n return false;\n }\n if (origin !== \"remote\" && _transactGate?.(tab, origin)) {\n return false;\n }\n const selectionBefore = cloneSelection(tab.session.selection);\n const dirtyBefore = tab.doc.dirty;\n beginRecording();\n let record: TransactionRecord;\n let failure: { error: unknown } | null = null;\n try {\n mutationFn(tab);\n } catch (error) {\n // Boxed rather than tested for truthiness: a mutation is free to throw a falsy value, and\n // \"did it throw\" must not become \"was what it threw interesting\".\n failure = { error };\n } finally {\n record = endRecording();\n }\n if (failure) {\n rollbackFailedTransaction(tab, record, selectionBefore, dirtyBefore);\n throw failure.error;\n }\n\n // Replace the document root reference so effects tracking tab.doc.document re-trigger.\n // Nested objects are shared — the mutation already modified them in place.\n const raw = toRaw(tab.doc.document);\n const newRef = { ...raw };\n\n // When the canvas patcher can apply this change surgically, mark the new root reference as\n // Consumed BEFORE assigning it — the canvas doc-effect runs synchronously on assignment and\n // Skips the full render for consumed references. Panels' own effects still fire as before.\n // Anything unrecorded or unclassifiable falls through to today's full-render path.\n const consumer = getPatchConsumer();\n const verdict =\n consumer === null\n ? { patchable: false, reason: \"no-patch-consumer\" }\n : record.ops.length === 0\n ? { patchable: false, reason: \"unrecorded-mutation\" }\n : consumer.classify(tab, record.ops);\n if (verdict.patchable) {\n consumer!.markConsumed(newRef, tab);\n }\n\n tab.doc.document = newRef;\n\n if (verdict.patchable) {\n try {\n consumer!.apply(tab, record.ops, record);\n } catch (error) {\n consumer!.escalate(\n `patch-apply-failed: ${error instanceof Error ? error.message : String(error)}`,\n tab,\n );\n }\n }\n\n if (!skipHistory && !_batchTab) {\n pushHistoryEntry(tab, raw, record, selectionBefore, coalesceKey);\n }\n\n tab.doc.dirty = true;\n\n _transactObserver?.(tab, record, origin);\n return true;\n}\n\n/**\n * Append a history entry for a completed transaction. With patch-based history, entries carry\n * replayable forward/inverse ops and only periodic checkpoints store full document snapshots —\n * eliminating the whole-document clone per edit. Non-invertible or un-instrumented transactions\n * store a snapshot, which always keeps every state recoverable.\n *\n * @param {Tab} tab\n * @param {JxMutableNode} raw Post-mutation raw document\n * @param {TransactionRecord} record\n * @param {JxPath[]} selectionBefore\n */\nfunction pushHistoryEntry(\n tab: Tab,\n raw: JxMutableNode,\n record: TransactionRecord,\n selectionBefore: JxPath[],\n coalesceKey: string | null = null,\n) {\n const truncated = tab.history.snapshots.slice(0, tab.history.index + 1);\n const useOps =\n patchHistoryEnabled() &&\n record.invertible &&\n (record.docOps.length > 0 || record.fmOps.length > 0);\n\n // Successive commits to the same block are ONE undoable edit. Fold this transaction into the\n // Previous entry: its inverse already restores the state before the run began (undoing A→B then\n // B→C is C→A), so only the forward ops and the resulting document advance.\n const prev = truncated.at(-1);\n if (coalesceKey && useOps && prev && prev.coalesceKey === coalesceKey && prev.inverseOps) {\n prev.forwardOps = [...(prev.forwardOps ?? []), ...record.docOps.map((pair) => pair.forward)];\n // BOTH halves accumulate. Keeping only the run's first inverse would cover only the keys that\n // First commit happened to touch, so a later commit that changes the block's SHAPE — a plain\n // Block becoming rich, which clears `textContent` and writes `children` — would never be undone,\n // Leaving the node holding both keys at once. Undo replays inverses in reverse order, so\n // Appending yields \"undo the last commit, then the one before it, …\".\n prev.inverseOps = [...prev.inverseOps, ...record.docOps.map((pair) => pair.inverse)];\n prev.selection = cloneSelection(tab.session.selection);\n if (prev.document) {\n prev.document = jsonClone(raw);\n }\n tab.history.snapshots = truncated;\n tab.history.index = truncated.length - 1;\n return;\n }\n\n const needCheckpoint = !useOps || truncated.length % CHECKPOINT_INTERVAL === 0;\n truncated.push({\n document: needCheckpoint ? jsonClone(raw) : null,\n fmOps: useOps && record.fmOps.length > 0 ? record.fmOps : null,\n forwardOps: useOps ? record.docOps.map((p) => p.forward) : null,\n inverseOps: useOps ? record.docOps.map((p) => p.inverse) : null,\n coalesceKey,\n selection: cloneSelection(tab.session.selection),\n selectionBefore,\n });\n if (truncated.length > HISTORY_LIMIT) {\n // The new base entry must be a self-contained checkpoint before the old base is dropped.\n if (!truncated[1]!.document) {\n truncated[1]!.document = materializeState(truncated, 1);\n }\n truncated.shift();\n }\n tab.history.snapshots = truncated;\n tab.history.index = truncated.length - 1;\n}\n\n/**\n * Reconstruct the document at history state `target`: copy the nearest checkpoint at or before it,\n * then replay forward ops. Every entry holds either a snapshot or forward ops, so this always\n * succeeds.\n *\n * @param {HistorySnapshot[]} snapshots\n * @param {number} target\n * @returns {JxMutableNode}\n */\nfunction materializeState(\n snapshots: { document: JxMutableNode | null; forwardOps?: JxDocOp[] | null }[],\n target: number,\n): JxMutableNode {\n let base = target;\n while (base >= 0 && !snapshots[base]!.document) {\n base -= 1;\n }\n if (base < 0) {\n throw new Error(\"history-missing-checkpoint\");\n }\n const doc = jsonClone(snapshots[base]!.document) as JxMutableNode;\n for (let i = base + 1; i <= target; i++) {\n for (const op of snapshots[i]!.forwardOps ?? []) {\n applyDocOpToDoc(doc, op);\n }\n }\n return doc;\n}\n\n/**\n * Convenience: transact with a mutation fn that receives the document directly.\n *\n * @param {Tab | null} tab\n * @param {(doc: JxMutableNode) => void} fn\n * @param {{ skipHistory?: boolean; origin?: TransactOrigin }} [opts]\n * @returns {boolean} Whatever {@link transactDoc} answered — whether the mutation was applied.\n */\nexport function transact(\n tab: Tab | null,\n fn: (doc: JxMutableNode) => void,\n opts?: { skipHistory?: boolean; origin?: TransactOrigin },\n): boolean {\n return transactDoc(tab, (t) => fn(t.doc.document), opts);\n}\n\n/**\n * Apply externally-produced doc ops (a remote collaborator's edits) through the normal transaction\n * pipeline: the canvas patches surgically exactly as it does for undo/redo replay, panels' effects\n * fire, and — because the origin is \"remote\" — the transact observer will not republish them.\n * History is skipped; while a collab session is attached, undo is delegated (see\n * setHistoryDelegate) and local-only.\n *\n * @param {Tab} tab\n * @param {JxDocOp[]} ops\n */\nexport function applyExternalDocOps(tab: Tab, ops: JxDocOp[]) {\n transactDoc(\n tab,\n (t) => {\n for (const op of ops) {\n applyDocOp(t, op);\n }\n },\n { origin: \"remote\", skipHistory: true },\n );\n}\n\n// ─── Document-op application ─────────────────────────────────────────────────\n\n/** Document-level keys whose changes require a full scope/panel rebuild on the canvas. */\nconst DOC_META_KEYS = new Set([\"state\", \"$media\", \"$head\", \"$elements\", \"imports\", \"$layout\"]);\n\n/**\n * Apply a doc op to the live document AND record the matching canvas patch op, so undo/redo\n * transactions patch the canvas surgically like any other edit.\n *\n * @param {Tab} tab\n * @param {JxDocOp} op\n */\nfunction applyDocOp(tab: Tab, op: JxDocOp) {\n const prev =\n op.op === \"set-key\" ? (getNodeAtPath(tab.doc.document, op.path)?.[op.key] as unknown) : null;\n applyDocOpToDoc(tab.doc.document, op);\n // The canvas lives in an iframe and can only be patched from VALUE-CARRYING ops (`record.docOps`),\n // Which is what crosses the bridge. Recording only the classification patch below left docOps\n // Empty on this path, so undo/redo posted an EMPTY patch: the document changed, the patch\n // Classified as applicable (suppressing the full render), and the canvas silently kept showing\n // The pre-undo content. Replaying an op IS a forward op — record it as one.\n //\n // History never reads the inverse here: undo/redo run with `skipHistory`, and the entry they\n // Replay already holds the pair. `markNonInvertible` would be wrong (it forces a whole-document\n // Checkpoint), so the op is paired with itself.\n recordDocOp({ forward: op, inverse: op });\n switch (op.op) {\n case \"set-key\": {\n if (DOC_META_KEYS.has(op.key)) {\n recordPatch({ key: op.key, op: \"doc-meta\" });\n } else if (op.key === \"style\") {\n recordPatch({ op: \"set-style\", path: op.path });\n } else if (op.key === \"textContent\") {\n recordPatch({ op: \"set-text\", path: op.path });\n } else if (op.key === \"attributes\" || op.key === \"cases\" || op.key === \"$props\") {\n recordPatch({ op: \"replace\", path: op.path });\n } else {\n const isEvent =\n op.key.startsWith(\"on\") && (isEventBinding(op.value) || isEventBinding(prev));\n recordPatch({ isEvent, key: op.key, op: \"set-prop\", path: op.path });\n }\n return;\n }\n case \"insert-child\": {\n recordPatch({ index: op.index, op: \"insert\", parentPath: op.parentPath });\n return;\n }\n case \"remove-child\": {\n recordPatch({ op: \"remove\", path: [...op.parentPath, \"children\", op.index] });\n return;\n }\n case \"set-child\": {\n recordPatch({ op: \"replace\", path: [...op.parentPath, \"children\", op.index] });\n return;\n }\n case \"move-child\": {\n recordPatch({\n fromPath: [...op.fromParentPath, \"children\", op.fromIndex],\n op: \"move\",\n toIndex: op.toIndex,\n toParentPath: op.toParentPath,\n });\n break;\n }\n default: {\n break;\n }\n }\n}\n\n// ─── Batch (group multiple mutations into one undo step) ────────────────────\n\nlet _batchTab: Tab | null = null;\n\n/** Module-level hook invoked when a batch closes (collab flushes its buffered ops as one step). */\nexport type BatchEndNotifier = (tab: Tab) => void;\n\nlet _batchEndNotifier: BatchEndNotifier | null = null;\n\nexport function setBatchEndNotifier(fn: BatchEndNotifier | null) {\n _batchEndNotifier = fn;\n}\n\nexport function beginBatch(tab: Tab | null) {\n _batchTab = tab;\n}\n\nexport function endBatch() {\n const tab = _batchTab;\n // A history delegate owns undo grouping while registered; the snapshot push would be dead weight.\n if (tab && !_historyDelegates.has(tab)) {\n const raw = toRaw(tab.doc.document);\n const snapshot = {\n document: jsonClone(raw),\n selection: cloneSelection(tab.session.selection),\n };\n const truncated = tab.history.snapshots.slice(0, tab.history.index + 1);\n truncated.push(snapshot);\n if (truncated.length > HISTORY_LIMIT) {\n truncated.shift();\n }\n tab.history.snapshots = truncated;\n tab.history.index = truncated.length - 1;\n }\n _batchTab = null;\n if (tab) {\n _batchEndNotifier?.(tab);\n }\n}\n\nexport function isBatching(): boolean {\n return _batchTab !== null;\n}\n\n/**\n * Which tab the open batch belongs to, or `null` when none is open.\n *\n * The agent loop needs this to keep a batch honest across a tab change. A batch is opened against\n * one tab and closed against the same one — {@link endBatch} pushes ITS history snapshot and fires\n * the collab notifier for IT — so a loop whose tools moved to a second document has to close the\n * first batch and open a second, or the second document's edits get neither a history entry nor a\n * collab publish. Reading the batched tab is how the loop can tell.\n */\nexport function batchTab(): Tab | null {\n return _batchTab;\n}\n\n// ─── Undo / Redo ─────────────────────────────────────────────────────────────\n\n/**\n * Per-tab replacement for the built-in op-log history. While a delegate is registered (a collab\n * session's Y.UndoManager), undo/redo route to it and the snapshot history is bypassed — keeping\n * this module free of any yjs knowledge.\n */\nexport interface HistoryDelegate {\n undo: (tab: Tab) => void;\n redo: (tab: Tab) => void;\n canUndo: (tab: Tab) => boolean;\n canRedo: (tab: Tab) => boolean;\n}\n\nconst _historyDelegates = new WeakMap<Tab, HistoryDelegate>();\n\nexport function setHistoryDelegate(tab: Tab, delegate: HistoryDelegate | null) {\n if (delegate) {\n _historyDelegates.set(tab, delegate);\n } else {\n _historyDelegates.delete(tab);\n }\n}\n\nexport function getHistoryDelegate(tab: Tab): HistoryDelegate | null {\n return _historyDelegates.get(tab) ?? null;\n}\n\nexport function canUndo(tab: Tab): boolean {\n const delegate = _historyDelegates.get(tab);\n return delegate ? delegate.canUndo(tab) : tab.history.index > 0;\n}\n\nexport function canRedo(tab: Tab): boolean {\n const delegate = _historyDelegates.get(tab);\n return delegate ? delegate.canRedo(tab) : tab.history.index < tab.history.snapshots.length - 1;\n}\n\n/** Restore a materialized snapshot state (full-render path). */\nfunction restoreState(tab: Tab, index: number) {\n const { snapshots } = tab.history;\n tab.doc.document = materializeState(snapshots, index);\n const snap = snapshots[index]!;\n tab.session.selection = cloneSelection(toRaw(snap.selection));\n}\n\n/** Debug-flag assertion: ops-based undo/redo must land on the same state replay produces. */\nfunction assertHistoryConsistency(tab: Tab, index: number) {\n try {\n if (typeof localStorage === \"undefined\" || !localStorage.getItem(\"jx-canvas-debug\")) {\n return;\n }\n } catch {\n return;\n }\n const expected = JSON.stringify(materializeState(tab.history.snapshots, index));\n const actual = JSON.stringify(jsonClone(toRaw(tab.doc.document)));\n if (expected !== actual) {\n console.error(\"jx history: ops-based undo/redo diverged from checkpoint replay\", {\n index,\n });\n }\n}\n\n/** @param {Tab} tab */\nexport function undo(tab: Tab) {\n const delegate = _historyDelegates.get(tab);\n if (delegate) {\n delegate.undo(tab);\n return;\n }\n if (tab.history.index <= 0) {\n return;\n }\n const entry = tab.history.snapshots[tab.history.index]!;\n const inverseOps = patchHistoryEnabled() ? entry.inverseOps : null;\n const fmOps = patchHistoryEnabled() ? entry.fmOps : null;\n if ((inverseOps && inverseOps.length > 0) || (fmOps && fmOps.length > 0)) {\n // Surgical path: apply inverse ops through the normal transaction pipeline (the canvas\n // Patches in place when it can), in reverse recording order.\n const applied = transactDoc(\n tab,\n (t) => {\n if (inverseOps) {\n for (let i = inverseOps.length - 1; i >= 0; i--) {\n applyDocOp(t, toRaw(inverseOps[i]) as JxDocOp);\n }\n }\n if (fmOps) {\n for (let i = fmOps.length - 1; i >= 0; i--) {\n const op = toRaw(fmOps[i]) as JxFmOp;\n applyFmState(t, op.field, op.before);\n }\n }\n },\n { origin: \"history\", skipHistory: true },\n );\n /* A REFUSED REPLAY IS NOT A STEP TAKEN. `\"history\"` is not `\"remote\"`, so the gate refuses this\n exactly as it refuses a direct edit — and everything below assumed the ops landed. Moving the\n index over a document that did not change desynchronises the log from the tree: the next redo\n replays a forward op onto a state it was never the inverse of, and `doc.dirty` claims an edit\n nobody made. Undo that cannot run is undo that does nothing, which is the honest answer. */\n if (!applied) {\n return;\n }\n tab.session.selection = cloneSelection(toRaw(entry.selectionBefore ?? []));\n tab.history.index -= 1;\n assertHistoryConsistency(tab, tab.history.index);\n } else {\n tab.history.index -= 1;\n restoreState(tab, tab.history.index);\n }\n tab.doc.dirty = true;\n}\n\n/** @param {Tab} tab */\nexport function redo(tab: Tab) {\n const delegate = _historyDelegates.get(tab);\n if (delegate) {\n delegate.redo(tab);\n return;\n }\n if (tab.history.index >= tab.history.snapshots.length - 1) {\n return;\n }\n const entry = tab.history.snapshots[tab.history.index + 1]!;\n const forwardOps = patchHistoryEnabled() ? entry.forwardOps : null;\n const fmOps = patchHistoryEnabled() ? entry.fmOps : null;\n if ((forwardOps && forwardOps.length > 0) || (fmOps && fmOps.length > 0)) {\n const applied = transactDoc(\n tab,\n (t) => {\n if (forwardOps) {\n for (const op of forwardOps) {\n applyDocOp(t, toRaw(op) as JxDocOp);\n }\n }\n if (fmOps) {\n for (const op of fmOps) {\n const raw = toRaw(op) as JxFmOp;\n applyFmState(t, raw.field, raw.after);\n }\n }\n },\n { origin: \"history\", skipHistory: true },\n );\n // Same as {@link undo}: a refused replay leaves the document alone, so the index must stay\n // Where it is or the log stops describing the tree.\n if (!applied) {\n return;\n }\n tab.session.selection = cloneSelection(toRaw(entry.selection));\n tab.history.index += 1;\n assertHistoryConsistency(tab, tab.history.index);\n } else {\n tab.history.index += 1;\n restoreState(tab, tab.history.index);\n }\n tab.doc.dirty = true;\n}\n\n// ─── In-place document mutators ──────────────────────────────────────────────\n\n/**\n * @param {Tab} tab\n * @param {JxPath} parentPath\n * @param {number} index\n * @param {JxMutableNode} nodeDef\n */\nexport function mutateInsertNode(\n tab: Tab,\n parentPath: JxPath,\n index: number,\n nodeDef: JxMutableNode,\n) {\n const parent = getNodeAtPath(tab.doc.document, parentPath);\n if (!parent) {\n return;\n }\n childArray(parent).splice(index, 0, structuredClone(nodeDef));\n recordPatch({ index, op: \"insert\", parentPath });\n recordDocOp({\n forward: { index, node: cloneValue(nodeDef), op: \"insert-child\", parentPath },\n inverse: { index, op: \"remove-child\", parentPath },\n });\n}\n\n/**\n * Remove the node at `path` from its parent's children array.\n *\n * The guard is {@link isSpliceablePath}, not `path.length < 2`: the shorter test admits the\n * Outline's map-template and `$switch`-case rows, whose `parentElementPath` is a children ARRAY\n * rather than a node — `.children.splice` on it throws, and the throw is what left a batch's\n * earlier removals applied and unrecorded.\n *\n * @param {Tab} tab\n * @param {JxPath} path\n */\nexport function mutateRemoveNode(tab: Tab, path: JxPath) {\n if (!path || !isSpliceablePath(path)) {\n return;\n }\n const elemPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const [removed] = (getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(\n idx,\n 1,\n );\n recordPatch({ op: \"remove\", path });\n recordDocOp({\n forward: { index: idx, op: \"remove-child\", parentPath: elemPath },\n inverse: { index: idx, node: cloneValue(removed), op: \"insert-child\", parentPath: elemPath },\n });\n tab.session.selection = pruneSelection(tab.session.selection, path);\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n */\nexport function mutateDuplicateNode(tab: Tab, path: JxPath) {\n if (!path || !isSpliceablePath(path)) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node) {\n return;\n }\n const elemPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const clone = structuredClone(toRaw(node));\n (getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx + 1, 0, clone);\n recordPatch({ index: idx + 1, op: \"insert\", parentPath: elemPath });\n recordDocOp({\n forward: { index: idx + 1, node: cloneValue(clone), op: \"insert-child\", parentPath: elemPath },\n inverse: { index: idx + 1, op: \"remove-child\", parentPath: elemPath },\n });\n tab.session.selection = [[...elemPath, \"children\", idx + 1]];\n}\n\n/**\n * Remove every selected node, in ONE transaction and therefore ONE undo step (§6.5).\n *\n * Three things make a batch different from a loop. `structuralBatch` drops paths contained by\n * another selected path — deleting a `<section>` and a paragraph inside it is one deletion — drops\n * paths that name no splice coordinate at all (the document element, a repeater's map template, a\n * `$switch` case, each of which the Outline offers as a ctrl-clickable row), and orders what\n * survives LAST-node-first, so each splice happens above coordinates no later step depends on. A\n * forward loop would delete `children/0` and then `children/1`, which by then is the node that used\n * to be `children/2`.\n *\n * Selection repair is `mutateRemoveNode`'s, applied once per removal: a path is dropped when the\n * node it addresses has gone. With a single path in, that is exactly the old behaviour — the\n * selection ends up empty.\n *\n * @param {Tab} tab\n * @param {readonly JxPath[]} paths\n */\nexport function mutateRemoveNodes(tab: Tab, paths: readonly JxPath[]) {\n for (const path of structuralBatch(paths)) {\n mutateRemoveNode(tab, path);\n }\n}\n\n/**\n * Duplicate every selected node in one transaction, selecting the clones.\n *\n * Same descending order, for the same reason: inserting a clone at `idx + 1` renumbers every later\n * sibling, so the batch starts at the last. The resulting selection is the clones in document\n * order, which means a duplicate-then-duplicate-again walks down the page the way repeating the\n * single-node command always did.\n *\n * @param {Tab} tab\n * @param {readonly JxPath[]} paths\n */\nexport function mutateDuplicateNodes(tab: Tab, paths: readonly JxPath[]) {\n let clones: JxPath[] = [];\n for (const path of structuralBatch(paths)) {\n const before = tab.session.selection;\n mutateDuplicateNode(tab, path);\n const made = primarySelection(tab.session.selection);\n // `mutateDuplicateNode` refuses a path that addresses nothing and leaves the selection alone;\n // Only a real insertion contributes a clone.\n if (!made || tab.session.selection === before) {\n continue;\n }\n // Descending order keeps the ORIGINALS valid, but not the clones already made: this insertion\n // Sits before them, so every one of their coordinates moved up by one. Translating them here\n // Is the difference between \"the copies are selected\" and \"two of the originals are\".\n const parentPath = parentElementPath(made) as JxPath;\n const spliceIndex = childIndex(made) as number;\n clones = clones.map((clone) => shiftPrefixedIndex(parentPath, clone, spliceIndex, 1, true));\n clones.unshift(made);\n }\n if (clones.length > 0) {\n tab.session.selection = clones;\n }\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} wrapperTag\n */\nexport function mutateWrapNode(tab: Tab, path: JxPath, wrapperTag = \"div\") {\n if (!path || !isSpliceablePath(path)) {\n return;\n }\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node) {\n return;\n }\n const elemPath = parentElementPath(path) as JxPath;\n const idx = childIndex(path) as number;\n const wrapper = {\n children: [structuredClone(toRaw(node))],\n tagName: wrapperTag,\n };\n const original = cloneValue(node);\n (getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx, 1, wrapper);\n recordPatch({ op: \"replace\", path });\n recordDocOp({\n forward: { index: idx, node: cloneValue(wrapper), op: \"set-child\", parentPath: elemPath },\n inverse: { index: idx, node: original, op: \"set-child\", parentPath: elemPath },\n });\n tab.session.selection = [[...elemPath, \"children\", idx]];\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} fromPath\n * @param {JxPath} toParentPath\n * @param {number} toIndex\n */\nexport function mutateMoveNode(tab: Tab, fromPath: JxPath, toParentPath: JxPath, toIndex: number) {\n const doc = tab.doc.document;\n const fromParentPath = parentElementPath(fromPath) as JxPath;\n const fromIdx = childIndex(fromPath) as number;\n if (!fromParentPath || typeof fromIdx !== \"number\") {\n return;\n }\n const fromParent = getNodeAtPath(doc, fromParentPath);\n const toParent = getNodeAtPath(doc, toParentPath);\n if (!fromParent || !Array.isArray(fromParent.children) || !toParent) {\n return;\n }\n const [node] = fromParent.children.splice(fromIdx, 1);\n if (node === undefined) {\n return;\n }\n let adjustedIndex = toIndex;\n if (fromParent === toParent && fromIdx < toIndex) {\n adjustedIndex -= 1;\n }\n childArray(toParent).splice(adjustedIndex, 0, node);\n recordPatch({ fromPath, op: \"move\", toIndex: adjustedIndex, toParentPath });\n recordDocOp({\n forward: {\n fromIndex: fromIdx,\n fromParentPath,\n op: \"move-child\",\n toIndex: adjustedIndex,\n toParentPath,\n },\n inverse: {\n fromIndex: adjustedIndex,\n // The inverse runs against the post-move document, so both parent paths are translated\n // Into post-move coordinates: the removal shifted paths under fromParent, the insertion\n // Shifted paths under toParent.\n fromParentPath: shiftPrefixedIndex(fromParentPath, toParentPath, fromIdx, -1, false),\n op: \"move-child\",\n toIndex: fromIdx,\n toParentPath: shiftPrefixedIndex(toParentPath, fromParentPath, adjustedIndex, 1, true),\n },\n });\n\n if (pathsEqual(primarySelection(tab.session.selection), fromPath)) {\n let idx = toIndex;\n if (\n fromParentPath.length === toParentPath.length &&\n fromParentPath.every((v, i) => v === toParentPath[i]) &&\n fromIdx < toIndex\n ) {\n idx = toIndex - 1;\n }\n tab.session.selection = [[...toParentPath, \"children\", idx]];\n }\n}\n\n/**\n * Set (or, for an empty value, delete) one property on the node `path` names.\n *\n * **A path that no longer resolves is a no-op, not a throw.** `getNodeAtPath` answers `undefined`\n * for a coordinate that has been deleted, and `node[key]` on that is `undefined is not an object` —\n * an exception thrown from inside a mutation, which {@link transactDoc} correctly rolls back and\n * rethrows into whatever asked for the edit. For a panel that is one stale click; for the dock's\n * debounced body commit it escaped through `commitBufferWrites` and out of the dock's\n * `afterRender`, aborting the repaint with the editor undisposed and its 500ms timer still armed.\n * Deletions arrive from collaborators and from the author's own undo while an editor is open, so a\n * stale path is an ordinary state of the document rather than a programming error, and the ordinary\n * answer is to change nothing. Callers that must distinguish \"wrote\" from \"nothing to write to\"\n * resolve the node themselves first — `panels/editors.ts`'s `bodyWriter` does exactly that.\n *\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} key\n * @param {JxNodeValue} value\n */\nexport function mutateUpdateProperty(tab: Tab, path: JxPath, key: string, value?: JxNodeValue) {\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node) {\n return;\n }\n const prev = node[key];\n const before = cloneValue(prev);\n if (value === undefined || value === null || value === \"\") {\n delete node[key];\n } else {\n node[key] = value;\n }\n recordDocOp(setKeyPair(path, key, before, cloneValue(node[key])));\n if (key === \"textContent\") {\n recordPatch({ op: \"set-text\", path });\n } else if (key === \"style\") {\n recordPatch({ op: \"set-style\", path });\n } else {\n // Event-binding edits are invisible on the canvas (stripped in design/edit renders); the\n // Deleted-value case checks the previous value since the new one is gone.\n const bindingValue = value === undefined || value === null || value === \"\" ? prev : value;\n const isEvent = key.startsWith(\"on\") && isEventBinding(bindingValue);\n recordPatch({ isEvent, key, op: \"set-prop\", path });\n }\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateStyle(tab: Tab, path: JxPath, prop: string, value: string | undefined) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n if (value === undefined || value === \"\") {\n delete node.style[prop];\n } else {\n node.style[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} attr\n * @param {JxAttributeValue | undefined} value — a literal, `$ref` binding, or `${}` template.\n */\nexport function mutateUpdateAttribute(\n tab: Tab,\n path: JxPath,\n attr: string,\n value?: JxAttributeValue | undefined,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const attrsBefore = cloneValue(node.attributes);\n if (!node.attributes) {\n node.attributes = {};\n }\n if (value === undefined || value === \"\") {\n delete node.attributes[attr];\n } else {\n node.attributes[attr] = value;\n }\n if (Object.keys(node.attributes).length === 0) {\n delete node.attributes;\n }\n recordDocOp(setKeyPair(path, \"attributes\", attrsBefore, cloneValue(node.attributes)));\n recordPatch({ attr, op: \"set-attr\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} mediaName\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateMediaStyle(\n tab: Tab,\n path: JxPath,\n mediaName: string,\n prop: string,\n value: string | undefined,\n) {\n if (!mediaName) {\n return mutateUpdateStyle(tab, path, prop, value);\n }\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n const key = `@${mediaName}`;\n const media = ensureNestedStyle(node.style, key);\n if (value === undefined || value === \"\") {\n delete media[prop];\n if (Object.keys(media).length === 0) {\n delete node.style[key];\n }\n } else {\n media[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} selector\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateNestedStyle(\n tab: Tab,\n path: JxPath,\n selector: string,\n prop: string,\n value: string | undefined,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n const block = ensureNestedStyle(node.style, selector);\n if (value === undefined || value === \"\") {\n delete block[prop];\n if (Object.keys(block).length === 0) {\n delete node.style[selector];\n }\n } else {\n block[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} mediaName\n * @param {string} selector\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateMediaNestedStyle(\n tab: Tab,\n path: JxPath,\n mediaName: string,\n selector: string,\n prop: string,\n value: string | undefined,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n const key = `@${mediaName}`;\n const media = ensureNestedStyle(node.style, key);\n const block = ensureNestedStyle(media, selector);\n if (value === undefined || value === \"\") {\n delete block[prop];\n if (Object.keys(block).length === 0) {\n delete media[selector];\n }\n if (Object.keys(media).length === 0) {\n delete node.style[key];\n }\n } else {\n block[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * Update a style property at a nested style path (e.g., [\"table\", \"th\"]). Creates intermediate\n * objects as needed.\n *\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string[]} stylePath\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateNestedStylePath(\n tab: Tab,\n path: JxPath,\n stylePath: string[],\n prop: string,\n value: string | undefined,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n let obj = node.style;\n for (const seg of stylePath) {\n obj = ensureNestedStyle(obj, seg);\n }\n if (value === undefined || value === \"\") {\n delete obj[prop];\n // Clean up empty parent objects\n let cur: JxStyle | undefined = node.style;\n for (let i = 0; i < stylePath.length && cur; i++) {\n const child = getNestedStyle(cur, stylePath[i]!);\n if (child && Object.keys(child).length === 0) {\n delete cur[stylePath[i]!];\n break;\n }\n cur = child;\n }\n } else {\n obj[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * Update a style property at a nested style path within a media query.\n *\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} mediaName\n * @param {string[]} stylePath\n * @param {string} prop\n * @param {string | undefined} value\n */\nexport function mutateUpdateMediaNestedStylePath(\n tab: Tab,\n path: JxPath,\n mediaName: string,\n stylePath: string[],\n prop: string,\n value: string | undefined,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (!node.style) {\n node.style = {};\n }\n const key = `@${mediaName}`;\n const media = ensureNestedStyle(node.style, key);\n let obj = media;\n for (const seg of stylePath) {\n obj = ensureNestedStyle(obj, seg);\n }\n if (value === undefined || value === \"\") {\n delete obj[prop];\n let cur: JxStyle | undefined = media;\n for (let i = 0; i < stylePath.length && cur; i++) {\n const child = getNestedStyle(cur, stylePath[i]!);\n if (child && Object.keys(child).length === 0) {\n delete cur[stylePath[i]!];\n break;\n }\n cur = child;\n }\n if (Object.keys(media).length === 0) {\n delete node.style[key];\n }\n } else {\n obj[prop] = value;\n }\n if (Object.keys(node.style).length === 0) {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {Record<string, string | undefined> | undefined} style\n */\nexport function mutateReplaceStyle(tab: Tab, path: JxPath, style: JxStyle | undefined) {\n const node = getNodeAtPath(tab.doc.document, path);\n const styleBefore = cloneValue(node.style);\n if (style && Object.keys(style).length > 0) {\n node.style = style;\n } else {\n delete node.style;\n }\n recordDocOp(setKeyPair(path, \"style\", styleBefore, cloneValue(node.style)));\n recordPatch({ op: \"set-style\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {string} name\n * @param {Record<string, JsonValue>} def\n */\nexport function mutateAddDef(tab: Tab, name: string, def: Record<string, JsonValue>) {\n const doc = tab.doc.document;\n const before = cloneValue(doc.state);\n if (!doc.state) {\n doc.state = {};\n }\n doc.state[name] = def;\n recordDocOp(setKeyPair([], \"state\", before, cloneValue(doc.state)));\n recordPatch({ key: \"state\", op: \"doc-meta\" });\n}\n\n/**\n * @param {Tab} tab\n * @param {string} name\n */\nexport function mutateRemoveDef(tab: Tab, name: string) {\n const doc = tab.doc.document;\n if (doc.state) {\n const before = cloneValue(doc.state);\n delete doc.state[name];\n if (Object.keys(doc.state).length === 0) {\n delete doc.state;\n }\n recordDocOp(setKeyPair([], \"state\", before, cloneValue(doc.state)));\n recordPatch({ key: \"state\", op: \"doc-meta\" });\n }\n}\n\n/**\n * @param {Tab} tab\n * @param {string} name\n * @param {Record<string, JsonValue>} updates\n */\nexport function mutateUpdateDef(tab: Tab, name: string, updates: Record<string, unknown>) {\n const doc = tab.doc.document;\n const stateBefore = cloneValue(doc.state);\n if (!doc.state) {\n doc.state = {};\n }\n const existing = doc.state[name];\n const entry: JxStateObject =\n existing == null\n ? {}\n : typeof existing !== \"object\" || Array.isArray(existing)\n ? { default: existing }\n : (existing as JxStateObject);\n doc.state[name] = entry;\n Object.assign(entry, updates);\n for (const k of Object.keys(entry)) {\n if (entry[k] === undefined || entry[k] === null) {\n delete entry[k];\n }\n }\n recordDocOp(setKeyPair([], \"state\", stateBefore, cloneValue(doc.state)));\n recordPatch({ key: \"state\", op: \"doc-meta\" });\n}\n\n/**\n * @param {Tab} tab\n * @param {string} oldName\n * @param {string} newName\n */\nexport function mutateRenameDef(tab: Tab, oldName: string, newName: string) {\n const doc = tab.doc.document;\n if (!doc.state || !doc.state[oldName]) {\n return;\n }\n const before = cloneValue(doc.state);\n doc.state[newName] = doc.state[oldName];\n delete doc.state[oldName];\n recordDocOp(setKeyPair([], \"state\", before, cloneValue(doc.state)));\n recordPatch({ key: \"state\", op: \"doc-meta\" });\n}\n\n/**\n * @param {Tab} tab\n * @param {string} name\n * @param {string | undefined} query\n */\nexport function mutateUpdateMedia(tab: Tab, name: string, query?: string | undefined) {\n const doc = tab.doc.document;\n const mediaBefore = cloneValue(doc.$media);\n if (!doc.$media) {\n doc.$media = {};\n }\n if (query === undefined || query === \"\") {\n delete doc.$media[name];\n if (Object.keys(doc.$media).length === 0) {\n delete doc.$media;\n }\n } else {\n doc.$media[name] = query;\n }\n recordDocOp(setKeyPair([], \"$media\", mediaBefore, cloneValue(doc.$media)));\n recordPatch({ key: \"$media\", op: \"doc-meta\" });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} propName\n * @param {JsonValue} value\n */\nexport function mutateUpdateProp(tab: Tab, path: JxPath, propName: string, value: JsonValue) {\n const node = getNodeAtPath(tab.doc.document, path);\n const propsBefore = cloneValue(node.$props);\n if (!node.$props) {\n node.$props = {};\n }\n if (value === undefined || value === null || value === \"\") {\n delete node.$props[propName];\n } else {\n node.$props[propName] = value;\n }\n if (Object.keys(node.$props).length === 0) {\n delete node.$props;\n }\n recordDocOp(setKeyPair(path, \"$props\", propsBefore, cloneValue(node.$props)));\n recordPatch({ op: \"replace\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} caseName\n * @param {JxMutableNode} [caseDef]\n */\nexport function mutateAddSwitchCase(\n tab: Tab,\n path: JxPath,\n caseName: string,\n caseDef?: JxMutableNode,\n) {\n const node = getNodeAtPath(tab.doc.document, path);\n const before = cloneValue(node.cases);\n if (!node.cases) {\n node.cases = {};\n }\n node.cases[caseName] = caseDef || { tagName: \"div\", textContent: caseName };\n recordDocOp(setKeyPair(path, \"cases\", before, cloneValue(node.cases)));\n recordPatch({ op: \"replace\", path });\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} caseName\n */\nexport function mutateRemoveSwitchCase(tab: Tab, path: JxPath, caseName: string) {\n const node = getNodeAtPath(tab.doc.document, path);\n if (node.cases) {\n const before = cloneValue(node.cases);\n delete node.cases[caseName];\n recordDocOp(setKeyPair(path, \"cases\", before, cloneValue(node.cases)));\n recordPatch({ op: \"replace\", path });\n }\n}\n\n/**\n * @param {Tab} tab\n * @param {JxPath} path\n * @param {string} oldName\n * @param {string} newName\n */\nexport function mutateRenameSwitchCase(tab: Tab, path: JxPath, oldName: string, newName: string) {\n const node = getNodeAtPath(tab.doc.document, path);\n if (!node.cases || !node.cases[oldName]) {\n return;\n }\n const before = cloneValue(node.cases);\n node.cases[newName] = node.cases[oldName];\n delete node.cases[oldName];\n recordDocOp(setKeyPair(path, \"cases\", before, cloneValue(node.cases)));\n recordPatch({ op: \"replace\", path });\n}\n\n// ─── Frontmatter ─────────────────────────────────────────────────────────────\n\n/**\n * Update a frontmatter field on a tab. Does not push document history.\n *\n * @param {Tab} tab\n * @param {string} field\n * @param {JsonValue} value\n */\nexport function mutateUpdateFrontmatter(tab: Tab, field: string, value?: JsonValue) {\n const fm = tab.doc.content.frontmatter;\n const before = Object.hasOwn(fm, field) ? cloneValue(fm[field]) : undefined;\n const deletes = value === undefined || value === null || value === \"\";\n if (deletes) {\n delete fm[field];\n } else {\n fm[field] = value;\n }\n const after = deletes ? undefined : cloneValue(value);\n recordFmOp({ after, before, field });\n tab.doc.dirty = true;\n}\n\n/**\n * Restore a frontmatter key to a recorded history state: `undefined` means the key was absent.\n * Unlike `mutateUpdateFrontmatter`, values like `\"\"`/`false`/`null` are written verbatim (source\n * round-trips can put them there) and no fm op is recorded — history replay must not re-record.\n */\nfunction applyFmState(tab: Tab, field: string, value: unknown) {\n if (value === undefined) {\n delete tab.doc.content.frontmatter[field];\n } else {\n tab.doc.content.frontmatter[field] = value;\n }\n}\n",
|
|
21
|
+
"/**\n * Active-registry.ts — the one registry this window's chrome renders from.\n *\n * `registry.ts` deliberately has no module-level singleton: the context a registry closes over is\n * one window's, the CI checks build their own, and every test wants a registry it can state\n * exactly. That is right, and it leaves one gap — the Command Bar and the Palette are mounted by\n * `studio.ts` BEFORE the bootstrap composes the registry (`toolbar.mount` runs at the top of the\n * file, `createCommandRegistry` near the bottom), so neither surface can be handed one at mount.\n *\n * This is the seam, in the same idiom as `platform.ts`'s `registerPlatform` / `getPlatform` and\n * `canvas/preview-navigate.ts`'s handler slot: the bootstrap sets it once, and the surfaces ask.\n *\n * The holder is a `shallowRef`, which is the load-bearing part. A surface that reads\n * {@link activeRegistry} inside its render effect TRACKS the holder, so the effect re-runs the\n * moment the bootstrap sets it — which is what lets the Command Bar paint an honest empty band at\n * mount and fill in without anyone remembering to call `render()` afterwards.\n */\n\nimport { shallowRef } from \"../reactivity\";\nimport type { CommandRegistry } from \"./registry\";\n\nconst _registry = shallowRef<CommandRegistry | null>(null);\n\n/**\n * Publish this window's registry. Called once by the bootstrap, and by tests with their own.\n *\n * Passing `null` clears it, which is what an unmounting test does so the next one starts cold.\n */\nexport function setActiveRegistry(registry: CommandRegistry | null): void {\n _registry.value = registry;\n}\n\n/**\n * This window's registry, or `null` before the bootstrap has composed it.\n *\n * Returning `null` rather than throwing is deliberate: the surfaces render a skeleton in that\n * window, and a chrome that crashes because it painted one frame early would be a worse bug than\n * the one this seam exists to solve.\n */\nexport function activeRegistry(): CommandRegistry | null {\n return _registry.value;\n}\n",
|
|
22
|
+
"/// <reference lib=\"dom\" />\n/**\n * The overlay layers — the only sanctioned way to open a popover, modal, dialog or toast in Studio.\n *\n * Everything renders into one of the four fixed hosts declared in index.html (#layer-popover,\n * #layer-modal, #layer-dialog, #layer-toast), bound once at boot by initLayers(). Native browser\n * dialogs (`prompt`, `confirm`, `alert`) are not permitted anywhere in Studio — use\n * `showPromptDialog`, `showConfirmDialog`, or `showSaveDiscardDialog`. See studio-ui-guidelines.md\n * §8.7.\n *\n * The toast host is the fourth layer (plan §3.2 ④, §7.1). It is a rendering of\n * `services/notify.ts`'s `toasts` array and owns exactly two things that array does not: the timer\n * that retires a resting toast, and the transition account {@link overlayIdleBlockers} publishes.\n */\nimport { html, render as litRender, nothing } from \"lit-html\";\nimport { ref } from \"lit-html/directives/ref.js\";\nimport { repeat } from \"lit-html/directives/repeat.js\";\nimport { overlayRegion, REGION_ATTR } from \"./regions\";\nimport { dismiss, toasts } from \"../services/notify\";\nimport { activeRegistry } from \"../commands/active-registry\";\nimport { effect, effectScope } from \"../reactivity\";\nimport type { Notification, Severity } from \"../services/notify\";\nimport type { EffectScope } from \"@vue/reactivity\";\nimport type { TemplateResult } from \"lit-html\";\n\n/** The four fixed layer hosts, by name. Also the `kind` half of every overlay region id. */\nexport type LayerKind = \"popover\" | \"modal\" | \"dialog\" | \"toast\";\n\nlet _popoverLayer: HTMLElement;\nlet _modalLayer: HTMLElement;\nlet _dialogLayer: HTMLElement;\nlet _toastLayer: HTMLElement;\n\n/** The host a layer kind renders into, falling back to `<body>` before `initLayers()` has run. */\nfunction layerHost(kind: LayerKind): HTMLElement {\n const host =\n kind === \"popover\"\n ? _popoverLayer\n : kind === \"modal\"\n ? _modalLayer\n : kind === \"toast\"\n ? _toastLayer\n : _dialogLayer;\n return host || document.body;\n}\n\nexport function initLayers() {\n _popoverLayer = document.querySelector(\"#layer-popover\") as HTMLElement;\n _modalLayer = document.querySelector(\"#layer-modal\") as HTMLElement;\n _dialogLayer = document.querySelector(\"#layer-dialog\") as HTMLElement;\n _toastLayer = document.querySelector(\"#layer-toast\") as HTMLElement;\n mountToastHost();\n}\n\n/** Anything in the modal/dialog layers that paints a viewport-wide underlay over the app. */\nconst UNDERLAID = \"sp-dialog-wrapper[open], sp-underlay[open]\";\n\n/**\n * Whether a surface with an underlay is up — a dialog from {@link showDialog}, or an\n * {@link openModal} body that renders its own `sp-underlay`.\n *\n * Read by the app-level keyboard handlers, which must stand down while one is: an underlay swallows\n * every pointer event across the viewport, so leaving shortcuts live means <kbd>Delete</kbd>,\n * <kbd>Enter</kbd>, ⌘S and ⌘W keep hitting the document BEHIND a surface the author cannot even\n * click on. Derived from the live DOM rather than a registration counter, so the rule is simply\n * \"whatever blocks the mouse blocks the keyboard\" — no bookkeeping for a new modal to forget.\n */\nexport function isModalOpen(): boolean {\n return Boolean(_dialogLayer?.querySelector(UNDERLAID) || _modalLayer?.querySelector(UNDERLAID));\n}\n\n/** Focusable candidates in an overlay body, in the order a keyboard user would reach them. */\nconst BODY_FOCUSABLE =\n 'a[href], input, textarea, select, button, sp-textfield, sp-button, sp-action-button, sp-picker, sp-checkbox, sp-menu-item, [tabindex]:not([tabindex=\"-1\"])';\n\n/** The body's focusables that can actually take the caret right now. */\nfunction focusablesIn(slot: HTMLElement): HTMLElement[] {\n return [...slot.querySelectorAll<HTMLElement>(BODY_FOCUSABLE)].filter(\n (el) => !el.hasAttribute(\"disabled\") && el.getAttribute(\"aria-hidden\") !== \"true\",\n );\n}\n\n/**\n * Hand the keyboard to a freshly opened overlay.\n *\n * `sp-dialog-wrapper` only throws focus into itself when an `<sp-overlay>` drives it. Opened\n * directly through its `open` attribute — Studio's pattern, because this layer stack owns stacking\n * rather than Spectrum's overlay system — NOTHING does, so focus stays on whatever sits behind the\n * underlay: the surface is unreachable by keyboard, <kbd>Escape</kbd> never reaches it, and\n * keystrokes keep landing in the app the underlay is blocking.\n *\n * Prefers the first focusable in the BODY (a bespoke form's opening field), else the wrapper's own\n * cancel button — DialogWrapper renders cancel → secondary → confirm, so the first shadow button is\n * the least destructive landing spot — else the slot itself, which carries `tabindex=\"-1\"` so a\n * body made only of static content (a progress spinner) still receives <kbd>Escape</kbd>. A body\n * that already claimed focus ({@link showPromptDialog}'s field) is left alone.\n */\nfunction focusOverlay(slot: HTMLElement): void {\n // Deferred a frame: the wrapper's buttons live in a shadow root Spectrum renders asynchronously.\n requestAnimationFrame(() => {\n if (!slot.isConnected || slot.contains(document.activeElement)) {\n return;\n }\n const wrapper = slot.querySelector(\"sp-dialog-wrapper\");\n const target =\n focusablesIn(slot)[0] ?? wrapper?.shadowRoot?.querySelector<HTMLElement>(\"sp-button\") ?? slot;\n target.focus();\n });\n}\n\n/**\n * Keep <kbd>Tab</kbd> inside the overlay: cycle through the body's focusables, wrapping at both\n * ends. With no focusable body at all the caret stays on the slot — tabbing out of a surface the\n * mouse cannot leave either would strand the keyboard behind the underlay.\n */\nfunction trapTab(slot: HTMLElement, e: KeyboardEvent): void {\n e.preventDefault();\n const items = focusablesIn(slot);\n if (items.length === 0) {\n return;\n }\n const at = items.indexOf(document.activeElement as HTMLElement);\n const next = e.shiftKey\n ? items[at <= 0 ? items.length - 1 : at - 1]\n : items[at === -1 || at === items.length - 1 ? 0 : at + 1];\n next?.focus();\n}\n\n/** How an overlay slot behaves once it is up. */\ninterface OverlaySlotOptions {\n /** Layer host the slot is appended to. */\n layer: HTMLElement;\n /** Which layer this is, for the slot's region id. */\n kind: LayerKind;\n /**\n * Optional instance name, making the slot `overlay.<instance>:<id>` instead of the bare\n * `overlay.<instance>`. A surface that can be open alongside another one of its kind wants this.\n */\n regionId?: string | undefined;\n /** Handle <kbd>Escape</kbd> pressed inside the slot; the callback owns `preventDefault`. */\n onEscape?: (e: KeyboardEvent, slot: HTMLElement) => void;\n /** Cycle <kbd>Tab</kbd> within the slot instead of letting it walk into the app behind. */\n trapFocus?: boolean;\n}\n\n/**\n * Open a slot in a layer with the full overlay keyboard contract: focus in on open, focus back to\n * the opener on close, centralised <kbd>Escape</kbd>, and (optionally) a Tab trap.\n *\n * Both {@link showDialog} and {@link openModal} are thin wrappers over this — one contract, one\n * implementation, so no surface can ship without the machinery.\n */\nfunction openOverlaySlot(opts: OverlaySlotOptions): { slot: HTMLElement; release: () => void } {\n const slot = document.createElement(\"div\");\n slot.style.pointerEvents = \"auto\";\n slot.setAttribute(REGION_ATTR, overlayRegion(opts.kind, opts.regionId));\n // Focusable as a last resort, so a body with no controls still owns the keyboard (focusOverlay).\n slot.tabIndex = -1;\n // The slot is a zero-height wrapper around fixed-position bodies, so its own focus ring would\n // Paint as a stray line across the top of the layer.\n slot.style.outline = \"none\";\n opts.layer.append(slot);\n // Whoever held focus before the overlay took it, so it can be handed back (a dialog opened from a\n // Toolbar button returns the caret to that button, not to <body>).\n const restoreTo = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n opts.onEscape?.(e, slot);\n return;\n }\n if (e.key === \"Tab\" && opts.trapFocus) {\n trapTab(slot, e);\n }\n };\n slot.addEventListener(\"keydown\", onKeydown);\n return {\n release() {\n slot.removeEventListener(\"keydown\", onKeydown);\n litRender(nothing, slot);\n slot.remove();\n if (restoreTo?.isConnected) {\n restoreTo.focus();\n }\n },\n slot,\n };\n}\n\n/**\n * Show an ephemeral dialog. Returns a Promise that resolves when the dialog is dismissed.\n *\n * Takes the keyboard on open ({@link focusOverlay}) and hands it back to the previously focused\n * element on close. <kbd>Escape</kbd> dismisses by firing the wrapper's `close` event, so each\n * helper's own `@close` binding decides what \"dismissed\" resolves to; a bespoke body with no\n * `sp-dialog-wrapper` owns its own keys.\n *\n * @template T\n * @param {(done: (value: T) => void) => import(\"lit-html\").TemplateResult} templateFn\n * @returns {Promise<T>}\n */\nexport function showDialog<T>(\n templateFn: (done: (value: T) => void) => TemplateResult,\n opts: { region?: string; label?: string } = {},\n): Promise<T> {\n return new Promise((resolve) => {\n const { release, slot } = openOverlaySlot({\n kind: \"dialog\",\n // `layerHost`, not the raw binding: it is the one that falls back to `<body>`, and reading\n // The binding directly threw before `initLayers()` had run — which is any test that stands up\n // A shell without the four layer hosts, and the boot window before layers are bound.\n layer: layerHost(\"dialog\"),\n regionId: opts.region,\n onEscape(e, host) {\n const wrapper = host.querySelector(\"sp-dialog-wrapper\");\n if (!wrapper) {\n return;\n }\n // Stop it ALSO reaching the app behind (which clears the canvas selection on Escape).\n e.preventDefault();\n e.stopPropagation();\n wrapper.dispatchEvent(new Event(\"close\", { bubbles: true }));\n },\n // No Tab trap: the wrapper's action buttons live in a shadow root a light-DOM cycle cannot\n // Enumerate, so trapping here would strand the caret on the body and never reach Cancel.\n });\n /*\n * The slot IS the dialog, so it says so.\n *\n * `aria-modal` is also the answer to the comment above: it tells assistive technology that\n * everything outside this element is inert, which constrains a screen reader's virtual cursor —\n * the thing a Tab trap cannot reach anyway, since the virtual cursor does not use Tab. So the\n * caret still escapes into the shadow-root buttons, as it must, and a reader is no longer free\n * to wander the page behind a modal that is covering it.\n */\n slot.setAttribute(\"role\", \"dialog\");\n slot.setAttribute(\"aria-modal\", \"true\");\n let resolved = false;\n const done = (value: T) => {\n if (resolved) {\n return;\n }\n resolved = true;\n release();\n resolve(value);\n };\n litRender(templateFn(done), slot);\n /*\n * The name, after render, because the usual source of one is the wrapper's own `headline` —\n * which does not exist until the template has run. An explicit `label` wins; a dialog with\n * neither is nameless, which is a defect in the caller rather than something to invent here.\n */\n const headline =\n opts.label ?? slot.querySelector(\"sp-dialog-wrapper\")?.getAttribute(\"headline\") ?? null;\n if (headline !== null && headline !== \"\") {\n slot.setAttribute(\"aria-label\", headline);\n }\n focusOverlay(slot);\n });\n}\n\n/**\n * Show a confirm/cancel dialog. Returns true if confirmed, false otherwise.\n *\n * @param {string} headline\n * @param {string | import(\"lit-html\").TemplateResult} message\n * @param {{ confirmLabel?: string; cancelLabel?: string; destructive?: boolean }} [opts]\n * @returns {Promise<boolean>}\n */\nexport function showConfirmDialog(\n headline: string,\n message: string | TemplateResult,\n opts: {\n confirmLabel?: string;\n cancelLabel?: string;\n destructive?: boolean;\n } = {},\n) {\n const { confirmLabel = \"Confirm\", cancelLabel = \"Cancel\", destructive = false } = opts;\n // Explicit, because `done(true)` gives the generic nothing to infer from and it landed on\n // `unknown` — which every caller happened to survive by using the answer in a truthy position.\n return showDialog<boolean>(\n (done) => html`\n <sp-dialog-wrapper\n open\n underlay\n headline=${headline}\n confirm-label=${confirmLabel}\n cancel-label=${cancelLabel}\n size=\"s\"\n @confirm=${() => done(true)}\n @cancel=${() => done(false)}\n @close=${() => done(false)}\n class=${destructive ? \"dialog-destructive\" : \"\"}\n >\n <p>${message}</p>\n </sp-dialog-wrapper>\n `,\n );\n}\n\n/**\n * Show a three-way Save / Discard / Cancel dialog. Resolves \"save\", \"discard\", or \"cancel\"\n * (dismiss/close counts as cancel).\n *\n * @param {string} headline\n * @param {string | import(\"lit-html\").TemplateResult} message\n * @param {{ saveLabel?: string; discardLabel?: string; cancelLabel?: string }} [opts]\n * @returns {Promise<\"save\" | \"discard\" | \"cancel\">}\n */\nexport function showSaveDiscardDialog(\n headline: string,\n message: string | TemplateResult,\n opts: {\n saveLabel?: string;\n discardLabel?: string;\n cancelLabel?: string;\n } = {},\n): Promise<\"save\" | \"discard\" | \"cancel\"> {\n const { saveLabel = \"Save\", discardLabel = \"Discard\", cancelLabel = \"Cancel\" } = opts;\n return showDialog<\"save\" | \"discard\" | \"cancel\">(\n (done) => html`\n <sp-dialog-wrapper\n open\n underlay\n headline=${headline}\n confirm-label=${saveLabel}\n secondary-label=${discardLabel}\n cancel-label=${cancelLabel}\n size=\"s\"\n @confirm=${() => done(\"save\")}\n @secondary=${() => done(\"discard\")}\n @cancel=${() => done(\"cancel\")}\n @close=${() => done(\"cancel\")}\n >\n <p>${message}</p>\n </sp-dialog-wrapper>\n `,\n );\n}\n\n/** Options accepted by {@link showPromptDialog}. */\nexport interface PromptDialogOptions {\n /** Label on the confirming button. */\n confirmLabel?: string;\n /** Label on the dismissing button. */\n cancelLabel?: string;\n /** Explanatory copy rendered above the text field. */\n message?: string | TemplateResult;\n /** Placeholder shown while the field is empty. */\n placeholder?: string;\n /** How much of the pre-filled value to select once the field takes focus. */\n select?: \"all\" | \"stem\" | \"none\";\n /**\n * Validate the raw field value. Return an empty string when valid, or a message to show as\n * negative help text (which also blocks confirmation). Defaults to \"must not be blank\".\n */\n validate?: (value: string) => string;\n /** Pre-filled value. */\n value?: string;\n}\n\n/**\n * Show a single-field text-entry dialog — the Spectrum replacement for `window.prompt()`.\n *\n * Resolves the trimmed value, or `null` when cancelled/dismissed. Confirming with an invalid value\n * keeps the dialog open and surfaces the validation message as negative help text.\n *\n * @param {string} headline\n * @param {PromptDialogOptions} [opts]\n * @returns {Promise<string | null>}\n */\nexport function showPromptDialog(\n headline: string,\n opts: PromptDialogOptions = {},\n): Promise<string | null> {\n const {\n cancelLabel = \"Cancel\",\n confirmLabel = \"OK\",\n message,\n placeholder = \"\",\n select = \"all\",\n validate,\n value: initialValue = \"\",\n } = opts;\n\n const check = (candidate: string) =>\n validate ? validate(candidate) : candidate.trim() ? \"\" : \"Enter a value.\";\n\n let value = initialValue;\n let error = \"\";\n let wrapperEl: HTMLElement | null = null;\n let focusRequested = false;\n\n return showDialog<string | null>((done) => {\n function rerender() {\n // Resolved lazily: lit commits element refs before inserting the fragment, so the host is\n // Only reachable once the first render has landed.\n const host = wrapperEl?.parentElement;\n if (host) {\n litRender(buildTpl(), host);\n }\n }\n\n function confirm() {\n error = check(value);\n if (error) {\n rerender();\n return;\n }\n done(value.trim());\n }\n\n function onInput(e: Event) {\n value = (e.target as HTMLInputElement).value || \"\";\n const next = check(value);\n if (next !== error) {\n error = next;\n rerender();\n }\n }\n\n function onKeydown(e: KeyboardEvent) {\n if (e.key === \"Enter\") {\n confirm();\n }\n }\n\n /** Capture the dialog element so validation errors can re-render in place. */\n function onWrapperRef(el?: Element) {\n if (el) {\n wrapperEl = el as HTMLElement;\n }\n }\n\n /** Focus (and optionally select) the field once, on first render only. */\n function onFieldRef(el?: Element) {\n if (!el || focusRequested) {\n return;\n }\n focusRequested = true;\n const field = el as HTMLElement;\n requestAnimationFrame(() => {\n field.focus();\n const input = field.shadowRoot?.querySelector(\"input\");\n if (!input || select === \"none\") {\n return;\n }\n if (select === \"stem\") {\n const dot = input.value.lastIndexOf(\".\");\n input.setSelectionRange(0, dot > 0 ? dot : input.value.length);\n return;\n }\n input.select();\n });\n }\n\n function buildTpl() {\n return html`\n <sp-dialog-wrapper\n open\n underlay\n headline=${headline}\n confirm-label=${confirmLabel}\n cancel-label=${cancelLabel}\n size=\"s\"\n @confirm=${confirm}\n @cancel=${() => done(null)}\n @close=${() => done(null)}\n ${ref(onWrapperRef)}\n >\n ${\n // Spectrum resets <p> margins to 0, so without this the copy sits flush on the field.\n message ? html`<p style=\"margin:0 0 8px\">${message}</p>` : nothing\n }\n <sp-textfield\n style=\"width:100%\"\n placeholder=${placeholder}\n value=${value}\n ?invalid=${Boolean(error)}\n @input=${onInput}\n @keydown=${onKeydown}\n ${ref(onFieldRef)}\n >\n ${\n error\n ? html`<sp-help-text slot=\"negative-help-text\">${error}</sp-help-text>`\n : nothing\n }\n </sp-textfield>\n </sp-dialog-wrapper>\n `;\n }\n\n return buildTpl();\n });\n}\n\n/** Options accepted by {@link openModal}. */\nexport interface ModalOptions {\n /**\n * Accessible name for the modal, applied as `aria-label` on the wrapper. Required: it is the only\n * name assistive tech gets, and a per-modal opt-in would be forgotten.\n */\n label: string;\n /**\n * Whether <kbd>Escape</kbd> dismisses. `false` for modals that must not vanish mid-flight (a\n * running operation, a step that has to be confirmed).\n */\n dismissible?: boolean;\n /**\n * What <kbd>Escape</kbd> runs. Defaults to the handle's own `close()`; pass the call site's close\n * function when it keeps bookkeeping of its own (a module-level handle to clear).\n */\n onDismiss?: () => void;\n /**\n * Instance name for this modal's region — `overlay.dialog:settings`.\n *\n * Optional because one modal at a time is the norm and `overlay.dialog` addresses it. A modal\n * that can be open beside another, or that a command needs to move focus back into by name,\n * declares one.\n */\n region?: string;\n}\n\n/**\n * Open a persistent modal. Returns a handle with update() and close() methods.\n *\n * The wrapper — not the body — owns the modal contract, so no surface can ship without it: the slot\n * is the `role=\"dialog\"` element, carries `aria-modal` and the caller's label, takes the keyboard\n * on open, cycles <kbd>Tab</kbd> within itself, dismisses on <kbd>Escape</kbd>, and hands focus\n * back to the opener on close. Bodies render content only.\n *\n * @param {import(\"lit-html\").TemplateResult} template\n * @param {ModalOptions} opts\n */\nexport function openModal(template: TemplateResult, opts: ModalOptions) {\n const { release, slot } = openOverlaySlot({\n kind: \"modal\",\n layer: layerHost(\"modal\"),\n onEscape(e) {\n if (opts.dismissible === false) {\n return;\n }\n // Stop it ALSO reaching the app behind (which clears the canvas selection on Escape).\n e.preventDefault();\n e.stopPropagation();\n (opts.onDismiss ?? handle.close)();\n },\n regionId: opts.region,\n trapFocus: true,\n });\n slot.setAttribute(\"role\", \"dialog\");\n slot.setAttribute(\"aria-modal\", \"true\");\n slot.setAttribute(\"aria-label\", opts.label);\n\n const handle = {\n close() {\n release();\n },\n host: slot,\n /** @param {import(\"lit-html\").TemplateResult} tpl */\n update(tpl: TemplateResult) {\n litRender(tpl, slot);\n },\n };\n litRender(template, slot);\n focusOverlay(slot);\n return handle;\n}\n\n/**\n * Render a popover into a layer.\n *\n * @param {import(\"lit-html\").TemplateResult} template\n * @param {{\n * dismissOnOutsideClick?: boolean;\n * onDismiss?: () => void;\n * layer?: LayerKind;\n * region?: string;\n * }} [opts]\n */\nexport function renderPopover(\n template: TemplateResult,\n opts: {\n dismissOnOutsideClick?: boolean;\n onDismiss?: () => void;\n layer?: LayerKind;\n /** Instance name for this popover's region — `overlay.menu:blockbar`. */\n region?: string;\n } = {},\n) {\n const kind = opts.layer ?? \"popover\";\n const slot = document.createElement(\"div\");\n slot.style.pointerEvents = \"auto\";\n slot.setAttribute(REGION_ATTR, overlayRegion(kind, opts.region));\n layerHost(kind).append(slot);\n litRender(template, slot);\n\n let outsideClickHandler: ((e: MouseEvent) => void) | null = null;\n if (opts.dismissOnOutsideClick !== false) {\n outsideClickHandler = (e: MouseEvent) => {\n if (!slot.contains(e.target as Node)) {\n handle.dismiss();\n opts.onDismiss?.();\n }\n };\n requestAnimationFrame(() => {\n if (outsideClickHandler) {\n document.addEventListener(\"mousedown\", outsideClickHandler, true);\n }\n });\n }\n\n const handle = {\n dismiss() {\n if (outsideClickHandler) {\n document.removeEventListener(\"mousedown\", outsideClickHandler, true);\n /* Disarm the PENDING arming too, not just the armed listener. The `addEventListener` above\n is deferred a frame so the click that opened this popover cannot immediately close it —\n so a popover dismissed within that frame (open the same menu twice in one frame, which a\n double-click does) would otherwise be armed AFTER its own death: a document-wide capture\n listener on a detached slot, never removed, that answers the next mousedown by calling\n its owner's `onDismiss`. Owners null their handle field there, so the corpse's callback\n cleared the pointer to the LIVE popover and stranded it on screen, un-dismissable. The\n `if` in the rAF was always written for this; nothing had ever nulled the variable. */\n outsideClickHandler = null;\n }\n litRender(nothing, slot);\n slot.remove();\n },\n host: slot,\n /** @param {import(\"lit-html\").TemplateResult} tpl */\n update(tpl: TemplateResult) {\n litRender(tpl, slot);\n },\n };\n return handle;\n}\n\nconst _namedSlots = new Map<string, HTMLElement>();\n\n/**\n * Get or create a named slot in a layer. Useful for persistent popovers like the zoom indicator.\n *\n * The `${layer}:${id}` key this already builds IS the slot's region: it is stamped as\n * `overlay.<instance>:<id>`, so naming a slot names its region and every persistent overlay becomes\n * addressable for free. That also settles a latent ambiguity — two open popovers used to be\n * indistinguishable to anything matching on `sp-popover[open]`, and each now answers to its own\n * id.\n *\n * @param {LayerKind} layer\n * @param {string} id\n * @returns {HTMLElement}\n */\n/**\n * The layer a transient popover must use to appear ABOVE the surface that opened it.\n *\n * The four layer hosts are sibling stacking contexts (`index.html`): popover 1000, modal 2000,\n * dialog 3000, toast 4000. So a popover anchored to a control INSIDE a modal — the media picker's\n * Browse button in Search appearance, say — renders into a layer that paints entirely beneath the\n * modal body, and the author clicks Browse and sees nothing happen. Putting it in the modal's own\n * layer makes it a later sibling of the modal body instead, which is exactly the relationship it\n * should have: above the surface that opened it, below any dialog.\n *\n * @param {Element | null} anchor The control the popover is anchored to.\n * @returns {LayerKind}\n */\nexport function popoverLayerFor(anchor: Element | null): LayerKind {\n if (anchor?.closest(\"#layer-dialog\")) {\n return \"dialog\";\n }\n return anchor?.closest(\"#layer-modal\") ? \"modal\" : \"popover\";\n}\n\nexport function getLayerSlot(layer: LayerKind, id: string) {\n const key = `${layer}:${id}`;\n let slot = _namedSlots.get(key);\n if (slot && slot.parentElement) {\n return slot;\n }\n\n slot = document.createElement(\"div\");\n slot.style.pointerEvents = \"auto\";\n slot.setAttribute(REGION_ATTR, overlayRegion(layer, id));\n layerHost(layer).append(slot);\n _namedSlots.set(key, slot);\n return slot;\n}\n\n/**\n * Clear a named layer slot (remove from DOM and map).\n *\n * @param {LayerKind} layer\n * @param {string} id\n */\nexport function clearLayerSlot(layer: LayerKind, id: string) {\n const key = `${layer}:${id}`;\n const slot = _namedSlots.get(key);\n if (slot) {\n litRender(nothing, slot);\n slot.remove();\n _namedSlots.delete(key);\n }\n}\n\n// ─── The toast host — the fourth layer ───────────────────────────────────────\n\n/**\n * How long a toast is settling into place, in ms.\n *\n * Published to {@link overlayIdleBlockers} rather than kept private, because \"the shell has stopped\n * moving\" is a question `services/idle.ts` answers on behalf of the screenshot runner and the\n * verify skill, and a toast sliding in is exactly the half-painted frame a capture must not catch.\n */\nexport const TOAST_ENTER_MS = 180;\n\n/** The severity glyphs. One character each: the toast's job is a line of text, not an illustration. */\nconst TOAST_ICON: Readonly<Record<Severity, string>> = {\n error: \"✕\",\n info: \"ℹ\",\n success: \"✓\",\n warn: \"!\",\n};\n\nlet _toastScope: EffectScope | null = null;\n/** Toast id → its retirement timer, so a re-render never schedules a second one. */\nconst _toastTimers = new Map<string, ReturnType<typeof setTimeout>>();\n/** Toast id → when it started settling in. Cleared by its own timer. */\nconst _toastEntering = new Set<string>();\n\n/**\n * Whether the reader has asked for less movement.\n *\n * Read per call rather than cached: §13.3 clause 6 says the app must HONOUR this rather than have\n * the runner inject a freeze stylesheet, which means the answer has to be able to change.\n */\nfunction reducedMotion(): boolean {\n return globalThis.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches === true;\n}\n\n/**\n * **One of the three listed exceptions to §13.3 clause 6** — behaviour that differs under\n * `?automation=1` beyond installing the hook, pinning the clock and selecting a profile. The other\n * Two are both refusals to touch the project on disk: `packages/ensure-deps.ts` declines to run\n * `bun install`, and `packages/jxsuite-update.ts` declines to prompt for a dependency update. This\n * One is the only exception that changes what a picture SHOWS rather than what it avoids doing.\n *\n * A toast is the single surface in the app whose lifetime is a TIMER rather than a state. Every\n * other surface a shot can photograph is there because the app is in a state, and it stays there\n * until a command changes it; a toast retires itself between the step that raised it and the frame\n * that captures it, so a shot of one is a race the manifest has no way to express. Holding it open\n * is the smaller lie: the picture then shows a toast that a human reader would also have seen, for\n * as long as they cared to look, instead of showing the toast that happened to still be there.\n *\n * The gate is re-derived from `location.search` rather than imported from `services/automation.ts`\n * deliberately: §13.3 requires the scripting surface to be absent from the desktop and cloud\n * bundles (`check-bundle-budget.ts`'s next assertion), and importing it from a module every layer\n * pulls in would ship it everywhere. One line of duplication, on purpose.\n */\nexport function toastsAreHeld(): boolean {\n try {\n return new URLSearchParams(globalThis.location?.search ?? \"\").get(\"automation\") === \"1\";\n } catch {\n // Intentionally ignored: no location (a bare test realm) means no automation.\n return false;\n }\n}\n\n/**\n * What is still moving in the overlay layers, as `services/idle.ts` phrases it.\n *\n * Empty when every toast has settled — a RESTING toast is not a blocker, which is the property that\n * lets {@link toastsAreHeld} hold one open forever without `probeIdle()` waiting forever with it.\n */\nexport function overlayIdleBlockers(): readonly string[] {\n return [..._toastEntering].map((id) => `overlay: toast ${id} settling in`);\n}\n\n/** Take a toast away, cancelling any timer it still owns. */\nfunction retireToast(id: string): void {\n const timer = _toastTimers.get(id);\n if (timer !== undefined) {\n clearTimeout(timer);\n _toastTimers.delete(id);\n }\n _toastEntering.delete(id);\n dismiss(id);\n}\n\n/**\n * Give a newly-arrived toast its timers: the settle window the idle account reads, and (unless\n * held) the rest period after which it retires itself.\n */\nfunction scheduleToast(record: Notification): void {\n if (_toastTimers.has(record.id) || _toastEntering.has(record.id)) {\n return;\n }\n const settle = reducedMotion() ? 0 : TOAST_ENTER_MS;\n if (settle > 0) {\n _toastEntering.add(record.id);\n setTimeout(() => _toastEntering.delete(record.id), settle);\n }\n const rest = record.timeoutMs ?? 0;\n if (rest <= 0 || toastsAreHeld()) {\n return;\n }\n _toastTimers.set(\n record.id,\n setTimeout(() => retireToast(record.id), rest),\n );\n}\n\n/** The recovery button, or `nothing` when the record named no command or the command is hidden. */\nfunction toastActionTpl(record: Notification) {\n const registry = record.action === undefined ? null : activeRegistry();\n const id = record.action;\n if (!registry || id === undefined || !registry.get(id) || !registry.isVisible(id)) {\n return nothing;\n }\n const command = registry.get(id)!;\n const reason = registry.disabledReason(id);\n return html`\n <button\n class=\"toast-action\"\n ?disabled=${reason !== undefined}\n title=${reason === undefined ? command.title : `${command.title} — requires ${reason}`}\n @click=${() => {\n retireToast(record.id);\n void registry.run(id, record.actionArgs);\n }}\n >\n ${command.title}\n </button>\n `;\n}\n\n/** One toast. `role=\"status\"` lives on the HOST, so a stack of them is announced as one region. */\nfunction toastTpl(record: Notification) {\n return html`\n <div class=\"toast toast--${record.severity}\">\n <span class=\"toast-icon\" aria-hidden=\"true\">${TOAST_ICON[record.severity]}</span>\n <span class=\"toast-message\">${record.message}</span>\n ${toastActionTpl(record)}\n <button\n class=\"toast-dismiss\"\n title=\"Dismiss\"\n aria-label=\"Dismiss notification\"\n @click=${() => retireToast(record.id)}\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n </div>\n `;\n}\n\n/** The whole stack, newest at the bottom — the reading order of a log, not of a menu. */\nexport function toastStackTemplate() {\n return html`\n <div class=\"toast-stack\">\n ${repeat(\n toasts,\n (record) => record.id,\n (record) => toastTpl(record),\n )}\n </div>\n `;\n}\n\n/**\n * Subscribe the toast layer to `notify`'s store.\n *\n * Called by {@link initLayers}, so no bootstrap has to remember it, and idempotent so a second call\n * replaces the effect rather than stacking a second renderer on the same host.\n */\nexport function mountToastHost(): void {\n unmountToastHost();\n if (!_toastLayer) {\n return;\n }\n _toastScope = effectScope();\n _toastScope.run(() => {\n effect(() => {\n // Tracked: the array itself (arrivals and retirements) and the registry holder, so a toast\n // Raised before the bootstrap composed the registry grows its Retry button when it lands.\n void toasts.length;\n void activeRegistry();\n for (const record of toasts) {\n scheduleToast(record);\n }\n litRender(toastStackTemplate(), _toastLayer);\n });\n });\n}\n\n/** Release the effect and every pending timer. Tests and a window teardown both need this. */\nexport function unmountToastHost(): void {\n _toastScope?.stop();\n _toastScope = null;\n for (const timer of _toastTimers.values()) {\n clearTimeout(timer);\n }\n _toastTimers.clear();\n _toastEntering.clear();\n if (_toastLayer) {\n litRender(nothing, _toastLayer);\n }\n}\n",
|
|
23
|
+
"/**\n * Reactive per-tab collab state, kept OUTSIDE the Tab type: UI reads it through collabState(tab),\n * and non-collab builds never touch it. The path registry answers \"is this file co-edited?\" for the\n * fs-sync/reload guards without importing the session machinery.\n */\n\nimport { reactive, toRaw } from \"../reactivity\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { CollabAwarenessState } from \"@jxsuite/collab/awareness-types\";\n\n/**\n * What co-editing is doing for this tab.\n *\n * `\"detached\"` used to mean three different things at once and say none of them: this build has no\n * collaboration at all, this project has collaboration but this tab is solo, and the attach was\n * tried and it FAILED. §7.4: a freeze is currently indistinguishable from a bug, and so was a\n * broken connection. `\"unavailable\"` and `\"failed\"` split the third and first cases out, so the\n * chip can say which one it is.\n */\nexport type CollabTabStatus =\n | \"unavailable\"\n | \"detached\"\n | \"connecting\"\n | \"synced\"\n | \"offline\"\n | \"failed\";\n\nexport interface PeerPresence {\n clientId: number;\n state: CollabAwarenessState;\n}\n\nexport interface TabCollabState {\n status: CollabTabStatus;\n /** True once a session is attached and past its initial sync. */\n active: boolean;\n readOnly: boolean;\n /** Other clients' awareness states (this project connection, all docs). */\n peers: PeerPresence[];\n /**\n * True while source holds the canonical lock (someone is co-editing the code view): structural\n * surfaces soft-freeze and the canvas previews the source reconciler's parses.\n *\n * The freeze is real and it is brief, and until now its only rendering was a grey line for three\n * seconds — which is exactly what a bug looks like. It gets an indicator (§7.4).\n */\n sourceCanonical: boolean;\n /**\n * Why the last attach failed, when it did. Empty while `status` is anything but `\"failed\"`.\n *\n * The attach used to swallow its own exception into `status = \"detached\"`, so a dead relay, an\n * expired token and a project that simply is not shared all produced the same silence.\n */\n attachError: string;\n}\n\nconst states = new WeakMap<Tab, TabCollabState>();\nconst attachedPaths = new Map<string, number>();\n\nexport function collabState(tab: Tab): TabCollabState {\n // Key on the raw tab: writers (the collab session, via ensureCollab's raw tab) and readers\n // (toolbar/tab-strip, via reactive `workspace.tabs.get` proxies) must resolve the same entry.\n const key = toRaw(tab as unknown as object) as Tab;\n let state = states.get(key);\n if (!state) {\n state = reactive({\n active: false,\n attachError: \"\",\n peers: [],\n readOnly: false,\n sourceCanonical: false,\n status: \"unavailable\",\n }) as TabCollabState;\n states.set(key, state);\n }\n return state;\n}\n\nexport function isCollabActive(tab: Tab): boolean {\n return states.get(tab)?.active === true;\n}\n\n/** Track which project-relative paths have live sessions (fs-event/reload suppression). */\nexport function registerCollabPath(path: string): void {\n attachedPaths.set(path, (attachedPaths.get(path) ?? 0) + 1);\n}\n\nexport function unregisterCollabPath(path: string): void {\n const count = attachedPaths.get(path) ?? 0;\n if (count <= 1) {\n attachedPaths.delete(path);\n } else {\n attachedPaths.set(path, count - 1);\n }\n}\n\n/** True while some tab co-edits this path — its Y.Doc is ahead of any provider write-back. */\nexport function isCollabPath(path: string): boolean {\n return attachedPaths.has(path.replaceAll(\"\\\\\", \"/\"));\n}\n",
|
|
24
|
+
"/**\n * Context.ts — the record every `when` / `enablement` predicate closes over.\n *\n * One flat-ish record of the facts a command can be gated on (UX-REDESIGN-PLAN §5.2). Predicates\n * are plain closures over this record — the shape `services/gated-registry.ts` already ships for\n * the AI's tools — not a serialisable string DSL. §13 rejects the DSL explicitly: a `\"project.open\n * && editor.kind == 'canvas'\"` grammar needs a tokenizer, a parser and a reactive evaluator to buy\n * serialisability nothing in Studio consumes.\n *\n * This module owns the SHAPE and a pure builder. It deliberately imports nothing from the state\n * modules: the registry takes a `getContext()` thunk, so wiring the live sources (the reactive\n * `shell` record, `workspace`, `activeTab`) is a next-wave change to one function, and every test\n * here builds its own context with {@link makeContext} instead of standing up the app.\n *\n * `capability.*` mirrors the Platform Abstraction Layer so cloud / desktop / dev-server differences\n * stop being `if (platform.x)` scattered across templates and become one `when` clause per\n * command.\n *\n * {@link keyScopeStack} lives here for the same reason: it is a pure function of this record, so\n * the keyboard's \"where am I\" question is answered by the same facts every `when` predicate reads,\n * rather than by a second set of `if (canvasMode === …)` branches in the listener.\n */\n\nimport type { KeyScope } from \"./levels\";\nimport type { JxPath } from \"../state\";\n\n/** PAL-derived capability keys. One `when` clause replaces a scattered `if (platform.x)`. */\nexport const CAPABILITIES = [\n \"gitClone\",\n \"importSite\",\n \"openProjectInNewWindow\",\n \"dataRows\",\n \"windowControls\",\n \"findReferences\",\n] as const;\n\nexport type Capability = (typeof CAPABILITIES)[number];\n\n/** Which shell region owns focus. Drives the keyboard scope stack and F6 region cycling. */\nexport type FocusRegion =\n | \"rail\"\n | \"navigator\"\n | \"pane\"\n | \"inspector\"\n | \"dock\"\n | \"status\"\n | \"palette\";\n\n/** The editor kind the focused pane is rendering. */\nexport type EditorKind =\n | \"canvas\"\n | \"grid\"\n | \"code\"\n | \"diff\"\n | \"library\"\n | \"config\"\n | \"entry\"\n | \"none\";\n\n/** The Canvas view axis — one control, three values (§4.2). */\nexport type CanvasView = \"edit\" | \"design\" | \"preview\";\n\n/*\n * ─── Modes → the two axes ────────────────────────────────────────────────────\n *\n * `canvasMode` is ONE string conflating two orthogonal questions: WHICH EDITOR is open, and (for\n * the Canvas editor only) WHICH VIEW of it. Both maps live here, beside the types they produce and\n * beside `keyScopeStack`, because they are the same fact and there must be exactly one place to add\n * an entry to.\n *\n * They used to be two copies — one in `tabs/tab.ts` driving the pane model, one in\n * `commands/live-context.ts` driving every `when` predicate and the keyboard — each falling through\n * to its own `?? \"canvas\"` default. Neither learned about `settings` when Project Settings became a\n * document, so a JSON configuration object resolved into the CANVAS key scope: ⌘V over Project\n * Settings ran `edit.paste`, which inserted an element node at the root of `project.json`, through\n * the transaction log, and saved it.\n */\n\n/** The `canvasMode` strings, mapped onto the editor each one actually names. */\nconst EDITOR_KIND_BY_MODE: Readonly<Record<string, EditorKind>> = {\n design: \"canvas\",\n edit: \"canvas\",\n /* The Entry editor — `content/entry-editor.ts`'s ENTRY_MODE. A form over ONE content entry's\n frontmatter, typed by its collection's schema; the same document the canvas edits the body of,\n which is why it is a mode of that tab rather than a tab of its own. */\n entry: \"entry\",\n \"git-diff\": \"diff\",\n grid: \"grid\",\n manage: \"library\",\n preview: \"canvas\",\n /* Project Settings — `settings/settings-document.ts`'s SETTINGS_MODE. A form over `project.json`,\n which is a configuration object and not a document tree; `stylebook` (Project Styles) is the\n second editor over that same document and answers `config` for the same reason. */\n settings: \"config\",\n source: \"code\",\n stylebook: \"config\",\n};\n\n/**\n * The editor kind a mode string names.\n *\n * An unknown mode reads as Canvas, and that default is only for modes STUDIO DOES NOT OWN: a format\n * declares its own list (`format.studio.modes`) and every mode declared that way is a view of the\n * artboard. A mode Studio itself introduces is not covered by it and belongs in the map above —\n * which is what `settings` was not.\n */\n/**\n * Human names for the editor kinds, so no surface prints an enum at a reader — and so two surfaces\n * cannot print DIFFERENT words for the same kind. The status bar and the pane context bar each had\n * their own copy, and they disagreed: one said \"Stylebook\", the wire value, where the other said\n * \"Project Styles\". §16.2 exists to stop the shell contradicting itself about what is on screen.\n */\nexport const EDITOR_KIND_LABELS: Readonly<Record<EditorKind, string>> = {\n canvas: \"Canvas\",\n code: \"Code\",\n config: \"Project Styles\",\n diff: \"Diff\",\n entry: \"Entry\",\n grid: \"Grid\",\n library: \"Library\",\n none: \"None\",\n};\n\nexport function editorKindForMode(mode: string): EditorKind {\n return EDITOR_KIND_BY_MODE[mode] ?? \"canvas\";\n}\n\n/** Only the three canvas modes carry a view. */\nconst CANVAS_VIEW_BY_MODE: Readonly<Record<string, CanvasView>> = {\n design: \"design\",\n edit: \"edit\",\n preview: \"preview\",\n};\n\n/**\n * The Canvas view a mode names — the neutral \"design\" for a mode that has none.\n *\n * Meaningful only where {@link editorKindForMode} answers `\"canvas\"`; every reader pairs the two.\n */\nexport function canvasViewForMode(mode: string): CanvasView {\n return CANVAS_VIEW_BY_MODE[mode] ?? \"design\";\n}\n\n/** Facts a command may be gated on. Every field is a plain value; predicates read, never write. */\nexport interface CommandContext {\n project: {\n open: boolean;\n isSite: boolean;\n isRepo: boolean;\n /** The project declares two or more locales — the gate on every `i18n.*` verb and surface. */\n isMultilingual: boolean;\n };\n git: {\n ahead: number;\n behind: number;\n dirtyCount: number;\n };\n document: {\n open: boolean;\n dirty: boolean;\n /** Format class of the open document — \"json\", \"md\", \"css\", … */\n mode: string;\n canUndo: boolean;\n canRedo: boolean;\n };\n editor: {\n kind: EditorKind;\n };\n canvas: {\n view: CanvasView;\n };\n pane: {\n count: number;\n derived: boolean;\n };\n selection: {\n count: number;\n /**\n * The selected document paths, in selection order — `[]` when nothing is selected (§6.5).\n *\n * The context is what `probe.state()` answers with, so this is how a script, a screenshot step\n * or the assistant READS a multi-selection back. `count` is its length; the last entry is the\n * primary, which every other fact in this group describes.\n */\n paths: JxPath[];\n /** Tag or node kind of the primary selection, \"\" when nothing is selected. */\n kind: string;\n isRoot: boolean;\n isComponentInstance: boolean;\n isLayoutNode: boolean;\n /**\n * Whether the selection IS a repeater — an `$prototype: \"Array\"` pseudo-element.\n *\n * A fact rather than a verb's precondition, in the idiom of `isComponentInstance`: a repeater\n * has no child list (its content is the single `map` template), so several structural verbs\n * mean nothing on one, and each of them used to re-derive it from the node it could not see.\n */\n isRepeater: boolean;\n };\n /**\n * Whether a live text caret owns the keyboard. Derived host-side in `iframe-host.ts` from the\n * editStart / selectionChanged / editEnd messages the canvas bridge already sends — this is the\n * fact that stops ⌘C/⌘X/⌘V being stolen from a writer mid-sentence.\n */\n caret: {\n active: boolean;\n /**\n * Whether that caret is the CANVAS's, rather than a parent-realm text field's.\n *\n * `active` folds both together on purpose: for {@link keyScopeStack} they are the same fact —\n * something is being typed into, so element-level chords must not fire. For a record they are\n * not. `format.bold` acts on a run of text inside the selected node and is meaningless while\n * the caret is in the Inspector's href field or the link popover's own URL box; a record gated\n * on `active` alone would fire there, and `mod+k` would re-mount the popover the author is\n * typing into.\n *\n * Sourced from the bridge alone (`isCaretActive()`), never from `isTextEntryFocused()`.\n */\n inCanvas: boolean;\n };\n focus: {\n region: FocusRegion;\n };\n modal: {\n open: boolean;\n };\n collab: {\n attached: boolean;\n readOnly: boolean;\n sourceCanonical: boolean;\n };\n ai: {\n configured: boolean;\n streaming: boolean;\n };\n capability: Record<Capability, boolean>;\n}\n\n/** A partial context, one group at a time — what tests and call sites actually write. */\nexport type CommandContextPatch = {\n [K in keyof CommandContext]?: Partial<CommandContext[K]>;\n};\n\n/**\n * The zero context: no project, no document, no selection, no capabilities.\n *\n * This is the honest cold-start state, which makes it the right default for the `when` predicates\n * to be tested against — a command that is enabled here has said so deliberately.\n */\n/**\n * The three selection predicates every node-editing verb is gated on.\n *\n * Here rather than in one verb module because two of them define records: `editor/shortcuts.ts`'s\n * chord table and `editor/context-menu.ts`'s element family. Importing one from the other made a\n * cycle (`shortcuts` already imports `copyNode`/`cutNode` from `context-menu`), and re-declaring\n * them is how \"an element selection\" comes to mean two different things in two menus.\n */\n\n/** The editor showing a document TREE. Every verb that addresses a node needs this. */\nexport const inCanvas = (ctx: CommandContext) => ctx.editor.kind === \"canvas\";\n\n/** Something is selected — including the document root, which is a selection of one. */\nexport const hasSelection = (ctx: CommandContext) => inCanvas(ctx) && ctx.selection.count > 0;\n\n/** A selection that is not the document element, i.e. a node with a parent to act relative to. */\nexport const hasElementSelection = (ctx: CommandContext) =>\n hasSelection(ctx) && !ctx.selection.isRoot;\n\nexport function emptyContext(): CommandContext {\n return {\n project: { open: false, isSite: false, isRepo: false, isMultilingual: false },\n git: { ahead: 0, behind: 0, dirtyCount: 0 },\n document: { open: false, dirty: false, mode: \"\", canUndo: false, canRedo: false },\n editor: { kind: \"none\" },\n canvas: { view: \"design\" },\n pane: { count: 1, derived: false },\n selection: {\n count: 0,\n paths: [],\n kind: \"\",\n isRoot: false,\n isComponentInstance: false,\n isLayoutNode: false,\n isRepeater: false,\n },\n caret: { active: false, inCanvas: false },\n focus: { region: \"pane\" },\n modal: { open: false },\n collab: { attached: false, readOnly: false, sourceCanonical: false },\n ai: { configured: false, streaming: false },\n capability: {\n gitClone: false,\n importSite: false,\n openProjectInNewWindow: false,\n dataRows: false,\n windowControls: false,\n findReferences: false,\n },\n };\n}\n\n/**\n * Build a context by overriding groups of {@link emptyContext}.\n *\n * Group-level merge, not a deep one: `makeContext({ selection: { count: 1 } })` keeps the other\n * selection fields at their empty defaults. One level is all the record has, and a general deep\n * merge would be a second thing to get right.\n */\nexport function makeContext(patch: CommandContextPatch = {}): CommandContext {\n const base = emptyContext();\n for (const key of Object.keys(patch) as (keyof CommandContext)[]) {\n const group = patch[key];\n if (group) {\n Object.assign(base[key], group);\n }\n }\n return base;\n}\n\n/**\n * An overlay owns the keyboard outright.\n *\n * This is what replaces `shortcuts.ts`'s blanket `if (isModalOpen()) return`. Expressing it as a\n * stack rather than a `!ctx.modal.open` term repeated in fourteen `when` predicates keeps the rule\n * in ONE place — and a dialog that swallows every click has to swallow every chord too, including\n * ones registered next week by a surface that never heard of dialogs. `palette` is the scope\n * overlay-owned bindings register in; nothing outside it resolves while one is up.\n */\nconst MODAL_STACK: readonly KeyScope[] = [\"palette\"];\n\n/** A live caret shadows the canvas: app-level chords still fire, element-level ones do not. */\nconst CARET_STACK: readonly KeyScope[] = [\"caret\", \"global\"];\n\n/** Focus outside the pane grid. Dock-scoped bindings, then the app's. */\nconst DOCK_STACK: readonly KeyScope[] = [\"dock\", \"global\"];\n\nconst CANVAS_STACK: readonly KeyScope[] = [\"canvas\", \"global\"];\nconst GRID_STACK: readonly KeyScope[] = [\"grid\", \"global\"];\nconst CODE_STACK: readonly KeyScope[] = [\"code\", \"global\"];\n\n/** No engine owns the keyboard — only app-level chords are live. */\nconst GLOBAL_STACK: readonly KeyScope[] = [\"global\"];\n\n/**\n * The scope stack for the current context, narrowest scope first.\n *\n * The ladder is `caret > grid/code engine > focused dock > global` (plan §5.3), and the whole point\n * is that a scope which is not on the stack cannot fire AT ALL. Three hand-written guards collapse\n * into it:\n *\n * - The blanket modal return → the `palette`-only stack;\n * - The `canvasMode === \"grid\" && ![\"o\",\"p\",\"s\",\"w\",\"z\",\"Z\"].includes(key)` allow-list → the `grid`\n * stack, whose six survivors are precisely the `global`-scoped commands;\n * - The caret guard → the `caret` stack, which drops `canvas` so ⌘C/⌘X/⌘V/Delete stay off a sentence\n * being typed while ⌘S still saves.\n *\n * Preview and the non-editing surfaces (the diff view, the media library, the stylebook) get the\n * bare `global` stack. Preview draws no overlays and posts no hits, so a selection carried in from\n * Design is invisible: every element-level chord there — destructive or not — acts on something the\n * author cannot see. That is one rule where `shortcuts.ts` had two ad-hoc refusal sets which\n * disagreed with each other (⌘X was refused, ⌘C was not).\n */\nexport function keyScopeStack(ctx: CommandContext): readonly KeyScope[] {\n if (ctx.modal.open) {\n return MODAL_STACK;\n }\n if (ctx.caret.active) {\n return CARET_STACK;\n }\n if (ctx.focus.region !== \"pane\") {\n return DOCK_STACK;\n }\n switch (ctx.editor.kind) {\n case \"grid\": {\n return GRID_STACK;\n }\n case \"code\": {\n return CODE_STACK;\n }\n case \"canvas\": {\n return ctx.canvas.view === \"preview\" ? GLOBAL_STACK : CANVAS_STACK;\n }\n default: {\n return GLOBAL_STACK;\n }\n }\n}\n",
|
|
25
|
+
"/// <reference lib=\"dom\" />\nimport { effectScope, reactive } from \"../reactivity\";\nimport { formatByName, formatForPath } from \"../format/format-host\";\nimport { normalizeArrayChildren } from \"../state\";\nimport type { FormulaEditDef, FunctionEditDef, InlineEditDef, JsonValue } from \"../types\";\nimport { editorKindForMode } from \"../commands/context\";\nimport type { EditorKind } from \"../commands/context\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport type { JxDocOp, JxFmOp } from \"./patch-ops\";\n\n/**\n * The project's configuration file, project-relative.\n *\n * Named here rather than at the four places that used to spell it, because it is a DOCUMENT PATH —\n * `inferModes` answers `[\"stylebook\", \"source\"]` for it (editor kind `config`), and\n * `tabs/project-config.ts` binds the tab at this path as the configuration document.\n */\nexport const PROJECT_CONFIG_PATH = \"project.json\";\n\nexport interface TabUi {\n rightTab: string;\n canvasMode: string;\n /** Preview toggle — composes with an edit/design canvasMode; the effective mode becomes \"preview\". */\n preview: boolean;\n /** Show elements inherited from the page's layout (pages with an effective layout only). */\n showLayout: boolean;\n /** Chosen literal values for dynamic route params (e.g. { sku: \"mini-trencher\" }). */\n previewParams: Record<string, string>;\n /**\n * Chosen test values for a component doc's props (state entries), seeded into the canvas render\n * so a non-instantiated component previews with real data (M6) — the previewParams mirror.\n */\n previewProps: Record<string, JsonValue> | null;\n zoom: number;\n /**\n * Edit-mode content zoom — browser-page-zoom semantics (content reflows at the zoomed effective\n * width while the canvas footprint stays fixed), unlike `zoom` which pan/zooms the whole canvas.\n */\n editZoom: number;\n activeMedia: string | null;\n activeSelector: string | null;\n editingFunction: FunctionEditDef | null;\n /** Logic-tab formula target ($expression editing); editingFunction wins if both are set. */\n editingFormula: FormulaEditDef | null;\n featureToggles: Record<string, boolean>;\n /**\n * Canvas color-scheme preview: follow the OS (\"auto\") or force a scheme. Drives the\n * data-color-scheme attribute on the canvas iframe root (spec §9.5) and, in the style sidebar,\n * which scheme layer edits target.\n */\n previewColorScheme: \"auto\" | \"light\" | \"dark\";\n /**\n * The locale this pane renders AS — the artboard's `lang` and `dir` (§13.4), never which file is\n * open.\n *\n * Jx has no message catalogue: a translation is a different file in a different directory, so\n * \"show this page in French\" is a navigation and belongs to the locale preset. This axis is the\n * other half — the rendering context a document is _drawn_ under, which is how an author sees\n * their layout mirror under an RTL locale without leaving the document they are editing.\n *\n * `null` is \"the document's own language\", resolved from its path at render time rather than\n * baked in here: a file moved into `pages/fr/` must change what the pane draws, and a stored tag\n * would go on claiming the language the file used to be in.\n */\n previewLocale: string | null;\n styleSections: Record<string, boolean>;\n /**\n * Which Data rows have their editor and value open, by state-entry name.\n *\n * PER TAB, and a set rather than a single name: comparing two entries means seeing both at once,\n * and coming back to a tab means finding it as you left it. It was one module-global string\n * (`expandedSignal`) plus one module-global Set (`expandedDataKeys`) — two answers to one\n * question, both shared across every open document.\n */\n dataRows: Record<string, boolean>;\n /**\n * How far each truncation marker in a Data row's value tree has been opened, keyed by tree path.\n *\n * PER TAB, for the reason `dataRows` is: the paths are entry names, and a module-global record\n * would have applied \"show 50 more of `listings`\" to a different document's `listings`.\n */\n dataLimits: Record<string, number>;\n inspectorSections: Record<string, boolean>;\n styleShorthands: Record<string, boolean>;\n styleFilter: string;\n pendingInlineEdit: InlineEditDef | null;\n}\n\n/**\n * A live (iframe-evaluated) expression preview retained per editing target (M6). Stored on\n * `session.canvas` beside `scope` — plain wire data (path-key → display-string pairs), rebuilt into\n * an ExpressionPreview by services/live-preview.ts on read.\n */\nexport interface StoredLivePreview {\n /** Serialized expression + context the values were computed for (staleness check). */\n key: string;\n values: [string, string][];\n error: string | null;\n}\n\ninterface HistorySnapshot {\n /** Full document at this state (checkpoint), or null when the ops describe the transition. */\n document: Record<string, unknown> | null;\n /** Selection after this state's transaction — the whole set, so a batch undoes back to it. */\n selection: (string | number)[][];\n /** Selection before this state's transaction (restored on surgical undo). */\n selectionBefore?: (string | number)[][];\n /** Replayable ops transforming the previous state into this one. */\n forwardOps?: JxDocOp[] | null;\n /** Replayable ops transforming this state back into the previous one. */\n inverseOps?: JxDocOp[] | null;\n /** Frontmatter key changes in this transaction (before/after values, replayed both ways). */\n fmOps?: JxFmOp[] | null;\n /**\n * Identifies a run of edits that undo as ONE step (successive text commits to the same block).\n *\n * Typing commits on every pause, so without coalescing a minute of writing would push dozens of\n * entries and evict every structural edit before it from the 100-entry ring — and ⌘Z would walk\n * back through the prose one pause at a time instead of undoing the edit.\n */\n coalesceKey?: string | null;\n}\n\n/**\n * Where a tab was drilled in FROM — a relationship, not a navigation stack.\n *\n * Drilling into a component opens a real tab of its own (see `workspace/workspace.ts`), so the old\n * \"swap the document under the same tab id\" breadcrumb is gone. What survives is this: the tab\n * remembers which document sent the author here, and the tab strip prints it. Nothing restores from\n * it, nothing pops it — closing the parent leaves the child perfectly usable.\n */\nexport interface TabOrigin {\n /** Id of the tab the author drilled in from. */\n tabId: string;\n /** That tab's document path at the moment of the drill-in — what the strip prints. */\n documentPath: string | null;\n}\n\nexport interface Tab {\n id: string;\n documentPath: string | null;\n fileHandle: FileSystemFileHandle | null;\n capabilities: { modes: string[] };\n /** Pinned tabs hold the head of their pane's strip, and a preview open never takes their slot. */\n pinned: boolean;\n /**\n * A PREVIEW tab is disposable: the next preview open in the same pane replaces it, and it renders\n * italic to say so. It stops being one the moment the author commits to it — an edit, a pin, a\n * double-click. The palette's `@`/`#` modes make browsing cheap, and browsing must not litter.\n */\n preview: boolean;\n scope: {\n stop: () => void;\n run: <T>(fn: () => T) => T | undefined;\n [k: string]: unknown;\n };\n doc: {\n document: JxMutableNode;\n content: { frontmatter: Record<string, unknown> };\n mode: string;\n sourceFormat: string | null;\n handlersSource: string | null;\n dirty: boolean;\n };\n session: {\n /**\n * The selected document paths, in the order the user built them (§6.5).\n *\n * `[]` is \"nothing selected\" — there is no `null` state, because \"no selection\" and \"a\n * selection of nothing\" were never two different things. `selection[0]` is the anchor a\n * shift-range extends from; the LAST entry is the primary, which every single-target surface\n * reads through `tabs/selection.ts`'s `primarySelection`. **Always assign a fresh array**:\n * several render effects track this with a bare property read and would miss an in-place push.\n */\n selection: (string | number)[][];\n hover: (string | number)[] | null;\n clipboard: JxMutableNode | null;\n /** The document this tab was drilled in from, if any. Rendered by the tab strip. */\n openedFrom: TabOrigin | null;\n ui: TabUi;\n canvas: {\n status: string;\n /**\n * A Refresh is out and the snapshot below has not come back yet.\n *\n * The button used to guess: fire the re-render, then `setTimeout(…, 200)` and repaint,\n * because nothing told the panel when the values had actually changed. A fetch slower than\n * 200ms repainted the OLD values and looked like a Refresh that did nothing. The iframe posts\n * `dataScope` when the render resolves, so the honest answer is to say \"refreshing\" until it\n * arrives and let the arrival be the repaint.\n */\n refreshing: boolean;\n // A serializable snapshot of the iframe's resolved `$defs` (data-source values), posted over\n // The bridge as a `dataScope` message and read by the data-explorer panel. Plain data now —\n // The old live `EffectScope` (with `.stop()`) moved into the iframe realm with buildScope.\n scope: Record<string, unknown> | null;\n // Latest live (iframe-evaluated) expression previews keyed by editing-target id, stored\n // Beside `scope` the same way (services/live-preview.ts owns reads/writes).\n livePreviews: Record<string, StoredLivePreview> | null;\n error: string | null;\n pendingInlineEdit: InlineEditDef | null;\n };\n };\n history: {\n snapshots: HistorySnapshot[];\n index: number;\n };\n}\n\n/**\n * @param {string} canvasMode — initial canvas mode (the tab's first allowed mode)\n * @param {boolean} preview — initial preview-toggle state\n * @returns {TabUi}\n */\nfunction createDefaultUi(canvasMode: string, preview = false) {\n return {\n activeMedia: null,\n activeSelector: null,\n canvasMode,\n editZoom: 1,\n editingFormula: null,\n editingFunction: null,\n featureToggles: {},\n inspectorSections: {},\n pendingInlineEdit: null,\n preview,\n previewColorScheme: \"auto\" as const,\n previewLocale: null as string | null,\n previewParams: {},\n previewProps: null,\n rightTab: \"properties\",\n showLayout: true,\n styleFilter: \"\",\n styleSections: {},\n dataRows: {},\n dataLimits: {},\n styleShorthands: {},\n zoom: 1,\n };\n}\n\nconst ALL_MODES = [\"edit\", \"design\", \"preview\", \"source\", \"stylebook\"];\n\n/**\n * Create a new tab with reactive doc/session/history trees, owned by an effectScope.\n *\n * @param {{\n * id: string;\n * documentPath?: string | null;\n * fileHandle?: FileSystemFileHandle | null;\n * document: Record<string, unknown>;\n * frontmatter?: Record<string, unknown>;\n * sourceFormat?: string | null;\n * capabilities?: { modes?: string[] };\n * openedFrom?: TabOrigin | null;\n * preview?: boolean;\n * }} opts\n * @returns {Tab}\n */\nexport function createTab({\n id,\n documentPath = null,\n fileHandle = null,\n document,\n frontmatter,\n sourceFormat = null,\n capabilities,\n openedFrom = null,\n preview: previewTab = false,\n}: {\n id: string;\n documentPath?: string | null;\n fileHandle?: FileSystemFileHandle | null;\n document: Record<string, unknown>;\n frontmatter?: Record<string, unknown>;\n sourceFormat?: string | null;\n capabilities?: { modes?: string[] };\n openedFrom?: TabOrigin | null;\n preview?: boolean;\n}) {\n const scope = effectScope();\n\n // Normalize legacy whole-children repeaters to the canonical array-member form before the doc\n // (and its first history checkpoint) are stored.\n normalizeArrayChildren(document);\n\n const resolvedModes = capabilities?.modes ?? inferModes(documentPath, sourceFormat);\n // A tab opens in its first allowed mode — never one the toolbar would disable.\n // Formats author mode order so the default comes first (edit, stylebook, etc.).\n // \"preview\" is a per-tab toggle rather than a base mode: a preview-first format opens\n // In its first non-preview mode with the toggle already on.\n const initialCanvasMode = resolvedModes.find((m) => m !== \"preview\") ?? \"edit\";\n const initialPreview = resolvedModes[0] === \"preview\";\n\n const tab = scope.run(() => ({\n capabilities: { modes: resolvedModes },\n doc: reactive({\n content: { frontmatter: frontmatter || {} },\n dirty: false,\n document,\n handlersSource: null,\n mode: inferDocumentMode(documentPath, sourceFormat),\n sourceFormat,\n }),\n documentPath,\n fileHandle,\n history: reactive({\n index: 0,\n snapshots: [{ document: structuredClone(document), selection: [] }],\n }),\n id,\n pinned: false,\n preview: previewTab,\n scope,\n session: reactive({\n canvas: {\n refreshing: false,\n error: null,\n livePreviews: null,\n pendingInlineEdit: null,\n scope: null,\n status: \"idle\",\n },\n clipboard: null,\n hover: null,\n openedFrom,\n selection: [],\n ui: createDefaultUi(initialCanvasMode, initialPreview),\n }),\n })) as unknown as Tab;\n\n return tab;\n}\n\n/**\n * Allowed modes for a document. \"preview\" in a format's mode list means the preview toggle is\n * Available for the tab (it is not a base canvas mode the toolbar switches to).\n *\n * @param {string | null | undefined} documentPath\n * @param {string | null} sourceFormat\n * @returns {string[]}\n */\nfunction inferModes(documentPath: string | null | undefined, sourceFormat: string | null) {\n if (documentPath === PROJECT_CONFIG_PATH) {\n return [\"stylebook\", \"source\"];\n }\n const format = formatByName(sourceFormat) ?? formatForPath(documentPath);\n if (format) {\n return format.studio?.modes ?? [\"edit\", \"design\", \"preview\", \"source\"];\n }\n return ALL_MODES;\n}\n\n/**\n * Document mode for a new tab: format-class documents default to their $studio.documentMode\n * (content unless promoted to component); JSON is component.\n *\n * @param {string | null | undefined} documentPath\n * @param {string | null} sourceFormat\n * @returns {string}\n */\nfunction inferDocumentMode(documentPath: string | null | undefined, sourceFormat: string | null) {\n const format = formatByName(sourceFormat) ?? formatForPath(documentPath);\n if (format) {\n return format.studio?.documentMode?.default ?? \"content\";\n }\n return \"component\";\n}\n\n// ─── Editor kinds ─────────────────────────────────────────────────────────────\n// §4.2's first axis. `canvasMode` conflates two orthogonal questions — WHICH EDITOR is open, and\n// (for the Canvas editor only) WHICH VIEW of it. The pane context bar labels them separately, and\n// The pane model needs the first one on its own: the second pane is capped to non-Canvas kinds\n// Until P8's `canvas-patcher` fan-out lands, because a second live `@jxsuite/runtime` host is the\n// Expensive part.\n//\n// The mode → kind map itself is `commands/context.ts`'s `editorKindForMode`. It was duplicated\n// Here, and the copy that drifted is what let a settings document resolve into the canvas key\n// Scope; the pane model and the command context now read the same table.\n\n/**\n * The editor kind a tab is currently showing. Reads the BASE mode: the preview toggle is a value on\n * the Canvas view axis, not a different editor.\n *\n * @param {Tab} tab\n * @returns {EditorKind}\n */\nexport function editorKindOf(tab: Tab): EditorKind {\n return editorKindForMode(tab.session.ui.canvasMode);\n}\n\n/**\n * Every editor kind this document supports, in the format's own mode order and deduplicated — the\n * dropdown's entries, so it can never contain a permanently dead one (§4.2).\n *\n * `preview` contributes nothing: it is a Canvas VIEW, and the kind it would add is already there.\n *\n * @param {Tab} tab\n * @returns {EditorKind[]}\n */\nexport function editorKindsOf(tab: Tab): EditorKind[] {\n const kinds: EditorKind[] = [];\n for (const mode of tab.capabilities.modes) {\n if (mode === \"preview\") {\n continue;\n }\n const kind = editorKindForMode(mode);\n if (!kinds.includes(kind)) {\n kinds.push(kind);\n }\n }\n return kinds;\n}\n\n/**\n * The first mode this tab supports that renders `kind`, or `undefined` when it supports none.\n *\n * The inverse of {@link editorKindOf}: choosing an editor kind has to land on a real `canvasMode`,\n * because that string is what the canvas render message carries.\n *\n * @param {Tab} tab\n * @param {EditorKind} kind\n * @returns {string | undefined}\n */\nexport function modeForEditorKind(tab: Tab, kind: EditorKind): string | undefined {\n return tab.capabilities.modes.find(\n (mode) => mode !== \"preview\" && editorKindForMode(mode) === kind,\n );\n}\n\n// ─── There is no sub-document stack ───────────────────────────────────────────\n// A tab held one, and it was scaffolding for a navigation model the tab model replaced. `studio.md`\n// §14.3 justified it for exactly two cases and both moved: a function body opens in the Bottom\n// Dock's Logic tab (P8), and a `$map` template is a subtree of its parent document, selected in\n// Place on the canvas rather than loaded as a document of its own. Everything with a file of its\n// Own — a component, a layout — opens a REAL TAB with an `openedFrom` relationship (§14.1–2):\n// {@link TabOrigin}, above, which nothing pops and nothing restores from.\n//\n// So `pushSubDocument` had no caller in `src/`, the stack was permanently `[]`, and every reader\n// Below it — `popSubDocument`, `popToSubDocument`, the UI capture/restore pair, the pane-context\n// Breadcrumb, the jump bar's `subdocument` segment, `document.setStackLevel`, collab's `drilled`\n// Guard — was live code that could only ever take its empty branch. They are gone together: a\n// Stack with no way in is not an unfinished feature, it is a shape the design moved past.\n\n/**\n * Dispose a tab — stops its effectScope, killing all effects created within it.\n *\n * @param {Tab} tab\n */\nexport function disposeTab(tab: Tab) {\n tab.scope.stop();\n}\n",
|
|
26
|
+
"/**\n * CollabSession — the bridge between a tab's transactional document and a shared Y.Doc obtained\n * from `platform.collab(docPath)`.\n *\n * Outbound: the transact observer publishes every local transaction's forward JxDocOps into the Y\n * structure tree (un-instrumented and bypass writes reconcile by diff — the Y.Doc doubles as the\n * before-image). Inbound: remote Y transactions convert back into JxDocOps and replay through\n * `applyExternalDocOps`, riding the surgical canvas patcher; unconvertible shapes hard-reconcile\n * the tab from the Y tree. Undo becomes a local-origin-scoped Y.UndoManager registered as the tab's\n * history delegate.\n *\n * Saving is EXPLICIT even while attached: syncing edits to peers (the Y.Doc) is automatic, but\n * folding the shared source to disk is not. Local edits mark `tab.doc.dirty` immediately for\n * instant Save-button feedback; the room-level, server-authoritative unsaved state then arrives via\n * `handle.onDirty` (any peer's edit dirties the room for everyone; a save clears it for everyone).\n * Cmd+S / Save runs a serialize→mirror→flush, and the provider broadcasts the room clean once the\n * write lands.\n *\n * All yjs code sits behind a dynamic import: the unsplit bundle inlines the bytes, but module\n * evaluation defers until a collab session actually attaches.\n */\n\nimport { effect, onScopeDispose, reactive, toRaw } from \"../reactivity\";\nimport { getPlatform } from \"../platform\";\nimport { jsonClone } from \"../utils/studio-utils\";\nimport { cloneSelection } from \"../tabs/selection\";\nimport {\n applyExternalDocOps,\n isBatching,\n setBatchEndNotifier,\n setHistoryDelegate,\n setTransactGate,\n setTransactObserver,\n transactDoc,\n} from \"../tabs/transact\";\nimport { PROJECT_CONFIG_PATH } from \"../tabs/tab\";\nimport type { TransactOrigin } from \"../tabs/transact\";\nimport type { TransactionRecord } from \"../tabs/patch-ops\";\nimport type { Tab } from \"../tabs/tab\";\nimport type { JxDocOp } from \"@jxsuite/collab/ops\";\nimport type { CollabHandle } from \"@jxsuite/collab/provider\";\nimport type { JxMutableNode } from \"@jxsuite/schema/types\";\nimport type * as CollabNS from \"@jxsuite/collab\";\nimport { collabState, registerCollabPath, unregisterCollabPath } from \"./collab-state\";\nimport { notify } from \"../services/notify\";\n\ntype CollabModule = typeof CollabNS;\n\n/** How long the initial sync may take before falling back to solo editing. */\nconst SYNC_TIMEOUT_MS = 8000;\n/** Debounce for the elected reconciler's structure→source mirror. */\nconst MIRROR_DEBOUNCE_MS = 800;\n\n/**\n * The longest the shared source text may lag behind local edits while typing continues.\n *\n * The debounce above is re-armed on EVERY transaction, so any commit cadence faster than it starves\n * the mirror completely — and the canvas now commits on a ~500ms typing pause. Without a ceiling,\n * sustained writing would leave the source Y.Text (what peers preview and what providers persist)\n * frozen for the whole session. This bounds the lag instead: the debounce still coalesces bursts,\n * but a mirror is forced once the text is this stale.\n */\nconst MIRROR_MAX_LAG_MS = 2500;\n\nlet collabModulePromise: Promise<CollabModule> | null = null;\n\nfunction loadCollab(): Promise<CollabModule> {\n collabModulePromise ??= import(\"@jxsuite/collab\");\n return collabModulePromise;\n}\n\n/** Tabs can open before any platform registers (headless tests); collab simply stays off. */\nfunction maybePlatform(): ReturnType<typeof getPlatform> | null {\n try {\n return getPlatform();\n } catch {\n return null;\n }\n}\n\n/** Serializer injected at studio init (file-ops' serializeDocument); avoids an import cycle. */\nlet _serialize: ((tab: Tab) => Promise<string>) | null = null;\n\nexport function configureCollabSerializer(fn: ((tab: Tab) => Promise<string>) | null): void {\n _serialize = fn;\n}\n\n/** Parser injected at studio init (file-ops' parseSourceForPath) for the source reconciler. */\nexport type CollabParser = (\n tab: Tab,\n text: string,\n) => Promise<{ document: JxMutableNode; frontmatter?: Record<string, unknown> }>;\n\nlet _parse: CollabParser | null = null;\n\nexport function configureCollabParser(fn: CollabParser | null): void {\n _parse = fn;\n}\n\n/** Status-message sink injected at studio init (a direct statusbar import would cycle). */\nlet _notify: (message: string) => void = () => {};\n\nexport function configureCollabNotifier(fn: ((message: string) => void) | null): void {\n _notify = fn ?? (() => {});\n}\n\ninterface ActiveSession {\n tab: Tab;\n path: string;\n handle: CollabHandle;\n collab: CollabModule;\n undoManager: InstanceType<CollabModule[\"UndoManager\"]> | null;\n /** The last document root reference produced through transactDoc (bypass-write detection). */\n lastSeenRef: object | null;\n /** Buffered forward ops while an AI batch runs; null outside batches. */\n batchOps: JxDocOp[] | null;\n batchNeedsDiff: boolean;\n /** Guards the frontmatter watcher against echoing remote-applied fields. */\n applyingRemoteFrontmatter: boolean;\n synced: boolean;\n canWrite: boolean;\n mirrorTimer: ReturnType<typeof setTimeout> | null;\n /** When the shared source text was last brought up to date; bounds the debounce's max lag. */\n lastMirrorAt?: number;\n /** Debounce for the source reconciler's Y.Text → structure parse mirror. */\n sourceParseTimer: ReturnType<typeof setTimeout> | null;\n /**\n * Which source surface currently speaks for this client's canonical lock.\n *\n * The lock is a room-level fact with no owner, and `leave()` reaches it from exactly one place —\n * the cleanup {@link canvas/canvas-render.ts}'s `createSourceCollabBinding` returns. Toggling Code\n * view off and on inside one round trip runs two mounts that overlap: the second `enter()` has\n * already re-flipped the lock by the time the first mount's cleanup fires, and that cleanup\n * released a lock the live mount was holding — leaving a co-edited buffer bound to a Y.Text that\n * the room no longer treats as canonical, with the structure mirror free to serialize over it.\n *\n * A token, minted synchronously by each `enter()`, is the identity the release checks. Call\n * order, not resolution order: `enter()` awaits a serialization, so the last mount to be ASKED\n * must win regardless of which round trip returns first.\n */\n sourceLockOwner: object | null;\n disposers: (() => void)[];\n}\n\ninterface TabRuntime {\n watcherInstalled: boolean;\n /** Bumped on every detach; in-flight attaches abandon when it moves. */\n generation: number;\n session: ActiveSession | null;\n attaching: Promise<void> | null;\n /**\n * The user asked to leave this document's session.\n *\n * Reactive, because the watcher effect that owns attach/detach has to re-run when it changes —\n * which is also why leaving is a STATE rather than a teardown verb: the effect stays the single\n * owner of the session lifecycle, and `Collaborate: Stop sharing` sets a flag it reads.\n */\n optedOut: { value: boolean };\n}\n\nconst runtimes = new WeakMap<Tab, TabRuntime>();\n\n/** Callers hold either the raw tab or a reactive proxy of it; key runtimes by the raw object. */\nfunction rawTab(tab: Tab): Tab {\n return toRaw(tab as unknown as object) as Tab;\n}\n\nfunction runtimeOf(tab: Tab): TabRuntime | undefined {\n return runtimes.get(rawTab(tab));\n}\n\nfunction runtimeFor(tab: Tab): TabRuntime {\n const key = rawTab(tab);\n let runtime = runtimes.get(key);\n if (!runtime) {\n runtime = {\n attaching: null,\n generation: 0,\n optedOut: reactive({ value: false }),\n session: null,\n watcherInstalled: false,\n };\n runtimes.set(key, runtime);\n }\n return runtime;\n}\n\n// ─── Global transact hooks (installed once; no-ops for unattached tabs) ──────\n\nlet hooksInstalled = false;\n\nfunction installGlobalHooks(): void {\n if (hooksInstalled) {\n return;\n }\n hooksInstalled = true;\n setTransactObserver(onTransact);\n setBatchEndNotifier(onBatchEnd);\n /* Soft-freeze structural editing while ANYONE holds source-canonical (remote origins pass — they\n ARE the reconciler's mirror of the frozen representation).\n **Including the client holding the lock, which used to be exempt** (`&& !session.inSourceMode`).\n The exemption assumed a carrier that does not exist: a structural edit made by the lock holder\n never reaches the shared `Y.Text`, because `scheduleMirror` returns early while canonical is\n `\"source\"`, and nothing notices, because the source observer fires on TEXT changes only. So the\n tree and the text diverged, held apart until `leave()` — which runs `sourceParseNow` before\n releasing the lock, parses the UNCHANGED text back into a tree, and reverts the author's edit\n under `MIRROR_ORIGIN`. It then arrives at every peer through `applyExternalDocOps` (origin\n `\"remote\"`, which passes this gate by design), so the layer they deleted in the Outline\n reappeared seconds later with no explanation — and they were the one client this toast was\n never shown to.\n Mirroring the other way while source is canonical is not the alternative: it is exactly the\n round trip `services/monaco-buffer.ts`'s clause 5 exists to refuse. Clause 5's own reasoning\n settles this one — if the CRDT owns that text and the tree is DERIVED from it, then nobody may\n edit the tree directly, and \"nobody\" includes whoever is holding the pen. */\n setTransactGate((tab) => {\n const session = runtimeOf(tab)?.session;\n if (session?.synced && collabState(tab).sourceCanonical) {\n _notify(\"Source editing in progress — structural edits are paused\");\n return \"source-canonical\";\n }\n return null;\n });\n}\n\n/** Test hook: uninstall global observers and forget module state. */\nexport function resetCollabForTests(): void {\n hooksInstalled = false;\n setTransactObserver(null);\n setBatchEndNotifier(null);\n setTransactGate(null);\n _serialize = null;\n _parse = null;\n _notify = () => {};\n}\n\nfunction onTransact(tab: Tab, record: TransactionRecord, origin: TransactOrigin): void {\n const session = runtimeOf(tab)?.session;\n if (!session || !session.synced) {\n return;\n }\n session.lastSeenRef = toRaw(tab.doc.document) as object;\n if (origin === \"remote\") {\n // The reconciler keeps source text fresh regardless of WHO edited the structure. The tab's\n // Dirty state is driven by the server's room-level `doc-dirty` broadcast (see onDirty in\n // CreateSession), not forced here.\n scheduleMirror(session);\n return;\n }\n if (session.canWrite) {\n publishRecord(session, record);\n scheduleMirror(session);\n }\n // Local edits leave the tab dirty (transactDoc already set it) until an explicit save flushes and\n // The provider broadcasts the room clean.\n}\n\nfunction onBatchEnd(tab: Tab): void {\n const session = runtimeOf(tab)?.session;\n if (!session?.synced || session.batchOps === null) {\n return;\n }\n const ops = session.batchOps;\n const needsDiff = session.batchNeedsDiff;\n session.batchOps = null;\n session.batchNeedsDiff = false;\n if (!session.canWrite) {\n return;\n }\n // One Y transaction — one wire message, one undo step for the whole AI run.\n session.undoManager?.stopCapturing();\n if (needsDiff) {\n publishDiff(session);\n } else if (ops.length > 0) {\n try {\n session.collab.applyDocOpsToY(session.handle.doc, ops, session.collab.LOCAL_ORIGIN);\n } catch {\n publishDiff(session);\n }\n }\n session.undoManager?.stopCapturing();\n}\n\nfunction publishRecord(session: ActiveSession, record: TransactionRecord): void {\n const forward = record.docOps.map((pair) => pair.forward);\n if (isBatching()) {\n session.batchOps ??= [];\n if (forward.length === 0) {\n session.batchNeedsDiff = true;\n } else {\n session.batchOps.push(...forward);\n }\n return;\n }\n if (forward.length === 0) {\n // Un-instrumented mutation: the Y tree is the last-synced before-image — diff against it.\n publishDiff(session);\n return;\n }\n try {\n session.collab.applyDocOpsToY(session.handle.doc, forward, session.collab.LOCAL_ORIGIN);\n } catch {\n publishDiff(session);\n }\n}\n\n/** Make the Y structure tree match the tab's document (diff when possible, hard replace beyond). */\nfunction publishDiff(session: ActiveSession): void {\n const { collab, handle, tab } = session;\n const before = collab.yDocToJson(handle.doc);\n const after = jsonClone(toRaw(tab.doc.document)) as JxMutableNode;\n const ops = collab.diffDocs(before, after);\n if (ops === null) {\n collab.replaceYStructure(handle.doc, after, collab.LOCAL_ORIGIN);\n } else if (ops.length > 0) {\n try {\n collab.applyDocOpsToY(handle.doc, ops, collab.LOCAL_ORIGIN);\n } catch {\n collab.replaceYStructure(handle.doc, after, collab.LOCAL_ORIGIN);\n }\n }\n}\n\n/** Replace the tab document in place from the Y tree (remote origin, full-render fallback). */\nfunction reconcileTabFromY(session: ActiveSession): void {\n const next = session.collab.yDocToJson(session.handle.doc);\n transactDoc(\n session.tab,\n (t) => {\n const target = t.doc.document as Record<string, unknown>;\n for (const key of Object.keys(target)) {\n if (!(key in next)) {\n delete target[key];\n }\n }\n Object.assign(target, next);\n },\n { origin: \"remote\", skipHistory: true },\n );\n}\n\n// ─── Source mirror (Phase A: canonical is always \"structure\") ────────────────\n\n/** The elected reconciler: lowest write-capable clientID keeps source Y.Text fresh. */\nfunction isReconciler(session: ActiveSession): boolean {\n if (!session.canWrite) {\n return false;\n }\n const { awareness } = session.handle;\n let lowest = awareness.clientID;\n for (const [clientId, state] of awareness.getStates()) {\n if ((state as { canWrite?: boolean }).canWrite !== false && clientId < lowest) {\n lowest = clientId;\n }\n }\n return lowest === session.handle.awareness.clientID;\n}\n\nfunction scheduleMirror(session: ActiveSession): void {\n if (!_serialize || !isReconciler(session)) {\n return;\n }\n // While source holds the canonical lock, mirroring runs the OTHER way (parse, not serialize).\n if (session.collab.canonicalOf(session.handle.doc) === \"source\") {\n return;\n }\n // Re-arming on every transaction means a faster commit cadence would push the mirror out\n // Forever. Once the shared text is MIRROR_MAX_LAG_MS stale, stop deferring and mirror now.\n const now = Date.now();\n session.lastMirrorAt ??= now;\n if (now - session.lastMirrorAt >= MIRROR_MAX_LAG_MS) {\n if (session.mirrorTimer) {\n clearTimeout(session.mirrorTimer);\n session.mirrorTimer = null;\n }\n session.lastMirrorAt = now;\n void mirrorNow(session);\n return;\n }\n if (session.mirrorTimer) {\n clearTimeout(session.mirrorTimer);\n }\n session.mirrorTimer = setTimeout(() => {\n session.mirrorTimer = null;\n session.lastMirrorAt = Date.now();\n void mirrorNow(session);\n }, MIRROR_DEBOUNCE_MS);\n}\n\n/** Serialize the tab and fold the text into source Y.Text (what providers persist and commit). */\nasync function mirrorNow(session: ActiveSession): Promise<void> {\n if (!_serialize || !session.synced) {\n return;\n }\n try {\n const text = await _serialize(session.tab);\n session.collab.updateSourceText(session.handle.doc, text, session.collab.MIRROR_ORIGIN);\n } catch {\n // Serialization failures leave the previous mirror in place; the next edit retries.\n }\n}\n\n// ─── Save ─────────────────────────────────────────────────────────────────────\n\n/** Parse the shared source text back into the structure tree (the source reconciler's duty). */\nasync function sourceParseNow(session: ActiveSession): Promise<void> {\n if (!_parse || !session.synced || !session.canWrite) {\n return;\n }\n const { collab, handle, tab } = session;\n const rev = collab.canonicalRevOf(handle.doc);\n const text = collab.sourceText(handle.doc).toString();\n let parsed: Awaited<ReturnType<CollabParser>>;\n try {\n parsed = await _parse(tab, text);\n } catch {\n // Unparseable source: keep the last good structure (the preview goes stale, not wrong).\n return;\n }\n if (!session.synced || collab.canonicalRevOf(handle.doc) !== rev) {\n // The lock flipped while parsing; this mirror was computed against a dead representation.\n return;\n }\n const ops = collab.diffDocs(collab.yDocToJson(handle.doc), parsed.document);\n if (ops === null) {\n collab.replaceYStructure(handle.doc, parsed.document, collab.MIRROR_ORIGIN);\n } else if (ops.length > 0) {\n try {\n collab.applyDocOpsToY(handle.doc, ops, collab.MIRROR_ORIGIN);\n } catch {\n collab.replaceYStructure(handle.doc, parsed.document, collab.MIRROR_ORIGIN);\n }\n }\n const frontmatter = collab.frontmatterMap(handle.doc);\n const next = parsed.frontmatter ?? {};\n handle.doc.transact(() => {\n // Detached copy: keys are deleted while iterating.\n const sharedKeys = [...frontmatter.keys()];\n for (const key of sharedKeys) {\n if (!(key in next)) {\n frontmatter.delete(key);\n }\n }\n for (const [key, value] of Object.entries(next)) {\n if (!collab.deepEqual(frontmatter.get(key), value)) {\n frontmatter.set(key, value);\n }\n }\n }, collab.MIRROR_ORIGIN);\n}\n\n/**\n * The code view's co-editing surface for a tab, or null when the tab isn't in a synced session.\n * `enter()` flips the canonical lock to source (seeding the text from the flipper's serialization);\n * `leave()` reverts to structure-canonical when the last source editor departs. `text` is the real\n * Y.Text and `awareness` the connection's Awareness — exactly what y-monaco's MonacoBinding\n * consumes (it owns the awareness `selection` field while bound).\n */\nexport function collabSourceContext(tab: Tab): {\n text: unknown;\n awareness: CollabHandle[\"awareness\"];\n localOrigin: unknown;\n readOnly: boolean;\n enter: () => Promise<void>;\n leave: () => void;\n} | null {\n const session = runtimeOf(tab)?.session;\n if (!session?.synced) {\n return null;\n }\n const { collab, handle } = session;\n /* THIS CONTEXT'S CLAIM ON THE LOCK, and the reason a release needs one.\n One context object is handed to one mount, and `leave()` is called by that mount's cleanup —\n but the lock it releases is the SESSION's, shared by every mount this client makes. Toggling\n Code view off and on inside one round trip overlaps two of them, and the first one's cleanup\n handed back a lock the second one had just taken. The token is minted synchronously at\n `enter()` so the ordering is the order the surfaces were asked for, not the order two\n serializations happened to resolve in. */\n let claim: object | null = null;\n const holdsClaim = () => claim !== null && session.sourceLockOwner === claim;\n return {\n awareness: handle.awareness,\n enter: async () => {\n claim = {};\n session.sourceLockOwner = claim;\n const local = handle.awareness.getLocalState();\n if (local) {\n handle.awareness.setLocalState({ ...local, mode: \"source\" });\n }\n if (!session.canWrite) {\n return;\n }\n let serialized: string | null = null;\n if (_serialize) {\n try {\n serialized = await _serialize(tab);\n } catch {\n serialized = null;\n }\n }\n // Asked again across the await: a later mount owns the surface now, and seeding the shared\n // Text from THIS mount's serialization would push a stale document at the room.\n if (!holdsClaim()) {\n return;\n }\n collab.acquireSourceCanonical(\n handle.doc,\n serialized ?? collab.sourceText(handle.doc).toString(),\n collab.LOCAL_ORIGIN,\n );\n },\n leave: () => {\n // Not this mount's lock to hand back, and not its awareness state to reset either — the live\n // Mount is in source mode and says so.\n if (!holdsClaim()) {\n claim = null;\n return;\n }\n claim = null;\n session.sourceLockOwner = null;\n const local = handle.awareness.getLocalState();\n if (local) {\n handle.awareness.setLocalState({ ...local, mode: \"structure\" });\n }\n /* A client with no write access never reached `acquireSourceCanonical` above, so it holds\n nothing to hand back — and `releaseSourceCanonical` is itself a write to shared state,\n which the relay drops from a read-only socket anyway. The guard is right; it was never the\n asymmetry. See below for the one that was. */\n if (!session.canWrite) {\n return;\n }\n /* AND A READ-ONLY VIEWER MUST NOT COUNT AS SOMEONE STILL HOLDING THE LOCK.\n `otherSourceEditors` answers \"who else has Code view open\", per awareness, which is a\n different question from the one asked here: who else could be the reason not to release.\n A read-only guest publishes `mode: \"source\"` when they open Code view and then returns at\n the guard above — they can neither acquire the lock nor hand it back. Counted, they made\n the LAST WRITE-CAPABLE editor's departure release nothing, and their own departure release\n nothing: `meta.canonical` stayed `\"source\"` for the whole room, forever, and with the\n lock-holder exemption gone from the transact gate that is every client frozen out of every\n structural edit, with only the keyed \"structural edits are paused\" toast to explain it.\n The same `canWrite !== false` filter the reconciler election above uses, for the same\n reason: a client that cannot write cannot be the one holding a write. */\n const others = collab\n .otherSourceEditors(handle.awareness, session.path, handle.awareness.clientID)\n .filter((clientId) => {\n const peer = handle.awareness.getStates().get(clientId) as\n | { canWrite?: boolean }\n | undefined;\n return peer?.canWrite !== false;\n });\n if (others.length === 0) {\n // Freshen the structure mirror once more, then hand the lock back.\n void sourceParseNow(session).then(() => {\n collab.releaseSourceCanonical(handle.doc, collab.LOCAL_ORIGIN);\n });\n }\n },\n localOrigin: collab.LOCAL_ORIGIN,\n readOnly: !session.canWrite,\n text: collab.sourceText(handle.doc),\n };\n}\n\n/**\n * Whether this client is in `tab`'s session **without write access**.\n *\n * The single spelling of \"this tab cannot be saved by me\". A read-only client edits its local\n * reactive document freely — nothing blocks structural editing, and `transactDoc` still marks the\n * tab dirty — but `onTransact` gates BOTH `publishRecord` and `scheduleMirror` behind `canWrite`,\n * so those edits exist in this browser and nowhere else: not in the Y-doc, not on the relay, not on\n * disk. Every question that turns on \"is this work recoverable from somewhere?\" has to ask this\n * one, which is why it is exported rather than re-derived per caller.\n */\nexport function collabReadOnly(tab: Tab): boolean {\n const state = collabState(tab);\n return state.active && state.readOnly;\n}\n\n/**\n * Cmd+S for a collab tab: refresh the source mirror and ask the provider to persist now. Returns\n * false when the tab has no active session (caller saves through the file path as usual), and false\n * when this client cannot write to the session it does have.\n *\n * **The read-only `false` is the load-bearing one.** This used to skip `mirrorNow` for a read-only\n * client and then flush and return `true` anyway — flushing a Y-doc that had received none of the\n * edits, and reporting the result as a save. `saveFile` stamped \"Saved just now\" on it and the tab\n * strip's Save button closed the tab on top of work that was still only in the browser. Answering\n * `false` is the truth; `saveFile` is where the read-only tab is refused outright, so this never\n * becomes a licence to write the file behind the room's back.\n */\nexport async function collabSave(tab: Tab): Promise<boolean> {\n const session = runtimeOf(tab)?.session;\n if (!session?.synced || !session.canWrite) {\n return false;\n }\n if (session.mirrorTimer) {\n clearTimeout(session.mirrorTimer);\n session.mirrorTimer = null;\n }\n await mirrorNow(session);\n await session.handle.flush();\n return true;\n}\n\n/** Refresh mirrors and flush every active session (call before commits). */\nexport async function flushAllCollab(): Promise<void> {\n for (const tab of liveTabs) {\n const session = runtimeOf(tab)?.session;\n if (session?.synced) {\n await collabSave(tab);\n }\n }\n}\n\n// ─── Attach / detach ─────────────────────────────────────────────────────────\n\n/** Tabs with installed watchers (module-scoped so flushAllCollab can walk them). */\nconst liveTabs = new Set<Tab>();\n\n/**\n * Idempotently wire collaboration for a tab. Installs a per-tab watcher that attaches a session for\n * the tab's file unless the author has opted out, and tears everything down when the tab's scope is\n * disposed.\n *\n * The watcher used to carry a second condition — detach while the tab is \"drilled into\" a\n * sub-document — guarding a `session.documentStack` that nothing could ever push onto. It never\n * fired, and a tab holds one document now: drilling in opens a tab of its own, which gets its own\n * watcher for its own file.\n *\n * **`project.json` is out of replication.** It is the one document whose edits arrive from surfaces\n * that are not the canvas — every settings form, the imports panel, the deploy flow — and whose\n * value the studio ITSELF reads to configure formats, extensions, schemas and the style cascade. A\n * shared Y.Doc over it would mean a peer's extension list reconfiguring your editor mid-keystroke,\n * and the source-canonical freeze would pause configuration edits that have nothing to do with\n * text. Returning here is the whole gate: no session is attached, so `setHistoryDelegate` is never\n * called for this tab and its history stays the local op log `tabs/project-config.ts` transacts\n * on.\n */\nexport function ensureCollab(tab: Tab): void {\n const platform = maybePlatform();\n if (!platform?.collab || !tab.documentPath || tab.documentPath === PROJECT_CONFIG_PATH) {\n return;\n }\n const runtime = runtimeFor(tab);\n if (runtime.watcherInstalled) {\n return;\n }\n runtime.watcherInstalled = true;\n installGlobalHooks();\n liveTabs.add(tab);\n tab.scope.run(() => {\n effect(() => {\n if (runtime.optedOut.value) {\n detachSession(tab);\n } else {\n void attachSession(tab);\n }\n });\n onScopeDispose(() => {\n liveTabs.delete(tab);\n detachSession(tab);\n });\n });\n}\n\n/**\n * Join or leave this document's collaboration session — the idempotent setter behind `Collaborate:\n * Share this document` and `Collaborate: Stop sharing` (§7.4).\n *\n * Leaving sets a flag the watcher effect reads rather than calling `detachSession` directly, so the\n * effect remains the one owner of the session lifecycle and re-joining is the same call with the\n * other value. Calling it twice with the same value does nothing, which is the property the\n * `app-commands` pairing test checks for.\n *\n * @param {Tab} tab @param {boolean} enabled\n */\nexport function setCollabEnabled(tab: Tab, enabled: boolean): void {\n const runtime = runtimeFor(tab);\n if (runtime.optedOut.value === !enabled) {\n return;\n }\n runtime.optedOut.value = !enabled;\n if (!runtime.watcherInstalled && enabled) {\n ensureCollab(tab);\n }\n}\n\n/** True while the user has not opted this tab out of collaboration. */\nexport function isCollabEnabled(tab: Tab): boolean {\n return runtimeOf(tab)?.optedOut.value !== true;\n}\n\n/** Re-key after a file rename: tear down and re-attach against the new path. */\nexport function rekeyCollab(tab: Tab): void {\n const runtime = runtimeOf(tab);\n if (!runtime?.watcherInstalled) {\n ensureCollab(tab);\n return;\n }\n detachSession(tab);\n void attachSession(tab);\n}\n\nasync function attachSession(tab: Tab): Promise<void> {\n const runtime = runtimeFor(tab);\n if (runtime.session || runtime.attaching) {\n return;\n }\n const { documentPath: path } = tab;\n const platform = maybePlatform();\n if (!path || !platform?.collab) {\n /* Not a failure and not a session: this build/platform has no collaboration to offer. Saying\n so is the difference between \"nobody else is here\" and \"something broke\" (§7.4). */\n collabState(tab).status = \"unavailable\";\n return;\n }\n const { generation } = runtime;\n const state = collabState(tab);\n state.status = \"connecting\";\n state.attachError = \"\";\n const attempt = (async () => {\n try {\n const [collab, handle] = await Promise.all([loadCollab(), platform.collab!(path)]);\n if (!handle) {\n // The platform offers collaboration; this document is simply not shared. Solo, not broken.\n state.status = \"detached\";\n return;\n }\n if (runtime.generation !== generation) {\n handle.destroy();\n return;\n }\n let timer: ReturnType<typeof setTimeout> | null = null;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"collab-sync-timeout\")), SYNC_TIMEOUT_MS);\n });\n try {\n await Promise.race([handle.whenSynced, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n if (runtime.generation !== generation) {\n handle.destroy();\n return;\n }\n runtime.session = createSession(tab, path, collab, handle);\n state.active = true;\n state.status = \"synced\";\n state.readOnly = !runtime.session.canWrite;\n state.attachError = \"\";\n registerCollabPath(path);\n } catch (error) {\n /* An attach that threw is a FAILURE, and it used to be reported as \"detached\" — the same\n value a solo document carries. A relay that is down, a token that expired and a document\n nobody shared were one indistinguishable state (§7.4). */\n state.status = \"failed\";\n state.active = false;\n state.attachError = error instanceof Error ? error.message : String(error);\n notify.warn(`Live collaboration is not available for \"${path}\" — ${state.attachError}`, {\n key: `collab:${path}`,\n path,\n source: \"Collaboration\",\n });\n } finally {\n runtime.attaching = null;\n }\n })();\n runtime.attaching = attempt;\n await attempt;\n}\n\nfunction detachSession(tab: Tab): void {\n const runtime = runtimeOf(tab);\n if (!runtime) {\n return;\n }\n runtime.generation += 1;\n const { session } = runtime;\n runtime.session = null;\n const state = collabState(tab);\n state.active = false;\n state.status = \"detached\";\n state.attachError = \"\";\n state.peers = [];\n if (!session) {\n return;\n }\n unregisterCollabPath(session.path);\n if (session.mirrorTimer) {\n clearTimeout(session.mirrorTimer);\n }\n if (session.sourceParseTimer) {\n clearTimeout(session.sourceParseTimer);\n }\n for (const dispose of session.disposers) {\n try {\n dispose();\n } catch {\n // Disposal is best-effort; the handle teardown below is what matters.\n }\n }\n setHistoryDelegate(tab, null);\n // Re-base the op-log history on the current document for solo editing.\n tab.history.snapshots = [\n {\n document: jsonClone(toRaw(tab.doc.document)) as Record<string, unknown>,\n selection: cloneSelection(tab.session.selection),\n },\n ];\n tab.history.index = 0;\n session.undoManager?.destroy();\n session.handle.destroy();\n}\n\nfunction createSession(\n tab: Tab,\n path: string,\n collab: CollabModule,\n handle: CollabHandle,\n): ActiveSession {\n const identity = handle.identity();\n const session: ActiveSession = {\n applyingRemoteFrontmatter: false,\n batchNeedsDiff: false,\n batchOps: null,\n canWrite: identity ? identity.permission !== \"read\" : true,\n collab,\n disposers: [],\n handle,\n lastSeenRef: toRaw(tab.doc.document) as object,\n mirrorTimer: null,\n path,\n sourceLockOwner: null,\n sourceParseTimer: null,\n synced: false,\n tab,\n undoManager: null,\n };\n\n // Initial reconcile: first client seeds structure from the parsed doc; later clients adopt the\n // Shared tree when it differs from their local parse.\n const meta = collab.metaMap(handle.doc);\n if (meta.get(\"structureSeeded\") === true) {\n const yJson = collab.yDocToJson(handle.doc);\n const tabJson = jsonClone(toRaw(tab.doc.document)) as JxMutableNode;\n if (!collab.deepEqual(yJson, tabJson)) {\n const ops = collab.diffDocs(tabJson, yJson);\n if (ops === null) {\n session.synced = true;\n reconcileTabFromY(session);\n session.synced = false;\n } else if (ops.length > 0) {\n applyExternalDocOps(tab, ops);\n }\n }\n session.applyingRemoteFrontmatter = true;\n const sharedFrontmatter = collab.frontmatterMap(handle.doc);\n for (const [key, value] of sharedFrontmatter.entries()) {\n tab.doc.content.frontmatter[key] = value as never;\n }\n session.applyingRemoteFrontmatter = false;\n } else if (session.canWrite) {\n collab.seedStructure(handle.doc, jsonClone(toRaw(tab.doc.document)) as JxMutableNode, {\n frontmatter: jsonClone(toRaw(tab.doc.content.frontmatter)),\n origin: collab.SEED_ORIGIN,\n sourceFormat: tab.doc.sourceFormat,\n });\n }\n session.lastSeenRef = toRaw(tab.doc.document) as object;\n\n // The server owns the room-level unsaved state: `onDirty` fires synchronously with the current\n // Value on subscribe (delivered during the open handshake), so attaching to a clean room clears\n // Any dirty the initial reconcile set, and attaching to an already-dirty room shows dirty.\n session.disposers.push(\n handle.onDirty((dirty) => {\n tab.doc.dirty = dirty;\n }),\n );\n\n // Presence identity + write capability (drives reconciler election).\n handle.awareness.setLocalState({\n canWrite: session.canWrite,\n focusedPath: path,\n structuralSelection: null,\n user: identity\n ? {\n avatarUrl: identity.avatarUrl,\n color: identity.color,\n login: identity.login,\n name: identity.name,\n }\n : {\n color: collab.colorForKey(String(handle.awareness.clientID)),\n login: `guest-${handle.awareness.clientID % 1000}`,\n },\n });\n\n // Undo: local-origin-scoped Y.UndoManager replaces the op-log while attached.\n const undoManager = new collab.UndoManager(\n [collab.structureMap(handle.doc), collab.frontmatterMap(handle.doc)],\n { trackedOrigins: new Set([collab.LOCAL_ORIGIN]) },\n );\n session.undoManager = undoManager;\n const onStackAdd = ({ stackItem }: { stackItem: { meta: Map<unknown, unknown> } }) => {\n stackItem.meta.set(\"selection\", cloneSelection(tab.session.selection));\n };\n const onStackPop = ({ stackItem }: { stackItem: { meta: Map<unknown, unknown> } }) => {\n const selection = stackItem.meta.get(\"selection\") as (string | number)[][] | undefined;\n tab.session.selection = cloneSelection(selection ?? []);\n };\n undoManager.on(\"stack-item-added\", onStackAdd);\n undoManager.on(\"stack-item-popped\", onStackPop);\n session.disposers.push(() => {\n undoManager.off(\"stack-item-added\", onStackAdd);\n undoManager.off(\"stack-item-popped\", onStackPop);\n });\n setHistoryDelegate(tab, {\n canRedo: () => undoManager.canRedo(),\n canUndo: () => undoManager.canUndo(),\n redo: () => {\n undoManager.redo();\n },\n undo: () => {\n undoManager.undo();\n },\n });\n\n // Inbound: remote structure transactions → JxDocOps → the surgical pipeline.\n const structure = collab.structureMap(handle.doc);\n const structureObserver = (events: unknown, transaction: { origin: unknown }) => {\n if (transaction.origin === collab.LOCAL_ORIGIN || !session.synced) {\n return;\n }\n const ops = collab.yEventsToDocOps(events as never);\n if (ops === null) {\n reconcileTabFromY(session);\n return;\n }\n if (ops.length === 0) {\n return;\n }\n try {\n applyExternalDocOps(tab, ops);\n } catch {\n reconcileTabFromY(session);\n }\n };\n structure.observeDeep(structureObserver);\n session.disposers.push(() => structure.unobserveDeep(structureObserver));\n\n // The canonical-representation lock: while source holds it, structural surfaces soft-freeze\n // (Transact gate) and the source reconciler's parses arrive as MIRROR-origin structure changes.\n const tabState = collabState(tab);\n tabState.sourceCanonical = collab.canonicalOf(handle.doc) === \"source\";\n const lockMeta = collab.metaMap(handle.doc);\n const lockObserver = () => {\n tabState.sourceCanonical = collab.canonicalOf(handle.doc) === \"source\";\n };\n lockMeta.observe(lockObserver);\n session.disposers.push(() => lockMeta.unobserve(lockObserver));\n\n // The source reconciler (lowest write clientID in source mode) parses Y.Text back into the\n // Structure tree on a debounce, so every client's canvas previews source edits live.\n const source = collab.sourceText(handle.doc);\n const sourceObserver = (_event: unknown, transaction: { origin: unknown }) => {\n if (transaction.origin === collab.MIRROR_ORIGIN || !session.synced) {\n return;\n }\n if (collab.canonicalOf(handle.doc) !== \"source\") {\n return;\n }\n if (!collab.isSourceReconciler(handle.awareness, session.path)) {\n return;\n }\n if (session.sourceParseTimer) {\n clearTimeout(session.sourceParseTimer);\n }\n session.sourceParseTimer = setTimeout(() => {\n session.sourceParseTimer = null;\n void sourceParseNow(session);\n }, 600);\n };\n source.observe(sourceObserver as never);\n session.disposers.push(() => source.unobserve(sourceObserver as never));\n\n // Inbound frontmatter (per-field).\n const frontmatter = collab.frontmatterMap(handle.doc);\n const frontmatterObserver = (\n event: { changes: { keys: Map<string, { action: string }> }; target: unknown },\n transaction: { origin: unknown },\n ) => {\n if (transaction.origin === collab.LOCAL_ORIGIN || !session.synced) {\n return;\n }\n session.applyingRemoteFrontmatter = true;\n try {\n for (const [key, change] of event.changes.keys) {\n if (change.action === \"delete\") {\n delete tab.doc.content.frontmatter[key];\n } else {\n tab.doc.content.frontmatter[key] = frontmatter.get(key) as never;\n }\n }\n } finally {\n session.applyingRemoteFrontmatter = false;\n }\n };\n frontmatter.observe(frontmatterObserver as never);\n session.disposers.push(() => frontmatter.unobserve(frontmatterObserver as never));\n\n // Outbound frontmatter: mutateUpdateFrontmatter bypasses transactDoc, so watch the map deeply.\n tab.scope.run(() => {\n let lastJson = JSON.stringify(tab.doc.content.frontmatter);\n effect(() => {\n const json = JSON.stringify(tab.doc.content.frontmatter);\n if (json === lastJson) {\n return;\n }\n lastJson = json;\n if (session.applyingRemoteFrontmatter || !session.synced || !session.canWrite) {\n return;\n }\n const local = JSON.parse(json) as Record<string, unknown>;\n handle.doc.transact(() => {\n // Detached copy: keys are deleted while iterating.\n const sharedKeys = [...frontmatter.keys()];\n for (const key of sharedKeys) {\n if (!(key in local)) {\n frontmatter.delete(key);\n }\n }\n for (const [key, value] of Object.entries(local)) {\n if (!collab.deepEqual(frontmatter.get(key), value)) {\n frontmatter.set(key, value);\n }\n }\n }, collab.LOCAL_ORIGIN);\n scheduleMirror(session);\n });\n\n // Publish the local structural selection for remote canvas overlays (peers filter by\n // FocusedPath, so per-doc boxes come free from the one project-level awareness state). The\n // Plain `selection` field is y-monaco's (in-buffer text cursors) — never write it here.\n effect(() => {\n // The whole selection SET crosses awareness, so a peer's canvas draws every node the author\n // Has selected. A selection of one publishes a one-entry list, which is the same box.\n // Empty stays `null` rather than `[]`: \"this peer is not pointing at anything\" is one fact\n // With one wire value, and every consumer already tests it by presence.\n const structuralSelection =\n tab.session.selection.length > 0 ? cloneSelection(tab.session.selection) : null;\n const local = handle.awareness.getLocalState();\n if (local) {\n handle.awareness.setLocalState({ ...local, structuralSelection });\n }\n });\n\n // Bypass-write net: any doc root swap that did not come through transactDoc (Monaco parse\n // Flush) reconciles by diff. Deferred one microtask so the transact observer marks its own\n // Refs first (the assignment happens mid-transaction, before the observer runs).\n effect(() => {\n const ref = toRaw(tab.doc.document) as object;\n queueMicrotask(() => {\n const current = runtimeOf(tab)?.session;\n if (current !== session || !session.synced || !session.canWrite) {\n return;\n }\n const nowRef = toRaw(tab.doc.document) as object;\n if (nowRef !== ref || nowRef === session.lastSeenRef) {\n return;\n }\n session.lastSeenRef = nowRef;\n publishDiff(session);\n scheduleMirror(session);\n // Dirty stays as the edit left it; the server's doc-dirty broadcast is authoritative.\n });\n });\n });\n\n // Presence roster + status.\n const state = collabState(tab);\n const awarenessObserver = () => {\n const peers: { clientId: number; state: never }[] = [];\n for (const [clientId, peerState] of handle.awareness.getStates()) {\n if (clientId !== handle.awareness.clientID && peerState[\"user\"]) {\n peers.push({ clientId, state: peerState as never });\n }\n }\n state.peers = peers;\n };\n awarenessObserver();\n handle.awareness.on(\"change\", awarenessObserver);\n session.disposers.push(\n () => handle.awareness.off(\"change\", awarenessObserver),\n handle.onStatus((status) => {\n if (status === \"offline\" || status === \"connecting\") {\n state.status = \"offline\";\n } else if (session.synced) {\n state.status = \"synced\";\n }\n }),\n handle.onReset(() => {\n // The server replaced this doc's history: drop the session and re-attach fresh.\n detachSession(tab);\n void attachSession(tab);\n }),\n );\n\n session.synced = true;\n return session;\n}\n",
|
|
27
|
+
"/**\n * Command-args.ts — loud coercion for the arguments a command record declares.\n *\n * Every scriptable command carries an `args` JSON Schema (spec §13.1, plan §13.3): the palette\n * prompts from it, the AI tool's parameters are it, and `scripts/check-shot-contract.ts` validates\n * every manifest step against it in the `checks` job. This module is the RUNTIME half of that same\n * declaration — the four lines inside `run` that turn `Record<string, unknown>` into the typed\n * value the implementation wants.\n *\n * Two rules, and they are the reason this is a module rather than twelve copies of `String(x)`:\n *\n * 1. **Reject loudly, never clamp.** An unknown panel id, a mode the tab cannot enter, a selection\n * path that is not in the document — each throws. A no-op would photograph the previous state\n * and a docs build would accept it; a clamp would photograph a state the caller did not ask for.\n * Plan §13.4 makes this a tested property.\n * 2. **The failure names the fix.** `{@link enumArg}` prints the declared values, which is what makes\n * §13.5's headline failure — _manifest shot \"properties-bar\" names panel \"head\"; the registry\n * declares \"page\"_ — a sentence a reader can act on rather than a stack trace. Nothing else in\n * this file matters as much as that message.\n *\n * `RangeError` (not a bespoke class) because `services/profile.ts` already throws it for exactly\n * this — an id outside a declared set — and one refusal shape is easier to catch than two.\n */\n\n/** Arguments as they arrive from a palette prompt, a manifest step or an AI tool call. */\nexport type CommandArgValues = Record<string, unknown>;\n\n/** `command \"<id>\" argument \"<key>\": <problem>` — the one sentence shape every failure here uses. */\nfunction refuse(commandId: string, key: string, problem: string): RangeError {\n return new RangeError(`command \"${commandId}\" argument \"${key}\": ${problem}`);\n}\n\n/** How a received value is quoted back to the caller. Strings keep their quotes; nothing is elided. */\nfunction describe(value: unknown): string {\n if (value === undefined) {\n return \"missing\";\n }\n return typeof value === \"string\" ? `\"${value}\"` : `${typeof value} ${JSON.stringify(value)}`;\n}\n\n/** A required string argument. */\nexport function stringArg(commandId: string, args: CommandArgValues, key: string): string {\n const value = args[key];\n if (typeof value !== \"string\" || value === \"\") {\n throw refuse(commandId, key, `expected a non-empty string, got ${describe(value)}`);\n }\n return value;\n}\n\n/** An optional string argument — `undefined` when absent, never coerced from another type. */\nexport function optionalStringArg(\n commandId: string,\n args: CommandArgValues,\n key: string,\n): string | undefined {\n if (args[key] === undefined) {\n return undefined;\n }\n return stringArg(commandId, args, key);\n}\n\n/** A required finite number argument. `NaN` and `Infinity` are refusals, not values. */\nexport function numberArg(commandId: string, args: CommandArgValues, key: string): number {\n const value = args[key];\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw refuse(commandId, key, `expected a finite number, got ${describe(value)}`);\n }\n return value;\n}\n\n/**\n * A required number argument inside a closed interval.\n *\n * REJECTS out of range rather than clamping, which is the difference between a shot that fails and\n * a shot that photographs 500% when it asked for 1000% — the second is a wrong picture the docs\n * build accepts. The interactive controls still clamp: dragging a slider past its end is a gesture\n * with an obvious meaning, whereas a caller naming a number outside the range is stating something\n * untrue about the app.\n */\nexport function boundedNumberArg(\n commandId: string,\n args: CommandArgValues,\n key: string,\n minimum: number,\n maximum: number,\n): number {\n const value = numberArg(commandId, args, key);\n if (value < minimum || value > maximum) {\n throw refuse(commandId, key, `${value} is outside the supported range ${minimum}–${maximum}`);\n }\n return value;\n}\n\n/** A required boolean argument. A setter's whole point is that `false` is a value, so no default. */\nexport function booleanArg(commandId: string, args: CommandArgValues, key: string): boolean {\n const value = args[key];\n if (typeof value !== \"boolean\") {\n throw refuse(commandId, key, `expected a boolean, got ${describe(value)}`);\n }\n return value;\n}\n\n/**\n * A required argument drawn from a declared set.\n *\n * The `declared:` clause is the point — see the module header. It is printed in full rather than\n * truncated: these sets are panel ids and tab ids, never long enough to be a wall, and a reader\n * comparing a stale id against the current list needs the whole list.\n */\nexport function enumArg<T extends string>(\n commandId: string,\n args: CommandArgValues,\n key: string,\n declared: readonly T[],\n): T {\n const value = args[key];\n if (typeof value !== \"string\" || !(declared as readonly string[]).includes(value)) {\n throw refuse(\n commandId,\n key,\n `${describe(value)} is not declared — declared: ${declared.join(\", \")}`,\n );\n }\n return value as T;\n}\n\n/**\n * A document path (`JxPath`) argument: an array of strings and numbers.\n *\n * The empty array is the document root and therefore VALID — `selection.set { path: [] }` is how a\n * shot selects the root element, and treating `[]` as \"no path\" would silently deselect instead.\n */\nexport function pathArg(\n commandId: string,\n args: CommandArgValues,\n key: string,\n): (string | number)[] {\n const value = args[key];\n if (\n !Array.isArray(value) ||\n !value.every((s) => typeof s === \"string\" || typeof s === \"number\")\n ) {\n throw refuse(\n commandId,\n key,\n `expected an array of path segments (strings or numbers), got ${describe(value)}`,\n );\n }\n return value as (string | number)[];\n}\n\n/** A path argument that may be `null` — \"select nothing\" is a state a user can be in. */\nexport function nullablePathArg(\n commandId: string,\n args: CommandArgValues,\n key: string,\n): (string | number)[] | null {\n if (args[key] === null) {\n return null;\n }\n return pathArg(commandId, args, key);\n}\n\n/**\n * A LIST of document paths — the whole selection set (§6.5).\n *\n * Every element is validated as a path, so a caller that passes one bare path by mistake\n * (`[\"children\", 0]` rather than `[[\"children\", 0]]`) is refused by name instead of selecting two\n * nodes called \"children\" and \"0\". `[]` is legal and means \"select nothing\", which is the same\n * thing `selection.set { path: null }` means.\n */\nexport function pathListArg(\n commandId: string,\n args: CommandArgValues,\n key: string,\n): (string | number)[][] {\n const value = args[key];\n if (!Array.isArray(value)) {\n throw refuse(commandId, key, `expected an array of document paths, got ${describe(value)}`);\n }\n return value.map((entry, i) => {\n if (\n !Array.isArray(entry) ||\n !entry.every((s) => typeof s === \"string\" || typeof s === \"number\")\n ) {\n throw refuse(\n commandId,\n key,\n `entry ${i} is not a document path — expected an array of segments, got ${describe(entry)}`,\n );\n }\n return entry as (string | number)[];\n });\n}\n\n// ─── Schema fragments ─────────────────────────────────────────────────────────\n// The declarations above are enforced at RUN time; these are the same facts in the form the palette\n// Prompt, the AI tool's parameter list and Lane 1's static check read. Keeping the pair adjacent is\n// Deliberate: a schema that disagrees with its coercion is the defect this module exists to prevent.\n\n/** `{ type: \"object\", properties, required, additionalProperties: false }` in one call. */\nexport function argsSchema(\n properties: Record<string, object>,\n required: readonly string[] = Object.keys(properties),\n): object {\n return {\n additionalProperties: false,\n properties,\n required: [...required],\n type: \"object\",\n };\n}\n\n/** A string property constrained to a declared set, with the human sentence the palette shows. */\nexport function enumProperty(declared: readonly string[], description: string): object {\n return { description, enum: [...declared], type: \"string\" };\n}\n\n/** A number property, optionally bounded — the bounds a control already enforces, written down. */\nexport function numberProperty(\n description: string,\n bounds: { minimum?: number; maximum?: number } = {},\n): object {\n return { description, type: \"number\", ...bounds };\n}\n\n/** A boolean property. Named `open`/`enabled`/… by the caller; the description carries the sense. */\nexport function booleanProperty(description: string): object {\n return { description, type: \"boolean\" };\n}\n\n/** A `JxPath` property — an array of string keys and numeric indexes. */\nexport function pathProperty(description: string, nullable = false): object {\n const path = {\n items: { type: [\"string\", \"number\"] },\n type: \"array\",\n };\n return nullable ? { description, oneOf: [path, { type: \"null\" }] } : { description, ...path };\n}\n\n/** A property holding a LIST of `JxPath`s — an array of arrays of segments. */\nexport function pathListProperty(description: string): object {\n return {\n description,\n items: { items: { type: [\"string\", \"number\"] }, type: \"array\" },\n type: \"array\",\n };\n}\n\n/** A free-form string property. */\nexport function stringProperty(description: string): object {\n return { description, type: \"string\" };\n}\n",
|
|
28
|
+
"import { computed, reactive, toRaw } from \"../reactivity\";\nimport { commitTabBuffers } from \"../services/monaco-buffer\";\nimport { ensureCollab, rekeyCollab } from \"../collab/collab-session\";\nimport { createTab, disposeTab } from \"../tabs/tab\";\nimport { projectState } from \"../state\";\nimport {\n argsSchema,\n booleanArg,\n booleanProperty,\n stringArg,\n stringProperty,\n} from \"../commands/command-args\";\nimport type { Tab, TabOrigin } from \"../tabs/tab\";\n\nimport type { ComponentEntry } from \"../files/components\";\nimport type { AnyCommand, CommandRegistry } from \"../commands/registry\";\nimport type { GitDiffState } from \"../types\";\nimport type { JxMutableNode, JxStyle } from \"@jxsuite/schema/types\";\nimport type { ComputedRef } from \"@vue/reactivity\";\n\ninterface FileEntry {\n name: string;\n path: string;\n type: string;\n}\n\n/** A tab that was closed, kept so `⌘⇧T` can bring it back. Only file-backed tabs qualify. */\nexport interface ClosedTabRecord {\n documentPath: string;\n}\n\n/** How many closed tabs `⌘⇧T` can walk back through. */\nconst CLOSED_TAB_LIMIT = 20;\n\n/**\n * One editor pane — the unit of split, focus and zoom (§4.1).\n *\n * A tab BELONGS to a pane, and the pane is what splits; the tab strip is per-pane for the same\n * reason. This is the minimal model P3 asks for: an ordered list and an active id, with no rules\n * for derived panes and no follow behaviour (those are P8).\n */\nexport interface Pane {\n id: string;\n /** Left-to-right order in this pane's strip. Pinned tabs occupy the head of it. */\n tabOrder: string[];\n activeTabId: string | null;\n /**\n * Non-null when this pane draws a projection of ANOTHER pane rather than a document of its own.\n *\n * The one field §18.4 needed, and the only place the derivation lives. Written by\n * `workspace/pane-derive.ts` and nothing else.\n */\n derived: PaneDerivation | null;\n}\n\n/**\n * What a derived pane is showing, and why it changes when the pane it derives from does.\n *\n * **Two families, because \"a projection of another pane's document\" turns out to be two mechanisms\n * with different identity consequences**, and conflating them is what made §18.4 look like it\n * violated §14.1.\n *\n * - A **lens** re-draws the SAME document its source pane is showing, in a different mode, at a\n * different breakpoint, or against a different diff. It owns NO tab: `tabOrder` is `[]` and\n * `activeTabId` is `null`, and `tabOfPane` hops through `sourcePaneId` to answer what it draws.\n * No id maps to two documents and no document takes two ids, so §14.1's identity rule is\n * untouched — what changes is only the unstated operational corollary that a tab lived in one\n * pane. Ownership stays one-to-one; DISPLAY becomes many-to-one.\n * - A **companion** shows a DIFFERENT document chosen by a rule from the source — the layout that\n * wraps its page, the component definition under its selection, the same page written in another\n * language. That is an ordinary path-keyed tab which this pane owns normally; the derivation only\n * decides WHICH of its tabs is on screen, which is what `activateTab` has always done.\n *\n * The split is also the answer to what Pin means: a companion can be pinned (it names a different\n * file), a lens cannot (a second tab for the source's own path IS the §14.1 violation) — its exit\n * is `pane.unsplit`.\n */\nexport type PaneDerivation =\n | {\n kind: \"lens\";\n sourcePaneId: string;\n preset: \"code\" | \"diff\" | \"breakpoint\";\n /** The canvas mode THIS pane draws the shared tab in. Never written onto the tab. */\n mode: string;\n /** `breakpoint` only: the media name, null for base. */\n media: string | null;\n /** `diff` only: this pane's OWN diff, never `shell.git.diffState`. */\n diff: GitDiffState | null;\n /**\n * This pane's own scale. `session.ui.zoom` is per-TAB, so under a lens the mobile view and\n * the desktop view it is a lens OF would zoom together.\n */\n zoom: number;\n status: DerivationStatus;\n /** Printed by the pane when `status` is `unavailable`. Empty otherwise. */\n reason: string;\n }\n | {\n kind: \"companion\";\n sourcePaneId: string;\n preset: \"layout\" | \"component\";\n /** The follow's memo: the path this derivation last resolved to. */\n resolved: string | null;\n status: DerivationStatus;\n reason: string;\n }\n /*\n * The `locale` companion is a THIRD member rather than a `locale: string | null` on the arm\n * above, because a locale is the one thing this preset cannot be without: `companionTarget` has\n * no answer at all for a locale derivation that names no locale, and a field every other\n * companion carries as `null` forever is a field the type system stops guarding. Narrowing on\n * `preset === \"locale\"` — which the resolver and the strip chip both already do to say anything\n * useful — is what makes the tag reachable, so nothing reads it without having asked which\n * preset this is.\n */\n | {\n kind: \"companion\";\n sourcePaneId: string;\n preset: \"locale\";\n /**\n * The canonical BCP 47 tag this pane holds. Null only while `pane.derive` was given none —\n * {@link presetRefusal} refuses that, and the pane says so rather than opening a file.\n */\n locale: string | null;\n /** The follow's memo: the path this derivation last resolved to. */\n resolved: string | null;\n status: DerivationStatus;\n reason: string;\n };\n\n/** Where a derivation is in its own lifecycle. `unavailable` DRAWS; it never collapses the pane. */\nexport type DerivationStatus = \"loading\" | \"ready\" | \"unavailable\";\n\nexport const PRIMARY_PANE = \"primary\";\n\nexport const SECONDARY_PANE = \"secondary\";\n\n/**\n * Two, and enforced.\n *\n * Not a UI preference and not a placeholder: every additional Canvas pane is a real\n * `@jxsuite/runtime` render, an `iframe-channel` connection and a structured clone of the resolved\n * document, all on one main thread. Two is a budget that was measured; three is a cliff.\n *\n * This is the ONE cap left. `SECONDARY_PANE_KINDS` used to sit beside it — Code, Diff, Config,\n * Entry, Grid, Library, the cheap kinds — because a second LIVE host was unaffordable while the\n * shell had one stage to hand between panes and one app-wide render generation to invalidate.\n * Neither is true: `canvas/surface-registry.ts` gives every pane its own panels, mode, pan, Monaco\n * and generation, and `panels/pane-grid.ts` gives every pane its own stage. A Canvas in the side\n * pane is now the same object the primary has always had, so the kind cap has nothing left to\n * protect and every predicate that read it is deleted with it — including the one that FLIPPED a\n * splitting Design tab to Code on its way across.\n */\nexport const MAX_PANES = 2;\n\nexport interface Workspace {\n projectRoot: string | null;\n projectConfig: object | null;\n componentRegistry: ComponentEntry[];\n clipboard: JxMutableNode | null;\n styleClipboard: JxStyle | null;\n fileTree: {\n dirs: Map<string, FileEntry[]>;\n expanded: Set<string>;\n selectedPath: string | null;\n searchQuery: string;\n };\n tabs: Map<string, Tab>;\n /** One or two panes, `panes[0]` always the primary. The pane grid, as data. */\n panes: Pane[];\n /** Which pane the keyboard and every \"the active document\" read resolve through. */\n activePaneId: string;\n /**\n * Most-recently-used order, newest first, ACROSS panes. `⌃Tab` walks this, NOT\n * {@link Pane.tabOrder} — \"the tab I was just in\" is the one people reach for, and it is rarely\n * the one to the left. Cycling onto a tab in the other pane focuses that pane too.\n */\n mruOrder: string[];\n /** Newest first. `⌘⇧T` pops this. */\n closedTabs: ClosedTabRecord[];\n ui: { activityBar: string };\n /**\n * The focused pane's strip order.\n *\n * A derived read, not a second store: with panes, \"the workspace's tab order\" can only mean the\n * order of the pane you are in. Assigning to it is a type error on purpose — every write goes\n * through a pane.\n */\n readonly tabOrder: readonly string[];\n /** The focused pane's active tab. Derived from {@link Workspace.panes} for the same reason. */\n readonly activeTabId: string | null;\n}\n\n// Annotated as Workspace: Vue's UnwrapNestedRefs cannot terminate on the\n// Recursive document types, and reactive() does not unwrap refs we never use.\nexport const workspace: Workspace = reactive({\n activePaneId: PRIMARY_PANE,\n clipboard: null as JxMutableNode | null,\n closedTabs: [] as ClosedTabRecord[],\n componentRegistry: [] as ComponentEntry[],\n mruOrder: [] as string[],\n fileTree: {\n dirs: new Map<string, FileEntry[]>(),\n expanded: new Set<string>(),\n searchQuery: \"\",\n selectedPath: null as string | null,\n },\n panes: [\n {\n activeTabId: null as string | null,\n derived: null as PaneDerivation | null,\n id: PRIMARY_PANE,\n tabOrder: [] as string[],\n },\n ],\n projectConfig: null as object | null,\n projectRoot: null as string | null,\n styleClipboard: null as JxStyle | null,\n tabs: new Map<string, Tab>(),\n ui: {\n activityBar: \"files\",\n },\n // The two derived reads. Defined as getters on the object reactive() wraps, so a consumer that\n // Reads `workspace.activeTabId` inside an effect tracks `panes` and `activePaneId` — the same\n // Dependency it used to have on the field these replace, with no second source of truth.\n get activeTabId(): string | null {\n /* THE LENS HOP, and it is here rather than at any reader because this getter is the only\n thing that can observe an un-hopped `activePane().activeTabId` (its two other readers are\n both inside this object literal).\n\n Without it, focusing a lens pane makes `activeTab.value` null and the Inspector, the\n toolbar, ⌘S, undo and every `ctx.document.open` print \"no document\" over a stage that is\n visibly drawing one — §18.1 rule 1's exact recorded failure, mintable by one click. A lens\n has no document of its own, so \"the document I am in\" is the source pane's; ⌘W in a focused\n lens pane therefore closes that document, which is coherent and collapses the lens. */\n const pane = activePane();\n return pane.derived?.kind === \"lens\"\n ? (paneById(pane.derived.sourcePaneId)?.activeTabId ?? null)\n : pane.activeTabId;\n },\n get tabOrder(): readonly string[] {\n return activePane().tabOrder;\n },\n}) as unknown as Workspace;\n\nexport const activeTab = computed(() =>\n workspace.activeTabId ? (workspace.tabs.get(workspace.activeTabId) ?? null) : null,\n) as unknown as ComputedRef<Tab | null>;\n\n// ─── Panes ────────────────────────────────────────────────────────────────────\n\n/**\n * The focused pane. Never null: `panes[0]` is created with the store and is never removed, so\n * \"where am I\" always has an answer even with no project open.\n *\n * @returns {Pane}\n */\nexport function activePane(): Pane {\n const { panes } = workspace;\n return panes.find((pane) => pane.id === workspace.activePaneId) ?? panes[0]!;\n}\n\n/**\n * @param {string} paneId\n * @returns {Pane | undefined}\n */\nexport function paneById(paneId: string): Pane | undefined {\n return workspace.panes.find((pane) => pane.id === paneId);\n}\n\n/**\n * The pane holding `tabId`, or undefined when no pane does.\n *\n * @param {string} tabId\n * @returns {Pane | undefined}\n */\nexport function paneOfTab(tabId: string): Pane | undefined {\n return workspace.panes.find((pane) => pane.tabOrder.includes(tabId));\n}\n\n/**\n * Move focus to a pane. A no-op for an id no pane carries, so a stale persisted layout cannot\n * strand the keyboard in a pane that is not there.\n *\n * **And a no-op for the pane that already has it**, which is what makes it safe to call on every\n * pointerdown. Moving focus is not only the `activePaneId` write — Vue skips that one when the\n * value is unchanged — it is also `resetTabCycle` (which abandons a live ⌘-Tab walk), `promoteMru`\n * (which rewrites the MRU order every ⌘-Tab reads) and `syncTreeSelection` (which moves the\n * Library's cursor). Running those on a click that changed nothing would make every click in the\n * focused pane a small act of state destruction, so the guard is HERE rather than at the call site:\n * this is the module that owns focus, and a caller holding a `paneId` may not ask which pane has it\n * (`scripts/check-pane-singletons.ts` rule 4).\n *\n * @param {string} paneId\n */\nexport function focusPane(paneId: string) {\n const pane = paneById(paneId);\n if (!pane || pane.id === workspace.activePaneId) {\n return;\n }\n workspace.activePaneId = pane.id;\n resetTabCycle();\n const { activeTabId } = pane;\n if (activeTabId) {\n promoteMru(activeTabId);\n const tab = workspace.tabs.get(activeTabId);\n if (tab) {\n syncTreeSelection(tab);\n }\n }\n}\n\n/**\n * Whether `paneId` is the pane the keyboard is in.\n *\n * A one-line predicate that exists so a pane-scoped renderer can DRAW the focus without READING it.\n * `panels/tab-strip.ts` is the case: its strip carries a `focused` class, so \"which pane has focus\"\n * is genuinely part of what it paints — but it is handed a pane, and\n * `scripts/check-pane-singletons.ts` rule 4 (rightly) refuses `pane.id === workspace.activePaneId`\n * inside a function that was told which pane it is about. Asking the module that OWNS focus is the\n * distinction the rule is drawing: a surface may render the answer, it may not resolve its subject\n * from it.\n *\n * @param {string} paneId\n * @returns {boolean}\n */\nexport function isPaneFocused(paneId: string): boolean {\n return workspace.activePaneId === paneId;\n}\n\n/** Focus the pane that is not the focused one, when there is one. */\nexport function focusOtherPane() {\n const other = workspace.panes.find((pane) => pane.id !== workspace.activePaneId);\n if (other) {\n focusPane(other.id);\n }\n}\n\n/*\n * There is no `paneCanHostKind`, no `canOpenInSecondPane`, no `hostableKindsOf`, no\n * `paneOfTabCanHostMode` and no `capToPaneKind`.\n *\n * Five predicates, one cap: \"a pane other than the primary may only host Code, Diff, Config, Entry,\n * Grid or Library\". Two of them enforced it (the split, and every later write of\n * `session.ui.canvasMode`), one picked the replacement kind, and two narrowed what the controls\n * offered so no dropdown could contain an entry the app would refuse.\n *\n * The cap existed because a second LIVE canvas host was unaffordable, and it is gone because\n * workstream 1 made it affordable — see {@link MAX_PANES}. Its LAST act was a bug: `capToPaneKind`\n * flipped a splitting Design tab to `source` before focus moved, so `⌘\\` on a page you were\n * designing silently became \"open this as Code somewhere else\".\n *\n * What replaces them is `tabs/tab.ts`'s `editorKindsOf` — the kinds a DOCUMENT declares — which is\n * the only narrowing left and the only one that was ever about the document rather than about what\n * the shell could afford to draw.\n */\n\n/**\n * Split the grid and move the focused tab into the new pane, which becomes focused.\n *\n * Moves rather than duplicates: one tab is one document with one undo history and one collab\n * session, and two strips claiming the same id is the duplicate-`repeat`-key bug §4.3 describes.\n *\n * @returns {Pane | null} The pane the tab landed in, or null when the split was refused\n */\nexport function splitRight(): Pane | null {\n const source = activePane();\n const tabId = source.activeTabId;\n const tab = tabId ? workspace.tabs.get(tabId) : null;\n if (!tabId || !tab) {\n return null;\n }\n /* The tab moves AS IT IS. `capToPaneKind` used to run here and rewrite `session.ui.canvasMode`\n when the target pane could not host the tab's kind — which, for a Design tab, meant `⌘\\`\n silently reopened your page as Code in the pane you had just made. Both panes host every kind\n now, so a split is a move and nothing else. */\n const target = receivingPane();\n detachTab(tabId);\n insertIntoPane(target, tabId);\n /* Focus moves LAST, and every write above went through {@link addPane}'s reactive record.\n Publishing the focus first made the pane observable while it still showed nothing: the\n `activeTab` computed re-ran, cached null, and the jump bar, the Inspector and the toolbar all\n printed \"no document\" over a stage that was drawing one. The write that should have corrected\n them notified nobody, because it went through the raw literal this used to push. */\n target.activeTabId = tabId;\n workspace.activePaneId = target.id;\n resetTabCycle();\n promoteMru(tabId);\n return target;\n}\n\n/**\n * The pane BESIDE the focused one, created if the grid has only one.\n *\n * The `existing ?? addPane(SECONDARY_PANE)` shape {@link splitRight} has always used, named because\n * three callers now want it: the split, `pane.compareWith` and `pane.derive`. Unlike `splitRight`\n * it moves NOTHING — \"give me the other pane\" and \"send my document to it\" are two requests, and\n * only the split makes both.\n *\n * `SECONDARY_PANE` unconditionally, and it is free unconditionally: {@link closePane} refuses to\n * remove the primary, so \"there is no other pane\" can only mean the grid is exactly `[primary]` and\n * the focused pane is that primary. This used to be `existing?.id ?? SECONDARY_PANE` handed\n * straight to `addPane` with no check that the id was free — which, on a grid of `[\"secondary\"]`,\n * pushed a SECOND record under that id and gave lit's keyed `repeat` a duplicate key. Both ends are\n * closed: the state is unreachable, and {@link addPane} would not mint the duplicate even if it\n * were. {@link MAX_PANES} is therefore satisfied by construction — there are two ids in play.\n *\n * @returns {Pane}\n */\nexport function sidePane(): Pane {\n const source = activePane();\n return workspace.panes.find((pane) => pane.id !== source.id) ?? addPane(SECONDARY_PANE);\n}\n\n/**\n * The pane beside the focused one, ready to OWN a tab.\n *\n * {@link sidePane} answers \"which pane is beside me\". This answers \"which pane may I put a document\n * IN\", and they differ by exactly one case — a LENS, whose invariant D2 is that it owns no tab at\n * all. Three callers mean the second question and all three were asking the first:\n *\n * - `splitRight` moved the focused tab into a lens. Between that write and the follow's next frame\n * the pane held both a derivation and a tab — D2 violated and observable — and `applyDerivation`\n * then handed the tab straight back, so `⌘\\` left the author looking at a different document,\n * their tab at the back of the primary's strip and the keyboard in a pane that owned nothing.\n * - `pane.compareWith` landed its tab in the lens's `tabOrder`, where `tabOfPane` hopped straight\n * past it to the source pane: the compared document was in no strip and on no stage, and the\n * follow — which tracks `derived` and the SOURCE pane's tab, neither of which a tab insertion\n * touches — never ran to repair it.\n * - `navigateToComponent` read `tabOfPane(target.id)` back and got the SOURCE tab, so the §14.2\n * `openedFrom` relationship the function exists to record was silently skipped.\n *\n * **The derivation is released rather than the request refused.** \"Put this document over there\" is\n * an explicit instruction about the pane a projection is currently borrowing, and a projection is a\n * view with no state of its own to lose — releasing it costs the author nothing and refusing costs\n * them the gesture.\n *\n * **A COMPANION is released too, and leaving it alone was the defect.** \"It owns real tabs, so the\n * new one simply joins them\" is true of the TABS and false of everything else. A layout companion\n * that has just been handed the page the author split in is still following the source pane's\n * `$layout`, so the next click on layout chrome re-points it and throws the new document off\n * screen; its `tabOrder` is no longer empty, so `panels/tab-strip.ts` draws tab chips instead of\n * the derivation chip and the pane loses both its name and its ✕; and `pane.pin` — which promotes\n * `activeTabId` — promotes whichever document is on top, which after `⌘\\` is the page, not the\n * layout the author was keeping. A gesture that empties a derivation of its meaning ends it.\n *\n * @returns {Pane}\n */\nexport function receivingPane(): Pane {\n const target = sidePane();\n if (target.derived) {\n /* The same write {@link closePane} makes for D4, for the same reason and in the same module:\n clearing a derivation is a fact about the PANE GRID. `pane-derive.ts`'s\n `clearPaneDerivation` is the reader-facing spelling and it imports from here, so calling it\n would be a cycle for one field assignment. */\n target.derived = null;\n }\n return target;\n}\n\n/**\n * Publish a new pane and hand back the REACTIVE record.\n *\n * The pane is constructed HERE so no caller can hold the raw literal. `reactive()` wraps on READ:\n * an object pushed into the array is still the plain object the caller has a reference to, and a\n * write through that reference reaches the same fields while notifying no effect at all. Building\n * the record inside the one function that publishes it is what makes that mistake unavailable\n * rather than merely absent — see the same failure recorded for nested reactive collections.\n *\n * @param {string} paneId\n * @returns {Pane}\n */\nfunction addPane(paneId: string): Pane {\n /* A pane id is unique BY CONSTRUCTION, not by every caller checking first. `workspace.panes` is\n the array lit's keyed `repeat` walks, and two records under one key is undefined behaviour\n there — the grid draws two cells for one pane, each `ref` overwriting the other's surface\n record. Handing back the record that is already published is the only answer that cannot\n produce one. */\n const existing = paneById(paneId);\n if (existing) {\n return existing;\n }\n workspace.panes = [\n ...workspace.panes,\n {\n activeTabId: null as string | null,\n derived: null as PaneDerivation | null,\n id: paneId,\n tabOrder: [] as string[],\n },\n ];\n return paneById(paneId)!;\n}\n\n/**\n * Collapse a pane, moving its tabs back into the one that remains.\n *\n * Closing a pane must never close documents — that is the difference between a layout action and a\n * destructive one, and only the second is allowed to lose work.\n *\n * **The PRIMARY never leaves the grid, and asking for it collapses the other pane instead.** §18.1\n * rule 3 — a pane with nothing in it is a hole in the grid — held on one side only until\n * `collapseEmptiedPane` was written, and that helper stated the rule a second time: `PRIMARY_PANE`\n * is the id nine screenshots crop, the one `resolveRegion(\"pane\")` canonicalises onto, and\n * `panes[0]`, so it must never be the pane that goes. Stating it in a helper left this function\n * exported and unguarded — `closePane(PRIMARY_PANE)` produced `panes = [\"secondary\"]`, a\n * `resolveRegion(\"pane\")` of null, and a `splitRight` that then minted a duplicate `repeat` key.\n * Both callers happened to guard; the function did not. It does now, and the helper is gone,\n * because the rule wanted one home rather than two.\n *\n * @param {string} paneId The pane to collapse. `PRIMARY_PANE` collapses the other one.\n */\nexport function closePane(paneId: string) {\n if (workspace.panes.length < 2) {\n return;\n }\n const closingId =\n paneId === PRIMARY_PANE\n ? workspace.panes.find((candidate) => candidate.id !== PRIMARY_PANE)?.id\n : paneId;\n const pane = closingId === undefined ? undefined : paneById(closingId);\n const survivor = workspace.panes.find((candidate) => candidate.id !== closingId);\n if (!pane || !survivor) {\n return;\n }\n /* The ORDER is the whole of this function.\n \"The active pane does not exist\" must never be observable. Every reader resolves through\n `workspace.activePaneId` — the stage, `tabOfPane`, the jump bar, the Inspector — so removing\n the pane while the focus still names it publishes, for one synchronous instant, a workspace\n whose focused pane has no tab. A render scheduled in that instant tore the canvas down to its\n welcome state and NOTHING scheduled another: the focus flip that followed changed no\n `activeTab`, so both canvas effects stayed quiet and the editor was gone until a reload.\n So: the survivor takes the tabs and the focus while both panes are still in the grid, and only\n then does the closing pane leave it. */\n for (const tabId of pane.tabOrder) {\n insertIntoPane(survivor, tabId);\n }\n /* The document you were LOOKING AT follows you; the one you were not does not replace it.\n This was `pane.activeTabId ?? survivor.activeTabId` unconditionally, so Unsplit run from the\n primary — which closes the SIDE pane, never the focused one — swapped the primary's document\n for the side pane's: focused=primary showing=a became focused=primary showing=b, and the only\n way back was the tab strip. Nothing is lost either way, because the closing pane's tabs have\n just been moved into the survivor above; this only decides which of them is on screen. */\n survivor.activeTabId =\n workspace.activePaneId === pane.id\n ? (pane.activeTabId ?? survivor.activeTabId)\n : (survivor.activeTabId ?? pane.activeTabId);\n workspace.activePaneId = survivor.id;\n /* Invariant D4, and it goes HERE — after the survivor has inherited the tabs and the focus, and\n before the closing pane leaves the grid, inside the ordering this function's comment insists\n on. A derived pane's source is mintable in either direction (derive from the secondary and the\n PRIMARY becomes the lens), so a survivor deriving from the pane that is leaving would be a\n pane whose `sourcePaneId` names nothing: `tabOfPane` would answer null and the grid would hold\n a stage drawing a document that no longer has a pane. Clearing it leaves you looking at the\n document, which is what unsplitting a Code lens should give you.\n\n There is no RESTORE path beside it, deliberately: a branch nothing can enter is the\n `documentStack` failure §14.3 records at length. */\n if (survivor.derived?.sourcePaneId === pane.id) {\n survivor.derived = null;\n }\n workspace.panes = workspace.panes.filter((candidate) => candidate.id !== pane.id);\n resetTabCycle();\n}\n\n/**\n * §18.1 rule 3, as a predicate: **a pane with no SUBJECT is a hole in the grid.**\n *\n * The rule used to be spelled `tabOrder.length === 0` at both sites that apply it, which was the\n * same question while every pane's subject was its tabs. A lens pane's subject is its derivation —\n * its `tabOrder` is empty BY DESIGN — so the literal test would collapse it the instant it was\n * created.\n */\nfunction paneIsEmpty(pane: Pane): boolean {\n return pane.tabOrder.length === 0 && pane.derived === null;\n}\n\n/* No `togglePaneZoom`. Zoom is a view of a GRID, and there is no grid: §18.3 hands the one stage\n between panes, so the focused pane already fills the shell and the other one is not on screen to\n be zoomed away from. The state existed, both commands wrote it, and nothing that draws ever read\n it — a control whose only observable effect is on itself. It comes back with the second live\n host, and not one release earlier. */\n\n/**\n * Remove a tab id from whichever pane holds it, without touching the tab itself.\n *\n * Exported for `workspace/pane-derive.ts`, which needs both halves of a move: `pane.derive` hands\n * the side pane's tabs BACK to the pane the author is in before publishing a lens there, because a\n * derivation is a layout action and nothing may be closed by one.\n */\nexport function detachTab(tabId: string) {\n const emptied: string[] = [];\n for (const pane of workspace.panes) {\n if (!pane.tabOrder.includes(tabId)) {\n continue;\n }\n pane.tabOrder = pane.tabOrder.filter((id) => id !== tabId);\n if (pane.activeTabId === tabId) {\n pane.activeTabId = pane.tabOrder.at(-1) ?? null;\n }\n /* The PRIMARY is exempt HERE and only here. `splitRight` moves the tab out of the source pane\n through this function, so a lone document split from the primary empties it — and that state\n is the one the author just asked for, a welcome screen beside the document they sent across.\n Closing a document is a different request, and `closeTab` collapses on both sides. */\n if (pane.id !== PRIMARY_PANE && paneIsEmpty(pane)) {\n emptied.push(pane.id);\n }\n }\n // The same rule `closeTab` applies, applied wherever a pane empties: a pane with nothing in it is\n // A hole in the grid. `splitRight` from the side pane moves the tab back to the primary and used\n // To leave the empty pane standing with `pane.focusSecondary` still enabled on it — three\n // Keystrokes to a shell with no stage, no strip, no jump bar and two documents still open. It was\n // Not `closePane`'s ordering bug, which is fixed: \"the active pane exists and has no tab\"\n // Produces the identical empty shell, and only this stops it being mintable.\n for (const paneId of emptied) {\n closePane(paneId);\n }\n}\n\n/* There is no `collapseEmptiedPane`. It existed to say \"collapse whichever side emptied, but never\n remove the primary — collapse the other one instead\", which is a rule about what CLOSING a pane\n means rather than about emptying one, and {@link closePane} now states it where the removal\n happens. Two homes for one rule is how `closePane` stayed exported and unguarded while both of\n its callers were careful. */\n\n/**\n * Put a tab id into a pane at the right place: after the pinned prefix for an ordinary tab, at the\n * end of it for a pinned one. Idempotent.\n *\n * Exported for `workspace/pane-derive.ts` — see {@link detachTab}.\n */\nexport function insertIntoPane(pane: Pane, tabId: string, index?: number) {\n if (pane.tabOrder.includes(tabId)) {\n return;\n }\n const at = index ?? defaultSlot(pane, tabId);\n pane.tabOrder = [...pane.tabOrder.slice(0, at), tabId, ...pane.tabOrder.slice(at)];\n}\n\n/** How many tabs at the head of `pane` are pinned. */\nfunction pinnedCount(pane: Pane): number {\n let count = 0;\n for (const id of pane.tabOrder) {\n if (workspace.tabs.get(id)?.pinned !== true) {\n break;\n }\n count += 1;\n }\n return count;\n}\n\n/** The slot a newly-arriving tab takes: inside the pinned prefix if pinned, else at the end. */\nfunction defaultSlot(pane: Pane, tabId: string): number {\n return workspace.tabs.get(tabId)?.pinned === true ? pinnedCount(pane) : pane.tabOrder.length;\n}\n\n/**\n * Record the open project on the reactive workspace. `root` must be the absolute project root (the\n * same value `createProject` returns and the pending-agent-prompt handoff is keyed by) — not the\n * \".\"-relative root projectState sometimes holds. Consumers: AI session scoping, system-prompt\n * project context, and the chat panel's pending-prompt effect.\n *\n * @param {string | null} root\n * @param {object | null} [config]\n */\nexport function setWorkspaceProject(root: string | null, config: object | null = null) {\n workspace.projectRoot = root;\n workspace.projectConfig = config;\n}\n\n/**\n * Whether `tab` is the active tab. Identity check survives reactive-proxy wrapping (activeTab.value\n * is a proxy; callers may hold either the raw tab or a proxy of it).\n *\n * @param {Tab | null} tab\n */\nexport function isTabActive(tab: Tab | null): boolean {\n const active = activeTab.value;\n return (\n tab !== null && active !== null && toRaw(active as object) === toRaw(tab as unknown as object)\n );\n}\n\n/**\n * Whether `tab` is still open.\n *\n * The question a CAPTURED tab owes before anything is written into it. Both Monaco surfaces commit\n * on a debounce, and a debounce is a promise to write into the document a tab held half a second\n * ago — by which time the tab may have been closed, so `workspace.tabs` no longer holds it and\n * nothing else will ever look at what was written. Deliberately not `isTabActive`: a commit belongs\n * to the tab its editor was mounted for whether or not that tab is the one on screen when the timer\n * fires, and resolving it through the FOCUSED tab is precisely the cross-document write this\n * replaces.\n *\n * @param {Tab | null | undefined} tab\n * @returns {boolean}\n */\nexport function tabIsLive(tab: Tab | null | undefined): boolean {\n if (!tab) {\n return false;\n }\n const held = workspace.tabs.get(tab.id);\n return held !== undefined && toRaw(held as object) === toRaw(tab as unknown as object);\n}\n\n/**\n * Move `tabId` to the front of the MRU list.\n *\n * @param {string} tabId\n */\nfunction promoteMru(tabId: string) {\n workspace.mruOrder = [tabId, ...workspace.mruOrder.filter((id) => id !== tabId)];\n}\n\n/*\n * ⌃Tab cycling holds a frozen snapshot of the MRU list for the duration of the cycle.\n *\n * Without it, the first ⌃Tab would promote the tab it landed on and the second press would come\n * straight back — the classic \"the shortcut only ever toggles between two tabs\" bug. The cycle ends\n * at {@link endTabCycle} (the modifier release) or at the next ordinary activation, and only then\n * does the tab the author settled on become the most recent.\n */\nlet _cycleList: string[] | null = null;\n\nlet _cycleIndex = 0;\n\n/** Abandon any in-flight ⌃Tab cycle without promoting anything. */\nfunction resetTabCycle() {\n _cycleList = null;\n _cycleIndex = 0;\n}\n\n/**\n * Point the file tree at the tab the author is now in.\n *\n * The tree and the strip disagreeing about \"where am I\" is the same class of defect as the tab id\n * disagreeing with its path: two surfaces answering one question two ways.\n *\n * @param {Tab} tab\n */\nfunction syncTreeSelection(tab: Tab) {\n if (projectState && tab.documentPath) {\n projectState.selectedPath = tab.documentPath;\n }\n}\n\n/**\n * Make `tabId` the active tab OF ITS OWN PANE. The one place activation happens.\n *\n * `focus: false` is \"put it on screen there, and leave the keyboard where it is\" — the shape a\n * side-open needs. It writes `pane.activeTabId` and stops: no `activePaneId` write, no\n * `resetTabCycle`, no `promoteMru`, no `syncTreeSelection`, because every one of those describes\n * where the AUTHOR is and the author has not moved. Drilling into a component with the focus\n * following it is the failure it exists to prevent: the pane the author is typing in changes under\n * them, and their next keystroke edits the definition instead of the page.\n *\n * Legal here and nowhere else — this module is `check-pane-singletons.ts`'s `FOCUS_OWNER`, and the\n * default is still to move the focus, so no existing caller changes behaviour.\n *\n * @param {string} tabId\n * @param {{ cycling?: boolean; focus?: boolean }} [opts] — `cycling` suppresses MRU promotion (see\n * {@link cycleTab}); `focus: false` leaves the keyboard in the pane it is in.\n */\nfunction setActiveTab(tabId: string, opts: { cycling?: boolean; focus?: boolean } = {}) {\n const tab = workspace.tabs.get(tabId);\n const pane = paneOfTab(tabId);\n if (!tab || !pane) {\n return;\n }\n pane.activeTabId = tabId;\n if (opts.focus === false) {\n return;\n }\n workspace.activePaneId = pane.id;\n if (!opts.cycling) {\n resetTabCycle();\n promoteMru(tabId);\n }\n syncTreeSelection(tab);\n}\n\n/**\n * Open a new tab and make it active.\n *\n * Re-opening an id that is already open REPLACES it: the previous tab is disposed and its slot in\n * the strip is reused. It used to be overwritten in the map while its effect scope leaked and a\n * SECOND copy of the id was pushed into `tabOrder`, which is what produced duplicate lit `repeat`\n * keys. Callers that mean \"show me this file\" should use `files/files.ts`'s `openFileInTab`, which\n * activates the existing tab instead.\n *\n * `preview: true` opens a DISPOSABLE tab (§4.3): single-clicking through the tree or the palette is\n * browsing, and browsing must not litter, so the next preview open in the same pane takes its slot.\n * It is opt-in rather than the default because only the CALLER knows whether the author was\n * browsing or committing — an author who typed a new file name has committed, and silently\n * discarding that tab on their next click is the one failure a preview tab must never have.\n * {@link promoteTab} records a commitment made after the fact.\n *\n * `paneId` says WHERE, and `focus` says whether the keyboard goes with it. Both default to today's\n * answer — the focused pane, and yes — because \"open this document\" has always meant \"in front of\n * me\". They exist because drilling into a component, comparing two documents and following a\n * selection all mean the opposite: put it in the pane beside this one and leave me where I am. A\n * `paneId` no pane carries falls back to the focused pane rather than dropping the open, which is\n * the same answer a stale persisted layout gets everywhere else in this module.\n *\n * @param {{\n * id: string;\n * documentPath?: string | null;\n * fileHandle?: FileSystemFileHandle | null;\n * document: Record<string, unknown>;\n * frontmatter?: Record<string, unknown>;\n * sourceFormat?: string | null;\n * capabilities?: { modes?: string[] };\n * openedFrom?: TabOrigin | null;\n * preview?: boolean;\n * paneId?: string;\n * focus?: boolean;\n * }} opts\n * @returns {Tab}\n */\nexport function openTab(opts: {\n id: string;\n documentPath?: string | null;\n fileHandle?: FileSystemFileHandle | null;\n document: Record<string, unknown>;\n frontmatter?: Record<string, unknown>;\n sourceFormat?: string | null;\n capabilities?: { modes?: string[] };\n openedFrom?: TabOrigin | null;\n preview?: boolean;\n paneId?: string;\n focus?: boolean;\n}) {\n const previous = workspace.tabs.get(opts.id);\n const preview = opts.preview === true && previous?.pinned !== true;\n const tab = createTab({ ...opts, preview });\n const pane = (opts.paneId === undefined ? undefined : paneById(opts.paneId)) ?? activePane();\n let slot: number | undefined;\n if (previous) {\n tab.pinned = previous.pinned;\n disposeTab(previous);\n } else {\n /* A preview open takes the pane's existing preview slot rather than adding a chip beside it —\n but only after the sitting tab has been given the chance to become ineligible.\n `promoteDirtyPreviewTabs` is the gate: an edited preview tab stops being replaceable. It\n reads `doc.dirty`, which is a fact a buffer's armed commit has not established yet, so the\n flush has to come BEFORE the victim is chosen. Choosing first and flushing after — which is\n what this did — ran the gate against the state of half a second ago and then destroyed the\n tab the gate would have saved. */\n if (preview) {\n const sitting = previewTabIn(pane);\n const sittingTab = sitting ? workspace.tabs.get(sitting) : null;\n if (sittingTab) {\n void commitTabBuffers(sittingTab);\n }\n promoteDirtyPreviewTabs();\n }\n const replaced = preview ? previewTabIn(pane) : null;\n if (replaced) {\n slot = pane.tabOrder.indexOf(replaced);\n /* THE EIGHTH WAY OUT OF A MONACO BUFFER, and the only one nobody asked for.\n `services/monaco-buffer.ts` lists seven exits: the disposers flush five, and\n `commitTabBuffers` covers ⌘W and quitting. This is the eighth — the author single-clicked\n another page, so the tab they were typing in is destroyed by a gesture that is not a close\n and shows no dialog. Anything the flush above carried has already promoted this tab out of\n the preview slot, so reaching here means the buffer had nothing of the author's in it.\n The flush is not awaited and cannot be: `openTab` is synchronous, its callers hold the\n `Tab` it returns, and `slot` is computed against the strip as it stands. The dock's body\n write is synchronous and therefore counts; the source view's parse is a format round trip\n and does not. That one resolves into a tab that is already gone and its own `tabIsLive`\n re-check drops it — the correct answer to \"write into a destroyed tab\", and the reason a\n source buffer is the one case this ordering still cannot rescue. */\n closeTab(replaced);\n }\n insertIntoPane(pane, tab.id, slot);\n }\n workspace.tabs.set(tab.id, tab);\n setActiveTab(tab.id, { focus: opts.focus !== false });\n ensureCollab(tab);\n return tab;\n}\n\n/** The pane's one preview tab, or null. */\nfunction previewTabIn(pane: Pane): string | null {\n return pane.tabOrder.find((id) => workspace.tabs.get(id)?.preview === true) ?? null;\n}\n\n/**\n * Commit to a tab: it stops being replaceable and starts rendering upright.\n *\n * @param {string} tabId\n */\nexport function promoteTab(tabId: string) {\n const tab = workspace.tabs.get(tabId);\n if (tab?.preview === true) {\n tab.preview = false;\n }\n}\n\n/**\n * Promote every preview tab that now has unsaved changes.\n *\n * An edit is the least ambiguous commitment there is, and the alternative — silently discarding\n * someone's typing because they clicked another file — is the one failure a preview tab must never\n * have. Called from the strip's tracking effect, which already reads every tab's `dirty` flag.\n */\nexport function promoteDirtyPreviewTabs() {\n for (const [id, tab] of workspace.tabs) {\n if (tab.preview && tab.doc.dirty) {\n promoteTab(id);\n }\n }\n}\n\n/**\n * Pin or unpin a tab, moving it to the boundary of the pinned prefix so the head of the strip is\n * always exactly the pinned set.\n *\n * @param {string} tabId\n * @param {boolean} pinned\n */\nexport function setTabPinned(tabId: string, pinned: boolean) {\n const tab = workspace.tabs.get(tabId);\n const pane = paneOfTab(tabId);\n if (!tab || !pane) {\n return;\n }\n tab.pinned = pinned;\n if (pinned) {\n tab.preview = false;\n }\n const without = pane.tabOrder.filter((id) => id !== tabId);\n const boundary = without.filter((id) => workspace.tabs.get(id)?.pinned === true).length;\n pane.tabOrder = [...without.slice(0, boundary), tabId, ...without.slice(boundary)];\n}\n\n/**\n * Drag-reorder within a pane. `toIndex` is clamped into the region the tab's pinned state allows,\n * so a drag can never interleave a pinned tab with an unpinned one.\n *\n * @param {string} tabId\n * @param {number} toIndex — the index in the pane's order the tab should end up at\n */\nexport function moveTab(tabId: string, toIndex: number) {\n const tab = workspace.tabs.get(tabId);\n const pane = paneOfTab(tabId);\n if (!tab || !pane) {\n return;\n }\n const without = pane.tabOrder.filter((id) => id !== tabId);\n const boundary = without.filter((id) => workspace.tabs.get(id)?.pinned === true).length;\n const lower = tab.pinned ? 0 : boundary;\n const upper = tab.pinned ? boundary : without.length;\n const at = Math.min(Math.max(toIndex, lower), upper);\n pane.tabOrder = [...without.slice(0, at), tabId, ...without.slice(at)];\n}\n\n/**\n * Close a tab and dispose its scope. Activates the most recently used remaining tab.\n *\n * @param {string} tabId\n */\nexport function closeTab(tabId: string) {\n const tab = workspace.tabs.get(tabId);\n if (!tab) {\n return;\n }\n const pane = paneOfTab(tabId);\n const wasActive = pane?.activeTabId === tabId;\n rememberClosedTab(tab);\n disposeTab(tab);\n workspace.tabs.delete(tabId);\n detachTab(tabId);\n workspace.mruOrder = workspace.mruOrder.filter((id) => id !== tabId);\n resetTabCycle();\n // Emptying EITHER pane collapses the grid: a pane with nothing in it is a hole in it, and the\n // Author asked to close a document, not to keep a slot open for one. `detachTab` above has\n // Usually done this already; this is the belt to its braces, and it goes through the same helper\n // So the primary can never be the pane that leaves.\n if (pane && paneIsEmpty(pane)) {\n closePane(pane.id);\n }\n if (!wasActive) {\n return;\n }\n // The MRU list, not the strip order: closing a tab should land you on the one you were in before\n // It, which is almost never the rightmost tab in the strip. `detachTab` has already put the\n // Rightmost there as the safe default, so this only ever improves on it.\n const survivor = activePane();\n const next =\n workspace.mruOrder.find((id) => survivor.tabOrder.includes(id)) ??\n survivor.tabOrder.at(-1) ??\n null;\n if (next) {\n setActiveTab(next);\n }\n}\n\n/**\n * Close all open tabs, disposing each. Defers reactivity until fully cleared.\n *\n * **Deliberately no gate and no `commitTabBuffers`, unlike `openTab`'s preview replacement and\n * `requestClose` — and that is now a statement about this function's CALLERS rather than a hole.**\n * It is the destructive half of a decision somebody else makes: the only caller in `src/` is the\n * project switch, and `panels/tab-strip.ts`'s `confirmCloseAll` runs both halves of the discipline\n * for it — commit every tab's buffers, then prompt once for the whole set — before the switch\n * begins, because everything the switch does after that point is one-way. Putting either half here\n * would put an `await` and a dialog inside a synchronous teardown that the test harness and\n * `resetStudioState` also call, which is exactly how a reset would start prompting.\n */\nexport function closeAllTabs() {\n const tabs = [...workspace.tabs.values()];\n workspace.tabs.clear();\n resetPanes();\n workspace.mruOrder = [];\n resetTabCycle();\n for (const tab of tabs) {\n disposeTab(tab);\n }\n}\n\n/** Back to one empty primary pane — the state the store boots in. */\nfunction resetPanes() {\n workspace.panes = [{ activeTabId: null, derived: null, id: PRIMARY_PANE, tabOrder: [] }];\n workspace.activePaneId = PRIMARY_PANE;\n}\n\n// ─── Reopen closed ────────────────────────────────────────────────────────────\n\n/**\n * Record a closing tab so `⌘⇧T` can bring it back.\n *\n * Only file-backed tabs are recorded: a virtual grid tab or an untitled document has nothing to\n * re-read, so offering to reopen it would be a lie.\n *\n * @param {Tab} tab\n */\nfunction rememberClosedTab(tab: Tab) {\n if (!tab.documentPath) {\n return;\n }\n const path = tab.documentPath;\n workspace.closedTabs = [\n { documentPath: path },\n ...workspace.closedTabs.filter((entry) => entry.documentPath !== path),\n ].slice(0, CLOSED_TAB_LIMIT);\n}\n\n/**\n * Take the most recently closed document path off the stack.\n *\n * Returns the path rather than opening it: reading and parsing a file belongs to `files/files.ts`,\n * and this module deliberately owns no I/O.\n *\n * @returns {string | undefined}\n */\nexport function takeClosedTabPath(): string | undefined {\n const [entry] = workspace.closedTabs;\n if (!entry) {\n return undefined;\n }\n workspace.closedTabs = workspace.closedTabs.slice(1);\n return entry.documentPath;\n}\n\n// ─── MRU cycling ──────────────────────────────────────────────────────────────\n\n/**\n * Walk the MRU list by `step` and activate what it lands on, without reordering it.\n *\n * @param {number} step — +1 for `⌃Tab`, -1 for `⌃⇧Tab`\n * @returns {string | undefined} The id activated, or undefined with fewer than two tabs\n */\nexport function cycleTab(step: number): string | undefined {\n if (!_cycleList) {\n _cycleList = workspace.mruOrder.filter((id) => workspace.tabs.has(id));\n _cycleIndex = 0;\n }\n const list = _cycleList;\n if (list.length < 2) {\n return undefined;\n }\n _cycleIndex = (((_cycleIndex + step) % list.length) + list.length) % list.length;\n const id = list[_cycleIndex]!;\n setActiveTab(id, { cycling: true });\n return id;\n}\n\n/** End a ⌃Tab cycle — the modifier came up, so the tab the author settled on is now the recent one. */\nexport function endTabCycle() {\n const settled = workspace.activeTabId;\n resetTabCycle();\n if (settled) {\n promoteMru(settled);\n }\n}\n\n/**\n * Replace all existing tabs with a new one atomically. Ensures activeTab is never null during the\n * transition.\n *\n * @param {{\n * id: string;\n * documentPath?: string | null;\n * document: Record<string, unknown>;\n * frontmatter?: Record<string, unknown>;\n * sourceFormat?: string | null;\n * }} newTabOpts\n * @returns {import(\"../tabs/tab.js\").Tab}\n */\nexport function replaceAllTabs(newTabOpts: {\n id: string;\n documentPath?: string | null;\n document: Record<string, unknown>;\n frontmatter?: Record<string, unknown>;\n sourceFormat?: string | null;\n}) {\n const oldIds = [...workspace.tabs.keys()];\n const oldTabs = [...workspace.tabs.values()];\n\n const newTab = createTab(newTabOpts);\n workspace.tabs.set(newTab.id, newTab);\n resetPanes();\n workspace.panes[0]!.tabOrder = [newTab.id];\n workspace.mruOrder = [];\n resetTabCycle();\n setActiveTab(newTab.id);\n ensureCollab(newTab);\n\n for (const id of oldIds) {\n if (id === newTab.id) {\n continue;\n }\n workspace.tabs.delete(id);\n }\n for (const tab of oldTabs) {\n disposeTab(tab);\n }\n\n return newTab;\n}\n\n/**\n * Switch to an existing tab.\n *\n * Activation also points the file tree at the tab's document and promotes it in the MRU list — the\n * strip, the tree and `⌃Tab` all read the same answer to \"where am I\". With `focus: false` it does\n * none of those: the tab comes to the front of the pane that owns it and the author stays put.\n *\n * @param {string} tabId\n * @param {{ focus?: boolean }} [opts]\n */\nexport function activateTab(tabId: string, opts: { focus?: boolean } = {}) {\n setActiveTab(tabId, opts);\n}\n\n/**\n * Move an already-open tab into a pane, and nothing else.\n *\n * One tab is one document in one pane's strip (§14.1's ownership half), so this is a MOVE: the tab\n * leaves whichever pane held it. Nothing is closed, nothing is activated and the focus does not\n * move — `openFileInTab` decides all three, because only the caller knows whether the author is\n * committing or browsing.\n *\n * Idempotent for a tab already in `paneId`, which is what makes it safe on the follow path.\n *\n * @param {string} tabId\n * @param {string} paneId\n * @returns {Pane | null} The pane it landed in, or null when either id names nothing.\n */\nexport function moveTabToPane(tabId: string, paneId: string): Pane | null {\n const pane = paneById(paneId);\n if (!pane || !workspace.tabs.has(tabId)) {\n return null;\n }\n if (pane.tabOrder.includes(tabId)) {\n return pane;\n }\n detachTab(tabId);\n insertIntoPane(pane, tabId);\n return pane;\n}\n\n/**\n * Re-key a tab after its backing file has been renamed. Preserves all tab state including unsaved\n * changes.\n *\n * @param {string} oldId\n * @param {string} newId\n * @param {string} newDocumentPath\n */\nexport function renameTab(oldId: string, newId: string, newDocumentPath: string) {\n const tab = workspace.tabs.get(oldId);\n if (!tab) {\n return;\n }\n tab.id = newId;\n tab.documentPath = newDocumentPath;\n workspace.tabs.delete(oldId);\n workspace.tabs.set(newId, tab);\n for (const pane of workspace.panes) {\n pane.tabOrder = pane.tabOrder.map((id) => (id === oldId ? newId : id));\n if (pane.activeTabId === oldId) {\n pane.activeTabId = newId;\n }\n }\n workspace.mruOrder = workspace.mruOrder.map((id) => (id === oldId ? newId : id));\n resetTabCycle();\n rekeyCollab(tab);\n}\n\n// ─── Commands ─────────────────────────────────────────────────────────────────\n\n/** What the tab commands need from the rest of Studio. */\nexport interface TabCommandDeps {\n /** Read a file from disk and show it — `files/files.ts`'s `openFileInTab`. */\n openFile: (path: string) => void | Promise<void>;\n /**\n * Read a file from disk and show it in a NAMED pane, browsing rather than committing and leaving\n * the keyboard where it is — `files/files.ts`'s `openFileInPane`.\n *\n * Injected for the same reason `openFile` is: this module owns the pane model and deliberately\n * owns no I/O, and `files/files.ts` imports from here.\n */\n openFileInPane: (paneId: string, path: string) => void | Promise<void>;\n}\n\n/**\n * The tab-navigation commands, defined next to the model they drive.\n *\n * They live here rather than in `commands/defaults.ts` because a capability's record belongs beside\n * its implementation: the id, the chord and the `run` are one thing, and splitting them across\n * files is how a second definition site gets born.\n *\n * `⌃Tab` carries two chords on purpose. `chordFromEvent` maps the platform's primary modifier to\n * `mod`, so the SAME physical Ctrl+Tab normalises to `ctrl+tab` on a mac (where ⌘ is `mod` and ⌃\n * stays `ctrl`) and to `mod+tab` everywhere else. Each spelling is unreachable on the other\n * platform, so declaring both binds one gesture rather than two.\n *\n * @param {CommandRegistry} registry\n * @param {TabCommandDeps} deps\n */\nexport function registerTabCommands(registry: CommandRegistry, deps: TabCommandDeps) {\n registry.registerAll([...tabCommands(deps), ...paneCommands(deps)]);\n}\n\n/**\n * The tab command records. Exported for the CI placement/budget checks and for tests.\n *\n * @param {TabCommandDeps} deps\n * @returns {AnyCommand[]}\n */\nexport function tabCommands(deps: TabCommandDeps): AnyCommand[] {\n // The MRU list is workspace-wide, so cycling is available whenever a second document is open —\n // In either pane, not just the focused one's strip.\n const twoOrMoreTabs = () => workspace.tabs.size > 1;\n return [\n {\n id: \"document.nextTab\",\n title: \"Next Tab\",\n category: \"Document\",\n level: \"document\",\n keybinding: [\"ctrl+tab\", \"mod+tab\"],\n menus: [\"palette\"],\n group: \"2_navigate\",\n when: (ctx) => ctx.document.open,\n enablement: twoOrMoreTabs,\n requires: \"a second open document\",\n run: () => {\n cycleTab(1);\n },\n },\n {\n id: \"document.previousTab\",\n title: \"Previous Tab\",\n category: \"Document\",\n level: \"document\",\n keybinding: [\"ctrl+shift+tab\", \"mod+shift+tab\"],\n menus: [\"palette\"],\n group: \"2_navigate\",\n when: (ctx) => ctx.document.open,\n enablement: twoOrMoreTabs,\n requires: \"a second open document\",\n run: () => {\n cycleTab(-1);\n },\n },\n {\n id: \"document.reopenClosed\",\n title: \"Reopen Closed Document\",\n category: \"Document\",\n level: \"document\",\n keybinding: \"mod+shift+t\",\n menus: [\"context/tab\", \"palette\"],\n group: \"1_file\",\n enablement: () => workspace.closedTabs.length > 0,\n requires: \"a document closed in this session\",\n run: async () => {\n const path = takeClosedTabPath();\n if (path) {\n await deps.openFile(path);\n }\n },\n },\n {\n id: \"document.togglePinned\",\n title: \"Pin / Unpin Document\",\n category: \"Document\",\n level: \"document\",\n menus: [\"context/tab\", \"palette\"],\n group: \"1_file\",\n when: (ctx) => ctx.document.open,\n requires: \"an open document\",\n run: () => {\n const id = workspace.activeTabId;\n const tab = id ? workspace.tabs.get(id) : null;\n if (id && tab) {\n setTabPinned(id, !tab.pinned);\n }\n },\n },\n {\n args: argsSchema({\n pinned: booleanProperty(\"True to pin the active document's tab, false to unpin it.\"),\n }),\n id: \"document.setPinned\",\n title: \"Set Document Pinned\",\n category: \"Document\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"1_file\",\n when: (ctx) => ctx.document.open,\n requires: \"an open document\",\n run: (_ctx, args) => {\n const id = workspace.activeTabId;\n if (id && workspace.tabs.get(id)) {\n setTabPinned(id, booleanArg(\"document.setPinned\", args, \"pinned\"));\n }\n },\n },\n {\n id: \"document.keepOpen\",\n title: \"Keep Document Open\",\n category: \"Document\",\n level: \"document\",\n menus: [\"context/tab\", \"palette\"],\n group: \"1_file\",\n when: (ctx) => ctx.document.open,\n enablement: () => {\n const id = workspace.activeTabId;\n return id !== null && workspace.tabs.get(id)?.preview === true;\n },\n requires: \"a preview document — one opened by a single click\",\n run: () => {\n const id = workspace.activeTabId;\n if (id) {\n promoteTab(id);\n }\n },\n },\n ];\n}\n\n/**\n * The pane commands.\n *\n * They live beside the pane model for the same reason the tab commands do, and they are the whole\n * user-facing surface of §4.1's Pane transport: split, focus, unsplit, zoom.\n *\n * `⌘0` and `⌘⌥0` are a PAIR, and they are both bound. `⌘0` was `canvas.zoomReset`, which held it\n * for the one verb of the zoom cluster that also has a button in the floating zoom pod (§3.2 ⑩) —\n * so the chord was the second way to reach a control that is already on screen, while focusing a\n * pane had no way at all. The zoom keeps its pod button and gives up the key.\n *\n * @param {TabCommandDeps} deps\n * @returns {AnyCommand[]}\n */\nexport function paneCommands(deps: TabCommandDeps): AnyCommand[] {\n const twoPanes = () => workspace.panes.length > 1;\n return [\n {\n id: \"pane.splitRight\",\n title: \"Split Right\",\n category: \"View\",\n level: \"document\",\n keybinding: \"mod+\\\\\",\n menus: [\"context/pane\", \"context/tab\", \"palette\"],\n group: \"5_pane\",\n when: (ctx) => ctx.document.open,\n /* One condition, and it is the one the `when` already states: there has to be a document to\n move. The enablement used to ask `canOpenInSecondPane` — whether the tab declared any of\n the six kinds the side pane was allowed to host — and refuse a Design-only page outright.\n Both panes draw a live Canvas now, so the only thing that can refuse a split is having\n nothing to split. */\n enablement: () => workspace.activeTabId !== null,\n // A `requires` string is printed verbatim in every refusal, tooltip and palette row, so it\n // May only promise what a reader will actually see.\n requires: \"an open document\",\n undo: \"none\",\n run: () => {\n splitRight();\n },\n },\n {\n args: argsSchema({\n path: stringProperty(\"Project-relative path of the document to open beside this one.\"),\n }),\n id: \"pane.compareWith\",\n title: \"Compare With…\",\n category: \"View\",\n level: \"document\",\n menus: [\"context/pane\", \"context/tab\", \"palette\"],\n group: \"5_pane\",\n when: (ctx) => ctx.document.open,\n /* This is NOT `pane.derive`, and the distinction is the whole reason both exist. `derive`\n shows a projection OF THIS PANE — its Code, its diff, the same page at another breakpoint —\n and follows it. `compareWith` puts THAT DOCUMENT beside this one and then leaves it alone.\n Collapsing them would give \"open a second document in the other pane\" two definition\n sites, which is how the two names in §4.1 came to disagree in the first place. */\n enablement: () => workspace.activeTabId !== null,\n requires: \"an open document\",\n undo: \"none\",\n aiTool: {\n description:\n \"Open a second document in the pane beside the current one, without moving the document \" +\n \"you are in.\",\n name: \"compare_with\",\n },\n run: async (_ctx, args) => {\n const path = stringArg(\"pane.compareWith\", args, \"path\");\n const here = activePane();\n const held = here.activeTabId ? workspace.tabs.get(here.activeTabId) : null;\n /* Refused by NAME rather than by `requires`, which is one sentence for the whole command\n and cannot express \"in the other pane\". Comparing a document with itself is not a\n refusal the enablement can see: it depends on the argument. */\n if (held?.documentPath === path) {\n throw new RangeError(\n `command \"pane.compareWith\" argument \"path\": \"${path}\" is the document this pane is ` +\n `already showing — name a different one`,\n );\n }\n /* Nothing closes, nothing unsplits, and the FOCUS DOES NOT MOVE: comparing is a read.\n {@link receivingPane} rather than `sidePane`, because the pane beside this one may be a\n LENS — and a lens owns no tab, so the document landed in a `tabOrder` that `tabOfPane`\n hops straight past. Nothing was on screen, nothing was in a strip, and\n `workspace.activeTabId` went on reporting the source. */\n await deps.openFileInPane(receivingPane().id, path);\n },\n },\n {\n id: \"pane.focusPrimary\",\n title: \"Focus Primary Pane\",\n category: \"View\",\n level: \"document\",\n keybinding: \"mod+0\",\n menus: [\"palette\"],\n group: \"5_pane\",\n enablement: twoPanes,\n requires: \"a split pane grid\",\n undo: \"none\",\n run: () => {\n focusPane(PRIMARY_PANE);\n },\n },\n {\n id: \"pane.focusSecondary\",\n title: \"Focus Side Pane\",\n category: \"View\",\n level: \"document\",\n keybinding: \"mod+alt+0\",\n menus: [\"palette\"],\n group: \"5_pane\",\n enablement: twoPanes,\n requires: \"a split pane grid\",\n undo: \"none\",\n run: () => {\n focusPane(SECONDARY_PANE);\n },\n },\n {\n id: \"pane.unsplit\",\n /* \"Unsplit\" and \"a split pane grid\" were true while a second pane could only arrive by\n splitting. A derived pane is not a split — nothing moved into it — and it is also the only\n exit a LENS has, so the record has to name what it does rather than what undoes the one\n gesture that used to make it. The id is unchanged: the manifest addresses the id. */\n title: \"Close Side Pane\",\n category: \"View\",\n level: \"document\",\n menus: [\"context/pane\", \"palette\"],\n group: \"5_pane\",\n enablement: twoPanes,\n requires: \"a second pane\",\n undo: \"none\",\n run: runUnsplit,\n },\n ];\n}\n\n/**\n * `pane.unsplit`'s subject: **the DERIVED pane when the grid has one**, else the side pane.\n *\n * The subject used to be `activePaneId === PRIMARY ? SECONDARY : activePaneId` — \"the pane beside\n * me, unless I am in it\" — a complete answer while a second pane could only arrive by splitting and\n * both panes were the same kind of thing. A derived pane is not: it is subordinate to the pane it\n * projects, it is mintable in EITHER direction (derive from the secondary and the PRIMARY becomes\n * the projection), and two new surfaces offer this command as _that pane's own exit_ — the\n * derivation chip's ✕ in `panels/tab-strip.ts` and the `Close Side Pane` row of its own preset\n * menu. Both focus their pane before running, so with a derived PRIMARY the old expression read the\n * focus, saw `PRIMARY`, and closed the pane holding the author's work:\n *\n * before: primary[pages/index.json]*derived secondary[scratch.json] focus=secondary\n * after: primary[pages/index.json, scratch.json] focus=primary\n *\n * Scanning for the derivation is the same shape `pane-derive.ts`'s `pinnablePane` uses, and for the\n * same reason: a grid holds at most one derived pane, so the answer reads no focus and is therefore\n * the same from the palette, from the chip and from either pane's menu.\n *\n * **One title, two acts, because for every pane that CAN leave the grid they are the same act.**\n * Closing a projection's pane ends the projection. {@link closePane} refuses to remove the PRIMARY\n * — it is `panes[0]`, the id `resolveRegion(\"pane\")` canonicalises onto and nine screenshots crop —\n * so for a derived primary only the second half is available: the derivation is dropped and the\n * pane keeps whatever it owns. Passing `PRIMARY_PANE` to `closePane` would not have done that; it\n * redirects to \"collapse the other pane instead\", which is how pressing the projection's ✕ closed\n * the author's second pane and left them looking at the projection's document.\n *\n * A LENS owns no tab, so ending its derivation leaves a pane with no subject — §18.1 rule 3 — and\n * the repair for an empty primary is exactly that redirect. That case therefore still collapses,\n * which is right: unsplitting a Code lens should leave you with the document.\n */\nfunction runUnsplit(): void {\n const derived = workspace.panes.find((pane) => pane.derived !== null);\n if (derived?.id === PRIMARY_PANE) {\n derived.derived = null;\n if (!paneIsEmpty(derived)) {\n return;\n }\n }\n /* `SECONDARY_PANE`, flatly, where the fallback used to read\n `activePaneId === PRIMARY ? SECONDARY : activePaneId`. With {@link MAX_PANES} at 2 and both ids\n minted by {@link addPane} from the two constants, `activePaneId` is one of those two and BOTH\n branches of that ternary evaluate to `SECONDARY_PANE` — a choice with one outcome, which no\n test could tell from its opposite. It is a fossil of the pre-derivation subject, described in\n the docstring above; the sentence it belonged to is the one that has to stay. */\n closePane(derived?.id ?? SECONDARY_PANE);\n}\n",
|
|
29
|
+
"/**\n * Session.ts — what a project looked like when you left it, and how it looks that way again.\n *\n * Plan §4.4: \"Session state persists **per project root** … open tabs and order per pane, active\n * tab, per-tab editor kind / view / zoom / rendering context.\" P3's \"Newly possible\" states the\n * consequence plainly: **the session survives a relaunch.** Neither shipped. The per-project record\n * held `layouts` and `activeLayout` and nothing else, its interface said \"Session state (§4.4)\n * grows into this shape\", and reopening a project landed on the home page with an empty strip — so\n * nine open documents, a split, and the breakpoint you were checking were lost every time.\n *\n * **Paths, not tab ids.** A tab id is minted per open and means nothing across a reload; the\n * document's path is the identity the workspace already dedupes on (`openFileInTab` scans\n * `tab.documentPath`). A stored path that no longer resolves is skipped on restore rather than\n * failing the whole session — files move, and losing the other eight tabs because one was renamed\n * would be worse than the problem this solves.\n *\n * **Only what the author chose.** Per tab it records the canvas mode, the preview flag, the zooms\n * and the rendering context — the settings a person deliberately put a document into. Selection,\n * hover, clipboard, undo history and the live canvas scope are all derived or transient, and\n * restoring a selection into a document that has since changed on disk would point at a node that\n * may not exist.\n *\n * **Untrusted input.** Everything read back is `localStorage`, which is hand-editable and survives\n * across versions. Every field is validated on the way in and a bad record restores nothing.\n */\n\nimport { PRIMARY_PANE, SECONDARY_PANE, focusPane, workspace } from \"./workspace\";\nimport { isWellFormedLocale } from \"@jxsuite/schema/locale\";\nimport type { Tab } from \"../tabs/tab\";\n\n/** One pane's share of a session. */\nexport interface PersistedPane {\n /** `PRIMARY_PANE` or `SECONDARY_PANE` — the two ids the grid has (§18.1). */\n id: string;\n /** Document paths in strip order. Untitled tabs are absent: they have no path to restore from. */\n files: string[];\n /** Which of `files` was active, or `null`. */\n activeFile: string | null;\n}\n\n/** What a document was showing when the project was last closed. */\nexport interface PersistedTabUi {\n canvasMode?: string;\n preview?: boolean;\n zoom?: number;\n editZoom?: number;\n activeMedia?: string | null;\n previewColorScheme?: string;\n /** BCP 47 tag, or `null` for \"the document's own language\". */\n previewLocale?: string | null;\n showLayout?: boolean;\n}\n\n/** The whole session, as stored. */\nexport interface PersistedSession {\n panes: PersistedPane[];\n /** Which pane had the keyboard. */\n focusedPane: string;\n /** Per-document view settings, keyed by path. */\n ui: Record<string, PersistedTabUi>;\n}\n\nconst PANE_IDS = new Set([PRIMARY_PANE, SECONDARY_PANE]);\nconst SCHEMES = new Set([\"auto\", \"light\", \"dark\"]);\n\n/** The view settings this tab was left in — the ones a person chose, not the ones derived. */\nfunction uiOf(tab: Tab): PersistedTabUi {\n const { ui } = tab.session;\n return {\n activeMedia: ui.activeMedia,\n canvasMode: ui.canvasMode,\n editZoom: ui.editZoom,\n preview: ui.preview,\n previewColorScheme: ui.previewColorScheme,\n previewLocale: ui.previewLocale,\n showLayout: ui.showLayout,\n zoom: ui.zoom,\n };\n}\n\n/**\n * Snapshot the workspace.\n *\n * A pane with no restorable tab is dropped rather than stored empty — restoring a split whose\n * second half has nothing in it would reopen a pane the author would immediately close.\n */\nexport function captureSession(): PersistedSession {\n const ui: Record<string, PersistedTabUi> = {};\n const panes: PersistedPane[] = [];\n for (const pane of workspace.panes) {\n // A DERIVED pane owns no tabs — it is a projection of another pane (§18.4) — and re-deriving it\n // Needs the source pane's document to exist first. Not stored; the author re-derives in a\n // Keystroke, and a half-restored derivation pointing at a pane that failed to fill is worse.\n if (pane.derived) {\n continue;\n }\n const files: string[] = [];\n for (const tabId of pane.tabOrder) {\n const tab = workspace.tabs.get(tabId);\n if (!tab?.documentPath) {\n continue;\n }\n files.push(tab.documentPath);\n ui[tab.documentPath] = uiOf(tab);\n }\n if (files.length === 0) {\n continue;\n }\n const activeTab = pane.activeTabId ? workspace.tabs.get(pane.activeTabId) : null;\n panes.push({\n activeFile: activeTab?.documentPath ?? null,\n files,\n id: pane.id,\n });\n }\n return { focusedPane: workspace.activePaneId, panes, ui };\n}\n\n/** Whether a parsed value is a usable {@link PersistedTabUi}. Hand-edited storage is input. */\nfunction readTabUi(value: unknown): PersistedTabUi {\n if (typeof value !== \"object\" || value === null) {\n return {};\n }\n const raw = value as Record<string, unknown>;\n const out: PersistedTabUi = {};\n if (typeof raw.canvasMode === \"string\") {\n out.canvasMode = raw.canvasMode;\n }\n if (typeof raw.preview === \"boolean\") {\n out.preview = raw.preview;\n }\n if (typeof raw.zoom === \"number\" && Number.isFinite(raw.zoom)) {\n out.zoom = raw.zoom;\n }\n if (typeof raw.editZoom === \"number\" && Number.isFinite(raw.editZoom)) {\n out.editZoom = raw.editZoom;\n }\n if (raw.activeMedia === null || typeof raw.activeMedia === \"string\") {\n out.activeMedia = raw.activeMedia;\n }\n if (typeof raw.previewColorScheme === \"string\" && SCHEMES.has(raw.previewColorScheme)) {\n out.previewColorScheme = raw.previewColorScheme;\n }\n /* `null` is a value here, not an absence: it is \"the document's own language\", so a pane put\n deliberately back onto its own file's language would otherwise restore the tag it left.\n A tag is checked for WELL-FORMEDNESS only — whether the project still declares it is a\n question about `project.json`, which the reader cannot see and which changes between sessions;\n the control refuses an undeclared tag on the way in and the render falls back on the way out. */\n if (raw.previewLocale === null || isWellFormedLocale(raw.previewLocale)) {\n out.previewLocale = raw.previewLocale as string | null;\n }\n if (typeof raw.showLayout === \"boolean\") {\n out.showLayout = raw.showLayout;\n }\n return out;\n}\n\n/**\n * Validate a stored session. Returns `null` for anything that is not one — a corrupt record\n * restores nothing rather than restoring half a workspace.\n */\nexport function readSession(value: unknown): PersistedSession | null {\n if (typeof value !== \"object\" || value === null) {\n return null;\n }\n const raw = value as Partial<PersistedSession>;\n if (!Array.isArray(raw.panes)) {\n return null;\n }\n const panes: PersistedPane[] = [];\n for (const entry of raw.panes) {\n if (typeof entry !== \"object\" || entry === null) {\n continue;\n }\n const pane = entry as Partial<PersistedPane>;\n if (typeof pane.id !== \"string\" || !PANE_IDS.has(pane.id)) {\n continue;\n }\n const files = Array.isArray(pane.files)\n ? pane.files.filter((file): file is string => typeof file === \"string\" && file !== \"\")\n : [];\n if (files.length === 0) {\n continue;\n }\n panes.push({\n activeFile:\n typeof pane.activeFile === \"string\" && files.includes(pane.activeFile)\n ? pane.activeFile\n : null,\n files,\n id: pane.id,\n });\n }\n if (panes.length === 0) {\n return null;\n }\n const ui: Record<string, PersistedTabUi> = {};\n if (typeof raw.ui === \"object\" && raw.ui !== null) {\n for (const [path, entry] of Object.entries(raw.ui as Record<string, unknown>)) {\n ui[path] = readTabUi(entry);\n }\n }\n return {\n focusedPane:\n typeof raw.focusedPane === \"string\" && PANE_IDS.has(raw.focusedPane)\n ? raw.focusedPane\n : PRIMARY_PANE,\n panes,\n ui,\n };\n}\n\n/** What {@link restoreSession} needs from the rest of Studio, so this module opens no files itself. */\nexport interface RestoreDeps {\n /** Open one path into one pane, without moving the keyboard. Rejects if the file is gone. */\n openFile: (path: string, paneId: string) => Promise<void>;\n /**\n * Make sure the grid HAS a second pane, without moving anything into it.\n *\n * `receivingPane()`, not `splitRight()`: a split moves the focused pane's active tab, and at this\n * point nothing is open — so `splitRight()` returns `null`, the pane is never created, and the\n * second pane's documents all land in the first.\n */\n ensureSecondPane: () => void;\n}\n\n/**\n * Reopen what the session describes. Returns how many documents actually landed.\n *\n * A path that no longer resolves is SKIPPED, not fatal: files move, and losing eight tabs because\n * one was renamed would be a worse bug than the one this fixes. `0` means nothing restored, which\n * is the caller's signal to fall back to the home page.\n */\nexport async function restoreSession(\n session: PersistedSession,\n deps: RestoreDeps,\n): Promise<number> {\n let opened = 0;\n if (session.panes.some((pane) => pane.id === SECONDARY_PANE)) {\n deps.ensureSecondPane();\n }\n for (const pane of session.panes) {\n for (const file of pane.files) {\n try {\n await deps.openFile(file, pane.id);\n } catch {\n // Moved, renamed or deleted since. The rest of the session is still worth having.\n }\n /*\n * COUNT WHAT LANDED, not what failed to throw.\n *\n * `openFileInTab` reports a missing file by raising a Problem and returning normally — it is\n * a user action, not an exception — so counting calls made every restore look like a success.\n * A session of three deleted files then reported `3`, the caller skipped its home-page\n * fallback, and the window opened empty. The workspace is the only honest answer to \"is it\n * open?\", and it is the same field `openFileInTab` dedupes against.\n */\n if ([...workspace.tabs.values()].some((tab) => tab.documentPath === file)) {\n opened += 1;\n }\n }\n }\n if (opened === 0) {\n return 0;\n }\n // The view settings, applied AFTER every tab exists: `canvasMode` is validated against the tab's\n // Own `capabilities.modes` by the setter, and a mode a document does not support is dropped.\n for (const tab of workspace.tabs.values()) {\n const stored = tab.documentPath ? session.ui[tab.documentPath] : undefined;\n if (!stored) {\n continue;\n }\n const { ui } = tab.session;\n if (stored.canvasMode && tab.capabilities.modes.includes(stored.canvasMode)) {\n ui.canvasMode = stored.canvasMode;\n }\n if (stored.preview !== undefined) {\n ui.preview = stored.preview;\n }\n if (stored.zoom !== undefined) {\n ui.zoom = stored.zoom;\n }\n if (stored.editZoom !== undefined) {\n ui.editZoom = stored.editZoom;\n }\n if (stored.activeMedia !== undefined) {\n ui.activeMedia = stored.activeMedia;\n }\n if (stored.previewColorScheme !== undefined) {\n ui.previewColorScheme = stored.previewColorScheme as \"auto\" | \"dark\" | \"light\";\n }\n if (stored.previewLocale !== undefined) {\n ui.previewLocale = stored.previewLocale;\n }\n if (stored.showLayout !== undefined) {\n ui.showLayout = stored.showLayout;\n }\n }\n // Each pane's active tab, then the pane that had the keyboard — in that order, because activating\n // A tab in a pane is what makes that pane's strip meaningful and focusing comes last.\n for (const stored of session.panes) {\n const pane = workspace.panes.find((p) => p.id === stored.id);\n if (!pane || !stored.activeFile) {\n continue;\n }\n const match = pane.tabOrder.find(\n (tabId) => workspace.tabs.get(tabId)?.documentPath === stored.activeFile,\n );\n if (match) {\n pane.activeTabId = match;\n }\n }\n if (workspace.panes.some((pane) => pane.id === session.focusedPane)) {\n focusPane(session.focusedPane);\n }\n return opened;\n}\n",
|
|
30
|
+
"/**\n * Startup profiles — a named, defined cold start.\n *\n * \"What does Studio look like to someone who has never opened it?\" currently has no answer inside\n * the app. Every consumer of that question reaches _around_ it: the screenshot runner injects\n * `localStorage.clear()` before the first navigation, the verify recipe says \"use a fresh browser\n * profile\", and a support thread says \"try a private window\". All three clear the whole ORIGIN —\n * including keys Studio does not own — and none of them can be invoked from inside the running\n * app.\n *\n * Three shipped things need it to be a real, addressable state:\n *\n * - **Per-project layout and session persistence** cannot be tested without a defined starting point;\n * \"whatever was in storage\" is not one.\n * - **Preferences: Reset Layout** is `applyProfile(\"fresh\")` scoped to the layout keys, and the plan\n * promises it is \"always one action away\".\n * - **Support** wants \"reproduce with a clean profile\" to be a URL, not an instruction.\n *\n * The profile is selected by `?profile=<id>` and applied ONCE, at import time, before anything\n * reads persisted state — {@link import(\"../shell\").shell} calls this above its own `localStorage`\n * read for exactly that reason. `?clock=` rides alongside because it is the other boot-time knob:\n * both describe the world the app wakes up in, and neither changes behaviour after.\n */\n\nimport { pinClock } from \"./clock\";\n\n/** What a profile resets. */\nexport type ProfileReset = \"none\" | \"app-state\";\n\nexport interface StartupProfile {\n id: string;\n /** Shown wherever a profile is offered (Preferences, the palette). */\n description: string;\n reset: ProfileReset;\n}\n\n/**\n * The profiles Studio declares.\n *\n * `default` is not a no-op by omission — it is a named state, so \"the app started normally\" and\n * \"the profile was unrecognised\" are different outcomes and the second one is loud.\n */\nexport const STARTUP_PROFILES: Readonly<Record<string, StartupProfile>> = {\n default: {\n description: \"Resume whatever was persisted — layout, recents, settings, chat history.\",\n id: \"default\",\n reset: \"none\",\n },\n fresh: {\n description: \"A first-run app: no layout, no recents, no settings, no history.\",\n id: \"fresh\",\n reset: \"app-state\",\n },\n};\n\nexport const DEFAULT_PROFILE_ID = \"default\";\n\n/**\n * Studio's own persisted keys, by prefix.\n *\n * Scoped rather than `localStorage.clear()`: the dev server, the docs site and Studio share an\n * origin, and a profile that wipes a neighbour's state is a worse bug than the one it fixes. Every\n * key Studio writes begins with `jx` followed by one of these separators — the panel widths, the\n * recents, the GitHub token, the AI and Cloudflare settings, the chat sessions, the update\n * dismissals and the canvas debug flag.\n */\nconst OWNED_KEY_PATTERN = /^jx[-._:]/;\n\n/** Whether a storage key belongs to Studio and is therefore a profile's to clear. */\nexport function isStudioStorageKey(key: string): boolean {\n return OWNED_KEY_PATTERN.test(key);\n}\n\n/**\n * Drop every Studio-owned key from `localStorage`.\n *\n * @returns The keys removed, so a caller (Preferences, a test) can report what it did.\n */\nexport function clearStudioStorage(): string[] {\n const store = globalThis.localStorage as Storage | undefined;\n if (!store) {\n return [];\n }\n const doomed: string[] = [];\n try {\n for (let i = 0; i < store.length; i++) {\n const key = store.key(i);\n if (key && isStudioStorageKey(key)) {\n doomed.push(key);\n }\n }\n for (const key of doomed) {\n store.removeItem(key);\n }\n } catch {\n // Storage unavailable (private mode, disabled cookies) — there is nothing persisted to reset.\n }\n return doomed;\n}\n\n/**\n * Apply a profile by id.\n *\n * @throws {RangeError} When the id is not declared. A misspelled profile that silently fell back to\n * `default` would start the app in the state the caller was trying to avoid.\n */\nexport function applyProfile(id: string): StartupProfile {\n const profile = STARTUP_PROFILES[id];\n if (!profile) {\n throw new RangeError(\n `unknown startup profile \"${id}\"; declared: ${Object.keys(STARTUP_PROFILES).join(\", \")}`,\n );\n }\n if (profile.reset === \"app-state\") {\n clearStudioStorage();\n }\n return profile;\n}\n\n/** What {@link applyStartupProfile} resolved. */\nexport interface StartupState {\n profile: StartupProfile;\n /** The instant the clock was pinned to, or `null` when it follows the wall clock. */\n clock: number | null;\n}\n\nlet _startup: StartupState | null = null;\n\n/**\n * Read `?profile=` and `?clock=` and apply them. Idempotent — the first call wins, so importing\n * this from a second module cannot re-clear storage the app has already written to.\n *\n * @param search The query string to read. Defaults to the live location, and is passed explicitly\n * by the tests, which have no navigation.\n */\nexport function applyStartupProfile(search?: string): StartupState {\n if (_startup) {\n return _startup;\n }\n const query = new URLSearchParams(search ?? globalThis.location?.search ?? \"\");\n const profile = applyProfile(query.get(\"profile\") ?? DEFAULT_PROFILE_ID);\n const clockParam = query.get(\"clock\");\n _startup = { clock: clockParam === null ? null : pinClock(clockParam), profile };\n return _startup;\n}\n\n/** What the app started as. `null` until {@link applyStartupProfile} has run. */\nexport function startupState(): StartupState | null {\n return _startup;\n}\n\n/** Forget the resolved startup state, so the next call re-reads the query. Tests only. */\nexport function resetStartupProfile(): void {\n _startup = null;\n}\n",
|
|
31
|
+
"/// <reference lib=\"dom\" />\n/**\n * Shell — the reactive record of Jx Studio's UI _inputs_.\n *\n * Companion to `view.ts`, and the other half of the split that `view.ts` used to straddle:\n *\n * - `view` holds render **outputs** — Monaco instances, the panzoom wrap, observers, DOM refs and the\n * per-render cleanup arrays. It stays a plain object, because wrapping a live editor instance and\n * detached DOM nodes in a reactive proxy is an active hazard.\n * - `shell` (here) holds UI **inputs** — which panel each dock shows, whether each dock is open and\n * how wide, the focused region, the layout preset, and the project-level state (source control,\n * the stylebook selection, the settings tab) that a _document_ must not own.\n *\n * Because this record is reactive, a surface tracks it by reading it: the rail, the left panel and\n * the toolbar all repaint from the effects they already run. The stand-in that preceded this —\n * `onPanelCollapse(fn)` plus an explicit `render()` in every toggle handler — is deleted.\n *\n * **Project-level state does not live on the focused tab.** Git status is a property of the\n * project, not of whichever document happens to be open: sourcing it from `activeTab` meant the\n * rail's Source Control badge vanished when the last tab closed, and two tabs could disagree about\n * the branch. See specs/studio.md and the level × placement matrix.\n */\n\nimport { effect, effectScope, reactive } from \"./reactivity\";\nimport { applyStartupProfile } from \"./services/profile\";\nimport { stampShellRegions } from \"./ui/regions\";\nimport { workspace } from \"./workspace/workspace\";\nimport { captureSession, readSession } from \"./workspace/session\";\nimport type { PersistedSession } from \"./workspace/session\";\nimport {\n argsSchema,\n booleanArg,\n booleanProperty,\n enumArg,\n enumProperty,\n stringArg,\n stringProperty,\n} from \"./commands/command-args\";\nimport type { EffectScope } from \"@vue/reactivity\";\nimport type { LayoutHit } from \"./canvas/iframe-protocol\";\nimport type { GitBranchesResult, GitDiffState, GitStatusResult } from \"./types\";\nimport type { AnyCommand, CommandRegistry } from \"./commands/registry\";\n\n/**\n * The canvas selection when the author clicked LAYOUT chrome rather than page content — a header, a\n * footer, anything contributed by the layout file. It is deliberately NOT a document selection: the\n * node is not in the open page at all, so the properties panel shows the read-only layout panel\n * (with \"Open Layout →\") instead of the element inspector. See {@link setLayoutSelection}.\n */\nexport type LayoutSelection = LayoutHit;\n\n/**\n * The three resizable docks around the pane grid: two flanking it, one under it.\n *\n * `\"chat\"` is not among them: the assistant is the Inspector's fourth TAB, not a dock, so it has no\n * column, no size, no collapse flag and no resize handle of its own — which is the whole claim of\n * plan §3.2 ⑨, that folding it in costs zero additional width. What selects it is\n * {@link INSPECTOR_TAB_IDS}, the same mechanism that selects Content, Style and Logic.\n *\n * `\"bottom\"` is the one that arrives with P4.2. It is a dock like the other two — a collapse flag,\n * a remembered size, a resize handle, a place in every {@link LayoutPreset} — and the reason\n * `view.toggleBottomDock` had no idempotent setter for two phases is that it was not on this\n * record. It sits under the PANE GRID rather than under the window (plan §3.2 ⑪), so opening it\n * never narrows the Navigator or the Inspector.\n */\nexport type DockId = \"left\" | \"right\" | \"bottom\";\n\n/**\n * The ids of the panels the NAVIGATOR DOCK draws, in REGISTRATION order.\n *\n * This is the DECLARATION `view.setActivity`'s `args` enum is built from, and it is the reason a\n * panel rename fails `scripts/check-shot-contract.ts` in the renaming PR naming both ids instead of\n * silently photographing the wrong panel (plan §13.5). `shell.leftTab` stays a `string` because it\n * is also read from persisted state written by an older build — the COMMAND is what refuses an\n * undeclared id, at the one door a caller comes through, and {@link migratePanelId} is what turns a\n * stale stored id into a current one before it gets there.\n *\n * **`\"problems\"` is not here, and it has no rail button either.** It is hosted in the Bottom dock,\n * so `view.setBottomTab { tab: \"problems\" }` is the verb that shows it and this enum would be a\n * second, wrong door. That verb is now the ONLY door: the status bar's warning count runs it, and\n * `panel.focus.problems` no longer exists, because the roster it was generated from follows the\n * rail and Problems is off the rail.\n *\n * The records themselves live in `panels/navigator-panels.ts`, one per owning module, and that\n * file's registration order is this one — which is rail order within each level group, with a\n * rail-less record sitting where its module registers it rather than at the end. Languages is the\n * one that makes the difference visible: it is registered with the PROJECT group, beside the panels\n * it belongs with in the palette, and it draws no rail button at all.\n *\n * This list is the same set written down in a module that imports no DOM, because\n * `commands/app-commands.ts` must load the enum in a bare Bun process;\n * `tests/panel-registry.test.ts` asserts the two agree, so the duplicate cannot drift.\n */\nexport const NAVIGATOR_PANEL_IDS = [\n \"files\",\n \"search\",\n \"git\",\n \"i18n\",\n \"layers\",\n \"page\",\n \"data\",\n \"packages\",\n \"insert\",\n] as const;\n\nexport type NavigatorPanelId = (typeof NAVIGATOR_PANEL_IDS)[number];\n\n/**\n * Panel ids a previous build persisted, and what they are called now.\n *\n * Three renames, each fixing a name that described a mechanism rather than a task: `blocks` was an\n * insert palette, `head` was an HTML element, `imports` was the verb and not the thing. A stored\n * value is the one place those old strings can still arrive from, so they are translated once, on\n * read, and then never again — there is no alias in the registry and no branch in the rail.\n */\nconst RENAMED_PANEL_IDS: Readonly<Record<string, NavigatorPanelId>> = {\n blocks: \"insert\",\n head: \"page\",\n imports: \"packages\",\n /* Not a rename — a MERGE. The State editor is part of the Data panel now (plan §11.2), so a\n stored `leftTab: \"state\"` names a real place and lands on it, rather than returning `null` and\n booting into the default the way `problems` does. Defining a value and watching it resolve are\n one task; they were two panels. */\n state: \"data\",\n};\n\n/** The panel the Navigator wakes up on when nothing usable is stored. */\nexport const DEFAULT_PANEL_ID: NavigatorPanelId = \"layers\";\n\n/** Whether a string is a declared panel id. */\nexport function isNavigatorPanelId(value: unknown): value is NavigatorPanelId {\n return typeof value === \"string\" && (NAVIGATOR_PANEL_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Narrow an id arriving from a `string`-typed roster, or throw naming where it came from.\n *\n * The lock on the door {@link NAVIGATOR_PANEL_IDS} describes, in one place so the rail and the ⌘1–8\n * dispatcher cannot disagree about what an undeclared id means. Both receive their id from\n * `PanelRecord.id`, which is deliberately a `string` — the registry hosts the Bottom dock's panels\n * too, and their ids are {@link BOTTOM_TAB_IDS}.\n *\n * It throws rather than returning null because `tests/panel-registry.test.ts` asserts the enum and\n * the registry agree, so a failure here means the two have drifted — and the symptom of the last\n * drift was a control that silently did nothing.\n */\nexport function requireNavigatorPanelId(value: string, source: string): NavigatorPanelId {\n if (!isNavigatorPanelId(value)) {\n throw new Error(`${source}: \"${value}\" is not a declared Navigator panel id.`);\n }\n return value;\n}\n\n/**\n * Translate a stored panel id into a current one, or `null` when it names nothing.\n *\n * `null` rather than a default, so the caller decides: the boot path falls back to\n * {@link DEFAULT_PANEL_ID}, and a test can tell \"I stored junk\" from \"I stored `layers`\".\n *\n * `\"problems\"` is the one id that returns `null` because it MOVED rather than because it was junk:\n * a build before §7.2's correction could persist `leftTab: \"problems\"`, and the Navigator can no\n * longer show it. There is no alias to add — Problems is not a Navigator panel under any name — so\n * the shell boots into {@link DEFAULT_PANEL_ID} and the Bottom dock keeps its own `bottomTab`,\n * which already defaults to Problems. This is exactly the wedge this function exists to prevent.\n */\nexport function migratePanelId(stored: unknown): NavigatorPanelId | null {\n if (typeof stored !== \"string\") {\n return null;\n }\n const renamed = RENAMED_PANEL_IDS[stored];\n if (renamed) {\n return renamed;\n }\n return isNavigatorPanelId(stored) ? stored : null;\n}\n\n/**\n * The Inspector's tab ids, in strip order — the `value`s `panels/right-panel.ts` renders.\n *\n * Four now, and `\"assistant\"` is one of them: the chat is a tab of this dock, so the id space that\n * addresses Content, Style and Logic addresses it too. The old arrangement needed a fourth verb\n * (`view.setAssistant`) precisely because the assistant was somewhere else; it survives as the\n * dock-toggle spelling of \"show me the assistant\", but it now writes the same field as the others.\n *\n * The ORDER is §3.2 ⑨'s — Content · Style · Logic · Assistant — which is the order ⌘⇧1–4 follow.\n * The human titles live in `commands/defaults.ts`'s `INSPECTOR_TABS` (a module with no state and no\n * DOM, so the CI checks can load it); `tests/right-panel.test.ts` asserts the two agree, the same\n * way `tests/panel-registry.test.ts` does for the rail.\n */\nexport const INSPECTOR_TAB_IDS = [\"properties\", \"style\", \"events\", \"assistant\"] as const;\n\nexport type InspectorTabId = (typeof INSPECTOR_TAB_IDS)[number];\n\n/** The tab the Inspector falls back to — the leftmost, Content. */\nexport const DEFAULT_INSPECTOR_TAB: InspectorTabId = \"properties\";\n\n/** Whether a string is a declared Inspector tab id. */\nexport function isInspectorTabId(value: unknown): value is InspectorTabId {\n return typeof value === \"string\" && (INSPECTOR_TAB_IDS as readonly string[]).includes(value);\n}\n\n/**\n * The Bottom dock's tab ids, in strip order — plan §3.2 ⑪, at the documented cap of four.\n *\n * **Four, not five.** `scripts/check-chrome-budget.ts` caps a dock at four tabs, and §12's P4 entry\n * resolves the fifth candidate explicitly: **Deploy folds into Activity**, because a deploy IS a\n * long operation with a log, and giving it its own tab would have bought a fifth strip item to say\n * what the fourth already says.\n *\n * Declared here, beside {@link NAVIGATOR_PANEL_IDS} and {@link INSPECTOR_TAB_IDS} and for the same\n * reason: `view.setBottomTab`'s `args` enum is built from it, and `commands/app-commands.ts` must\n * load that enum in a bare Bun process, which it could not do from a module that renders lit\n * templates. `panels/bottom-dock.ts` builds its strip from this list and\n * `tests/bottom-dock.test.ts` asserts the two agree, exactly as the rail's do.\n */\nexport const BOTTOM_TAB_IDS = [\"problems\", \"logic\", \"activity\"] as const;\n\nexport type BottomTabId = (typeof BOTTOM_TAB_IDS)[number];\n\n/** The tab the Bottom dock opens on. Problems, because that is the one it opens itself for. */\nexport const DEFAULT_BOTTOM_TAB: BottomTabId = \"problems\";\n\n/** Whether a string is a declared Bottom dock tab id. */\nexport function isBottomTabId(value: unknown): value is BottomTabId {\n return typeof value === \"string\" && (BOTTOM_TAB_IDS as readonly string[]).includes(value);\n}\n\n/** The Studio chrome's Spectrum theme — the `color` attribute on `<sp-theme>`. */\nexport const CHROME_THEMES = [\"light\", \"dark\"] as const;\n\nexport type ChromeTheme = (typeof CHROME_THEMES)[number];\n\n/** Which shell region currently owns keyboard focus (`focus.region` in the command context). */\nexport type FocusRegion = \"rail\" | \"navigator\" | \"pane\" | \"inspector\" | \"dock\" | \"status\";\n\n/**\n * Open/closed plus size, per dock. Persisted together under one storage key.\n *\n * `size` and not `width`: the Bottom dock resizes on the other axis, so the field is measured along\n * whichever axis its dock's handle drags — px across for the two side docks, px tall for the bottom\n * one. {@link DOCK_CSS_VAR} names the custom property each one is projected onto, and that is where\n * the axis is stated in a place CSS can read.\n */\nexport interface DockState {\n collapsed: boolean;\n size: number;\n}\n\n/** One row of `git log`, as the Source Control panel's History tab renders it. */\nexport interface GitLogEntry {\n hash: string;\n message: string;\n author: string;\n date: string;\n}\n\n/** Source control — project level, one copy, independent of which document is focused. */\nexport interface ShellGit {\n status: GitStatusResult | null;\n branches: GitBranchesResult | null;\n commitMessage: string;\n loading: boolean;\n error: string | null;\n diffState: GitDiffState | null;\n logEntries: GitLogEntry[] | null;\n /** \"changes\" | \"history\" — the panel's sub-tab. */\n subTab: string;\n /** Epoch ms of the last successful refresh, or null when never refreshed. */\n lastUpdated: number | null;\n}\n\n/** The stylebook catalogue's selection and filters — project level, like the styles they edit. */\nexport interface ShellStylebook {\n selection: string | null;\n /** \"elements\" | \"variables\" */\n tab: string;\n filter: string;\n customizedOnly: boolean;\n}\n\n/**\n * A named arrangement of the shell — plan §3.2 ①b.\n *\n * A layout is a TUPLE, not a mode: which Navigator panel is showing, whether each dock is open and\n * how wide, and which Inspector tab is selected. Picking one reconfigures; it never removes. Every\n * panel stays reachable by rail, chord and palette afterwards, because §13 rejects workspaces that\n * gate features — telling a copy editor the Style panel \"is in ⌘K\" hands the non-technical user the\n * one affordance they are least likely to reach for.\n *\n * The field this replaces (`shell.layout`, a string with a declared default and NO writer) was the\n * exact failure `layoutSelection` had already been through: a record nothing sets, read by chrome\n * that therefore cannot change. Wiring it was the alternative to deleting it, and these are the\n * writers.\n *\n * **Editor kind is deliberately not in the tuple.** §3.2 ①b names it, but nothing in the shell can\n * apply it: switching a pane's editor is `studio.ts`'s `setCanvasMode`, which this module does not\n * have and cannot be handed without changing a bootstrap it does not own. A fourth field no writer\n * could honour would recreate the defect this type exists to close, so the tuple is three fields\n * and the fourth arrives with the pane record that can carry it.\n */\nexport interface LayoutPreset {\n /** Stable key. Built-ins use their own lowercase name; a saved layout gets a slug of its. */\n id: string;\n /** What the Command Bar tab reads. Renamed by double-clicking it. */\n name: string;\n /** Which Navigator panel this arrangement shows. */\n navigatorPanel: NavigatorPanelId;\n /** Which Inspector tab this arrangement selects. */\n inspectorTab: InspectorTabId;\n /** Which Bottom dock tab this arrangement selects — read whether or not the dock is open. */\n bottomTab: BottomTabId;\n /** Dock visibility and sizes, all three of them. */\n docks: Record<DockId, DockState>;\n}\n\nexport interface ShellState {\n /** Which panel the Navigator dock shows. One of {@link NAVIGATOR_PANEL_IDS}. */\n leftTab: string;\n /**\n * Which tab the Bottom dock shows. One of {@link BOTTOM_TAB_IDS}.\n *\n * A `string` for the same reason `leftTab` is: it is also read back from persisted state, and the\n * COMMAND (`view.setBottomTab`) is what refuses an undeclared id, at the one door callers use.\n */\n bottomTab: string;\n /** The Studio chrome's Spectrum theme. One of {@link CHROME_THEMES}. */\n theme: ChromeTheme;\n docks: Record<DockId, DockState>;\n /**\n * Where the splitter sits between two panes, as the primary's share of the grid — [0.2, 0.8].\n *\n * On `shell` rather than on `workspace` because it is pure LAYOUT: it names no tab, no document\n * and no pane identity, and it is remembered with the dock widths because it is the same kind of\n * thing. Read only when `workspace.panes.length > 1`, so a value restored with no split open is\n * inert rather than wrong.\n */\n paneSplit: number;\n focusRegion: FocusRegion;\n /** The active {@link LayoutPreset}'s id — the Command Bar tab drawn as selected. */\n layout: string;\n /** Every layout this project has, built-ins included. Persisted per project root. */\n layouts: LayoutPreset[];\n layoutSelection: LayoutSelection | null;\n /** Which section Project Settings opens on. */\n settingsTab: string;\n stylebook: ShellStylebook;\n git: ShellGit;\n}\n\nconst DOCK_STORAGE_KEY = \"jx-studio-panel-widths\";\n\nconst THEME_STORAGE_KEY = \"jx-studio-theme\";\n\n/**\n * The per-project record's key prefix — one namespaced record per project root (§4.4).\n *\n * Namespaced because a layout is an arrangement of THIS project's panels: \"Ship\" over a repo with\n * no git remote is not the same tuple as \"Ship\" over one that has one, and two projects sharing a\n * key means opening the second silently rewrites the first.\n *\n * Dock geometry stays in {@link DOCK_STORAGE_KEY}, which is read at module scope, before any\n * project root exists. It is workspace state — `resetProjectShell()` has always kept it across a\n * project switch for that reason — and moving it here would mean the shell could not lay itself out\n * until a project opened.\n */\nconst PROJECT_STORAGE_PREFIX = \"jx-studio-project::\";\n\n/**\n * The chrome theme Studio wakes up in.\n *\n * `index.html` hard-codes `color=\"dark\"` on `<sp-theme>` so the first paint has a theme before this\n * module evaluates; the default here has to agree with it or the shell flashes.\n */\nconst DEFAULT_THEME: ChromeTheme = \"dark\";\n\n/** Whether a string is one of the declared {@link CHROME_THEMES}. */\nfunction isChromeTheme(value: unknown): value is ChromeTheme {\n return typeof value === \"string\" && (CHROME_THEMES as readonly string[]).includes(value);\n}\n\n/** Read the persisted theme, falling back to {@link DEFAULT_THEME} on absent/corrupt storage. */\nfunction readPersistedTheme(): ChromeTheme {\n try {\n const stored = localStorage.getItem(THEME_STORAGE_KEY);\n return isChromeTheme(stored) ? stored : DEFAULT_THEME;\n } catch {\n return DEFAULT_THEME;\n }\n}\n\nexport const DOCK_IDS: DockId[] = [\"left\", \"right\", \"bottom\"];\n\n/**\n * First-run docks.\n *\n * The two side docks open, because the shell's whole point is that it says where you are. The\n * Bottom dock CLOSED, because it is the one dock whose contents are usually empty: a Problems list\n * with nothing in it and an Activity log with nothing running would spend 220px of the canvas — the\n * one region §3.2 says must never disappear — to say \"nothing has gone wrong\". ⌘J opens it, the\n * rail badge and the status bar say when it has something to show, and nothing opens it for you.\n */\nconst DOCK_DEFAULTS: Record<DockId, DockState> = {\n bottom: { collapsed: true, size: 220 },\n left: { collapsed: false, size: 240 },\n right: { collapsed: false, size: 280 },\n};\n\n/** The size a dock returns to when its handle is double-clicked. */\nexport const DOCK_DEFAULT_SIZES: Record<DockId, number> = {\n bottom: DOCK_DEFAULTS.bottom.size,\n left: DOCK_DEFAULTS.left.size,\n right: DOCK_DEFAULTS.right.size,\n};\n\n/**\n * The custom property each dock's size is projected onto — and where its axis is written down.\n *\n * `--panel-w-*` feeds `grid-template-columns`, `--dock-h-bottom` feeds `grid-template-rows`. Both\n * carry a declared fallback in `styles/tokens.css`, because an unset custom property inside a\n * `grid-template-*` shorthand invalidates the WHOLE declaration at computed-value time and the\n * shell would paint with no grid at all for the frame before the effect first runs.\n */\nconst DOCK_CSS_VAR: Record<DockId, string> = {\n bottom: \"--dock-h-bottom\",\n left: \"--panel-w-left\",\n right: \"--panel-w-right\",\n};\n\nconst DOCK_CLASS: Record<DockId, string> = {\n bottom: \"bottom-collapsed\",\n left: \"left-collapsed\",\n right: \"right-collapsed\",\n};\n\n/**\n * The persisted shell record. Absent keys keep the declared default.\n *\n * `leftTab` rides in the same record as the dock geometry because it is remembered for the same\n * reason and by the same writer — one key, one shape, one `JSON.stringify`. P3.7 replaces the whole\n * thing with a per-project session record; until then, adding a second localStorage key would\n * recreate the two-writer bug this record was consolidated to fix.\n */\ninterface PersistedDocks {\n left?: number;\n right?: number;\n bottom?: number;\n leftCollapsed?: boolean;\n rightCollapsed?: boolean;\n bottomCollapsed?: boolean;\n /** The Navigator panel last shown. Migrated through {@link migratePanelId} on read. */\n leftTab?: string;\n /** The Bottom dock tab last shown. Checked by {@link isBottomTabId} on read. */\n bottomTab?: string;\n /** The pane splitter's position. Clamped on READ — see {@link clampPaneSplit}. */\n paneSplit?: number;\n}\n\n/** An even split — what the grid opens on, and what a double-click on the splitter restores. */\nexport const DEFAULT_PANE_SPLIT = 0.5;\n\n/**\n * Coerce a stored split into the supported range.\n *\n * Clamped here, at the READ, rather than at the drag site: the drag already refuses to leave the\n * range, so the only way a bad value arrives is a corrupt or hand-edited record — and that is the\n * one caller that has to be defended.\n */\nfunction clampPaneSplit(value: unknown): number {\n return typeof value === \"number\" && value >= 0.2 && value <= 0.8 ? value : DEFAULT_PANE_SPLIT;\n}\n\n/** Move the splitter. Clamped, and the one writer every control routes through. */\nexport function setPaneSplit(value: number): void {\n shell.paneSplit = Math.min(0.8, Math.max(0.2, value));\n}\n\n/** Read the persisted dock record, tolerating absent/corrupt storage. */\nfunction readPersistedDocks(): PersistedDocks {\n try {\n return JSON.parse(localStorage.getItem(DOCK_STORAGE_KEY) || \"{}\") as PersistedDocks;\n } catch {\n return {};\n }\n}\n\nfunction freshGit(): ShellGit {\n return {\n branches: null,\n commitMessage: \"\",\n diffState: null,\n error: null,\n lastUpdated: null,\n loading: false,\n logEntries: null,\n status: null,\n subTab: \"changes\",\n };\n}\n\nfunction freshStylebook(): ShellStylebook {\n return { customizedOnly: false, filter: \"\", selection: null, tab: \"elements\" };\n}\n\n/**\n * The four layouts every project starts with — §3.2 ①b's `Write · Design · Build · Ship`.\n *\n * Each is a real arrangement of surfaces that already exist, not a mode: Write puts the file set\n * beside the prose and the Inspector on Content; Design opens the Outline against the Style tab;\n * Build pairs Data with Logic; Ship opens Source Control and gives the whole width to the diff by\n * collapsing the Inspector — which stays one ⌘B away, because a layout never removes.\n *\n * Written as a factory so every project gets its own objects: they are mutable records (a saved\n * layout overwrites the one with its name) and a shared array literal would leak one project's\n * edits into the next.\n */\nfunction builtInLayouts(): LayoutPreset[] {\n return [\n {\n bottomTab: \"problems\",\n docks: {\n bottom: { collapsed: true, size: 220 },\n left: { collapsed: false, size: 240 },\n /* WRITE COLLAPSES THE INSPECTOR. §3.1's arithmetic is the whole point of this preset:\n 1600px − 56 rail − 240 navigator ≈ **1284px of page, 80%**, against Design's 974. It\n shipped with the Inspector open at 280px, which is Design's number and makes Write a\n Design with a different panel selected.\n\n It does NOT re-open on selection. The plan's sentence reads \"until something is\n selected\", and clicking a paragraph to put a caret in it IS a selection — a dock that\n opened every time you clicked into prose would take the 80% back on the first keystroke.\n `⌘⇧1`–`⌘⇧4` expand it (`focusInspectorTab` sets `collapsed: false` before it focuses), so\n the Inspector is one chord away whenever it is wanted. */\n right: { collapsed: true, size: 280 },\n },\n id: \"write\",\n inspectorTab: \"properties\",\n name: \"Write\",\n navigatorPanel: \"files\",\n },\n {\n bottomTab: \"problems\",\n docks: {\n bottom: { collapsed: true, size: 220 },\n left: { collapsed: false, size: 240 },\n right: { collapsed: false, size: 320 },\n },\n id: \"design\",\n inspectorTab: \"style\",\n name: \"Design\",\n navigatorPanel: \"layers\",\n },\n {\n bottomTab: \"logic\",\n docks: {\n bottom: { collapsed: true, size: 260 },\n left: { collapsed: false, size: 280 },\n right: { collapsed: false, size: 300 },\n },\n id: \"build\",\n inspectorTab: \"events\",\n name: \"Build\",\n navigatorPanel: \"data\",\n },\n {\n // The one built-in that OPENS the Bottom dock, on Activity: shipping is a long operation\n // With a log, which is exactly what that tab is (§12 P4 — Deploy folds into Activity).\n bottomTab: \"activity\",\n docks: {\n bottom: { collapsed: false, size: 240 },\n left: { collapsed: false, size: 300 },\n right: { collapsed: true, size: 280 },\n },\n id: \"ship\",\n inspectorTab: \"properties\",\n name: \"Ship\",\n navigatorPanel: \"git\",\n },\n ];\n}\n\n/** The layout a project wakes up on, and the fallback when a stored id names nothing. */\nexport const DEFAULT_LAYOUT_ID = \"design\";\n\n/**\n * Build the whole record — nested collections complete — before it is handed to `reactive()`.\n *\n * Assembling it this way is not style: writing into a nested plain object AFTER the proxy exists\n * goes through the raw target and skips every effect depending on it.\n */\nfunction createShellState(): ShellState {\n const saved = readPersistedDocks();\n const docks = {} as Record<DockId, DockState>;\n for (const id of DOCK_IDS) {\n const width = saved[id];\n const collapsed = saved[`${id}Collapsed` as const];\n docks[id] = {\n // A stored `false` has to REOPEN a dock, so this cannot be the usual\n // `if (saved.x) { collapse() }` shape — that silently pins a dock shut forever for\n // Everyone who ever closed it once.\n collapsed: typeof collapsed === \"boolean\" ? collapsed : DOCK_DEFAULTS[id].collapsed,\n size: typeof width === \"number\" && width > 0 ? width : DOCK_DEFAULTS[id].size,\n };\n }\n return {\n bottomTab: isBottomTabId(saved.bottomTab) ? saved.bottomTab : DEFAULT_BOTTOM_TAB,\n docks,\n focusRegion: \"pane\",\n paneSplit: clampPaneSplit(saved.paneSplit),\n git: freshGit(),\n layout: DEFAULT_LAYOUT_ID,\n layoutSelection: null,\n layouts: builtInLayouts(),\n leftTab: migratePanelId(saved.leftTab) ?? DEFAULT_PANEL_ID,\n settingsTab: \"stylebook\",\n stylebook: freshStylebook(),\n theme: readPersistedTheme(),\n };\n}\n\n/*\n * The startup profile is applied HERE, above the first read of persisted state.\n *\n * `?profile=fresh` has to mean \"the app woke up with nothing\", and this module's `createShellState()`\n * is the earliest `localStorage.getItem` in the import graph — every other read is inside a function\n * and therefore runs after module evaluation. Clearing storage a statement later would restore the\n * dock widths from a profile that claims not to have any.\n */\napplyStartupProfile();\n\n/*\n * The input is widened before `reactive()` sees it: `UnwrapNestedRefs<ShellState>` recurses through\n * `LayoutHit` and the git result shapes deeply enough for tsc to give up (TS2589). The proxy is\n * deep either way — only the type computation is short-circuited — and the declared annotation is\n * what every consumer sees. Same reason `tabs/tab.ts` casts its own reactive tree.\n */\nexport const shell: ShellState = reactive(\n createShellState() as unknown as Record<string, unknown>,\n) as unknown as ShellState;\n\n/**\n * Write the whole dock record in one shot.\n *\n * One writer, one shape. The predecessor had two: `persistWidths()` wrote a fresh `{left,right,…}`\n * to this key while `applyPanelCollapse()` read-merge-wrote the collapse booleans into it, so\n * dragging any handle wiped all of them.\n */\nexport function persistDocks(): void {\n try {\n localStorage.setItem(\n DOCK_STORAGE_KEY,\n JSON.stringify({\n bottom: shell.docks.bottom.size,\n bottomCollapsed: shell.docks.bottom.collapsed,\n bottomTab: shell.bottomTab,\n left: shell.docks.left.size,\n leftCollapsed: shell.docks.left.collapsed,\n leftTab: shell.leftTab,\n paneSplit: shell.paneSplit,\n right: shell.docks.right.size,\n rightCollapsed: shell.docks.right.collapsed,\n } satisfies PersistedDocks),\n );\n } catch {\n // Storage full or unavailable — the layout is still applied, just not remembered.\n }\n}\n\n// ─── Named layouts (§3.2 ①b) ──────────────────────────────────────────────────\n\n/** What a project's namespaced record holds: its named layouts, and the session it was left in. */\ninterface PersistedProject {\n layouts?: unknown;\n activeLayout?: unknown;\n /** §4.4's session — open documents per pane, the active one, and each one's view settings. */\n session?: unknown;\n}\n\n/** The project whose layouts are loaded, or `undefined` before the first sync. */\nlet _layoutRoot: string | null | undefined;\n\n/** Whether a parsed value is a usable {@link LayoutPreset} — a stored record is untrusted input. */\nfunction isLayoutPreset(value: unknown): value is LayoutPreset {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const preset = value as Partial<LayoutPreset>;\n return (\n typeof preset.id === \"string\" &&\n preset.id !== \"\" &&\n typeof preset.name === \"string\" &&\n isNavigatorPanelId(preset.navigatorPanel) &&\n isInspectorTabId(preset.inspectorTab) &&\n isBottomTabId(preset.bottomTab) &&\n DOCK_IDS.every((dock) => typeof preset.docks?.[dock]?.size === \"number\")\n );\n}\n\n/** The raw record for `root`, or `{}` for absent, corrupt or hand-edited storage. */\nfunction rawPersistedProject(root: string | null): PersistedProject {\n if (!root) {\n return {};\n }\n try {\n return JSON.parse(\n localStorage.getItem(`${PROJECT_STORAGE_PREFIX}${root}`) || \"{}\",\n ) as PersistedProject;\n } catch {\n return {};\n }\n}\n\n/** Read a project's namespaced record, tolerating absent, corrupt and hand-edited storage. */\nfunction readPersistedProject(root: string | null): {\n layouts: LayoutPreset[];\n activeLayout: string | null;\n} {\n const fresh = { activeLayout: null, layouts: builtInLayouts() };\n if (!root) {\n return fresh;\n }\n const parsed = rawPersistedProject(root);\n const layouts = Array.isArray(parsed.layouts) ? parsed.layouts.filter(isLayoutPreset) : [];\n if (layouts.length === 0) {\n return fresh;\n }\n return {\n activeLayout: typeof parsed.activeLayout === \"string\" ? parsed.activeLayout : null,\n layouts,\n };\n}\n\n/**\n * The session `root` was last left in, or `null` when there is none to restore.\n *\n * Separate from {@link readPersistedProject} because the two are read at different moments: the\n * layouts load reactively the instant the project root changes, and the session is read once, by\n * the open sequence, at the point where it would otherwise open the home page.\n */\nexport function persistedSession(root: string | null): PersistedSession | null {\n return readSession(rawPersistedProject(root).session);\n}\n\n/**\n * The project whose session has been READ, and may therefore be overwritten.\n *\n * Without this the feature ate itself. Opening a project sets `workspace.projectRoot`, which fires\n * the persist effect below while the workspace is still empty — so `captureSession()` returned\n * `{panes: []}` and wrote it over the record the open sequence was about to read, three lines\n * later. The stored session was always destroyed a moment before it was wanted.\n *\n * So a session is only written for a root that has already been restored from. Until then the\n * stored one is carried forward verbatim, and a project that fails halfway through opening leaves\n * the record it could not use intact.\n */\nlet _sessionRoot: string | null = null;\n\n/** Declare that `root`'s session has been read, so this window may now write over it. */\nexport function markSessionRestored(root: string | null): void {\n _sessionRoot = root;\n}\n\n/**\n * Write the project's namespaced record. One key, one writer, one shape.\n *\n * The dock record's two-writer bug (`persistWidths` vs `applyPanelCollapse`, both on\n * {@link DOCK_STORAGE_KEY}) is the reason this is a single function that serialises the whole\n * record rather than a merge at each call site.\n */\n/**\n * Write the session on the way out — the moment the whole feature exists for.\n *\n * The effect above tracks the session's SHAPE. The view settings ride along on the next shape\n * change, so a zoom or a breakpoint chosen after the last tab was opened would otherwise be the one\n * thing a relaunch forgot. `beforeunload` cannot await, and this does not need to: one synchronous\n * `localStorage` write.\n */\nexport function flushSession(): void {\n persistProjectShell();\n}\n\nexport function persistProjectShell(): void {\n const root = workspace.projectRoot;\n if (!root) {\n return;\n }\n try {\n localStorage.setItem(\n `${PROJECT_STORAGE_PREFIX}${root}`,\n JSON.stringify({\n activeLayout: shell.layout,\n layouts: shell.layouts,\n // Only for a project whose session has been read — see {@link markSessionRestored}.\n session: root === _sessionRoot ? captureSession() : rawPersistedProject(root).session,\n } satisfies PersistedProject),\n );\n } catch {\n // Storage full or unavailable — the arrangement is applied, just not remembered.\n }\n}\n\n/**\n * Load the layouts belonging to `root`. Idempotent per root, so the effect can call it freely.\n *\n * Loading does NOT apply the active layout: a boot that re-applied it would overwrite the dock\n * widths the user dragged since, which are persisted separately and are the more recent statement.\n * The stored id says which tab is drawn as selected; clicking it is what re-applies the tuple.\n */\nexport function syncProjectLayouts(root: string | null): void {\n if (root === _layoutRoot) {\n return;\n }\n _layoutRoot = root;\n const { activeLayout, layouts } = readPersistedProject(root);\n shell.layouts = layouts;\n const has = (id: string | null) => id !== null && layouts.some((preset) => preset.id === id);\n // The stored active layout wins, then the one already selected, then the default, then whatever\n // The project actually has — a bar drawn with nothing selected says the app has lost your place.\n shell.layout = has(activeLayout)\n ? activeLayout!\n : has(shell.layout)\n ? shell.layout\n : has(DEFAULT_LAYOUT_ID)\n ? DEFAULT_LAYOUT_ID\n : (layouts[0]?.id ?? DEFAULT_LAYOUT_ID);\n}\n\n/** The layout with this id, or `undefined`. */\nexport function layoutById(id: string): LayoutPreset | undefined {\n return shell.layouts.find((preset) => preset.id === id);\n}\n\n/** A stable id for a saved layout's name: `My Layout` → `my-layout`. */\nexport function layoutIdFor(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/g, \"-\")\n .replaceAll(/^-|-$/g, \"\");\n return slug || \"layout\";\n}\n\n/** What applying or capturing a layout needs from the Inspector, which lives on the active tab. */\nexport interface LayoutDeps {\n setInspectorTab: (tab: InspectorTabId) => void;\n inspectorTab: () => InspectorTabId;\n}\n\n/**\n * Adopt a layout: its panel, its docks, its Inspector tab — and remember that it is the active one.\n *\n * Throws on an unknown id rather than silently doing nothing, because the id space is the user's\n * own (their saved layouts) and a typo in a command argument has to be reportable.\n */\nexport function applyLayout(id: string, deps: LayoutDeps): void {\n const preset = layoutById(id);\n if (!preset) {\n throw new RangeError(\n `no layout named \"${id}\" — this project has: ${shell.layouts.map((p) => p.id).join(\", \")}`,\n );\n }\n shell.layout = preset.id;\n shell.leftTab = preset.navigatorPanel;\n shell.bottomTab = preset.bottomTab;\n for (const dock of DOCK_IDS) {\n shell.docks[dock].collapsed = preset.docks[dock].collapsed;\n shell.docks[dock].size = preset.docks[dock].size;\n }\n deps.setInspectorTab(preset.inspectorTab);\n persistDocks();\n persistProjectShell();\n}\n\n/**\n * Save the current arrangement under `name`, and make it the active layout.\n *\n * Saving over an existing name overwrites it — that is what `+` on a layout you have just adjusted\n * means, and it keeps the operation idempotent for a caller that cannot see the list.\n */\nexport function saveLayout(name: string, deps: LayoutDeps): LayoutPreset {\n const trimmed = name.trim();\n const id = layoutIdFor(trimmed);\n const docks = {} as Record<DockId, DockState>;\n for (const dock of DOCK_IDS) {\n docks[dock] = { collapsed: shell.docks[dock].collapsed, size: shell.docks[dock].size };\n }\n const preset: LayoutPreset = {\n bottomTab: isBottomTabId(shell.bottomTab) ? shell.bottomTab : DEFAULT_BOTTOM_TAB,\n docks,\n id,\n inspectorTab: deps.inspectorTab(),\n name: trimmed || id,\n navigatorPanel: migratePanelId(shell.leftTab) ?? DEFAULT_PANEL_ID,\n };\n const existing = shell.layouts.findIndex((entry) => entry.id === id);\n if (existing === -1) {\n shell.layouts.push(preset);\n } else {\n shell.layouts.splice(existing, 1, preset);\n }\n shell.layout = id;\n persistProjectShell();\n return preset;\n}\n\n/** Rename a layout in place. The id — and therefore every reference to it — is unchanged. */\nexport function renameLayout(id: string, name: string): void {\n const preset = layoutById(id);\n const trimmed = name.trim();\n if (!preset || !trimmed) {\n return;\n }\n preset.name = trimmed;\n persistProjectShell();\n}\n\n/**\n * Forget a layout. The last one cannot be deleted: an empty Command Bar with a `+` and no way to\n * know what it does is worse than a layout you do not use.\n */\nexport function deleteLayout(id: string): void {\n if (shell.layouts.length < 2) {\n return;\n }\n const index = shell.layouts.findIndex((preset) => preset.id === id);\n if (index === -1) {\n return;\n }\n shell.layouts.splice(index, 1);\n if (shell.layout === id) {\n shell.layout = shell.layouts[0]!.id;\n }\n persistProjectShell();\n}\n\n/**\n * Re-apply the active layout as declared — `View: Reset Layout`, always one action away (§3.2 ①b).\n *\n * This is the escape hatch that makes a layout safe to drift from: drag a dock, collapse the\n * Inspector, open a different panel, and one command puts the arrangement back.\n */\nexport function resetLayout(deps: LayoutDeps): void {\n applyLayout(shell.layout, deps);\n}\n\n/**\n * Project the theme record onto `<sp-theme>`.\n *\n * The predecessor was a raw `document.querySelector(\"sp-theme\")?.setAttribute(...)` inside the\n * automation hook — a presentation poke no user could make and no surface could read back. It is a\n * shell input like the docks, so it lives on the record and is applied by the same effect.\n */\nexport function applyChromeTheme(): void {\n document.querySelector(\"sp-theme\")?.setAttribute(\"color\", shell.theme);\n}\n\n/** Project the dock record onto the shell grid: collapse classes on #app, sizes as CSS vars. */\nexport function applyDockLayout(): void {\n const root = document.documentElement;\n for (const id of DOCK_IDS) {\n root.style.setProperty(DOCK_CSS_VAR[id], `${shell.docks[id].size}px`);\n }\n const app = document.querySelector(\"#app\");\n if (!app) {\n return;\n }\n for (const id of DOCK_IDS) {\n app.classList.toggle(DOCK_CLASS[id], shell.docks[id].collapsed);\n }\n}\n\nlet _scope: EffectScope | null = null;\n\n/**\n * A surface that lives and dies with the shell but is drawn somewhere else.\n *\n * The Bottom dock is the first: it is a DOCK — projected onto the grid by this module's own record\n * and effect — but it renders lit templates over the panel registry, and a direct import here would\n * be a cycle (`shell → bottom-dock → shell`) that `oxlint`'s `import/no-cycle` refuses and that\n * would drag the panel registry into every bare-Bun process that reads the command enums.\n *\n * So the dependency points one way: the surface's own module registers itself, and this module\n * knows only that something wants to be mounted when the shell is.\n */\nexport interface ShellSurface {\n mount: () => void;\n unmount: () => void;\n}\n\nconst _surfaces: ShellSurface[] = [];\n\n/**\n * Attach a surface to the shell's lifecycle. Idempotent per object.\n *\n * Called at module scope by the surface itself, so importing it is enough — the same bargain\n * `ui/panel-resize.ts` makes, minus its unguarded `document` read at import time.\n */\nexport function registerShellSurface(surface: ShellSurface): void {\n if (!_surfaces.includes(surface)) {\n _surfaces.push(surface);\n }\n}\n\n/** Forget every registered surface. Tests only. */\nexport function resetShellSurfaces(): void {\n _surfaces.length = 0;\n}\n\n/**\n * Start the one effect that keeps the DOM in step with the dock record. Idempotent.\n *\n * Nothing else applies the grid: a caller flips `shell.docks.right.collapsed` and the layout\n * follows, whether the flip came from a click, the automation runner or the boot-time restore.\n */\nexport function mountShell(): void {\n if (_scope) {\n return;\n }\n // The six shell hosts are bare `<div id>`s in index.html, so they cannot stamp their own region\n // The way a panel or an overlay slot does. One table, applied once the tree exists.\n stampShellRegions();\n // The Bottom dock mounts from here rather than from the bootstrap because it is a DOCK: it is\n // Projected onto the grid by the same record and the same effect as the other two, and a second\n // Mounting site would be a second place the shell's own layout is decided. Every surface's own\n // Mount is idempotent and inert when its host is absent — the desktop shell and the tests both\n // Boot partial trees.\n for (const surface of _surfaces) {\n surface.mount();\n }\n _scope = effectScope();\n _scope.run(() => {\n effect(() => {\n applyDockLayout();\n });\n effect(() => {\n applyChromeTheme();\n });\n // Layouts belong to a project, and the project root is reactive: opening one loads its record\n // With no boot-order hook to forget. `resetProjectShell()` runs while the OLD root is still\n // Set — it is the closing half of a switch — which is why the load cannot live there.\n effect(() => {\n syncProjectLayouts(workspace.projectRoot);\n });\n /*\n * §4.4's session, written whenever its SHAPE changes.\n *\n * The reads below are the tracking list: which panes exist, what is in each strip and in what\n * order, which tab is active, and where the keyboard is. Every one of them is a deliberate act\n * by the author, and there are few enough of them per session that a `localStorage` write each\n * time costs nothing measurable.\n *\n * Per-tab view settings are captured at write time rather than tracked. Zoom moves on every\n * wheel tick, and an effect that persisted the record sixty times a second to remember a scale\n * would be a worse bug than forgetting the scale — so a mode change or a new tab carries the\n * zoom along with it, and `flushSession()` on the way out catches the rest.\n */\n effect(() => {\n const root = workspace.projectRoot;\n void workspace.activePaneId;\n for (const pane of workspace.panes) {\n void pane.id;\n void pane.activeTabId;\n void pane.tabOrder.join(\"\\u0000\");\n }\n if (root) {\n persistProjectShell();\n }\n });\n });\n}\n\nexport function unmountShell(): void {\n _scope?.stop();\n _scope = null;\n for (const surface of _surfaces) {\n surface.unmount();\n }\n}\n\n/**\n * Open or close a dock, and remember it.\n *\n * There is no cross-dock coupling left to write here. The predecessor had to keep \"assistant open,\n * inspector collapsed\" unreachable by hand, because the assistant was a fifth column sharing the\n * inspector's cell; a TAB cannot be in that state by construction — collapsing the Inspector dock\n * hides whichever of its four tabs was selected, assistant included.\n */\nexport function setDockCollapsed(dock: DockId, collapsed: boolean): void {\n if (shell.docks[dock].collapsed === collapsed) {\n persistDocks();\n return;\n }\n shell.docks[dock].collapsed = collapsed;\n persistDocks();\n}\n\n/** Flip a dock's open state, and remember it. */\nexport function toggleDock(dock: DockId): void {\n setDockCollapsed(dock, !shell.docks[dock].collapsed);\n}\n\n/** Resize a dock. Persisting is the caller's call — a drag persists once, on release. */\nexport function setDockSize(dock: DockId, size: number): void {\n shell.docks[dock].size = size;\n}\n\n/**\n * Reveal a Navigator panel: select it, make sure the dock is open, and remember both.\n *\n * `persistDocks()` is called unconditionally rather than relying on `setDockCollapsed` — that only\n * writes when the collapse flag actually changed, so re-picking a panel in an already-open dock\n * would have been forgotten.\n *\n * **The parameter is a {@link NavigatorPanelId}, not a `string`, and that is the whole guard.**\n * `shell.leftTab` stays a `string` because it is read back from state an older build persisted —\n * {@link migratePanelId} is what turns one of those into a current id. A LIVE caller is a different\n * question, and it was answered wrong: the Outline's empty state called this with `\"blocks\"` for\n * three phases after `blocks` became `insert`, so \"Add an element\" put the Navigator into\n * `unknownPanel`'s dead state (`panels/left-panel.ts`). The rename shipped a migration for the read\n * path and nothing for the write path, and no test could see it because a string is a string. This\n * signature makes that class of bug a type error at the call site.\n */\nexport function setActivityTab(tab: NavigatorPanelId): void {\n shell.leftTab = tab;\n setDockCollapsed(\"left\", false);\n persistDocks();\n}\n\n/**\n * Reveal a Bottom dock tab: select it, make sure the dock is open, and remember both.\n *\n * The Navigator's {@link setActivityTab} shape, for the same reason — \"show me the Activity log\"\n * means the log is on screen when it returns, not that a tab is selected inside a closed dock.\n */\nexport function setBottomTab(tab: string): void {\n shell.bottomTab = tab;\n setDockCollapsed(\"bottom\", false);\n persistDocks();\n}\n\n/** Set the chrome theme, apply it, and remember it. */\nexport function setChromeTheme(theme: ChromeTheme): void {\n if (shell.theme === theme) {\n return;\n }\n shell.theme = theme;\n try {\n localStorage.setItem(THEME_STORAGE_KEY, theme);\n } catch {\n // Storage full or unavailable — the theme is still applied, just not remembered.\n }\n}\n\n/**\n * Toggle-focus semantics for the rail: re-picking the panel that is already showing closes the dock\n * instead of reselecting it.\n */\nexport function toggleActivityTab(tab: NavigatorPanelId): void {\n if (tab === shell.leftTab && !shell.docks.left.collapsed) {\n setDockCollapsed(\"left\", true);\n return;\n }\n setActivityTab(tab);\n}\n\n/**\n * Adopt (or clear) a layout-chrome selection reported by the canvas.\n *\n * The canvas host calls this on a `layoutHit`, and clears it (`null`) whenever an ordinary document\n * node is selected — the two are mutually exclusive, and only one panel can be right at a time. It\n * exists as a function rather than a bare assignment so the one writer has a name: the field spent\n * a long release cycle with a reader (the properties panel's layout panel) and no writer at all,\n * which is why clicking a header did nothing.\n */\nexport function setLayoutSelection(selection: LayoutSelection | null): void {\n shell.layoutSelection = selection;\n}\n\n/**\n * Drop everything scoped to the project being closed.\n *\n * Source control, the stylebook selection and the settings tab all describe _a_ project; carrying\n * them into the next one showed the previous repository's branch, file count and \"last updated\"\n * time under the new project's name. Docks, the layout preset and the active rail panel are\n * deliberately kept — they describe the workspace, not the project.\n */\nexport function resetProjectShell(): void {\n Object.assign(shell.git, freshGit());\n Object.assign(shell.stylebook, freshStylebook());\n shell.settingsTab = \"stylebook\";\n shell.layoutSelection = null;\n // …and which project's session may be written, so the one being opened cannot be overwritten\n // Before it has been read.\n _sessionRoot = null;\n // Forget which project's layouts are loaded, so the next `syncProjectLayouts()` reloads even if\n // The same root is opened again. The docks and the active rail panel stay: they describe the\n // Workspace, and re-applying a layout on project open would discard the widths you just dragged.\n _layoutRoot = undefined;\n}\n\n// ─── Commands ─────────────────────────────────────────────────────────────────\n\n/** What the shell's view verbs need that this module does not own. */\nexport interface ShellCommandDeps {\n /**\n * Show an Inspector tab. Writes the ACTIVE TAB's `session.ui.rightTab`, which is per-document\n * session state this module deliberately does not reach into (`shell` is workspace state, and the\n * split is the whole point of the file).\n */\n setInspectorTab: (tab: InspectorTabId) => void;\n /**\n * Which Inspector tab is showing right now.\n *\n * Only `view.setAssistant { open: false }` needs it, and it needs it to stay idempotent: \"the\n * assistant is not showing\" is a state, not a delta, so the verb steps off the Assistant tab and\n * leaves any OTHER tab exactly where it was. Without the read it would have to guess, and a\n * screenshot that closed the assistant would silently also lose your Style tab.\n */\n inspectorTab: () => InspectorTabId;\n /**\n * Whether a dock tab's panel record is currently available — its own `when` holding.\n *\n * INJECTED rather than imported for the reason the rest of this object exists: `shell` is\n * workspace state and must not reach into the panel registry, which reaches back. It is here\n * because `panel.focus.<id>` composes the record's own `when` and these two enum setters did not,\n * so one surface answered two ways. `view.setActivity { tab: \"search\" }` succeeded against a\n * panel registered `when: () => false`, wrote `shell.leftTab = \"search\"`, un-collapsed the dock\n * and PERSISTED it — after which the Navigator drew \"No Navigator panel is registered as\n * 'search'\", a sentence that is false: it is registered, it is gated off. Defaults to available\n * so a caller with no registry (the CI projection) is unaffected.\n */\n panelAvailable?: (id: string) => boolean;\n}\n\n/** The Navigator dock hosts a panel — the precondition its own verbs share. */\nconst projectOpen = (ctx: { project: { open: boolean } }) => ctx.project.open;\n\n/**\n * The shell's view verbs: idempotent SETTERS, never toggles.\n *\n * Plan §13.3 clause 3 is the whole shape of this list. `view.toggleAssistant` names a _delta_\n * against state the caller cannot observe, so flipping the assistant's default silently inverted 18\n * screenshots and an agent calling it is guessing; `view.setAssistant { open: false }` means the\n * same thing whichever way the default points. The rail's own click handler keeps its\n * toggle-to-collapse behaviour ({@link toggleActivityTab}) because a human CAN see which panel is\n * open — that is a gesture, not an API.\n *\n * The `args` enums are the highest-value declaration here: `view.setActivity`'s `tab` is exactly\n * {@link NAVIGATOR_PANEL_IDS}, so renaming a panel turns every stale manifest step red naming both\n * ids, in the PR that renamed it (plan §13.5).\n *\n * @param {ShellCommandDeps} deps\n * @returns {AnyCommand[]}\n */\nexport function shellViewCommands(deps: ShellCommandDeps): AnyCommand[] {\n return [\n {\n args: argsSchema({\n tab: enumProperty(NAVIGATOR_PANEL_IDS, \"Which Navigator panel to show.\"),\n }),\n category: \"View\",\n id: \"view.setActivity\",\n level: \"application\",\n menus: [\"commandbar/overflow\", \"palette\"],\n group: \"4_docks\",\n requires: \"an open project\",\n when: projectOpen,\n aiTool: {\n description:\n \"Show one of the Navigator panels (Files, Search, Source Control, Languages, Outline, \" +\n \"Page, Data, Packages, Insert) and open the Navigator dock if it is closed. Languages is \" +\n \"the translation-parity grid, and it exists only in a project that declares two or more \" +\n \"locales. Problems is a Bottom dock tab — use show_bottom_tab for it.\",\n name: \"show_navigator_panel\",\n },\n run: (_ctx, args) => {\n const tab = enumArg(\"view.setActivity\", args, \"tab\", NAVIGATOR_PANEL_IDS);\n // The record's own `when`, asked here because `enablement` cannot see an argument — the\n // Same shape `pane.derive` uses to refuse a preset the document cannot support.\n if (deps.panelAvailable && !deps.panelAvailable(tab)) {\n throw new RangeError(\n `command \"view.setActivity\" argument \"tab\": \"${tab}\" names a panel that is registered but not ` +\n `available right now, so showing it would persist a Navigator tab nothing can draw`,\n );\n }\n setActivityTab(tab);\n },\n title: \"Show Navigator Panel\",\n },\n {\n args: argsSchema({\n tab: enumProperty(INSPECTOR_TAB_IDS, \"Which Inspector tab to show.\"),\n }),\n category: \"View\",\n id: \"view.setRightTab\",\n level: \"document\",\n menus: [\"palette\"],\n group: \"4_docks\",\n requires: \"an open document\",\n when: (ctx) => ctx.document.open,\n run: (_ctx, args) => {\n deps.setInspectorTab(enumArg(\"view.setRightTab\", args, \"tab\", INSPECTOR_TAB_IDS));\n },\n title: \"Show Inspector Tab\",\n },\n {\n args: argsSchema({\n open: booleanProperty(\"True to show the Navigator dock, false to collapse it.\"),\n }),\n category: \"View\",\n // The idempotent half of `toggleActivityTab`. A shot that wants the Navigator CLOSED used to\n // Say `view.toggleActivity { tab: \"layers\" }` — re-pick the open panel and the dock\n // Collapses — which only means \"closed\" if you already know it was open.\n id: \"view.setNavigator\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_docks\",\n run: (_ctx, args) => {\n setDockCollapsed(\"left\", !booleanArg(\"view.setNavigator\", args, \"open\"));\n },\n title: \"Show Navigator Dock\",\n },\n {\n args: argsSchema({\n open: booleanProperty(\"True to show the Inspector dock, false to collapse it.\"),\n }),\n category: \"View\",\n id: \"view.setRightPanel\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_docks\",\n run: (_ctx, args) => {\n setDockCollapsed(\"right\", !booleanArg(\"view.setRightPanel\", args, \"open\"));\n },\n title: \"Show Inspector Dock\",\n },\n {\n args: argsSchema({\n open: booleanProperty(\"True to show the Bottom dock, false to collapse it.\"),\n }),\n category: \"View\",\n // The idempotent half of `view.toggleBottomDock`, and the reason the toggle can exist at all:\n // `tests/app-commands.test.ts` fails any `toggle*` id with no `set*` beside it, and this one\n // Has been listed as HANDOFF debt since P2 because the dock was not on the `shell` record.\n // It is now, so this is a two-line `run` rather than the special case ⌘J used to need.\n id: \"view.setBottomDock\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_docks\",\n run: (_ctx, args) => {\n setDockCollapsed(\"bottom\", !booleanArg(\"view.setBottomDock\", args, \"open\"));\n },\n title: \"Show Bottom Dock\",\n },\n {\n // ⌘J. A gesture, not an API: a human presses it while looking at the dock, which is the\n // Exemption §13.3 clause 3 grants a toggle whose state the presser can SEE. A script says\n // `view.setBottomDock { open }` instead, and the test beside the registry enforces the pair.\n category: \"View\",\n id: \"view.toggleBottomDock\",\n keybinding: \"mod+j\",\n level: \"application\",\n menus: [\"commandbar/overflow\", \"palette\"],\n group: \"4_docks\",\n run: () => {\n toggleDock(\"bottom\");\n },\n title: \"Toggle Bottom Dock\",\n },\n {\n args: argsSchema({\n tab: enumProperty(BOTTOM_TAB_IDS, \"Which Bottom dock tab to show.\"),\n }),\n category: \"View\",\n id: \"view.setBottomTab\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_docks\",\n aiTool: {\n description:\n \"Show one of the Bottom dock's tabs (Problems, Diff, Logic, Activity) and open the \" +\n \"Bottom dock if it is closed.\",\n name: \"show_bottom_tab\",\n },\n run: (_ctx, args) => {\n const tab = enumArg(\"view.setBottomTab\", args, \"tab\", BOTTOM_TAB_IDS);\n // The record's own `when`, asked here because `enablement` cannot see an argument — the\n // Same shape `pane.derive` uses to refuse a preset the document cannot support.\n if (deps.panelAvailable && !deps.panelAvailable(tab)) {\n throw new RangeError(\n `command \"view.setBottomTab\" argument \"tab\": \"${tab}\" names a panel that is registered but not ` +\n `available right now, so showing it would persist a Bottom dock tab nothing can draw`,\n );\n }\n setBottomTab(tab);\n },\n title: \"Show Bottom Dock Tab\",\n },\n {\n args: argsSchema({\n open: booleanProperty(\"True to show the Assistant tab, false to step off it.\"),\n }),\n category: \"View\",\n // Kept as a verb of its own even though the assistant is now an ordinary Inspector tab: it\n // Is the one tab with a dock toggle's meaning (\"show me the assistant, wherever it lives\"),\n // Three screenshot shots address it by this name, and `open` reads as a STATE where\n // `view.setRightTab { tab: \"assistant\" }` can only ever select.\n id: \"view.setAssistant\",\n level: \"application\",\n /* `never`, not `palette` — and the reason is a rule, not a preference.\n This and `inspector.focus.assistant` are both `View` + \"Show Assistant\", so the palette\n printed the SAME SENTENCE twice, in two level groups, with two different chords: the only\n duplicate title among 130 records. A palette row is a NAME, and two rows with one name is\n the defect the registry exists to prevent, arriving through the registry itself.\n `inspector.focus.assistant` is the row (it carries ⌘⇧4). This one keeps every other\n consumer — the `open` STATE that `setRightTab` cannot express, the layout presets, three\n screenshot steps, `⌘J`'s legacy branch — none of which needs a row to work. */\n menus: [\"never\"],\n group: \"4_docks\",\n run: (_ctx, args) => {\n if (booleanArg(\"view.setAssistant\", args, \"open\")) {\n setDockCollapsed(\"right\", false);\n deps.setInspectorTab(\"assistant\");\n return;\n }\n if (deps.inspectorTab() === \"assistant\") {\n deps.setInspectorTab(DEFAULT_INSPECTOR_TAB);\n }\n },\n title: \"Show Assistant\",\n },\n // ── Named layouts ────────────────────────────────────────────────────────\n // Five verbs, because a named arrangement you can create but not rename, delete or restore is\n // A trap. All five are SETTERS: `view.setLayout { layout: \"ship\" }` means the same thing twice\n // In a row, and `view.resetLayout` is the one action that puts a drifted arrangement back.\n {\n args: argsSchema({\n layout: stringProperty(\"The layout's id — one of this project's saved layouts.\"),\n }),\n category: \"View\",\n id: \"view.setLayout\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_layouts\",\n requires: \"an open project\",\n when: projectOpen,\n aiTool: {\n description:\n \"Adopt one of the project's named layouts (Write, Design, Build, Ship, or one the user \" +\n \"saved): its Navigator panel, its dock widths and visibility, and its Inspector tab.\",\n name: \"set_layout\",\n },\n run: (_ctx, args) => {\n applyLayout(stringArg(\"view.setLayout\", args, \"layout\"), deps);\n },\n title: \"Switch Layout\",\n },\n {\n args: argsSchema({\n name: stringProperty(\"What to call this arrangement. An existing name is overwritten.\"),\n }),\n category: \"View\",\n id: \"view.saveLayout\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_layouts\",\n requires: \"an open project\",\n when: projectOpen,\n run: (_ctx, args) => {\n saveLayout(stringArg(\"view.saveLayout\", args, \"name\"), deps);\n },\n title: \"Save Layout\",\n },\n {\n args: argsSchema({\n layout: stringProperty(\"The layout's id.\"),\n name: stringProperty(\"Its new name. The id, and every reference to it, is unchanged.\"),\n }),\n category: \"View\",\n id: \"view.renameLayout\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_layouts\",\n requires: \"an open project\",\n when: projectOpen,\n run: (_ctx, args) => {\n renameLayout(\n stringArg(\"view.renameLayout\", args, \"layout\"),\n stringArg(\"view.renameLayout\", args, \"name\"),\n );\n },\n title: \"Rename Layout\",\n },\n {\n args: argsSchema({\n layout: stringProperty(\"The layout's id. The last remaining layout is kept.\"),\n }),\n category: \"View\",\n id: \"view.deleteLayout\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_layouts\",\n requires: \"an open project\",\n when: projectOpen,\n run: (_ctx, args) => {\n deleteLayout(stringArg(\"view.deleteLayout\", args, \"layout\"));\n },\n title: \"Delete Layout\",\n },\n {\n // No `args`: this verb takes none. An empty schema would be a promise of parameters the\n // Palette would then prompt for and the record would ignore.\n category: \"View\",\n id: \"view.resetLayout\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"4_layouts\",\n requires: \"an open project\",\n when: projectOpen,\n run: () => {\n resetLayout(deps);\n },\n title: \"Reset Layout\",\n },\n {\n args: argsSchema({\n color: enumProperty(CHROME_THEMES, \"The Studio chrome's theme.\"),\n }),\n category: \"View\",\n id: \"view.setTheme\",\n level: \"application\",\n menus: [\"palette\"],\n group: \"6_appearance\",\n run: (_ctx, args) => {\n setChromeTheme(enumArg(\"view.setTheme\", args, \"color\", CHROME_THEMES));\n },\n title: \"Set Theme\",\n },\n ];\n}\n\n/**\n * Register the shell's view verbs. Called from the bootstrap, beside the state they write.\n *\n * @param {CommandRegistry} registry\n * @param {ShellCommandDeps} deps\n */\nexport function registerShellViewCommands(registry: CommandRegistry, deps: ShellCommandDeps): void {\n registry.registerAll(shellViewCommands(deps));\n}\n",
|
|
32
|
+
"/// <reference lib=\"dom\" />\n/**\n * The project configuration document — `project.json` under the transaction log.\n *\n * `project.json` is the file that defines the project, and until now it was the one file Studio\n * edited with no document behind it. Twenty-nine call sites across eight modules each reached for\n * `platform.writeFile(\"project.json\", …)` (directly or through `updateSiteConfig`), in two\n * different serialisations, with no history and no dirty flag — and twenty-one of them dropped a\n * rejected write on the floor, leaving the form showing a value that was never persisted.\n *\n * This module is the one door. Every configuration write is now a TRANSACTION on a real {@link Tab}\n * whose `documentPath` is `project.json`, which is what buys undo, the dirty flag and ⌘S from the\n * machinery every other document already uses (`tabs/transact.ts`). `tab.ts`'s `inferModes` has\n * always answered `[\"stylebook\", \"source\"]` for this path, so the tab's editor kind is `config`\n * (see `editorKindForMode`) with no new wiring.\n *\n * **The document of record.** When the author has `project.json` open in the workspace, THAT tab is\n * the configuration document: the settings surfaces and the open tab edit one object, so neither\n * can silently clobber the other. When it is not open the module keeps a document of its own, with\n * the same log, and hands over the moment a tab appears. One rule, stated once:\n * `projectState.projectConfig` is always `toRaw(document.doc.document)`.\n *\n * **One object, and a handover that cannot lose an edit.** That rule is restored at the moment a\n * tab is adopted, and adoption is reached lazily — from inside a commit. So a `project.json` tab\n * opened from the Files tree (`files/files.ts` parses the file itself) arrives holding a SECOND\n * configuration object, and until the next commit the settings surfaces are still rendering, and\n * mutating in place, the one they were loaded with. {@link commitProjectConfig} therefore reads the\n * live configuration BEFORE it binds and commits THAT object's content, adopting it into the\n * document; the alternative — letting the tab's parse win because it happened to bind last —\n * dropped the first settings edit after the tab was opened, wrote the drop to disk, and reported\n * success. When the document holds unsaved authoring of its own the two cannot be reconciled, and\n * §16 gets a Problem instead of a silent winner. {@link adoptProjectConfig} is the same handover\n * from the other side: a config that reached disk without passing through here (the assistant's\n * `write_file`) is put INTO the document rather than left beside it as a rival.\n *\n * **One serialisation.** {@link serializeProjectConfig} is `JSON.stringify(config, null, 2)` —\n * byte-for-byte what `files/file-ops.ts`'s native-JSON branch writes, so a ⌘S on the open tab and a\n * settings edit produce the same file. The predecessor had `null, 2` in `site-context.ts` and\n * `\"\\t\"` in both `settings/contributed-section.ts` and `settings/defs-editor.ts`, so a settings\n * edit re-indented the entire file — every `project.json` in this repository is on disk with two\n * spaces.\n *\n * **A no-op edit writes nothing.** A form that re-commits the value it already holds — and every\n * one of these surfaces has such a path — used to rewrite the whole file. A commit now compares the\n * serialised result against what the file itself says and returns without a transaction, without a\n * write, and therefore with an empty diff.\n *\n * **Collaboration.** `project.json` is out of collab replication; the gate is in\n * `collab/collab-session.ts`'s `ensureCollab`, which is what would otherwise register the Yjs\n * history delegate over this tab.\n */\n\nimport { errorMessage } from \"@jxsuite/schema/parse\";\nimport { effect, toRaw } from \"../reactivity\";\nimport { getPlatform } from \"../platform\";\nimport { notify } from \"../services/notify\";\nimport { requireProjectState, setProjectState } from \"../state\";\nimport { setWorkspaceProject, workspace } from \"../workspace/workspace\";\nimport { PROJECT_CONFIG_PATH, createTab, disposeTab } from \"./tab\";\nimport { transactDoc } from \"./transact\";\n\nimport type { Tab } from \"./tab\";\nimport type { ProjectConfig } from \"@jxsuite/schema/types\";\n\nexport { PROJECT_CONFIG_PATH } from \"./tab\";\n\n/**\n * The project configuration, as a file.\n *\n * The ONE serialisation. Identical to the native-JSON branch of `files/file-ops.ts`'s\n * `serializeDocument`, which is what ⌘S on the open `project.json` tab goes through — the two must\n * agree or every save would fight the last one.\n *\n * @param {ProjectConfig} config\n * @returns {string}\n */\nexport function serializeProjectConfig(config: ProjectConfig): string {\n return JSON.stringify(config, null, 2);\n}\n\n// ─── The document of record ───────────────────────────────────────────────────\n\n/** The bound configuration document, or null before the first bind. */\nlet _bound: Tab | null = null;\n\n/** The document this module owns while no `project.json` tab is open. */\nlet _detached: Tab | null = null;\n\n/**\n * What the FILE says, re-serialised through {@link serializeProjectConfig}.\n *\n * Read from disk once per binding rather than assumed from the config in memory, because by the\n * time a commit arrives the caller has usually already mutated that config in place — the CSS\n * variables editor writes into `config.style` and then hands the same object over as a patch. A\n * value taken from memory would call every one of those edits a no-op.\n *\n * Comparing two `JSON.stringify(_, null, 2)` renderings of the same key order is a SEMANTIC test,\n * not a textual one, which is the point: `project.json` on disk is formatted by `oxfmt` (two-space\n * indent, short arrays kept on one line), so a byte comparison against the file would call every\n * edit a change and rewrite the whole file. This calls it unchanged and writes nothing.\n *\n * `null` means \"unknown\" — no project file, or one that would not parse — and every commit writes.\n */\nlet _committed: string | null = null;\n\n/** Whether {@link _committed} has been sought for the current binding. One read per project. */\nlet _seeding: Promise<void> | null = null;\n\n/**\n * The `project.json` tab the author has open, if any.\n *\n * Unwrapped, because `workspace.tabs` is a reactive Map and hands out a proxy: identity is how this\n * module decides whether to rebind, and the raw object is the identity every other tab-keyed\n * structure in Studio uses (`collab-session.ts`'s `rawTab` for the same reason).\n */\nfunction openConfigTab(): Tab | null {\n const tab = workspace.tabs.get(PROJECT_CONFIG_PATH);\n return tab ? (toRaw(tab as unknown as object) as Tab) : null;\n}\n\n/** Drop the current binding, disposing the detached document if that is what it was. */\nfunction unbind(): void {\n if (_detached) {\n disposeTab(_detached);\n _detached = null;\n }\n _bound = null;\n _committed = null;\n _seeding = null;\n}\n\n/** Learn what the file holds, once per binding. Memoised on the promise so commits cannot race. */\nfunction seedCommitted(): Promise<void> {\n _seeding ??= (async () => {\n try {\n const text = await getPlatform().readFile(PROJECT_CONFIG_PATH);\n _committed = serializeProjectConfig(JSON.parse(text) as ProjectConfig);\n } catch {\n // No file, an unreadable one, or one that does not parse. \"Unknown\" is the honest answer,\n // And an unknown file is one every commit must write.\n _committed = null;\n }\n })();\n return _seeding;\n}\n\n/**\n * Forget the configuration document — the project-switch and test hook.\n *\n * Also reached implicitly: {@link projectConfigDocument} rebinds whenever the project state stops\n * pointing at the bound document, which is what a reload or a second project does.\n */\nexport function resetProjectConfigDocument(): void {\n unbind();\n}\n\n/**\n * Keep `projectState` and the workspace pointing at the document.\n *\n * Called from the bind effect rather than from the commit, so it is equally true after an undo: ⌘Z\n * on the open `project.json` tab replaces the document root, and the app's live configuration has\n * to follow it or the canvas would keep rendering the state the author just took back.\n *\n * @param {ProjectConfig} config\n */\nfunction syncProjectState(config: ProjectConfig): void {\n const state = requireProjectState();\n if (state.projectConfig === config) {\n return;\n }\n setProjectState({ ...state, projectConfig: config });\n setWorkspaceProject(workspace.projectRoot, config);\n}\n\n/**\n * The configuration object the app is live on, unwrapped, or `null` before a project has one.\n *\n * Read at the TOP of a commit, before {@link projectConfigDocument} can rebind: this is the object\n * the settings surfaces rendered from and mutated in place, and after a rebind it may no longer be\n * the one `projectState` points at.\n *\n * @returns {ProjectConfig | null}\n */\nfunction liveConfig(): ProjectConfig | null {\n const config = requireProjectState()?.projectConfig;\n return config ? (toRaw(config as unknown as object) as ProjectConfig) : null;\n}\n\n/**\n * Make `target` hold exactly `source`'s keys — assignment alone would leave the removals behind.\n *\n * @param {Record<string, unknown>} target\n * @param {ProjectConfig} source\n */\nfunction replaceContents(target: Record<string, unknown>, source: ProjectConfig): void {\n for (const key of Object.keys(target)) {\n if (!Object.hasOwn(source, key)) {\n delete target[key];\n }\n }\n Object.assign(target, source);\n}\n\n/**\n * Adopt `tab` as the configuration document and install the state-sync effect in its scope.\n *\n * @param {Tab} tab\n * @returns {Tab}\n */\nfunction bind(tab: Tab): Tab {\n _bound = tab;\n tab.scope.run(() => {\n effect(() => {\n const doc = tab.doc.document;\n if (_bound !== tab || !requireProjectState()) {\n return;\n }\n syncProjectState(toRaw(doc) as unknown as ProjectConfig);\n });\n });\n return tab;\n}\n\n/**\n * The configuration document, bound on demand.\n *\n * Rebinding is driven by two observations rather than by a lifecycle callback nobody would remember\n * to call: the workspace's `project.json` tab appearing or going away, and the project state\n * ceasing to point at the bound document (a project switch, or a reload that re-parsed the file).\n *\n * @returns {Tab}\n */\nexport function projectConfigDocument(): Tab {\n const state = requireProjectState();\n const open = openConfigTab();\n if (\n _bound &&\n (_bound !== (open ?? _detached) || toRaw(_bound.doc.document) !== state.projectConfig)\n ) {\n unbind();\n }\n if (_bound) {\n return _bound;\n }\n if (open) {\n return bind(open);\n }\n _detached = createTab({\n document: (state.projectConfig ?? {}) as unknown as Record<string, unknown>,\n documentPath: PROJECT_CONFIG_PATH,\n id: PROJECT_CONFIG_PATH,\n });\n return bind(_detached);\n}\n\n// ─── The chokepoint ───────────────────────────────────────────────────────────\n\n/** What a commit did. A write failure is reported, never thrown — the caller decides the tier. */\nexport interface ProjectConfigCommit {\n ok: boolean;\n /** The platform's rejection, when the write failed. */\n error?: unknown;\n}\n\n/** Extensions, as a comparable value — the enabled-extension surface gate. */\nfunction extensionsKey(config: ProjectConfig): string {\n return JSON.stringify(config.extensions ?? null);\n}\n\n/** Rebuild the format registry and the contributed settings sections after an `extensions` edit. */\nasync function refreshExtensionSurfaces(): Promise<void> {\n const { loadFormats, refreshExtensionUi, refreshFormats } = await import(\"../format/format-host\");\n refreshFormats();\n void loadFormats();\n refreshExtensionUi(getPlatform());\n}\n\n/**\n * Commit the project configuration: one transaction, one serialisation, one error path.\n *\n * Two calling styles, because the surfaces have two shapes. Pass a `patch` and its top-level keys\n * are merged onto the document (a value of `undefined` CLEARS the key — `JSON.stringify` drops it,\n * which is how General Settings removes a production URL). Pass nothing and the caller has already\n * mutated the live configuration in place, which is what the master-detail editors do; the empty\n * transaction is what puts that mutation into the log.\n *\n * Either way the object committed is the one the CALLER was editing, read before the bind: a\n * `project.json` tab that appeared since the last commit is adopted here, and adopting it repoints\n * `projectState.projectConfig` at the tab's own parse of the file. Committing the document instead\n * would silently discard whatever the form had just written into the object it rendered from. The\n * two are one object again by the time this returns.\n *\n * A failed write leaves the document dirty and files a Problem (§16): it is about a named file and\n * it must be fixed, so it belongs in a list that keeps it rather than a toast that erases it. ⌘S on\n * the `project.json` tab is the retry, and it writes the same bytes this does. A commit that cannot\n * be applied at all — an edited configuration meeting a document with unsaved authoring of its own\n * — files the same kind of Problem and writes nothing, because picking a winner is what made the\n * loss silent in the first place.\n *\n * @param {Partial<ProjectConfig>} [patch]\n * @returns {Promise<ProjectConfigCommit>}\n */\nexport async function commitProjectConfig(\n patch?: Partial<ProjectConfig>,\n): Promise<ProjectConfigCommit> {\n // Before the bind, not after it: adopting a `project.json` tab repoints `projectState` at the\n // Tab's own parse, and the caller has already mutated the object it rendered from.\n const live = liveConfig();\n const tab = projectConfigDocument();\n await seedCommitted();\n const current = toRaw(tab.doc.document) as unknown as ProjectConfig;\n const currentText = serializeProjectConfig(current);\n\n // Two objects that disagree — whichever one loses, an edit written into it is lost. Null when\n // There is one object, or two saying the same thing, which is every commit after the first.\n const rival =\n live && live !== current && serializeProjectConfig(live) !== currentText ? live : null;\n\n if (rival && tab.doc.dirty) {\n /* The document holds unsaved authoring of its own — the source editor's, since a successful\n commit always leaves it clean — and the live configuration holds an edit the document has\n never seen. Applying either one discards the other, so neither is applied: §16 files the\n write that cannot be applied, which is the one outcome silence is not allowed to be.\n `ai-project-tools.ts`'s `write_file` refuses a dirty tab on exactly these grounds. */\n const error = new Error(`${PROJECT_CONFIG_PATH} has unsaved changes in its editor tab`);\n notify.error(\n `Could not save ${PROJECT_CONFIG_PATH} — the file is open with unsaved changes. Save or ` +\n `revert that tab, then make the settings change again.`,\n { key: `save:${PROJECT_CONFIG_PATH}`, path: PROJECT_CONFIG_PATH, source: \"Settings\" },\n );\n return { error, ok: false };\n }\n\n const base = rival ?? current;\n const next = patch ? ({ ...base, ...patch } as ProjectConfig) : base;\n const text = serializeProjectConfig(next);\n\n // Nothing the file does not already say: no transaction, no write, and therefore no diff. The\n // Dirty conjunct is what makes a retry after a failed write always write; the rival conjunct is\n // What keeps the handover from being skipped when the file already agrees with the live config\n // But the DOCUMENT does not.\n if (!rival && !tab.doc.dirty && text === _committed) {\n return { ok: true };\n }\n\n const before = extensionsKey(current);\n transactDoc(tab, (t) => {\n const doc = t.doc.document as unknown as Record<string, unknown>;\n if (rival) {\n replaceContents(doc, rival);\n }\n for (const [key, value] of Object.entries(patch ?? {})) {\n doc[key] = value;\n }\n });\n\n // Serialised from what the transaction actually LANDED, not from the `next` computed above: a\n // Gate on `transactDoc` can refuse a mutation, and writing the value it refused would put the\n // File and the document into the one disagreement this module exists to make impossible.\n const config = toRaw(tab.doc.document) as unknown as ProjectConfig;\n const output = serializeProjectConfig(config);\n try {\n await getPlatform().writeFile(PROJECT_CONFIG_PATH, output);\n } catch (error) {\n notify.error(`Could not save ${PROJECT_CONFIG_PATH} — ${errorMessage(error)}`, {\n key: `save:${PROJECT_CONFIG_PATH}`,\n path: PROJECT_CONFIG_PATH,\n source: \"Settings\",\n });\n return { error, ok: false };\n }\n _committed = output;\n tab.doc.dirty = false;\n if (extensionsKey(config) !== before) {\n await refreshExtensionSurfaces();\n }\n return { ok: true };\n}\n\n/**\n * Adopt a configuration that is ALREADY on disk into the document.\n *\n * The other direction of the handover. `services/ai-project-tools.ts`'s `write_file` writes\n * `project.json` straight to the platform — it has to, the model authors the whole file as text —\n * and then has to tell the app what it wrote. Announcing it by constructing a fresh object and\n * assigning it to `projectState.projectConfig` is what left a rival beside the document: the next\n * settings commit read the document, which still held the PREVIOUS configuration, and persisted the\n * assistant's write back out of existence. Putting the bytes into the document instead keeps the\n * one-object rule true, and the state sync follows from the bind effect like every other change.\n *\n * `skipHistory`, because this is a RELOAD and not an edit: the file already says this, and\n * `write_file` tells the model in as many words that its disk writes are not undoable. A history\n * entry here would offer ⌘Z a change it could not take back from the file.\n *\n * @param {ProjectConfig} config The configuration as written — already past the schema gate.\n * @returns {Promise<void>}\n */\nexport async function adoptProjectConfig(config: ProjectConfig): Promise<void> {\n if (!requireProjectState()) {\n // No project state is no configuration document either ({@link projectConfigDocument} reads\n // One). The workspace copy is then the only thing there is to keep true.\n setWorkspaceProject(workspace.projectRoot, config);\n return;\n }\n const tab = projectConfigDocument();\n transactDoc(\n tab,\n (t) => replaceContents(t.doc.document as unknown as Record<string, unknown>, config),\n { skipHistory: true },\n );\n tab.doc.dirty = false;\n // Settle a read already in flight before saying what the file holds, or it would resolve after\n // This line with the PREVIOUS bytes and make the next real commit look like a no-op.\n await seedCommitted();\n _committed = serializeProjectConfig(config);\n}\n",
|
|
33
|
+
"/// <reference lib=\"dom\" />\n/**\n * Site context helpers - merge site-level definitions with file-level.\n *\n * When a project has a project.json, its $media and style cascade into every file. File-level\n * definitions merge on top (file wins on conflict).\n *\n * @docs framework/site/i18n\n */\n\nimport { projectState } from \"./store\";\nimport { getPlatform } from \"./platform\";\nimport { commitProjectConfig } from \"./tabs/project-config\";\n\nimport { resolveI18n } from \"@jxsuite/schema/locale\";\nimport type { ResolvedI18n } from \"@jxsuite/schema/locale\";\nimport type {\n JxElement,\n JxHeadEntry,\n JxMutableNode,\n JxStyle,\n ProjectConfig,\n} from \"@jxsuite/schema/types\";\n\n/**\n * Merge site $media with document $media. Document keys win on conflict.\n *\n * @param {Record<string, string> | undefined} docMedia - The current document's $media (may be\n * undefined)\n * @returns {Record<string, string>}\n */\nexport function getEffectiveMedia(docMedia?: Record<string, string>) {\n const siteMedia = projectState?.projectConfig?.$media;\n if (!siteMedia) {\n return docMedia || {};\n }\n if (!docMedia) {\n return { ...siteMedia };\n }\n return { ...siteMedia, ...docMedia };\n}\n\n/**\n * Merge site style with document style. Document keys win on conflict. Nested selector objects\n * (e.g. `& li`) are shallow-merged individually.\n *\n * @param {JxStyle | undefined} docStyle - The current document's style (may be undefined)\n * @returns {JxStyle}\n */\nexport function getEffectiveStyle(docStyle?: JxStyle) {\n const siteStyle = projectState?.projectConfig?.style;\n if (!siteStyle) {\n return docStyle || {};\n }\n if (!docStyle) {\n return { ...siteStyle };\n }\n const merged = { ...siteStyle };\n for (const [k, v] of Object.entries(docStyle)) {\n merged[k] =\n typeof v === \"object\" && v !== null && typeof merged[k] === \"object\" && merged[k] !== null\n ? { ...(merged[k] as JxStyle), ...(v as JxStyle) }\n : v;\n }\n return merged;\n}\n\n/**\n * Merge site imports with document imports. Document keys win on conflict.\n *\n * @param {Record<string, string> | undefined} docImports - The current document's imports (may be\n * undefined)\n * @returns {Record<string, string>}\n */\nexport function getEffectiveImports(docImports?: Record<string, string>) {\n const siteImports = projectState?.projectConfig?.imports;\n if (!siteImports) {\n return docImports || {};\n }\n if (!docImports) {\n return { ...siteImports };\n }\n return { ...siteImports, ...docImports };\n}\n\n/**\n * Merge site $elements with document $elements. Union with dedup by $ref or string value.\n *\n * @param {(JxElement | string)[]} [docElements] - The current document's $elements (may be\n * undefined)\n * @returns {(JxElement | string)[]}\n */\nexport function getEffectiveElements(docElements?: (JxElement | string)[]) {\n const siteElements = projectState?.projectConfig?.$elements;\n if (!siteElements?.length) {\n return docElements || [];\n }\n if (!docElements?.length) {\n return [...siteElements];\n }\n const seen = new Set<string>();\n const merged: (JxElement | string)[] = [];\n for (const entry of [...siteElements, ...docElements]) {\n const key = typeof entry === \"string\" ? entry : entry?.$ref;\n if (key && !seen.has(key)) {\n seen.add(key);\n merged.push(entry);\n }\n }\n return merged;\n}\n\n/**\n * Merge site $head with document $head. Union with dedup by href/src.\n *\n * @param {JxHeadEntry[]} [docHead] - The current document's $head (may be undefined)\n * @returns {JxHeadEntry[]}\n */\nexport function getEffectiveHead(docHead?: JxHeadEntry[]) {\n const siteHead = projectState?.projectConfig?.$head;\n if (!siteHead?.length) {\n return docHead || [];\n }\n if (!docHead?.length) {\n return [...siteHead];\n }\n const seen = new Set<string>();\n const merged: JxHeadEntry[] = [];\n for (const entry of [...siteHead, ...docHead]) {\n const key =\n String(entry?.attributes?.href || entry?.attributes?.src || \"\") || JSON.stringify(entry);\n if (!seen.has(key)) {\n seen.add(key);\n merged.push(entry);\n }\n }\n return merged;\n}\n\n/**\n * The project's resolved locales, or null when it declares none.\n *\n * The resolution is `@jxsuite/schema/locale`'s own — literally the function the compiler runs — so\n * a tag Studio offers is a tag the build accepts, and the two cannot drift into disagreeing about\n * what `EN-us` means or which locales exist.\n *\n * Errors are dropped here on purpose. Every helper in this file answers a render, and a render has\n * nowhere to put a sentence; `settings/locales-section.ts` is where a malformed tag is refused with\n * words, before it can reach the file.\n *\n * Called at render time rather than cached: `projectState` is a plain module-level binding replaced\n * wholesale on a project switch, so a cached answer would outlive the project it described.\n *\n * @returns {ResolvedI18n | null}\n */\nexport function getEffectiveLocales(): ResolvedI18n | null {\n const config = projectState?.projectConfig;\n return config ? resolveI18n(config).i18n : null;\n}\n\n// ─── Layout resolution ──────────────────────────────────────────────────────\n\nconst layoutCache = new Map<string, JxMutableNode>();\n\nexport function invalidateLayoutCache() {\n layoutCache.clear();\n}\n\n/**\n * Determine the effective layout path for a document.\n *\n * @param {string | false | undefined} docLayout - The document's $layout value (string path, false,\n * or undefined)\n * @returns {string | null} The layout path, or null if no layout applies\n */\nexport function getEffectiveLayoutPath(docLayout: string | false | undefined) {\n if (docLayout === false) {\n return null;\n }\n const defaultLayout = projectState?.projectConfig?.defaults?.layout;\n return docLayout || defaultLayout || null;\n}\n\n/**\n * Resolve a layout document by path. Fetches and caches the parsed JSON.\n *\n * @param {string} layoutPath - Relative path to the layout file (e.g., \"./layouts/base.json\")\n * @returns {Promise<JxMutableNode | null>} The parsed layout document, or null on failure\n */\nexport async function resolveLayoutDoc(layoutPath: string) {\n const normalized = layoutPath.replace(/^\\.\\//, \"\");\n if (layoutCache.has(normalized)) {\n return structuredClone(layoutCache.get(normalized) as JxMutableNode);\n }\n\n try {\n const platform = getPlatform();\n const content = await platform.readFile(normalized);\n const doc = JSON.parse(content) as JxMutableNode;\n layoutCache.set(normalized, doc);\n return structuredClone(doc);\n } catch {\n return null;\n }\n}\n\n/**\n * Distribute page children into a layout document's <slot> elements. Returns the merged document\n * with page content injected into slots.\n *\n * @param {JxMutableNode} layoutDoc - Deep-cloned layout document\n * @param {JxMutableNode} pageDoc - The page document\n * @returns {JxMutableNode} The merged document\n */\nexport function distributePageIntoLayout(layoutDoc: JxMutableNode, pageDoc: JxMutableNode) {\n const pageChildren = pageDoc.children ?? [];\n const children = Array.isArray(pageChildren) ? pageChildren : [];\n\n const named = new Map<string, JxMutableNode[]>();\n const defaults: (JxMutableNode | string)[] = [];\n\n for (const child of children) {\n const slotName = typeof child === \"object\" ? child.attributes?.slot : undefined;\n if (typeof child === \"object\" && typeof slotName === \"string\" && slotName) {\n if (!named.has(slotName)) {\n named.set(slotName, []);\n }\n named.get(slotName)!.push(child);\n } else {\n defaults.push(child);\n }\n }\n\n fillSlots(layoutDoc, named, defaults);\n\n if (pageDoc.state) {\n layoutDoc.state = { ...layoutDoc.state, ...pageDoc.state };\n }\n if (pageDoc.$media) {\n layoutDoc.$media = { ...layoutDoc.$media, ...pageDoc.$media };\n }\n if (pageDoc.style) {\n layoutDoc.style = { ...layoutDoc.style, ...pageDoc.style };\n }\n if (pageDoc.attributes) {\n layoutDoc.attributes = { ...layoutDoc.attributes, ...pageDoc.attributes };\n }\n\n return layoutDoc;\n}\n\nfunction fillSlots(\n node: JxMutableNode,\n named: Map<string, JxMutableNode[]>,\n defaults: (JxMutableNode | string)[],\n) {\n if (!node || typeof node !== \"object\") {\n return;\n }\n if (!Array.isArray(node.children)) {\n return;\n }\n\n const newChildren: (JxMutableNode | string)[] = [];\n for (const child of node.children) {\n if (child && typeof child === \"object\" && child.tagName === \"slot\") {\n const slotName = child.attributes?.name;\n if (typeof slotName === \"string\" && slotName && named.has(slotName)) {\n newChildren.push(...named.get(slotName)!);\n named.delete(slotName);\n } else if (!slotName && defaults.length > 0) {\n newChildren.push(...defaults);\n } else if (Array.isArray(child.children)) {\n newChildren.push(...child.children);\n }\n } else {\n if (typeof child !== \"string\") {\n fillSlots(child, named, defaults);\n }\n newChildren.push(child);\n }\n }\n node.children = newChildren as JxMutableNode[];\n}\n\n/**\n * Merge a partial patch into the project's configuration and persist it.\n *\n * The patch-shaped door onto `tabs/project-config.ts` — the single chokepoint every configuration\n * write goes through. It used to serialize and write `project.json` itself, which is how this file\n * came to hold one of the two serializations in play, and how ten call sites came to change the\n * file that defines the project with no history behind them.\n *\n * **It still rejects.** `settings/general-settings.ts` and `settings/contexts-section.ts` catch the\n * rejection and park it on the control that caused it (§7.1's inline tier), and that is the right\n * treatment for a field the author is looking at. The chokepoint ALSO files the failure as a\n * Problem, because the eight other sites reach this through `void updateSiteConfig(...)` and used\n * to drop it on the floor.\n *\n * @param {Partial<ProjectConfig>} patch - Fields to merge into the current projectConfig; a value\n * of `undefined` clears the key.\n * @throws {unknown} The platform's rejection, when the write fails.\n */\nexport async function updateSiteConfig(patch: Partial<ProjectConfig>) {\n const result = await commitProjectConfig(patch);\n if (!result.ok) {\n throw result.error;\n }\n}\n"
|
|
34
|
+
],
|
|
35
|
+
"mappings": "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",
|
|
36
|
+
"debugId": "D2B31F6EB602116364756E2164756E21",
|
|
37
|
+
"names": []
|
|
38
|
+
}
|