@jxsuite/studio 2.0.1 → 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-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.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-8jxwts2p.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-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.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-esrewxap.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-v7jkjqng.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-jm0z592w.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 +21080 -32585
- 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 +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- 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 -53
- 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 +30 -1
- 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 +7 -1
- 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-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.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-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- 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-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- 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-8jxwts2p.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-esrewxap.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
|
@@ -13,9 +13,10 @@ import { live } from "lit-html/directives/live.js";
|
|
|
13
13
|
import { renderFieldRow } from "../ui/field-row";
|
|
14
14
|
import { spNumberField, spTextField } from "../ui/field-input";
|
|
15
15
|
import { renderMediaPicker } from "../ui/media-picker";
|
|
16
|
-
import { activeTab } from "../workspace/workspace";
|
|
17
16
|
import { mutateUpdateFrontmatter, transactDoc } from "../tabs/transact";
|
|
18
17
|
import { findContentTypeSchema } from "../utils/studio-utils";
|
|
18
|
+
import { NULL_FORM_CONTEXT, getFormControl, referenceTarget } from "../ui/schema-form";
|
|
19
|
+
import type { JsonSchema } from "../ui/schema-form";
|
|
19
20
|
|
|
20
21
|
import type { JsonValue } from "../types";
|
|
21
22
|
import type { Tab } from "../tabs/tab";
|
|
@@ -26,6 +27,8 @@ export interface FmSchemaEntry {
|
|
|
26
27
|
enum?: string[];
|
|
27
28
|
format?: string;
|
|
28
29
|
properties?: Record<string, unknown>;
|
|
30
|
+
/** `#/content/<type>` — a relationship to another collection (site-architecture.md §6.1). */
|
|
31
|
+
$ref?: string;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
export interface FmField {
|
|
@@ -103,8 +106,19 @@ export function collectFmFields(
|
|
|
103
106
|
|
|
104
107
|
/**
|
|
105
108
|
* Render one frontmatter field as a typed widget row. Commits through `transactDoc` +
|
|
106
|
-
* `mutateUpdateFrontmatter` on
|
|
109
|
+
* `mutateUpdateFrontmatter` on `tab`.
|
|
107
110
|
*
|
|
111
|
+
* **`tab` is a parameter because this renderer has two hosts and only one of them follows the
|
|
112
|
+
* focus.** It committed to `activeTab.value` at each of its seven widgets, which is right for the
|
|
113
|
+
* Navigator's Document panel (an app-level surface showing the focused document) and wrong for the
|
|
114
|
+
* Document Header card, which `panels/frontmatter-panel.ts` draws INSIDE a pane's stage, once per
|
|
115
|
+
* pane. So a collection field edited on the card in one pane wrote into whichever document had the
|
|
116
|
+
* keyboard: the card went on showing the old value, and a document nobody was looking at changed.
|
|
117
|
+
* The Document Header's `transact(tab, …)` branch was fixed for JSON documents in an earlier pass
|
|
118
|
+
* and this — every schema-driven frontmatter field, on every content document — is what that pass
|
|
119
|
+
* missed.
|
|
120
|
+
*
|
|
121
|
+
* @param {Tab | null} tab The document to commit into.
|
|
108
122
|
* @param {string} field
|
|
109
123
|
* @param {FmSchemaEntry} entry
|
|
110
124
|
* @param {JsonValue} value
|
|
@@ -112,6 +126,7 @@ export function collectFmFields(
|
|
|
112
126
|
* @returns {import("lit-html").TemplateResult}
|
|
113
127
|
*/
|
|
114
128
|
export function renderFmField(
|
|
129
|
+
tab: Tab | null,
|
|
115
130
|
field: string,
|
|
116
131
|
entry: FmSchemaEntry,
|
|
117
132
|
value: JsonValue,
|
|
@@ -121,7 +136,34 @@ export function renderFmField(
|
|
|
121
136
|
const label = field.replaceAll(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase());
|
|
122
137
|
const displayLabel = label + (isRequired ? " *" : "");
|
|
123
138
|
const hasVal = value !== undefined && value !== "" && value !== false;
|
|
124
|
-
const onClear = () => transactDoc(
|
|
139
|
+
const onClear = () => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field));
|
|
140
|
+
|
|
141
|
+
/* A relationship to another collection is the ONE registered `reference` control — the same
|
|
142
|
+
picker the entry editor and the settings forms draw, reached through the registry rather than
|
|
143
|
+
reimplemented here. Before this branch a `$ref` field fell through to the textfield at the
|
|
144
|
+
bottom of this function, so the author typed an entry id from memory with no way to see what
|
|
145
|
+
ids exist and no sign when the one they typed was wrong. */
|
|
146
|
+
const referenceControl =
|
|
147
|
+
referenceTarget(entry) === null ? undefined : getFormControl("reference");
|
|
148
|
+
if (referenceControl) {
|
|
149
|
+
return renderFieldRow({
|
|
150
|
+
hasValue: hasVal,
|
|
151
|
+
label: displayLabel,
|
|
152
|
+
onClear,
|
|
153
|
+
prop: field,
|
|
154
|
+
widget: referenceControl({
|
|
155
|
+
// The reference control resolves nothing through the context — its choices are files.
|
|
156
|
+
ctx: NULL_FORM_CONTEXT,
|
|
157
|
+
key: field,
|
|
158
|
+
onChange: (next) =>
|
|
159
|
+
transactDoc(tab, (t) =>
|
|
160
|
+
mutateUpdateFrontmatter(t, field, (next ?? undefined) as JsonValue),
|
|
161
|
+
),
|
|
162
|
+
schema: entry as JsonSchema,
|
|
163
|
+
value,
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
125
167
|
|
|
126
168
|
if (entry.type === "boolean") {
|
|
127
169
|
return renderFieldRow({
|
|
@@ -134,7 +176,7 @@ export function renderFmField(
|
|
|
134
176
|
size="s"
|
|
135
177
|
.checked=${live(Boolean(value))}
|
|
136
178
|
@change=${(e: Event) =>
|
|
137
|
-
transactDoc(
|
|
179
|
+
transactDoc(tab, (t) =>
|
|
138
180
|
mutateUpdateFrontmatter(
|
|
139
181
|
t,
|
|
140
182
|
field,
|
|
@@ -163,7 +205,7 @@ export function renderFmField(
|
|
|
163
205
|
.map((s: string) => s.trim())
|
|
164
206
|
.filter(Boolean)
|
|
165
207
|
: undefined;
|
|
166
|
-
transactDoc(
|
|
208
|
+
transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field, arr));
|
|
167
209
|
},
|
|
168
210
|
{ placeholder: "comma, separated" },
|
|
169
211
|
),
|
|
@@ -181,7 +223,7 @@ export function renderFmField(
|
|
|
181
223
|
size="s"
|
|
182
224
|
.value=${live(value || "")}
|
|
183
225
|
@change=${(e: Event) =>
|
|
184
|
-
transactDoc(
|
|
226
|
+
transactDoc(tab, (t) =>
|
|
185
227
|
mutateUpdateFrontmatter(t, field, (e.target as HTMLInputElement).value || undefined),
|
|
186
228
|
)}
|
|
187
229
|
>
|
|
@@ -198,7 +240,7 @@ export function renderFmField(
|
|
|
198
240
|
onClear,
|
|
199
241
|
prop: field,
|
|
200
242
|
widget: renderMediaPicker(field, value as string, (v: string) =>
|
|
201
|
-
transactDoc(
|
|
243
|
+
transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field, v || undefined)),
|
|
202
244
|
),
|
|
203
245
|
});
|
|
204
246
|
}
|
|
@@ -210,7 +252,7 @@ export function renderFmField(
|
|
|
210
252
|
onClear,
|
|
211
253
|
prop: field,
|
|
212
254
|
widget: spNumberField(value !== undefined ? Number(value) : undefined, (n) =>
|
|
213
|
-
transactDoc(
|
|
255
|
+
transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field, n)),
|
|
214
256
|
),
|
|
215
257
|
});
|
|
216
258
|
}
|
|
@@ -223,8 +265,7 @@ export function renderFmField(
|
|
|
223
265
|
widget: spTextField(
|
|
224
266
|
`fm:${field}`,
|
|
225
267
|
(value as string) || "",
|
|
226
|
-
(v: string) =>
|
|
227
|
-
transactDoc(activeTab.value, (t) => mutateUpdateFrontmatter(t, field, v || undefined)),
|
|
268
|
+
(v: string) => transactDoc(tab, (t) => mutateUpdateFrontmatter(t, field, v || undefined)),
|
|
228
269
|
{ placeholder: entry.format === "date" ? "YYYY-MM-DD" : "" },
|
|
229
270
|
),
|
|
230
271
|
});
|
|
@@ -1,61 +1,141 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* The Document Header card (§3.2 ⑧) — the artefact's own header, drawn IN the stage.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the
|
|
5
|
+
* It replaces the old "Properties" bar, which was a fourth full-width band that **appeared and
|
|
6
|
+
* vanished as a side effect of the canvas mode** with no control to summon it, and which showed
|
|
7
|
+
* nothing at all unless `findContentTypeSchema` matched the document to a content collection — so
|
|
8
|
+
* it never appeared on the default home page, the one document every new author opens first.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Three gates are gone, and each was a lie about what the card is for:
|
|
11
|
+
*
|
|
12
|
+
* - The **collection gate** (`if (!fieldSet?.collection)`) — a page's `title` is frontmatter whether
|
|
13
|
+
* or not a collection schema describes it;
|
|
14
|
+
* - The **mode gate** (`getCanvasMode() === "edit"`) — the header is part of the document, not a view
|
|
15
|
+
* of it, so switching to Design must not delete it;
|
|
16
|
+
* - The **document-mode gate** (`doc.mode === "content"`) — a JSON page carries `title` and `$head`
|
|
17
|
+
* directly on the root node, and it has a header for exactly the same reason.
|
|
18
|
+
*
|
|
19
|
+
* What it renders instead: **any** document with frontmatter or `$head`, in every named layout and
|
|
20
|
+
* in both authoring views of the stage — Title, Route, the layout picker, the
|
|
21
|
+
* schema-and-frontmatter field list, the door to Search appearance and a "Raw head tags"
|
|
22
|
+
* disclosure. `hasDocumentHeader` is the whole predicate, and it is a fact about the DOCUMENT.
|
|
23
|
+
*
|
|
24
|
+
* **One reserved-key policy, one `collectFmFields` call.** The two field sets this card merges used
|
|
25
|
+
* to disagree: this module passed an empty reserved set and `head-panel.ts` passed `{title}`, so
|
|
26
|
+
* `title` could render twice with two different commit paths. `RESERVED_FM_KEYS` wins and is
|
|
27
|
+
* imported, not restated — see the note on its declaration.
|
|
28
|
+
*
|
|
29
|
+
* **The card has no host of its own.** `#frontmatter-panel` — the grid row, the `hidden` div, the
|
|
30
|
+
* `frontmatterPanelEl` ref and the 40vh cap that came with them — is deleted. The STAGE renders the
|
|
31
|
+
* host now ({@link attachDocumentHeaderHost}, called from a `ref` in `canvas/canvas-render.ts`), so
|
|
32
|
+
* the card sits inside the artefact rather than in a band above it. This module keeps only the
|
|
33
|
+
* focus-aware scheduler and the reactive effect, because a field commit must still repaint the card
|
|
34
|
+
* WITHOUT repainting the canvas — a full canvas render remounts the document iframe.
|
|
12
35
|
*/
|
|
13
36
|
|
|
14
37
|
import { html, nothing, render as litRender } from "lit-html";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
38
|
+
import { projectState } from "../store";
|
|
39
|
+
import { workspace } from "../workspace/workspace";
|
|
40
|
+
import { tabOfPane } from "../canvas/canvas-surface";
|
|
41
|
+
import { paneRegion } from "../ui/regions";
|
|
17
42
|
import { effect, effectScope } from "../reactivity";
|
|
18
43
|
import { createPanelScheduler } from "./panel-scheduler";
|
|
19
44
|
import { collectFmFields, renderFmField } from "./frontmatter-fields";
|
|
45
|
+
import { renderFieldRow } from "../ui/field-row";
|
|
46
|
+
import { spTextField } from "../ui/field-input";
|
|
47
|
+
import { transact } from "../tabs/transact";
|
|
48
|
+
import { pageRoute } from "./tab-strip";
|
|
49
|
+
import {
|
|
50
|
+
RESERVED_FM_KEYS,
|
|
51
|
+
applyContentMutation,
|
|
52
|
+
buildHeadDoc,
|
|
53
|
+
entryLabel,
|
|
54
|
+
entryValue,
|
|
55
|
+
isPageDocument,
|
|
56
|
+
isManagedEntry,
|
|
57
|
+
renderLayoutPickerRow,
|
|
58
|
+
} from "./head-panel";
|
|
59
|
+
import { isGoogleFontEntry, isGoogleFontPreconnect } from "../utils/google-fonts";
|
|
60
|
+
import { activeRegistry } from "../commands/active-registry";
|
|
20
61
|
|
|
62
|
+
import type { JxHeadEntry, JxMutableNode } from "@jxsuite/schema/types";
|
|
63
|
+
import type { Tab } from "../tabs/tab";
|
|
21
64
|
import type { PanelScheduler } from "./panel-scheduler";
|
|
65
|
+
import type { TemplateResult } from "lit-html";
|
|
22
66
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
67
|
+
/**
|
|
68
|
+
* The card's host and scheduler, per PANE.
|
|
69
|
+
*
|
|
70
|
+
* A single `_host` was the same singleton every other stage-content module had, and it produced a
|
|
71
|
+
* subtler failure than most: the stage hands the host over from a lit `ref`, so with two stages
|
|
72
|
+
* drawing a header the second `ref` to fire silently took the card away from the first, leaving one
|
|
73
|
+
* pane's Document Header frozen on the frontmatter of the moment it lost the handle.
|
|
74
|
+
*/
|
|
75
|
+
const _hosts = new Map<string, { el: HTMLElement; scheduler: PanelScheduler }>();
|
|
32
76
|
let _scope: { stop: () => void; run: <T>(fn: () => T) => T | undefined } | null = null;
|
|
33
77
|
|
|
78
|
+
/** Per-document disclosure state, keyed by tab id — not stored on the document. */
|
|
79
|
+
const _rawOpen = new Set<string>();
|
|
80
|
+
|
|
34
81
|
/**
|
|
35
|
-
*
|
|
36
|
-
* reactively on tab/mode/frontmatter changes.
|
|
82
|
+
* The element the stage has made available for the card, or `null` while no stage hosts it.
|
|
37
83
|
*
|
|
38
|
-
*
|
|
84
|
+
* Called from a lit `ref` in `canvas/canvas-render.ts`, so the host's lifetime is the stage's: the
|
|
85
|
+
* canvas creates it when it draws a document that has a header and drops it otherwise. The
|
|
86
|
+
* scheduler is re-created per host because it binds `focusin`/`focusout` to that exact node, and
|
|
87
|
+
* the focus guard is the whole reason this module still owns a render path of its own.
|
|
88
|
+
*
|
|
89
|
+
* @param {HTMLElement | null} el
|
|
39
90
|
*/
|
|
40
|
-
export function
|
|
41
|
-
|
|
91
|
+
export function attachDocumentHeaderHost(paneId: string, el: HTMLElement | null): void {
|
|
92
|
+
const held = _hosts.get(paneId);
|
|
93
|
+
if (held?.el === el) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
held?.scheduler.unbind();
|
|
97
|
+
_hosts.delete(paneId);
|
|
98
|
+
if (!el) {
|
|
42
99
|
return;
|
|
43
100
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
101
|
+
const scheduler = createPanelScheduler({ render: () => _doRender(paneId), root: el });
|
|
102
|
+
_hosts.set(paneId, { el, scheduler });
|
|
103
|
+
scheduler.bindFocus();
|
|
104
|
+
scheduler.schedule();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The host the stage last handed over, or `null`. The stage reads it back to settle Lit's
|
|
109
|
+
* order-independent detach report; nothing else needs to know where the card lives.
|
|
110
|
+
*/
|
|
111
|
+
export function documentHeaderHost(paneId: string): HTMLElement | null {
|
|
112
|
+
return _hosts.get(paneId)?.el ?? null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Mount the Document Header card: subscribe to the tab / document / frontmatter reads it renders
|
|
117
|
+
* from, so a change repaints the card without repainting the canvas around it.
|
|
118
|
+
*
|
|
119
|
+
* The card takes no context. It used to take `getCanvasMode()` purely to decide whether to exist,
|
|
120
|
+
* and that predicate is the thing this change deletes.
|
|
121
|
+
*/
|
|
122
|
+
export function mount() {
|
|
47
123
|
_scope = effectScope();
|
|
48
124
|
_scope.run(() => {
|
|
49
125
|
effect(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
//
|
|
126
|
+
// Every pane's tab, not the focused one's: two stages can each be drawing a header, and a
|
|
127
|
+
// Card that only tracked `activeTab` stopped repainting the moment focus moved away from it.
|
|
128
|
+
for (const tab of paneTabs()) {
|
|
129
|
+
// Track everything the card reads: the document root (title / `$head` / `$layout` live
|
|
130
|
+
// There for a JSON page) plus the frontmatter object AND its entries — field commits mutate
|
|
131
|
+
// Keys in place while the source-mode round-trip swaps the whole object, and both must
|
|
132
|
+
// Re-fire this effect.
|
|
55
133
|
void tab.doc.mode;
|
|
56
|
-
void tab.
|
|
57
|
-
void tab.
|
|
58
|
-
void tab.
|
|
134
|
+
void tab.documentPath;
|
|
135
|
+
void tab.doc.document;
|
|
136
|
+
void tab.doc.document?.title;
|
|
137
|
+
void tab.doc.document?.$head;
|
|
138
|
+
void tab.doc.document?.$layout;
|
|
59
139
|
const fm = tab.doc.content?.frontmatter;
|
|
60
140
|
if (fm) {
|
|
61
141
|
for (const key of Object.keys(fm)) {
|
|
@@ -71,62 +151,260 @@ export function mount(ctx: FrontmatterPanelCtx) {
|
|
|
71
151
|
export function unmount() {
|
|
72
152
|
_scope?.stop();
|
|
73
153
|
_scope = null;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
154
|
+
for (const { scheduler } of _hosts.values()) {
|
|
155
|
+
scheduler.unbind();
|
|
156
|
+
}
|
|
157
|
+
_hosts.clear();
|
|
158
|
+
_rawOpen.clear();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Each pane's tab, deduplicated — the set of documents a header could be drawn for. */
|
|
162
|
+
function paneTabs(): Tab[] {
|
|
163
|
+
const tabs: Tab[] = [];
|
|
164
|
+
for (const pane of workspace.panes) {
|
|
165
|
+
const tab = tabOfPane(pane.id);
|
|
166
|
+
if (tab && !tabs.includes(tab)) {
|
|
167
|
+
tabs.push(tab);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return tabs;
|
|
77
171
|
}
|
|
78
172
|
|
|
79
173
|
/**
|
|
80
|
-
* Request a render. Coalesced and deferred while a text input in the
|
|
81
|
-
*
|
|
174
|
+
* Request a render. Coalesced and deferred while a text input in the card is focused, so re-renders
|
|
175
|
+
* never clobber a field mid-edit.
|
|
82
176
|
*/
|
|
83
177
|
export function render() {
|
|
84
|
-
|
|
178
|
+
for (const { scheduler } of _hosts.values()) {
|
|
179
|
+
scheduler.schedule();
|
|
180
|
+
}
|
|
85
181
|
}
|
|
86
182
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Whether a document has a header to show.
|
|
185
|
+
*
|
|
186
|
+
* The one remaining gate, and it is a fact about the document rather than about the view: a
|
|
187
|
+
* component definition with no frontmatter, no title and no `$head` has no header, and printing an
|
|
188
|
+
* empty card over its canvas would be chrome pretending to be content.
|
|
189
|
+
*
|
|
190
|
+
* @param {Tab} tab
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
*/
|
|
193
|
+
export function hasDocumentHeader(tab: Tab): boolean {
|
|
194
|
+
const fm = tab.doc.content?.frontmatter ?? {};
|
|
195
|
+
const doc = tab.doc.document;
|
|
196
|
+
if (Object.keys(fm).length > 0) {
|
|
197
|
+
return true;
|
|
90
198
|
}
|
|
199
|
+
if (typeof doc?.title === "string" || (doc?.$head?.length ?? 0) > 0) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
// A page always has one, even an empty one: Title and Route are the two facts it must state.
|
|
203
|
+
// THIS tab's page-ness. `isPageDocument()` was zero-argument and answered about the focused
|
|
204
|
+
// Pane's document, so a predicate whose every other line reads `tab` finished by asking about a
|
|
205
|
+
// Different one: a page in the side pane lost its header whenever a component was focused, and a
|
|
206
|
+
// Bare component in the side pane grew one whenever a page was.
|
|
207
|
+
return isPageDocument(tab);
|
|
208
|
+
}
|
|
91
209
|
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
litRender(nothing,
|
|
103
|
-
|
|
210
|
+
function _doRender(paneId: string) {
|
|
211
|
+
const host = _hosts.get(paneId)?.el;
|
|
212
|
+
if (!host) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const tab = tabOfPane(paneId);
|
|
216
|
+
if (!tab || !hasDocumentHeader(tab)) {
|
|
217
|
+
// The stage decides whether the host exists; this only covers the window between a document
|
|
218
|
+
// Losing its header and the canvas noticing. Lit leaves comment markers, so `:empty` cannot be
|
|
219
|
+
// The signal and the host is hidden explicitly.
|
|
220
|
+
litRender(nothing, host);
|
|
221
|
+
host.hidden = true;
|
|
104
222
|
return;
|
|
105
223
|
}
|
|
224
|
+
litRender(documentHeaderTemplate(tab, paneId), host);
|
|
225
|
+
host.hidden = false;
|
|
226
|
+
}
|
|
106
227
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
228
|
+
/**
|
|
229
|
+
* The card.
|
|
230
|
+
*
|
|
231
|
+
* Exported as a template because the STAGE hosts it: `canvas-render.ts` emits the host div and this
|
|
232
|
+
* module paints into it. The region id (`pane.primary/frontmatter`) rides on the `<section>` rather
|
|
233
|
+
* than on a shell host, which is what made the move a layout change instead of a rename — the id
|
|
234
|
+
* names the card's PLACE in the pane, and the pane still has one.
|
|
235
|
+
*
|
|
236
|
+
* @param {Tab} tab
|
|
237
|
+
* @returns {TemplateResult}
|
|
238
|
+
*/
|
|
239
|
+
export function documentHeaderTemplate(tab: Tab, paneId: string): TemplateResult {
|
|
240
|
+
const isContent = tab.doc.mode === "content";
|
|
241
|
+
const fm = (tab.doc.content?.frontmatter ?? {}) as Record<string, unknown>;
|
|
242
|
+
// ONE view of the document's head material, whichever realm it lives in: frontmatter keys for a
|
|
243
|
+
// Markdown page, root properties for a JSON one.
|
|
244
|
+
const headDoc = isContent ? buildHeadDoc(tab.doc.document, fm) : tab.doc.document;
|
|
245
|
+
/*
|
|
246
|
+
* `tab`, not `activeTab` — the card is drawn for the pane that mounted it, and every other line
|
|
247
|
+
* in this template already reads that. Both branches resolved through FOCUS, so with two panes
|
|
248
|
+
* the visible card's controls edited whichever document happened to be focused: click "Clear
|
|
249
|
+
* title" on the card in the left pane and the field disappears from the right pane's document
|
|
250
|
+
* instead. Invisible with one stage, which is why it survived the pane keying.
|
|
251
|
+
*
|
|
252
|
+
* **The first fix reached the JSON branch only, and the comment here said it was done.** A
|
|
253
|
+
* markdown page takes the CONTENT branch, where `applyContentMutation` resolved the focus for
|
|
254
|
+
* itself one call deeper — and `renderFmField` below did the same at each of its seven widgets.
|
|
255
|
+
* Both take their tab now, so the whole card commits into one document: the one it is showing.
|
|
256
|
+
*/
|
|
257
|
+
const applyMutation = isContent
|
|
258
|
+
? (fn: (doc: JxMutableNode) => void) => applyContentMutation(tab, render, fn)
|
|
259
|
+
: (fn: (doc: JxMutableNode) => void) => {
|
|
260
|
+
transact(tab, fn);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// ONE call. The old pair of surfaces made two, with two different reserved-key policies.
|
|
264
|
+
const { collection, fields, requiredFields } = collectFmFields(
|
|
265
|
+
tab,
|
|
266
|
+
projectState?.projectConfig,
|
|
267
|
+
RESERVED_FM_KEYS,
|
|
130
268
|
);
|
|
131
|
-
|
|
269
|
+
|
|
270
|
+
const route = tab.documentPath ? pageRoute(tab.documentPath) : null;
|
|
271
|
+
const title = typeof headDoc.title === "string" ? headDoc.title : "";
|
|
272
|
+
const head = headDoc.$head ?? [];
|
|
273
|
+
|
|
274
|
+
return html`
|
|
275
|
+
<section
|
|
276
|
+
class="doc-header"
|
|
277
|
+
aria-label="Document header"
|
|
278
|
+
data-jx-region=${paneRegion(paneId, "frontmatter")}
|
|
279
|
+
>
|
|
280
|
+
<header class="doc-header-bar">
|
|
281
|
+
<span class="doc-header-title">${collection ? collection.name : "Document"}</span>
|
|
282
|
+
${
|
|
283
|
+
route === null
|
|
284
|
+
? nothing
|
|
285
|
+
: html`<code class="doc-header-route" title="This page's route">${route}</code>`
|
|
286
|
+
}
|
|
287
|
+
</header>
|
|
288
|
+
<div class="doc-header-body">
|
|
289
|
+
${renderFieldRow({
|
|
290
|
+
hasValue: Boolean(title),
|
|
291
|
+
label: "Title",
|
|
292
|
+
onClear: () =>
|
|
293
|
+
applyMutation((d) => {
|
|
294
|
+
delete d.title;
|
|
295
|
+
}),
|
|
296
|
+
prop: "title",
|
|
297
|
+
widget: spTextField(
|
|
298
|
+
"doc-header:title",
|
|
299
|
+
title,
|
|
300
|
+
(v: string) =>
|
|
301
|
+
applyMutation((d) => {
|
|
302
|
+
const val = v.trim();
|
|
303
|
+
if (val) {
|
|
304
|
+
d.title = val;
|
|
305
|
+
} else {
|
|
306
|
+
delete d.title;
|
|
307
|
+
}
|
|
308
|
+
}),
|
|
309
|
+
{ placeholder: "Untitled" },
|
|
310
|
+
),
|
|
311
|
+
})}
|
|
312
|
+
${isPageDocument(tab) ? renderLayoutPickerRow(headDoc, applyMutation) : nothing}
|
|
313
|
+
${fields.map((f) => renderFmField(tab, f.field, f.entry, f.value, requiredFields))}
|
|
314
|
+
</div>
|
|
315
|
+
${seoButtonRow()} ${disclosure(tab.id, _rawOpen, "Raw head tags", rawHeadBody(head))}
|
|
316
|
+
</section>
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* The door to Search appearance (`panels/seo-modal.ts`).
|
|
322
|
+
*
|
|
323
|
+
* A row rather than a disclosure, because what is behind it is a surface and not more of this card.
|
|
324
|
+
* It runs the COMMAND rather than calling `openSeoModal` — the Page panel offers the same door and
|
|
325
|
+
* neither of them should own it.
|
|
326
|
+
*/
|
|
327
|
+
function seoButtonRow(): TemplateResult {
|
|
328
|
+
return html`
|
|
329
|
+
<div class="doc-header-seo">
|
|
330
|
+
<sp-action-button
|
|
331
|
+
quiet
|
|
332
|
+
size="s"
|
|
333
|
+
class="doc-header-seo-btn"
|
|
334
|
+
@click=${() => {
|
|
335
|
+
void activeRegistry()?.run("document.openSeo");
|
|
336
|
+
}}
|
|
337
|
+
>
|
|
338
|
+
<sp-icon-search slot="icon"></sp-icon-search>
|
|
339
|
+
Search appearance…
|
|
340
|
+
</sp-action-button>
|
|
341
|
+
</div>
|
|
342
|
+
`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* A collapsible block whose open state is per tab and lives in this module.
|
|
347
|
+
*
|
|
348
|
+
* Deliberately NOT on `tab.session.ui`: P3's first workstream is hoisting view flags OUT of the tab
|
|
349
|
+
* record, and adding two more would be moving in the wrong direction for a disclosure nobody needs
|
|
350
|
+
* restored across a relaunch.
|
|
351
|
+
*/
|
|
352
|
+
function disclosure(
|
|
353
|
+
tabId: string,
|
|
354
|
+
open: Set<string>,
|
|
355
|
+
label: string,
|
|
356
|
+
body: TemplateResult,
|
|
357
|
+
): TemplateResult {
|
|
358
|
+
const isOpen = open.has(tabId);
|
|
359
|
+
return html`
|
|
360
|
+
<details
|
|
361
|
+
class="doc-header-disclosure"
|
|
362
|
+
?open=${isOpen}
|
|
363
|
+
@toggle=${(e: Event) => {
|
|
364
|
+
const el = e.target as HTMLDetailsElement;
|
|
365
|
+
if (el.open) {
|
|
366
|
+
open.add(tabId);
|
|
367
|
+
} else {
|
|
368
|
+
open.delete(tabId);
|
|
369
|
+
}
|
|
370
|
+
}}
|
|
371
|
+
>
|
|
372
|
+
<summary>${label}</summary>
|
|
373
|
+
<div class="doc-header-body">${body}</div>
|
|
374
|
+
</details>
|
|
375
|
+
`;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* THE SEO BLOCK IS A MODAL — `panels/seo-modal.ts`.
|
|
379
|
+
Two rendered previews, a resolved-field list, a warning list, the page and Open Graph meta rows
|
|
380
|
+
and an icon picker, all disclosed inside a card whose job is the four or five fields you fill in
|
|
381
|
+
while writing. A previewed SERP result is not a field; it is a picture you study, and studying it
|
|
382
|
+
in a strip above the canvas made the card taller than the document it describes. The card keeps
|
|
383
|
+
Title — the one head value you type while writing — and offers the door. */
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* The `$head` entries no structured control owns, listed read-only.
|
|
387
|
+
*
|
|
388
|
+
* Read-only on purpose: the card discloses what is there so the author is never surprised by a tag
|
|
389
|
+
* they cannot see, and the Page panel remains the surface that adds and removes them.
|
|
390
|
+
*/
|
|
391
|
+
function rawHeadBody(head: JxHeadEntry[]): TemplateResult {
|
|
392
|
+
const custom = head.filter(
|
|
393
|
+
(e: JxHeadEntry) => !isManagedEntry(e) && !isGoogleFontEntry(e) && !isGoogleFontPreconnect(e),
|
|
394
|
+
);
|
|
395
|
+
if (custom.length === 0) {
|
|
396
|
+
return html`<p class="doc-header-empty">No custom head tags on this document.</p>`;
|
|
397
|
+
}
|
|
398
|
+
return html`
|
|
399
|
+
<ul class="doc-header-raw">
|
|
400
|
+
${custom.map(
|
|
401
|
+
(entry) => html`
|
|
402
|
+
<li>
|
|
403
|
+
<code>${entryLabel(entry)}</code>
|
|
404
|
+
<span title=${entryValue(entry)}>${entryValue(entry)}</span>
|
|
405
|
+
</li>
|
|
406
|
+
`,
|
|
407
|
+
)}
|
|
408
|
+
</ul>
|
|
409
|
+
`;
|
|
132
410
|
}
|