@jxsuite/studio 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +23711 -35185
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +34 -9
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +270 -262
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -120
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +75 -2
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +113 -0
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
- package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
- package/dist/chunks/files-02zn5y24.js +0 -50
- package/dist/chunks/files-02zn5y24.js.map +0 -9
- package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
- package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
- package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
- package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
- package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
- package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-568nx4t5.js +0 -469
- package/dist/chunks/studio-568nx4t5.js.map +0 -14
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-asvf0j9e.js +0 -429
- package/dist/chunks/studio-asvf0j9e.js.map +0 -13
- package/dist/chunks/studio-d77qm3pk.js +0 -3427
- package/dist/chunks/studio-d77qm3pk.js.map +0 -26
- package/dist/chunks/studio-j6gqyjf4.js +0 -1854
- package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
- package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-rq0vxb19.js +0 -3744
- package/dist/chunks/studio-rq0vxb19.js.map +0 -22
- package/dist/chunks/studio-wd6ewdvd.js +0 -853
- package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-ygzav7z5.js.map +0 -46
- package/dist/chunks/studio-zmy7241e.js +0 -399
- package/dist/chunks/studio-zmy7241e.js.map +0 -12
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
classMap,
|
|
3
|
-
ifDefined,
|
|
4
|
-
styleMap
|
|
5
|
-
} from "./studio-cx91mnh8.js";
|
|
6
|
-
import {
|
|
7
|
-
live
|
|
8
|
-
} from "./studio-nqw433kv.js";
|
|
9
|
-
import {
|
|
10
|
-
isRef
|
|
11
|
-
} from "./studio-rq0vxb19.js";
|
|
12
|
-
import {
|
|
13
|
-
html,
|
|
14
|
-
nothing
|
|
15
|
-
} from "./studio-5x5774ak.js";
|
|
16
|
-
|
|
17
|
-
// src/ui/field-row.ts
|
|
18
|
-
function renderFieldRow({
|
|
19
|
-
prop,
|
|
20
|
-
label,
|
|
21
|
-
hasValue,
|
|
22
|
-
onClear,
|
|
23
|
-
widget,
|
|
24
|
-
labelExtra,
|
|
25
|
-
span,
|
|
26
|
-
warning
|
|
27
|
-
}) {
|
|
28
|
-
return html`
|
|
29
|
-
<div
|
|
30
|
-
class=${classMap({ "style-row": true, "style-row--warning": Boolean(warning) })}
|
|
31
|
-
data-prop=${prop}
|
|
32
|
-
style=${span === 2 ? "grid-column: 1 / -1" : ""}
|
|
33
|
-
>
|
|
34
|
-
<div class="style-row-label">
|
|
35
|
-
${hasValue && onClear ? html`<span
|
|
36
|
-
class="set-dot"
|
|
37
|
-
title="Clear ${prop}"
|
|
38
|
-
@click=${(e) => {
|
|
39
|
-
e.stopPropagation();
|
|
40
|
-
onClear();
|
|
41
|
-
}}
|
|
42
|
-
></span>` : nothing}
|
|
43
|
-
<sp-field-label size="s" title=${prop}>${label}</sp-field-label>
|
|
44
|
-
${labelExtra ?? nothing}
|
|
45
|
-
</div>
|
|
46
|
-
${widget}
|
|
47
|
-
</div>
|
|
48
|
-
`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// src/ui/schema-form.ts
|
|
52
|
-
var controlRegistry = new Map;
|
|
53
|
-
function registerFormControl(name, control) {
|
|
54
|
-
controlRegistry.set(name, control);
|
|
55
|
-
}
|
|
56
|
-
var NULL_CONTEXT = {
|
|
57
|
-
resolvePointer: () => {}
|
|
58
|
-
};
|
|
59
|
-
function resolveFormEnum(enumDef, ctx, scope) {
|
|
60
|
-
if (Array.isArray(enumDef)) {
|
|
61
|
-
return enumDef;
|
|
62
|
-
}
|
|
63
|
-
let pointer;
|
|
64
|
-
if (enumDef && typeof enumDef === "object") {
|
|
65
|
-
const ref = enumDef.$ref;
|
|
66
|
-
if (typeof ref === "string") {
|
|
67
|
-
pointer = ref;
|
|
68
|
-
}
|
|
69
|
-
} else if (typeof enumDef === "string") {
|
|
70
|
-
pointer = enumDef;
|
|
71
|
-
}
|
|
72
|
-
if (pointer === undefined || !ctx) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const resolved = ctx.resolvePointer(pointer, scope);
|
|
76
|
-
if (Array.isArray(resolved)) {
|
|
77
|
-
return resolved.map(String);
|
|
78
|
-
}
|
|
79
|
-
if (resolved && typeof resolved === "object") {
|
|
80
|
-
return Object.keys(resolved);
|
|
81
|
-
}
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
function parseNumericField(raw, integer) {
|
|
85
|
-
if (raw.trim() === "") {
|
|
86
|
-
return Number.NaN;
|
|
87
|
-
}
|
|
88
|
-
return integer ? Math.trunc(Number(raw)) : Number(raw);
|
|
89
|
-
}
|
|
90
|
-
function refTextField(key, refVal, onChange) {
|
|
91
|
-
return html`<sp-textfield
|
|
92
|
-
size="s"
|
|
93
|
-
label=${key}
|
|
94
|
-
placeholder=${key}
|
|
95
|
-
.value=${live(refVal)}
|
|
96
|
-
@change=${(e) => {
|
|
97
|
-
const v = e.target.value.trim();
|
|
98
|
-
onChange(v ? { $ref: v } : undefined);
|
|
99
|
-
}}
|
|
100
|
-
></sp-textfield>`;
|
|
101
|
-
}
|
|
102
|
-
function renderInlineField(key, schema, value, onChange, ctx, scope) {
|
|
103
|
-
if (isRef(value)) {
|
|
104
|
-
return refTextField(key, value.$ref, onChange);
|
|
105
|
-
}
|
|
106
|
-
const enumValues = resolveFormEnum(schema.enum, ctx, scope);
|
|
107
|
-
if (enumValues) {
|
|
108
|
-
return html`<sp-picker
|
|
109
|
-
size="s"
|
|
110
|
-
label=${key}
|
|
111
|
-
value=${value !== undefined ? String(value) : "__none__"}
|
|
112
|
-
@change=${(e) => onChange(e.target.value === "__none__" ? undefined : e.target.value)}
|
|
113
|
-
>
|
|
114
|
-
<sp-menu-item value="__none__">—</sp-menu-item>
|
|
115
|
-
${enumValues.map((v) => html`<sp-menu-item value=${v}>${v}</sp-menu-item>`)}
|
|
116
|
-
</sp-picker>`;
|
|
117
|
-
}
|
|
118
|
-
if (schema.type === "boolean") {
|
|
119
|
-
return html`<sp-switch
|
|
120
|
-
size="s"
|
|
121
|
-
?checked=${Boolean(value)}
|
|
122
|
-
@change=${(e) => onChange(e.target.checked)}
|
|
123
|
-
>${key}</sp-switch
|
|
124
|
-
>`;
|
|
125
|
-
}
|
|
126
|
-
if (schema.type === "integer" || schema.type === "number") {
|
|
127
|
-
return html`<sp-number-field
|
|
128
|
-
size="s"
|
|
129
|
-
label=${key}
|
|
130
|
-
.value=${value !== undefined ? value : nothing}
|
|
131
|
-
step=${schema.type === "integer" ? "1" : nothing}
|
|
132
|
-
@change=${(e) => {
|
|
133
|
-
const parsed = parseNumericField(e.target.value, schema.type === "integer");
|
|
134
|
-
onChange(Number.isNaN(parsed) ? undefined : parsed);
|
|
135
|
-
}}
|
|
136
|
-
></sp-number-field>`;
|
|
137
|
-
}
|
|
138
|
-
return html`<sp-textfield
|
|
139
|
-
size="s"
|
|
140
|
-
label=${key}
|
|
141
|
-
placeholder=${key}
|
|
142
|
-
.value=${value ?? ""}
|
|
143
|
-
@input=${(e) => onChange(e.target.value || undefined)}
|
|
144
|
-
></sp-textfield>`;
|
|
145
|
-
}
|
|
146
|
-
function renderJsonTextField(currentValue, ps, commit) {
|
|
147
|
-
let debounce;
|
|
148
|
-
return html`<sp-textfield
|
|
149
|
-
multiline
|
|
150
|
-
size="s"
|
|
151
|
-
style="min-height:40px"
|
|
152
|
-
.value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
|
|
153
|
-
placeholder=${ps.default !== undefined ? JSON.stringify(ps.default) : nothing}
|
|
154
|
-
@input=${(e) => {
|
|
155
|
-
clearTimeout(debounce);
|
|
156
|
-
debounce = setTimeout(() => {
|
|
157
|
-
try {
|
|
158
|
-
commit(JSON.parse(e.target.value));
|
|
159
|
-
} catch {}
|
|
160
|
-
}, 500);
|
|
161
|
-
}}
|
|
162
|
-
></sp-textfield>`;
|
|
163
|
-
}
|
|
164
|
-
function renderPropertyControl(prop, ps, value, required, opts, ctx) {
|
|
165
|
-
const currentValue = value[prop];
|
|
166
|
-
const commit = (next) => opts.onChange({ [prop]: next });
|
|
167
|
-
const controlArgs = {
|
|
168
|
-
ctx,
|
|
169
|
-
key: prop,
|
|
170
|
-
onChange: commit,
|
|
171
|
-
rerender: opts.rerender,
|
|
172
|
-
schema: ps,
|
|
173
|
-
value: currentValue
|
|
174
|
-
};
|
|
175
|
-
const overrideName = opts.ui?.[prop]?.control;
|
|
176
|
-
if (overrideName) {
|
|
177
|
-
const custom = controlRegistry.get(overrideName);
|
|
178
|
-
if (custom) {
|
|
179
|
-
return custom(controlArgs);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if (isRef(currentValue) && ps.format !== "json-schema" && ps.type !== "object" && ps.type !== "array") {
|
|
183
|
-
const binding = controlRegistry.get("binding");
|
|
184
|
-
if (binding) {
|
|
185
|
-
return binding(controlArgs);
|
|
186
|
-
}
|
|
187
|
-
return refTextField(prop, currentValue.$ref, commit);
|
|
188
|
-
}
|
|
189
|
-
const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);
|
|
190
|
-
if (enumValues) {
|
|
191
|
-
return html`
|
|
192
|
-
<sp-picker
|
|
193
|
-
size="s"
|
|
194
|
-
value=${currentValue !== undefined ? String(currentValue) : ps.default !== undefined ? String(ps.default) : "__none__"}
|
|
195
|
-
@change=${(e) => commit(e.target.value === "__none__" ? undefined : e.target.value)}
|
|
196
|
-
>
|
|
197
|
-
${!required.has(prop) ? html`<sp-menu-item value="__none__">—</sp-menu-item>` : nothing}
|
|
198
|
-
${enumValues.map((val) => html`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}
|
|
199
|
-
</sp-picker>
|
|
200
|
-
`;
|
|
201
|
-
}
|
|
202
|
-
if (ps.type === "boolean") {
|
|
203
|
-
return html`<sp-checkbox
|
|
204
|
-
?checked=${currentValue ?? ps.default ?? false}
|
|
205
|
-
@change=${(e) => commit(e.target.checked)}
|
|
206
|
-
></sp-checkbox>`;
|
|
207
|
-
}
|
|
208
|
-
if (ps.type === "integer" || ps.type === "number") {
|
|
209
|
-
let debounce2;
|
|
210
|
-
return html`<sp-number-field
|
|
211
|
-
size="s"
|
|
212
|
-
min=${ifDefined(ps.minimum)}
|
|
213
|
-
max=${ifDefined(ps.maximum)}
|
|
214
|
-
step=${ps.type === "integer" ? "1" : nothing}
|
|
215
|
-
.value=${currentValue !== undefined ? currentValue : nothing}
|
|
216
|
-
placeholder=${ps.default != null ? String(ps.default) : nothing}
|
|
217
|
-
@change=${(e) => {
|
|
218
|
-
clearTimeout(debounce2);
|
|
219
|
-
debounce2 = setTimeout(() => {
|
|
220
|
-
const parsed = parseNumericField(e.target.value, ps.type === "integer");
|
|
221
|
-
commit(Number.isNaN(parsed) ? undefined : parsed);
|
|
222
|
-
}, 400);
|
|
223
|
-
}}
|
|
224
|
-
></sp-number-field>`;
|
|
225
|
-
}
|
|
226
|
-
if (ps.format === "json-schema") {
|
|
227
|
-
const hasValue = currentValue && typeof currentValue === "object" && Object.keys(currentValue).length > 0;
|
|
228
|
-
const cv = currentValue;
|
|
229
|
-
const isSchemaRef = hasValue && cv.$ref;
|
|
230
|
-
let debounce2;
|
|
231
|
-
return html`
|
|
232
|
-
<div class="schema-param-editor">
|
|
233
|
-
${hasValue && !isSchemaRef && cv.properties ? html`
|
|
234
|
-
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px">
|
|
235
|
-
${Object.entries(cv.properties).map(([k, v]) => html`
|
|
236
|
-
<span
|
|
237
|
-
style="background:var(--bg);padding:1px 6px;border-radius:var(--radius);font-size:10px;color:var(--fg-dim)"
|
|
238
|
-
>${k}: ${v.type ?? "any"}</span
|
|
239
|
-
>
|
|
240
|
-
`)}
|
|
241
|
-
</div>
|
|
242
|
-
` : nothing}
|
|
243
|
-
<sp-textfield
|
|
244
|
-
multiline
|
|
245
|
-
size="s"
|
|
246
|
-
style=${styleMap({
|
|
247
|
-
fontFamily: "monospace",
|
|
248
|
-
fontSize: "11px",
|
|
249
|
-
minHeight: hasValue ? "80px" : "40px"
|
|
250
|
-
})}
|
|
251
|
-
.value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
|
|
252
|
-
placeholder=${ps.description ?? "JSON Schema defining the data shape…"}
|
|
253
|
-
@input=${(e) => {
|
|
254
|
-
clearTimeout(debounce2);
|
|
255
|
-
debounce2 = setTimeout(() => {
|
|
256
|
-
try {
|
|
257
|
-
commit(JSON.parse(e.target.value));
|
|
258
|
-
} catch {}
|
|
259
|
-
}, 500);
|
|
260
|
-
}}
|
|
261
|
-
></sp-textfield>
|
|
262
|
-
</div>
|
|
263
|
-
`;
|
|
264
|
-
}
|
|
265
|
-
if (ps.type === "array" && ps.items?.type === "object" && ps.items?.properties) {
|
|
266
|
-
const rows = Array.isArray(currentValue) ? currentValue : [];
|
|
267
|
-
const itemProps = ps.items.properties;
|
|
268
|
-
return html`
|
|
269
|
-
<div class="array-object-field">
|
|
270
|
-
${rows.map((row, idx) => html`
|
|
271
|
-
<div
|
|
272
|
-
class="array-object-row"
|
|
273
|
-
style="display:flex;gap:4px;align-items:center;margin-bottom:4px"
|
|
274
|
-
>
|
|
275
|
-
${Object.entries(itemProps).map(([propKey, propSchema]) => renderInlineField(propKey, propSchema, row[propKey], (val) => {
|
|
276
|
-
const updated = [...rows];
|
|
277
|
-
updated[idx] = { ...updated[idx], [propKey]: val };
|
|
278
|
-
commit(updated);
|
|
279
|
-
}, ctx, value))}
|
|
280
|
-
<sp-action-button
|
|
281
|
-
quiet
|
|
282
|
-
size="s"
|
|
283
|
-
@click=${() => {
|
|
284
|
-
const updated = rows.filter((_, i) => i !== idx);
|
|
285
|
-
commit(updated.length > 0 ? updated : undefined);
|
|
286
|
-
opts.rerender?.();
|
|
287
|
-
}}
|
|
288
|
-
>
|
|
289
|
-
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
290
|
-
</sp-action-button>
|
|
291
|
-
</div>
|
|
292
|
-
`)}
|
|
293
|
-
<sp-action-button
|
|
294
|
-
quiet
|
|
295
|
-
size="s"
|
|
296
|
-
@click=${(e) => {
|
|
297
|
-
e.stopPropagation();
|
|
298
|
-
const newRow = {};
|
|
299
|
-
for (const [k, v] of Object.entries(itemProps)) {
|
|
300
|
-
if (v.default !== undefined) {
|
|
301
|
-
newRow[k] = v.default;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
commit([...rows, newRow]);
|
|
305
|
-
opts.rerender?.();
|
|
306
|
-
}}
|
|
307
|
-
>+ Add</sp-action-button
|
|
308
|
-
>
|
|
309
|
-
</div>
|
|
310
|
-
`;
|
|
311
|
-
}
|
|
312
|
-
if (ps.type === "array" || ps.type === "object") {
|
|
313
|
-
return renderJsonTextField(currentValue, ps, commit);
|
|
314
|
-
}
|
|
315
|
-
let debounce;
|
|
316
|
-
const params = ctx.params ?? [];
|
|
317
|
-
const ph = ps.default !== undefined ? String(ps.default) : ps.examples?.[0] ?? "";
|
|
318
|
-
return html`<div style="display:flex;gap:4px;align-items:center">
|
|
319
|
-
<sp-textfield
|
|
320
|
-
size="s"
|
|
321
|
-
style="flex:1"
|
|
322
|
-
.value=${currentValue ?? ""}
|
|
323
|
-
placeholder=${ph || nothing}
|
|
324
|
-
title=${ps.description || nothing}
|
|
325
|
-
@input=${(e) => {
|
|
326
|
-
clearTimeout(debounce);
|
|
327
|
-
debounce = setTimeout(() => commit(e.target.value || undefined), 400);
|
|
328
|
-
}}
|
|
329
|
-
></sp-textfield>
|
|
330
|
-
${params.length > 0 ? html`<sp-action-button
|
|
331
|
-
quiet
|
|
332
|
-
size="s"
|
|
333
|
-
title="Bind to route param"
|
|
334
|
-
@click=${() => {
|
|
335
|
-
commit({ $ref: `#/$params/${params[0]}` });
|
|
336
|
-
opts.rerender?.();
|
|
337
|
-
}}
|
|
338
|
-
><sp-icon-link slot="icon"></sp-icon-link
|
|
339
|
-
></sp-action-button>` : nothing}
|
|
340
|
-
</div>`;
|
|
341
|
-
}
|
|
342
|
-
function renderForm(schema, value, opts) {
|
|
343
|
-
const required = new Set(schema.required);
|
|
344
|
-
const ctx = opts.context ?? NULL_CONTEXT;
|
|
345
|
-
const propertyFields = Object.entries(schema.properties ?? {}).map(([prop, ps]) => {
|
|
346
|
-
const labelText = prop + (required.has(prop) ? " *" : "");
|
|
347
|
-
return renderFieldRow({
|
|
348
|
-
hasValue: false,
|
|
349
|
-
label: labelText,
|
|
350
|
-
prop: ps.name || prop,
|
|
351
|
-
widget: renderPropertyControl(prop, ps, value, required, opts, ctx)
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
return html`${propertyFields}`;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// src/services/context-resolver.ts
|
|
358
|
-
var PARAM_SEGMENT = /^\{@(\w+)\}$/;
|
|
359
|
-
function resolveContextPointer(pointer, opts) {
|
|
360
|
-
if (!pointer.startsWith("#/$context/")) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const segments = [];
|
|
364
|
-
for (const raw of pointer.slice("#/$context/".length).split("/")) {
|
|
365
|
-
const match = raw.match(PARAM_SEGMENT);
|
|
366
|
-
if (match) {
|
|
367
|
-
const value = opts.scope?.[match[1]];
|
|
368
|
-
if (typeof value !== "string" && typeof value !== "number") {
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
const substituted = String(value);
|
|
372
|
-
if (!substituted) {
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
segments.push(substituted);
|
|
376
|
-
} else {
|
|
377
|
-
segments.push(raw);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
if (segments[0] === "$formats") {
|
|
381
|
-
if (segments.length !== 1) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
return (opts.formats ?? []).map((format) => format.name);
|
|
385
|
-
}
|
|
386
|
-
let node = opts.projectConfig;
|
|
387
|
-
for (const segment of segments) {
|
|
388
|
-
if (node === null || typeof node !== "object") {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
node = node[segment];
|
|
392
|
-
}
|
|
393
|
-
return node;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
export { renderFieldRow, registerFormControl, renderForm, resolveContextPointer };
|
|
397
|
-
|
|
398
|
-
//# debugId=C2BB6E7E97CDF54564756E2164756E21
|
|
399
|
-
//# sourceMappingURL=studio-zmy7241e.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/ui/field-row.ts", "../src/ui/schema-form.ts", "../src/services/context-resolver.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/// <reference lib=\"dom\" />\n/**\n * Field-row.js — Universal field row layout for all Studio panels.\n *\n * Renders the consistent pattern: indicator dot + label + widget slot. Used by style panel,\n * attributes panel, frontmatter panel, signals panel, etc.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport { classMap } from \"lit-html/directives/class-map.js\";\n\n/**\n * Render a universal field row with indicator dot, label, and widget.\n *\n * @param {{\n * prop: string;\n * label: string;\n * hasValue: boolean;\n * onClear?: () => void;\n * widget: unknown;\n * labelExtra?: unknown;\n * span?: number;\n * warning?: boolean;\n * }} opts\n * @returns {import(\"lit-html\").TemplateResult}\n */\nexport function renderFieldRow({\n prop,\n label,\n hasValue,\n onClear,\n widget,\n labelExtra,\n span,\n warning,\n}: {\n prop: string;\n label: string;\n hasValue: boolean;\n onClear?: () => void;\n widget: unknown;\n /** Rendered after the label inside the label cell (e.g. the dynamic-slot mode button). */\n labelExtra?: unknown;\n span?: number;\n warning?: boolean;\n}) {\n return html`\n <div\n class=${classMap({ \"style-row\": true, \"style-row--warning\": Boolean(warning) })}\n data-prop=${prop}\n style=${span === 2 ? \"grid-column: 1 / -1\" : \"\"}\n >\n <div class=\"style-row-label\">\n ${\n hasValue && onClear\n ? html`<span\n class=\"set-dot\"\n title=\"Clear ${prop}\"\n @click=${(e: Event) => {\n e.stopPropagation();\n onClear();\n }}\n ></span>`\n : nothing\n }\n <sp-field-label size=\"s\" title=${prop}>${label}</sp-field-label>\n ${labelExtra ?? nothing}\n </div>\n ${widget}\n </div>\n `;\n}\n",
|
|
6
|
-
"/// <reference lib=\"dom\" />\n/**\n * Schema-form — reusable JSON-Schema → form rendering engine, extracted from the signals panel.\n *\n * Maps schema property types to Spectrum controls (enum → picker, boolean → checkbox,\n * number/integer → number-field, `json-schema` format → multiline JSON editor, array-of-objects →\n * multi-row inline form, other array/object → JSON text field, default → textfield). Hosts commit\n * edits through a single `onChange(patch)` callback; dynamic enum choices and `$ref` bindings\n * resolve through a {@link SchemaFormContext}. Custom controls register by name via\n * {@link registerFormControl} and are consulted first for `ui` overrides.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport { ifDefined } from \"lit-html/directives/if-defined.js\";\nimport { live } from \"lit-html/directives/live.js\";\nimport { styleMap } from \"lit-html/directives/style-map.js\";\nimport { isRef } from \"@jxsuite/schema/guards\";\nimport { renderFieldRow } from \"./field-row\";\nimport type { TemplateResult } from \"lit-html\";\n\n/** A (possibly nested) JSON Schema node, covering both object and property level keys. */\nexport interface JsonSchema {\n type?: string;\n properties?: Record<string, JsonSchema>;\n required?: string[];\n description?: string;\n enum?: unknown;\n default?: unknown;\n format?: string;\n minimum?: number;\n maximum?: number;\n examples?: string[];\n name?: string;\n items?: JsonSchema;\n}\n\n/** Host-provided context threaded to every control. */\nexport interface SchemaFormContext {\n /** Resolve a `#/$context/…` pointer (or legacy sentinel) against the host's project config. */\n resolvePointer: (pointer: string, scope?: Record<string, unknown>) => unknown;\n /** Route params available for `$ref` bindings (e.g. from the document path). */\n params?: string[] | undefined;\n /** Unique prefix for per-field ephemeral UI state (e.g. the binding control's custom mode). */\n fieldKeyPrefix?: string | undefined;\n /**\n * Commit hook for the \"secret\" control: stores the VALUE in the platform's secret store (never\n * project.json) and returns the derived env-var NAME, which the control persists to the field\n * instead of the value.\n */\n commitSecret?: ((key: string, value: string) => string | Promise<string>) | undefined;\n}\n\n/** Arguments passed to a registered form control. */\nexport interface SchemaFormControlArgs {\n key: string;\n schema: JsonSchema;\n value: unknown;\n onChange: (next: unknown) => void;\n ctx: SchemaFormContext;\n rerender?: (() => void) | undefined;\n}\n\nexport type SchemaFormControl = (args: SchemaFormControlArgs) => TemplateResult;\n\n/** Options for {@link renderForm}. */\nexport interface RenderFormOptions {\n onChange: (patch: Record<string, unknown>) => void;\n context?: SchemaFormContext | undefined;\n /**\n * Per-field overrides from `$studio.settings.entry.ui`: a registered control name, and/or an\n * `enum` source (choice list or `{ \"$ref\": \"#/$context/<pointer>\" }`) layered over the field\n * schema — fragments stay valid JSON Schema while descriptors add dynamic choices.\n */\n ui?: Record<string, { control?: string; enum?: unknown }> | undefined;\n rerender?: (() => void) | undefined;\n}\n\n// ─── Control registry ────────────────────────────────────────────────────────\n\nconst controlRegistry = new Map<string, SchemaFormControl>();\n\n/** Register (or replace) a named form control. */\nexport function registerFormControl(name: string, control: SchemaFormControl): void {\n controlRegistry.set(name, control);\n}\n\n/** Look up a registered form control by name. */\nexport function getFormControl(name: string): SchemaFormControl | undefined {\n return controlRegistry.get(name);\n}\n\n/** Inert context used when a host renders a form without one. */\nconst NULL_CONTEXT: SchemaFormContext = {\n resolvePointer: () => {\n // Nothing to resolve against without a host context\n },\n};\n\n// ─── Enum resolution ─────────────────────────────────────────────────────────\n\n/**\n * Resolve a schema enum definition to concrete choices. Plain arrays pass through; `$ref` objects\n * and sentinel strings resolve through the context's pointer resolver, applying object →\n * `Object.keys` and string[] → itself.\n *\n * @param {unknown} enumDef\n * @param {SchemaFormContext | undefined} ctx\n * @param {Record<string, unknown>} [scope] - Scope for `{@param}` substitution (the form value)\n * @returns {string[] | undefined}\n */\nexport function resolveFormEnum(\n enumDef: unknown,\n ctx?: SchemaFormContext,\n scope?: Record<string, unknown>,\n): string[] | undefined {\n if (Array.isArray(enumDef)) {\n return enumDef as string[];\n }\n let pointer: string | undefined;\n if (enumDef && typeof enumDef === \"object\") {\n const ref = (enumDef as Record<string, unknown>).$ref;\n if (typeof ref === \"string\") {\n pointer = ref;\n }\n } else if (typeof enumDef === \"string\") {\n // Legacy sentinel strings (e.g. \"$contentTypes\") resolve through the host's pointer resolver\n pointer = enumDef;\n }\n if (pointer === undefined || !ctx) {\n return undefined;\n }\n const resolved = ctx.resolvePointer(pointer, scope);\n if (Array.isArray(resolved)) {\n return resolved.map(String);\n }\n if (resolved && typeof resolved === \"object\") {\n return Object.keys(resolved);\n }\n return undefined;\n}\n\n// ─── Field helpers ───────────────────────────────────────────────────────────\n\n/** Parse a numeric field value, returning NaN for blank input (so callers can treat it as unset). */\nexport function parseNumericField(raw: string, integer: boolean): number {\n if (raw.trim() === \"\") {\n return Number.NaN;\n }\n return integer ? Math.trunc(Number(raw)) : Number(raw);\n}\n\n/** Plain textfield editing a `{ $ref }` value directly — the fallback when no binding control. */\nfunction refTextField(key: string, refVal: string, onChange: (next: unknown) => void) {\n return html`<sp-textfield\n size=\"s\"\n label=${key}\n placeholder=${key}\n .value=${live(refVal)}\n @change=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value.trim();\n onChange(v ? { $ref: v } : undefined);\n }}\n ></sp-textfield>`;\n}\n\n/**\n * Render a single inline field within an array-of-objects row. Dispatches by schema type: enum →\n * picker, boolean → switch, number → number-field, else → textfield.\n *\n * @param {string} key\n * @param {JsonSchema} schema\n * @param {unknown} value\n * @param {(val: unknown) => void} onChange\n * @param {SchemaFormContext | undefined} ctx\n * @param {Record<string, unknown>} [scope] - Scope for dependent enum refs (the parent form value)\n */\nexport function renderInlineField(\n key: string,\n schema: JsonSchema,\n value: unknown,\n onChange: (val: unknown) => void,\n ctx?: SchemaFormContext,\n scope?: Record<string, unknown>,\n) {\n if (isRef(value)) {\n return refTextField(key, value.$ref, onChange);\n }\n const enumValues = resolveFormEnum(schema.enum, ctx, scope);\n\n if (enumValues) {\n return html`<sp-picker\n size=\"s\"\n label=${key}\n value=${value !== undefined ? String(value) : \"__none__\"}\n @change=${(e: Event) =>\n onChange(\n (e.target as HTMLInputElement).value === \"__none__\"\n ? undefined\n : (e.target as HTMLInputElement).value,\n )}\n >\n <sp-menu-item value=\"__none__\">—</sp-menu-item>\n ${enumValues.map((v: string) => html`<sp-menu-item value=${v}>${v}</sp-menu-item>`)}\n </sp-picker>`;\n }\n if (schema.type === \"boolean\") {\n return html`<sp-switch\n size=\"s\"\n ?checked=${Boolean(value)}\n @change=${(e: Event) => onChange((e.target as HTMLInputElement).checked)}\n >${key}</sp-switch\n >`;\n }\n if (schema.type === \"integer\" || schema.type === \"number\") {\n return html`<sp-number-field\n size=\"s\"\n label=${key}\n .value=${value !== undefined ? value : nothing}\n step=${schema.type === \"integer\" ? \"1\" : nothing}\n @change=${(e: Event) => {\n const parsed = parseNumericField(\n (e.target as HTMLInputElement).value,\n schema.type === \"integer\",\n );\n onChange(Number.isNaN(parsed) ? undefined : parsed);\n }}\n ></sp-number-field>`;\n }\n return html`<sp-textfield\n size=\"s\"\n label=${key}\n placeholder=${key}\n .value=${value ?? \"\"}\n @input=${(e: Event) => onChange((e.target as HTMLInputElement).value || undefined)}\n ></sp-textfield>`;\n}\n\n/** Render a debounced multiline JSON text field for array/object schema properties. */\nfunction renderJsonTextField(currentValue: unknown, ps: JsonSchema, commit: (v: unknown) => void) {\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`<sp-textfield\n multiline\n size=\"s\"\n style=\"min-height:40px\"\n .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : \"\"}\n placeholder=${ps.default !== undefined ? JSON.stringify(ps.default) : nothing}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n try {\n commit(JSON.parse((e.target as HTMLInputElement).value) as unknown);\n } catch {}\n }, 500);\n }}\n ></sp-textfield>`;\n}\n\n// ─── Per-property control dispatch ───────────────────────────────────────────\n\n/** Render the widget for one schema property, honoring registered-control overrides. */\nfunction renderPropertyControl(\n prop: string,\n ps: JsonSchema,\n value: Record<string, unknown>,\n required: Set<string>,\n opts: RenderFormOptions,\n ctx: SchemaFormContext,\n): TemplateResult {\n const currentValue = value[prop];\n const commit = (next: unknown) => opts.onChange({ [prop]: next });\n const controlArgs: SchemaFormControlArgs = {\n ctx,\n key: prop,\n onChange: commit,\n rerender: opts.rerender,\n schema: ps,\n value: currentValue,\n };\n\n // Explicit ui override → consult the control registry first\n const overrideName = opts.ui?.[prop]?.control;\n if (overrideName) {\n const custom = controlRegistry.get(overrideName);\n if (custom) {\n return custom(controlArgs);\n }\n }\n\n if (\n isRef(currentValue) &&\n ps.format !== \"json-schema\" &&\n ps.type !== \"object\" &&\n ps.type !== \"array\"\n ) {\n const binding = controlRegistry.get(\"binding\");\n if (binding) {\n return binding(controlArgs);\n }\n return refTextField(prop, currentValue.$ref, commit);\n }\n\n const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);\n if (enumValues) {\n return html`\n <sp-picker\n size=\"s\"\n value=${\n currentValue !== undefined\n ? String(currentValue)\n : ps.default !== undefined\n ? String(ps.default)\n : \"__none__\"\n }\n @change=${(e: Event) =>\n commit(\n (e.target as HTMLInputElement).value === \"__none__\"\n ? undefined\n : (e.target as HTMLInputElement).value,\n )}\n >\n ${!required.has(prop) ? html`<sp-menu-item value=\"__none__\">—</sp-menu-item>` : nothing}\n ${enumValues.map((val: string) => html`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}\n </sp-picker>\n `;\n }\n if (ps.type === \"boolean\") {\n return html`<sp-checkbox\n ?checked=${currentValue ?? ps.default ?? false}\n @change=${(e: Event) => commit((e.target as HTMLInputElement).checked)}\n ></sp-checkbox>`;\n }\n if (ps.type === \"integer\" || ps.type === \"number\") {\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`<sp-number-field\n size=\"s\"\n min=${ifDefined(ps.minimum)}\n max=${ifDefined(ps.maximum)}\n step=${ps.type === \"integer\" ? \"1\" : nothing}\n .value=${currentValue !== undefined ? currentValue : nothing}\n placeholder=${ps.default != null ? String(ps.default) : nothing}\n @change=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n const parsed = parseNumericField(\n (e.target as HTMLInputElement).value,\n ps.type === \"integer\",\n );\n commit(Number.isNaN(parsed) ? undefined : parsed);\n }, 400);\n }}\n ></sp-number-field>`;\n }\n if (ps.format === \"json-schema\") {\n const hasValue =\n currentValue && typeof currentValue === \"object\" && Object.keys(currentValue).length > 0;\n const cv = currentValue as Record<string, unknown>;\n const isSchemaRef = hasValue && cv.$ref;\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`\n <div class=\"schema-param-editor\">\n ${\n hasValue && !isSchemaRef && cv.properties\n ? html`\n <div style=\"display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px\">\n ${Object.entries(cv.properties as Record<string, Record<string, unknown>>).map(\n ([k, v]) => html`\n <span\n style=\"background:var(--bg);padding:1px 6px;border-radius:var(--radius);font-size:10px;color:var(--fg-dim)\"\n >${k}: ${v.type ?? \"any\"}</span\n >\n `,\n )}\n </div>\n `\n : nothing\n }\n <sp-textfield\n multiline\n size=\"s\"\n style=${styleMap({\n fontFamily: \"monospace\",\n fontSize: \"11px\",\n minHeight: hasValue ? \"80px\" : \"40px\",\n })}\n .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : \"\"}\n placeholder=${ps.description ?? \"JSON Schema defining the data shape…\"}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n try {\n commit(JSON.parse((e.target as HTMLInputElement).value) as unknown);\n } catch {}\n }, 500);\n }}\n ></sp-textfield>\n </div>\n `;\n }\n if (ps.type === \"array\" && ps.items?.type === \"object\" && ps.items?.properties) {\n // Array of objects with defined schema → multi-row inline form\n const rows: Record<string, unknown>[] = Array.isArray(currentValue)\n ? (currentValue as Record<string, unknown>[])\n : [];\n const itemProps = ps.items.properties;\n return html`\n <div class=\"array-object-field\">\n ${rows.map(\n (row: Record<string, unknown>, idx: number) => html`\n <div\n class=\"array-object-row\"\n style=\"display:flex;gap:4px;align-items:center;margin-bottom:4px\"\n >\n ${Object.entries(itemProps).map(([propKey, propSchema]) =>\n renderInlineField(\n propKey,\n propSchema,\n row[propKey],\n (val) => {\n const updated = [...rows];\n updated[idx] = { ...updated[idx], [propKey]: val };\n commit(updated);\n },\n ctx,\n value,\n ),\n )}\n <sp-action-button\n quiet\n size=\"s\"\n @click=${() => {\n const updated = rows.filter((_: unknown, i: number) => i !== idx);\n commit(updated.length > 0 ? updated : undefined);\n opts.rerender?.();\n }}\n >\n <sp-icon-delete slot=\"icon\"></sp-icon-delete>\n </sp-action-button>\n </div>\n `,\n )}\n <sp-action-button\n quiet\n size=\"s\"\n @click=${(e: Event) => {\n e.stopPropagation();\n const newRow: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(itemProps)) {\n if (v.default !== undefined) {\n newRow[k] = v.default;\n }\n }\n commit([...rows, newRow]);\n opts.rerender?.();\n }}\n >+ Add</sp-action-button\n >\n </div>\n `;\n }\n if (ps.type === \"array\" || ps.type === \"object\") {\n return renderJsonTextField(currentValue, ps, commit) as TemplateResult;\n }\n\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n const params = ctx.params ?? [];\n const ph = ps.default !== undefined ? String(ps.default) : (ps.examples?.[0] ?? \"\");\n return html`<div style=\"display:flex;gap:4px;align-items:center\">\n <sp-textfield\n size=\"s\"\n style=\"flex:1\"\n .value=${currentValue ?? \"\"}\n placeholder=${ph || nothing}\n title=${ps.description || nothing}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => commit((e.target as HTMLInputElement).value || undefined), 400);\n }}\n ></sp-textfield>\n ${\n params.length > 0\n ? html`<sp-action-button\n quiet\n size=\"s\"\n title=\"Bind to route param\"\n @click=${() => {\n commit({ $ref: `#/$params/${params[0]}` });\n opts.rerender?.();\n }}\n ><sp-icon-link slot=\"icon\"></sp-icon-link\n ></sp-action-button>`\n : nothing\n }\n </div>`;\n}\n\n// ─── Form rendering ──────────────────────────────────────────────────────────\n\n/**\n * Render form field rows for a JSON Schema's `properties`, committing edits through `opts.onChange`\n * as single-key patches (`undefined` values mean \"unset the key\").\n *\n * @param {JsonSchema} schema\n * @param {Record<string, unknown>} value - The record being edited\n * @param {RenderFormOptions} opts\n * @returns {TemplateResult}\n */\nexport function renderForm(\n schema: JsonSchema,\n value: Record<string, unknown>,\n opts: RenderFormOptions,\n): TemplateResult {\n const required = new Set(schema.required);\n const ctx = opts.context ?? NULL_CONTEXT;\n\n const propertyFields = Object.entries(schema.properties ?? {}).map(([prop, ps]) => {\n const labelText = prop + (required.has(prop) ? \" *\" : \"\");\n return renderFieldRow({\n hasValue: false,\n label: labelText,\n prop: ps.name || prop,\n widget: renderPropertyControl(prop, ps, value, required, opts, ctx),\n });\n });\n\n return html`${propertyFields}`;\n}\n",
|
|
7
|
-
"/**\n * Context resolver — generic `#/$context/<pointer>` resolution over the project config\n * (specs/extensions.md §9.1).\n *\n * Pointers walk the project config segment by segment. `{@param}` segments substitute values from a\n * caller-provided scope (e.g. the form's current value record), and the `$formats` virtual root\n * resolves to the registered format names instead of a project.json key.\n */\n\n/** Options for {@link resolveContextPointer}. */\nexport interface ResolveContextOptions {\n /** The project configuration object the pointer walks over. */\n projectConfig: Record<string, unknown>;\n /** Scope record supplying `{@param}` substitutions (e.g. the enclosing form value). */\n scope?: Record<string, unknown> | undefined;\n /** Registered formats backing the `$formats` virtual root. */\n formats?: { name: string }[] | undefined;\n}\n\n/** Matches a `{@param}` pointer segment, capturing the param name. */\nconst PARAM_SEGMENT = /^\\{@(\\w+)\\}$/;\n\n/**\n * Resolve a `#/$context/<seg>/<seg>…` pointer.\n *\n * - `{@param}` segments substitute from `opts.scope`; an unresolvable param yields `undefined`.\n * - The `$formats` virtual root returns the format names from `opts.formats`.\n * - Every other pointer is a plain JSON-pointer walk over `opts.projectConfig` — no key is\n * special-cased, so both legacy (`contentTypes`) and newer (`content`) sections resolve alike.\n *\n * @param {string} pointer\n * @param {ResolveContextOptions} opts\n * @returns {unknown} The resolved value, or `undefined` when the pointer does not resolve.\n */\nexport function resolveContextPointer(pointer: string, opts: ResolveContextOptions): unknown {\n if (!pointer.startsWith(\"#/$context/\")) {\n return undefined;\n }\n\n const segments: string[] = [];\n for (const raw of pointer.slice(\"#/$context/\".length).split(\"/\")) {\n const match = raw.match(PARAM_SEGMENT);\n if (match) {\n const value = opts.scope?.[match[1]!];\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return undefined;\n }\n const substituted = String(value);\n if (!substituted) {\n return undefined;\n }\n segments.push(substituted);\n } else {\n segments.push(raw);\n }\n }\n\n if (segments[0] === \"$formats\") {\n if (segments.length !== 1) {\n return undefined;\n }\n return (opts.formats ?? []).map((format) => format.name);\n }\n\n let node: unknown = opts.projectConfig;\n for (const segment of segments) {\n if (node === null || typeof node !== \"object\") {\n return undefined;\n }\n node = (node as Record<string, unknown>)[segment];\n }\n return node;\n}\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "C2BB6E7E97CDF54564756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../node_modules/y-protocols/sync.js", "../../collab/src/ws-client.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * @module sync-protocol\n */\n\nimport * as encoding from 'lib0/encoding'\nimport * as decoding from 'lib0/decoding'\nimport * as Y from 'yjs'\n\n/**\n * @typedef {Map<number, number>} StateMap\n */\n\n/**\n * Core Yjs defines two message types:\n * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.\n * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it\n * received all information from the remote client.\n *\n * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection\n * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both\n * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.\n *\n * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.\n * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies\n * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the\n * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can\n * easily be implemented on top of http and websockets. 2. The server should only reply to requests, and not initiate them.\n * Therefore it is necessary that the client initiates the sync.\n *\n * Construction of a message:\n * [messageType : varUint, message definition..]\n *\n * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!\n *\n * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)\n */\n\nexport const messageYjsSyncStep1 = 0\nexport const messageYjsSyncStep2 = 1\nexport const messageYjsUpdate = 2\n\n/**\n * Create a sync step 1 message based on the state of the current shared document.\n *\n * @param {encoding.Encoder} encoder\n * @param {Y.Doc} doc\n */\nexport const writeSyncStep1 = (encoder, doc) => {\n encoding.writeVarUint(encoder, messageYjsSyncStep1)\n const sv = Y.encodeStateVector(doc)\n encoding.writeVarUint8Array(encoder, sv)\n}\n\n/**\n * @param {encoding.Encoder} encoder\n * @param {Y.Doc} doc\n * @param {Uint8Array} [encodedStateVector]\n */\nexport const writeSyncStep2 = (encoder, doc, encodedStateVector) => {\n encoding.writeVarUint(encoder, messageYjsSyncStep2)\n encoding.writeVarUint8Array(encoder, Y.encodeStateAsUpdate(doc, encodedStateVector))\n}\n\n/**\n * Read SyncStep1 message and reply with SyncStep2.\n *\n * @param {decoding.Decoder} decoder The reply to the received message\n * @param {encoding.Encoder} encoder The received message\n * @param {Y.Doc} doc\n */\nexport const readSyncStep1 = (decoder, encoder, doc) =>\n writeSyncStep2(encoder, doc, decoding.readVarUint8Array(decoder))\n\n/**\n * Read and apply Structs and then DeleteStore to a y instance.\n *\n * @param {decoding.Decoder} decoder\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler]\n */\nexport const readSyncStep2 = (decoder, doc, transactionOrigin, errorHandler) => {\n try {\n Y.applyUpdate(doc, decoding.readVarUint8Array(decoder), transactionOrigin)\n } catch (error) {\n if (errorHandler != null) errorHandler(/** @type {Error} */ (error))\n // This catches errors that are thrown by event handlers\n console.error('Caught error while handling a Yjs update', error)\n }\n}\n\n/**\n * @param {encoding.Encoder} encoder\n * @param {Uint8Array} update\n */\nexport const writeUpdate = (encoder, update) => {\n encoding.writeVarUint(encoder, messageYjsUpdate)\n encoding.writeVarUint8Array(encoder, update)\n}\n\n/**\n * Read and apply Structs and then DeleteStore to a y instance.\n *\n * @param {decoding.Decoder} decoder\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler]\n */\nexport const readUpdate = readSyncStep2\n\n/**\n * @param {decoding.Decoder} decoder A message received from another client\n * @param {encoding.Encoder} encoder The reply message. Does not need to be sent if empty.\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler] Optional error handler that catches errors when reading Yjs messages.\n */\nexport const readSyncMessage = (decoder, encoder, doc, transactionOrigin, errorHandler) => {\n const messageType = decoding.readVarUint(decoder)\n switch (messageType) {\n case messageYjsSyncStep1:\n readSyncStep1(decoder, encoder, doc)\n break\n case messageYjsSyncStep2:\n readSyncStep2(decoder, doc, transactionOrigin, errorHandler)\n break\n case messageYjsUpdate:\n readUpdate(decoder, doc, transactionOrigin, errorHandler)\n break\n default:\n throw new Error('Unknown message type')\n }\n return messageType\n}\n",
|
|
6
|
-
"/**\n * The browser half of the wire envelope: one WebSocket per project, multiplexing every open\n * document. `createWsCollabConnection` owns the socket (exponential-backoff reconnect, re-open of\n * live docs on reconnect), the shared project-level Awareness, and per-doc sync state;\n * `openDoc(path)` hands out {@link CollabHandle}s for `StudioPlatform.collab`.\n */\n\nimport * as Y from \"yjs\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport {\n applyAwarenessUpdate,\n Awareness,\n encodeAwarenessUpdate,\n removeAwarenessStates,\n} from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { decodeFrame, encodeFrame } from \"./envelope.ts\";\nimport type { CollabFrame, ControlMessage } from \"./envelope.ts\";\nimport type { CollabHandle, CollabIdentity, CollabStatus } from \"./provider.ts\";\n\n/** The subset of the WebSocket API the connection uses (injectable for tests). */\nexport interface WsLike {\n binaryType: string;\n readyState: number;\n send: (data: Uint8Array) => void;\n close: () => void;\n onopen: (() => void) | null;\n onclose: (() => void) | null;\n onerror: (() => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n}\n\nexport interface WsCollabConnectionOptions {\n /** The ws(s):// endpoint for this project's collab socket. */\n url: string;\n /** WebSocket constructor override (tests, non-browser runtimes). */\n webSocketImpl?: new (url: string) => WsLike;\n /**\n * Called when the server refuses a doc with content-not-loaded: hydrate the file over HTTP (which\n * caches it server-side) so the retry can seed. One retry per open.\n */\n hydratePath?: (path: string) => Promise<void>;\n /** Give up on an openDoc after this long (falls back to solo editing). */\n openTimeoutMs?: number;\n /** Initial reconnect backoff (doubles to 30s). */\n reconnectDelayMs?: number;\n}\n\nexport interface WsCollabConnection {\n openDoc: (path: string) => Promise<CollabHandle | null>;\n status: () => CollabStatus;\n destroy: () => void;\n}\n\nconst WS_OPEN = 1;\n\ninterface DocEntry {\n doc: Y.Doc;\n epoch: number;\n opened: boolean;\n synced: boolean;\n hydrated: boolean;\n resolveOpen: ((ok: boolean) => void) | null;\n resolveSynced: () => void;\n whenSynced: Promise<void>;\n resetCbs: Set<() => void>;\n pendingFlush: Set<() => void>;\n handleDestroyed: boolean;\n /** Latest room-level dirty state from the server (survives reconnect on the same entry). */\n dirty: boolean;\n dirtyCbs: Set<(dirty: boolean) => void>;\n}\n\nexport function createWsCollabConnection(options: WsCollabConnectionOptions): WsCollabConnection {\n const WebSocketCtor =\n options.webSocketImpl ?? (globalThis.WebSocket as unknown as new (url: string) => WsLike);\n const openTimeoutMs = options.openTimeoutMs ?? 10_000;\n const docs = new Map<string, DocEntry>();\n const statusCbs = new Set<(status: CollabStatus) => void>();\n const awarenessDoc = new Y.Doc();\n const awareness = new Awareness(awarenessDoc);\n /* Clear the constructor's implicit {} state: it sits at clock 0, which applyAwarenessUpdate on\n the receiving side can never apply (currClock 0 < clock 0 is false) — publishing it would\n poison the server's controlled-id tracking. Real state arrives via setLocalState (clock ≥ 2). */\n awareness.setLocalState(null);\n\n let socket: WsLike | null = null;\n let identity: CollabIdentity | null = null;\n let status: CollabStatus = \"connecting\";\n let destroyed = false;\n let retryMs = options.reconnectDelayMs ?? 1000;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n\n const setStatus = (next: CollabStatus) => {\n if (status === next) {\n return;\n }\n status = next;\n for (const cb of statusCbs) {\n cb(next);\n }\n };\n\n const sendFrame = (frame: CollabFrame) => {\n if (socket && socket.readyState === WS_OPEN) {\n try {\n socket.send(encodeFrame(frame));\n } catch {\n // The close handler owns recovery.\n }\n }\n };\n\n const sendOpen = (path: string) => {\n sendFrame({ message: { path, type: \"open\" }, type: \"control\" });\n };\n\n // Local awareness changes always go to the wire (queued sends drop; awareness self-heals on\n // Reconnect via the full-state re-publish below).\n awareness.on(\n \"update\",\n (changes: { added: number[]; updated: number[]; removed: number[] }, origin: unknown) => {\n if (origin === \"remote\") {\n return;\n }\n const changed = [...changes.added, ...changes.updated, ...changes.removed];\n sendFrame({ body: encodeAwarenessUpdate(awareness, changed), type: \"awareness\" });\n },\n );\n\n const handleControl = (message: ControlMessage) => {\n switch (message.type) {\n case \"hello\": {\n identity = {\n color: message.color,\n login: message.login,\n permission: message.permission,\n ...(message.name === undefined ? {} : { name: message.name }),\n ...(message.avatarUrl === undefined ? {} : { avatarUrl: message.avatarUrl }),\n };\n return;\n }\n case \"opened\": {\n const entry = docs.get(message.path);\n if (!entry) {\n return;\n }\n if (entry.opened && entry.epoch !== message.epoch) {\n // The doc's history moved while we were away: this handle is dead.\n fireReset(message.path, entry);\n return;\n }\n entry.epoch = message.epoch;\n entry.opened = true;\n entry.resolveOpen?.(true);\n entry.resolveOpen = null;\n // Client-initiated step1 (mirrors y-websocket): fetch the server's state.\n const body = encoding.createEncoder();\n syncProtocol.writeSyncStep1(body, entry.doc);\n sendFrame({\n body: encoding.toUint8Array(body),\n epoch: entry.epoch,\n path: message.path,\n type: \"doc-sync\",\n });\n return;\n }\n case \"doc-reset\": {\n const entry = docs.get(message.path);\n if (entry) {\n fireReset(message.path, entry);\n }\n return;\n }\n case \"flush-ack\": {\n const entry = docs.get(message.path);\n if (entry) {\n for (const resolve of entry.pendingFlush) {\n resolve();\n }\n entry.pendingFlush.clear();\n }\n return;\n }\n case \"doc-dirty\": {\n const entry = docs.get(message.path);\n if (entry) {\n entry.dirty = message.dirty;\n for (const cb of entry.dirtyCbs) {\n cb(message.dirty);\n }\n }\n return;\n }\n case \"error\": {\n if (!message.path) {\n return;\n }\n const entry = docs.get(message.path);\n if (!entry) {\n return;\n }\n if (message.code === \"content-not-loaded\" && options.hydratePath && !entry.hydrated) {\n entry.hydrated = true;\n void options.hydratePath(message.path).then(\n () => sendOpen(message.path!),\n () => {\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n },\n );\n return;\n }\n if (!entry.opened) {\n // Fatal refusal (binary-file, too-large, unresolved hydration): fall back to solo.\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n }\n break;\n }\n default: {\n break;\n }\n }\n };\n\n const handleDocSync = (path: string, epoch: number, body: Uint8Array) => {\n const entry = docs.get(path);\n if (!entry || !entry.opened || entry.epoch !== epoch) {\n return;\n }\n const decoder = decoding.createDecoder(body);\n const reply = encoding.createEncoder();\n const messageType = syncProtocol.readSyncMessage(decoder, reply, entry.doc, \"remote\");\n if (encoding.length(reply) > 0) {\n sendFrame({ body: encoding.toUint8Array(reply), epoch, path, type: \"doc-sync\" });\n }\n if (messageType === syncProtocol.messageYjsSyncStep2 && !entry.synced) {\n entry.synced = true;\n entry.resolveSynced();\n }\n };\n\n const fireReset = (path: string, entry: DocEntry) => {\n docs.delete(path);\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n for (const cb of entry.resetCbs) {\n cb();\n }\n entry.doc.destroy();\n };\n\n const connect = () => {\n if (destroyed) {\n return;\n }\n setStatus(\"connecting\");\n const ws = new WebSocketCtor(options.url);\n socket = ws;\n ws.binaryType = \"arraybuffer\";\n /* Each connect() builds a FRESH socket; single-assignment handlers are the point (and keep\n the injectable WsLike test surface minimal). */\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onopen = () => {\n retryMs = options.reconnectDelayMs ?? 1000;\n setStatus(\"connected\");\n // Re-open every live doc and re-publish our awareness state.\n for (const path of docs.keys()) {\n sendOpen(path);\n }\n const local = awareness.getLocalState();\n if (local !== null) {\n sendFrame({\n body: encodeAwarenessUpdate(awareness, [awareness.clientID]),\n type: \"awareness\",\n });\n }\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onmessage = (event) => {\n const raw = event.data;\n const data =\n raw instanceof ArrayBuffer ? new Uint8Array(raw) : raw instanceof Uint8Array ? raw : null;\n if (!data) {\n return;\n }\n let frame: CollabFrame;\n try {\n frame = decodeFrame(data);\n } catch {\n return;\n }\n switch (frame.type) {\n case \"control\": {\n handleControl(frame.message);\n return;\n }\n case \"doc-sync\": {\n handleDocSync(frame.path, frame.epoch, frame.body);\n return;\n }\n case \"awareness\": {\n applyAwarenessUpdate(awareness, frame.body, \"remote\");\n break;\n }\n default: {\n break;\n }\n }\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onclose = () => {\n if (destroyed) {\n return;\n }\n setStatus(\"offline\");\n for (const entry of docs.values()) {\n entry.opened = false;\n }\n retryTimer = setTimeout(connect, retryMs);\n retryMs = Math.min(retryMs * 2, 30_000);\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onerror = () => {\n // The close handler follows and owns retry.\n };\n };\n connect();\n\n return {\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n if (retryTimer) {\n clearTimeout(retryTimer);\n }\n removeAwarenessStates(awareness, [awareness.clientID], \"destroy\");\n awareness.destroy();\n awarenessDoc.destroy();\n for (const [path, entry] of docs) {\n entry.resolveOpen?.(false);\n entry.doc.destroy();\n docs.delete(path);\n }\n socket?.close();\n },\n\n async openDoc(path: string): Promise<CollabHandle | null> {\n if (destroyed) {\n return null;\n }\n const existing = docs.get(path);\n if (existing && !existing.handleDestroyed) {\n return null;\n }\n let resolveSynced: () => void = () => {};\n const whenSynced = new Promise<void>((resolve) => {\n resolveSynced = resolve;\n });\n const entry: DocEntry = {\n dirty: false,\n dirtyCbs: new Set(),\n doc: new Y.Doc(),\n epoch: 0,\n handleDestroyed: false,\n hydrated: false,\n opened: false,\n pendingFlush: new Set(),\n resetCbs: new Set(),\n resolveOpen: null,\n resolveSynced,\n synced: false,\n whenSynced,\n };\n docs.set(path, entry);\n\n // Local doc updates go to the wire (unless they came FROM the wire).\n entry.doc.on(\"update\", (update: Uint8Array, origin: unknown) => {\n if (origin === \"remote\" || !entry.opened) {\n return;\n }\n const body = encoding.createEncoder();\n syncProtocol.writeUpdate(body, update);\n sendFrame({\n body: encoding.toUint8Array(body),\n epoch: entry.epoch,\n path,\n type: \"doc-sync\",\n });\n });\n\n const openedOk = await new Promise<boolean>((resolve) => {\n entry.resolveOpen = resolve;\n const timer = setTimeout(() => {\n entry.resolveOpen = null;\n resolve(false);\n }, openTimeoutMs);\n entry.resolveOpen = (ok) => {\n clearTimeout(timer);\n resolve(ok);\n };\n sendOpen(path);\n });\n if (!openedOk) {\n if (docs.get(path) === entry) {\n docs.delete(path);\n }\n entry.doc.destroy();\n return null;\n }\n\n const handle: CollabHandle = {\n awareness,\n destroy: () => {\n if (entry.handleDestroyed) {\n return;\n }\n entry.handleDestroyed = true;\n if (docs.get(path) === entry) {\n docs.delete(path);\n sendFrame({ path, type: \"doc-close\" });\n }\n entry.doc.destroy();\n },\n doc: entry.doc,\n flush: () =>\n new Promise<void>((resolve) => {\n entry.pendingFlush.add(resolve);\n sendFrame({ message: { path, type: \"flush\" }, type: \"control\" });\n }),\n identity: () => identity,\n onDirty: (cb) => {\n entry.dirtyCbs.add(cb);\n // Deliver current state synchronously: the server's open-handshake `doc-dirty` may have\n // Already landed before the caller subscribes, and it must not miss the initial value.\n cb(entry.dirty);\n return () => entry.dirtyCbs.delete(cb);\n },\n onReset: (cb) => {\n entry.resetCbs.add(cb);\n return () => entry.resetCbs.delete(cb);\n },\n onStatus: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n whenSynced: entry.whenSynced,\n };\n return handle;\n },\n\n status: () => status,\n };\n}\n"
|
|
7
|
-
],
|
|
8
|
-
"mappings": "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",
|
|
9
|
-
"debugId": "A5C0E576FD4383EF64756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/// <reference lib="dom" />
|
|
2
|
-
/**
|
|
3
|
-
* Browse modal — fullscreen overlay for the project file browser (Manage view). Opens via toolbar
|
|
4
|
-
* button; selecting a file closes the modal and opens it in the editor.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { html } from "lit-html";
|
|
8
|
-
import { ref } from "lit-html/directives/ref.js";
|
|
9
|
-
import { renderBrowse } from "./browse";
|
|
10
|
-
import { openFileInTab } from "../files/files";
|
|
11
|
-
import { openModal } from "../ui/layers";
|
|
12
|
-
|
|
13
|
-
let _handle: ReturnType<typeof openModal> | null = null;
|
|
14
|
-
|
|
15
|
-
let _escHandler: ((e: KeyboardEvent) => void) | null = null;
|
|
16
|
-
|
|
17
|
-
export function openBrowseModal() {
|
|
18
|
-
if (_handle) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
_escHandler = (e: KeyboardEvent) => {
|
|
23
|
-
if (e.key === "Escape") {
|
|
24
|
-
closeBrowseModal();
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
document.addEventListener("keydown", _escHandler, true);
|
|
28
|
-
|
|
29
|
-
const tpl = html`
|
|
30
|
-
<sp-underlay open @close=${closeBrowseModal}></sp-underlay>
|
|
31
|
-
<div class="browse-modal">
|
|
32
|
-
<div class="browse-modal-header">
|
|
33
|
-
<h2 class="browse-modal-title">Manage Files</h2>
|
|
34
|
-
<sp-action-button quiet size="s" @click=${closeBrowseModal} title="Close">
|
|
35
|
-
<sp-icon-close slot="icon"></sp-icon-close>
|
|
36
|
-
</sp-action-button>
|
|
37
|
-
</div>
|
|
38
|
-
<div
|
|
39
|
-
class="browse-modal-content"
|
|
40
|
-
${ref((el) => {
|
|
41
|
-
if (el) {
|
|
42
|
-
requestAnimationFrame(() => {
|
|
43
|
-
void renderBrowse(el as HTMLElement, {
|
|
44
|
-
openFile: (path: string) => {
|
|
45
|
-
closeBrowseModal();
|
|
46
|
-
void openFileInTab(path);
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
})}
|
|
52
|
-
></div>
|
|
53
|
-
</div>
|
|
54
|
-
`;
|
|
55
|
-
|
|
56
|
-
_handle = openModal(tpl);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function closeBrowseModal() {
|
|
60
|
-
if (!_handle) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (_escHandler) {
|
|
64
|
-
document.removeEventListener("keydown", _escHandler, true);
|
|
65
|
-
_escHandler = null;
|
|
66
|
-
}
|
|
67
|
-
_handle.close();
|
|
68
|
-
_handle = null;
|
|
69
|
-
}
|