@jxsuite/studio 6.1.1 → 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/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- 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-6rbra5dy.js +4 -0
- package/dist/chunks/color-field-gy56c94g.js +4 -0
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
- package/dist/chunks/combobox-72h32ejk.js +4 -0
- 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/dialog-c4x05vyx.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-qg1b5eqx.js +51 -0
- package/dist/chunks/icons-63bjtbs7.js +4 -0
- package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
- package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-8nbvs12s.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-c421cf8c.js +4 -0
- 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-bdpzbfvs.js +4 -0
- package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
- 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/number-field-y62xq0ty.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/select-rzds841e.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/split-c9zfdgxf.js +4 -0
- 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-6m380wp7.js +5 -0
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/studio-8tr6cfrc.js +5 -0
- 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-bbe4c90a.js +5 -0
- 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-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/studio-k7evxqh4.js +5 -0
- 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-rv11kfwa.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-h46vtzk8.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-wszjyh0j.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-pre0skq6.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-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
- 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/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-yypz28gq.js +4 -0
- package/dist/chunks/tree-9xa4hm7n.js +4 -0
- 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-bv552sfx.js +4 -0
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +106 -107
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +17 -16
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +270 -53
- package/src/browse/library-model.ts +194 -134
- package/src/browse/library-pane.ts +748 -440
- package/src/browse/library-preview.ts +161 -26
- 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 +40 -10
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +260 -77
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +175 -148
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +147 -61
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +120 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +104 -75
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +269 -158
- package/src/canvas/iframe-inline-edit.ts +49 -30
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +30 -25
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +25 -21
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +36 -21
- package/src/canvas/iframe-render.ts +84 -35
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +10 -3
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +7 -2
- package/src/canvas/surface-registry.ts +27 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +13 -11
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +55 -28
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +56 -43
- package/src/commands/levels.ts +14 -8
- package/src/commands/live-context.ts +9 -7
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +22 -11
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +11 -9
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +54 -62
- package/src/content/entry-editor.ts +137 -32
- package/src/content/entry-fields.ts +25 -8
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +38 -15
- 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/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +78 -48
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +29 -22
- package/src/editor/inline-edit-apply.ts +79 -17
- package/src/editor/inline-edit.ts +76 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +14 -5
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +76 -42
- package/src/editor/slash-menu.ts +52 -14
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +89 -20
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +92 -41
- package/src/files/files.ts +248 -239
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +97 -2
- package/src/files/media-paths.ts +3 -0
- 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 +15 -5
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +91 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +21 -11
- package/src/github/github-publish.ts +28 -23
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +25 -23
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -33
- package/src/grid/grid-panel.ts +65 -6
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +9 -31
- package/src/grid/grid-view.ts +45 -23
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +100 -31
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +61 -34
- package/src/hosting/document.ts +2 -2
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +3 -3
- 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 +51 -20
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +38 -14
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +57 -46
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +36 -26
- 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 +63 -26
- package/src/panels/data-grid.ts +18 -11
- package/src/panels/dnd.ts +115 -138
- package/src/panels/editors.ts +52 -21
- package/src/panels/elements-panel.ts +19 -5
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +78 -54
- package/src/panels/frontmatter-fields.ts +33 -28
- package/src/panels/git-diff-open.ts +10 -6
- package/src/panels/head-panel.ts +488 -202
- package/src/panels/i18n-panel.ts +20 -12
- package/src/panels/imports-panel.ts +25 -47
- package/src/panels/jump-bar.ts +75 -31
- package/src/panels/layers-panel.ts +130 -101
- package/src/panels/left-panel.ts +25 -11
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +140 -49
- package/src/panels/pane-grid.ts +55 -26
- package/src/panels/panel-registry.ts +36 -46
- package/src/panels/properties-panel.ts +182 -124
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +201 -45
- package/src/panels/seo-modal.ts +54 -125
- package/src/panels/settings-menu.ts +63 -61
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +156 -135
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +253 -206
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +195 -60
- package/src/panels/stylebook-layers-panel.ts +48 -89
- package/src/panels/stylebook-panel.ts +60 -27
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +143 -49
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +59 -31
- package/src/platforms/cloud.ts +373 -176
- package/src/platforms/default-platform.ts +14 -8
- package/src/platforms/devserver.ts +180 -142
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +20 -9
- package/src/publish/pages-service.ts +66 -27
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +88 -22
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-panel.ts +10 -6
- 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/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +74 -51
- package/src/services/cem-export.ts +149 -58
- package/src/services/cf-settings.ts +4 -4
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +20 -14
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +29 -9
- package/src/services/settings/definitions.ts +25 -14
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +128 -70
- package/src/settings/css-vars-editor.ts +119 -32
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +42 -14
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +101 -28
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +17 -7
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +28 -11
- package/src/settings/schema-field-ui.ts +12 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +186 -166
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +536 -477
- package/src/site-context.ts +101 -32
- package/src/state.ts +68 -57
- package/src/store.ts +54 -34
- package/src/studio.ts +219 -116
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +40 -7
- 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/token-ref.ts +5 -4
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +33 -38
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +17 -16
- package/src/surfaces/cf-account-picker.ts +17 -18
- 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 +145 -105
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +35 -11
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +59 -31
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +111 -77
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +26 -11
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +47 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +44 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +8 -7
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +49 -25
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +25 -39
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +5 -29
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +29 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish-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/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +22 -79
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +17 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +32 -12
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +82 -16
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +9 -16
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +14 -8
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +88 -36
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/shell.ts +1 -2
- 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 +42 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +56 -29
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- 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/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +6 -8
- 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/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +99 -48
- package/src/tabs/transact.ts +98 -53
- package/src/types.ts +53 -43
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +104 -56
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +57 -31
- package/src/ui/media-picker.ts +300 -47
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +14 -12
- package/src/ui/schema-form.ts +372 -97
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +29 -3
- package/src/utils/base64.ts +6 -4
- package/src/utils/edit-display.ts +366 -111
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/local-day.ts +18 -0
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +14 -16
- package/src/workspace/session.ts +81 -50
- 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 +165 -47
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-va2wwra4.js +0 -4
- package/dist/chunks/adapter-f93pafd7.js +0 -4
- package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
- package/dist/chunks/cf-settings-125tdm0w.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-ax2f1fnn.js +0 -4
- package/dist/chunks/content-source-108aqtk1.js +0 -4
- package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-pfgdmkb0.js +0 -4
- package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
- package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
- package/dist/chunks/file-ops-meej5mqf.js +0 -4
- package/dist/chunks/files-44vp8a2s.js +0 -4
- package/dist/chunks/format-host-7q1petb9.js +0 -4
- package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
- package/dist/chunks/git-panel-zngbymvd.js +0 -4
- package/dist/chunks/grid-view-sx9vynsp.js +0 -51
- package/dist/chunks/icons-p44xhjf0.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-qk3ycq87.js +0 -4
- package/dist/chunks/index-wkyfjeqz.js +0 -4
- package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
- package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
- package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
- package/dist/chunks/layers-xd92fg8d.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
- package/dist/chunks/media-picker-0svzkdyb.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/menu-5c55ea3d.js +0 -4
- package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
- package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
- package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
- package/dist/chunks/notify-0xgtn8q1.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-v1qctbe6.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
- package/dist/chunks/quick-search-a54e6t5n.js +0 -4
- package/dist/chunks/references-gmqp82fs.js +0 -4
- package/dist/chunks/right-panel-v7t9awbk.js +0 -4
- package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0bhx5hz6.js +0 -5
- package/dist/chunks/studio-0k1ddnyy.js +0 -6
- package/dist/chunks/studio-1b04pd0j.js +0 -64
- package/dist/chunks/studio-4dwbj6gb.js +0 -5
- package/dist/chunks/studio-4tanh828.js +0 -5
- package/dist/chunks/studio-55h4mstj.js +0 -4
- package/dist/chunks/studio-5tnvjkz4.js +0 -5
- package/dist/chunks/studio-60dqgb0c.js +0 -5
- package/dist/chunks/studio-61dp09qg.js +0 -9
- package/dist/chunks/studio-63epcrj2.js +0 -5
- package/dist/chunks/studio-74k29dy9.js +0 -5
- package/dist/chunks/studio-7vg6jcd3.js +0 -5
- package/dist/chunks/studio-7zx31knw.js +0 -9
- package/dist/chunks/studio-8bxk97km.js +0 -5
- package/dist/chunks/studio-933e30n4.js +0 -5
- package/dist/chunks/studio-98wnwhbg.js +0 -5
- package/dist/chunks/studio-9mccjwjh.js +0 -14
- package/dist/chunks/studio-a2ke1e4t.js +0 -5
- package/dist/chunks/studio-e3a2a6v3.js +0 -4
- package/dist/chunks/studio-e81q1vb9.js +0 -5
- package/dist/chunks/studio-epgrmqqm.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-g1shz58g.js +0 -5
- package/dist/chunks/studio-gf0fz03c.js +0 -5
- package/dist/chunks/studio-gjtpe62q.js +0 -6
- package/dist/chunks/studio-gkskhg7m.js +0 -5
- package/dist/chunks/studio-gx4dnjzd.js +0 -5
- package/dist/chunks/studio-j03zga3y.js +0 -9
- package/dist/chunks/studio-jhpxeckz.js +0 -5
- package/dist/chunks/studio-k01r7ykp.js +0 -5
- package/dist/chunks/studio-kk7h30ne.js +0 -7
- package/dist/chunks/studio-kt1zqney.js +0 -5
- package/dist/chunks/studio-m3cwhvye.js +0 -5
- package/dist/chunks/studio-mcayt6hz.js +0 -5
- package/dist/chunks/studio-myjcghv3.js +0 -5
- package/dist/chunks/studio-n8bxwc3y.js +0 -4
- package/dist/chunks/studio-ngm8gvpb.js +0 -5
- package/dist/chunks/studio-nj5a01jy.js +0 -928
- package/dist/chunks/studio-pcgz8heb.js +0 -5
- package/dist/chunks/studio-qcsq0t15.js +0 -5
- package/dist/chunks/studio-qkstvve9.js +0 -5
- package/dist/chunks/studio-qv1pwd3c.js +0 -5
- package/dist/chunks/studio-rc6dvxjb.js +0 -7
- package/dist/chunks/studio-s8dmmz66.js +0 -5
- package/dist/chunks/studio-sp5xzbj4.js +0 -6
- package/dist/chunks/studio-szsjbj0g.js +0 -5
- package/dist/chunks/studio-t1xzawhr.js +0 -16
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- package/dist/chunks/studio-vrmcjf9g.js +0 -7
- package/dist/chunks/studio-vyc0b4he.js +0 -10
- package/dist/chunks/studio-w0cgf6jg.js +0 -5
- package/dist/chunks/studio-w3hskzqk.js +0 -5
- package/dist/chunks/studio-xgrgcdyh.js +0 -9
- package/dist/chunks/studio-xz2yxfcb.js +0 -5
- package/dist/chunks/studio-y6n42tgs.js +0 -5
- package/dist/chunks/studio-yb560vxr.js +0 -5
- package/dist/chunks/studio-yn9f8vtx.js +0 -5
- package/dist/chunks/studio-yw05w8f0.js +0 -7
- package/dist/chunks/studio-z16sgavc.js +0 -5
- package/dist/chunks/studio-zey7zsdw.js +0 -12
- package/dist/chunks/studio-zyqn40w4.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-2frah6h1.js +0 -14
- package/dist/chunks/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -701
- package/src/panels/git-panel.ts +0 -1120
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -231
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -272
package/src/ui/media-picker.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Media Picker — the project's media, and the
|
|
3
|
+
* Media Picker — the project's media, and the compact surfaces that offer them.
|
|
4
4
|
*
|
|
5
5
|
* The FIELD (`surfaces/media-field.json`) is a control a row draws: a thumbnail of what the value
|
|
6
6
|
* names, the value itself, an Upload button that adds a new file to the project and assigns it, and
|
|
7
|
-
* a Browse button. The BROWSER (`surfaces/media-browser.json`) is the panel Browse opens: a
|
|
8
|
-
* box over the
|
|
7
|
+
* a Browse button. The BROWSER (`surfaces/media-browser.json`) is the compact panel Browse opens: a
|
|
8
|
+
* search box over the project's media, with thumbnail previews for images, and a last row, **Browse
|
|
9
|
+
* all media…**, that opens the Media workspace's own surface in a dialog in pick mode
|
|
10
|
+
* (`media/media-library.ts`, studio.md §9.3). One picker, two sizes.
|
|
11
|
+
*
|
|
12
|
+
* **What media the project has is answered here, once.** {@link projectMediaFiles} walks
|
|
13
|
+
* `public/**` and every collection's `content/<collection>/images/**`, and the Media workspace, the
|
|
14
|
+
* Site panel's Media section, both pickers and the search-appearance dialog all read that one
|
|
15
|
+
* listing, so "what media does this project have" cannot have two answers in two choosers.
|
|
9
16
|
*
|
|
10
17
|
* **This module is the flow, not the markup.** Both surfaces are Jx documents now; what is left
|
|
11
18
|
* here is which files count as media, what a row's caption says, how long a keystroke waits before
|
|
@@ -20,13 +27,13 @@
|
|
|
20
27
|
* `<img>` has finished by the time `load` fires, so the caption is a read of work already done
|
|
21
28
|
* rather than a second fetch per row. What is NOT here is a usage count: `findReferences` sweeps
|
|
22
29
|
* every document in the project per query, and fifty of those to caption a list is the wrong trade.
|
|
23
|
-
* Usage is asked
|
|
24
|
-
*
|
|
30
|
+
* Usage is asked about one file where it changes a decision (the delete confirmation, the Media
|
|
31
|
+
* workspace's detail pane), and about every file only when the reader asks for **Unused**.
|
|
25
32
|
*
|
|
26
33
|
* @docs studio/projects/media
|
|
27
34
|
*/
|
|
28
35
|
|
|
29
|
-
import { getPlatform } from "../platform";
|
|
36
|
+
import { getPlatform, hasPlatform } from "../platform";
|
|
30
37
|
import { debouncedStyleCommit, renderOnly } from "../store";
|
|
31
38
|
import { mountMediaFieldSurface } from "../surfaces/media-field";
|
|
32
39
|
import { openMediaBrowserSurface } from "../surfaces/media-browser";
|
|
@@ -35,12 +42,15 @@ import { previewAssetSrc } from "../canvas/asset-refs";
|
|
|
35
42
|
import {
|
|
36
43
|
IMAGE_EXTENSIONS,
|
|
37
44
|
MEDIA_EXTENSIONS,
|
|
38
|
-
uploadAccept,
|
|
39
45
|
extensionOf,
|
|
46
|
+
mediaFileKind,
|
|
47
|
+
uploadAccept,
|
|
40
48
|
uploadAssets,
|
|
41
49
|
} from "../files/media-upload";
|
|
42
50
|
import {
|
|
43
51
|
invalidateMediaMeta,
|
|
52
|
+
loadMediaMeta,
|
|
53
|
+
mediaMetaSettled,
|
|
44
54
|
mediaMetaSummary,
|
|
45
55
|
peekMediaMeta,
|
|
46
56
|
recordImageSize,
|
|
@@ -48,24 +58,51 @@ import {
|
|
|
48
58
|
} from "../files/media-meta";
|
|
49
59
|
import { mediaSiteUrl, previewFileSrc } from "../files/media-paths";
|
|
50
60
|
import { notedListing } from "../files/asset-versions";
|
|
51
|
-
import type {
|
|
61
|
+
import type { MediaFileKind } from "../files/media-upload";
|
|
62
|
+
import type {
|
|
63
|
+
MediaBrowserRow,
|
|
64
|
+
MediaBrowserSurfaceHandle,
|
|
65
|
+
MediaBrowserView,
|
|
66
|
+
} from "../surfaces/media-browser";
|
|
52
67
|
import type { MediaFieldHandle, MediaFieldView } from "../surfaces/media-field";
|
|
68
|
+
import type * as MediaLibraryModule from "../media/media-library";
|
|
53
69
|
|
|
54
70
|
// ─── Media file cache ────────────────────────────────────────────────────────
|
|
55
71
|
|
|
56
|
-
/** One
|
|
57
|
-
interface
|
|
58
|
-
/** The
|
|
59
|
-
path: string;
|
|
60
|
-
/** Project-relative path on disk, the key everything in `media-meta` is stored under. */
|
|
72
|
+
/** One media file of the project, as every browsing surface lists it. */
|
|
73
|
+
export interface ProjectMediaFile {
|
|
74
|
+
/** The project-relative path on disk, the key everything in `media-meta` is stored under. */
|
|
61
75
|
file: string;
|
|
62
76
|
name: string;
|
|
77
|
+
/** The site URL a document authors for it, which is what a pick commits. */
|
|
78
|
+
ref: string;
|
|
63
79
|
isImage: boolean;
|
|
80
|
+
/** What the file is, as the Media workspace's filters name it. */
|
|
81
|
+
kind: MediaFileKind;
|
|
64
82
|
}
|
|
65
83
|
|
|
66
|
-
let mediaCache:
|
|
84
|
+
let mediaCache: ProjectMediaFile[] = [];
|
|
67
85
|
let mediaCacheLoaded = false;
|
|
68
86
|
|
|
87
|
+
/**
|
|
88
|
+
* The directory every collection co-locates its uploads in (`files/media-upload.ts`
|
|
89
|
+
* `uploadDirFor`).
|
|
90
|
+
*/
|
|
91
|
+
const COLLECTION_IMAGES = "images";
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Whether a project path is inside the media scan: under `public/`, or under a collection's
|
|
95
|
+
* `content/<collection>/images/`. A filesystem batch that touches neither cannot change what
|
|
96
|
+
* {@link projectMediaFiles} lists, so the listing is kept.
|
|
97
|
+
*/
|
|
98
|
+
export function isMediaScanPath(path: string): boolean {
|
|
99
|
+
const normalized = path.replaceAll("\\", "/");
|
|
100
|
+
return (
|
|
101
|
+
normalized.startsWith("public/") ||
|
|
102
|
+
new RegExp(`^content/[^/]+/${COLLECTION_IMAGES}/`).test(normalized)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
69
106
|
/**
|
|
70
107
|
* Recursively collect media files from a directory, seeding {@link seedMediaMeta} with the listing
|
|
71
108
|
* on the way past — the size of every row is already in the response that enumerated it.
|
|
@@ -73,8 +110,8 @@ let mediaCacheLoaded = false;
|
|
|
73
110
|
async function collectMedia(
|
|
74
111
|
dir: string,
|
|
75
112
|
platform: ReturnType<typeof getPlatform>,
|
|
76
|
-
): Promise<
|
|
77
|
-
const results:
|
|
113
|
+
): Promise<ProjectMediaFile[]> {
|
|
114
|
+
const results: ProjectMediaFile[] = [];
|
|
78
115
|
try {
|
|
79
116
|
const entries = await notedListing(() => platform.listDirectory(dir));
|
|
80
117
|
seedMediaMeta(entries);
|
|
@@ -88,10 +125,11 @@ async function collectMedia(
|
|
|
88
125
|
results.push({
|
|
89
126
|
file: entry.path,
|
|
90
127
|
isImage: IMAGE_EXTENSIONS.has(ext),
|
|
128
|
+
kind: mediaFileKind(entry.name),
|
|
91
129
|
name: entry.name,
|
|
92
130
|
// The site URL is what production serves and therefore what a document should say.
|
|
93
|
-
// Media-paths holds the one definition of that mapping.
|
|
94
|
-
|
|
131
|
+
// Media-paths holds the one definition of that mapping, a collection's mount included.
|
|
132
|
+
ref: mediaSiteUrl(entry.path),
|
|
95
133
|
});
|
|
96
134
|
}
|
|
97
135
|
}
|
|
@@ -102,16 +140,141 @@ async function collectMedia(
|
|
|
102
140
|
return results;
|
|
103
141
|
}
|
|
104
142
|
|
|
105
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Every collection's co-located `images/` folder: `content/<collection>/images/**`.
|
|
145
|
+
*
|
|
146
|
+
* Listed from `content/` itself rather than from `project.json`'s declarations, because the folder
|
|
147
|
+
* is where an upload from an entry lands whatever its collection's `source` says, and a picker that
|
|
148
|
+
* could not see it could not choose a cover image the author had just uploaded to an entry.
|
|
149
|
+
*/
|
|
150
|
+
async function collectCollectionImages(
|
|
151
|
+
platform: ReturnType<typeof getPlatform>,
|
|
152
|
+
): Promise<ProjectMediaFile[]> {
|
|
153
|
+
let collections: string[];
|
|
154
|
+
try {
|
|
155
|
+
const entries = await platform.listDirectory("content");
|
|
156
|
+
collections = entries.filter((entry) => entry.type === "directory").map((entry) => entry.path);
|
|
157
|
+
} catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
const results: ProjectMediaFile[] = [];
|
|
161
|
+
for (const dir of collections) {
|
|
162
|
+
/* Descend only into an `images/` the collection actually holds: most collections have none,
|
|
163
|
+
and asking the backend to list a directory that does not exist is a 404 in the console. */
|
|
164
|
+
let holdsImages = false;
|
|
165
|
+
try {
|
|
166
|
+
const entries = await platform.listDirectory(dir);
|
|
167
|
+
holdsImages = entries.some(
|
|
168
|
+
(entry) => entry.type === "directory" && entry.name === COLLECTION_IMAGES,
|
|
169
|
+
);
|
|
170
|
+
} catch {
|
|
171
|
+
// An unreadable collection folder has no images to offer.
|
|
172
|
+
}
|
|
173
|
+
if (holdsImages) {
|
|
174
|
+
results.push(...(await collectMedia(`${dir}/${COLLECTION_IMAGES}`, platform)));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return results;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Which of the two scan roots, `public` and `content`, the project root holds as folders. A root
|
|
182
|
+
* listing that fails says nothing either way, so both are then walked, each tolerating its own
|
|
183
|
+
* absence as it always has.
|
|
184
|
+
*/
|
|
185
|
+
async function projectScanRoots(platform: ReturnType<typeof getPlatform>): Promise<Set<string>> {
|
|
186
|
+
try {
|
|
187
|
+
const entries = await platform.listDirectory(".");
|
|
188
|
+
return new Set(
|
|
189
|
+
entries
|
|
190
|
+
.filter((entry) => entry.type === "directory")
|
|
191
|
+
.map((entry) => entry.name)
|
|
192
|
+
.filter((name) => name === "public" || name === "content"),
|
|
193
|
+
);
|
|
194
|
+
} catch {
|
|
195
|
+
return new Set(["public", "content"]);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** The walk in flight, so every caller that asks while it runs shares it instead of starting one. */
|
|
200
|
+
let _mediaLoading: Promise<void> | null = null;
|
|
201
|
+
/** Bumped by {@link invalidateMediaCache}, so a walk that started before it cannot land after it. */
|
|
202
|
+
let _mediaEpoch = 0;
|
|
203
|
+
|
|
204
|
+
/** Surfaces that own their own repaint and want to hear when the listing moves. */
|
|
205
|
+
const _listeners = new Set<() => void>();
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Hear about every change to the listing: a walk landing, or an invalidation dropping it.
|
|
209
|
+
*
|
|
210
|
+
* For a surface that is not one of the named panels {@link loadMediaCache} repaints — the Media
|
|
211
|
+
* workspace's library, which owns its own reactivity the way the Library pane does.
|
|
212
|
+
*
|
|
213
|
+
* @returns The unsubscribe.
|
|
214
|
+
*/
|
|
215
|
+
export function onProjectMediaChange(listener: () => void): () => void {
|
|
216
|
+
_listeners.add(listener);
|
|
217
|
+
return () => {
|
|
218
|
+
_listeners.delete(listener);
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function announce(): void {
|
|
223
|
+
for (const listener of _listeners) {
|
|
224
|
+
listener();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function loadMediaCache(): Promise<void> {
|
|
106
229
|
if (mediaCacheLoaded) {
|
|
107
|
-
return;
|
|
230
|
+
return Promise.resolve();
|
|
231
|
+
}
|
|
232
|
+
if (_mediaLoading) {
|
|
233
|
+
return _mediaLoading;
|
|
108
234
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
235
|
+
if (!hasPlatform()) {
|
|
236
|
+
// No backend to list (a window still booting): nothing is known, and nothing is claimed.
|
|
237
|
+
return Promise.resolve();
|
|
238
|
+
}
|
|
239
|
+
const epoch = _mediaEpoch;
|
|
240
|
+
const walk = (async () => {
|
|
241
|
+
const platform = getPlatform();
|
|
242
|
+
/* Descend only into the scan roots the project actually has: a project with no `content/` (a
|
|
243
|
+
site of pages alone) or no `public/` would otherwise ask the backend to list a folder that
|
|
244
|
+
does not exist, which is a 404 in the console on every visit to Media. */
|
|
245
|
+
const roots = await projectScanRoots(platform);
|
|
246
|
+
const [published, collections] = await Promise.all([
|
|
247
|
+
roots.has("public") ? collectMedia("public", platform) : [],
|
|
248
|
+
roots.has("content") ? collectCollectionImages(platform) : [],
|
|
249
|
+
]);
|
|
250
|
+
if (epoch !== _mediaEpoch) {
|
|
251
|
+
// Superseded: this listing is older than the invalidation, and a newer walk owns the cache.
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
mediaCache = [...published, ...collections];
|
|
255
|
+
mediaCacheLoaded = true;
|
|
256
|
+
_mediaLoading = null;
|
|
257
|
+
// Re-render the host panels so the browse panel has entries to show once the async listing
|
|
258
|
+
// Resolves. Mirrors loadLayoutEntries()'s renderOnly() in head-panel.
|
|
259
|
+
renderOnly("leftPanel", "rightPanel");
|
|
260
|
+
announce();
|
|
261
|
+
})();
|
|
262
|
+
_mediaLoading = walk;
|
|
263
|
+
return walk;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The project's media, or `null` while the listing is still being read — the same cache the picker
|
|
268
|
+
* browses, so the Site panel's Media section, the Media workspace and the image field cannot
|
|
269
|
+
* disagree about what exists. Asking starts the read; it repaints the panels that read it when it
|
|
270
|
+
* lands, and tells every {@link onProjectMediaChange} listener.
|
|
271
|
+
*/
|
|
272
|
+
export function projectMediaFiles(): readonly ProjectMediaFile[] | null {
|
|
273
|
+
if (!mediaCacheLoaded) {
|
|
274
|
+
void loadMediaCache();
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
return mediaCache;
|
|
115
278
|
}
|
|
116
279
|
|
|
117
280
|
/**
|
|
@@ -123,30 +286,74 @@ async function loadMediaCache() {
|
|
|
123
286
|
export function invalidateMediaCache() {
|
|
124
287
|
mediaCache = [];
|
|
125
288
|
mediaCacheLoaded = false;
|
|
289
|
+
_mediaEpoch += 1;
|
|
290
|
+
_mediaLoading = null;
|
|
126
291
|
invalidateMediaMeta();
|
|
292
|
+
announce();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ─── The full-size picker ────────────────────────────────────────────────────
|
|
296
|
+
|
|
297
|
+
/** What a chooser offers: every media file, or only images, for a field whose value is a picture. */
|
|
298
|
+
export interface MediaPickOptions {
|
|
299
|
+
images?: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* The library flow, imported on the first **Browse all media…**. One cached promise, because two
|
|
304
|
+
* dynamic imports of a module in flight at once is the shape that loses its coverage record, and a
|
|
305
|
+
* field nobody opened the big picker from should not load the workspace's surface.
|
|
306
|
+
*/
|
|
307
|
+
let _library: Promise<typeof MediaLibraryModule> | null = null;
|
|
308
|
+
|
|
309
|
+
function mediaLibrary(): Promise<typeof MediaLibraryModule> {
|
|
310
|
+
_library ??= import("../media/media-library");
|
|
311
|
+
return _library;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Open the Media workspace's surface in a dialog, in pick mode, and commit what is chosen.
|
|
316
|
+
*
|
|
317
|
+
* @param {(val: string) => void} onCommit - What a pick writes: the file's site URL
|
|
318
|
+
* @param {MediaPickOptions} options - Images only, for a field that holds a picture
|
|
319
|
+
*/
|
|
320
|
+
export async function openFullMediaPicker(
|
|
321
|
+
onCommit: (val: string) => void,
|
|
322
|
+
options: MediaPickOptions = {},
|
|
323
|
+
): Promise<void> {
|
|
324
|
+
const library = await mediaLibrary();
|
|
325
|
+
library.openMediaPickDialog({ images: options.images === true, onPick: onCommit });
|
|
127
326
|
}
|
|
128
327
|
|
|
129
328
|
// ─── The browser ─────────────────────────────────────────────────────────────
|
|
130
329
|
|
|
131
|
-
/**
|
|
330
|
+
/**
|
|
331
|
+
* How many rows the panel lists at first, and how many more each **Show N more** adds. Past the cap
|
|
332
|
+
* the rows are counted, and the count is the control that lists them, so every file the Media
|
|
333
|
+
* workspace has can be reached from here: the cap bounds the first paint, never the answer.
|
|
334
|
+
*/
|
|
132
335
|
const BROWSE_LIMIT = 50;
|
|
133
336
|
|
|
134
337
|
/** The open panel, and what a pick in it commits. One at a time. */
|
|
135
338
|
let _browser: MediaBrowserSurfaceHandle | null = null;
|
|
136
339
|
let _browserCommit: ((value: string) => void) | null = null;
|
|
137
340
|
let _browserFilter = "";
|
|
341
|
+
/** How many rows the open panel lists; raised by Show more, and never lowered while it is open. */
|
|
342
|
+
let _browserLimit = BROWSE_LIMIT;
|
|
343
|
+
let _browserOptions: MediaPickOptions = {};
|
|
138
344
|
/** Where the panel was opened, kept so a filter keystroke does not move it. */
|
|
139
345
|
let _browserOrigin = { x: 0, y: 0 };
|
|
140
346
|
|
|
141
347
|
/** What the panel shows for the filter that stands now. */
|
|
142
|
-
function browserView() {
|
|
348
|
+
function browserView(): MediaBrowserView {
|
|
143
349
|
const query = _browserFilter.toLowerCase();
|
|
350
|
+
const offered = _browserOptions.images ? mediaCache.filter((m) => m.isImage) : mediaCache;
|
|
144
351
|
const filtered = query
|
|
145
|
-
?
|
|
146
|
-
(m) => m.
|
|
352
|
+
? offered.filter(
|
|
353
|
+
(m) => m.ref.toLowerCase().includes(query) || m.name.toLowerCase().includes(query),
|
|
147
354
|
)
|
|
148
|
-
:
|
|
149
|
-
const listed = filtered.slice(0,
|
|
355
|
+
: offered;
|
|
356
|
+
const listed = filtered.slice(0, _browserLimit);
|
|
150
357
|
const rows: MediaBrowserRow[] = listed.map((m) => {
|
|
151
358
|
const caption = mediaMetaSummary(peekMediaMeta(m.file));
|
|
152
359
|
return {
|
|
@@ -155,18 +362,26 @@ function browserView() {
|
|
|
155
362
|
file: m.file,
|
|
156
363
|
key: m.file,
|
|
157
364
|
name: m.name,
|
|
158
|
-
path: m.
|
|
365
|
+
path: m.ref,
|
|
159
366
|
thumbSrc: m.isImage ? previewFileSrc(m.file) : "",
|
|
160
367
|
thumbState: m.isImage ? "shown" : "hidden",
|
|
161
368
|
};
|
|
162
369
|
});
|
|
163
370
|
return {
|
|
164
|
-
|
|
371
|
+
browseAllLabel: _browserOptions.images ? "Browse all images…" : "Browse all media…",
|
|
372
|
+
/* An empty project says so, rather than "No matches" over a search nobody typed: the Upload
|
|
373
|
+
beside the field and the row below are what to do about it. */
|
|
374
|
+
emptyLabel:
|
|
375
|
+
offered.length > 0
|
|
376
|
+
? "No matches"
|
|
377
|
+
: _browserOptions.images
|
|
378
|
+
? "No images in this project yet"
|
|
379
|
+
: "No media in this project yet",
|
|
165
380
|
filter: _browserFilter,
|
|
166
|
-
moreLabel:
|
|
167
|
-
moreState:
|
|
381
|
+
moreLabel: `Show ${Math.min(filtered.length - _browserLimit, BROWSE_LIMIT)} more`,
|
|
382
|
+
moreState: filtered.length > _browserLimit ? "shown" : "hidden",
|
|
168
383
|
rows,
|
|
169
|
-
rowsState:
|
|
384
|
+
rowsState: rows.length > 0 ? "listed" : "empty",
|
|
170
385
|
x: _browserOrigin.x,
|
|
171
386
|
y: _browserOrigin.y,
|
|
172
387
|
};
|
|
@@ -178,6 +393,7 @@ function dismissMediaPickerPopover() {
|
|
|
178
393
|
_browser = null;
|
|
179
394
|
_browserCommit = null;
|
|
180
395
|
_browserFilter = "";
|
|
396
|
+
_browserLimit = BROWSE_LIMIT;
|
|
181
397
|
open?.close();
|
|
182
398
|
}
|
|
183
399
|
|
|
@@ -194,7 +410,14 @@ let _sizeRepaint = 0;
|
|
|
194
410
|
* because the measurement has not changed.
|
|
195
411
|
*/
|
|
196
412
|
function noteImageSize(file: string, width: number, height: number) {
|
|
197
|
-
if (!recordImageSize(file, width, height)
|
|
413
|
+
if (!recordImageSize(file, width, height)) {
|
|
414
|
+
if (!mediaMetaSettled(file)) {
|
|
415
|
+
// An SVG's decode is not its size: the file says what it is, read once.
|
|
416
|
+
void loadMediaMeta(file).then(() => _browser?.update(browserView()));
|
|
417
|
+
}
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (_sizeRepaint !== 0) {
|
|
198
421
|
return;
|
|
199
422
|
}
|
|
200
423
|
_sizeRepaint = requestAnimationFrame(() => {
|
|
@@ -208,14 +431,23 @@ function noteImageSize(file: string, width: number, height: number) {
|
|
|
208
431
|
*
|
|
209
432
|
* Exported because the panel is a SURFACE OF ITS OWN — it renders into the popover layer, not into
|
|
210
433
|
* the field that opened it — so a converted surface can offer the same browser without
|
|
211
|
-
* re-implementing it.
|
|
434
|
+
* re-implementing it. The Inspector's Page tab's Browse button is one such caller, and the
|
|
435
|
+
* search-appearance dialog's image rows another: the panel is a top-layer `jx-popover`, so it
|
|
436
|
+
* paints over the modal that opened it.
|
|
212
437
|
*
|
|
213
438
|
* @param {HTMLElement} anchorEl
|
|
214
439
|
* @param {(val: string) => void} onCommit
|
|
440
|
+
* @param {MediaPickOptions} options - Images only, for a field that holds a picture
|
|
215
441
|
*/
|
|
216
|
-
export function showMediaPickerPopover(
|
|
442
|
+
export function showMediaPickerPopover(
|
|
443
|
+
anchorEl: HTMLElement,
|
|
444
|
+
onCommit: (val: string) => void,
|
|
445
|
+
options: MediaPickOptions = {},
|
|
446
|
+
) {
|
|
217
447
|
dismissMediaPickerPopover();
|
|
448
|
+
void loadMediaCache().then(() => _browser?.update(browserView()));
|
|
218
449
|
_browserCommit = onCommit;
|
|
450
|
+
_browserOptions = options;
|
|
219
451
|
const box = rectOf(anchorEl);
|
|
220
452
|
/* Where it opens, once. `jx-popover` clamps a freshly shown panel into the viewport itself, so
|
|
221
453
|
nothing here measures the panel or flips it above a low anchor — that was the layer-div
|
|
@@ -224,10 +456,19 @@ export function showMediaPickerPopover(anchorEl: HTMLElement, onCommit: (val: st
|
|
|
224
456
|
_browser = openMediaBrowserSurface(
|
|
225
457
|
browserView(),
|
|
226
458
|
{
|
|
459
|
+
browseAll: () => {
|
|
460
|
+
const commit = _browserCommit;
|
|
461
|
+
const chosen = _browserOptions;
|
|
462
|
+
dismissMediaPickerPopover();
|
|
463
|
+
if (commit) {
|
|
464
|
+
void openFullMediaPicker(commit, chosen);
|
|
465
|
+
}
|
|
466
|
+
},
|
|
227
467
|
dismissed: () => {
|
|
228
468
|
_browser = null;
|
|
229
469
|
_browserCommit = null;
|
|
230
470
|
_browserFilter = "";
|
|
471
|
+
_browserLimit = BROWSE_LIMIT;
|
|
231
472
|
},
|
|
232
473
|
measure: noteImageSize,
|
|
233
474
|
pick: (path: string) => {
|
|
@@ -235,6 +476,10 @@ export function showMediaPickerPopover(anchorEl: HTMLElement, onCommit: (val: st
|
|
|
235
476
|
dismissMediaPickerPopover();
|
|
236
477
|
commit?.(path);
|
|
237
478
|
},
|
|
479
|
+
showMore: () => {
|
|
480
|
+
_browserLimit += BROWSE_LIMIT;
|
|
481
|
+
_browser?.update(browserView());
|
|
482
|
+
},
|
|
238
483
|
setFilter: (value: string) => {
|
|
239
484
|
_browserFilter = value;
|
|
240
485
|
_browser?.update(browserView());
|
|
@@ -293,10 +538,15 @@ export function pickAndUpload(onCommit: (val: string) => void) {
|
|
|
293
538
|
const FIELD_DEBOUNCE_MS = 400;
|
|
294
539
|
|
|
295
540
|
/** One mounted field, and the decisions that move under it between repaints. */
|
|
296
|
-
|
|
297
|
-
|
|
541
|
+
/** What a field's callbacks read at call time; a re-mount rewrites both in place. */
|
|
542
|
+
interface FieldBinding {
|
|
298
543
|
prop: string;
|
|
299
544
|
commit: (value: string) => void;
|
|
545
|
+
options: MediaPickOptions;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
interface FieldEntry extends FieldBinding {
|
|
549
|
+
handle: MediaFieldHandle;
|
|
300
550
|
}
|
|
301
551
|
|
|
302
552
|
/**
|
|
@@ -331,12 +581,14 @@ function fieldView(prop: string, value: string): MediaFieldView {
|
|
|
331
581
|
* @param {string} prop - The attribute or prop being edited; the field's accessible name
|
|
332
582
|
* @param {string} value - What it holds now
|
|
333
583
|
* @param {(val: string) => void} onCommit - What a pick or a settled keystroke writes
|
|
584
|
+
* @param {MediaPickOptions} options - Images only, for a field whose value is a picture
|
|
334
585
|
*/
|
|
335
586
|
export function mountMediaPicker(
|
|
336
587
|
host: HTMLElement,
|
|
337
588
|
prop: string,
|
|
338
589
|
value: string,
|
|
339
590
|
onCommit: (val: string) => void,
|
|
591
|
+
options: MediaPickOptions = {},
|
|
340
592
|
): void {
|
|
341
593
|
// Kick off async load (won't block the mount)
|
|
342
594
|
void loadMediaCache();
|
|
@@ -344,14 +596,14 @@ export function mountMediaPicker(
|
|
|
344
596
|
if (existing) {
|
|
345
597
|
existing.prop = prop;
|
|
346
598
|
existing.commit = onCommit;
|
|
599
|
+
existing.options = options;
|
|
347
600
|
existing.handle.update(fieldView(prop, value));
|
|
348
601
|
return;
|
|
349
602
|
}
|
|
350
|
-
const entry:
|
|
351
|
-
|
|
603
|
+
const entry: FieldBinding = { commit: onCommit, options, prop };
|
|
604
|
+
const handle = mountMediaFieldSurface(host, fieldView(prop, value), {
|
|
352
605
|
browse: (anchor: HTMLElement) => {
|
|
353
|
-
|
|
354
|
-
showMediaPickerPopover(anchor, (val: string) => entry.commit(val));
|
|
606
|
+
showMediaPickerPopover(anchor, (val: string) => entry.commit(val), entry.options);
|
|
355
607
|
},
|
|
356
608
|
/* Debounced under the prop's own key, so the canvas follows the typing without a document write
|
|
357
609
|
per keystroke and two fields never share a timer. */
|
|
@@ -364,7 +616,8 @@ export function mountMediaPicker(
|
|
|
364
616
|
void loadMediaCache();
|
|
365
617
|
},
|
|
366
618
|
});
|
|
367
|
-
|
|
619
|
+
// The same object, so the callbacks above see a later re-mount's `prop` and `commit`.
|
|
620
|
+
_fields.set(host, Object.assign(entry, { handle }));
|
|
368
621
|
}
|
|
369
622
|
|
|
370
623
|
/**
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
import { layerHost } from "./layers";
|
|
31
31
|
import { overlayRegion, REGION_ATTR } from "./regions";
|
|
32
32
|
import { mountSurface } from "./surface";
|
|
33
|
-
import type { JxMountOptions } from "@jxsuite/runtime/types";
|
|
34
|
-
import type { SurfaceHandle } from "./surface";
|
|
33
|
+
import type { JxHostScope, JxMountOptions, JxScope } from "@jxsuite/runtime/types";
|
|
34
|
+
import type { MountSurfaceOptions, SurfaceHandle } from "./surface";
|
|
35
35
|
|
|
36
36
|
/** A popover panel element, as the platform's popover API sees it. */
|
|
37
37
|
type PanelElement = HTMLElement & {
|
|
@@ -51,13 +51,14 @@ export interface PopoverSurfaceHandle {
|
|
|
51
51
|
readonly close: () => void;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
/** How a popover surface is opened. `S` is the scope's own type, held to `JxHostScope` on open. */
|
|
55
|
+
export interface OpenPopoverSurfaceOptions<S = JxScope> {
|
|
55
56
|
/** The registered surface name — its document's root must be a `jx-popover`. */
|
|
56
57
|
name: string;
|
|
57
58
|
/** The panel's instance name; its region becomes `overlay.<kind>:<id>`. */
|
|
58
59
|
slot: string;
|
|
59
60
|
/** The reactive scope the document reads. */
|
|
60
|
-
scope:
|
|
61
|
+
scope: S;
|
|
61
62
|
/**
|
|
62
63
|
* The control it was opened from. It becomes the popover's invoker, so a press on that control
|
|
63
64
|
* does not light-dismiss the panel its own click is about to toggle, and focus goes back to it.
|
|
@@ -78,7 +79,9 @@ export interface OpenPopoverSurfaceOptions {
|
|
|
78
79
|
* @param {OpenPopoverSurfaceOptions} options
|
|
79
80
|
* @returns {PopoverSurfaceHandle}
|
|
80
81
|
*/
|
|
81
|
-
export function openPopoverSurface
|
|
82
|
+
export function openPopoverSurface<S extends JxHostScope<S>>(
|
|
83
|
+
options: OpenPopoverSurfaceOptions<S>,
|
|
84
|
+
): PopoverSurfaceHandle {
|
|
82
85
|
const { anchor, name, scope, slot: slotId } = options;
|
|
83
86
|
const host = document.createElement("div");
|
|
84
87
|
host.style.pointerEvents = "auto";
|
|
@@ -88,6 +91,8 @@ export function openPopoverSurface(options: OpenPopoverSurfaceOptions): PopoverS
|
|
|
88
91
|
let panel: PanelElement | null = null;
|
|
89
92
|
let mounted: SurfaceHandle | null = null;
|
|
90
93
|
let closed = false;
|
|
94
|
+
// A function rather than a property read, because the signal can abort across every `await` below.
|
|
95
|
+
const aborted = (): boolean => controller.signal.aborted;
|
|
91
96
|
|
|
92
97
|
const finish = (fromPlatform: boolean): void => {
|
|
93
98
|
if (closed) {
|
|
@@ -104,21 +109,24 @@ export function openPopoverSurface(options: OpenPopoverSurfaceOptions): PopoverS
|
|
|
104
109
|
};
|
|
105
110
|
|
|
106
111
|
const ready = (async () => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
+
const mountOptions: MountSurfaceOptions = { signal: controller.signal };
|
|
113
|
+
if (options.onNodeCreated) {
|
|
114
|
+
mountOptions.onNodeCreated = options.onNodeCreated;
|
|
115
|
+
}
|
|
116
|
+
const surface = await mountSurface(name, scope, host, mountOptions);
|
|
117
|
+
if (aborted()) {
|
|
112
118
|
return;
|
|
113
119
|
}
|
|
114
120
|
mounted = surface;
|
|
121
|
+
/* SAFETY: `name` must register a document whose root is a `jx-popover` (see
|
|
122
|
+
OpenPopoverSurfaceOptions.name), an HTMLElement carrying `open` and the popover methods. */
|
|
115
123
|
panel = surface.root as PanelElement;
|
|
116
124
|
/* On the PANEL as well as the slot: a popover is `position: fixed` in the top layer, so the
|
|
117
125
|
slot around it has a zero-height box and the screenshots lane refuses it ("has an empty
|
|
118
126
|
box"). Both carry the id; the measurement takes the last match, which is the panel. */
|
|
119
127
|
panel.setAttribute(REGION_ATTR, overlayRegion("popover", slotId));
|
|
120
128
|
panel.addEventListener("toggle", (event) => {
|
|
121
|
-
if (
|
|
129
|
+
if ("newState" in event && event.newState === "closed") {
|
|
122
130
|
finish(true);
|
|
123
131
|
}
|
|
124
132
|
});
|
|
@@ -130,7 +138,7 @@ export function openPopoverSurface(options: OpenPopoverSurfaceOptions): PopoverS
|
|
|
130
138
|
panel?.addEventListener("jx-ready", () => resolve(), { once: true });
|
|
131
139
|
});
|
|
132
140
|
}
|
|
133
|
-
if (
|
|
141
|
+
if (aborted()) {
|
|
134
142
|
return;
|
|
135
143
|
}
|
|
136
144
|
panel.showPopover(anchor ? { source: anchor } : undefined);
|
package/src/ui/progress-modal.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { beginActivity } from "../panels/activity-panel";
|
|
|
29
29
|
import { setBottomTab } from "../shell";
|
|
30
30
|
import { layerHost } from "./layers";
|
|
31
31
|
import { openProgressSurface } from "../surfaces/progress-modal";
|
|
32
|
-
import type { ActivityHandle } from "../panels/activity-panel";
|
|
32
|
+
import type { ActivityHandle, ActivityOptions } from "../panels/activity-panel";
|
|
33
33
|
|
|
34
34
|
export interface ProgressModalHandle {
|
|
35
35
|
/** Update the status line shown under the title. Also the Activity entry's status. */
|
|
@@ -68,12 +68,17 @@ export interface ProgressModalOptions {
|
|
|
68
68
|
export function showProgressModal(opts: ProgressModalOptions): ProgressModalHandle {
|
|
69
69
|
let closed = false;
|
|
70
70
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
const activityOptions: ActivityOptions = { title: opts.title };
|
|
72
|
+
if (opts.status !== undefined) {
|
|
73
|
+
activityOptions.status = opts.status;
|
|
74
|
+
}
|
|
75
|
+
if (opts.source !== undefined) {
|
|
76
|
+
activityOptions.source = opts.source;
|
|
77
|
+
}
|
|
78
|
+
if (opts.cancel !== undefined) {
|
|
79
|
+
activityOptions.cancel = opts.cancel;
|
|
80
|
+
}
|
|
81
|
+
const activity = beginActivity(activityOptions);
|
|
77
82
|
|
|
78
83
|
const close = () => {
|
|
79
84
|
if (closed) {
|
|
@@ -118,7 +123,7 @@ export function showProgressModal(opts: ProgressModalOptions): ProgressModalHand
|
|
|
118
123
|
// CAPTURED LOG as their message — `result.log ?? "bun install failed"` — so a multi-line one
|
|
119
124
|
// Is split the way the old view split it: "<title> failed" as the headline, the whole text
|
|
120
125
|
// As the detail. A Problems list whose first row is 400 lines of `bun` output is not a list.
|
|
121
|
-
const text =
|
|
126
|
+
const text = message.trim();
|
|
122
127
|
if (text === "" || text.includes("\n")) {
|
|
123
128
|
activity.log(text);
|
|
124
129
|
activity.fail(`${opts.title} failed`);
|