@agent-native/core 0.92.10 → 0.92.12
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +29 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +214 -17
- package/corpus/core/src/agent/run-manager.ts +72 -14
- package/corpus/core/src/agent/run-store.ts +152 -27
- package/corpus/core/src/cli/design-connect.ts +433 -151
- package/corpus/core/src/cli/skills.ts +14 -0
- package/corpus/core/src/client/AssistantChat.tsx +25 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
- package/corpus/core/src/client/agent-chat-adapter.ts +56 -12
- package/corpus/core/src/client/agent-chat.ts +165 -1
- package/corpus/core/src/client/chat/index.ts +9 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
- package/corpus/core/src/collab/awareness-store.ts +23 -12
- package/corpus/core/src/collab/client.ts +16 -5
- package/corpus/core/src/collab/index.ts +4 -0
- package/corpus/core/src/collab/recent-edits.ts +65 -2
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
- package/corpus/core/src/server/builder-design-systems.ts +30 -4
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/create-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
- package/corpus/templates/clips/actions/request-transcript.ts +102 -33
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +75 -9
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
- package/corpus/templates/clips/app/routes/record.tsx +17 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +12 -2
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +6 -3
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
- package/corpus/templates/clips/shared/recording-core.ts +12 -0
- package/corpus/templates/content/AGENTS.md +7 -6
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +82 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +149 -30
- package/corpus/templates/content/actions/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +4 -7
- package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
- package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/pull-document.ts +5 -7
- package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
- package/corpus/templates/content/actions/push-notion-page.ts +10 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
- package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
- package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/content/app/i18n-data.ts +18 -0
- package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
- package/corpus/templates/content/shared/api.ts +1 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
- package/corpus/templates/design/AGENTS.md +45 -10
- package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
- package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
- package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
- package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
- package/corpus/templates/design/actions/generate-design.ts +79 -12
- package/corpus/templates/design/actions/generate-screens.ts +57 -12
- package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
- package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
- package/corpus/templates/design/actions/import-design-source.ts +4 -31
- package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
- package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/design/actions/list-design-components.ts +104 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
- package/corpus/templates/design/actions/open-component-source.ts +2 -4
- package/corpus/templates/design/actions/present-design-variants.ts +412 -16
- package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
- package/corpus/templates/design/actions/run-design-audit.ts +25 -3
- package/corpus/templates/design/actions/show-design-questions.ts +10 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
- package/corpus/templates/design/actions/write-local-file.ts +25 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
- package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
- package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
- package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
- package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
- package/corpus/templates/design/app/components/design/types.ts +33 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
- package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
- package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
- package/corpus/templates/design/app/i18n-data.ts +1217 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
- package/corpus/templates/design/app/lib/design-import.ts +24 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
- package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
- package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
- package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
- package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -6
- package/corpus/templates/design/e2e/helpers.ts +27 -6
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
- package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
- package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
- package/corpus/templates/design/server/plugins/db.ts +41 -0
- package/corpus/templates/design/server/source-workspace.ts +64 -0
- package/corpus/templates/design/shared/board-file.ts +13 -2
- package/corpus/templates/design/shared/canvas-math.ts +231 -33
- package/corpus/templates/design/shared/code-layer.ts +122 -8
- package/corpus/templates/design/shared/component-library.ts +161 -0
- package/corpus/templates/design/shared/db-conflict.ts +27 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
- package/corpus/templates/design/shared/figma-url.ts +149 -0
- package/corpus/templates/design/shared/pen-path.ts +16 -7
- package/corpus/templates/design/shared/source-mode.ts +1 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
- package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
- package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
- package/dist/agent/production-agent.d.ts +82 -7
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +180 -17
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +63 -14
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +46 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +129 -22
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/design-connect.d.ts +6 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +336 -139
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +14 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +19 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +38 -18
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +48 -12
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts +60 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +122 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +36 -2
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +5 -0
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +19 -12
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +13 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +3 -1
- package/dist/collab/recent-edits.d.ts.map +1 -1
- package/dist/collab/recent-edits.js +57 -2
- package/dist/collab/recent-edits.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +87 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +15 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -4
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyVisualEdit,
|
|
3
|
+
buildCodeLayerProjection,
|
|
4
|
+
type CodeLayerNode,
|
|
5
|
+
type CodeLayerProjection,
|
|
6
|
+
} from "@shared/code-layer";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
inferAutoLayoutFromChildren,
|
|
10
|
+
type AlignableRect,
|
|
11
|
+
} from "./layout-operations";
|
|
12
|
+
|
|
13
|
+
export type EnableInlineScreenAutoLayoutResult =
|
|
14
|
+
| {
|
|
15
|
+
status: "applied" | "unchanged";
|
|
16
|
+
content: string;
|
|
17
|
+
targetNodeId: string;
|
|
18
|
+
direction: "row" | "column";
|
|
19
|
+
gap: number;
|
|
20
|
+
padding: number;
|
|
21
|
+
}
|
|
22
|
+
| {
|
|
23
|
+
status: "unsupported" | "failed";
|
|
24
|
+
content: string;
|
|
25
|
+
message?: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function nodeById(projection: CodeLayerProjection): Map<string, CodeLayerNode> {
|
|
29
|
+
return new Map(projection.nodes.map((node) => [node.id, node]));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A screen frame owns the authored document body. Fragment-only design files
|
|
34
|
+
* have no editable body in source, so a single visual root is the only safe
|
|
35
|
+
* equivalent. Multiple fragment roots would require inventing a wrapper and
|
|
36
|
+
* changing source structure, which is deliberately left to a semantic edit.
|
|
37
|
+
*/
|
|
38
|
+
export function resolveInlineScreenAutoLayoutRoot(
|
|
39
|
+
projection: CodeLayerProjection,
|
|
40
|
+
): CodeLayerNode | null {
|
|
41
|
+
const body = projection.nodes.find((node) => node.tag === "body");
|
|
42
|
+
if (body) return body;
|
|
43
|
+
|
|
44
|
+
const nodes = nodeById(projection);
|
|
45
|
+
const roots = projection.rootNodeIds
|
|
46
|
+
.map((id) => nodes.get(id))
|
|
47
|
+
.filter((node): node is CodeLayerNode =>
|
|
48
|
+
Boolean(node && node.tag !== "html" && node.tag !== "head"),
|
|
49
|
+
);
|
|
50
|
+
return roots.length === 1 ? roots[0]! : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function finiteStyleNumber(value: string | undefined, fallback = 0): number {
|
|
54
|
+
const parsed = Number.parseFloat(value ?? "");
|
|
55
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function rectForNode(
|
|
59
|
+
node: CodeLayerNode,
|
|
60
|
+
fallback: { width?: number; height?: number } = {},
|
|
61
|
+
): AlignableRect {
|
|
62
|
+
return {
|
|
63
|
+
id: node.id,
|
|
64
|
+
x: finiteStyleNumber(node.style.left),
|
|
65
|
+
y: finiteStyleNumber(node.style.top),
|
|
66
|
+
width: finiteStyleNumber(node.style.width, fallback.width ?? 0),
|
|
67
|
+
height: finiteStyleNumber(node.style.height, fallback.height ?? 0),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Deterministically enable auto layout on an inline HTML/Alpine screen root. */
|
|
72
|
+
export function enableInlineScreenAutoLayout(args: {
|
|
73
|
+
content: string;
|
|
74
|
+
width?: number;
|
|
75
|
+
height?: number;
|
|
76
|
+
}): EnableInlineScreenAutoLayoutResult {
|
|
77
|
+
const projection = buildCodeLayerProjection(args.content);
|
|
78
|
+
const target = resolveInlineScreenAutoLayoutRoot(projection);
|
|
79
|
+
if (!target) {
|
|
80
|
+
return { status: "unsupported", content: args.content };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const nodes = nodeById(projection);
|
|
84
|
+
const targetRect = rectForNode(target, {
|
|
85
|
+
width: args.width,
|
|
86
|
+
height: args.height,
|
|
87
|
+
});
|
|
88
|
+
const childRects = target.children
|
|
89
|
+
.map((childId) => nodes.get(childId))
|
|
90
|
+
.filter((node): node is CodeLayerNode => Boolean(node))
|
|
91
|
+
.map((node) => rectForNode(node));
|
|
92
|
+
const inferred = inferAutoLayoutFromChildren(targetRect, childRects);
|
|
93
|
+
const autoLayoutPatch = applyVisualEdit(args.content, {
|
|
94
|
+
kind: "autoLayout",
|
|
95
|
+
targetId: target.id,
|
|
96
|
+
enabled: true,
|
|
97
|
+
direction: inferred.direction,
|
|
98
|
+
gap: `${inferred.gap}px`,
|
|
99
|
+
});
|
|
100
|
+
if (autoLayoutPatch.result.status !== "applied") {
|
|
101
|
+
return {
|
|
102
|
+
status: "failed",
|
|
103
|
+
content: args.content,
|
|
104
|
+
message: autoLayoutPatch.result.message,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let content = autoLayoutPatch.content;
|
|
109
|
+
if (inferred.padding > 0) {
|
|
110
|
+
const paddingPatch = applyVisualEdit(content, {
|
|
111
|
+
kind: "style",
|
|
112
|
+
target: { nodeId: target.id },
|
|
113
|
+
property: "padding",
|
|
114
|
+
value: `${inferred.padding}px`,
|
|
115
|
+
});
|
|
116
|
+
if (paddingPatch.result.status === "applied") {
|
|
117
|
+
content = paddingPatch.content;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
status: content === args.content ? "unchanged" : "applied",
|
|
123
|
+
content,
|
|
124
|
+
targetNodeId: target.id,
|
|
125
|
+
...inferred,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function hasExactReactProvenance(node: CodeLayerNode): boolean {
|
|
130
|
+
const sourceFile = node.dataAttributes["data-source-file"]?.trim();
|
|
131
|
+
const line = Number(node.dataAttributes["data-source-line"]);
|
|
132
|
+
const column = Number(node.dataAttributes["data-source-column"]);
|
|
133
|
+
return Boolean(
|
|
134
|
+
sourceFile &&
|
|
135
|
+
Number.isSafeInteger(line) &&
|
|
136
|
+
line > 0 &&
|
|
137
|
+
Number.isSafeInteger(column) &&
|
|
138
|
+
column > 0,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolve the shallowest compiler-provenanced React roots beneath the live
|
|
144
|
+
* screen body. Unsourced mount nodes such as `#root` are traversed, while
|
|
145
|
+
* later body branches (for example portals) are ignored once the primary app
|
|
146
|
+
* branch yields editable roots.
|
|
147
|
+
*/
|
|
148
|
+
export function getRuntimeScreenAutoLayoutSubjectIds(
|
|
149
|
+
projection: CodeLayerProjection,
|
|
150
|
+
): string[] {
|
|
151
|
+
const nodes = nodeById(projection);
|
|
152
|
+
const collect = (nodeId: string, ancestors: Set<string>): string[] => {
|
|
153
|
+
if (ancestors.has(nodeId)) return [];
|
|
154
|
+
const node = nodes.get(nodeId);
|
|
155
|
+
if (!node) return [];
|
|
156
|
+
if (hasExactReactProvenance(node)) return [node.id];
|
|
157
|
+
const nextAncestors = new Set(ancestors);
|
|
158
|
+
nextAncestors.add(nodeId);
|
|
159
|
+
return node.children.flatMap((childId) => collect(childId, nextAncestors));
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const body = projection.nodes.find((node) => node.tag === "body");
|
|
163
|
+
const branchIds = body?.children ?? projection.rootNodeIds;
|
|
164
|
+
for (const branchId of branchIds) {
|
|
165
|
+
const subjects = collect(branchId, new Set());
|
|
166
|
+
if (subjects.length > 0) return Array.from(new Set(subjects));
|
|
167
|
+
}
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
@@ -46,6 +46,33 @@ export function getOverviewScreenRuntimeReplacementKey({
|
|
|
46
46
|
return [screenId, updatedAt ?? "", getContentSignature(content)].join(":");
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/** Keep inline overview iframe identity stable across active-screen switches
|
|
50
|
+
* and content/history updates. Inline overview screens have the bridge-backed
|
|
51
|
+
* full-document replacement channel, so content changes belong in
|
|
52
|
+
* `runtimeReplacementKey`, never in the iframe's srcdoc identity key. Other
|
|
53
|
+
* source types retain the legacy remount fallback because they may not expose
|
|
54
|
+
* an in-place document replacement bridge. */
|
|
55
|
+
export function getOverviewScreenContentKey({
|
|
56
|
+
screenId,
|
|
57
|
+
screenIsActive,
|
|
58
|
+
contentRenderRevision,
|
|
59
|
+
updatedAt,
|
|
60
|
+
content,
|
|
61
|
+
useRuntimeReplacement,
|
|
62
|
+
}: {
|
|
63
|
+
screenId: string;
|
|
64
|
+
screenIsActive: boolean;
|
|
65
|
+
contentRenderRevision: number;
|
|
66
|
+
updatedAt?: string | null;
|
|
67
|
+
content: string;
|
|
68
|
+
useRuntimeReplacement: boolean;
|
|
69
|
+
}): string {
|
|
70
|
+
if (useRuntimeReplacement) return `${screenId}:inline-overview`;
|
|
71
|
+
return screenIsActive
|
|
72
|
+
? [screenId, contentRenderRevision].join(":")
|
|
73
|
+
: [screenId, updatedAt ?? "", getContentSignature(content), 0].join(":");
|
|
74
|
+
}
|
|
75
|
+
|
|
49
76
|
export function shouldUseOverviewRuntimeReplacement({
|
|
50
77
|
sourceType,
|
|
51
78
|
externalSnapshotHtml,
|
|
@@ -84,6 +111,38 @@ export function sameStringIds(a: string[], b: string[]) {
|
|
|
84
111
|
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
85
112
|
}
|
|
86
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Undo/redo inspector-panel resync — decides whether a pending live edit
|
|
116
|
+
* being reverted/replayed (by handleUndo's pendingStyleUndo/
|
|
117
|
+
* pendingNonStyleUndo branches, or handleRedo's pendingTextRedo/
|
|
118
|
+
* pendingLiveRedo branches) targets the SAME element as the current
|
|
119
|
+
* `selectedElement`. Undo/redo aren't guaranteed to be undoing the
|
|
120
|
+
* currently-selected element (the user may have re-selected something else
|
|
121
|
+
* since the edit was made), so the panel should only be patched with the
|
|
122
|
+
* revert/redo payload when this returns true — otherwise a background
|
|
123
|
+
* undo would incorrectly clobber whatever the user has selected right now.
|
|
124
|
+
* Matches by sourceId when BOTH sides carry one (the stable, authoritative
|
|
125
|
+
* identity across re-renders) — a sourceId mismatch there means a different
|
|
126
|
+
* element even if their selectors coincidentally collide (e.g. repeated
|
|
127
|
+
* list items sharing one CSS selector). Falls back to the CSS selector only
|
|
128
|
+
* when a sourceId comparison isn't possible on at least one side.
|
|
129
|
+
*
|
|
130
|
+
* Exported for unit testing.
|
|
131
|
+
*/
|
|
132
|
+
export function pendingEditTargetsSelectedElement(args: {
|
|
133
|
+
editSourceId?: string | null;
|
|
134
|
+
editSelector: string;
|
|
135
|
+
selectedSourceId?: string | null;
|
|
136
|
+
selectedSelector?: string | null;
|
|
137
|
+
}): boolean {
|
|
138
|
+
if (args.editSourceId && args.selectedSourceId) {
|
|
139
|
+
return args.selectedSourceId === args.editSourceId;
|
|
140
|
+
}
|
|
141
|
+
return Boolean(
|
|
142
|
+
args.selectedSelector && args.selectedSelector === args.editSelector,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
87
146
|
export function isScreenRootElementInfo(info: ElementInfo | null | undefined) {
|
|
88
147
|
const tagName = info?.tagName?.toUpperCase();
|
|
89
148
|
return tagName === "BODY" || tagName === "HTML";
|
|
@@ -104,13 +163,29 @@ export function shouldIgnoreOverviewLayerCreationEcho(args: {
|
|
|
104
163
|
pendingScreenId: string | null | undefined;
|
|
105
164
|
screenId: string;
|
|
106
165
|
info?: ElementInfo | null;
|
|
166
|
+
resolvedLayerId?: string | null;
|
|
107
167
|
event: "select" | "clear";
|
|
108
168
|
}) {
|
|
109
169
|
if (!args.pendingLayerId) return false;
|
|
110
170
|
if (args.pendingScreenId && args.pendingScreenId !== args.screenId) {
|
|
111
171
|
return false;
|
|
112
172
|
}
|
|
113
|
-
|
|
173
|
+
if (args.event === "clear" || isScreenRootElementInfo(args.info)) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
// Layers-panel selection is applied optimistically in the host, then the
|
|
177
|
+
// selected selector is mirrored into the overview iframe. The bridge echoes
|
|
178
|
+
// that exact layer back as an ordinary element-select a frame later. Without
|
|
179
|
+
// recognizing the matching id here, a Cmd/Ctrl toggle or Shift range briefly
|
|
180
|
+
// renders the correct multi-selection and is then collapsed to the echoed
|
|
181
|
+
// primary layer. Only ignore the exact pending layer; a real canvas click on
|
|
182
|
+
// any other element must still replace the panel selection immediately.
|
|
183
|
+
const echoedLayerId =
|
|
184
|
+
args.info?.sourceId ?? args.info?.id ?? args.info?.pendingNodeId;
|
|
185
|
+
return (
|
|
186
|
+
args.resolvedLayerId === args.pendingLayerId ||
|
|
187
|
+
echoedLayerId === args.pendingLayerId
|
|
188
|
+
);
|
|
114
189
|
}
|
|
115
190
|
|
|
116
191
|
export function getSelectedScreenIdsForEditorState(args: {
|
|
@@ -291,6 +366,99 @@ export function shouldEscapeToOverview(args: {
|
|
|
291
366
|
);
|
|
292
367
|
}
|
|
293
368
|
|
|
369
|
+
/**
|
|
370
|
+
* A node's `parentId` in the FLAT code-layer ownership map
|
|
371
|
+
* (`codeLayerOwnerByNodeId` / `codeLayerOwnerByNodeIdRef` in DesignEditor.tsx)
|
|
372
|
+
* still points at `<html>`/`<body>` even though the VISUAL layers tree
|
|
373
|
+
* collapses those document-shell nodes away (see shared/code-layer.ts's
|
|
374
|
+
* `isCollapsibleDocumentShellNode` / `compactCodeLayerTreeNodes`) — the flat
|
|
375
|
+
* map is built straight from `projection.nodes`, which is never filtered.
|
|
376
|
+
* Mirrors `isCollapsibleDocumentShellNode`'s own check (tag is html/body AND
|
|
377
|
+
* the layer name came from the tag itself, i.e. nothing more specific named
|
|
378
|
+
* it) against the flat `CodeLayerNode`'s own fields directly, since the flat
|
|
379
|
+
* node already carries `tag`/`layerNameSource` without needing a separate
|
|
380
|
+
* lookup map.
|
|
381
|
+
*
|
|
382
|
+
* Both the Escape pop-one-level walk (`resolveEscapePopSelectionAction`) and
|
|
383
|
+
* the shared Shift+Enter / "\\" select-parent walk (`handleSelectParentLayer`
|
|
384
|
+
* in DesignEditor.tsx) must treat a parent that resolves to a document-shell
|
|
385
|
+
* node as NO parent at all — otherwise popping from a top-level layer selects
|
|
386
|
+
* the raw `<body>`/`<html>` DOM nodes instead of stopping at the screen/frame
|
|
387
|
+
* level (or fully deselecting), which produces a permanently broken 0x0
|
|
388
|
+
* inspector with no way back to a deselected state.
|
|
389
|
+
*
|
|
390
|
+
* Exported for unit testing.
|
|
391
|
+
*/
|
|
392
|
+
export function isDocumentShellCodeLayerNode(node: {
|
|
393
|
+
tag: string;
|
|
394
|
+
layerNameSource: string;
|
|
395
|
+
}): boolean {
|
|
396
|
+
return (
|
|
397
|
+
(node.tag === "html" || node.tag === "body") &&
|
|
398
|
+
node.layerNameSource === "tag"
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* True only when `parentNode` exists AND is not a document-shell node — see
|
|
404
|
+
* `isDocumentShellCodeLayerNode`. Callers walking the flat code-layer
|
|
405
|
+
* ownership map (Escape pop-one-level, Shift+Enter select-parent) must use
|
|
406
|
+
* this instead of a bare `Boolean(parentNode)` truthiness check, or a
|
|
407
|
+
* top-level layer's collapsed `<body>`/`<html>` ancestor gets treated as a
|
|
408
|
+
* selectable parent layer.
|
|
409
|
+
*
|
|
410
|
+
* Exported for unit testing.
|
|
411
|
+
*/
|
|
412
|
+
export function hasSelectableCodeLayerParent(args: {
|
|
413
|
+
parentNode: { tag: string; layerNameSource: string } | null | undefined;
|
|
414
|
+
}): boolean {
|
|
415
|
+
return (
|
|
416
|
+
args.parentNode != null && !isDocumentShellCodeLayerNode(args.parentNode)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export type EscapePopSelectionAction =
|
|
421
|
+
| { kind: "pop-to-parent-layer" }
|
|
422
|
+
| { kind: "pop-to-screen-frame" }
|
|
423
|
+
| { kind: "deselect" };
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Figma parity — Escape on a plain canvas selection pops one level at a
|
|
427
|
+
* time (child layer -> parent layer -> containing screen/frame -> fully
|
|
428
|
+
* deselected) instead of deselecting everything on the first press.
|
|
429
|
+
*
|
|
430
|
+
* - A selected layer that has a code-layer parent (`hasLayerParent`) pops to
|
|
431
|
+
* that parent, reusing the same ancestor-walk `handleSelectParentLayer`
|
|
432
|
+
* (Shift+Enter / "\\") already uses via `codeLayerOwnerByNodeIdRef`.
|
|
433
|
+
* - A selected TOP-level layer (no code-layer parent) in overview mode pops
|
|
434
|
+
* to selecting its containing screen/frame — the same selection kind
|
|
435
|
+
* (`overviewSelectedScreenIds`) clicking a frame directly in overview
|
|
436
|
+
* already produces.
|
|
437
|
+
* - Anything else — nothing selected, or a top-level layer in single-screen
|
|
438
|
+
* mode where there's no separate "frame" to pop to (the screen already
|
|
439
|
+
* fills the view, so top-level already reads as "the frame boundary") —
|
|
440
|
+
* falls straight through to a full deselect, matching the previous
|
|
441
|
+
* unconditional Escape behavior.
|
|
442
|
+
*
|
|
443
|
+
* Callers must have already handled every higher-priority Escape consumer
|
|
444
|
+
* (an in-progress marquee/drag, an active breakpoint edit target,
|
|
445
|
+
* `shouldEscapeToOverview`'s zoom-out-to-overview case) before calling this
|
|
446
|
+
* — it only decides the remaining plain-canvas-selection case.
|
|
447
|
+
*
|
|
448
|
+
* Exported for unit testing.
|
|
449
|
+
*/
|
|
450
|
+
export function resolveEscapePopSelectionAction(args: {
|
|
451
|
+
hasSelectedLayer: boolean;
|
|
452
|
+
hasLayerParent: boolean;
|
|
453
|
+
viewMode: "single" | "overview";
|
|
454
|
+
}): EscapePopSelectionAction {
|
|
455
|
+
if (args.hasSelectedLayer) {
|
|
456
|
+
if (args.hasLayerParent) return { kind: "pop-to-parent-layer" };
|
|
457
|
+
if (args.viewMode === "overview") return { kind: "pop-to-screen-frame" };
|
|
458
|
+
}
|
|
459
|
+
return { kind: "deselect" };
|
|
460
|
+
}
|
|
461
|
+
|
|
294
462
|
/**
|
|
295
463
|
* B5-1: an empty-canvas click (a marquee/hit-test that resolved to zero
|
|
296
464
|
* elements) must deselect ANY current selection kind — a selected
|
|
@@ -315,6 +483,38 @@ export function shouldClearBridgeSelectionOnEmptyMarquee(args: {
|
|
|
315
483
|
return args.resolvedCount === 0 && !args.additive;
|
|
316
484
|
}
|
|
317
485
|
|
|
486
|
+
/**
|
|
487
|
+
* PICK-RACE: MultiScreenCanvas's `onPick` prop is `(id: string) => void` — no
|
|
488
|
+
* modifier/event info — even though a shift-click there already toggled a
|
|
489
|
+
* full multi-id array internally (handleFrameClick's own `selectedIds`
|
|
490
|
+
* state) before calling `onPick` with just the resulting PRIMARY id. That
|
|
491
|
+
* full array only reaches DesignEditor a render later, via the
|
|
492
|
+
* `onScreenSelectionChange` effect (MultiScreenCanvas reports its
|
|
493
|
+
* `selectedIds` from a `useEffect` that commits after this synchronous
|
|
494
|
+
* `onPick` call already ran).
|
|
495
|
+
*
|
|
496
|
+
* Forcing `selectedLayerIdsState` down to `[pickedId]` in
|
|
497
|
+
* `handleOverviewScreenPick` is wrong for BOTH shift-click cases: adding a
|
|
498
|
+
* screen would drop every other already-selected screen, and removing one
|
|
499
|
+
* would replace the whole array with just the new primary — there is no way
|
|
500
|
+
* to reconstruct the correct multi-id array from a single id. So: while
|
|
501
|
+
* Shift is held, this returns the CURRENT selection unchanged instead of a
|
|
502
|
+
* wrong singleton, and lets `overviewSelectedScreenIds` (which the
|
|
503
|
+
* `selectedLayerIds` derivation already prefers whenever non-empty) be the
|
|
504
|
+
* sole source of truth once that effect settles. When Shift isn't held this
|
|
505
|
+
* is a plain single-screen pick, matching the previous unconditional
|
|
506
|
+
* behavior.
|
|
507
|
+
*
|
|
508
|
+
* Exported for unit testing.
|
|
509
|
+
*/
|
|
510
|
+
export function computeOverviewScreenPickSelectionIds(args: {
|
|
511
|
+
pickedId: string;
|
|
512
|
+
shiftKeyHeld: boolean;
|
|
513
|
+
currentSelectedLayerIds: string[];
|
|
514
|
+
}): string[] {
|
|
515
|
+
return args.shiftKeyHeld ? args.currentSelectedLayerIds : [args.pickedId];
|
|
516
|
+
}
|
|
517
|
+
|
|
318
518
|
/**
|
|
319
519
|
* Build the set of all node ids (both projection ids and data-agent-native-node-id
|
|
320
520
|
* attribute values) that exist in the given projection. Used by handleGroupSelection
|