@jxsuite/studio 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-8jxwts2p.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-esrewxap.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-v7jkjqng.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-jm0z592w.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +21080 -32585
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -53
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +30 -1
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +7 -1
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-8jxwts2p.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-esrewxap.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual-window.ts — the windowing primitive behind every long list in Studio.
|
|
3
|
+
*
|
|
4
|
+
* **Why this is the acceptance criterion and not a nicety.** The Manage view the Library replaces
|
|
5
|
+
* rendered one card per file with no cap, and each Pages/Layouts/Components/Content card mounted a
|
|
6
|
+
* REAL `@jxsuite/runtime` render of that document. Opening "All" on a 300-page project therefore
|
|
7
|
+
* built 300 live documents, in one synchronous lit pass, and kept every one of them alive in an
|
|
8
|
+
* unbounded `Map`. The window is what makes the cost proportional to the VIEWPORT instead of to the
|
|
9
|
+
* project. The two trees pay a smaller version of the same bill — a 5 000-node page drew 5 000
|
|
10
|
+
* rows, each an `sp-icon` custom element — and they now pay it through this file.
|
|
11
|
+
*
|
|
12
|
+
* **It lives in `ui/`, not in `browse/`.** P3 workstream 11 promised "one virtual-list primitive
|
|
13
|
+
* behind the Files tree and the Outline tree, reused by the Library grid", and what shipped sat
|
|
14
|
+
* inside the Library and was imported by the Library alone. A primitive two surfaces share cannot
|
|
15
|
+
* live inside one of them: the next surface that needs it either reaches across a feature boundary
|
|
16
|
+
* or writes a second copy, and a second copy is how "the tree renders every row" survived a phase
|
|
17
|
+
* that had already solved it.
|
|
18
|
+
*
|
|
19
|
+
* The maths is deliberately a pure function ({@link computeWindow}) rather than a class: it is the
|
|
20
|
+
* part that has to be right, it is the part the perf test measures, and it needs no DOM to state.
|
|
21
|
+
* {@link createVirtualWindow} is the thin observer that feeds it scroll positions, and the
|
|
22
|
+
* {@link nearestScroller} half below is the small amount of DOM a list that does NOT own its own
|
|
23
|
+
* scrollbar needs — both trees scroll inside `#left-panel`, which also holds their toolbars.
|
|
24
|
+
*
|
|
25
|
+
* One primitive, three surfaces: the Library (Table rows, Cards, Media), the Files tree and the
|
|
26
|
+
* Outline. The geometry never mentions what an item IS.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/// <reference lib="dom" />
|
|
30
|
+
|
|
31
|
+
import { rectOf } from "../utils/geometry";
|
|
32
|
+
|
|
33
|
+
/** The measurement a window is computed from. Everything is in CSS pixels. */
|
|
34
|
+
export interface WindowSpec {
|
|
35
|
+
/** How many items exist in total. */
|
|
36
|
+
count: number;
|
|
37
|
+
/** Height of one ROW. A grid row holds {@link WindowSpec.columns} items. */
|
|
38
|
+
rowHeight: number;
|
|
39
|
+
/** Items per row. 1 for a list. Clamped to at least 1. */
|
|
40
|
+
columns?: number;
|
|
41
|
+
/** The scroller's current `scrollTop`. */
|
|
42
|
+
scrollTop: number;
|
|
43
|
+
/** The scroller's visible height. */
|
|
44
|
+
viewportHeight: number;
|
|
45
|
+
/** Extra rows rendered above and below the viewport. Defaults to {@link DEFAULT_OVERSCAN_ROWS}. */
|
|
46
|
+
overscanRows?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Which items to render, and how much empty space to reserve either side of them.
|
|
51
|
+
*
|
|
52
|
+
* `padTop`/`padBottom` are spacer heights rather than absolute positioning, so a windowed list is
|
|
53
|
+
* still an ordinary flow container: it wraps, it prints, and a focused control inside it scrolls
|
|
54
|
+
* into view without anything computing coordinates.
|
|
55
|
+
*/
|
|
56
|
+
export interface WindowRange {
|
|
57
|
+
/** First item index, inclusive. */
|
|
58
|
+
start: number;
|
|
59
|
+
/** Last item index, EXCLUSIVE. */
|
|
60
|
+
end: number;
|
|
61
|
+
/** Pixels of spacer above the first rendered row. */
|
|
62
|
+
padTop: number;
|
|
63
|
+
/** Pixels of spacer below the last rendered row. */
|
|
64
|
+
padBottom: number;
|
|
65
|
+
/** Total rows the full list would occupy — what the scrollbar is sized from. */
|
|
66
|
+
totalRows: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Rows kept beyond each edge of the viewport.
|
|
71
|
+
*
|
|
72
|
+
* Three, not zero: a window with no overscan repaints on every scroll frame and shows a blank strip
|
|
73
|
+
* for one frame at speed. Three is the smallest value at which neither is observable at a normal
|
|
74
|
+
* wheel velocity, and it is small enough that the LRU preview cap still dominates.
|
|
75
|
+
*/
|
|
76
|
+
export const DEFAULT_OVERSCAN_ROWS = 3;
|
|
77
|
+
|
|
78
|
+
/** Clamp `value` into `[low, high]`. */
|
|
79
|
+
function clamp(value: number, low: number, high: number): number {
|
|
80
|
+
return Math.min(high, Math.max(low, value));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The visible window for a spec.
|
|
85
|
+
*
|
|
86
|
+
* Total-safe by construction: a zero or negative `rowHeight` (an unmeasured container, a display:
|
|
87
|
+
* none pane) yields the whole list rather than an infinite loop or an empty render, because a
|
|
88
|
+
* Library that renders nothing is indistinguishable from a Library that found nothing — the exact
|
|
89
|
+
* confusion this phase exists to remove.
|
|
90
|
+
*/
|
|
91
|
+
export function computeWindow(spec: WindowSpec): WindowRange {
|
|
92
|
+
const count = Math.max(0, Math.trunc(spec.count));
|
|
93
|
+
const columns = Math.max(1, Math.trunc(spec.columns ?? 1));
|
|
94
|
+
const totalRows = Math.ceil(count / columns);
|
|
95
|
+
|
|
96
|
+
if (!(spec.rowHeight > 0) || !(spec.viewportHeight > 0)) {
|
|
97
|
+
return { end: count, padBottom: 0, padTop: 0, start: 0, totalRows };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const overscan = Math.max(0, Math.trunc(spec.overscanRows ?? DEFAULT_OVERSCAN_ROWS));
|
|
101
|
+
const scrollTop = Math.max(0, spec.scrollTop);
|
|
102
|
+
const firstVisibleRow = Math.floor(scrollTop / spec.rowHeight);
|
|
103
|
+
const visibleRows = Math.ceil(spec.viewportHeight / spec.rowHeight) + 1;
|
|
104
|
+
|
|
105
|
+
const startRow = clamp(firstVisibleRow - overscan, 0, totalRows);
|
|
106
|
+
const endRow = clamp(firstVisibleRow + visibleRows + overscan, startRow, totalRows);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
end: Math.min(count, endRow * columns),
|
|
110
|
+
padBottom: (totalRows - endRow) * spec.rowHeight,
|
|
111
|
+
padTop: startRow * spec.rowHeight,
|
|
112
|
+
start: Math.min(count, startRow * columns),
|
|
113
|
+
totalRows,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Two ranges are the same window — the guard that keeps scrolling from repainting every frame. */
|
|
118
|
+
export function sameWindow(a: WindowRange, b: WindowRange): boolean {
|
|
119
|
+
return a.start === b.start && a.end === b.end && a.totalRows === b.totalRows;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── The observer ────────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
export interface VirtualWindow {
|
|
125
|
+
/** The current range. Read during render; never stale by more than one frame. */
|
|
126
|
+
range: () => WindowRange;
|
|
127
|
+
/** Re-measure and recompute (count changed, layout changed, container resized). */
|
|
128
|
+
measure: () => void;
|
|
129
|
+
/** Stop listening. Idempotent. */
|
|
130
|
+
destroy: () => void;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface VirtualWindowOptions {
|
|
134
|
+
/** The element that scrolls. */
|
|
135
|
+
scroller: HTMLElement;
|
|
136
|
+
/**
|
|
137
|
+
* The list inside `scroller`, when the scroller carries more than the list.
|
|
138
|
+
*
|
|
139
|
+
* Both trees scroll inside `#left-panel`, which also holds a project header, a toolbar and — for
|
|
140
|
+
* the Files tree — a search field. Their first row is therefore NOT at `scrollTop` 0, and a
|
|
141
|
+
* window computed from the scroller's own `scrollTop` would be that header's height out from the
|
|
142
|
+
* first scroll onwards. Omit it when the list IS the scroller (the Library's pane).
|
|
143
|
+
*/
|
|
144
|
+
list?: HTMLElement;
|
|
145
|
+
/** Item count right now — read on every measure, so it may change without re-creating. */
|
|
146
|
+
count: () => number;
|
|
147
|
+
/** Row height right now. */
|
|
148
|
+
rowHeight: () => number;
|
|
149
|
+
/** Items per row right now. */
|
|
150
|
+
columns?: () => number;
|
|
151
|
+
/** Called only when the window actually CHANGED. */
|
|
152
|
+
onChange: (range: WindowRange) => void;
|
|
153
|
+
overscanRows?: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Watch a scroller and report window changes.
|
|
158
|
+
*
|
|
159
|
+
* Scroll is listened to passively and answered synchronously: the range is cheap to compute and a
|
|
160
|
+
* rAF hop would paint the spacer before the content one frame in three. `ResizeObserver` covers the
|
|
161
|
+
* pane being resized; where the environment has none (happy-dom), `measure()` is the whole contract
|
|
162
|
+
* and the caller drives it — which is also how the perf test drives it.
|
|
163
|
+
*/
|
|
164
|
+
export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindow {
|
|
165
|
+
const { scroller, list, count, rowHeight, columns, onChange, overscanRows } = options;
|
|
166
|
+
let current: WindowRange = { end: 0, padBottom: 0, padTop: 0, start: 0, totalRows: 0 };
|
|
167
|
+
let destroyed = false;
|
|
168
|
+
|
|
169
|
+
function measure() {
|
|
170
|
+
if (destroyed) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const next = computeWindow({
|
|
174
|
+
columns: columns?.() ?? 1,
|
|
175
|
+
count: count(),
|
|
176
|
+
overscanRows: overscanRows ?? DEFAULT_OVERSCAN_ROWS,
|
|
177
|
+
rowHeight: rowHeight(),
|
|
178
|
+
scrollTop: list ? listScrollTop(scroller, list) : scroller.scrollTop,
|
|
179
|
+
viewportHeight: scroller.clientHeight,
|
|
180
|
+
});
|
|
181
|
+
const changed = !sameWindow(current, next);
|
|
182
|
+
current = next;
|
|
183
|
+
if (changed) {
|
|
184
|
+
onChange(next);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
scroller.addEventListener("scroll", measure, { passive: true });
|
|
189
|
+
|
|
190
|
+
let resizeObserver: ResizeObserver | null = null;
|
|
191
|
+
if (typeof ResizeObserver === "function") {
|
|
192
|
+
resizeObserver = new ResizeObserver(() => measure());
|
|
193
|
+
resizeObserver.observe(scroller);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
measure();
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
destroy() {
|
|
200
|
+
destroyed = true;
|
|
201
|
+
scroller.removeEventListener("scroll", measure);
|
|
202
|
+
resizeObserver?.disconnect();
|
|
203
|
+
resizeObserver = null;
|
|
204
|
+
},
|
|
205
|
+
measure,
|
|
206
|
+
range: () => current,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ─── A list that does not own its scrollbar ──────────────────────────────────
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The element that scrolls `el`, or null when nothing does.
|
|
214
|
+
*
|
|
215
|
+
* TWO conditions, and the second is the one that makes this honest. An element is the scroller only
|
|
216
|
+
* if it both declares a scrolling overflow AND currently has something to scroll. `.file-tree`
|
|
217
|
+
* declares `overflow-y: auto` (styles/panels.css) but is never given a height, so it grows with its
|
|
218
|
+
* content and never scrolls — treating it as the scroller would read its full content height as the
|
|
219
|
+
* VIEWPORT height and window nothing at all, silently. The `scrollHeight > clientHeight` test walks
|
|
220
|
+
* past it to `#left-panel`, which is where both trees actually scroll.
|
|
221
|
+
*
|
|
222
|
+
* The same test is why a list whose content fits is never windowed: there is nothing to scroll, so
|
|
223
|
+
* there is nothing to save, and the whole list renders exactly as it always did.
|
|
224
|
+
*/
|
|
225
|
+
export function nearestScroller(el: HTMLElement | null): HTMLElement | null {
|
|
226
|
+
for (let node: HTMLElement | null = el; node; node = node.parentElement) {
|
|
227
|
+
// Cheap test first: happy-dom performs no layout, so this is 0 > 0 for every element and no
|
|
228
|
+
// Test ever pays for a `getComputedStyle` walk it cannot answer.
|
|
229
|
+
if (node.scrollHeight <= node.clientHeight) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const overflow = getComputedStyle(node).overflowY;
|
|
233
|
+
if (overflow === "auto" || overflow === "scroll" || overflow === "overlay") {
|
|
234
|
+
return node;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* How far `list`'s first row has scrolled above the top of `scroller`'s viewport.
|
|
242
|
+
*
|
|
243
|
+
* Measured from the two rects rather than from `offsetTop`, because the chrome between them is not
|
|
244
|
+
* a fixed height: the Files tree's toolbar and the project header are both conditional. When the
|
|
245
|
+
* list IS the scroller there is no chrome and its own `scrollTop` is the answer.
|
|
246
|
+
*/
|
|
247
|
+
export function listScrollTop(scroller: HTMLElement, list: HTMLElement): number {
|
|
248
|
+
if (scroller === list) {
|
|
249
|
+
return Math.max(0, scroller.scrollTop);
|
|
250
|
+
}
|
|
251
|
+
return Math.max(0, rectOf(scroller).top - rectOf(list).top);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* The window for a list rendered inside whatever scrolls it — the trees' entry point.
|
|
256
|
+
*
|
|
257
|
+
* Answers "the whole list" for a list that has not been rendered yet, has been detached, or is not
|
|
258
|
+
* inside anything that scrolls. That is not a fallback bolted on for tests: it is the FIRST paint
|
|
259
|
+
* of every session (nothing can be measured before the rows exist), and it is every list short
|
|
260
|
+
* enough to fit. Both must render everything, and both are what the trees did before they
|
|
261
|
+
* windowed.
|
|
262
|
+
*/
|
|
263
|
+
export function listWindow(
|
|
264
|
+
list: HTMLElement | null,
|
|
265
|
+
spec: { count: number; rowHeight: number; columns?: number; overscanRows?: number },
|
|
266
|
+
): WindowRange {
|
|
267
|
+
const scroller = list?.isConnected === true ? nearestScroller(list) : null;
|
|
268
|
+
if (!scroller || !list) {
|
|
269
|
+
const count = Math.max(0, Math.trunc(spec.count));
|
|
270
|
+
return { end: count, padBottom: 0, padTop: 0, start: 0, totalRows: count };
|
|
271
|
+
}
|
|
272
|
+
return computeWindow({
|
|
273
|
+
columns: spec.columns ?? 1,
|
|
274
|
+
count: spec.count,
|
|
275
|
+
...(spec.overscanRows === undefined ? {} : { overscanRows: spec.overscanRows }),
|
|
276
|
+
rowHeight: spec.rowHeight,
|
|
277
|
+
scrollTop: listScrollTop(scroller, list),
|
|
278
|
+
viewportHeight: scroller.clientHeight,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The `scrollTop` that brings row `index` into view, or null when it already is.
|
|
284
|
+
*
|
|
285
|
+
* `block: "nearest"` semantics, stated as arithmetic: a windowed list cannot delegate this to
|
|
286
|
+
* `Element.scrollIntoView`, because the row it must reveal is precisely the one that has no
|
|
287
|
+
* element. Pure, so the reveal rule is testable without a scroller.
|
|
288
|
+
*/
|
|
289
|
+
export function scrollTopToReveal(spec: {
|
|
290
|
+
index: number;
|
|
291
|
+
rowHeight: number;
|
|
292
|
+
/** Where the list's first row sits in the scroller's CONTENT, not its viewport. */
|
|
293
|
+
listOffset: number;
|
|
294
|
+
scrollTop: number;
|
|
295
|
+
viewportHeight: number;
|
|
296
|
+
}): number | null {
|
|
297
|
+
const top = spec.listOffset + spec.index * spec.rowHeight;
|
|
298
|
+
const bottom = top + spec.rowHeight;
|
|
299
|
+
if (top < spec.scrollTop) {
|
|
300
|
+
return Math.max(0, top);
|
|
301
|
+
}
|
|
302
|
+
if (bottom > spec.scrollTop + spec.viewportHeight) {
|
|
303
|
+
return Math.max(0, bottom - spec.viewportHeight);
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Scroll `list` so that its row at `index` is inside the window on the next render.
|
|
310
|
+
*
|
|
311
|
+
* Returns whether anything moved. The re-render is deliberately NOT triggered here: assigning
|
|
312
|
+
* `scrollTop` fires a `scroll` event, and the watch installed by {@link watchListWindow} is already
|
|
313
|
+
* the one thing that decides when a scroll is worth a repaint. A caller that repainted as well
|
|
314
|
+
* would paint twice for one keystroke.
|
|
315
|
+
*/
|
|
316
|
+
export function revealListRow(list: HTMLElement | null, index: number, rowHeight: number): boolean {
|
|
317
|
+
const scroller = list?.isConnected === true ? nearestScroller(list) : null;
|
|
318
|
+
if (!scroller || !list || index < 0 || !(rowHeight > 0)) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
const { scrollTop } = scroller;
|
|
322
|
+
const next = scrollTopToReveal({
|
|
323
|
+
index,
|
|
324
|
+
listOffset: scrollTop - listScrollTop(scroller, list),
|
|
325
|
+
rowHeight,
|
|
326
|
+
scrollTop,
|
|
327
|
+
viewportHeight: scroller.clientHeight,
|
|
328
|
+
});
|
|
329
|
+
if (next === null) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
scroller.scrollTop = next;
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* The height one row actually has, measured, with the stylesheet's declared height as the answer
|
|
338
|
+
* until a row exists to measure.
|
|
339
|
+
*
|
|
340
|
+
* Both are needed. The DECLARED height (`styles/panels.css` gives `.layer-row` and
|
|
341
|
+
* `.file-tree-item` a `block-size`) is what lets the FIRST render window anything at all, before
|
|
342
|
+
* any row has been laid out. The MEASUREMENT is what stops that constant becoming a lie the day
|
|
343
|
+
* someone changes the row's padding, a user zooms, or a locale's font raises the line box: a window
|
|
344
|
+
* computed from a stale height does not fail loudly, it drifts, and the list quietly ends a few
|
|
345
|
+
* rows short of its own scrollbar.
|
|
346
|
+
*/
|
|
347
|
+
export function measuredRowHeight(
|
|
348
|
+
list: HTMLElement | null,
|
|
349
|
+
selector: string,
|
|
350
|
+
declared: number,
|
|
351
|
+
): number {
|
|
352
|
+
const row = list?.querySelector<HTMLElement>(selector);
|
|
353
|
+
return row && row.offsetHeight > 0 ? row.offsetHeight : declared;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** A live scroll watch over one list element. Held at module scope by the surface that renders it. */
|
|
357
|
+
export interface ListWindowWatch {
|
|
358
|
+
/** The list this watch is bound to. A different element means a different watch. */
|
|
359
|
+
list: HTMLElement;
|
|
360
|
+
/** The scroller it resolved to when it was bound. */
|
|
361
|
+
scroller: HTMLElement;
|
|
362
|
+
window: VirtualWindow;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Bind — or keep — the scroll watch that repaints a windowed list.
|
|
367
|
+
*
|
|
368
|
+
* Called from the surface's `afterRender`, where the rows exist and the scroller can be resolved,
|
|
369
|
+
* and handed back its own previous handle so re-binding is the exception rather than the rule: the
|
|
370
|
+
* tree element survives every re-render (lit reuses it), so the steady state is "same list, same
|
|
371
|
+
* scroller, nothing to do". A new element — the panel remounted, or moved dock — moves the
|
|
372
|
+
* listener, and a list that no longer scrolls drops it.
|
|
373
|
+
*
|
|
374
|
+
* Returns the handle to keep, or null when nothing scrolls this list.
|
|
375
|
+
*/
|
|
376
|
+
export function watchListWindow(
|
|
377
|
+
previous: ListWindowWatch | null,
|
|
378
|
+
list: HTMLElement,
|
|
379
|
+
spec: { count: () => number; rowHeight: () => number; onChange: () => void },
|
|
380
|
+
): ListWindowWatch | null {
|
|
381
|
+
const scroller = nearestScroller(list);
|
|
382
|
+
if (previous && previous.list === list && previous.scroller === scroller) {
|
|
383
|
+
return previous;
|
|
384
|
+
}
|
|
385
|
+
previous?.window.destroy();
|
|
386
|
+
if (!scroller) {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
list,
|
|
391
|
+
scroller,
|
|
392
|
+
window: createVirtualWindow({
|
|
393
|
+
count: spec.count,
|
|
394
|
+
list,
|
|
395
|
+
onChange: () => spec.onChange(),
|
|
396
|
+
rowHeight: spec.rowHeight,
|
|
397
|
+
scroller,
|
|
398
|
+
}),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
9
|
+
import { displayTagName } from "@jxsuite/schema/guards";
|
|
9
10
|
|
|
10
11
|
const mediaTags = new Set(["img", "video", "source", "iframe", "audio"]);
|
|
11
12
|
const TRANSPARENT_PX =
|
|
@@ -103,10 +104,10 @@ export function computeEmptyPlaceholderClass(node: JxMutableNode): string | null
|
|
|
103
104
|
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
104
105
|
return null;
|
|
105
106
|
}
|
|
106
|
-
if (textTags.has(node.tagName)) {
|
|
107
|
+
if (textTags.has(displayTagName(node.tagName))) {
|
|
107
108
|
return "empty-text-placeholder";
|
|
108
109
|
}
|
|
109
|
-
if (containerTags.has(node.tagName)) {
|
|
110
|
+
if (containerTags.has(displayTagName(node.tagName))) {
|
|
110
111
|
return "empty-container-placeholder";
|
|
111
112
|
}
|
|
112
113
|
return null;
|
|
@@ -1,75 +1,105 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Inherited-style.js —
|
|
2
|
+
* Inherited-style.js — the effective inherited style for a breakpoint tab, **and the breakpoint it
|
|
3
|
+
* came from**.
|
|
3
4
|
*
|
|
4
5
|
* Walks the cascade (base → each media block in order) up to but not including the active
|
|
5
6
|
* breakpoint, producing the set of property values that would apply if no explicit override exists
|
|
6
7
|
* on the current tab.
|
|
8
|
+
*
|
|
9
|
+
* The walk has always known the donor — it is the loop variable — and the answer was thrown away
|
|
10
|
+
* one line later, which left the inspector able to show an inherited value only as an input
|
|
11
|
+
* placeholder, visually identical to the CSS initial value rendered beside it.
|
|
12
|
+
* {@link computeInheritedSources} keeps the donor; {@link computeInheritedStyle} is the projection
|
|
13
|
+
* that drops it, for callers that only want the value.
|
|
7
14
|
*/
|
|
8
15
|
|
|
9
16
|
import type { JxStyle } from "@jxsuite/schema/types";
|
|
10
17
|
|
|
18
|
+
/** One inherited property: the value that shows through, and the breakpoint it was set on. */
|
|
19
|
+
export interface InheritedSource {
|
|
20
|
+
value: string | number;
|
|
21
|
+
/** The donor breakpoint's name, or `null` when the value comes from the base context. */
|
|
22
|
+
donor: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
11
25
|
/**
|
|
12
|
-
* Compute the inherited style
|
|
26
|
+
* Compute the inherited style map WITH each value's donor breakpoint.
|
|
13
27
|
*
|
|
14
28
|
* @param {JxStyle} style — full style object (flat props + @media blocks + selectors)
|
|
15
29
|
* @param {string[]} mediaNames — ordered breakpoint names (from parseMediaEntries, respects cascade
|
|
16
30
|
* direction)
|
|
17
31
|
* @param {string | null} activeTab — current breakpoint tab name, or null for base
|
|
18
32
|
* @param {string | null} activeSelector — current nested selector, or null
|
|
19
|
-
* @returns {Record<string,
|
|
33
|
+
* @returns {Record<string, InheritedSource>} Prop → { value, donor }
|
|
20
34
|
*/
|
|
21
|
-
export function
|
|
35
|
+
export function computeInheritedSources(
|
|
22
36
|
style: JxStyle,
|
|
23
37
|
mediaNames: string[],
|
|
24
38
|
activeTab: string | null,
|
|
25
39
|
activeSelector: string | null = null,
|
|
26
|
-
) {
|
|
40
|
+
): Record<string, InheritedSource> {
|
|
27
41
|
if (activeTab === null || mediaNames.length === 0) {
|
|
28
42
|
return {};
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
const inherited: Record<string,
|
|
45
|
+
const inherited: Record<string, InheritedSource> = {};
|
|
32
46
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
for (const [p, v] of Object.entries(
|
|
36
|
-
if (typeof v !== "object") {
|
|
37
|
-
inherited[p] = (v as string | number) ?? "";
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// Layer each media block in order until current tab
|
|
41
|
-
for (const name of mediaNames) {
|
|
42
|
-
if (name === activeTab) {
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
const block = (style[`@${name}`] || {}) as JxStyle;
|
|
46
|
-
for (const [p, v] of Object.entries(block)) {
|
|
47
|
-
if (typeof v !== "object") {
|
|
48
|
-
inherited[p] = (v as string | number) ?? "";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
// Selector inheritance: base selector → each media's selector block in order
|
|
54
|
-
const baseSel = (style[activeSelector] || {}) as JxStyle;
|
|
55
|
-
for (const [p, v] of Object.entries(baseSel)) {
|
|
47
|
+
/** Layer one block over the accumulator, recording `donor` for everything it contributes. */
|
|
48
|
+
const layer = (block: JxStyle, donor: string | null) => {
|
|
49
|
+
for (const [p, v] of Object.entries(block)) {
|
|
56
50
|
if (typeof v !== "object") {
|
|
57
|
-
inherited[p] = (v as string | number) ?? "";
|
|
51
|
+
inherited[p] = { donor, value: (v as string | number) ?? "" };
|
|
58
52
|
}
|
|
59
53
|
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (activeSelector) {
|
|
57
|
+
// Selector inheritance: base selector → each media's selector block, in cascade order.
|
|
58
|
+
layer((style[activeSelector] || {}) as JxStyle, null);
|
|
60
59
|
for (const name of mediaNames) {
|
|
61
60
|
if (name === activeTab) {
|
|
62
61
|
break;
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
{}) as JxStyle
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
inherited[p] = (v as string | number) ?? "";
|
|
69
|
-
}
|
|
70
|
-
}
|
|
63
|
+
layer(
|
|
64
|
+
(((style[`@${name}`] || {}) as Record<string, unknown>)[activeSelector] || {}) as JxStyle,
|
|
65
|
+
name,
|
|
66
|
+
);
|
|
71
67
|
}
|
|
68
|
+
return inherited;
|
|
72
69
|
}
|
|
73
70
|
|
|
71
|
+
// Base flat props first, then each media block in order until the current tab.
|
|
72
|
+
layer(style, null);
|
|
73
|
+
for (const name of mediaNames) {
|
|
74
|
+
if (name === activeTab) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
layer((style[`@${name}`] || {}) as JxStyle, name);
|
|
78
|
+
}
|
|
74
79
|
return inherited;
|
|
75
80
|
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Compute the inherited style object for a given breakpoint tab — values only.
|
|
84
|
+
*
|
|
85
|
+
* @param {JxStyle} style — full style object (flat props + @media blocks + selectors)
|
|
86
|
+
* @param {string[]} mediaNames — ordered breakpoint names (from parseMediaEntries, respects cascade
|
|
87
|
+
* direction)
|
|
88
|
+
* @param {string | null} activeTab — current breakpoint tab name, or null for base
|
|
89
|
+
* @param {string | null} activeSelector — current nested selector, or null
|
|
90
|
+
* @returns {Record<string, string | number>} Inherited style map (prop → value)
|
|
91
|
+
*/
|
|
92
|
+
export function computeInheritedStyle(
|
|
93
|
+
style: JxStyle,
|
|
94
|
+
mediaNames: string[],
|
|
95
|
+
activeTab: string | null,
|
|
96
|
+
activeSelector: string | null = null,
|
|
97
|
+
): Record<string, string | number> {
|
|
98
|
+
const values: Record<string, string | number> = {};
|
|
99
|
+
for (const [prop, source] of Object.entries(
|
|
100
|
+
computeInheritedSources(style, mediaNames, activeTab, activeSelector),
|
|
101
|
+
)) {
|
|
102
|
+
values[prop] = source.value;
|
|
103
|
+
}
|
|
104
|
+
return values;
|
|
105
|
+
}
|