@agent-native/core 0.149.1 → 0.149.3
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/templates/analytics/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/analytics/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/analytics/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/analytics/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/analytics/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/analytics/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +2 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/analytics/AGENTS.md +25 -32
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +150 -46
- package/corpus/templates/analytics/app/global.css +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +37 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
- package/corpus/templates/analytics/changelog/2026-08-10-dashboard-tables-can-be-copied-and-sorted-by-multiple-column.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/assets/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/assets/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/assets/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/assets/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/assets/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/assets/AGENTS.md +6 -9
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/assets/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/brain/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/brain/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/brain/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/brain/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/brain/AGENTS.md +5 -12
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/brain/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/calendar/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/calendar/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/calendar/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/calendar/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/calendar/AGENTS.md +8 -9
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/chat/AGENTS.md +32 -80
- package/corpus/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/clips/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/clips/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/clips/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/clips/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/clips/AGENTS.md +25 -31
- package/corpus/templates/clips/changelog/2026-08-10-clips-desktop-sign-in-now-starts-with-magic-links-and-google.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.css +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +274 -137
- package/corpus/templates/clips/desktop/src/styles.css +35 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/content/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/content/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/content/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/content/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/content/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/content/AGENTS.md +5 -9
- package/corpus/templates/content/app/global.css +1 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/crm/AGENTS.md +7 -11
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/crm/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/crm/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/design/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/design/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/design/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/design/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +70 -3
- package/corpus/templates/design/AGENTS.md +13 -21
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +12 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +19 -2
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +115 -7
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +82 -7
- package/corpus/templates/design/app/components/design/design-trace.ts +120 -0
- package/corpus/templates/design/app/components/design/dnd-debug.ts +2 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +40 -26
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -1
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +12 -3
- package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +4 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +7 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +1 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -5
- package/corpus/templates/design/app/pages/DesignSystems.tsx +3 -2
- package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +100 -13
- package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/data-operations.ts +14 -0
- package/corpus/templates/design/changelog/2026-08-10-marquee-selecting-layers-far-down-a-tall-screen-now-selects-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-10-the-frame-tool-draws-a-plain-frame-by-default-with-screen-av.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +27 -32
- package/corpus/templates/design/playwright.config.ts +3 -5
- package/corpus/templates/design/shared/breakpoint-media.ts +9 -2
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/dispatch/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/dispatch/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/dispatch/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/dispatch/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/dispatch/AGENTS.md +9 -16
- package/corpus/templates/dispatch/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/factory/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/factory/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/factory/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/factory/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/factory/AGENTS.md +10 -24
- package/corpus/templates/factory/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/forms/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/forms/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/forms/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/forms/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/forms/AGENTS.md +11 -17
- package/corpus/templates/forms/app/global.css +1 -0
- package/corpus/templates/forms/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/macros/AGENTS.md +8 -8
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/mail/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/mail/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/mail/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/mail/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/mail/AGENTS.md +5 -6
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/plan/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/plan/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/plan/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/plan/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/plan/AGENTS.md +5 -14
- package/corpus/templates/plan/app/global.css +1 -0
- package/corpus/templates/plan/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-11-plan-no-longer-reloads-when-runtime-state-changes.md +6 -0
- package/corpus/templates/plan/server/ui-plan-html.ts +4 -1
- package/corpus/templates/plan/vite.config.ts +5 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/slides/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/slides/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/slides/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -2
- package/corpus/templates/slides/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/slides/.agents/skills/creative-context/SKILL.md +6 -3
- package/corpus/templates/slides/.agents/skills/deck-management/SKILL.md +6 -1
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +3 -2
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +3 -0
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +3 -3
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/slides/AGENTS.md +33 -35
- package/corpus/templates/slides/actions/add-deck.ts +2 -0
- package/corpus/templates/slides/actions/add-slide.ts +15 -1
- package/corpus/templates/slides/actions/create-deck.ts +18 -6
- package/corpus/templates/slides/actions/get-deck-reference-context.ts +2 -2
- package/corpus/templates/slides/actions/get-deck.ts +83 -7
- package/corpus/templates/slides/actions/import-file.ts +2 -1
- package/corpus/templates/slides/actions/patch-deck.ts +165 -9
- package/corpus/templates/slides/actions/save-deck.ts +24 -1
- package/corpus/templates/slides/actions/update-slide.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +2 -2
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -23
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +2 -2
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +6 -6
- package/corpus/templates/slides/app/components/editor/AnimationsPanel.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +4 -4
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +432 -668
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +296 -259
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +13 -1
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +56 -174
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +241 -116
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +42 -14
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +6 -12
- package/corpus/templates/slides/app/components/editor/editor-command-model.ts +35 -0
- package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +34 -35
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +8 -10
- package/corpus/templates/slides/app/components/layout/layout-route-policy.ts +2 -5
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +45 -40
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +63 -16
- package/corpus/templates/slides/app/context/DeckContext.tsx +2 -1
- package/corpus/templates/slides/app/global.css +76 -1
- package/corpus/templates/slides/app/hooks/use-generating-slide-preview.ts +25 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +2 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +52 -23
- package/corpus/templates/slides/app/lib/recent-references.ts +23 -1
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +104 -3
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -33
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +2 -2
- package/corpus/templates/slides/app/pages/Index.tsx +315 -151
- package/corpus/templates/slides/app/root.tsx +43 -0
- package/corpus/templates/slides/changelog/2026-08-10-ai-editing-avatar-badge.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-generated-decks-keep-a-clear-human-readable-title.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-new-deck-creation-now-shows-progress-opens-the-editor-direct.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-presentation-reveals-now-follow-valid-targets.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-editing-controls-are-consolidated-into-one-focused-me.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-now-verify-and-restyle-every-imported-slide-in-one-pa.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-only-suggests-a-google-connection-for-relevant-reques.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-the-google-slides-import-option-is-now-labeled-slides.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-faster-slides-chat-deck-reads.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-chat-can-read-one-slide-without-loading-the-full-deck.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-clearly-indicate-when-an-ai-agent-is-editing-alongsid.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/slides/server/lib/validate-slide-animations.ts +163 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +8 -5
- package/corpus/templates/slides/shared/api.ts +47 -15
- package/corpus/templates/slides/shared/deck-title.ts +135 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/tasks/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/tasks/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/tasks/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/tasks/.agents/skills/efficient-fable/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/efficient-frontier/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/tasks/.agents/skills/plan-arbiter/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/plow-ahead/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/quick-recap/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/read-the-damn-docs/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/stay-within-limits/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/tasks/AGENTS.md +5 -20
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +4 -1
- package/dist/agent/engine/ai-sdk-engine.js +1 -1
- package/dist/agent/production-agent.d.ts +21 -1
- package/dist/agent/production-agent.js +505 -355
- package/dist/agent/run-manager.js +156 -14
- package/dist/agent/run-store.d.ts +11 -10
- package/dist/agent/run-store.js +17 -13
- package/dist/agent/tool-approval-store.d.ts +18 -0
- package/dist/agent/tool-approval-store.js +122 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/cli/code-agent-executor.js +11 -2
- package/dist/client/AgentPanel.js +31 -6
- package/dist/client/AssistantChat.d.ts +9 -4
- package/dist/client/AssistantChat.js +221 -149
- package/dist/client/active-run-state.d.ts +9 -1
- package/dist/client/active-run-state.js +34 -3
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat-adapter.d.ts +8 -0
- package/dist/client/agent-chat-adapter.js +125 -28
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/chat/markdown-renderer.js +14 -2
- package/dist/client/chat/message-components.d.ts +13 -3
- package/dist/client/chat/message-components.js +57 -52
- package/dist/client/chat/run-recovery.d.ts +1 -0
- package/dist/client/chat/run-recovery.js +8 -0
- package/dist/client/chat/tool-call-display.d.ts +5 -5
- package/dist/client/chat/tool-call-display.js +9 -212
- package/dist/client/chat-first/apps-rail.js +3 -3
- package/dist/client/chat-first/browser-pane.js +4 -1
- package/dist/client/chat-first/chat-history.d.ts +3 -1
- package/dist/client/chat-first/chat-history.js +7 -4
- package/dist/client/chat-first/surface-tabs.d.ts +1 -1
- package/dist/client/chat-first/surface-tabs.js +52 -41
- package/dist/client/chat-first/types.d.ts +3 -0
- package/dist/client/chat-first.d.ts +10 -0
- package/dist/client/chat-first.js +37 -2
- package/dist/client/components/ui/message-scroller.js +4 -1
- package/dist/client/i18n.js +3 -1
- package/dist/client/resources/McpConnectionSuggestion.js +9 -1
- package/dist/client/sse-event-processor.d.ts +4 -2
- package/dist/client/sse-event-processor.js +46 -6
- package/dist/client/use-chat-models.js +156 -80
- package/dist/client/use-run-stuck-detection.d.ts +2 -0
- package/dist/client/use-run-stuck-detection.js +85 -9
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/adapters/slack.d.ts +0 -4
- package/dist/integrations/adapters/slack.js +6 -30
- package/dist/integrations/catalog.js +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +0 -8
- package/dist/integrations/pending-tasks-store.js +0 -21
- package/dist/integrations/slack-manifest.d.ts +2 -2
- package/dist/integrations/slack-manifest.js +0 -3
- package/dist/integrations/webhook-handler.js +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/scripts/docs/source-search.js +2 -2
- package/dist/server/agent-chat/framework-prompts.js +7 -2
- package/dist/server/agent-chat/prompt-resources.js +2 -2
- package/dist/server/agent-chat/skill-frontmatter.d.ts +31 -2
- package/dist/server/agent-chat/skill-frontmatter.js +41 -15
- package/dist/server/agent-chat-plugin.js +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agents-bundle.d.ts +16 -19
- package/dist/server/agents-bundle.js +19 -35
- package/dist/server/auth.js +262 -31
- package/dist/server/better-auth-instance.d.ts +1 -0
- package/dist/server/better-auth-instance.js +17 -2
- package/dist/server/onboarding-html.js +56 -9
- package/dist/server/prompts/framework-core-compact.d.ts +6 -1
- package/dist/server/prompts/framework-core-compact.js +12 -9
- package/dist/server/prompts/framework-core.d.ts +6 -1
- package/dist/server/prompts/framework-core.js +11 -9
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/shared-rules.d.ts +15 -11
- package/dist/server/prompts/shared-rules.js +17 -13
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/reasoning-effort.d.ts +8 -8
- package/dist/shared/reasoning-effort.js +10 -10
- package/dist/shared/streaming-text-smoothing.js +41 -11
- package/dist/styles/agent-native.css +19 -32
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/chat/AGENTS.md +32 -80
- package/dist/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/default/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/default/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/default/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/headless/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/headless/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/agent-page/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +21 -29
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -17
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +3 -3
- package/dist/templates/workspace-core/AGENTS.md +7 -16
- package/docs/content/messaging.mdx +6 -7
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/chat/AGENTS.md +32 -80
- package/src/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/default/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/default/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/default/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/headless/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/headless/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/headless/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/agent-page/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +21 -29
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -17
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +3 -3
- package/src/templates/workspace-core/AGENTS.md +7 -16
|
@@ -6,9 +6,7 @@ exports through actions against the shared SQL state.
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
Real depth lives in `.agents/skills/`; read the relevant skill before deeper
|
|
11
|
-
work in that area.
|
|
9
|
+
Read the relevant skill before deeper work in that area.
|
|
12
10
|
|
|
13
11
|
- `design-generation` — 5-phase generation flow, aesthetic quality bar, code
|
|
14
12
|
layers/code workspace, editor extensions, breakpoints/screen
|
|
@@ -23,19 +21,11 @@ work in that area.
|
|
|
23
21
|
- `design-review-feedback` — persisted, element-anchored review comments to a
|
|
24
22
|
verified close, one root thread at a time.
|
|
25
23
|
- `export-handoff` — HTML/PNG/SVG/ZIP/code and coding-handoff export.
|
|
26
|
-
- `visual-edit` — editing a real local app visually (localhost bridge, Code
|
|
27
|
-
tab, reprompt write boundary).
|
|
28
24
|
- `full-app-build` — design source modes and flag-gated fusion-backed full app
|
|
29
25
|
building.
|
|
30
26
|
- `shader-fills` — code-backed GLSL shader fills/effects.
|
|
31
|
-
- `
|
|
32
|
-
|
|
33
|
-
`security`, `self-modifying-code` for framework patterns.
|
|
34
|
-
|
|
35
|
-
Before building common workspace or agent UI, read `agent-native-toolkit` to
|
|
36
|
-
inventory existing public kits and installed package seams. Use
|
|
37
|
-
`customizing-agent-native` for the configure → compose → eject → propose seam
|
|
38
|
-
ladder.
|
|
27
|
+
- `capture-learnings` — record a user preference or correction so it outlives
|
|
28
|
+
the thread.
|
|
39
29
|
|
|
40
30
|
## Actions
|
|
41
31
|
|
|
@@ -58,10 +48,9 @@ ladder.
|
|
|
58
48
|
- Use the app actions for designs, files, versions, design systems, variants,
|
|
59
49
|
export, and sharing. Do not write design rows directly with SQL.
|
|
60
50
|
- A message beginning with `[Reprompt selection]` is preview-only: the only
|
|
61
|
-
mutation path is `propose-node-rewrite`; never call a content writer.
|
|
62
|
-
`
|
|
63
|
-
|
|
64
|
-
content-writing actions.
|
|
51
|
+
mutation path is `propose-node-rewrite`; never call a content writer.
|
|
52
|
+
`[Selection question]` is read-only: answer about the captured element and
|
|
53
|
+
subtree without calling content-writing actions.
|
|
65
54
|
- Call `view-screen` before editing a specific design if the current design or
|
|
66
55
|
selected file is not already clear from context.
|
|
67
56
|
- Generated files must be complete, standalone HTML (Alpine.js + Tailwind CDN)
|
|
@@ -75,8 +64,6 @@ ladder.
|
|
|
75
64
|
promise lossless Figma import/export.
|
|
76
65
|
- Persist useful work early: create/update the design and files as soon as a
|
|
77
66
|
coherent candidate exists, then iterate.
|
|
78
|
-
- In dev, call actions with `pnpm action <name>`; in production, call the
|
|
79
|
-
native tool.
|
|
80
67
|
- For shared prototype feedback, use the persisted review actions — read
|
|
81
68
|
`design-review-feedback` for the loop.
|
|
82
69
|
- Follow linked design-system tokens and `customInstructions` whenever
|
|
@@ -105,5 +92,10 @@ ladder.
|
|
|
105
92
|
see `design-generation`.
|
|
106
93
|
- `design-reprompt-pending:<designId>:<fileId>` /
|
|
107
94
|
`design-reprompt-proposal:<designId>:<fileId>:<repromptId>` — the
|
|
108
|
-
compare-and-set reprompt request/proposal pair
|
|
109
|
-
|
|
95
|
+
compare-and-set reprompt request/proposal pair. Both must be present and
|
|
96
|
+
matched before `propose-node-rewrite`; a stale pair is never applied.
|
|
97
|
+
|
|
98
|
+
## Source Changes
|
|
99
|
+
|
|
100
|
+
Before building common workspace or agent UI, read `agent-native-toolkit`; read
|
|
101
|
+
`customizing-agent-native` before adapting shared UI.
|
|
@@ -4444,6 +4444,18 @@ export function DesignCanvas({
|
|
|
4444
4444
|
readOnly,
|
|
4445
4445
|
})}
|
|
4446
4446
|
data-design-preview-iframe
|
|
4447
|
+
onLoad={(event) => {
|
|
4448
|
+
// The bridge logs into the IFRAME console and cannot read
|
|
4449
|
+
// import.meta.env, so dev has to switch it on from out here.
|
|
4450
|
+
if (!import.meta.env?.DEV) return;
|
|
4451
|
+
try {
|
|
4452
|
+
const win = event.currentTarget.contentWindow as
|
|
4453
|
+
| (Window & { __DND_DEBUG?: boolean })
|
|
4454
|
+
| null;
|
|
4455
|
+
if (win) win.__DND_DEBUG = true;
|
|
4456
|
+
// coercion-ok: a cross-origin preview exposes no contentWindow
|
|
4457
|
+
} catch {}
|
|
4458
|
+
}}
|
|
4447
4459
|
{...{
|
|
4448
4460
|
[SESSION_REPLAY_IFRAME_ATTRIBUTE]: !externalPreviewUrl
|
|
4449
4461
|
? ""
|
|
@@ -1782,6 +1782,9 @@ const LayerRow = memo(function LayerRow({
|
|
|
1782
1782
|
// doing so.
|
|
1783
1783
|
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
|
|
1784
1784
|
if (event.key === "Enter" || event.key === " " || event.key === "Space") {
|
|
1785
|
+
// Figma drills into the selection on Enter and walks up on Shift+Enter;
|
|
1786
|
+
// re-selecting an already-selected row here would swallow both.
|
|
1787
|
+
if (event.key === "Enter" && isSelected) return;
|
|
1785
1788
|
event.preventDefault();
|
|
1786
1789
|
if (!selectable) return;
|
|
1787
1790
|
onSelect(node.id, {
|
|
@@ -1797,12 +1800,21 @@ const LayerRow = memo(function LayerRow({
|
|
|
1797
1800
|
onStartRename(node);
|
|
1798
1801
|
return;
|
|
1799
1802
|
}
|
|
1800
|
-
|
|
1803
|
+
// Only the PLAIN chord toggles the chevron: Shift+Arrow is Figma's big
|
|
1804
|
+
// nudge and every modified arrow belongs to the canvas hotkeys below.
|
|
1805
|
+
const plainArrow =
|
|
1806
|
+
!event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
|
|
1807
|
+
if (
|
|
1808
|
+
plainArrow &&
|
|
1809
|
+
event.key === "ArrowRight" &&
|
|
1810
|
+
hasChildren &&
|
|
1811
|
+
!isExpanded
|
|
1812
|
+
) {
|
|
1801
1813
|
event.preventDefault();
|
|
1802
1814
|
onToggleExpanded(node.id, true);
|
|
1803
1815
|
return;
|
|
1804
1816
|
}
|
|
1805
|
-
if (event.key === "ArrowLeft" && hasChildren && isExpanded) {
|
|
1817
|
+
if (plainArrow && event.key === "ArrowLeft" && hasChildren && isExpanded) {
|
|
1806
1818
|
event.preventDefault();
|
|
1807
1819
|
onToggleExpanded(node.id, false);
|
|
1808
1820
|
return;
|
|
@@ -2077,17 +2089,22 @@ const LayerRow = memo(function LayerRow({
|
|
|
2077
2089
|
>
|
|
2078
2090
|
{activeDrop === "before" ? (
|
|
2079
2091
|
<span
|
|
2092
|
+
data-layer-drop-indicator="before"
|
|
2080
2093
|
className="pointer-events-none absolute right-2 top-0 z-10 h-px bg-[var(--design-editor-accent-color)]"
|
|
2081
2094
|
style={{ left: rowIndent(depth) }}
|
|
2082
2095
|
/>
|
|
2083
2096
|
) : null}
|
|
2084
2097
|
{activeDrop === "after" ? (
|
|
2085
2098
|
<span
|
|
2099
|
+
data-layer-drop-indicator="after"
|
|
2086
2100
|
className="pointer-events-none absolute bottom-0 right-2 z-10 h-px bg-[var(--design-editor-accent-color)]"
|
|
2087
2101
|
style={{ left: rowIndent(depth) }}
|
|
2088
2102
|
/>
|
|
2089
2103
|
) : null}
|
|
2090
2104
|
<div
|
|
2105
|
+
data-layer-drop-indicator={
|
|
2106
|
+
activeDrop === "inside" ? "inside" : undefined
|
|
2107
|
+
}
|
|
2091
2108
|
className={cn(
|
|
2092
2109
|
"group flex h-7 w-max min-w-full items-center gap-1 rounded-[5px] pr-1 text-[12px] bg-[var(--design-editor-panel-bg)]",
|
|
2093
2110
|
activeDrop === "inside" &&
|
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
IconHandClick,
|
|
52
52
|
IconPlus,
|
|
53
53
|
} from "@tabler/icons-react";
|
|
54
|
+
import { useTheme } from "next-themes";
|
|
54
55
|
import {
|
|
55
56
|
memo,
|
|
56
57
|
useRef,
|
|
@@ -89,6 +90,7 @@ import {
|
|
|
89
90
|
} from "./design-canvas/content-size-report";
|
|
90
91
|
import { appendHitTestResponder } from "./design-canvas/hit-test";
|
|
91
92
|
import { withLocalRuntimes } from "./design-canvas/local-runtime";
|
|
93
|
+
import { roundGeo, trace } from "./design-trace";
|
|
92
94
|
import { DesignCanvas } from "./DesignCanvas";
|
|
93
95
|
import { dndHostLog } from "./dnd-debug";
|
|
94
96
|
import {
|
|
@@ -473,6 +475,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
473
475
|
onPrimitiveCreated,
|
|
474
476
|
onPrimitiveReparent,
|
|
475
477
|
onCreateScreenFrame,
|
|
478
|
+
frameToolDraws = "frame",
|
|
476
479
|
onDeleteSelection,
|
|
477
480
|
onNudgeSelection,
|
|
478
481
|
onZoomChange,
|
|
@@ -522,6 +525,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
522
525
|
onDropFiles,
|
|
523
526
|
cameraCommand,
|
|
524
527
|
}: MultiScreenCanvasProps) {
|
|
528
|
+
const { resolvedTheme } = useTheme();
|
|
525
529
|
const t = useT();
|
|
526
530
|
const surfaceRef = useRef<HTMLDivElement>(null);
|
|
527
531
|
const [pan, setPan] = useState({ x: 0, y: 0 });
|
|
@@ -641,6 +645,17 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
641
645
|
height: surfaceSize.height / scale,
|
|
642
646
|
};
|
|
643
647
|
}, [canvasZoom, pan.x, pan.y, surfaceSize.height, surfaceSize.width]);
|
|
648
|
+
// The board iframe cannot read the host's CSS vars, so the themed canvas
|
|
649
|
+
// colour has to be resolved out here or the board stays dark in light mode.
|
|
650
|
+
const boardSurfaceBackground = useMemo(() => {
|
|
651
|
+
if (typeof window === "undefined") return BOARD_SURFACE_BACKGROUND;
|
|
652
|
+
const themed = window
|
|
653
|
+
.getComputedStyle(document.documentElement)
|
|
654
|
+
.getPropertyValue("--design-editor-canvas-bg")
|
|
655
|
+
.trim();
|
|
656
|
+
return themed || BOARD_SURFACE_BACKGROUND;
|
|
657
|
+
}, [resolvedTheme]);
|
|
658
|
+
|
|
644
659
|
const boardSurfaceRenderGeometry = useMemo(() => {
|
|
645
660
|
if (!boardFrameGeometry) return undefined;
|
|
646
661
|
const focusGeometry = boardSurfaceFocusPoint
|
|
@@ -692,8 +707,14 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
692
707
|
html: boardSurfaceHtml,
|
|
693
708
|
logicalGeometry: boardFrameGeometry,
|
|
694
709
|
viewport: boardStaticPreviewViewport,
|
|
710
|
+
background: boardSurfaceBackground,
|
|
695
711
|
});
|
|
696
|
-
}, [
|
|
712
|
+
}, [
|
|
713
|
+
boardSurfaceHtml,
|
|
714
|
+
boardFrameGeometry,
|
|
715
|
+
boardStaticPreviewViewport,
|
|
716
|
+
boardSurfaceBackground,
|
|
717
|
+
]);
|
|
697
718
|
const showBoardStaticPreview = Boolean(
|
|
698
719
|
boardFrameGeometry &&
|
|
699
720
|
boardSurfaceRenderGeometry &&
|
|
@@ -2189,6 +2210,25 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
2189
2210
|
const sourceIsBoard = sourceScreenId === boardFileId;
|
|
2190
2211
|
setCrossScreenSourceIsBoard(sourceIsBoard);
|
|
2191
2212
|
const target = getFrameEntryAtPoint(boardPoint);
|
|
2213
|
+
trace("drop", "resolve-target", {
|
|
2214
|
+
pointerInCanvasUnits: {
|
|
2215
|
+
x: Math.round(boardPoint.x),
|
|
2216
|
+
y: Math.round(boardPoint.y),
|
|
2217
|
+
},
|
|
2218
|
+
hitFrame: target?.id ?? null,
|
|
2219
|
+
sourceScreen: sourceScreenId,
|
|
2220
|
+
sourceIsBoard,
|
|
2221
|
+
frames: Object.entries(frameGeometryRef.current ?? {}).map(
|
|
2222
|
+
([id, g]: [string, any]) =>
|
|
2223
|
+
`${id.slice(0, 6)} @ ${Math.round(g.x)},${Math.round(g.y)} ${Math.round(g.width)}x${Math.round(g.height)}`,
|
|
2224
|
+
),
|
|
2225
|
+
verdict:
|
|
2226
|
+
target && target.id !== sourceScreenId
|
|
2227
|
+
? "will drop into that frame"
|
|
2228
|
+
: target
|
|
2229
|
+
? "hit the SOURCE frame, so no cross-screen move"
|
|
2230
|
+
: "NO frame under the pointer — drop cannot resolve a screen",
|
|
2231
|
+
});
|
|
2192
2232
|
if (target && target.id !== sourceScreenId) {
|
|
2193
2233
|
const nextTarget = { id: target.id, geometry: target.geometry };
|
|
2194
2234
|
if (crossScreenTargetRef.current?.id !== nextTarget.id) {
|
|
@@ -2261,6 +2301,29 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
2261
2301
|
const hasIdentifier = !!(payload.selector || payload.sourceId);
|
|
2262
2302
|
if (!hasIdentifier || !sourceScreenId) return;
|
|
2263
2303
|
if (!lastBoardPoint) return;
|
|
2304
|
+
// No candidate means the pointer never left the source screen, so the
|
|
2305
|
+
// bridge already handled it as an in-place reorder. Falling back to the
|
|
2306
|
+
// board here re-persists the move against a file that does not contain
|
|
2307
|
+
// the element, which fails to resolve and silently discards the drop.
|
|
2308
|
+
const sourceFrameGeometry = frameGeometryRef.current?.[sourceScreenId];
|
|
2309
|
+
const droppedInsideSourceScreen =
|
|
2310
|
+
!candidate &&
|
|
2311
|
+
!!sourceFrameGeometry &&
|
|
2312
|
+
lastBoardPoint.x >= sourceFrameGeometry.x &&
|
|
2313
|
+
lastBoardPoint.x <= sourceFrameGeometry.x + sourceFrameGeometry.width &&
|
|
2314
|
+
lastBoardPoint.y >= sourceFrameGeometry.y &&
|
|
2315
|
+
lastBoardPoint.y <= sourceFrameGeometry.y + sourceFrameGeometry.height;
|
|
2316
|
+
if (droppedInsideSourceScreen) return;
|
|
2317
|
+
trace("drop", "finalize", {
|
|
2318
|
+
candidate: candidate?.id ?? null,
|
|
2319
|
+
sourceScreen: sourceScreenId,
|
|
2320
|
+
droppedInsideSourceScreen,
|
|
2321
|
+
outcome: droppedInsideSourceScreen
|
|
2322
|
+
? "discarded — pointer never left the source screen"
|
|
2323
|
+
: candidate
|
|
2324
|
+
? "moving into candidate"
|
|
2325
|
+
: "no candidate; falling back to the board",
|
|
2326
|
+
});
|
|
2264
2327
|
const targetCandidate =
|
|
2265
2328
|
candidate ??
|
|
2266
2329
|
(boardFileId && sourceScreenId !== boardFileId && boardFrameGeometry
|
|
@@ -2927,6 +2990,14 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
2927
2990
|
const viewportWidth = iframe?.clientWidth || metadata.width;
|
|
2928
2991
|
const viewportHeight = iframe?.clientHeight || metadata.height;
|
|
2929
2992
|
const infos = await requestSelectableElementInfos(entry.id);
|
|
2993
|
+
// entry.geometry.height trails the measured auto-height, and an
|
|
2994
|
+
// independent y-scale off it squashes every child rect.
|
|
2995
|
+
const contentScale =
|
|
2996
|
+
entry.geometry.width / Math.max(1, viewportWidth);
|
|
2997
|
+
const renderedFrame = {
|
|
2998
|
+
...entry.geometry,
|
|
2999
|
+
height: viewportHeight * contentScale,
|
|
3000
|
+
};
|
|
2930
3001
|
return infos.map((info) => ({
|
|
2931
3002
|
screenId: entry.id,
|
|
2932
3003
|
info,
|
|
@@ -2937,7 +3008,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
2937
3008
|
width: info.boundingRect.width,
|
|
2938
3009
|
height: info.boundingRect.height,
|
|
2939
3010
|
},
|
|
2940
|
-
|
|
3011
|
+
renderedFrame,
|
|
2941
3012
|
{ width: viewportWidth, height: viewportHeight },
|
|
2942
3013
|
),
|
|
2943
3014
|
frameGeometry: entry.geometry,
|
|
@@ -3718,11 +3789,27 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
3718
3789
|
getScreenMetadata?.(targetScreen),
|
|
3719
3790
|
)
|
|
3720
3791
|
: undefined;
|
|
3792
|
+
// Metadata defaults to 1280x2560 while the renderer lays the iframe out
|
|
3793
|
+
// at the frame's own size; trusting metadata scales every drawn
|
|
3794
|
+
// primitive by metadataWidth/frameWidth. Same precedence as the marquee.
|
|
3795
|
+
const targetIframe = targetScreen
|
|
3796
|
+
? surfaceRef.current?.querySelector<HTMLIFrameElement>(
|
|
3797
|
+
`[data-screen-iframe-id="${CSS.escape(getActiveScreenIframeId(targetScreen))}"]`,
|
|
3798
|
+
)
|
|
3799
|
+
: null;
|
|
3800
|
+
const measuredMetadata =
|
|
3801
|
+
targetMetadata && targetIframe?.clientWidth && targetIframe.clientHeight
|
|
3802
|
+
? {
|
|
3803
|
+
...targetMetadata,
|
|
3804
|
+
width: targetIframe.clientWidth,
|
|
3805
|
+
height: targetIframe.clientHeight,
|
|
3806
|
+
}
|
|
3807
|
+
: targetMetadata;
|
|
3721
3808
|
|
|
3722
3809
|
const localPrimitive = draftPrimitiveToInsert(
|
|
3723
3810
|
draft,
|
|
3724
3811
|
targetFrame.geometry,
|
|
3725
|
-
|
|
3812
|
+
measuredMetadata,
|
|
3726
3813
|
);
|
|
3727
3814
|
const persisted = onCreatePrimitive(targetFrame.id, localPrimitive);
|
|
3728
3815
|
if (!persisted) {
|
|
@@ -4436,6 +4523,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
4436
4523
|
// originating screen.
|
|
4437
4524
|
if (
|
|
4438
4525
|
state.tool === "frame" &&
|
|
4526
|
+
frameToolDraws === "screen" &&
|
|
4439
4527
|
!state.originFrameId &&
|
|
4440
4528
|
onCreateScreenFrame
|
|
4441
4529
|
) {
|
|
@@ -4459,9 +4547,19 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
4459
4547
|
0,
|
|
4460
4548
|
)
|
|
4461
4549
|
: null;
|
|
4462
|
-
|
|
4463
|
-
|
|
4550
|
+
const screenGeometry = clampFrameGeometryToViewport(
|
|
4551
|
+
draftGeometry,
|
|
4552
|
+
viewportBounds,
|
|
4464
4553
|
);
|
|
4554
|
+
trace("screen", "create-from-frame-tool", {
|
|
4555
|
+
why: "frame tool started on empty canvas, so it becomes a SCREEN",
|
|
4556
|
+
drawn: roundGeo(draftGeometry),
|
|
4557
|
+
committed: roundGeo(screenGeometry),
|
|
4558
|
+
clamped:
|
|
4559
|
+
Math.round(draftGeometry.x) !== Math.round(screenGeometry.x) ||
|
|
4560
|
+
Math.round(draftGeometry.y) !== Math.round(screenGeometry.y),
|
|
4561
|
+
});
|
|
4562
|
+
onCreateScreenFrame(screenGeometry);
|
|
4465
4563
|
if (activeTool === undefined) {
|
|
4466
4564
|
setLocalActiveTool("move");
|
|
4467
4565
|
}
|
|
@@ -4469,6 +4567,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
4469
4567
|
finishDrag();
|
|
4470
4568
|
return;
|
|
4471
4569
|
}
|
|
4570
|
+
trace("draw", "commit-primitive", {
|
|
4571
|
+
tool: state.tool,
|
|
4572
|
+
startedInScreen: state.originFrameId ?? "(empty canvas → board)",
|
|
4573
|
+
});
|
|
4472
4574
|
const nextDraft = createDraftPrimitive({
|
|
4473
4575
|
tool: state.tool,
|
|
4474
4576
|
start: state.originCanvas,
|
|
@@ -4503,6 +4605,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
4503
4605
|
activeTool,
|
|
4504
4606
|
commitDraftPrimitive,
|
|
4505
4607
|
finishDrag,
|
|
4608
|
+
frameToolDraws,
|
|
4506
4609
|
getCanvasPoint,
|
|
4507
4610
|
getFrameEntryAtPoint,
|
|
4508
4611
|
installDragListeners,
|
|
@@ -7474,6 +7577,11 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
7474
7577
|
const chromeScale = scale > 0 ? 1 / scale : 1;
|
|
7475
7578
|
const showPixelGrid = canvasZoom >= PIXEL_GRID_ZOOM;
|
|
7476
7579
|
const effectiveTool = normalizeCanvasTool(activeTool ?? localActiveTool);
|
|
7580
|
+
const lastTracedToolRef = useRef<string | null>(null);
|
|
7581
|
+
if (lastTracedToolRef.current !== effectiveTool) {
|
|
7582
|
+
lastTracedToolRef.current = effectiveTool;
|
|
7583
|
+
trace("tool", "active-tool", { tool: effectiveTool });
|
|
7584
|
+
}
|
|
7477
7585
|
useEffect(() => {
|
|
7478
7586
|
effectiveToolRef.current = effectiveTool;
|
|
7479
7587
|
}, [effectiveTool]);
|
|
@@ -7624,7 +7732,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
7624
7732
|
metadata.previewUrl ?? getPreviewUrl(screen.content)
|
|
7625
7733
|
);
|
|
7626
7734
|
const autoHeight =
|
|
7627
|
-
isInlineScreen && measuredPrimaryHeight
|
|
7735
|
+
isInlineScreen && measuredPrimaryHeight && !metadata.heightPinned
|
|
7628
7736
|
? Math.max(
|
|
7629
7737
|
deviceViewportFloorForWidth(metadata.width),
|
|
7630
7738
|
rawGeometry.height ?? 0,
|
|
@@ -8055,7 +8163,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
8055
8163
|
zoom={100}
|
|
8056
8164
|
deviceFrame="none"
|
|
8057
8165
|
boardSurface
|
|
8058
|
-
embeddedFrameBackground={
|
|
8166
|
+
embeddedFrameBackground={boardSurfaceBackground}
|
|
8059
8167
|
embeddedFrame={{
|
|
8060
8168
|
viewportWidth: Math.max(1, Math.round(boardW)),
|
|
8061
8169
|
viewportHeight: Math.max(1, Math.round(boardH)),
|
|
@@ -2749,6 +2749,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
2749
2749
|
|
|
2750
2750
|
var passiveSelectionEls: Element[] = [];
|
|
2751
2751
|
var passiveSelectionOverlays: HTMLElement[] = [];
|
|
2752
|
+
// Figma draws ONE bounding box with handles around a multi-selection; the
|
|
2753
|
+
// per-element overlays above are the thin outlines inside it.
|
|
2754
|
+
var multiSelectionBoundsOverlay: HTMLElement | null = null;
|
|
2752
2755
|
var activeMarqueeSelection: {
|
|
2753
2756
|
startX: number;
|
|
2754
2757
|
startY: number;
|
|
@@ -3042,7 +3045,6 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
3042
3045
|
style === "soft"
|
|
3043
3046
|
? "position:fixed;pointer-events:none;z-index:99996;border:1px solid color-mix(in srgb,var(--design-editor-accent-color) 64%,transparent);background:color-mix(in srgb,var(--design-editor-accent-color) 5%,transparent);display:none;box-sizing:border-box;"
|
|
3044
3047
|
: "position:fixed;pointer-events:none;z-index:99996;border:1.5px solid var(--design-editor-accent-color);background:transparent;display:none;box-sizing:border-box;";
|
|
3045
|
-
if (style !== "soft") appendPassiveSelectionHandles(overlay);
|
|
3046
3048
|
document.body.appendChild(overlay);
|
|
3047
3049
|
return overlay;
|
|
3048
3050
|
}
|
|
@@ -3088,6 +3090,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
3088
3090
|
passiveSelectionOverlays.push(overlay);
|
|
3089
3091
|
positionOverlay(overlay, el);
|
|
3090
3092
|
});
|
|
3093
|
+
// Selection changes do not go through refreshOverlays, so the combined
|
|
3094
|
+
// bounds must be recomputed here too.
|
|
3095
|
+
positionMultiSelectionBounds();
|
|
3091
3096
|
}
|
|
3092
3097
|
|
|
3093
3098
|
function preservePreviousSelectedElementForShiftClick(
|
|
@@ -4536,6 +4541,70 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
4536
4541
|
return true;
|
|
4537
4542
|
}
|
|
4538
4543
|
|
|
4544
|
+
function ensureMultiSelectionBoundsOverlay(): HTMLElement {
|
|
4545
|
+
if (multiSelectionBoundsOverlay) return multiSelectionBoundsOverlay;
|
|
4546
|
+
var overlay = document.createElement("div");
|
|
4547
|
+
overlay.setAttribute("data-agent-native-edit-overlay", "multi-selection");
|
|
4548
|
+
overlay.setAttribute("data-agent-native-multi-selection-bounds", "true");
|
|
4549
|
+
overlay.style.cssText =
|
|
4550
|
+
"position:fixed;pointer-events:none;z-index:99996;border:1.5px solid var(--design-editor-accent-color);background:transparent;display:none;box-sizing:border-box;";
|
|
4551
|
+
appendPassiveSelectionHandles(overlay);
|
|
4552
|
+
document.body.appendChild(overlay);
|
|
4553
|
+
multiSelectionBoundsOverlay = overlay;
|
|
4554
|
+
return overlay;
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4557
|
+
function positionMultiSelectionBounds(): void {
|
|
4558
|
+
var members: Element[] = [];
|
|
4559
|
+
if (selectedEl && document.documentElement.contains(selectedEl)) {
|
|
4560
|
+
members.push(selectedEl);
|
|
4561
|
+
}
|
|
4562
|
+
passiveSelectionEls.forEach(function (el) {
|
|
4563
|
+
if (el && document.documentElement.contains(el)) members.push(el);
|
|
4564
|
+
});
|
|
4565
|
+
if (members.length < 2 || selectionChromeHidden) {
|
|
4566
|
+
if (multiSelectionBoundsOverlay) {
|
|
4567
|
+
multiSelectionBoundsOverlay.style.display = "none";
|
|
4568
|
+
}
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
4571
|
+
var rects = members.map(function (el) {
|
|
4572
|
+
return (el as HTMLElement).getBoundingClientRect();
|
|
4573
|
+
});
|
|
4574
|
+
var left = Math.min.apply(
|
|
4575
|
+
null,
|
|
4576
|
+
rects.map(function (r) {
|
|
4577
|
+
return r.left;
|
|
4578
|
+
}),
|
|
4579
|
+
);
|
|
4580
|
+
var top = Math.min.apply(
|
|
4581
|
+
null,
|
|
4582
|
+
rects.map(function (r) {
|
|
4583
|
+
return r.top;
|
|
4584
|
+
}),
|
|
4585
|
+
);
|
|
4586
|
+
var right = Math.max.apply(
|
|
4587
|
+
null,
|
|
4588
|
+
rects.map(function (r) {
|
|
4589
|
+
return r.right;
|
|
4590
|
+
}),
|
|
4591
|
+
);
|
|
4592
|
+
var bottom = Math.max.apply(
|
|
4593
|
+
null,
|
|
4594
|
+
rects.map(function (r) {
|
|
4595
|
+
return r.bottom;
|
|
4596
|
+
}),
|
|
4597
|
+
);
|
|
4598
|
+
var overlay = ensureMultiSelectionBoundsOverlay();
|
|
4599
|
+
overlay.style.display = "block";
|
|
4600
|
+
overlay.style.transform = "none";
|
|
4601
|
+
overlay.style.left = left + "px";
|
|
4602
|
+
overlay.style.top = top + "px";
|
|
4603
|
+
overlay.style.width = Math.max(0, right - left) + "px";
|
|
4604
|
+
overlay.style.height = Math.max(0, bottom - top) + "px";
|
|
4605
|
+
scalePassiveSelectionOverlay(overlay);
|
|
4606
|
+
}
|
|
4607
|
+
|
|
4539
4608
|
function positionOverlay(overlay: HTMLElement, el: Element): void {
|
|
4540
4609
|
if (!el || !document.documentElement.contains(el)) {
|
|
4541
4610
|
overlay.style.display = "none";
|
|
@@ -4603,6 +4672,7 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
4603
4672
|
var overlay = passiveSelectionOverlays[index];
|
|
4604
4673
|
if (overlay) positionOverlay(overlay, el);
|
|
4605
4674
|
});
|
|
4675
|
+
positionMultiSelectionBounds();
|
|
4606
4676
|
positionGradientOverlay();
|
|
4607
4677
|
syncOverlayObservers();
|
|
4608
4678
|
}
|
|
@@ -5000,10 +5070,12 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
5000
5070
|
if (isOverlayElement(target)) continue;
|
|
5001
5071
|
if (isLayerInteractionBlocked(target)) {
|
|
5002
5072
|
lastEditorPointWasBlocked = true;
|
|
5073
|
+
dndLog("select:blocked", { el: getSelector(target) });
|
|
5003
5074
|
return null;
|
|
5004
5075
|
}
|
|
5005
5076
|
return target;
|
|
5006
5077
|
}
|
|
5078
|
+
dndLog("select:nothing-at-point", { x: clientX, y: clientY });
|
|
5007
5079
|
return null;
|
|
5008
5080
|
}
|
|
5009
5081
|
|
|
@@ -7285,12 +7357,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
7285
7357
|
el.getAttribute("data-agent-native-primitive") ||
|
|
7286
7358
|
""
|
|
7287
7359
|
).toLowerCase();
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
primitive !== "frame"
|
|
7292
|
-
)
|
|
7293
|
-
return false;
|
|
7360
|
+
// Frames adopt; a rectangle is a vector shape and never becomes a
|
|
7361
|
+
// container (same contract appendCanvasPrimitiveToHtml enforces on draw).
|
|
7362
|
+
if (primitive !== "frame") return false;
|
|
7294
7363
|
var cs = window.getComputedStyle(el);
|
|
7295
7364
|
return cs.position === "absolute" || cs.position === "fixed";
|
|
7296
7365
|
}
|
|
@@ -7685,6 +7754,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
7685
7754
|
if (!el || el === document.documentElement) return false;
|
|
7686
7755
|
if (isOverlayElement(el) || isLayerInteractionBlocked(el)) return false;
|
|
7687
7756
|
if (el === document.body) return true;
|
|
7757
|
+
// Figma's shape primitives are vectors; only a frame adopts children.
|
|
7758
|
+
var primitiveKind = el.getAttribute("data-an-primitive");
|
|
7759
|
+
if (primitiveKind && primitiveKind !== "frame") return false;
|
|
7688
7760
|
var tag = (el.tagName || "").toLowerCase();
|
|
7689
7761
|
// Reject leaf/text tags — they cannot accept children
|
|
7690
7762
|
if (
|
|
@@ -12519,6 +12591,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
12519
12591
|
} else {
|
|
12520
12592
|
positionOverlay(selectionOverlay, target);
|
|
12521
12593
|
}
|
|
12594
|
+
// The combined box spans selectedEl plus the passive selection, so a
|
|
12595
|
+
// host-driven change leaves it on the previous geometry without this.
|
|
12596
|
+
positionMultiSelectionBounds();
|
|
12522
12597
|
if (hoveredEl === selectedEl) highlightOverlay.style.display = "none";
|
|
12523
12598
|
// A host-driven selection (e.g. picking a layer in the Layers panel)
|
|
12524
12599
|
// only ever moved the overlay above — it never sent the rich
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Interaction trace, on by default in dev. From the top-frame console:
|
|
2
|
+
// `__DESIGN_TRACE = false` silences it; `__designTrace.dump()` prints the
|
|
3
|
+
// whole story to copy; `.clear()` and `.only("drop")` narrow it.
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
__DESIGN_TRACE?: boolean;
|
|
7
|
+
__designTrace?: {
|
|
8
|
+
dump: () => string;
|
|
9
|
+
clear: () => void;
|
|
10
|
+
only: (area?: string) => void;
|
|
11
|
+
entries: () => TraceEntry[];
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type TraceArea =
|
|
17
|
+
| "tool"
|
|
18
|
+
| "draw"
|
|
19
|
+
| "screen"
|
|
20
|
+
| "select"
|
|
21
|
+
| "drag"
|
|
22
|
+
| "drop"
|
|
23
|
+
| "persist"
|
|
24
|
+
| "structure"
|
|
25
|
+
| "history";
|
|
26
|
+
|
|
27
|
+
export interface TraceEntry {
|
|
28
|
+
t: number;
|
|
29
|
+
area: TraceArea;
|
|
30
|
+
event: string;
|
|
31
|
+
data?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const MAX_ENTRIES = 2000;
|
|
35
|
+
const entries: TraceEntry[] = [];
|
|
36
|
+
let areaFilter: string | undefined;
|
|
37
|
+
let startedAt = 0;
|
|
38
|
+
|
|
39
|
+
function enabled(): boolean {
|
|
40
|
+
if (typeof window === "undefined") return false;
|
|
41
|
+
if (window.__DESIGN_TRACE === false) return false;
|
|
42
|
+
return window.__DESIGN_TRACE === true || import.meta.env?.DEV === true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ensureControls(): void {
|
|
46
|
+
if (typeof window === "undefined" || window.__designTrace) return;
|
|
47
|
+
window.__designTrace = {
|
|
48
|
+
entries: () => entries.slice(),
|
|
49
|
+
clear: () => {
|
|
50
|
+
entries.length = 0;
|
|
51
|
+
startedAt = 0;
|
|
52
|
+
},
|
|
53
|
+
only: (area?: string) => {
|
|
54
|
+
areaFilter = area;
|
|
55
|
+
},
|
|
56
|
+
dump: () =>
|
|
57
|
+
entries
|
|
58
|
+
.map((e) => {
|
|
59
|
+
const body = e.data === undefined ? "" : ` ${safeJson(e.data)}`;
|
|
60
|
+
return `+${String(e.t).padStart(6)}ms [${e.area}:${e.event}]${body}`;
|
|
61
|
+
})
|
|
62
|
+
.join("\n"),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Never let a circular ref or a DOM node break a gesture. */
|
|
67
|
+
function safeJson(value: unknown): string {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.stringify(value, (_key, v) =>
|
|
70
|
+
v instanceof Element ? v.tagName.toLowerCase() : v,
|
|
71
|
+
);
|
|
72
|
+
} catch {
|
|
73
|
+
return String(value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function trace(area: TraceArea, event: string, data?: unknown): void {
|
|
78
|
+
if (!enabled()) return;
|
|
79
|
+
try {
|
|
80
|
+
ensureControls();
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
if (!startedAt) startedAt = now;
|
|
83
|
+
const entry: TraceEntry = { t: now - startedAt, area, event, data };
|
|
84
|
+
entries.push(entry);
|
|
85
|
+
if (entries.length > MAX_ENTRIES) entries.shift();
|
|
86
|
+
if (areaFilter && areaFilter !== area) return;
|
|
87
|
+
const tag = `%c[${area}:${event}]`;
|
|
88
|
+
const style = "font-weight:bold";
|
|
89
|
+
if (data === undefined) console.log(tag, style);
|
|
90
|
+
else console.log(tag, style, data);
|
|
91
|
+
// coercion-ok: diagnostics must never break the interaction they observe
|
|
92
|
+
} catch {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Short, stable label for an element in a trace line. */
|
|
96
|
+
export function traceEl(el: Element | null | undefined): string | null {
|
|
97
|
+
if (!el) return null;
|
|
98
|
+
const id = el.getAttribute?.("data-agent-native-node-id");
|
|
99
|
+
const name = el.getAttribute?.("data-agent-native-layer-name");
|
|
100
|
+
const primitive = el.getAttribute?.("data-an-primitive");
|
|
101
|
+
const tag = el.tagName?.toLowerCase() ?? "?";
|
|
102
|
+
return [
|
|
103
|
+
tag,
|
|
104
|
+
primitive && `(${primitive})`,
|
|
105
|
+
name && `"${name}"`,
|
|
106
|
+
id && `#${id}`,
|
|
107
|
+
]
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.join(" ");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Compact geometry for a trace line. */
|
|
113
|
+
export function roundGeo(g: {
|
|
114
|
+
x: number;
|
|
115
|
+
y: number;
|
|
116
|
+
width: number;
|
|
117
|
+
height: number;
|
|
118
|
+
}): string {
|
|
119
|
+
return `${Math.round(g.x)},${Math.round(g.y)} ${Math.round(g.width)}x${Math.round(g.height)}`;
|
|
120
|
+
}
|
|
@@ -15,7 +15,8 @@ declare global {
|
|
|
15
15
|
|
|
16
16
|
export function dndHostLog(phase: string, data?: unknown): void {
|
|
17
17
|
if (typeof window === "undefined") return;
|
|
18
|
-
if (
|
|
18
|
+
if (window.__DND_DEBUG === false) return;
|
|
19
|
+
if (!window.__DND_DEBUG && !import.meta.env?.DEV) return;
|
|
19
20
|
try {
|
|
20
21
|
const tag = `%c[dnd:host:${phase}]`;
|
|
21
22
|
const style = "color:#0ea5e9;font-weight:bold";
|