@1agh/maude 0.28.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -2
- package/apps/studio/annotations-align.ts +149 -0
- package/apps/studio/annotations-bindings.ts +197 -0
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +681 -151
- package/apps/studio/annotations-groups.ts +270 -0
- package/apps/studio/annotations-layer.tsx +4537 -0
- package/apps/studio/annotations-model.ts +2077 -0
- package/apps/studio/annotations-snap.ts +125 -0
- package/{plugins/design/dev-server → apps/studio}/api.ts +616 -70
- package/{plugins/design/dev-server → apps/studio}/artboard-activity-overlay.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_motion-sample-playwright.mjs +129 -0
- package/{plugins/design/dev-server → apps/studio}/bin/_png-playwright.mjs +1 -1
- package/apps/studio/bin/annotate.mjs +732 -0
- package/apps/studio/bin/annotate.sh +17 -0
- package/{plugins/design/dev-server → apps/studio}/bin/canvas-edit.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/draw-proof.sh +37 -2
- package/{plugins/design/dev-server → apps/studio}/bin/preflight.sh +1 -1
- package/apps/studio/bin/read-annotations.mjs +573 -0
- package/apps/studio/bin/read-annotations.sh +11 -0
- package/{plugins/design/dev-server → apps/studio}/bin/runtime-health.sh +1 -1
- package/{plugins/design/dev-server → apps/studio}/bin/screenshot.sh +62 -2
- package/{plugins/design/dev-server → apps/studio}/bin/server-up.sh +9 -3
- package/apps/studio/bin/to-lottie-verify.html +68 -0
- package/apps/studio/bin/to-lottie.sh +128 -0
- package/{plugins/design/dev-server → apps/studio}/build.ts +6 -4
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +79 -10
- package/{plugins/design/dev-server → apps/studio}/canvas-comment-mount.tsx +1 -1
- package/apps/studio/canvas-create.ts +104 -0
- package/{plugins/design/dev-server → apps/studio}/canvas-cursors.ts +48 -12
- package/{plugins/design/dev-server → apps/studio}/canvas-edit.ts +257 -7
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +165 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-inline.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib-resolver.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/canvas-lib.tsx +31 -12
- package/{plugins/design/dev-server → apps/studio}/canvas-shell.tsx +360 -48
- package/apps/studio/client/app.jsx +6742 -0
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/apps/studio/client/index.html +16 -0
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +1161 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/3-shell.css +129 -0
- package/apps/studio/client/styles/4-components-maude.css +74 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/4-components.css +396 -34
- package/apps/studio/client/styles/5-maude-overrides.css +137 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles/_index.css +9 -0
- package/{plugins/design/dev-server → apps/studio}/client/styles.css +1 -1
- package/apps/studio/client/tour/overlay.jsx +279 -0
- package/apps/studio/client/tour/usage-tour.js +48 -0
- package/apps/studio/client/whats-new-seen.js +52 -0
- package/apps/studio/client/whats-new.jsx +250 -0
- package/{plugins/design/dev-server → apps/studio}/commands/annotation-strokes-command.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/commands/equal-spacing-command.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/commands/move-artboards-command.ts +2 -2
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +32 -11
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +5 -4
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +18 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +21 -21
- package/apps/studio/dist/client.bundle.js +25545 -0
- package/apps/studio/dist/comment-mount.js +2046 -0
- package/apps/studio/dist/styles.css +8018 -0
- package/apps/studio/dom-selection.ts +342 -0
- package/apps/studio/draw/animate.ts +333 -0
- package/{plugins/design/dev-server → apps/studio}/draw/brush.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/composition.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/geometry.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/index.ts +4 -1
- package/{plugins/design/dev-server → apps/studio}/draw/layout.ts +1 -1
- package/apps/studio/draw/morph.ts +204 -0
- package/{plugins/design/dev-server → apps/studio}/draw/optimize.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/palette.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/draw/primitives.ts +1 -1
- package/apps/studio/draw/serialize-animate.ts +324 -0
- package/{plugins/design/dev-server → apps/studio}/draw/serialize.ts +9 -3
- package/apps/studio/draw/test/animate.test.ts +172 -0
- package/apps/studio/draw/test/morph.test.ts +107 -0
- package/apps/studio/draw/test/serialize-animate.test.ts +142 -0
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-detector.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/equal-spacing-handles.tsx +7 -29
- package/{plugins/design/dev-server → apps/studio}/export-dialog.tsx +16 -4
- package/{plugins/design/dev-server → apps/studio}/history.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/http.ts +226 -6
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +15 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +50 -4
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +2 -8
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +23 -2
- package/{plugins/design/dev-server → apps/studio}/sync/agent.ts +231 -57
- package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +45 -0
- package/apps/studio/sync/cold-start.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/sync/connection-state.ts +58 -2
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +563 -221
- package/apps/studio/sync/journal.ts +190 -0
- package/apps/studio/sync/migrate-seed.ts +321 -0
- package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +22 -3
- package/{plugins/design/dev-server → apps/studio}/sync/status.ts +15 -4
- package/{plugins/design/dev-server → apps/studio}/test/activity.test.ts +1 -7
- package/apps/studio/test/annotate-write.test.ts +184 -0
- package/apps/studio/test/annotations-align.test.ts +88 -0
- package/apps/studio/test/annotations-bindings.test.ts +124 -0
- package/apps/studio/test/annotations-groups.test.ts +231 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-layer.test.ts +63 -0
- package/{plugins/design/dev-server → apps/studio}/test/annotations-roundtrip.test.ts +97 -0
- package/apps/studio/test/annotations-snap.test.ts +79 -0
- package/apps/studio/test/annotations-text-format.test.ts +396 -0
- package/apps/studio/test/asset-api.test.ts +149 -0
- package/apps/studio/test/canvas-create-api.test.ts +361 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-cursors.test.ts +2 -0
- package/apps/studio/test/canvas-edit.test.ts +319 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-resolver.test.ts +1 -1
- package/apps/studio/test/canvas-media-drop.test.ts +158 -0
- package/{plugins/design/dev-server → apps/studio}/test/canvas-origin-gate.test.ts +25 -1
- package/apps/studio/test/canvas-url.test.ts +99 -0
- package/{plugins/design/dev-server → apps/studio}/test/collab-bridge.test.ts +0 -2
- package/{plugins/design/dev-server → apps/studio}/test/collab-room.test.ts +2 -7
- package/{plugins/design/dev-server → apps/studio}/test/csp-canvas-shell.test.ts +5 -0
- package/apps/studio/test/csrf-write-guard.test.ts +52 -0
- package/apps/studio/test/figjam-v3-model.test.ts +342 -0
- package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +1 -0
- package/apps/studio/test/index-data-canvas-ds.test.ts +97 -0
- package/apps/studio/test/motion-sample.test.ts +35 -0
- package/{plugins/design/dev-server → apps/studio}/test/perf-harness.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/test/phase-3.6-smoke.test.ts +3 -1
- package/apps/studio/test/read-annotations.test.ts +409 -0
- package/{plugins/design/dev-server → apps/studio}/test/sanitize-annotation-svg.test.ts +108 -2
- package/{plugins/design/dev-server → apps/studio}/test/shared-doc-convergence.test.ts +1 -1
- package/apps/studio/test/shared-doc-migrate.test.ts +369 -0
- package/apps/studio/test/sync-agent.test.ts +575 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-codec.test.ts +65 -0
- package/apps/studio/test/sync-cold-start.test.ts +244 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.test.ts +68 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-hardening.test.ts +0 -8
- package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.test.ts +0 -1
- package/apps/studio/test/sync-incident-replay.test.ts +211 -0
- package/apps/studio/test/sync-journal.test.ts +176 -0
- package/{plugins/design/dev-server → apps/studio}/test/sync-runtime.test.ts +360 -5
- package/{plugins/design/dev-server → apps/studio}/test/sync-status.test.ts +66 -0
- package/apps/studio/test/tour-overlay.test.tsx +56 -0
- package/apps/studio/test/use-annotation-resize.test.ts +402 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-artboard-drag.test.ts +0 -1
- package/{plugins/design/dev-server → apps/studio}/test/use-collab.test.ts +0 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +8 -2
- package/apps/studio/test/whats-new.test.ts +101 -0
- package/apps/studio/text-imports.d.ts +9 -0
- package/{plugins/design/dev-server → apps/studio}/tool-palette.tsx +15 -70
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -2
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +5 -3
- package/apps/studio/use-annotation-resize.tsx +912 -0
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +17 -5
- package/{plugins/design/dev-server → apps/studio}/use-annotations-visibility.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-artboard-drag.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-canvas-activity.tsx +3 -3
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +21 -16
- package/{plugins/design/dev-server → apps/studio}/use-cursor-modifiers.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-keyboard-discipline.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/use-selection-set.tsx +18 -1
- package/{plugins/design/dev-server → apps/studio}/use-snap-guides.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-tool-mode.tsx +8 -2
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +1 -1
- package/apps/studio/whats-new.json +264 -0
- package/apps/studio/whats-new.schema.json +86 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design-link.test.mjs +84 -0
- package/cli/commands/design.mjs +16 -7
- package/cli/commands/design.test.mjs +40 -0
- package/cli/commands/help.mjs +8 -2
- package/cli/commands/hub.mjs +3 -3
- package/cli/commands/hub.test.mjs +1 -1
- package/cli/commands/scenario-report.mjs +2 -9
- package/cli/lib/design-link.mjs +51 -1
- package/cli/lib/flow-design-integration.test.mjs +1 -1
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/plugin-cli-reachability.test.mjs +8 -7
- package/cli/lib/preflight.mjs +1 -1
- package/package.json +15 -15
- package/plugins/design/templates/_shell.html +28 -4
- package/plugins/design/templates/brief-board.tsx.template +61 -0
- package/plugins/design/templates/canvas.tsx.template +1 -1
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +1 -1
- package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +1 -1
- package/plugins/flow/.claude-plugin/config.schema.json +16 -0
- package/plugins/design/dev-server/annotations-layer.tsx +0 -3402
- package/plugins/design/dev-server/client/app.jsx +0 -2985
- package/plugins/design/dev-server/client/index.html +0 -15
- package/plugins/design/dev-server/dist/client.bundle.js +0 -20692
- package/plugins/design/dev-server/dist/comment-mount.js +0 -1924
- package/plugins/design/dev-server/dist/styles.css +0 -2710
- package/plugins/design/dev-server/dom-selection.ts +0 -156
- package/plugins/design/dev-server/sync/migrate-seed.ts +0 -163
- package/plugins/design/dev-server/test/canvas-edit.test.ts +0 -139
- package/plugins/design/dev-server/test/shared-doc-migrate.test.ts +0 -159
- package/plugins/design/dev-server/test/sync-agent.test.ts +0 -305
- package/plugins/design/dev-server/test/use-annotation-resize.test.ts +0 -200
- package/plugins/design/dev-server/use-annotation-resize.tsx +0 -449
- /package/{plugins/design/dev-server → apps/studio}/activity.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_enumerate-artboards-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_html-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pdf-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pptx-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_pw-launch.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_screenshot-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_svg-optimize.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/_svg-playwright.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/asset-sweep.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/bootstrap-check.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/check-runtime-bundles.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/draw-build.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/handoff.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/prep.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/scenario-report.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/slug.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/smoke.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/svg-optimize.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/bin/visual-sanity.sh +0 -0
- /package/{plugins/design/dev-server → apps/studio}/boot-self-heal.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-build.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-header.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-meta.schema.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/canvas-pipeline.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/hmr.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/iframe-lazy.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/0-reset.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/1-tokens.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/2-layout.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/client/styles/5-utilities.css +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/ai-activity.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/awareness-bridge.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/git-lifecycle.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/index.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/persistence.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/protocol.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/registry.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/collab/room.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/config.schema.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/context.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/.min-sizes.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/lib0_decoding.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/lib0_encoding.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/motion.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/motion_react.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/pixi-js.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react-dom.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react-dom_client.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react_jsx-dev-runtime.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/react_jsx-runtime.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/y-protocols_awareness.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/y-protocols_sync.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/dist/runtime/yjs.js +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/brush.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/composition.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/geometry.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/gradient.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/layout.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/optimize.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/palette.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/primitives.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/draw/test/serialize.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/examples/README.md +0 -0
- /package/{plugins/design/dev-server → apps/studio}/examples/perf-100-artboards.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/_browser-bundles.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/canva-handoff-prompt.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/canva.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/html.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/index.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/pdf.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/png.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/pptx.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/scope.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/svg.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/exporters/zip.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/fs-watch.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/handoff.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/hmr-broadcast.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/locator.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/mem.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/runtime-bundle.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/server.mjs +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/echo-guard.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/fs-mirror.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/hubs-config.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/materialize.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/untrusted.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/_helpers.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/active-state.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/ai-activity.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotation-strokes-command.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotations-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/annotations-draw-modifiers.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/artboard-activity-overlay.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/binary-smoke.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/boot-self-heal.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/bundle-smoke.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-build.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-header.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-hmr-runtime.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-inline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-lib-motion.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-meta-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-pipeline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/canvas-route.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-annotations-bridge.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-awareness-bridge.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-loopback.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-protocol.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-reseed-guard.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/collab-stress.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/comment-mount.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/comments-api.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/compile-entry.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/context-resolve-tokens.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/equal-spacing-detector.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/canva.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/endpoint.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/history.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/html.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pdf.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/png.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx-deck.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pptx.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/pw-launch.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/scope.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/svg.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/exporters/zip.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-20-annotations.svg +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fixtures/phase-21-annotations.svg +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/fs-watch.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/git-lifecycle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/handoff-static-frames.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/handoff.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/history-rollback.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/hmr-broadcast.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/hmr-classify.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/input-router.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/locator.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/marquee-overlay.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/move-artboards-command.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/participants-chrome.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/paths.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle-error-mapping.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/runtime-bundle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/server-lifecycle.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/shared-doc-foundation.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/shared-doc-projection.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/snap-distance-pill.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-atomic-write.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-echo-guard.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-fs-mirror.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-meta-codec.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-untrusted.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/system-endpoint.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/tool-palette.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/undo-stack.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-agent-presence.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-annotation-selection.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-canvas-activity.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-cursor-modifiers.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-keyboard-discipline.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-selection-set.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-snap-guides.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/use-undo-stack.test.tsx +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/ws-handshake.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/tsconfig.json +0 -0
- /package/{plugins/design/dev-server → apps/studio}/ws.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file canvas-lib.tsx — dev-server-bundled canvas library
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/canvas-lib.tsx
|
|
4
4
|
* Ships with the dev-server install; resolved at canvas build time
|
|
5
5
|
* via the `@maude/canvas-lib` virtual specifier. Per DDR-025, this
|
|
6
6
|
* is the single source of truth — no project-side copy.
|
|
@@ -137,10 +137,9 @@ const ENGINE_CSS = `
|
|
|
137
137
|
/* Canvas-shell chrome — the workspace plane + dotted grid follow the Maude
|
|
138
138
|
chrome theme (--maude-chrome-*), NOT the DS palette. See canvas-shell.tsx
|
|
139
139
|
HUD_TOKENS_CSS. Artboards (.dc-artboard) keep the DS theme. */
|
|
140
|
-
background-color: var(--maude-chrome-bg-
|
|
140
|
+
background-color: var(--maude-chrome-bg-0, #f4f1ea);
|
|
141
141
|
background-image:
|
|
142
|
-
|
|
143
|
-
linear-gradient(90deg, var(--maude-chrome-border, rgba(0,0,0,0.08)) 1px, transparent 1px);
|
|
142
|
+
radial-gradient(var(--maude-chrome-dot, rgba(0,0,0,0.12)) 1.1px, transparent 1.2px);
|
|
144
143
|
background-size: 24px 24px;
|
|
145
144
|
}
|
|
146
145
|
/* DDR-046 — Snap guides. Sibling kind = confident magenta + glow + distance
|
|
@@ -199,6 +198,17 @@ const ENGINE_CSS = `
|
|
|
199
198
|
irrelevant under zoom (zoom anchors top-left of the box). will-change
|
|
200
199
|
hints to the compositor that this layer changes often. */
|
|
201
200
|
will-change: transform;
|
|
201
|
+
/* Marquee / multi-select drags over artboards must not trigger native text
|
|
202
|
+
selection (it highlighted the canvas content). Editable surfaces re-enable
|
|
203
|
+
it below. */
|
|
204
|
+
user-select: none;
|
|
205
|
+
-webkit-user-select: none;
|
|
206
|
+
}
|
|
207
|
+
.dc-world input,
|
|
208
|
+
.dc-world textarea,
|
|
209
|
+
.dc-world [contenteditable="true"] {
|
|
210
|
+
user-select: text;
|
|
211
|
+
-webkit-user-select: text;
|
|
202
212
|
}
|
|
203
213
|
.dc-section-collapsed { display: contents; }
|
|
204
214
|
|
|
@@ -1162,7 +1172,7 @@ export function useDragStateContext(): DragStateBus | null {
|
|
|
1162
1172
|
interface DesignCanvasProps {
|
|
1163
1173
|
children: ReactNode;
|
|
1164
1174
|
/** Per-overlay opt-out. `false` hides it; omit or `true` shows it. */
|
|
1165
|
-
controls?: { minimap?: boolean; toolbar?: boolean };
|
|
1175
|
+
controls?: { minimap?: boolean; toolbar?: boolean; zoom?: boolean };
|
|
1166
1176
|
}
|
|
1167
1177
|
|
|
1168
1178
|
/**
|
|
@@ -1374,6 +1384,7 @@ function DesignCanvasInner({ children, controls }: DesignCanvasProps) {
|
|
|
1374
1384
|
);
|
|
1375
1385
|
|
|
1376
1386
|
const showMiniMap = controls?.minimap !== false;
|
|
1387
|
+
const showZoom = controls?.zoom !== false;
|
|
1377
1388
|
|
|
1378
1389
|
// Drag-state bus (Phase 4.2). Single source of truth: only one artboard
|
|
1379
1390
|
// drag is active at a time. DCArtboards write here when their local drag
|
|
@@ -1445,10 +1456,12 @@ function DesignCanvasInner({ children, controls }: DesignCanvasProps) {
|
|
|
1445
1456
|
{children}
|
|
1446
1457
|
</div>
|
|
1447
1458
|
{showMiniMap ? <DCMiniMap /> : null}
|
|
1448
|
-
{/*
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1459
|
+
{/* Plan C F6 — separate bottom-left zoom pill (the design's ZoomHud).
|
|
1460
|
+
Phase 5.1 had folded zoom into the ToolPalette; user feedback wants
|
|
1461
|
+
the design's standalone pill, so DCZoomToolbar renders here again (the
|
|
1462
|
+
ToolPalette's inline zoom is removed in tool-palette.tsx). It carries
|
|
1463
|
+
MORE than the mock — fit + actual-size — so no capability is lost. */}
|
|
1464
|
+
{showZoom ? <DCZoomToolbar /> : null}
|
|
1452
1465
|
</div>
|
|
1453
1466
|
);
|
|
1454
1467
|
|
|
@@ -1900,6 +1913,9 @@ const OVERLAY_CSS = `
|
|
|
1900
1913
|
overflow: hidden;
|
|
1901
1914
|
}
|
|
1902
1915
|
.dc-mm-hd {
|
|
1916
|
+
display: flex;
|
|
1917
|
+
align-items: center;
|
|
1918
|
+
justify-content: space-between;
|
|
1903
1919
|
padding: 5px 8px 4px;
|
|
1904
1920
|
border-bottom: 1px solid var(--maude-chrome-border, rgba(0,0,0,0.08));
|
|
1905
1921
|
letter-spacing: 0.05em;
|
|
@@ -1907,6 +1923,7 @@ const OVERLAY_CSS = `
|
|
|
1907
1923
|
font-size: 9px;
|
|
1908
1924
|
background: var(--maude-chrome-bg-1, #f4f1ea);
|
|
1909
1925
|
}
|
|
1926
|
+
.dc-mm-count { font-variant-numeric: tabular-nums; color: var(--maude-chrome-fg-2, rgba(40,30,20,0.55)); }
|
|
1910
1927
|
.dc-mm-body {
|
|
1911
1928
|
position: relative;
|
|
1912
1929
|
width: 100%;
|
|
@@ -1932,9 +1949,8 @@ const OVERLAY_CSS = `
|
|
|
1932
1949
|
}
|
|
1933
1950
|
.dc-zoom-tb {
|
|
1934
1951
|
position: absolute;
|
|
1935
|
-
left:
|
|
1952
|
+
left: 16px;
|
|
1936
1953
|
bottom: 16px;
|
|
1937
|
-
transform: translateX(-50%);
|
|
1938
1954
|
display: flex;
|
|
1939
1955
|
align-items: stretch;
|
|
1940
1956
|
background: var(--maude-chrome-bg-0, #ffffff);
|
|
@@ -2105,7 +2121,10 @@ export function DCMiniMap() {
|
|
|
2105
2121
|
return (
|
|
2106
2122
|
<div className="dc-mm" aria-hidden="true">
|
|
2107
2123
|
<div className="dc-mm-hd">
|
|
2108
|
-
|
|
2124
|
+
<span>World</span>
|
|
2125
|
+
<span className="dc-mm-count">
|
|
2126
|
+
{world.artboards.length} / {world.artboards.length}
|
|
2127
|
+
</span>
|
|
2109
2128
|
</div>
|
|
2110
2129
|
<div
|
|
2111
2130
|
className="dc-mm-body"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file canvas-shell.tsx — universal input-grammar wrapper for TSX canvases
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/canvas-shell.tsx
|
|
4
4
|
* @purpose Mounted by `DesignCanvas` for every canvas. Stacks
|
|
5
5
|
* SelectionSetProvider + ContextMenuProvider, wires the input
|
|
6
6
|
* router to provider actions, and renders the floating chrome
|
|
@@ -59,12 +59,14 @@ import {
|
|
|
59
59
|
import { ContextualToolbar } from './contextual-toolbar.tsx';
|
|
60
60
|
import { CursorsOverlay } from './cursors-overlay.tsx';
|
|
61
61
|
import {
|
|
62
|
-
cssEscape,
|
|
63
62
|
cssPath,
|
|
64
63
|
deriveFile,
|
|
65
64
|
domPath,
|
|
66
65
|
hoverTargetToSelection,
|
|
67
66
|
realClasses,
|
|
67
|
+
resolveSelectionEl,
|
|
68
|
+
scopedCdSelector,
|
|
69
|
+
selectorIndex,
|
|
68
70
|
shortText,
|
|
69
71
|
} from './dom-selection.ts';
|
|
70
72
|
import { EqualSpacingHandles } from './equal-spacing-handles.tsx';
|
|
@@ -129,32 +131,46 @@ import { useUndoStack } from './use-undo-stack.tsx';
|
|
|
129
131
|
// theme (readInitialTheme() → 'dark'). DDR — mirrors the `--maude-hud-*`
|
|
130
132
|
// precedent; the `data-maude-theme` attribute is deliberately SEPARATE from the
|
|
131
133
|
// DS `data-theme` so chrome theming never touches artboard palettes.
|
|
134
|
+
// Plan B (Task 7) — the in-canvas chrome now mirrors the maude DS ladder (indigo
|
|
135
|
+
// accent hue 268, cool-neutral hue 255) so the iframe chrome reads as one product
|
|
136
|
+
// with the rewritten outer shell. Accent-fg is the maude dark navy (NOT white):
|
|
137
|
+
// maude's bright indigo accent needs a dark fg for WCAG contrast (white/indigo
|
|
138
|
+
// ≈ 3:1, fails AA; navy/indigo ≈ 6.3:1). Token-only swap — no overlay logic
|
|
139
|
+
// changes (DDR-054). Values lifted from `.design/system/maude/colors_and_type.css`.
|
|
132
140
|
const HUD_TOKENS_CSS = `
|
|
133
141
|
:root,
|
|
134
142
|
:root[data-maude-theme="dark"] {
|
|
135
|
-
--maude-hud-accent:
|
|
136
|
-
--maude-hud-accent-hover:
|
|
137
|
-
--maude-hud-accent-active:
|
|
138
|
-
--maude-hud-accent-fg:
|
|
139
|
-
--maude-hud-accent-tint: color-mix(in oklab,
|
|
140
|
-
|
|
141
|
-
--maude-chrome-bg-0: oklch(
|
|
142
|
-
--maude-chrome-bg-1: oklch(
|
|
143
|
-
--maude-chrome-bg-2: oklch(
|
|
144
|
-
--maude-chrome-fg-0: oklch(
|
|
145
|
-
--maude-chrome-fg-1: oklch(
|
|
146
|
-
--maude-chrome-border: oklch(
|
|
147
|
-
--maude-chrome-
|
|
148
|
-
--maude-chrome-
|
|
143
|
+
--maude-hud-accent: oklch(0.680 0.180 268);
|
|
144
|
+
--maude-hud-accent-hover: oklch(0.730 0.170 268);
|
|
145
|
+
--maude-hud-accent-active: oklch(0.630 0.180 268);
|
|
146
|
+
--maude-hud-accent-fg: oklch(0.180 0.030 268);
|
|
147
|
+
--maude-hud-accent-tint: color-mix(in oklab, oklch(0.680 0.180 268) 16%, transparent);
|
|
148
|
+
|
|
149
|
+
--maude-chrome-bg-0: oklch(0.165 0.012 255);
|
|
150
|
+
--maude-chrome-bg-1: oklch(0.198 0.012 255);
|
|
151
|
+
--maude-chrome-bg-2: oklch(0.232 0.013 255);
|
|
152
|
+
--maude-chrome-fg-0: oklch(0.955 0.005 250);
|
|
153
|
+
--maude-chrome-fg-1: oklch(0.790 0.008 250);
|
|
154
|
+
--maude-chrome-border: oklch(0.290 0.012 255);
|
|
155
|
+
--maude-chrome-dot: oklch(0.340 0.012 255);
|
|
156
|
+
--maude-chrome-shadow: rgba(0, 0, 0, 0.46);
|
|
157
|
+
--maude-chrome-font-mono: 'JetBrains Mono', 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
|
|
149
158
|
}
|
|
150
159
|
:root[data-maude-theme="light"] {
|
|
151
|
-
--maude-
|
|
152
|
-
--maude-
|
|
153
|
-
--maude-
|
|
154
|
-
--maude-
|
|
155
|
-
--maude-
|
|
156
|
-
|
|
157
|
-
--maude-chrome-
|
|
160
|
+
--maude-hud-accent: oklch(0.520 0.195 268);
|
|
161
|
+
--maude-hud-accent-hover: oklch(0.470 0.195 268);
|
|
162
|
+
--maude-hud-accent-active: oklch(0.430 0.190 268);
|
|
163
|
+
--maude-hud-accent-fg: oklch(0.995 0.004 268);
|
|
164
|
+
--maude-hud-accent-tint: color-mix(in oklab, oklch(0.520 0.195 268) 12%, transparent);
|
|
165
|
+
|
|
166
|
+
--maude-chrome-bg-0: oklch(0.975 0.004 255);
|
|
167
|
+
--maude-chrome-bg-1: oklch(1.000 0 0);
|
|
168
|
+
--maude-chrome-bg-2: oklch(0.987 0.003 255);
|
|
169
|
+
--maude-chrome-fg-0: oklch(0.225 0.015 260);
|
|
170
|
+
--maude-chrome-fg-1: oklch(0.400 0.014 260);
|
|
171
|
+
--maude-chrome-border: oklch(0.922 0.005 255);
|
|
172
|
+
--maude-chrome-dot: oklch(0.860 0.008 255);
|
|
173
|
+
--maude-chrome-shadow: color-mix(in oklab, oklch(0.225 0.015 260) 14%, transparent);
|
|
158
174
|
}
|
|
159
175
|
`;
|
|
160
176
|
|
|
@@ -286,6 +302,14 @@ const HALO_CSS = `
|
|
|
286
302
|
-webkit-font-smoothing: subpixel-antialiased;
|
|
287
303
|
font-smooth: always;
|
|
288
304
|
}
|
|
305
|
+
/* Phase 12 (DDR-103) — inline text editing: the element being edited carries an
|
|
306
|
+
accent ring + caret. plaintext-only contenteditable; commit writes to source. */
|
|
307
|
+
[contenteditable].dc-text-editing {
|
|
308
|
+
outline: 2px solid var(--maude-hud-accent, #0d99ff);
|
|
309
|
+
outline-offset: 1px;
|
|
310
|
+
border-radius: 1px;
|
|
311
|
+
cursor: text;
|
|
312
|
+
}
|
|
289
313
|
`.trim();
|
|
290
314
|
|
|
291
315
|
function ensureHaloStyles(): void {
|
|
@@ -306,6 +330,104 @@ function ensureHaloStyles(): void {
|
|
|
306
330
|
document.head.appendChild(s);
|
|
307
331
|
}
|
|
308
332
|
|
|
333
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
334
|
+
// Layers tree (Phase 12 Task 4, DDR-103). The shell's Layers tab is a browsable
|
|
335
|
+
// tree of the active artboard's stamped (`data-cd-id`) elements. We walk the
|
|
336
|
+
// artboard subtree in the iframe, serialize a nested tree, and post it to the
|
|
337
|
+
// shell; the shell renders it + posts back `select-by-id` / `highlight`.
|
|
338
|
+
|
|
339
|
+
interface LayerNode {
|
|
340
|
+
id: string;
|
|
341
|
+
tag: string;
|
|
342
|
+
label: string;
|
|
343
|
+
type: string;
|
|
344
|
+
/** Occurrence index of this id within the artboard — matches the resolver's
|
|
345
|
+
* `querySelectorAll([data-dc-screen=…] [data-cd-id=…])[index]`. */
|
|
346
|
+
index: number;
|
|
347
|
+
children: LayerNode[];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function kebabToTitle(s: string): string {
|
|
351
|
+
return s
|
|
352
|
+
.split('-')
|
|
353
|
+
.filter(Boolean)
|
|
354
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
355
|
+
.join(' ');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Human label: data-dc-element (Title Case) → aria-label → role → tag(.class).
|
|
359
|
+
function layerLabel(el: Element): string {
|
|
360
|
+
const dc = el.getAttribute('data-dc-element');
|
|
361
|
+
if (dc) return kebabToTitle(dc);
|
|
362
|
+
const aria = el.getAttribute('aria-label');
|
|
363
|
+
if (aria) return aria.slice(0, 40);
|
|
364
|
+
const role = el.getAttribute('role');
|
|
365
|
+
if (role) return role;
|
|
366
|
+
const tag = el.tagName.toLowerCase();
|
|
367
|
+
const cls = realClasses(el).split(/\s+/).filter(Boolean)[0];
|
|
368
|
+
return cls ? `${tag}.${cls}` : tag;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function layerType(el: Element): string {
|
|
372
|
+
const tag = el.tagName.toLowerCase();
|
|
373
|
+
const role = el.getAttribute('role') ?? '';
|
|
374
|
+
const dc = el.getAttribute('data-dc-element') ?? '';
|
|
375
|
+
if (tag === 'button' || role === 'button' || /(^|-)(btn|cta|button)(-|$)/.test(dc))
|
|
376
|
+
return 'button';
|
|
377
|
+
if (/^h[1-6]$/.test(tag) || role === 'heading') return 'heading';
|
|
378
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select') return 'input';
|
|
379
|
+
if (tag === 'img' || tag === 'svg' || tag === 'picture' || tag === 'video') return 'image';
|
|
380
|
+
if (tag === 'a') return 'link';
|
|
381
|
+
if (tag === 'ul' || tag === 'ol' || tag === 'li') return 'list';
|
|
382
|
+
if (tag === 'nav') return 'nav';
|
|
383
|
+
if (tag === 'form') return 'form';
|
|
384
|
+
if (tag === 'p' || tag === 'span' || tag === 'label') return 'text';
|
|
385
|
+
return 'box';
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function serializeArtboardTree(root: Element): LayerNode[] {
|
|
389
|
+
const seen = new Map<string, number>();
|
|
390
|
+
function walk(el: Element): LayerNode[] {
|
|
391
|
+
const out: LayerNode[] = [];
|
|
392
|
+
for (const child of Array.from(el.children)) {
|
|
393
|
+
// Skip dev-server overlay chrome (pins, halos) that lives inside the artboard.
|
|
394
|
+
if (child.closest('.dgn-pin, .dc-cv-halo, .dc-cv-group-bbox')) continue;
|
|
395
|
+
const cd = child.getAttribute('data-cd-id');
|
|
396
|
+
if (cd) {
|
|
397
|
+
const idx = seen.get(cd) ?? 0;
|
|
398
|
+
seen.set(cd, idx + 1);
|
|
399
|
+
out.push({
|
|
400
|
+
id: cd,
|
|
401
|
+
tag: child.tagName.toLowerCase(),
|
|
402
|
+
label: layerLabel(child),
|
|
403
|
+
type: layerType(child),
|
|
404
|
+
index: idx,
|
|
405
|
+
children: walk(child),
|
|
406
|
+
});
|
|
407
|
+
} else {
|
|
408
|
+
// Unstamped wrapper — descend so its stamped descendants still surface.
|
|
409
|
+
out.push(...walk(child));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return out;
|
|
413
|
+
}
|
|
414
|
+
return walk(root);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function postLayersTree(artboardId: string | null | undefined): void {
|
|
418
|
+
if (typeof document === 'undefined' || !artboardId) return;
|
|
419
|
+
const root = document.querySelector(`[data-dc-screen="${CSS.escape(artboardId)}"]`);
|
|
420
|
+
if (!root) return;
|
|
421
|
+
try {
|
|
422
|
+
window.parent.postMessage(
|
|
423
|
+
{ dgn: 'layers-tree', artboardId, tree: serializeArtboardTree(root) },
|
|
424
|
+
'*'
|
|
425
|
+
);
|
|
426
|
+
} catch {
|
|
427
|
+
/* detached / cross-origin */
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
309
431
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
310
432
|
// Shell
|
|
311
433
|
|
|
@@ -418,7 +540,7 @@ function CanvasCore({
|
|
|
418
540
|
if (!host) return;
|
|
419
541
|
const onDbl = (e: MouseEvent) => {
|
|
420
542
|
const t = e.target as Element | null;
|
|
421
|
-
if (!t
|
|
543
|
+
if (!t?.closest) return;
|
|
422
544
|
// Floating chrome / overlays / drawn user content / any artboard
|
|
423
545
|
// surface → leave alone. Only dblclick that lands on the canvas
|
|
424
546
|
// background outside every artboard triggers `fit()`.
|
|
@@ -501,7 +623,7 @@ function CanvasCore({
|
|
|
501
623
|
useEffect(() => {
|
|
502
624
|
if (!collab) return;
|
|
503
625
|
const first = selSet.selected[0];
|
|
504
|
-
if (!first
|
|
626
|
+
if (!first?.selector) {
|
|
505
627
|
collab.publishAwareness({ selection: null });
|
|
506
628
|
return;
|
|
507
629
|
}
|
|
@@ -931,7 +1053,7 @@ function applyArtboardFollowers(): void {
|
|
|
931
1053
|
function buildRegistry(deps: {
|
|
932
1054
|
controller: ViewportControllerHandle | null;
|
|
933
1055
|
clearSelection: () => void;
|
|
934
|
-
selSet: { selected: Selection[] };
|
|
1056
|
+
selSet: { selected: Selection[]; replace: (s: Selection | Selection[]) => void };
|
|
935
1057
|
distributeArtboards: (axis: 'x' | 'y') => void;
|
|
936
1058
|
alignArtboards: (mode: 'left' | 'right' | 'center-x' | 'top' | 'bottom' | 'center-y') => void;
|
|
937
1059
|
focusArtboard: (artboardId: string) => void;
|
|
@@ -956,12 +1078,16 @@ function buildRegistry(deps: {
|
|
|
956
1078
|
|
|
957
1079
|
const postComposeForTarget = (target: ContextTarget): void => {
|
|
958
1080
|
if (typeof window === 'undefined') return;
|
|
1081
|
+
const composeSelector = target.cdId
|
|
1082
|
+
? scopedCdSelector(target.cdId, target.artboardId)
|
|
1083
|
+
: cssPath(target.el);
|
|
959
1084
|
const sel: Selection | null = target.el
|
|
960
1085
|
? {
|
|
961
1086
|
file: deriveFile(),
|
|
962
1087
|
id: target.cdId ?? undefined,
|
|
963
|
-
selector:
|
|
1088
|
+
selector: composeSelector,
|
|
964
1089
|
artboardId: target.artboardId,
|
|
1090
|
+
index: target.cdId ? selectorIndex(document, composeSelector, target.el) : 0,
|
|
965
1091
|
tag: target.el.tagName.toLowerCase(),
|
|
966
1092
|
classes: realClasses(target.el),
|
|
967
1093
|
text: shortText(target.el, 240),
|
|
@@ -1089,9 +1215,24 @@ function buildRegistry(deps: {
|
|
|
1089
1215
|
id: 'inspect',
|
|
1090
1216
|
label: 'Inspect',
|
|
1091
1217
|
shortcut: '⌥I',
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1218
|
+
onSelect: (target) => {
|
|
1219
|
+
// Phase 12 — select the right-clicked element + open the shell's
|
|
1220
|
+
// right Inspector panel (Inspect / Layers / CSS). Was a disabled TODO
|
|
1221
|
+
// before the inspector shipped.
|
|
1222
|
+
if (target.el) {
|
|
1223
|
+
selSet.replace(
|
|
1224
|
+
hoverTargetToSelection({
|
|
1225
|
+
el: target.el,
|
|
1226
|
+
cdId: target.cdId ?? null,
|
|
1227
|
+
artboardId: target.artboardId ?? null,
|
|
1228
|
+
} as HoverTarget)
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
try {
|
|
1232
|
+
window.parent.postMessage({ dgn: 'open-inspector' }, '*');
|
|
1233
|
+
} catch {
|
|
1234
|
+
/* detached / cross-origin */
|
|
1235
|
+
}
|
|
1095
1236
|
},
|
|
1096
1237
|
},
|
|
1097
1238
|
],
|
|
@@ -1228,6 +1369,8 @@ function CanvasRouter({
|
|
|
1228
1369
|
const annotSel = useAnnotationSelection();
|
|
1229
1370
|
const ctxMenu = useContextMenu();
|
|
1230
1371
|
const undoStack = useUndoStack();
|
|
1372
|
+
// Shell View-menu zoom bridge (dgn:'zoom') — same controller the zoom pill uses.
|
|
1373
|
+
const zoomController = useViewportControllerContext();
|
|
1231
1374
|
|
|
1232
1375
|
// Hover state drives the floating .dc-cv-halo--hover overlay. The overlay
|
|
1233
1376
|
// itself reads getBoundingClientRect on every rAF tick to follow pan/zoom.
|
|
@@ -1283,6 +1426,96 @@ function CanvasRouter({
|
|
|
1283
1426
|
if (typeof t === 'string') setTool(t as never);
|
|
1284
1427
|
return;
|
|
1285
1428
|
}
|
|
1429
|
+
// Plan C — Edit menu (shell) bridges to the in-canvas undo stack.
|
|
1430
|
+
if (m.dgn === 'undo') {
|
|
1431
|
+
void undoStack.undo();
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (m.dgn === 'redo') {
|
|
1435
|
+
void undoStack.redo();
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
// Phase 12 Task 4 (DDR-103) — Layers-tree round-trip. select-by-id resolves
|
|
1439
|
+
// the node + replaces the selection (which posts select-set back, updating
|
|
1440
|
+
// the Inspect/CSS tabs + halos); highlight shows the transient hover halo;
|
|
1441
|
+
// request-layers re-walks + posts the tree for an artboard.
|
|
1442
|
+
if (m.dgn === 'select-by-id') {
|
|
1443
|
+
const mm = m as { id?: string; artboardId?: string | null; index?: number };
|
|
1444
|
+
if (mm.id) {
|
|
1445
|
+
const target = resolveSelectionEl(document, {
|
|
1446
|
+
id: mm.id,
|
|
1447
|
+
artboardId: mm.artboardId,
|
|
1448
|
+
index: mm.index,
|
|
1449
|
+
});
|
|
1450
|
+
if (target) {
|
|
1451
|
+
selSet.replace(
|
|
1452
|
+
hoverTargetToSelection({
|
|
1453
|
+
el: target,
|
|
1454
|
+
cdId: mm.id,
|
|
1455
|
+
artboardId: mm.artboardId ?? null,
|
|
1456
|
+
} as HoverTarget)
|
|
1457
|
+
);
|
|
1458
|
+
(target as HTMLElement).scrollIntoView?.({ block: 'nearest', behavior: 'smooth' });
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
if (m.dgn === 'highlight') {
|
|
1464
|
+
const mm = m as { id?: string; artboardId?: string | null; index?: number };
|
|
1465
|
+
setHoverEl(
|
|
1466
|
+
mm.id
|
|
1467
|
+
? resolveSelectionEl(document, {
|
|
1468
|
+
id: mm.id,
|
|
1469
|
+
artboardId: mm.artboardId,
|
|
1470
|
+
index: mm.index,
|
|
1471
|
+
})
|
|
1472
|
+
: null
|
|
1473
|
+
);
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
// Phase 12.3 (W1.1) — optimistic inline-style apply. The CSS panel posts
|
|
1477
|
+
// this on commit so the selected element updates INSTANTLY, before the
|
|
1478
|
+
// edit-css → file-watcher HMR reload re-renders from source. `value` null/
|
|
1479
|
+
// empty removes the property (the reset path). Purely a live-DOM preview;
|
|
1480
|
+
// the authoritative value is whatever the reload renders from source.
|
|
1481
|
+
// SECURITY (ethical-hacker A1/A2) — accept apply-style ONLY from the parent
|
|
1482
|
+
// shell, never from a canvas self-post. The canvas iframe is untrusted
|
|
1483
|
+
// (DDR-054); without this gate hostile canvas JS could repaint elements AND
|
|
1484
|
+
// (paired with the reload echo-guard) suppress reloads to desync view/source.
|
|
1485
|
+
// The reload-suppression timestamp now lives in _shell.html's closure (NOT a
|
|
1486
|
+
// canvas-writable window global) — set there from the same parent-gated msg.
|
|
1487
|
+
if (m.dgn === 'apply-style') {
|
|
1488
|
+
if (e.source !== window.parent) return;
|
|
1489
|
+
const mm = m as {
|
|
1490
|
+
id?: string;
|
|
1491
|
+
artboardId?: string | null;
|
|
1492
|
+
index?: number;
|
|
1493
|
+
prop?: string;
|
|
1494
|
+
value?: string | null;
|
|
1495
|
+
};
|
|
1496
|
+
if (mm.id && mm.prop) {
|
|
1497
|
+
const target = resolveSelectionEl(document, {
|
|
1498
|
+
id: mm.id,
|
|
1499
|
+
artboardId: mm.artboardId,
|
|
1500
|
+
index: mm.index,
|
|
1501
|
+
});
|
|
1502
|
+
if (target) {
|
|
1503
|
+
const style = (target as HTMLElement).style;
|
|
1504
|
+
try {
|
|
1505
|
+
// Live-DOM preview only; the reload renders the authoritative value.
|
|
1506
|
+
if (mm.value == null || mm.value === '') style.removeProperty(mm.prop);
|
|
1507
|
+
else style.setProperty(mm.prop, mm.value);
|
|
1508
|
+
} catch {
|
|
1509
|
+
/* invalid prop/value — ignore; the reload is the source of truth */
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (m.dgn === 'request-layers') {
|
|
1516
|
+
postLayersTree((m as { artboardId?: string }).artboardId ?? null);
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1286
1519
|
// D9 — canvas-shell chrome follows the Maude chrome theme. The chrome's
|
|
1287
1520
|
// `--maude-chrome-*` token family is keyed by `data-maude-theme` on the
|
|
1288
1521
|
// iframe documentElement (see HUD_TOKENS_CSS). This attribute is
|
|
@@ -1296,10 +1529,101 @@ function CanvasRouter({
|
|
|
1296
1529
|
}
|
|
1297
1530
|
return;
|
|
1298
1531
|
}
|
|
1532
|
+
// Shell View-menu zoom items — route to the live viewport controller
|
|
1533
|
+
// (the same methods the in-canvas zoom pill calls).
|
|
1534
|
+
if (m.dgn === 'zoom' && zoomController) {
|
|
1535
|
+
const op = (m as { op?: string }).op;
|
|
1536
|
+
if (op === 'in') zoomController.zoomIn();
|
|
1537
|
+
else if (op === 'out') zoomController.zoomOut();
|
|
1538
|
+
else if (op === 'fit') zoomController.fit();
|
|
1539
|
+
else if (op === 'actual') zoomController.reset();
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1299
1542
|
};
|
|
1300
1543
|
window.addEventListener('message', onMessage);
|
|
1301
1544
|
return () => window.removeEventListener('message', onMessage);
|
|
1302
|
-
}, [selSet, annotSel, setTool]);
|
|
1545
|
+
}, [selSet, annotSel, setTool, undoStack, zoomController]);
|
|
1546
|
+
|
|
1547
|
+
// Phase 12 (DDR-103) — double-click a LEAF-TEXT element (children all text
|
|
1548
|
+
// nodes) to edit its copy in place. Commit (blur / Enter) posts `dgn:edit-text`
|
|
1549
|
+
// to the shell, which calls the main-origin /_api/edit-text → editText writes
|
|
1550
|
+
// the escaped JSXText to source; the file-watcher HMR reload re-renders from
|
|
1551
|
+
// the persisted source. Esc restores the original. Mixed/expression elements
|
|
1552
|
+
// are skipped (the engine would refuse them anyway — honest no-op).
|
|
1553
|
+
useEffect(() => {
|
|
1554
|
+
if (typeof document === 'undefined') return;
|
|
1555
|
+
const host = hostRef.current;
|
|
1556
|
+
if (!host) return;
|
|
1557
|
+
let editing: HTMLElement | null = null;
|
|
1558
|
+
let original = '';
|
|
1559
|
+
const onBlur = (): void => commitEdit(true);
|
|
1560
|
+
const onKey = (e: KeyboardEvent): void => {
|
|
1561
|
+
if (e.key === 'Escape') {
|
|
1562
|
+
e.preventDefault();
|
|
1563
|
+
commitEdit(false);
|
|
1564
|
+
} else if (e.key === 'Enter' && !e.shiftKey) {
|
|
1565
|
+
e.preventDefault();
|
|
1566
|
+
(e.currentTarget as HTMLElement | null)?.blur?.();
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
function teardown(elx: HTMLElement): void {
|
|
1570
|
+
elx.removeAttribute('contenteditable');
|
|
1571
|
+
elx.classList.remove('dc-text-editing');
|
|
1572
|
+
elx.removeEventListener('blur', onBlur, true);
|
|
1573
|
+
elx.removeEventListener('keydown', onKey, true);
|
|
1574
|
+
}
|
|
1575
|
+
function commitEdit(commit: boolean): void {
|
|
1576
|
+
const elx = editing;
|
|
1577
|
+
if (!elx) return;
|
|
1578
|
+
editing = null;
|
|
1579
|
+
const text = (elx.textContent ?? '').trim();
|
|
1580
|
+
teardown(elx);
|
|
1581
|
+
if (!commit) {
|
|
1582
|
+
elx.textContent = original;
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
if (text === original.trim()) return;
|
|
1586
|
+
const cdId = elx.getAttribute('data-cd-id');
|
|
1587
|
+
if (!cdId) return;
|
|
1588
|
+
try {
|
|
1589
|
+
window.parent.postMessage({ dgn: 'edit-text', id: cdId, file: deriveFile(), text }, '*');
|
|
1590
|
+
} catch {
|
|
1591
|
+
/* detached / cross-origin */
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
const onDbl = (e: MouseEvent): void => {
|
|
1595
|
+
if (editing) return;
|
|
1596
|
+
const t = e.target as HTMLElement | null;
|
|
1597
|
+
const stamped = (t?.closest?.('[data-cd-id]') as HTMLElement | null) ?? null;
|
|
1598
|
+
if (!stamped) return;
|
|
1599
|
+
const kids = Array.from(stamped.childNodes);
|
|
1600
|
+
if (kids.length === 0 || !kids.every((n) => n.nodeType === 3)) return; // leaf-text only
|
|
1601
|
+
e.preventDefault();
|
|
1602
|
+
e.stopPropagation();
|
|
1603
|
+
editing = stamped;
|
|
1604
|
+
original = stamped.textContent ?? '';
|
|
1605
|
+
stamped.setAttribute('contenteditable', 'plaintext-only');
|
|
1606
|
+
stamped.classList.add('dc-text-editing');
|
|
1607
|
+
stamped.addEventListener('blur', onBlur, true);
|
|
1608
|
+
stamped.addEventListener('keydown', onKey, true);
|
|
1609
|
+
stamped.focus();
|
|
1610
|
+
try {
|
|
1611
|
+
const range = document.createRange();
|
|
1612
|
+
range.selectNodeContents(stamped);
|
|
1613
|
+
const sel = window.getSelection();
|
|
1614
|
+
sel?.removeAllRanges();
|
|
1615
|
+
sel?.addRange(range);
|
|
1616
|
+
} catch {
|
|
1617
|
+
/* selection API unavailable */
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
// Capture phase so we beat the fit-to-view dblclick handler.
|
|
1621
|
+
host.addEventListener('dblclick', onDbl, true);
|
|
1622
|
+
return () => {
|
|
1623
|
+
host.removeEventListener('dblclick', onDbl, true);
|
|
1624
|
+
if (editing) teardown(editing);
|
|
1625
|
+
};
|
|
1626
|
+
}, [hostRef]);
|
|
1303
1627
|
|
|
1304
1628
|
// Cleanup any pending rAF on unmount.
|
|
1305
1629
|
useEffect(
|
|
@@ -1334,6 +1658,8 @@ function CanvasRouter({
|
|
|
1334
1658
|
const sel = hoverTargetToSelection(target);
|
|
1335
1659
|
if (mode === 'replace') selSet.replace(sel);
|
|
1336
1660
|
else selSet.add(sel);
|
|
1661
|
+
// Phase 12 Task 4 — refresh the Layers tree for the selected artboard.
|
|
1662
|
+
postLayersTree(target.artboardId);
|
|
1337
1663
|
},
|
|
1338
1664
|
onContextMenu: ({ clientX, clientY }) => {
|
|
1339
1665
|
const target = resolveHoverTarget(document, clientX, clientY, { deep: true });
|
|
@@ -1725,7 +2051,7 @@ function HoverHalo({ el }: { el: Element | null }) {
|
|
|
1725
2051
|
rafRef.current = null;
|
|
1726
2052
|
const div = ref.current;
|
|
1727
2053
|
const t = targetRef.current;
|
|
1728
|
-
if (!div || !t
|
|
2054
|
+
if (!div || !t?.isConnected) {
|
|
1729
2055
|
if (div) div.style.display = 'none';
|
|
1730
2056
|
return;
|
|
1731
2057
|
}
|
|
@@ -1822,11 +2148,7 @@ function SelectionHalos() {
|
|
|
1822
2148
|
for (let i = 0; i < selected.length; i++) {
|
|
1823
2149
|
const sel = selected[i];
|
|
1824
2150
|
const child = c.children[i] as HTMLDivElement;
|
|
1825
|
-
const el = sel
|
|
1826
|
-
? document.querySelector(`[data-cd-id="${cssEscape(sel.id)}"]`)
|
|
1827
|
-
: sel
|
|
1828
|
-
? safeQuery(sel.selector)
|
|
1829
|
-
: null;
|
|
2151
|
+
const el = sel ? resolveSelectionEl(document, sel) : null;
|
|
1830
2152
|
if (!el) {
|
|
1831
2153
|
child.style.display = 'none';
|
|
1832
2154
|
continue;
|
|
@@ -1879,9 +2201,7 @@ function GroupBbox() {
|
|
|
1879
2201
|
let yMax = Number.NEGATIVE_INFINITY;
|
|
1880
2202
|
let anyHit = false;
|
|
1881
2203
|
for (const sel of selected) {
|
|
1882
|
-
const el = sel
|
|
1883
|
-
? document.querySelector(`[data-cd-id="${cssEscape(sel.id)}"]`)
|
|
1884
|
-
: safeQuery(sel.selector);
|
|
2204
|
+
const el = resolveSelectionEl(document, sel);
|
|
1885
2205
|
if (!el) continue;
|
|
1886
2206
|
// Post-Wave-2: direct artboard drag — the article updates its own
|
|
1887
2207
|
// `left/top` during drag, so the group bbox just follows via
|
|
@@ -1936,11 +2256,3 @@ function classifyContextKind(target: HoverTarget | null): ContextTargetKind {
|
|
|
1936
2256
|
if (target.artboardId) return 'artboard-chrome';
|
|
1937
2257
|
return 'world';
|
|
1938
2258
|
}
|
|
1939
|
-
|
|
1940
|
-
function safeQuery(selector: string): Element | null {
|
|
1941
|
-
try {
|
|
1942
|
-
return document.querySelector(selector);
|
|
1943
|
-
} catch {
|
|
1944
|
-
return null;
|
|
1945
|
-
}
|
|
1946
|
-
}
|