@1agh/maude 0.28.1 → 0.29.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 +2 -2
- package/{plugins/design/dev-server → apps/studio}/ai-banner.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/annotations-context-toolbar.tsx +285 -5
- package/{plugins/design/dev-server → apps/studio}/annotations-layer.tsx +1206 -119
- package/{plugins/design/dev-server → apps/studio}/api.ts +486 -32
- 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/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 +438 -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 +5 -3
- package/{plugins/design/dev-server → apps/studio}/canvas-arrowheads.ts +1 -1
- 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 +46 -12
- package/{plugins/design/dev-server → apps/studio}/canvas-icons.tsx +60 -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 +56 -41
- package/{plugins/design/dev-server → apps/studio}/client/app.jsx +1713 -530
- package/apps/studio/client/canvas-url.js +81 -0
- package/{plugins/design/dev-server → apps/studio}/client/comments-overlay.css +41 -27
- package/{plugins/design/dev-server → apps/studio}/client/index.html +2 -1
- package/apps/studio/client/styles/1-tokens-maude.css +296 -0
- package/apps/studio/client/styles/3-shell-maude.css +459 -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 +357 -34
- package/apps/studio/client/styles/5-maude-overrides.css +123 -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 +191 -0
- package/apps/studio/client/tour/usage-tour.js +35 -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 +1 -1
- 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 +1 -1
- package/{plugins/design/dev-server → apps/studio}/comments-overlay.tsx +25 -6
- package/{plugins/design/dev-server → apps/studio}/context-menu.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/contextual-toolbar.tsx +4 -7
- package/{plugins/design/dev-server → apps/studio}/cursors-overlay.tsx +1 -1
- package/apps/studio/dist/client.bundle.js +22825 -0
- package/apps/studio/dist/comment-mount.js +1960 -0
- package/apps/studio/dist/styles.css +5695 -0
- package/{plugins/design/dev-server → apps/studio}/dom-selection.ts +75 -4
- 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 +13 -1
- package/{plugins/design/dev-server → apps/studio}/http.ts +102 -1
- package/{plugins/design/dev-server → apps/studio}/input-router.tsx +8 -1
- package/{plugins/design/dev-server → apps/studio}/inspect.ts +20 -3
- package/{plugins/design/dev-server → apps/studio}/marquee-overlay.tsx +5 -2
- package/{plugins/design/dev-server → apps/studio}/participants-chrome.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/paths.ts +15 -11
- package/{plugins/design/dev-server → apps/studio}/server.ts +18 -0
- package/{plugins/design/dev-server → apps/studio}/sync/index.ts +1 -1
- 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-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/{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 +17 -1
- package/apps/studio/test/canvas-url.test.ts +99 -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/tour-overlay.test.tsx +56 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-annotation-resize.test.ts +43 -0
- package/{plugins/design/dev-server → apps/studio}/test/use-tool-mode.test.tsx +4 -1
- 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 +4 -69
- package/{plugins/design/dev-server → apps/studio}/undo-hud.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/undo-stack.ts +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-agent-presence.tsx +1 -1
- package/{plugins/design/dev-server → apps/studio}/use-annotation-resize.tsx +40 -7
- package/{plugins/design/dev-server → apps/studio}/use-annotation-selection.tsx +1 -1
- 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 +1 -1
- package/apps/studio/use-canvas-media-drop.tsx +343 -0
- package/{plugins/design/dev-server → apps/studio}/use-collab.tsx +1 -1
- 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 +9 -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 +3 -1
- package/{plugins/design/dev-server → apps/studio}/use-undo-stack.tsx +1 -1
- package/apps/studio/whats-new.json +139 -0
- package/apps/studio/whats-new.schema.json +70 -0
- package/apps/studio/whats-new.ts +87 -0
- package/cli/bin/maude.mjs +10 -0
- package/cli/commands/design.mjs +15 -7
- package/cli/commands/design.test.mjs +36 -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/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/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/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 → 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/_png-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-edit.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}/history.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/agent.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/atomic-write.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/codec.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/connection-state.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/migrate-seed.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/origins.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/projection.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/sync/status.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/activity.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-edit.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-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-room.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/csp-canvas-shell.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-migrate.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-agent.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-codec.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-connection-state.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-hardening.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-hubs-config.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-runtime.test.ts +0 -0
- /package/{plugins/design/dev-server → apps/studio}/test/sync-status.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-artboard-drag.test.ts +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-collab.test.ts +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
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// In-process (no hub process): a relay models Hocuspocus by re-broadcasting each
|
|
17
17
|
// doc update to every other peer (Yjs updates are commutative/idempotent, so a
|
|
18
18
|
// re-broadcast relay IS the hub's convergence contract). The real-hub N-peer
|
|
19
|
-
// soak lives in
|
|
19
|
+
// soak lives in apps/hub/test/stress-integration.test.mjs + the live
|
|
20
20
|
// cross-machine manual run; this suite is the deterministic property gate.
|
|
21
21
|
|
|
22
22
|
import { describe, expect, test } from 'bun:test';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// tour-overlay — Phase 3. Render contract for the hand-rolled tour engine.
|
|
2
|
+
//
|
|
3
|
+
// renderToStaticMarkup doesn't run effects, so the rect stays null on the
|
|
4
|
+
// server render → the overlay falls back to a centered card + scrim. We assert
|
|
5
|
+
// the a11y dialog contract + step/nav wiring; keyboard/focus-trap behavior is a
|
|
6
|
+
// live-only concern (verified via agent-browser).
|
|
7
|
+
|
|
8
|
+
import { describe, expect, test } from 'bun:test';
|
|
9
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
10
|
+
import { TourOverlay } from '../client/tour/overlay.jsx';
|
|
11
|
+
|
|
12
|
+
const STEP = { target: '.x', title: 'Welcome', body: 'Body copy here' };
|
|
13
|
+
|
|
14
|
+
describe('TourOverlay', () => {
|
|
15
|
+
test('renders an accessible dialog with the first step', () => {
|
|
16
|
+
const html = renderToStaticMarkup(
|
|
17
|
+
<TourOverlay open steps={[STEP]} onClose={() => {}} onComplete={() => {}} />
|
|
18
|
+
);
|
|
19
|
+
expect(html).toContain('mdcc-tour');
|
|
20
|
+
expect(html).toContain('role="dialog"');
|
|
21
|
+
expect(html).toContain('aria-modal="true"');
|
|
22
|
+
expect(html).toContain('Welcome');
|
|
23
|
+
expect(html).toContain('Body copy here');
|
|
24
|
+
expect(html).toContain('1 / 1');
|
|
25
|
+
expect(html).toContain('mdcc-tour__scrim'); // no rect on the server → scrim, not spotlight
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('single step shows Done (not Next) and no Back', () => {
|
|
29
|
+
const html = renderToStaticMarkup(
|
|
30
|
+
<TourOverlay open steps={[STEP]} onClose={() => {}} onComplete={() => {}} />
|
|
31
|
+
);
|
|
32
|
+
expect(html).toContain('Done');
|
|
33
|
+
expect(html).not.toContain('mdcc-tour__back');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('multi-step first page shows Next, the counter, and no Back yet', () => {
|
|
37
|
+
const steps = [STEP, { ...STEP, title: 'Two' }, { ...STEP, title: 'Three' }];
|
|
38
|
+
const html = renderToStaticMarkup(
|
|
39
|
+
<TourOverlay open steps={steps} onClose={() => {}} onComplete={() => {}} />
|
|
40
|
+
);
|
|
41
|
+
expect(html).toContain('1 / 3');
|
|
42
|
+
expect(html).toContain('Next');
|
|
43
|
+
expect(html).not.toContain('mdcc-tour__back'); // i === 0
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('closed or empty renders nothing', () => {
|
|
47
|
+
expect(
|
|
48
|
+
renderToStaticMarkup(
|
|
49
|
+
<TourOverlay open={false} steps={[STEP]} onClose={() => {}} onComplete={() => {}} />
|
|
50
|
+
)
|
|
51
|
+
).toBe('');
|
|
52
|
+
expect(
|
|
53
|
+
renderToStaticMarkup(<TourOverlay open steps={[]} onClose={() => {}} onComplete={() => {}} />)
|
|
54
|
+
).toBe('');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -10,6 +10,8 @@ import { describe, expect, test } from 'bun:test';
|
|
|
10
10
|
import type {
|
|
11
11
|
ArrowStroke,
|
|
12
12
|
EllipseStroke,
|
|
13
|
+
ImageStroke,
|
|
14
|
+
LinkStroke,
|
|
13
15
|
PenStroke,
|
|
14
16
|
PolygonStroke,
|
|
15
17
|
RectStroke,
|
|
@@ -123,6 +125,47 @@ describe('resizeStroke / sticky — always 1:1 square', () => {
|
|
|
123
125
|
});
|
|
124
126
|
});
|
|
125
127
|
|
|
128
|
+
describe('resizeStroke / image — Phase 23 (aspect-lock by default, Shift frees)', () => {
|
|
129
|
+
const image: ImageStroke = {
|
|
130
|
+
id: 'im1',
|
|
131
|
+
tool: 'image',
|
|
132
|
+
x: 0,
|
|
133
|
+
y: 0,
|
|
134
|
+
w: 100,
|
|
135
|
+
h: 50, // 2:1 intrinsic aspect
|
|
136
|
+
href: 'assets/abcd1234.png',
|
|
137
|
+
};
|
|
138
|
+
test('no modifiers keeps the intrinsic aspect (the inverse of shapes)', () => {
|
|
139
|
+
// se → 120,80 would be 2.4:1 free, but the lock keeps 2:1 (dominant axis).
|
|
140
|
+
expect(resizeStroke(image, 'se', 120, 80)).toEqual({ x: 0, y: 0, w: 160, h: 80 });
|
|
141
|
+
});
|
|
142
|
+
test('Shift held inverts to a free (unconstrained) resize', () => {
|
|
143
|
+
expect(resizeStroke(image, 'se', 120, 80, { shift: true, alt: false })).toEqual({
|
|
144
|
+
x: 0,
|
|
145
|
+
y: 0,
|
|
146
|
+
w: 120,
|
|
147
|
+
h: 80,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('resizeStroke / link — Phase 23 (free-resizes like a rect)', () => {
|
|
153
|
+
const link: LinkStroke = {
|
|
154
|
+
id: 'lk1',
|
|
155
|
+
tool: 'link',
|
|
156
|
+
x: 0,
|
|
157
|
+
y: 0,
|
|
158
|
+
w: 200,
|
|
159
|
+
h: 80,
|
|
160
|
+
url: 'https://example.com',
|
|
161
|
+
title: 'Example',
|
|
162
|
+
domain: 'example.com',
|
|
163
|
+
};
|
|
164
|
+
test('no modifiers free-resizes (no forced aspect)', () => {
|
|
165
|
+
expect(resizeStroke(link, 'se', 300, 120)).toEqual({ x: 0, y: 0, w: 300, h: 120 });
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
126
169
|
describe('resizeStroke / ellipse — Alt keeps the center fixed', () => {
|
|
127
170
|
const ell: EllipseStroke = {
|
|
128
171
|
id: 'e1',
|
|
@@ -12,12 +12,13 @@ import {
|
|
|
12
12
|
} from '../use-tool-mode.tsx';
|
|
13
13
|
|
|
14
14
|
describe('use-tool-mode / static', () => {
|
|
15
|
-
test('DEFAULT_TOOLS exposes V/H/C + draw set B/R/N/A/T/E (
|
|
15
|
+
test('DEFAULT_TOOLS exposes V/H/C + draw set B/I/R/N/A/T/E (single Shape tool + highlighter)', () => {
|
|
16
16
|
expect(DEFAULT_TOOLS.map((t) => t.id)).toEqual([
|
|
17
17
|
'move',
|
|
18
18
|
'hand',
|
|
19
19
|
'comment',
|
|
20
20
|
'pen',
|
|
21
|
+
'highlighter',
|
|
21
22
|
'shape',
|
|
22
23
|
'sticky',
|
|
23
24
|
'arrow',
|
|
@@ -29,6 +30,7 @@ describe('use-tool-mode / static', () => {
|
|
|
29
30
|
'H',
|
|
30
31
|
'C',
|
|
31
32
|
'B',
|
|
33
|
+
'I',
|
|
32
34
|
'R',
|
|
33
35
|
'N',
|
|
34
36
|
'A',
|
|
@@ -50,6 +52,7 @@ describe('use-tool-mode / static', () => {
|
|
|
50
52
|
'hand',
|
|
51
53
|
'comment',
|
|
52
54
|
'pen',
|
|
55
|
+
'highlighter',
|
|
53
56
|
'shape',
|
|
54
57
|
'sticky',
|
|
55
58
|
'arrow',
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { mkdtempSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { bestSeenVersion, computeUnseen, parseVer, verGt } from '../client/whats-new-seen.js';
|
|
6
|
+
import { loadWhatsNew, resolveMaudeVersion } from '../whats-new.ts';
|
|
7
|
+
|
|
8
|
+
describe('whats-new feed loader', () => {
|
|
9
|
+
test('loads the committed feed with a version + non-empty entries', () => {
|
|
10
|
+
const feed = loadWhatsNew({ fresh: true });
|
|
11
|
+
expect(typeof feed.version).toBe('string');
|
|
12
|
+
expect(Array.isArray(feed.entries)).toBe(true);
|
|
13
|
+
expect(feed.entries.length).toBeGreaterThan(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('every entry has the required shape', () => {
|
|
17
|
+
for (const e of loadWhatsNew({ fresh: true }).entries) {
|
|
18
|
+
expect(typeof e.id).toBe('string');
|
|
19
|
+
expect(e.id).toMatch(/^[a-z0-9][a-z0-9-]*$/);
|
|
20
|
+
expect(['feature', 'improvement', 'usage', 'fix']).toContain(e.kind);
|
|
21
|
+
expect(e.title.length).toBeGreaterThan(0);
|
|
22
|
+
expect(e.summary.length).toBeGreaterThan(0);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('resolveMaudeVersion reads the design plugin manifest', () => {
|
|
27
|
+
expect(resolveMaudeVersion()).toMatch(/^\d+\.\d+\.\d+/);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('a missing feed dir yields empty entries and never throws', () => {
|
|
31
|
+
const feed = loadWhatsNew({ root: join(import.meta.dir, '__does-not-exist__'), fresh: true });
|
|
32
|
+
expect(feed.entries).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Security regression (ethical-hacker creativity finding): the feed MUST
|
|
36
|
+
// resolve from the maude package root, NEVER a served project's tree. A
|
|
37
|
+
// hostile served project dropping its own whats-new.json must not inject
|
|
38
|
+
// entries into the privileged main-origin UI. Pin the boundary so a future
|
|
39
|
+
// "project-overridable feed" change can't silently erode it.
|
|
40
|
+
test('default resolution ignores a feed planted in an arbitrary (served-project) dir', () => {
|
|
41
|
+
const hostile = mkdtempSync(join(tmpdir(), 'mdcc-served-'));
|
|
42
|
+
writeFileSync(
|
|
43
|
+
join(hostile, 'whats-new.json'),
|
|
44
|
+
JSON.stringify({
|
|
45
|
+
entries: [{ id: 'evil', kind: 'feature', title: 'pwn', summary: 'x' }],
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
const feed = loadWhatsNew({ fresh: true }); // no root → package root only
|
|
49
|
+
expect(feed.entries.some((e) => e.id === 'evil')).toBe(false);
|
|
50
|
+
expect(feed.entries.length).toBeGreaterThan(0); // still reads the real package feed
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Defense-in-depth contract: a rendered learnMore is always an http(s) URL.
|
|
54
|
+
test('every committed entry learnMore is http(s) (no javascript:/data: scheme)', () => {
|
|
55
|
+
for (const e of loadWhatsNew({ fresh: true }).entries) {
|
|
56
|
+
if (e.learnMore != null) expect(e.learnMore).toMatch(/^https?:\/\//);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('seen logic (browser-safe, shared with the client)', () => {
|
|
62
|
+
test('parseVer extracts a semver triple', () => {
|
|
63
|
+
expect(parseVer('0.28.1')).toEqual([0, 28, 1]);
|
|
64
|
+
expect(parseVer('1.2.3-beta.4')).toEqual([1, 2, 3]);
|
|
65
|
+
expect(parseVer('dev')).toBeNull();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('verGt compares semver, treating unparseable seen as oldest', () => {
|
|
69
|
+
expect(verGt('0.29.0', '0.28.1')).toBe(true);
|
|
70
|
+
expect(verGt('0.28.1', '0.29.0')).toBe(false);
|
|
71
|
+
expect(verGt('1.0.0', '0.99.99')).toBe(true);
|
|
72
|
+
expect(verGt('0.28.1', '0.28.1')).toBe(false);
|
|
73
|
+
expect(verGt('0.28.1', 'dev')).toBe(true);
|
|
74
|
+
expect(verGt('dev', '0.28.1')).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('pending (null version) entries are always unseen', () => {
|
|
78
|
+
const u = computeUnseen(
|
|
79
|
+
[{ id: 'a', version: null, kind: 'feature', title: 't', summary: 's' }],
|
|
80
|
+
'9.9.9'
|
|
81
|
+
);
|
|
82
|
+
expect(u.map((e) => e.id)).toEqual(['a']);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('computeUnseen returns only entries newer than the seen version', () => {
|
|
86
|
+
const entries = [
|
|
87
|
+
{ id: 'old', version: '0.27.0', kind: 'feature', title: 't', summary: 's' },
|
|
88
|
+
{ id: 'new', version: '0.29.0', kind: 'feature', title: 't', summary: 's' },
|
|
89
|
+
];
|
|
90
|
+
expect(computeUnseen(entries, '0.28.0').map((e) => e.id)).toEqual(['new']);
|
|
91
|
+
expect(computeUnseen(entries, '0.29.0')).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('bestSeenVersion picks the highest of feed + entry versions', () => {
|
|
95
|
+
expect(bestSeenVersion([{ version: '0.29.0' }, { version: '0.27.0' }], '0.28.1')).toBe(
|
|
96
|
+
'0.29.0'
|
|
97
|
+
);
|
|
98
|
+
expect(bestSeenVersion([{ version: '0.20.0' }], '0.28.1')).toBe('0.28.1');
|
|
99
|
+
expect(bestSeenVersion([{ version: null }], '0.28.1')).toBe('0.28.1');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Ambient declarations for Bun text imports — `import x from './f.ext' with { type: 'text' }`.
|
|
2
|
+
// The dev-server runs under Bun (which honors the import attribute) and ships as
|
|
3
|
+
// a `bun --compile` binary (which inlines the text at build time). tsc only needs
|
|
4
|
+
// to know the module resolves to a string default export.
|
|
5
|
+
|
|
6
|
+
declare module '*.tsx.template' {
|
|
7
|
+
const content: string;
|
|
8
|
+
export default content;
|
|
9
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file tool-palette.tsx — Phase 5.1 centered icon toolbar
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/tool-palette.tsx
|
|
4
4
|
* @purpose Bottom-center floating chrome — navigate (V/H/C), draw
|
|
5
5
|
* (B/R/O/A/E), and zoom in one shell. Adopts the dev-server
|
|
6
6
|
* menubar's visual language (8 px radius, soft shadow, hairline
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
SHAPE_KIND_ICONS,
|
|
21
21
|
TOOL_ICONS,
|
|
22
22
|
} from './canvas-icons.tsx';
|
|
23
|
-
import { useViewportControllerContext } from './canvas-lib.tsx';
|
|
24
23
|
import { useAnnotationsVisibility } from './use-annotations-visibility.tsx';
|
|
25
24
|
import { type ShapeKind, useToolMode } from './use-tool-mode.tsx';
|
|
26
25
|
|
|
@@ -229,7 +228,7 @@ function ensurePaletteStyles(): void {
|
|
|
229
228
|
const NAV_TOOLS = ['move', 'hand', 'comment'] as const;
|
|
230
229
|
// Phase 24 — the two rect/ellipse buttons collapse into one Shape tool (with a
|
|
231
230
|
// kind popover); sticky/arrow/text/eraser keep their order.
|
|
232
|
-
const DRAW_TOOLS = ['pen', 'shape', 'sticky', 'arrow', 'text', 'eraser'] as const;
|
|
231
|
+
const DRAW_TOOLS = ['pen', 'highlighter', 'shape', 'sticky', 'arrow', 'text', 'eraser'] as const;
|
|
233
232
|
|
|
234
233
|
// Phase 24 — the Shape tool's primitive picker (popover order matches FigJam).
|
|
235
234
|
const SHAPE_KINDS: ReadonlyArray<{ kind: ShapeKind; label: string }> = [
|
|
@@ -247,25 +246,21 @@ const SHAPE_KINDS: ReadonlyArray<{ kind: ShapeKind; label: string }> = [
|
|
|
247
246
|
export function ToolPalette() {
|
|
248
247
|
ensurePaletteStyles();
|
|
249
248
|
const { tool, setTool, tools, sticky, toggleSticky, shapeKind, setShapeKind } = useToolMode();
|
|
250
|
-
const controller = useViewportControllerContext();
|
|
251
249
|
const visibilityCtx = useAnnotationsVisibility();
|
|
252
250
|
const [mounted, setMounted] = useState(false);
|
|
253
|
-
const [zoomOpen, setZoomOpen] = useState(false);
|
|
254
251
|
const [shapeOpen, setShapeOpen] = useState(false);
|
|
255
252
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
256
253
|
|
|
257
254
|
useEffect(() => setMounted(true), []);
|
|
258
255
|
useEffect(() => {
|
|
259
|
-
if (!
|
|
256
|
+
if (!shapeOpen) return;
|
|
260
257
|
const onDown = (e: PointerEvent) => {
|
|
261
258
|
if (!containerRef.current?.contains(e.target as Node)) {
|
|
262
|
-
setZoomOpen(false);
|
|
263
259
|
setShapeOpen(false);
|
|
264
260
|
}
|
|
265
261
|
};
|
|
266
262
|
const onKey = (e: KeyboardEvent) => {
|
|
267
263
|
if (e.key === 'Escape') {
|
|
268
|
-
setZoomOpen(false);
|
|
269
264
|
setShapeOpen(false);
|
|
270
265
|
}
|
|
271
266
|
};
|
|
@@ -275,7 +270,7 @@ export function ToolPalette() {
|
|
|
275
270
|
document.removeEventListener('pointerdown', onDown, true);
|
|
276
271
|
document.removeEventListener('keydown', onKey, true);
|
|
277
272
|
};
|
|
278
|
-
}, [
|
|
273
|
+
}, [shapeOpen]);
|
|
279
274
|
// Close the shape popover whenever the tool changes away from Shape.
|
|
280
275
|
useEffect(() => {
|
|
281
276
|
if (tool !== 'shape') setShapeOpen(false);
|
|
@@ -286,7 +281,6 @@ export function ToolPalette() {
|
|
|
286
281
|
const byId = new Map(tools.map((t) => [t.id, t]));
|
|
287
282
|
const navList = NAV_TOOLS.map((id) => byId.get(id)).filter(Boolean);
|
|
288
283
|
const drawList = DRAW_TOOLS.map((id) => byId.get(id)).filter(Boolean);
|
|
289
|
-
const pct = controller ? Math.round(controller.viewport.zoom * 100) : 100;
|
|
290
284
|
const annotationsHidden = visibilityCtx ? !visibilityCtx.visible : false;
|
|
291
285
|
|
|
292
286
|
const renderToolButton = (id: string, label: string, shortcut: string) => {
|
|
@@ -417,66 +411,7 @@ export function ToolPalette() {
|
|
|
417
411
|
>
|
|
418
412
|
<IconPresentation />
|
|
419
413
|
</button>
|
|
420
|
-
<button
|
|
421
|
-
type="button"
|
|
422
|
-
className="dc-tp-zoom"
|
|
423
|
-
aria-label={`Zoom ${pct}%, open zoom menu`}
|
|
424
|
-
aria-expanded={zoomOpen}
|
|
425
|
-
title={`Zoom ${pct}%`}
|
|
426
|
-
onClick={() => setZoomOpen((o) => !o)}
|
|
427
|
-
>
|
|
428
|
-
<span>{pct}%</span>
|
|
429
|
-
<IconChevronDown size={12} />
|
|
430
|
-
</button>
|
|
431
414
|
</div>
|
|
432
|
-
{zoomOpen && controller ? (
|
|
433
|
-
<div className="dc-tp-popover" role="menu" aria-label="Zoom">
|
|
434
|
-
<button
|
|
435
|
-
type="button"
|
|
436
|
-
role="menuitem"
|
|
437
|
-
onClick={() => {
|
|
438
|
-
controller.zoomIn();
|
|
439
|
-
setZoomOpen(false);
|
|
440
|
-
}}
|
|
441
|
-
>
|
|
442
|
-
<span>Zoom In</span>
|
|
443
|
-
<span className="dc-tp-kbd">⌘ +</span>
|
|
444
|
-
</button>
|
|
445
|
-
<button
|
|
446
|
-
type="button"
|
|
447
|
-
role="menuitem"
|
|
448
|
-
onClick={() => {
|
|
449
|
-
controller.zoomOut();
|
|
450
|
-
setZoomOpen(false);
|
|
451
|
-
}}
|
|
452
|
-
>
|
|
453
|
-
<span>Zoom Out</span>
|
|
454
|
-
<span className="dc-tp-kbd">⌘ −</span>
|
|
455
|
-
</button>
|
|
456
|
-
<button
|
|
457
|
-
type="button"
|
|
458
|
-
role="menuitem"
|
|
459
|
-
onClick={() => {
|
|
460
|
-
controller.fit();
|
|
461
|
-
setZoomOpen(false);
|
|
462
|
-
}}
|
|
463
|
-
>
|
|
464
|
-
<span>Fit to Screen</span>
|
|
465
|
-
<span className="dc-tp-kbd">⌘ 0</span>
|
|
466
|
-
</button>
|
|
467
|
-
<button
|
|
468
|
-
type="button"
|
|
469
|
-
role="menuitem"
|
|
470
|
-
onClick={() => {
|
|
471
|
-
controller.reset();
|
|
472
|
-
setZoomOpen(false);
|
|
473
|
-
}}
|
|
474
|
-
>
|
|
475
|
-
<span>Actual Size 100%</span>
|
|
476
|
-
<span className="dc-tp-kbd">⌘ 1</span>
|
|
477
|
-
</button>
|
|
478
|
-
</div>
|
|
479
|
-
) : null}
|
|
480
415
|
</div>
|
|
481
416
|
);
|
|
482
417
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file undo-hud.tsx — top-right toast announcing the last undo edit
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/undo-hud.tsx
|
|
4
4
|
* @purpose Subscribes to `useUndoStack().lastLabel` + `.lastTick` and
|
|
5
5
|
* surfaces a 1.2 s aria-live toast so the user (and a screen
|
|
6
6
|
* reader) knows which edit just got pushed / undone / redone.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file undo-stack.ts — per-canvas in-memory command stack
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/undo-stack.ts
|
|
4
4
|
* @purpose Pure state + reducer for canvas Cmd+Z / Cmd+Shift+Z. No React,
|
|
5
5
|
* no DOM, no fetch — `EditCommand.do()` / `.undo()` are caller-
|
|
6
6
|
* supplied side-effects so this file stays trivially testable
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-agent-presence.tsx — Phase 13.2 / DDR-078 agent presence.
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-agent-presence.tsx
|
|
4
4
|
* @purpose Turn the Phase 8 `ai-activity` heartbeat into a *presence* peer:
|
|
5
5
|
* when an agent (`/design:edit` / `/design:new`) is editing THIS
|
|
6
6
|
* canvas, surface it like another connected human — an avatar in the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-annotation-resize.tsx — Task 23 (Wave 2, G4)
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-annotation-resize.tsx
|
|
4
4
|
* @purpose Screen-space corner / endpoint handles for the selected
|
|
5
5
|
* annotation. Per-tool resize math with FigJam resize modifiers:
|
|
6
6
|
* Shift = lock aspect ratio (45° angle snap for arrows), Alt =
|
|
@@ -22,6 +22,8 @@ import { type ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
|
22
22
|
import {
|
|
23
23
|
type ArrowStroke,
|
|
24
24
|
type EllipseStroke,
|
|
25
|
+
type ImageStroke,
|
|
26
|
+
type LinkStroke,
|
|
25
27
|
type PenStroke,
|
|
26
28
|
type PolygonStroke,
|
|
27
29
|
type RectStroke,
|
|
@@ -72,14 +74,24 @@ type Corner = 'nw' | 'ne' | 'sw' | 'se' | 'ep1' | 'ep2';
|
|
|
72
74
|
/** Stroke types that expose resize handles. Text inherits its anchor bbox. */
|
|
73
75
|
function isResizable(
|
|
74
76
|
s: Stroke
|
|
75
|
-
): s is
|
|
77
|
+
): s is
|
|
78
|
+
| RectStroke
|
|
79
|
+
| EllipseStroke
|
|
80
|
+
| PolygonStroke
|
|
81
|
+
| ArrowStroke
|
|
82
|
+
| PenStroke
|
|
83
|
+
| StickyStroke
|
|
84
|
+
| ImageStroke
|
|
85
|
+
| LinkStroke {
|
|
76
86
|
return (
|
|
77
87
|
s.tool === 'rect' ||
|
|
78
88
|
s.tool === 'ellipse' ||
|
|
79
89
|
s.tool === 'polygon' ||
|
|
80
90
|
s.tool === 'arrow' ||
|
|
81
91
|
s.tool === 'pen' ||
|
|
82
|
-
s.tool === 'sticky'
|
|
92
|
+
s.tool === 'sticky' ||
|
|
93
|
+
s.tool === 'image' ||
|
|
94
|
+
s.tool === 'link'
|
|
83
95
|
);
|
|
84
96
|
}
|
|
85
97
|
|
|
@@ -170,9 +182,15 @@ export function resizeStroke(
|
|
|
170
182
|
wy: number,
|
|
171
183
|
mods: ResizeMods = NO_MODS
|
|
172
184
|
): Partial<Stroke> | null {
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
185
|
+
if (
|
|
186
|
+
start.tool === 'rect' ||
|
|
187
|
+
start.tool === 'sticky' ||
|
|
188
|
+
start.tool === 'polygon' ||
|
|
189
|
+
start.tool === 'link'
|
|
190
|
+
) {
|
|
191
|
+
// Rect / polygon / sticky / link all resize via their shared x / y / w / h
|
|
192
|
+
// bbox. Text re-wraps inside the foreignObject automatically. Sticky stays
|
|
193
|
+
// 1:1; the link card free-resizes (Shift still locks its current ratio).
|
|
176
194
|
const box = bboxResize(
|
|
177
195
|
{ x: start.x, y: start.y, w: start.w, h: start.h },
|
|
178
196
|
corner,
|
|
@@ -181,7 +199,22 @@ export function resizeStroke(
|
|
|
181
199
|
mods,
|
|
182
200
|
start.tool === 'sticky'
|
|
183
201
|
);
|
|
184
|
-
return box as Partial<RectStroke | StickyStroke | PolygonStroke>;
|
|
202
|
+
return box as Partial<RectStroke | StickyStroke | PolygonStroke | LinkStroke>;
|
|
203
|
+
}
|
|
204
|
+
if (start.tool === 'image') {
|
|
205
|
+
// Phase 23 — images aspect-LOCK by default and free-resize with Shift held
|
|
206
|
+
// (the inverse of the shape tools — Figma/FigJam image behaviour). Invert
|
|
207
|
+
// the Shift flag into bboxResize, which keeps the START ratio when shift is
|
|
208
|
+
// set; the start ratio IS the image's intrinsic aspect.
|
|
209
|
+
const box = bboxResize(
|
|
210
|
+
{ x: start.x, y: start.y, w: start.w, h: start.h },
|
|
211
|
+
corner,
|
|
212
|
+
wx,
|
|
213
|
+
wy,
|
|
214
|
+
{ shift: !mods.shift, alt: mods.alt },
|
|
215
|
+
false
|
|
216
|
+
);
|
|
217
|
+
return box as Partial<ImageStroke>;
|
|
185
218
|
}
|
|
186
219
|
if (start.tool === 'ellipse') {
|
|
187
220
|
// Treat the four corners as the bbox of the ellipse, then derive cx/cy/rx/ry.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-annotation-selection.tsx — Phase 5.1 annotation selection store
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-annotation-selection.tsx
|
|
4
4
|
* @purpose Parallel to `use-selection-set`, but holds annotation stroke IDs
|
|
5
5
|
* instead of DOM-element selections. Annotation IDs are local
|
|
6
6
|
* identifiers (`s_*`) generated by `rid()` — they never live in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-annotations-visibility.tsx — Phase 5.1 visibility store
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-annotations-visibility.tsx
|
|
4
4
|
* @purpose Tiny boolean store shared by AnnotationsLayer (render gate),
|
|
5
5
|
* ToolPalette (presentation toggle button), and the menubar
|
|
6
6
|
* bridge (`view-annotations` postMessage handler in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-artboard-drag.tsx — Phase 4.2 artboard drag controller
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-artboard-drag.tsx
|
|
4
4
|
* @purpose Owns the pointerdown → pointermove → pointerup state machine
|
|
5
5
|
* for dragging artboards on the infinite canvas. The pure
|
|
6
6
|
* `dragReducer` + `commitFromState` are unit-testable without a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file use-canvas-activity.tsx — Phase 13 / DDR-029 activity context.
|
|
3
|
-
* @scope
|
|
3
|
+
* @scope apps/studio/use-canvas-activity.tsx
|
|
4
4
|
* @purpose Iframe-runtime React context fed by the server's `activity` WS
|
|
5
5
|
* messages. `DCArtboard` reads it to render the "agent works here"
|
|
6
6
|
* overlay on the artboards being edited right now.
|