@jxsuite/studio 6.1.2 → 8.0.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/README.md +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
- package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
- package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
- package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
- package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
- package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
- package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/studio-r5qy30vx.js +5 -0
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
- package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
- package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +103 -104
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +12 -11
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +263 -49
- package/src/browse/library-model.ts +181 -133
- package/src/browse/library-pane.ts +738 -446
- package/src/browse/library-preview.ts +149 -19
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +16 -1
- package/src/canvas/canvas-live-render.ts +222 -30
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-render.ts +113 -107
- package/src/canvas/canvas-utils.ts +57 -12
- package/src/canvas/iframe-drop.ts +107 -0
- package/src/canvas/iframe-entry.ts +24 -12
- package/src/canvas/iframe-host.ts +134 -62
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-patch.ts +8 -7
- package/src/canvas/iframe-protocol.ts +24 -5
- package/src/canvas/iframe-render.ts +48 -1
- package/src/canvas/iframe-subtree.ts +5 -2
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/stage-scrollbar.ts +5 -1
- package/src/canvas/surface-registry.ts +6 -0
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +10 -8
- package/src/commands/context.ts +35 -10
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +9 -0
- package/src/commands/levels.ts +11 -5
- package/src/commands/live-context.ts +2 -0
- package/src/commands/registry.ts +10 -1
- package/src/content/collection-match.ts +6 -5
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/entry-commands.ts +51 -60
- package/src/content/entry-editor.ts +111 -18
- package/src/content/entry-fields.ts +13 -1
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +17 -3
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- package/src/editor/convert-to-component.ts +67 -43
- package/src/editor/file-drop-action.ts +9 -1
- package/src/editor/inline-edit-apply.ts +44 -0
- package/src/editor/inline-edit.ts +10 -0
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +13 -4
- package/src/editor/shortcuts.ts +44 -22
- package/src/editor/slash-menu.ts +51 -8
- package/src/files/components.ts +74 -10
- package/src/files/file-ops.ts +15 -5
- package/src/files/files.ts +164 -150
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +95 -1
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +13 -3
- package/src/format/format-host.ts +15 -0
- package/src/github/github-auth.ts +2 -2
- package/src/github/github-publish.ts +4 -3
- package/src/grid/grid-controller.ts +5 -1
- package/src/grid/grid-open.ts +0 -27
- package/src/grid/grid-panel.ts +54 -2
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +3 -25
- package/src/grid/grid-view.ts +31 -6
- package/src/grid/sources/content-source.ts +75 -7
- package/src/grid/tabulator-tables.d.ts +6 -0
- package/src/hosting/document.ts +2 -2
- package/src/i18n/i18n-commands.ts +2 -1
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +47 -19
- package/src/packages/pull-package-sync.ts +1 -1
- package/src/panels/activity-panel.ts +21 -5
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/block-action-bar.ts +11 -11
- package/src/panels/canvas-dnd-bridge.ts +5 -2
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +1 -1
- package/src/panels/data-grid.ts +4 -0
- package/src/panels/dnd.ts +17 -30
- package/src/panels/elements-panel.ts +9 -2
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/formula-workspace.ts +2 -3
- package/src/panels/frontmatter-fields.ts +9 -9
- package/src/panels/git-diff-open.ts +9 -5
- package/src/panels/head-panel.ts +369 -103
- package/src/panels/i18n-panel.ts +11 -10
- package/src/panels/imports-panel.ts +2 -0
- package/src/panels/jump-bar.ts +27 -2
- package/src/panels/layers-panel.ts +36 -30
- package/src/panels/left-panel.ts +22 -8
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +111 -29
- package/src/panels/pane-grid.ts +6 -6
- package/src/panels/panel-registry.ts +14 -9
- package/src/panels/properties-panel.ts +7 -3
- package/src/panels/right-panel.ts +199 -43
- package/src/panels/seo-modal.ts +41 -108
- package/src/panels/settings-menu.ts +52 -50
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +3 -4
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/style-panel.ts +37 -3
- package/src/panels/stylebook-doc.ts +142 -10
- package/src/panels/stylebook-layers-panel.ts +39 -80
- package/src/panels/stylebook-panel.ts +47 -10
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-strip.ts +109 -25
- package/src/platform.ts +1 -1
- package/src/platforms/cloud.ts +28 -1
- package/src/platforms/default-platform.ts +4 -4
- package/src/platforms/devserver.ts +51 -25
- package/src/publish/deploy-checklist.ts +12 -7
- package/src/publish/pages-service.ts +38 -14
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +83 -18
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- package/src/services/automation.ts +16 -20
- package/src/services/cf-settings.ts +4 -4
- package/src/services/connection.ts +2 -2
- package/src/services/directory-picker.ts +2 -2
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +21 -2
- package/src/services/settings/definitions.ts +25 -14
- package/src/settings/contributed-section.ts +49 -10
- package/src/settings/css-vars-editor.ts +93 -27
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-sections.ts +20 -2
- package/src/settings/general-settings.ts +91 -21
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/settings/project-sections.ts +27 -10
- package/src/settings/schema-field-ui.ts +3 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +182 -162
- package/src/shell.ts +467 -431
- package/src/site-context.ts +64 -10
- package/src/state.ts +28 -9
- package/src/studio.ts +194 -41
- package/src/style/project-styles.ts +34 -0
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/ai-chat.ts +2 -2
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +5 -5
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +134 -99
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +21 -0
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +46 -19
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +94 -59
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +15 -1
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +18 -0
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +24 -0
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +3 -1
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +38 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +5 -5
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +0 -21
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +8 -0
- package/src/surfaces/publish-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +18 -75
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +2 -0
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +18 -2
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +77 -4
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +1 -1
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +9 -2
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +85 -24
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +23 -0
- package/src/surfaces/statusbar.ts +39 -15
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/welcome.ts +1 -1
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- package/src/tabs/tab.ts +47 -7
- package/src/types.ts +21 -26
- package/src/ui/form-controls.ts +47 -8
- package/src/ui/layers.ts +13 -0
- package/src/ui/media-picker.ts +284 -40
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +259 -27
- package/src/ui/virtual-window.ts +26 -1
- package/src/utils/base64.ts +3 -3
- package/src/utils/edit-display.ts +322 -67
- package/src/utils/local-day.ts +18 -0
- package/src/workspace/pane-derive.ts +4 -4
- package/src/workspace/session.ts +28 -7
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +125 -11
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-f2gkpy8d.js +0 -4
- package/dist/chunks/adapter-4912g339.js +0 -4
- package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
- package/dist/chunks/cf-settings-br6105tr.js +0 -4
- package/dist/chunks/color-28ksk2qm.js +0 -4
- package/dist/chunks/components-db68vsn7.js +0 -4
- package/dist/chunks/content-source-1449qesq.js +0 -4
- package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
- package/dist/chunks/editor-x9jn86a7.js +0 -4
- package/dist/chunks/entry-commands-may24cpt.js +0 -4
- package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
- package/dist/chunks/file-ops-x9v54pcj.js +0 -4
- package/dist/chunks/files-j3knqf0s.js +0 -4
- package/dist/chunks/format-host-tyre2trb.js +0 -4
- package/dist/chunks/fs-events-64ma9htc.js +0 -4
- package/dist/chunks/git-panel-84ps5dex.js +0 -4
- package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
- package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
- package/dist/chunks/index-b8xw3vy9.js +0 -4
- package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
- package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
- package/dist/chunks/layers-h4xp1pss.js +0 -4
- package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
- package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
- package/dist/chunks/media-picker-2cweexc5.js +0 -4
- package/dist/chunks/menu-ynw13y0s.js +0 -4
- package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
- package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
- package/dist/chunks/notify-cj5zbrs2.js +0 -4
- package/dist/chunks/parse-b7ddhr8m.js +0 -4
- package/dist/chunks/platform-3dfws9js.js +0 -4
- package/dist/chunks/popover-jt2gxmzs.js +0 -4
- package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
- package/dist/chunks/quick-search-0dajrwqg.js +0 -4
- package/dist/chunks/references-49qgt404.js +0 -4
- package/dist/chunks/right-panel-jm1bwe53.js +0 -4
- package/dist/chunks/section-registry-6kwc4fky.js +0 -4
- package/dist/chunks/studio-0rt52vpq.js +0 -5
- package/dist/chunks/studio-18vgbhs5.js +0 -5
- package/dist/chunks/studio-24mccdrj.js +0 -5
- package/dist/chunks/studio-2eh507zk.js +0 -9
- package/dist/chunks/studio-2hcbccfv.js +0 -5
- package/dist/chunks/studio-2jbs3rxv.js +0 -5
- package/dist/chunks/studio-4h8k4dw9.js +0 -5
- package/dist/chunks/studio-5f6n18kx.js +0 -5
- package/dist/chunks/studio-5gthpky6.js +0 -5
- package/dist/chunks/studio-6ep3js6b.js +0 -9
- package/dist/chunks/studio-6wkmf3wz.js +0 -9
- package/dist/chunks/studio-841rf3cg.js +0 -5
- package/dist/chunks/studio-8gmwgheg.js +0 -5
- package/dist/chunks/studio-8qm0ep50.js +0 -5
- package/dist/chunks/studio-924p1tm1.js +0 -6
- package/dist/chunks/studio-a3shpz9y.js +0 -5
- package/dist/chunks/studio-amsbaaar.js +0 -6
- package/dist/chunks/studio-at5spjbc.js +0 -7
- package/dist/chunks/studio-b2xv945e.js +0 -5
- package/dist/chunks/studio-bn5nkafw.js +0 -5
- package/dist/chunks/studio-bw6q5xjf.js +0 -9
- package/dist/chunks/studio-c7q0t9x1.js +0 -5
- package/dist/chunks/studio-camnhc96.js +0 -6
- package/dist/chunks/studio-cffqvnzd.js +0 -5
- package/dist/chunks/studio-efvfrsf8.js +0 -5
- package/dist/chunks/studio-er30bpcx.js +0 -5
- package/dist/chunks/studio-ezscgr64.js +0 -5
- package/dist/chunks/studio-ffrrncvz.js +0 -5
- package/dist/chunks/studio-fpphgn8y.js +0 -10
- package/dist/chunks/studio-j1kvhdjk.js +0 -4
- package/dist/chunks/studio-j430n16g.js +0 -7
- package/dist/chunks/studio-jjkg84nj.js +0 -5
- package/dist/chunks/studio-m0q32ars.js +0 -4
- package/dist/chunks/studio-m6bdst11.js +0 -5
- package/dist/chunks/studio-nv2cptd4.js +0 -64
- package/dist/chunks/studio-nwfrc98n.js +0 -5
- package/dist/chunks/studio-p1wgvp7r.js +0 -5
- package/dist/chunks/studio-pag2wncm.js +0 -5
- package/dist/chunks/studio-qvanvzfd.js +0 -5
- package/dist/chunks/studio-qwa64kt7.js +0 -5
- package/dist/chunks/studio-rk1zc4x3.js +0 -928
- package/dist/chunks/studio-se2r3ptc.js +0 -5
- package/dist/chunks/studio-sg2a0dh0.js +0 -5
- package/dist/chunks/studio-tjzjhe68.js +0 -5
- package/dist/chunks/studio-v2w7q8r1.js +0 -7
- package/dist/chunks/studio-v5vjq1h0.js +0 -4
- package/dist/chunks/studio-v8aga3vp.js +0 -14
- package/dist/chunks/studio-vfcdrfmv.js +0 -5
- package/dist/chunks/studio-vmfkgdjf.js +0 -5
- package/dist/chunks/studio-wt1816jj.js +0 -5
- package/dist/chunks/studio-wz73q5kq.js +0 -4
- package/dist/chunks/studio-y04qtxvp.js +0 -7
- package/dist/chunks/studio-y21g8zzg.js +0 -5
- package/dist/chunks/studio-y64hrt8p.js +0 -12
- package/dist/chunks/studio-ynn90f58.js +0 -16
- package/dist/chunks/studio-yxz682sx.js +0 -5
- package/dist/chunks/studio-zp7snvkq.js +0 -5
- package/dist/chunks/studio-zq4z6tm6.js +0 -5
- package/dist/chunks/toast-c9fn075p.js +0 -4
- package/dist/chunks/tsMode-sf49ee9x.js +0 -14
- package/dist/chunks/workspace-jtfahpee.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -711
- package/src/panels/git-panel.ts +0 -1108
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -222
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -264
|
@@ -3,10 +3,19 @@
|
|
|
3
3
|
* Edit-mode display transforms — extracted from studio.js (Phase 4i). Pure stateless functions that
|
|
4
4
|
* convert document trees for visual editing (template expressions, $map, $switch, empty
|
|
5
5
|
* placeholders).
|
|
6
|
+
*
|
|
7
|
+
* @docs studio/interface/modes
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
|
|
9
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
displayTagName,
|
|
13
|
+
isNodeObject,
|
|
14
|
+
isNonNullObject,
|
|
15
|
+
isNumber,
|
|
16
|
+
isRef,
|
|
17
|
+
isString,
|
|
18
|
+
} from "@jxsuite/schema/guards";
|
|
10
19
|
import { isDocumentContainer } from "./strip-events";
|
|
11
20
|
import type { RebuiltNode } from "./strip-events";
|
|
12
21
|
|
|
@@ -57,6 +66,37 @@ function isImageUrlKey(key: string): boolean {
|
|
|
57
66
|
return IMAGE_KEY_RE.test(key);
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
/** A template that reads the repeater row (`item`, `index`, `$map`), which edit mode cannot supply. */
|
|
70
|
+
const ROW_BINDING_RE = /(?<![\w$.])(?:item|index|\$map)\b/u;
|
|
71
|
+
|
|
72
|
+
/** Whether a value is a template or `$ref` that reads the repeater row. */
|
|
73
|
+
export function isRowBound(value: JxDocumentValue | undefined): boolean {
|
|
74
|
+
if (isString(value)) {
|
|
75
|
+
return value.includes("${") && ROW_BINDING_RE.test(value);
|
|
76
|
+
}
|
|
77
|
+
return isNodeObject(value) && isString(value.$ref) && /^(?:#\/)?\$map\//u.test(value.$ref);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* What a row-bound value shows in the perimeter: link targets are inert, image-like keys the
|
|
82
|
+
* placeholder image, anything else its readable binding text.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} key
|
|
85
|
+
* @param {JxDocumentValue | undefined} value
|
|
86
|
+
*/
|
|
87
|
+
function rowBoundDisplay(key: string, value: JxDocumentValue | undefined): string {
|
|
88
|
+
if (key === "href" || key === "action") {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
if (isImageUrlKey(key)) {
|
|
92
|
+
return PLACEHOLDER_IMG;
|
|
93
|
+
}
|
|
94
|
+
if (isString(value)) {
|
|
95
|
+
return templateToEditDisplay(value);
|
|
96
|
+
}
|
|
97
|
+
return isNodeObject(value) && isString(value.$ref) ? refDisplayLabel(value.$ref) : "";
|
|
98
|
+
}
|
|
99
|
+
|
|
60
100
|
const textTags = new Set([
|
|
61
101
|
"p",
|
|
62
102
|
"h1",
|
|
@@ -118,6 +158,31 @@ export const EMPTY_PLACEHOLDER_CLASSES = [
|
|
|
118
158
|
"empty-container-placeholder",
|
|
119
159
|
] as const;
|
|
120
160
|
|
|
161
|
+
/** The style keys that give an element a size of its own: its box, not its content, sets it. */
|
|
162
|
+
const SIZING_KEYS = ["width", "height", "inlineSize", "blockSize"] as const;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Whether the node's own style fixes its width or height — a dot, a bar, a spacer.
|
|
166
|
+
*
|
|
167
|
+
* Such an element is drawn as a SHAPE, and an empty one is not missing anything: the jxsuite.com
|
|
168
|
+
* home's 6px status dot is an empty `<span>` sized in its style, and the text placeholder turned it
|
|
169
|
+
* into a column of letters one glyph wide over the hero. A placeholder that changes the box the
|
|
170
|
+
* author sized (the container one sets a `min-height` and a border) misdraws the page it is meant
|
|
171
|
+
* to explain, so a sized element gets none. Only the top-level declaration counts: a size set under
|
|
172
|
+
* a media query or a state is a variant of a box whose base the content still sizes.
|
|
173
|
+
*/
|
|
174
|
+
function fixesItsOwnSize(node: JxMutableNode): boolean {
|
|
175
|
+
const { style } = node;
|
|
176
|
+
if (!isNonNullObject(style)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return SIZING_KEYS.some((key) => {
|
|
180
|
+
const value = style[key];
|
|
181
|
+
const text = isNumber(value) ? String(value) : isString(value) ? value.trim() : "";
|
|
182
|
+
return text !== "" && text !== "auto";
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
121
186
|
/**
|
|
122
187
|
* The empty-placeholder class prepareForEditMode would add for this node, or null. Used by the
|
|
123
188
|
* canvas patcher to keep placeholder classes in sync when patching text without a full render.
|
|
@@ -136,6 +201,9 @@ export function computeEmptyPlaceholderClass(node: JxMutableNode): string | null
|
|
|
136
201
|
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
137
202
|
return null;
|
|
138
203
|
}
|
|
204
|
+
if (fixesItsOwnSize(node)) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
139
207
|
if (textTags.has(displayTagName(node.tagName))) {
|
|
140
208
|
return "empty-text-placeholder";
|
|
141
209
|
}
|
|
@@ -181,15 +249,184 @@ export function restoreTemplateExpressions(el: HTMLElement) {
|
|
|
181
249
|
* @param {JxMutableNode} arrayObj
|
|
182
250
|
* @returns {JxMutableNode}
|
|
183
251
|
*/
|
|
184
|
-
function arrayToPerimeter(arrayObj: JxMutableNode): JxMutableNode {
|
|
252
|
+
function arrayToPerimeter(arrayObj: JxMutableNode, row: SampleRow): JxMutableNode {
|
|
185
253
|
const template = arrayObj.map;
|
|
186
254
|
return {
|
|
187
|
-
children: isNonNullObject(template)
|
|
255
|
+
children: isNonNullObject(template)
|
|
256
|
+
? [prepareNode(template, sampleRowOf(arrayObj.items, row))]
|
|
257
|
+
: [],
|
|
188
258
|
className: "repeater-perimeter",
|
|
189
259
|
tagName: "div",
|
|
190
260
|
};
|
|
191
261
|
}
|
|
192
262
|
|
|
263
|
+
// ─── Live component props ────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* The row a repeater's template is drawn with in edit mode, as a JavaScript expression the runtime
|
|
267
|
+
* evaluates in the template's own scope, or null outside a repeater or where the repeater's items
|
|
268
|
+
* cannot be read.
|
|
269
|
+
*
|
|
270
|
+
* It is the repeater's FIRST item. A perimeter draws one instance of the template, and a component
|
|
271
|
+
* inside it used to be handed each bound prop's display text (`❪ item.data.date ❫`) as its value.
|
|
272
|
+
* Text survives that; a component that formats the prop does not: `Intl/formatDate` and a locale
|
|
273
|
+
* tag reject it with a `RangeError` (spec.md §16.4), and the instance was not rendered at all. The
|
|
274
|
+
* first item is real data of exactly the shape the template was written for, and it is the row
|
|
275
|
+
* Preview draws first.
|
|
276
|
+
*/
|
|
277
|
+
export type SampleRow = string | null;
|
|
278
|
+
|
|
279
|
+
/** A JSON value as a JavaScript literal: JSON is a subset of ECMAScript since ES2019. */
|
|
280
|
+
function jsLiteral(value: JxDocumentValue): string {
|
|
281
|
+
return JSON.stringify(value);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* A pointer the runtime resolves, as a JavaScript accessor over the template parameters, or null
|
|
286
|
+
* for a scheme a template cannot reach (`window#/`, `$defs`, an external file).
|
|
287
|
+
*/
|
|
288
|
+
function refAccessor(ref: string): string | null {
|
|
289
|
+
const pointer = ref.startsWith("#/") ? ref.slice(2) : ref;
|
|
290
|
+
const [head, ...rest] = pointer.split("/");
|
|
291
|
+
const base = head === "state" || head === "$map" ? head : null;
|
|
292
|
+
if (base === null) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
// JSON Pointer unescaping (RFC 6901): `~1` is `/`, `~0` is `~`, in that order.
|
|
296
|
+
const keys = rest.map((seg) => seg.replaceAll("~1", "/").replaceAll("~0", "~"));
|
|
297
|
+
return base + keys.map((key) => `?.[${jsLiteral(key)}]`).join("");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Evaluate `expr` where `item`, `index` and `$map` are the sample `row`, or as-is with no row. */
|
|
301
|
+
function inRow(expr: string, row: SampleRow): string {
|
|
302
|
+
if (row === null) {
|
|
303
|
+
return `(${expr})`;
|
|
304
|
+
}
|
|
305
|
+
return `((r) => ((item, index, $map) => (${expr}))(r, 0, { index: 0, item: r }))(${row})`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** The first item of a repeater's `items`, read inside the enclosing sample `row` (if any). */
|
|
309
|
+
function sampleRowOf(items: JxDocumentValue | undefined, row: SampleRow): SampleRow {
|
|
310
|
+
if (Array.isArray(items)) {
|
|
311
|
+
return `${jsLiteral(items)}[0]`;
|
|
312
|
+
}
|
|
313
|
+
if (isRef(items)) {
|
|
314
|
+
const accessor = refAccessor(items.$ref);
|
|
315
|
+
return accessor === null ? null : `${inRow(accessor, row)}?.[0]`;
|
|
316
|
+
}
|
|
317
|
+
const parts = isString(items) ? templateExpressions(items) : [];
|
|
318
|
+
if (isString(items) && parts.length === 1 && isWholeTemplate(items, parts[0]!)) {
|
|
319
|
+
return `${inRow(parts[0]!.expr, row)}?.[0]`;
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** One `${…}` of a template: where it starts and ends in the string, and its expression. */
|
|
325
|
+
interface TemplatePart {
|
|
326
|
+
start: number;
|
|
327
|
+
end: number;
|
|
328
|
+
expr: string;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Whether `part` is the whole of `template`: one expression end to end, so it keeps its type. */
|
|
332
|
+
function isWholeTemplate(template: string, part: TemplatePart): boolean {
|
|
333
|
+
return part.start === 0 && part.end === template.length - 1;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Each `${…}` of a template, located by brace depth rather than by pattern: an expression may hold
|
|
338
|
+
* an object literal or a nested template, which a `[^}]+` pattern cuts short.
|
|
339
|
+
*/
|
|
340
|
+
function templateExpressions(str: string): TemplatePart[] {
|
|
341
|
+
const found: TemplatePart[] = [];
|
|
342
|
+
let at = str.indexOf("${");
|
|
343
|
+
while (at !== -1) {
|
|
344
|
+
let depth = 0;
|
|
345
|
+
let end = -1;
|
|
346
|
+
for (let i = at + 1; i < str.length; i += 1) {
|
|
347
|
+
if (str[i] === "{") {
|
|
348
|
+
depth += 1;
|
|
349
|
+
} else if (str[i] === "}") {
|
|
350
|
+
depth -= 1;
|
|
351
|
+
if (depth === 0) {
|
|
352
|
+
end = i;
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (end === -1) {
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
found.push({ end, expr: str.slice(at + 2, end), start: at });
|
|
361
|
+
at = str.indexOf("${", end + 1);
|
|
362
|
+
}
|
|
363
|
+
return found;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* A bound component prop as edit mode passes it: the binding itself, evaluated LIVE by the runtime
|
|
368
|
+
* (against the page's own state and `$page`, and inside a repeater against its sample row) and
|
|
369
|
+
* guarded, so a binding with nothing to read yet (a collection still loading, an empty one) reads
|
|
370
|
+
* as the empty string, a component prop's usual default, rather than throwing out of the binding's
|
|
371
|
+
* effect.
|
|
372
|
+
*
|
|
373
|
+
* Display text is what edit mode shows for a binding the PAGE draws, because the author edits that
|
|
374
|
+
* text in place. A component's prop is not drawn by the page: the component decides what it means,
|
|
375
|
+
* and a date, a locale, a count or a colour cannot be a label.
|
|
376
|
+
*/
|
|
377
|
+
export function liveEditProp(template: string, row: SampleRow = null): string {
|
|
378
|
+
const parts = templateExpressions(template);
|
|
379
|
+
if (parts.length === 0) {
|
|
380
|
+
return template;
|
|
381
|
+
}
|
|
382
|
+
let out = "";
|
|
383
|
+
let last = 0;
|
|
384
|
+
for (const { start, end, expr } of parts) {
|
|
385
|
+
out += template.slice(last, start);
|
|
386
|
+
out += `\${(() => { try { return ${inRow(expr, row)}; } catch { return ""; } })()}`;
|
|
387
|
+
last = end + 1;
|
|
388
|
+
}
|
|
389
|
+
return out + template.slice(last);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* A `$ref`-bound component prop in edit mode: a scope pointer resolves live as it is, and a row
|
|
394
|
+
* pointer (`$map/item/…`) is read from the sample row, or dropped where there is none so the
|
|
395
|
+
* component keeps its own default.
|
|
396
|
+
*/
|
|
397
|
+
function liveEditRefProp(ref: string, row: SampleRow): JxDocumentValue | undefined {
|
|
398
|
+
const pointer = ref.startsWith("#/") ? ref.slice(2) : ref;
|
|
399
|
+
if (pointer !== "$map" && !pointer.startsWith("$map/")) {
|
|
400
|
+
return { $ref: ref };
|
|
401
|
+
}
|
|
402
|
+
const accessor = refAccessor(ref);
|
|
403
|
+
return row === null || accessor === null ? undefined : liveEditProp(`\${${accessor}}`, row);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* The sample row of the repeater template at `path` in `doc` (what {@link prepareForEditMode} draws
|
|
408
|
+
* a perimeter's instance with), so a subtree re-rendered on its own (`iframe-subtree.ts`) is
|
|
409
|
+
* prepared exactly as the full render prepared it.
|
|
410
|
+
*/
|
|
411
|
+
export function sampleRowAt(doc: JxDocumentValue, path: readonly (string | number)[]): SampleRow {
|
|
412
|
+
let node: JxDocumentValue | undefined = doc;
|
|
413
|
+
let row: SampleRow = null;
|
|
414
|
+
for (const seg of path) {
|
|
415
|
+
if (Array.isArray(node)) {
|
|
416
|
+
node = isNumber(seg) ? node[seg] : undefined;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (!isNodeObject(node)) {
|
|
420
|
+
return row;
|
|
421
|
+
}
|
|
422
|
+
if (seg === "map" && node.$prototype === "Array") {
|
|
423
|
+
row = sampleRowOf(node.items, row);
|
|
424
|
+
}
|
|
425
|
+
node = isString(seg) ? node[seg] : undefined;
|
|
426
|
+
}
|
|
427
|
+
return row;
|
|
428
|
+
}
|
|
429
|
+
|
|
193
430
|
/**
|
|
194
431
|
* The text a `$ref` binding shows in edit mode: its pointer, with the `#/state/` prefix dropped.
|
|
195
432
|
*
|
|
@@ -210,13 +447,33 @@ function refDisplayLabel(ref: string): string {
|
|
|
210
447
|
* @param {JxMutableNode} node
|
|
211
448
|
* @returns {JxMutableNode}
|
|
212
449
|
*/
|
|
213
|
-
export function prepareForEditMode(node: JxMutableNode): JxMutableNode;
|
|
214
|
-
export function prepareForEditMode(node: JxDocumentValue): JxDocumentValue;
|
|
215
|
-
export function prepareForEditMode(
|
|
216
|
-
|
|
450
|
+
export function prepareForEditMode(node: JxMutableNode, row?: SampleRow): JxMutableNode;
|
|
451
|
+
export function prepareForEditMode(node: JxDocumentValue, row?: SampleRow): JxDocumentValue;
|
|
452
|
+
export function prepareForEditMode(
|
|
453
|
+
node: JxDocumentValue | undefined,
|
|
454
|
+
row?: SampleRow,
|
|
455
|
+
): JxDocumentValue | undefined;
|
|
456
|
+
export function prepareForEditMode(
|
|
457
|
+
node: JxDocumentValue | undefined,
|
|
458
|
+
row: SampleRow = null,
|
|
459
|
+
): JxDocumentValue | undefined {
|
|
460
|
+
return prepareNode(node, row);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** {@link prepareForEditMode} for one value, inside the sample `row` of its enclosing repeater. */
|
|
464
|
+
function prepareNode(node: JxMutableNode, row: SampleRow): JxMutableNode;
|
|
465
|
+
function prepareNode(node: JxDocumentValue, row: SampleRow): JxDocumentValue;
|
|
466
|
+
function prepareNode(
|
|
467
|
+
node: JxDocumentValue | undefined,
|
|
468
|
+
row: SampleRow,
|
|
469
|
+
): JxDocumentValue | undefined;
|
|
470
|
+
function prepareNode(
|
|
471
|
+
node: JxDocumentValue | undefined,
|
|
472
|
+
row: SampleRow,
|
|
473
|
+
): JxDocumentValue | undefined {
|
|
217
474
|
if (Array.isArray(node)) {
|
|
218
475
|
// Arrays of nodes round-trip element-wise; the array itself is not a node.
|
|
219
|
-
return node.map((n) =>
|
|
476
|
+
return node.map((n) => prepareNode(n, row));
|
|
220
477
|
}
|
|
221
478
|
if (!isNodeObject(node)) {
|
|
222
479
|
return node;
|
|
@@ -225,7 +482,7 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
225
482
|
// A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an
|
|
226
483
|
// Array node directly). Members inside a children array funnel here via the children branch.
|
|
227
484
|
if (node.$prototype === "Array") {
|
|
228
|
-
return arrayToPerimeter(node);
|
|
485
|
+
return arrayToPerimeter(node, row);
|
|
229
486
|
}
|
|
230
487
|
|
|
231
488
|
const obj = node;
|
|
@@ -252,21 +509,27 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
252
509
|
if (k === "state" || k === "$media" || k === "$elements") {
|
|
253
510
|
out[k] = v; // Preserve as-is for runtime resolution
|
|
254
511
|
} else if (k === "$props" && isDocumentContainer(v)) {
|
|
255
|
-
|
|
512
|
+
/* A component's inputs render LIVE. They are its configuration, not text the author edits in
|
|
513
|
+
place (a template-valued prop is refused by inline prop editing), and showing their binding
|
|
514
|
+
text instead fed it to the component as a value: a header's `variant` became the literal
|
|
515
|
+
`❪ state.headerVariant ❫` and matched none of its styles. A prop that reads the repeater
|
|
516
|
+
row is drawn with the repeater's sample row (see liveEditProp), guarded, so a date or a
|
|
517
|
+
locale the component formats is real data rather than a label; a row-bound link target is
|
|
518
|
+
inert and a row-bound image-like key the placeholder image. */
|
|
256
519
|
const propsOut: RebuiltNode = {};
|
|
257
520
|
for (const [pk, pv] of Object.entries(v)) {
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
521
|
+
if (!isRowBound(pv)) {
|
|
522
|
+
propsOut[pk] = pv;
|
|
523
|
+
} else if (isString(pv)) {
|
|
524
|
+
propsOut[pk] =
|
|
525
|
+
isImageUrlKey(pk) || pk === "href" || pk === "action"
|
|
526
|
+
? rowBoundDisplay(pk, pv)
|
|
527
|
+
: liveEditProp(pv, row);
|
|
528
|
+
} else if (isRef(pv)) {
|
|
529
|
+
const live = liveEditRefProp(pv.$ref, row);
|
|
530
|
+
if (live !== undefined) {
|
|
531
|
+
propsOut[pk] = live;
|
|
267
532
|
}
|
|
268
|
-
} else if (isNodeObject(pv) && pv.$ref) {
|
|
269
|
-
propsOut[pk] = refDisplayLabel(pv.$ref);
|
|
270
533
|
} else {
|
|
271
534
|
propsOut[pk] = pv;
|
|
272
535
|
}
|
|
@@ -276,12 +539,12 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
276
539
|
if (Array.isArray(v)) {
|
|
277
540
|
// Each member recurses; array pseudo-elements become a single repeater-perimeter element
|
|
278
541
|
// (via the top-level array case) so they stay a 1:1 DOM node among their siblings.
|
|
279
|
-
out.children = v.map((c) =>
|
|
542
|
+
out.children = v.map((c) => prepareNode(c, row));
|
|
280
543
|
} else if (isNodeObject(v) && v.$prototype === "Array") {
|
|
281
544
|
// Legacy whole-children repeater → a single perimeter as the sole child.
|
|
282
|
-
out.children = [
|
|
545
|
+
out.children = [prepareNode(v, row)];
|
|
283
546
|
} else {
|
|
284
|
-
out.children =
|
|
547
|
+
out.children = prepareNode(v, row);
|
|
285
548
|
}
|
|
286
549
|
} else if (k === "cases" && obj.$switch && isDocumentContainer(v)) {
|
|
287
550
|
// Replace $switch cases with a placeholder showing the first case or a label
|
|
@@ -290,7 +553,7 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
290
553
|
const [, firstCase] = firstEntry;
|
|
291
554
|
out.children =
|
|
292
555
|
isDocumentContainer(firstCase) && !(isNodeObject(firstCase) && firstCase.$ref)
|
|
293
|
-
? [
|
|
556
|
+
? [prepareNode(firstCase, row)]
|
|
294
557
|
: [
|
|
295
558
|
{
|
|
296
559
|
style: {
|
|
@@ -309,35 +572,32 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
309
572
|
];
|
|
310
573
|
}
|
|
311
574
|
} else if (k === "attributes" && isMediaElement && isDocumentContainer(v)) {
|
|
312
|
-
//
|
|
575
|
+
// A media element's src/poster: live, unless it reads the repeater row or names nothing.
|
|
313
576
|
const processed: RebuiltNode = {};
|
|
314
577
|
for (const [ak, av] of Object.entries(v)) {
|
|
315
|
-
if (ak === "src" || ak === "poster") {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
} else {
|
|
319
|
-
needsMediaPlaceholder = true;
|
|
320
|
-
processed[ak] = TRANSPARENT_PX;
|
|
321
|
-
}
|
|
322
|
-
} else if (isString(av) && av.includes("${")) {
|
|
323
|
-
const isUrlAttr = ak === "href" || ak === "action";
|
|
324
|
-
processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
|
|
325
|
-
} else if (isNodeObject(av) && av.$ref) {
|
|
326
|
-
processed[ak] = refDisplayLabel(av.$ref);
|
|
578
|
+
if ((ak === "src" || ak === "poster") && (av === "" || av == null || isRowBound(av))) {
|
|
579
|
+
needsMediaPlaceholder = true;
|
|
580
|
+
processed[ak] = TRANSPARENT_PX;
|
|
327
581
|
} else {
|
|
328
|
-
processed[ak] = av;
|
|
582
|
+
processed[ak] = isRowBound(av) ? rowBoundDisplay(ak, av) : av;
|
|
329
583
|
}
|
|
330
584
|
}
|
|
331
585
|
out.attributes = processed;
|
|
586
|
+
} else if (k === "attributes" && isDocumentContainer(v)) {
|
|
587
|
+
const processed: RebuiltNode = {};
|
|
588
|
+
for (const [ak, av] of Object.entries(v)) {
|
|
589
|
+
processed[ak] = isRowBound(av) ? rowBoundDisplay(ak, av) : av;
|
|
590
|
+
}
|
|
591
|
+
out.attributes = processed;
|
|
332
592
|
} else if (k === "style") {
|
|
333
|
-
/*
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
593
|
+
/* Live, like every binding but text: state IS live on the canvas. Only a declaration that
|
|
594
|
+
reads the repeater row is omitted — the perimeter has no row — and omitted rather than
|
|
595
|
+
blanked, because `color: ` is a malformed declaration in a rule where the cascade answers
|
|
596
|
+
an absent one. Mirrored by iframe-patch's editModeStyle. */
|
|
337
597
|
if (isDocumentContainer(v)) {
|
|
338
598
|
const s: RebuiltNode = {};
|
|
339
599
|
for (const [sk, sv] of Object.entries(v)) {
|
|
340
|
-
if (!
|
|
600
|
+
if (!isRowBound(sv)) {
|
|
341
601
|
s[sk] = sv;
|
|
342
602
|
}
|
|
343
603
|
}
|
|
@@ -345,34 +605,29 @@ export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumen
|
|
|
345
605
|
} else {
|
|
346
606
|
out.style = v;
|
|
347
607
|
}
|
|
348
|
-
} else if (isString(v) && v.includes("${")) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
608
|
+
} else if (k === "$switch" && isString(v) && v.includes("${")) {
|
|
609
|
+
/* Not a render input any more: `cases` is replaced by the first case above, so a live
|
|
610
|
+
expression would hand the runtime a switch with nothing to choose from. */
|
|
611
|
+
out[k] = templateToEditDisplay(v);
|
|
612
|
+
} else if (k === "textContent" && isString(v) && v.includes("${")) {
|
|
613
|
+
// The author's text: shown as its binding, so editing it in place edits the template.
|
|
614
|
+
out[k] = templateToEditDisplay(v);
|
|
615
|
+
} else if (k === "textContent" && isNodeObject(v) && v.$ref) {
|
|
616
|
+
out[k] = refDisplayLabel(v.$ref);
|
|
617
|
+
} else if (isMediaElement && (k === "src" || k === "poster")) {
|
|
618
|
+
if (v === "" || v == null || isRowBound(v)) {
|
|
352
619
|
needsMediaPlaceholder = true;
|
|
353
620
|
out[k] = TRANSPARENT_PX;
|
|
354
621
|
} else {
|
|
355
|
-
|
|
356
|
-
out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
|
|
357
|
-
}
|
|
358
|
-
} else if (isNodeObject(v) && v.$ref) {
|
|
359
|
-
// $ref binding → show ref path as literal text
|
|
360
|
-
const label = refDisplayLabel(v.$ref);
|
|
361
|
-
const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
|
|
362
|
-
if (isMediaSrc) {
|
|
363
|
-
needsMediaPlaceholder = true;
|
|
364
|
-
out[k] = TRANSPARENT_PX;
|
|
365
|
-
} else {
|
|
366
|
-
out[k] = label;
|
|
622
|
+
out[k] = v;
|
|
367
623
|
}
|
|
624
|
+
} else if (isRowBound(v)) {
|
|
625
|
+
out[k] = rowBoundDisplay(k, v);
|
|
626
|
+
} else if (isString(v) || (isNodeObject(v) && v.$ref)) {
|
|
627
|
+
// Any other bound or literal property renders as the page will.
|
|
628
|
+
out[k] = v;
|
|
368
629
|
} else {
|
|
369
|
-
|
|
370
|
-
if ((k === "src" || k === "poster") && v === "" && isMediaElement) {
|
|
371
|
-
needsMediaPlaceholder = true;
|
|
372
|
-
out[k] = TRANSPARENT_PX;
|
|
373
|
-
} else {
|
|
374
|
-
out[k] = prepareForEditMode(v);
|
|
375
|
-
}
|
|
630
|
+
out[k] = prepareNode(v, row);
|
|
376
631
|
}
|
|
377
632
|
}
|
|
378
633
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An instant as the calendar day it is where Studio runs.
|
|
3
|
+
*
|
|
4
|
+
* A file's modification time, an upload's, "today": each is an instant, and the day a reader means
|
|
5
|
+
* by it is their own. `toISOString().slice(0, 10)` answers in UTC, so a file saved at 9 pm in
|
|
6
|
+
* Denver was listed as edited tomorrow. A date the author WROTE (`2026-06-03`) is not an instant
|
|
7
|
+
* and never goes through here: it is taken as written (`content/entry-summaries.ts` `entryDay`).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** `date` as `YYYY-MM-DD` in the local time zone, or "" for an invalid date. */
|
|
11
|
+
export function localDay(date: Date): string {
|
|
12
|
+
if (Number.isNaN(date.getTime())) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
16
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
17
|
+
return `${String(date.getFullYear()).padStart(4, "0")}-${month}-${day}`;
|
|
18
|
+
}
|
|
@@ -79,10 +79,10 @@ export type DerivePreset = (typeof DERIVE_PRESETS)[number];
|
|
|
79
79
|
* The canvas mode a preset needs the SOURCE document to DECLARE, for the presets that need one.
|
|
80
80
|
*
|
|
81
81
|
* `tab.capabilities.modes` is the format's own answer to "what can this document be shown as", and
|
|
82
|
-
* the preset menu consulted it nowhere: over a document that declares `["
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
82
|
+
* the preset menu consulted it nowhere: over a document that declares `["stylebook", "source"]` it
|
|
83
|
+
* still offered "Same page at Base" — a lens whose stage can only draw an empty artboard — and
|
|
84
|
+
* "Component definition", whose rule can never resolve because nothing in a configuration object is
|
|
85
|
+
* a component instance. Both produced a pane the author then had to close.
|
|
86
86
|
*
|
|
87
87
|
* Two presets are absent, for two different reasons. `diff` needs no mode: a comparison is two
|
|
88
88
|
* texts and every document has those, and it is already gated on the file having changes. `layout`
|
package/src/workspace/session.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* across versions. Every field is validated on the way in and a bad record restores nothing.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import { PRIMARY_PANE, SECONDARY_PANE, focusPane, workspace } from "./workspace";
|
|
28
|
+
import { PRIMARY_PANE, SECONDARY_PANE, activateTab, focusPane, workspace } from "./workspace";
|
|
29
29
|
import {
|
|
30
30
|
isBoolean,
|
|
31
31
|
isJsonObject,
|
|
@@ -307,8 +307,22 @@ export async function restoreSession(
|
|
|
307
307
|
ui.showLayout = stored.showLayout;
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
/*
|
|
311
|
+
* Each pane's active tab, then the pane that had the keyboard, in that order, because activating
|
|
312
|
+
* a tab in a pane is what makes that pane's strip meaningful and focusing comes last.
|
|
313
|
+
*
|
|
314
|
+
* The focused pane's tab is ACTIVATED, not merely assigned, because the restored tab is the most
|
|
315
|
+
* recently used one and the workspace switch that follows a restore asks exactly that question.
|
|
316
|
+
* Every document was reopened without moving the keyboard, so the MRU list was empty, and
|
|
317
|
+
* `focusPane` adds nothing for the pane that already has the keyboard. Entering the stored
|
|
318
|
+
* workspace then fell back to that workspace's FIRST tab in the strip: two exhibition entries
|
|
319
|
+
* restored with the English one active came back on whichever was opened first, and a Design
|
|
320
|
+
* session left on `/exhibitions` came back on `/`.
|
|
321
|
+
*/
|
|
322
|
+
const focused = workspace.panes.some((pane) => pane.id === session.focusedPane)
|
|
323
|
+
? session.focusedPane
|
|
324
|
+
: null;
|
|
325
|
+
let focusedTab: string | null = null;
|
|
312
326
|
for (const stored of session.panes) {
|
|
313
327
|
const pane = workspace.panes.find((p) => p.id === stored.id);
|
|
314
328
|
if (!pane || !stored.activeFile) {
|
|
@@ -317,12 +331,19 @@ export async function restoreSession(
|
|
|
317
331
|
const match = pane.tabOrder.find(
|
|
318
332
|
(tabId) => workspace.tabs.get(tabId)?.documentPath === stored.activeFile,
|
|
319
333
|
);
|
|
320
|
-
if (match) {
|
|
321
|
-
|
|
334
|
+
if (!match) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (pane.id === focused) {
|
|
338
|
+
focusedTab = match;
|
|
339
|
+
} else {
|
|
340
|
+
activateTab(match, { focus: false });
|
|
322
341
|
}
|
|
323
342
|
}
|
|
324
|
-
if (
|
|
325
|
-
|
|
343
|
+
if (focusedTab) {
|
|
344
|
+
activateTab(focusedTab);
|
|
345
|
+
} else if (focused) {
|
|
346
|
+
focusPane(focused);
|
|
326
347
|
}
|
|
327
348
|
return opened;
|
|
328
349
|
}
|