@agent-native/core 0.95.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +35 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/corpus/core/docs/content/template-design.mdx +16 -0
- package/corpus/core/package.json +4 -2
- package/corpus/core/src/a2a/client.ts +11 -1
- package/corpus/core/src/agent/production-agent.ts +107 -27
- package/corpus/core/src/agent/thread-data-builder.ts +48 -22
- package/corpus/core/src/chat-threads/store.ts +20 -1
- package/corpus/core/src/cli/code-agent-executor.ts +1 -0
- package/corpus/core/src/cli/code-agent-runs.ts +14 -0
- package/corpus/core/src/client/AgentPanel.tsx +32 -25
- package/corpus/core/src/client/AssistantChat.tsx +286 -45
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +141 -90
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +404 -0
- package/corpus/core/src/client/chat/index.ts +6 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +38 -4
- package/corpus/core/src/client/chat/use-reconnect-reader-owner.ts +28 -0
- package/corpus/core/src/client/code-agent-chat-adapter.ts +72 -4
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +52 -11
- package/corpus/core/src/client/composer/TiptapComposer.tsx +157 -20
- package/corpus/core/src/client/composer/VoiceButton.tsx +28 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +5 -0
- package/corpus/core/src/client/conversation/code-agent-transcript.ts +4 -5
- package/corpus/core/src/client/guided-questions.tsx +11 -2
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +6 -7
- package/corpus/core/src/client/sse-event-processor.ts +90 -21
- package/corpus/core/src/client/use-chat-threads.ts +10 -1
- package/corpus/core/src/client/voice-provider-status.ts +44 -0
- package/corpus/core/src/code-agents/transcript-normalizer.ts +76 -0
- package/corpus/core/src/connections/catalog.ts +2 -2
- package/corpus/core/src/deploy/build.ts +12 -8
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +35 -5
- package/corpus/core/src/integrations/adapters/slack.ts +74 -21
- package/corpus/core/src/integrations/catalog.ts +2 -2
- package/corpus/core/src/integrations/webhook-handler.ts +14 -0
- package/corpus/core/src/localization/default-messages.ts +6 -0
- package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
- package/corpus/core/src/observability/routes.ts +17 -0
- package/corpus/core/src/observability/store.ts +4 -1
- package/corpus/core/src/observability/traces.ts +41 -2
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +19 -1
- package/corpus/core/src/scripts/call-agent.ts +53 -3
- package/corpus/core/src/scripts/chat/search-chats.ts +11 -8
- package/corpus/core/src/secrets/register-framework-secrets.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +41 -6
- package/corpus/core/src/server/auth.ts +1 -1
- package/corpus/core/src/server/core-routes-plugin.ts +15 -0
- package/corpus/core/src/server/credential-provider.ts +7 -3
- package/corpus/core/src/server/realtime-voice.ts +71 -24
- package/corpus/core/src/server/voice-providers-status.ts +4 -3
- package/corpus/core/src/shared/cache-control.ts +4 -4
- package/corpus/core/src/styles/agent-native.css +1 -0
- package/corpus/core/src/styles/chat-history-list.css +313 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +7 -0
- package/corpus/templates/analytics/actions/bigquery.ts +26 -2
- package/corpus/templates/analytics/actions/data-source-status.ts +18 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -4
- package/corpus/templates/analytics/app/global.css +10 -0
- package/corpus/templates/analytics/app/lib/data-sources.ts +5 -4
- package/corpus/templates/analytics/app/pages/Ask.tsx +25 -2
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-answers-simple-time-bounded-metrics-without-unnece.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-chat-reliably-uses-connected-data-sources-across-s.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-chat-threads-now-stay-clear-of-top-actions-and-fade-smoothly.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-context-chips-can-now-be-selected-and-removed-one-at-a-time-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-slack-token-setup-marked-legacy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-composer-no-longer-carries-dashboard-or-panel-contex.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-section-stays-highlighted-while-its-chat-history-is-.md +6 -0
- package/corpus/templates/analytics/server/lib/bigquery.ts +90 -14
- package/corpus/templates/analytics/server/lib/credential-keys.ts +6 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +82 -7
- package/corpus/templates/brain/changelog/2026-07-10-slack-backfill-token-marked-legacy.md +6 -0
- package/corpus/templates/brain/server/register-secrets.ts +2 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -1
- package/corpus/templates/clips/app/components/library/page-header.tsx +19 -3
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +16 -12
- package/corpus/templates/clips/changelog/2026-07-10-new-recording-appears-once-when-the-library-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-slack-token-fallback-guidance.md +6 -0
- package/corpus/templates/clips/server/register-secrets.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +0 -66
- package/corpus/templates/content/app/routes/_app.local-files.tsx +7 -47
- package/corpus/templates/content/changelog/2026-07-10-local-folders-now-wait-for-an-explicit-pull-before-content-r.md +6 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/design/actions/generate-design.ts +128 -31
- package/corpus/templates/design/actions/present-design-variants.ts +37 -9
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +9 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +32 -10
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +2 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -5
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/global.css +10 -0
- package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +21 -11
- package/corpus/templates/design/changelog/2026-07-10-editor-panels-are-easier-to-distinguish-and-design-intake-qu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-interact-mode-now-stays-on-the-full-canvas-matches-edit-visu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-web-designs-open-at-desktop-size-and-adapt-across-mobile.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-now-link-to-full-documentation.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/mail/app/i18n/ar-SA.ts +3 -3
- package/corpus/templates/mail/app/i18n/de-DE.ts +3 -3
- package/corpus/templates/mail/app/i18n/en-US.ts +4 -3
- package/corpus/templates/mail/app/i18n/es-ES.ts +3 -3
- package/corpus/templates/mail/app/i18n/fr-FR.ts +3 -3
- package/corpus/templates/mail/app/i18n/hi-IN.ts +3 -3
- package/corpus/templates/mail/app/i18n/ja-JP.ts +3 -3
- package/corpus/templates/mail/app/i18n/ko-KR.ts +3 -3
- package/corpus/templates/mail/app/i18n/pt-BR.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-CN.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/mail/changelog/2026-07-10-slack-intake-marked-legacy.md +6 -0
- package/corpus/templates/mail/server/lib/env-config.ts +5 -4
- package/corpus/templates/plan/package.json +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +83 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +42 -23
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/chat-threads/store.d.ts +10 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +6 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +1 -0
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.d.ts +12 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +1 -0
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +3 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +207 -32
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +83 -10
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/chat/ChatHistoryList.d.ts +88 -0
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -0
- package/dist/client/chat/ChatHistoryList.js +83 -0
- package/dist/client/chat/ChatHistoryList.js.map +1 -0
- package/dist/client/chat/index.d.ts +1 -0
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -0
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +13 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +11 -3
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-reconnect-reader-owner.d.ts +11 -0
- package/dist/client/chat/use-reconnect-reader-owner.d.ts.map +1 -0
- package/dist/client/chat/use-reconnect-reader-owner.js +21 -0
- package/dist/client/chat/use-reconnect-reader-owner.js.map +1 -0
- package/dist/client/code-agent-chat-adapter.d.ts +17 -1
- package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +47 -3
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +11 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +5 -3
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +25 -2
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +96 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +21 -1
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +5 -0
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.d.ts +2 -0
- package/dist/client/conversation/code-agent-transcript.d.ts.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +3 -5
- package/dist/client/conversation/code-agent-transcript.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +7 -2
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +5 -7
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +67 -20
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +9 -1
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/voice-provider-status.d.ts +10 -0
- package/dist/client/voice-provider-status.d.ts.map +1 -0
- package/dist/client/voice-provider-status.js +32 -0
- package/dist/client/voice-provider-status.js.map +1 -0
- package/dist/code-agents/transcript-normalizer.d.ts +29 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +55 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.js +2 -2
- package/dist/connections/catalog.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +12 -8
- package/dist/deploy/build.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +25 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +55 -21
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/catalog.js +2 -2
- package/dist/integrations/catalog.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +11 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +5 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/hosted-model-experiment.d.ts +39 -0
- package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
- package/dist/observability/hosted-model-experiment.js +90 -0
- package/dist/observability/hosted-model-experiment.js.map +1 -0
- package/dist/observability/routes.d.ts.map +1 -1
- package/dist/observability/routes.js +16 -0
- package/dist/observability/routes.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +4 -1
- package/dist/observability/store.js.map +1 -1
- package/dist/observability/traces.d.ts +6 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +28 -2
- package/dist/observability/traces.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +19 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +43 -3
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/chat/search-chats.d.ts +1 -1
- package/dist/scripts/chat/search-chats.d.ts.map +1 -1
- package/dist/scripts/chat/search-chats.js +11 -8
- package/dist/scripts/chat/search-chats.js.map +1 -1
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +11 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.js +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +13 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +5 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +7 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +55 -21
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +2 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/shared/cache-control.d.ts +6 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +3 -3
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/chat-history-list.css +313 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/docs/content/template-design.mdx +16 -0
- package/package.json +4 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
} from "@/hooks/use-notion";
|
|
51
51
|
import {
|
|
52
52
|
canWriteLinkedLocalSource,
|
|
53
|
-
readDocumentFromLinkedLocalSource,
|
|
54
53
|
writeDocumentToLinkedLocalSource,
|
|
55
54
|
} from "@/lib/local-content-source-files";
|
|
56
55
|
import { cn } from "@/lib/utils";
|
|
@@ -538,71 +537,6 @@ function DocumentEditorBody({ documentId, document }: DocumentEditorBodyProps) {
|
|
|
538
537
|
}
|
|
539
538
|
}, [document, documentId]);
|
|
540
539
|
|
|
541
|
-
useEffect(() => {
|
|
542
|
-
if (!isInitializedRef.current || !isLinkedLocalSourceDocument) {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
let cancelled = false;
|
|
547
|
-
readDocumentFromLinkedLocalSource(document)
|
|
548
|
-
.then((result) => {
|
|
549
|
-
if (cancelled) return;
|
|
550
|
-
if (!result.ok) {
|
|
551
|
-
toast.error(t("editor.couldNotReadLocalSourceFile"), {
|
|
552
|
-
description: result.error,
|
|
553
|
-
});
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const fileDocument = result.document;
|
|
558
|
-
setLocalTitle(fileDocument.title);
|
|
559
|
-
setLocalContent(fileDocument.content);
|
|
560
|
-
setLocalContentUpdatedAt(result.updatedAt);
|
|
561
|
-
lastSavedTitleRef.current = {
|
|
562
|
-
title: fileDocument.title,
|
|
563
|
-
updatedAt: result.updatedAt,
|
|
564
|
-
};
|
|
565
|
-
lastSavedContentRef.current = {
|
|
566
|
-
content: fileDocument.content,
|
|
567
|
-
updatedAt: result.updatedAt,
|
|
568
|
-
};
|
|
569
|
-
queryClient.setQueryData(
|
|
570
|
-
["action", "get-document", { id: documentId }],
|
|
571
|
-
(old: Document | undefined) =>
|
|
572
|
-
old && typeof old === "object" ? { ...old, ...fileDocument } : old,
|
|
573
|
-
);
|
|
574
|
-
queryClient.setQueryData(
|
|
575
|
-
["action", "list-documents", undefined],
|
|
576
|
-
(old: any) => {
|
|
577
|
-
const docs = old?.documents ?? (Array.isArray(old) ? old : null);
|
|
578
|
-
if (!Array.isArray(docs)) return old;
|
|
579
|
-
const nextDocs = docs.map((doc: Document) =>
|
|
580
|
-
doc.id === documentId ? { ...doc, ...fileDocument } : doc,
|
|
581
|
-
);
|
|
582
|
-
return Array.isArray(old)
|
|
583
|
-
? nextDocs
|
|
584
|
-
: { ...old, documents: nextDocs };
|
|
585
|
-
},
|
|
586
|
-
);
|
|
587
|
-
})
|
|
588
|
-
.catch((error) => {
|
|
589
|
-
if (cancelled) return;
|
|
590
|
-
toast.error(t("editor.couldNotReadLocalSourceFile"), {
|
|
591
|
-
description:
|
|
592
|
-
error instanceof Error ? error.message : t("empty.genericError"),
|
|
593
|
-
});
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
return () => {
|
|
597
|
-
cancelled = true;
|
|
598
|
-
};
|
|
599
|
-
}, [
|
|
600
|
-
documentId,
|
|
601
|
-
document.source?.path,
|
|
602
|
-
isLinkedLocalSourceDocument,
|
|
603
|
-
queryClient,
|
|
604
|
-
]);
|
|
605
|
-
|
|
606
540
|
// NOTE: External body changes (agent edit, Notion pull, update-document) are
|
|
607
541
|
// reconciled into the editor by VisualEditor via its content prop + the
|
|
608
542
|
// updatedAt gate. The effects below keep DocumentEditor's own mirror
|
|
@@ -814,13 +814,6 @@ export default function LocalFilesRoute() {
|
|
|
814
814
|
count: restoredDirectories.length,
|
|
815
815
|
}),
|
|
816
816
|
});
|
|
817
|
-
await pullDirectories(restoredDirectories, {
|
|
818
|
-
showToast: false,
|
|
819
|
-
syncControlResources: false,
|
|
820
|
-
});
|
|
821
|
-
await connectLocalComponentWorkspaces(restoredDirectories, {
|
|
822
|
-
showToast: false,
|
|
823
|
-
});
|
|
824
817
|
return;
|
|
825
818
|
}
|
|
826
819
|
|
|
@@ -835,13 +828,6 @@ export default function LocalFilesRoute() {
|
|
|
835
828
|
count: restoredDirectories.length,
|
|
836
829
|
}),
|
|
837
830
|
});
|
|
838
|
-
await pullDirectories(restoredDirectories, {
|
|
839
|
-
showToast: false,
|
|
840
|
-
syncControlResources: false,
|
|
841
|
-
});
|
|
842
|
-
await connectLocalComponentWorkspaces(restoredDirectories, {
|
|
843
|
-
showToast: false,
|
|
844
|
-
});
|
|
845
831
|
};
|
|
846
832
|
restoreDirectories()
|
|
847
833
|
.catch((err) => {
|
|
@@ -943,32 +929,6 @@ export default function LocalFilesRoute() {
|
|
|
943
929
|
return { directories: nextDirectories, result };
|
|
944
930
|
}
|
|
945
931
|
|
|
946
|
-
async function pullDirectories(
|
|
947
|
-
selectedDirectories: SelectedDirectory[],
|
|
948
|
-
{
|
|
949
|
-
showToast = true,
|
|
950
|
-
syncControlResources = true,
|
|
951
|
-
}: { showToast?: boolean; syncControlResources?: boolean } = {},
|
|
952
|
-
) {
|
|
953
|
-
let activeDirectories = selectedDirectories;
|
|
954
|
-
let latestResult: ImportContentSourceResult | null = null;
|
|
955
|
-
for (const directory of selectedDirectories) {
|
|
956
|
-
const pulled = await pullDirectoryFiles(directory, activeDirectories, {
|
|
957
|
-
syncControlResources,
|
|
958
|
-
});
|
|
959
|
-
latestResult = pulled.result;
|
|
960
|
-
activeDirectories = pulled.directories;
|
|
961
|
-
}
|
|
962
|
-
if (latestResult) {
|
|
963
|
-
setStatus({
|
|
964
|
-
kind: "success",
|
|
965
|
-
title: t("localFiles.foldersPulled"),
|
|
966
|
-
detail: resultSummary(latestResult, t),
|
|
967
|
-
});
|
|
968
|
-
if (showToast) toast.success(t("localFiles.pulledLocalFiles"));
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
|
|
972
932
|
async function connectLocalComponentWorkspaces(
|
|
973
933
|
selectedDirectories: SelectedDirectory[],
|
|
974
934
|
{ showToast = true }: { showToast?: boolean } = {},
|
|
@@ -1029,7 +989,13 @@ export default function LocalFilesRoute() {
|
|
|
1029
989
|
});
|
|
1030
990
|
|
|
1031
991
|
setBusy(`pull:${selected.id}`);
|
|
1032
|
-
await
|
|
992
|
+
const { result } = await pullDirectoryFiles(selected, nextDirectories);
|
|
993
|
+
setStatus({
|
|
994
|
+
kind: "success",
|
|
995
|
+
title: t("localFiles.foldersPulled"),
|
|
996
|
+
detail: resultSummary(result, t),
|
|
997
|
+
});
|
|
998
|
+
toast.success(t("localFiles.pulledLocalFiles"));
|
|
1033
999
|
await connectLocalComponentWorkspaces([selected]);
|
|
1034
1000
|
} catch (err) {
|
|
1035
1001
|
setStatus({
|
|
@@ -1171,12 +1137,6 @@ export default function LocalFilesRoute() {
|
|
|
1171
1137
|
title: t("localFiles.folderRemoved"),
|
|
1172
1138
|
detail: directory.name,
|
|
1173
1139
|
});
|
|
1174
|
-
if (nextDirectories.length === 1) {
|
|
1175
|
-
await pullDirectories(nextDirectories, {
|
|
1176
|
-
showToast: false,
|
|
1177
|
-
syncControlResources: false,
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
1140
|
} catch (err) {
|
|
1181
1141
|
setStatus({
|
|
1182
1142
|
kind: "error",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@swc/core": "^1.13.3",
|
|
82
82
|
"@tailwindcss/typography": "^0.5.16",
|
|
83
83
|
"@tailwindcss/vite": "catalog:",
|
|
84
|
-
"@tanstack/react-query": "
|
|
84
|
+
"@tanstack/react-query": "5.101.2",
|
|
85
85
|
"@types/node": "^24.2.1",
|
|
86
86
|
"@types/react": "catalog:",
|
|
87
87
|
"@types/react-dom": "catalog:",
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
updateGenerationSessionWithSavedFiles,
|
|
34
34
|
} from "../shared/generation-session.js";
|
|
35
35
|
import { assertLockedLayersPreserved } from "../shared/locked-layers.js";
|
|
36
|
+
import { widthToPrefix } from "../shared/responsive-classes.js";
|
|
36
37
|
import { annotateScreenHtmlForPersist } from "../shared/screen-annotation.js";
|
|
37
38
|
|
|
38
39
|
/** Editor deep link so external agents can surface "Open design". */
|
|
@@ -54,6 +55,43 @@ function isRenderableDesignFile(file: {
|
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
type GenerationViewport = "mobile" | "tablet" | "desktop";
|
|
59
|
+
|
|
60
|
+
const DEFAULT_GENERATION_VIEWPORT: GenerationViewport = "desktop";
|
|
61
|
+
const GENERATION_VIEWPORT_SIZES: Record<
|
|
62
|
+
GenerationViewport,
|
|
63
|
+
{ width: number; height: number }
|
|
64
|
+
> = {
|
|
65
|
+
mobile: { width: 390, height: 844 },
|
|
66
|
+
tablet: { width: 768, height: 1024 },
|
|
67
|
+
desktop: { width: 1440, height: 1024 },
|
|
68
|
+
};
|
|
69
|
+
const GENERATED_FRAME_GAP = 96;
|
|
70
|
+
const DEFAULT_RESPONSIVE_BREAKPOINTS = [390, 768, 1440].map((widthPx) => ({
|
|
71
|
+
id: `generated-${widthPx}`,
|
|
72
|
+
label: widthPx === 390 ? "Mobile" : widthPx === 768 ? "Tablet" : "Desktop",
|
|
73
|
+
widthPx,
|
|
74
|
+
prefix: widthToPrefix(widthPx),
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
function hasBreakpointSet(value: unknown): boolean {
|
|
78
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const breakpoints = (value as { breakpoints?: unknown }).breakpoints;
|
|
82
|
+
return Array.isArray(breakpoints) && breakpoints.length > 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function nextGeneratedFrameX(
|
|
86
|
+
frames: ReturnType<typeof parseCanvasFrameGeometryById>,
|
|
87
|
+
): number {
|
|
88
|
+
return Object.values(frames).reduce((furthestRight, frame) => {
|
|
89
|
+
const x = frame.x ?? 0;
|
|
90
|
+
const width = frame.width ?? 0;
|
|
91
|
+
return Math.max(furthestRight, x + width + GENERATED_FRAME_GAP);
|
|
92
|
+
}, 0);
|
|
93
|
+
}
|
|
94
|
+
|
|
57
95
|
function jsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
58
96
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
59
97
|
}
|
|
@@ -149,7 +187,15 @@ const generateDesignAgentParameters = {
|
|
|
149
187
|
canvasFrames: {
|
|
150
188
|
type: "string",
|
|
151
189
|
description:
|
|
152
|
-
"Optional JSON array of overview-canvas placements keyed by filename or fileId."
|
|
190
|
+
"Optional JSON array of overview-canvas placements keyed by filename or fileId. " +
|
|
191
|
+
"Pass explicit x/y/width/height for every generated screen; desktop is 1440x1024.",
|
|
192
|
+
},
|
|
193
|
+
primaryViewport: {
|
|
194
|
+
type: "string",
|
|
195
|
+
enum: ["mobile", "tablet", "desktop"],
|
|
196
|
+
description:
|
|
197
|
+
"The requested primary form factor. Defaults to desktop (1440x1024). " +
|
|
198
|
+
"Set this from the intake answer when no explicit canvasFrames placement is supplied.",
|
|
153
199
|
},
|
|
154
200
|
},
|
|
155
201
|
required: ["designId", "prompt", "files"],
|
|
@@ -171,6 +217,9 @@ const generateDesignAction = defineAction({
|
|
|
171
217
|
"When `designSystemId` is provided, first use `get-design-system` and apply " +
|
|
172
218
|
"its `agentContext` tokens/docs before writing the file content; do not " +
|
|
173
219
|
"treat the id alone as enough design-system context. " +
|
|
220
|
+
"Every web design must be responsive. Use a desktop 1440x1024 primary " +
|
|
221
|
+
"canvas by default, or set `primaryViewport` for an explicitly mobile- or " +
|
|
222
|
+
"tablet-primary design; this action adds responsive editor breakpoints. " +
|
|
174
223
|
"Do not report a design as ready until this action succeeds. " +
|
|
175
224
|
"When adding multiple screens or states, pass canvasFrames with filenames " +
|
|
176
225
|
"and x/y/width/height so the new screens appear placed on the overview canvas.",
|
|
@@ -304,6 +353,14 @@ const generateDesignAction = defineAction({
|
|
|
304
353
|
"Reference each screen by filename or fileId and include x/y/width/height " +
|
|
305
354
|
"from generate-screens regions or your planned canvas layout.",
|
|
306
355
|
),
|
|
356
|
+
primaryViewport: z
|
|
357
|
+
.enum(["mobile", "tablet", "desktop"])
|
|
358
|
+
.optional()
|
|
359
|
+
.default(DEFAULT_GENERATION_VIEWPORT)
|
|
360
|
+
.describe(
|
|
361
|
+
"Primary generated viewport. Defaults to desktop (1440x1024); set " +
|
|
362
|
+
"mobile or tablet only when that is the requested form factor.",
|
|
363
|
+
),
|
|
307
364
|
}),
|
|
308
365
|
mcpApp: {
|
|
309
366
|
compactCatalog: true,
|
|
@@ -323,6 +380,7 @@ const generateDesignAction = defineAction({
|
|
|
323
380
|
projectType,
|
|
324
381
|
tweaks,
|
|
325
382
|
canvasFrames,
|
|
383
|
+
primaryViewport,
|
|
326
384
|
}) => {
|
|
327
385
|
await assertAccess("design", designId, "editor");
|
|
328
386
|
if (designSystemId) {
|
|
@@ -515,7 +573,7 @@ const generateDesignAction = defineAction({
|
|
|
515
573
|
}));
|
|
516
574
|
await mutateDesignData({
|
|
517
575
|
designId,
|
|
518
|
-
mutate: (prevData) => {
|
|
576
|
+
mutate: (prevData, { updatedAt }) => {
|
|
519
577
|
const mergedData: Record<string, unknown> = {
|
|
520
578
|
...prevData,
|
|
521
579
|
lastPrompt: prompt,
|
|
@@ -525,34 +583,74 @@ const generateDesignAction = defineAction({
|
|
|
525
583
|
if (normalizedTweaks !== undefined) {
|
|
526
584
|
mergedData.tweaks = normalizedTweaks;
|
|
527
585
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
? placement.fileId
|
|
546
|
-
: undefined;
|
|
547
|
-
}
|
|
548
|
-
return placement.filename
|
|
549
|
-
? (savedByFilename.get(placement.filename)?.id ??
|
|
550
|
-
existingByName.get(placement.filename)?.id)
|
|
586
|
+
const savedByFileId = new Map(
|
|
587
|
+
savedFiles.map((file) => [file.id, file]),
|
|
588
|
+
);
|
|
589
|
+
const savedByFilename = new Map(
|
|
590
|
+
savedFiles.map((file) => [file.filename, file]),
|
|
591
|
+
);
|
|
592
|
+
const existingByFileId = new Map(
|
|
593
|
+
existingFiles.map((file) => [file.id, file]),
|
|
594
|
+
);
|
|
595
|
+
const merged = mergeCanvasFramePlacements({
|
|
596
|
+
existing: prevData.canvasFrames,
|
|
597
|
+
placements: canvasFrames ?? [],
|
|
598
|
+
resolveFileId: (placement) => {
|
|
599
|
+
if (placement.fileId) {
|
|
600
|
+
return savedByFileId.has(placement.fileId) ||
|
|
601
|
+
existingByFileId.has(placement.fileId)
|
|
602
|
+
? placement.fileId
|
|
551
603
|
: undefined;
|
|
552
|
-
}
|
|
604
|
+
}
|
|
605
|
+
return placement.filename
|
|
606
|
+
? (savedByFilename.get(placement.filename)?.id ??
|
|
607
|
+
existingByName.get(placement.filename)?.id)
|
|
608
|
+
: undefined;
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
const viewport = GENERATION_VIEWPORT_SIZES[primaryViewport];
|
|
612
|
+
let nextX = nextGeneratedFrameX(merged.canvasFrames);
|
|
613
|
+
const generationFrames = [...merged.placedFrames];
|
|
614
|
+
for (const file of savedFiles) {
|
|
615
|
+
const source = files.find(
|
|
616
|
+
(candidate) => candidate.filename === file.filename,
|
|
617
|
+
);
|
|
618
|
+
if (!source || !isRenderableDesignFile(source)) continue;
|
|
619
|
+
const current = merged.canvasFrames[file.id] ?? {};
|
|
620
|
+
if (
|
|
621
|
+
current.x !== undefined &&
|
|
622
|
+
current.y !== undefined &&
|
|
623
|
+
current.width !== undefined &&
|
|
624
|
+
current.height !== undefined
|
|
625
|
+
) {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const frame = {
|
|
629
|
+
x: current.x ?? nextX,
|
|
630
|
+
y: current.y ?? 0,
|
|
631
|
+
width: current.width ?? viewport.width,
|
|
632
|
+
height: current.height ?? viewport.height,
|
|
633
|
+
z: current.z ?? generationFrames.length,
|
|
634
|
+
...(current.rotation === undefined
|
|
635
|
+
? {}
|
|
636
|
+
: { rotation: current.rotation }),
|
|
637
|
+
};
|
|
638
|
+
merged.canvasFrames[file.id] = frame;
|
|
639
|
+
generationFrames.push({
|
|
640
|
+
fileId: file.id,
|
|
641
|
+
filename: file.filename,
|
|
642
|
+
frame,
|
|
553
643
|
});
|
|
554
|
-
|
|
555
|
-
|
|
644
|
+
nextX = frame.x + frame.width + GENERATED_FRAME_GAP;
|
|
645
|
+
}
|
|
646
|
+
mergedData.canvasFrames = merged.canvasFrames;
|
|
647
|
+
placedFrames = generationFrames;
|
|
648
|
+
if (!hasBreakpointSet(mergedData.breakpointSet)) {
|
|
649
|
+
mergedData.breakpointSet = {
|
|
650
|
+
id: "generated-responsive",
|
|
651
|
+
breakpoints: DEFAULT_RESPONSIVE_BREAKPOINTS,
|
|
652
|
+
};
|
|
653
|
+
mergedData.breakpointSetUpdatedAt = updatedAt;
|
|
556
654
|
}
|
|
557
655
|
return mergedData;
|
|
558
656
|
},
|
|
@@ -566,12 +664,10 @@ const generateDesignAction = defineAction({
|
|
|
566
664
|
) {
|
|
567
665
|
return false;
|
|
568
666
|
}
|
|
569
|
-
if (canvasFrames === undefined) return true;
|
|
570
|
-
|
|
571
667
|
const currentFrames = parseCanvasFrameGeometryById(
|
|
572
668
|
current.canvasFrames,
|
|
573
669
|
);
|
|
574
|
-
|
|
670
|
+
const framesApplied = Boolean(
|
|
575
671
|
placedFrames?.every(({ fileId, frame }) => {
|
|
576
672
|
const currentFrame = currentFrames[fileId];
|
|
577
673
|
return (
|
|
@@ -583,6 +679,7 @@ const generateDesignAction = defineAction({
|
|
|
583
679
|
);
|
|
584
680
|
}),
|
|
585
681
|
);
|
|
682
|
+
return framesApplied && hasBreakpointSet(current.breakpointSet);
|
|
586
683
|
},
|
|
587
684
|
});
|
|
588
685
|
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type CanvasFramePlacement,
|
|
20
20
|
} from "../shared/canvas-frames.js";
|
|
21
21
|
import { isUniqueConstraintViolation } from "../shared/db-conflict.js";
|
|
22
|
+
import { widthToPrefix } from "../shared/responsive-classes.js";
|
|
22
23
|
import { annotateScreenHtmlForPersist } from "../shared/screen-annotation.js";
|
|
23
24
|
|
|
24
25
|
const VARIANT_GAP = 96;
|
|
@@ -27,8 +28,22 @@ const MOBILE_WIDTH = 390;
|
|
|
27
28
|
const MOBILE_HEIGHT = 844;
|
|
28
29
|
const TABLET_WIDTH = 768;
|
|
29
30
|
const TABLET_HEIGHT = 1024;
|
|
30
|
-
const DESKTOP_WIDTH =
|
|
31
|
-
const DESKTOP_HEIGHT =
|
|
31
|
+
const DESKTOP_WIDTH = 1440;
|
|
32
|
+
const DESKTOP_HEIGHT = 1024;
|
|
33
|
+
const DEFAULT_RESPONSIVE_BREAKPOINTS = [390, 768, 1440].map((widthPx) => ({
|
|
34
|
+
id: `generated-${widthPx}`,
|
|
35
|
+
label: widthPx === 390 ? "Mobile" : widthPx === 768 ? "Tablet" : "Desktop",
|
|
36
|
+
widthPx,
|
|
37
|
+
prefix: widthToPrefix(widthPx),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
function hasBreakpointSet(value: unknown): boolean {
|
|
41
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const breakpoints = (value as { breakpoints?: unknown }).breakpoints;
|
|
45
|
+
return Array.isArray(breakpoints) && breakpoints.length > 0;
|
|
46
|
+
}
|
|
32
47
|
|
|
33
48
|
function designDeepLink(designId: string): string {
|
|
34
49
|
return buildDeepLink({
|
|
@@ -951,6 +966,15 @@ export default defineAction({
|
|
|
951
966
|
canvasFrames: mergedFrames.canvasFrames,
|
|
952
967
|
screenMetadata: previousMetadata,
|
|
953
968
|
designVariantSets: previousVariantSets,
|
|
969
|
+
...(hasBreakpointSet(current.breakpointSet)
|
|
970
|
+
? {}
|
|
971
|
+
: {
|
|
972
|
+
breakpointSet: {
|
|
973
|
+
id: "generated-responsive",
|
|
974
|
+
breakpoints: DEFAULT_RESPONSIVE_BREAKPOINTS,
|
|
975
|
+
},
|
|
976
|
+
breakpointSetUpdatedAt: updatedAt,
|
|
977
|
+
}),
|
|
954
978
|
updatedAt,
|
|
955
979
|
};
|
|
956
980
|
},
|
|
@@ -968,13 +992,17 @@ export default defineAction({
|
|
|
968
992
|
? variantSets[variantSetId]
|
|
969
993
|
: null;
|
|
970
994
|
const persistedScreens = Array.isArray(set?.screens) ? set.screens : [];
|
|
971
|
-
return
|
|
972
|
-
(
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
995
|
+
return (
|
|
996
|
+
hasBreakpointSet(current.breakpointSet) &&
|
|
997
|
+
screens.every(
|
|
998
|
+
(screen) =>
|
|
999
|
+
isRecord(canvasFrames[screen.id]) &&
|
|
1000
|
+
isRecord(metadata[screen.id]) &&
|
|
1001
|
+
persistedScreens.some(
|
|
1002
|
+
(persisted) =>
|
|
1003
|
+
isRecord(persisted) && persisted.id === screen.id,
|
|
1004
|
+
),
|
|
1005
|
+
)
|
|
978
1006
|
);
|
|
979
1007
|
},
|
|
980
1008
|
});
|
|
@@ -249,9 +249,6 @@ const EDITOR_BRIDGE_VAR_NAMES = [
|
|
|
249
249
|
"--design-editor-component-strong-color",
|
|
250
250
|
"--design-editor-component-contrast-color",
|
|
251
251
|
"--design-editor-measure-color",
|
|
252
|
-
"--background",
|
|
253
|
-
"--foreground",
|
|
254
|
-
"--border",
|
|
255
252
|
];
|
|
256
253
|
|
|
257
254
|
function readEditorBridgeThemeVars(): Record<string, string> {
|
|
@@ -1949,6 +1946,15 @@ export function DesignCanvas({
|
|
|
1949
1946
|
// iframe document here; the bridge replays inspector state after that load.
|
|
1950
1947
|
}, [content, contentKey, runtimeReplacementContent, runtimeReplacementKey]);
|
|
1951
1948
|
|
|
1949
|
+
useEffect(() => {
|
|
1950
|
+
if (!interactMode) return;
|
|
1951
|
+
// Interact renders the authoritative persisted source because the editor
|
|
1952
|
+
// bridge is intentionally absent. Keep that same source as the next
|
|
1953
|
+
// edit-mode baseline so leaving Interact cannot resurrect the older
|
|
1954
|
+
// bridge-managed snapshot and make the design visibly jump backward.
|
|
1955
|
+
setRenderedContent(content);
|
|
1956
|
+
}, [content, interactMode]);
|
|
1957
|
+
|
|
1952
1958
|
usePinchZoom({
|
|
1953
1959
|
containerRef: scrollContainerRef,
|
|
1954
1960
|
zoom,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
type PenPath,
|
|
43
43
|
} from "@shared/pen-path";
|
|
44
44
|
import {
|
|
45
|
+
IconArrowsMaximize,
|
|
45
46
|
IconCopy,
|
|
46
47
|
IconDots,
|
|
47
48
|
IconHandClick,
|
|
@@ -393,6 +394,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
393
394
|
hiddenScreenIds = EMPTY_SCREEN_IDS,
|
|
394
395
|
lockedScreenIds = EMPTY_SCREEN_IDS,
|
|
395
396
|
fullViewScreenIds,
|
|
397
|
+
interactMode = false,
|
|
396
398
|
activeScreenHasHoveredChild = false,
|
|
397
399
|
hoveredChildScreenId,
|
|
398
400
|
directlyHoveredScreenId,
|
|
@@ -7531,8 +7533,8 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
7531
7533
|
}}
|
|
7532
7534
|
editorChromeScaleX={canvasZoom / 100}
|
|
7533
7535
|
editorChromeScaleY={canvasZoom / 100}
|
|
7534
|
-
editMode={boardEditMode}
|
|
7535
|
-
interactMode={
|
|
7536
|
+
editMode={boardEditMode && !interactMode}
|
|
7537
|
+
interactMode={interactMode}
|
|
7536
7538
|
scaleMode={boardIsActive && effectiveTool === "scale"}
|
|
7537
7539
|
clearSelectionRequest={boardClearSelectionRequest}
|
|
7538
7540
|
selectedSelector={
|
|
@@ -7602,6 +7604,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
7602
7604
|
!isBreakpointSelectionTarget(screen)
|
|
7603
7605
|
}
|
|
7604
7606
|
showFullView={fullViewIdSet.has(screen.id)}
|
|
7607
|
+
interactMode={interactMode}
|
|
7605
7608
|
isDirectlyHovered={screen.id === directlyHoveredScreenId}
|
|
7606
7609
|
isFileDragOver={
|
|
7607
7610
|
fileDragOverFrameId !== null &&
|
|
@@ -8859,6 +8862,7 @@ interface ScreenProps {
|
|
|
8859
8862
|
isSelected: boolean;
|
|
8860
8863
|
isTopScreen: boolean;
|
|
8861
8864
|
showFullView: boolean;
|
|
8865
|
+
interactMode: boolean;
|
|
8862
8866
|
isDirectlyHovered: boolean;
|
|
8863
8867
|
/** True while a native OS file drag is hovering this frame (Figma parity §1). */
|
|
8864
8868
|
isFileDragOver: boolean;
|
|
@@ -8926,6 +8930,7 @@ const Screen = memo(function Screen({
|
|
|
8926
8930
|
isSelected,
|
|
8927
8931
|
isTopScreen,
|
|
8928
8932
|
showFullView,
|
|
8933
|
+
interactMode,
|
|
8929
8934
|
isDirectlyHovered,
|
|
8930
8935
|
isFileDragOver,
|
|
8931
8936
|
hasHoveredChild,
|
|
@@ -9022,9 +9027,12 @@ const Screen = memo(function Screen({
|
|
|
9022
9027
|
const frameLabelHeight = FRAME_LABEL_HEIGHT * chromeScale;
|
|
9023
9028
|
const frameScreenWidth = geometry.width / Math.max(chromeScale, 0.001);
|
|
9024
9029
|
// Keep frame actions inside their own frame so closely spaced screens cannot
|
|
9025
|
-
// cover one another. Narrow frames collapse
|
|
9030
|
+
// cover one another. Narrow frames collapse the action to its familiar icon;
|
|
9026
9031
|
// the accessible name and native tooltip preserve the action's meaning.
|
|
9027
9032
|
const compactFullView = frameScreenWidth < FRAME_HEADER_BUTTON_COMPACT_WIDTH;
|
|
9033
|
+
const frameActionLabel = interactMode
|
|
9034
|
+
? t("multiScreenCanvas.fullView")
|
|
9035
|
+
: t("designEditor.modes.interact");
|
|
9028
9036
|
const labelInfoMaxWidth = Math.max(
|
|
9029
9037
|
64,
|
|
9030
9038
|
frameScreenWidth -
|
|
@@ -9157,8 +9165,8 @@ const Screen = memo(function Screen({
|
|
|
9157
9165
|
transformOrigin: "right center",
|
|
9158
9166
|
transition: getChromeLabelTransition(chromeSettling),
|
|
9159
9167
|
}}
|
|
9160
|
-
aria-label={
|
|
9161
|
-
title={
|
|
9168
|
+
aria-label={frameActionLabel}
|
|
9169
|
+
title={frameActionLabel}
|
|
9162
9170
|
onClick={(event) => onEdit(screen.id, event)}
|
|
9163
9171
|
onMouseDown={(event) => {
|
|
9164
9172
|
event.preventDefault();
|
|
@@ -9167,9 +9175,13 @@ const Screen = memo(function Screen({
|
|
|
9167
9175
|
onMouseEnter={() => updateDirectHover(true)}
|
|
9168
9176
|
onMouseLeave={() => updateDirectHover(false)}
|
|
9169
9177
|
>
|
|
9170
|
-
|
|
9178
|
+
{interactMode ? (
|
|
9179
|
+
<IconArrowsMaximize className="size-3 shrink-0" />
|
|
9180
|
+
) : (
|
|
9181
|
+
<IconHandClick className="size-3 shrink-0" />
|
|
9182
|
+
)}
|
|
9171
9183
|
<span className={cn("truncate", compactFullView && "sr-only")}>
|
|
9172
|
-
{
|
|
9184
|
+
{frameActionLabel}
|
|
9173
9185
|
</span>
|
|
9174
9186
|
</button>
|
|
9175
9187
|
</div>
|
|
@@ -9394,6 +9406,7 @@ const Screen = memo(function Screen({
|
|
|
9394
9406
|
renderBreakpointContent={renderBreakpointContent}
|
|
9395
9407
|
activeBreakpointWidth={screen.activeBreakpointWidth}
|
|
9396
9408
|
isScreenSelected={isSelected}
|
|
9409
|
+
interactMode={interactMode}
|
|
9397
9410
|
penActive={penActive}
|
|
9398
9411
|
creationToolActive={creationToolActive}
|
|
9399
9412
|
cullTier={cullTier}
|
|
@@ -9518,6 +9531,7 @@ function BreakpointPreviewRow({
|
|
|
9518
9531
|
renderBreakpointContent,
|
|
9519
9532
|
activeBreakpointWidth,
|
|
9520
9533
|
isScreenSelected,
|
|
9534
|
+
interactMode,
|
|
9521
9535
|
penActive,
|
|
9522
9536
|
creationToolActive,
|
|
9523
9537
|
cullTier,
|
|
@@ -9559,6 +9573,7 @@ function BreakpointPreviewRow({
|
|
|
9559
9573
|
* mirrors `Screen`'s own `isSelected`, used so a breakpoint frame's chrome
|
|
9560
9574
|
* reads as "part of a selected group" the same way the base frame does. */
|
|
9561
9575
|
isScreenSelected: boolean;
|
|
9576
|
+
interactMode: boolean;
|
|
9562
9577
|
penActive: boolean;
|
|
9563
9578
|
creationToolActive: boolean;
|
|
9564
9579
|
/** Uses the owning screen's exact culling lifecycle: never-seen/evicted
|
|
@@ -9595,6 +9610,9 @@ function BreakpointPreviewRow({
|
|
|
9595
9610
|
canEdit?: boolean;
|
|
9596
9611
|
}) {
|
|
9597
9612
|
const t = useT();
|
|
9613
|
+
const frameActionLabel = interactMode
|
|
9614
|
+
? t("multiScreenCanvas.fullView")
|
|
9615
|
+
: t("designEditor.modes.interact");
|
|
9598
9616
|
const breakpointWidths = screen.breakpointWidths ?? [];
|
|
9599
9617
|
// Place additional frames to the right of the primary, starting after the gap
|
|
9600
9618
|
let offsetX = primaryGeometry.width + BREAKPOINT_FRAME_GAP;
|
|
@@ -9884,8 +9902,8 @@ function BreakpointPreviewRow({
|
|
|
9884
9902
|
transform: `scale(${chromeScale})`,
|
|
9885
9903
|
transformOrigin: "right center",
|
|
9886
9904
|
}}
|
|
9887
|
-
aria-label={
|
|
9888
|
-
title={
|
|
9905
|
+
aria-label={frameActionLabel}
|
|
9906
|
+
title={frameActionLabel}
|
|
9889
9907
|
onClick={(e) => {
|
|
9890
9908
|
e.stopPropagation();
|
|
9891
9909
|
activateThisFrame(e);
|
|
@@ -9896,7 +9914,11 @@ function BreakpointPreviewRow({
|
|
|
9896
9914
|
e.stopPropagation();
|
|
9897
9915
|
}}
|
|
9898
9916
|
>
|
|
9899
|
-
|
|
9917
|
+
{interactMode ? (
|
|
9918
|
+
<IconArrowsMaximize className="size-3" />
|
|
9919
|
+
) : (
|
|
9920
|
+
<IconHandClick className="size-3" />
|
|
9921
|
+
)}
|
|
9900
9922
|
</button>
|
|
9901
9923
|
) : null}
|
|
9902
9924
|
<span
|
|
@@ -340,7 +340,7 @@ function OptionButton({
|
|
|
340
340
|
compact ? "px-2.5 py-1.5" : "px-3 py-2",
|
|
341
341
|
selected
|
|
342
342
|
? "border-[var(--design-editor-accent-color)] bg-[var(--design-editor-selection-color)] text-foreground"
|
|
343
|
-
: "border-[var(--design-editor-control-border)] bg-[var(--design-editor-
|
|
343
|
+
: "border-[var(--design-editor-control-border)] bg-[var(--design-editor-question-option-bg)] text-foreground hover:bg-[var(--design-editor-control-bg)]",
|
|
344
344
|
)}
|
|
345
345
|
>
|
|
346
346
|
<span
|
|
@@ -418,7 +418,7 @@ function ColorOptions({
|
|
|
418
418
|
"group inline-flex min-h-8 min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-md border px-2.5 py-1.5 text-start transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--design-editor-accent-color)] focus-visible:ring-offset-0",
|
|
419
419
|
selected
|
|
420
420
|
? "border-[var(--design-editor-accent-color)] bg-[var(--design-editor-selection-color)] text-foreground"
|
|
421
|
-
: "border-[var(--design-editor-control-border)] bg-[var(--design-editor-
|
|
421
|
+
: "border-[var(--design-editor-control-border)] bg-[var(--design-editor-question-option-bg)] text-foreground hover:bg-[var(--design-editor-control-bg)]",
|
|
422
422
|
)}
|
|
423
423
|
>
|
|
424
424
|
<span
|