@agent-native/core 0.80.4 → 0.80.5
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 +21 -2
- package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
- package/corpus/core/docs/content/template-design.mdx +1 -1
- package/corpus/core/package.json +3 -7
- package/corpus/core/src/action.ts +21 -0
- package/corpus/core/src/agent/durable-background.ts +32 -11
- package/corpus/core/src/agent/production-agent.ts +11 -1
- package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
- package/corpus/core/src/brand-kit/fig/index.ts +17 -37
- package/corpus/core/src/cli/index.ts +1 -1
- package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
- package/corpus/core/src/cli/skills.ts +18 -3
- package/corpus/core/src/client/AssistantChat.tsx +11 -1
- package/corpus/core/src/client/agent-chat.ts +12 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
- package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
- package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
- package/corpus/core/src/collab/presence.ts +1 -1
- package/corpus/core/src/mcp/connect-route.ts +34 -5
- package/corpus/core/src/server/action-discovery.ts +4 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
- package/corpus/templates/assets/actions/generate-image.ts +3 -0
- package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
- package/corpus/templates/assets/netlify.toml +3 -3
- package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
- package/corpus/templates/content/AGENTS.md +12 -0
- package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
- package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
- package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
- package/corpus/templates/content/app/i18n-data.ts +140 -0
- package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
- package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
- package/corpus/templates/content/shared/builder-mdx.ts +141 -4
- package/corpus/templates/content/shared/nfm.ts +62 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/design/_gitignore +7 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
- package/corpus/templates/design/actions/create-design-system.ts +15 -4
- package/corpus/templates/design/actions/create-file.ts +20 -1
- package/corpus/templates/design/actions/delete-design-system.ts +2 -2
- package/corpus/templates/design/actions/duplicate-design.ts +35 -9
- package/corpus/templates/design/actions/generate-design.ts +146 -69
- package/corpus/templates/design/actions/generate-screens.ts +51 -19
- package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
- package/corpus/templates/design/actions/get-design.ts +2 -0
- package/corpus/templates/design/actions/import-design-project.ts +28 -9
- package/corpus/templates/design/actions/import-document.ts +22 -8
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/design/actions/navigate.ts +105 -54
- package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
- package/corpus/templates/design/actions/show-design-questions.ts +2 -0
- package/corpus/templates/design/actions/update-design.ts +2 -1
- package/corpus/templates/design/actions/view-screen.ts +12 -6
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
- package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
- package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
- package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
- package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
- package/corpus/templates/design/app/global.css +4 -0
- package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
- package/corpus/templates/design/app/i18n-data.ts +527 -0
- package/corpus/templates/design/app/lib/design-systems.ts +6 -4
- package/corpus/templates/design/app/lib/design-templates.ts +15 -3
- package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
- package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
- package/corpus/templates/design/app/root.tsx +42 -9
- package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
- package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
- package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
- package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
- package/corpus/templates/design/e2e/README.md +71 -0
- package/corpus/templates/design/e2e/global-setup.ts +157 -0
- package/corpus/templates/design/e2e/helpers.ts +148 -0
- package/corpus/templates/design/netlify.toml +3 -4
- package/corpus/templates/design/package.json +5 -1
- package/corpus/templates/design/playwright.config.ts +51 -0
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
- package/corpus/templates/design/server/handlers/uploads.ts +89 -38
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
- package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
- package/corpus/templates/design/server/lib/design-export.ts +35 -8
- package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/design/server/plugins/auth.ts +10 -1
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/corpus/templates/design/shared/api.ts +2 -0
- package/corpus/templates/design/shared/apply-edits.ts +12 -8
- package/corpus/templates/design/shared/canvas-math.ts +19 -1
- package/corpus/templates/design/shared/code-layer.ts +87 -28
- package/corpus/templates/design/shared/generation-session.ts +1 -0
- package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
- package/corpus/templates/design/shared/shader-presets.ts +10 -0
- package/corpus/templates/design/shared/source-mode.ts +9 -0
- package/corpus/templates/design/vitest.config.ts +2 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
- package/corpus/templates/plan/AGENTS.md +1 -1
- package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
- package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
- package/corpus/templates/plan/server/plan-content.ts +1 -1
- package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
- package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
- package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
- package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
- package/corpus/templates/slides/netlify.toml +3 -6
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
- package/dist/action.d.ts +15 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +6 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/durable-background.d.ts +9 -7
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +27 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +7 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +2 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +2 -2
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/brand-kit/fig/index.d.ts +4 -4
- package/dist/brand-kit/fig/index.d.ts.map +1 -1
- package/dist/brand-kit/fig/index.js +14 -27
- package/dist/brand-kit/fig/index.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +15 -7
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +198 -45
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/skills.d.ts +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +11 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +15 -2
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +35 -1
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -1
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +2 -15
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/collab/presence.d.ts +1 -1
- package/dist/collab/presence.js +1 -1
- package/dist/collab/presence.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -5
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ar-SA/template-design.mdx +1 -1
- package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
- package/docs/content/locales/de-DE/template-design.mdx +1 -1
- package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/es-ES/template-design.mdx +1 -1
- package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/fr-FR/template-design.mdx +1 -1
- package/docs/content/locales/hi-IN/template-design.mdx +1 -1
- package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ja-JP/template-design.mdx +1 -1
- package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/ko-KR/template-design.mdx +1 -1
- package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/pt-BR/template-design.mdx +1 -1
- package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-CN/template-design.mdx +1 -1
- package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
- package/docs/content/locales/zh-TW/template-design.mdx +1 -1
- package/docs/content/real-time-collaboration.mdx +2 -2
- package/docs/content/template-design.mdx +1 -1
- package/package.json +3 -7
- package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
- package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
- package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
- package/corpus/templates/design/actions/import-figma.ts +0 -55
- package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
- package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
- package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
- package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
- package/dist/brand-kit/fig/decode.d.ts +0 -33
- package/dist/brand-kit/fig/decode.d.ts.map +0 -1
- package/dist/brand-kit/fig/decode.js +0 -358
- package/dist/brand-kit/fig/decode.js.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
- package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
- package/dist/brand-kit/fig/extract-design-system.js +0 -752
- package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
- package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
- package/dist/brand-kit/fig/fig-to-html.js +0 -1506
- package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
|
@@ -902,7 +902,11 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
902
902
|
var key = e.key;
|
|
903
903
|
var normalized = key && key.length === 1 ? key.toLowerCase() : key;
|
|
904
904
|
var primary = e.metaKey || e.ctrlKey;
|
|
905
|
-
if (key === 'Escape' || key === 'Enter'
|
|
905
|
+
if (key === 'Escape' || key === 'Enter') return true;
|
|
906
|
+
// Forward Tab only when an element is actively selected so the iframe does
|
|
907
|
+
// not intercept Tab when the user is tabbing through browser UI with nothing
|
|
908
|
+
// selected (preserves native keyboard accessibility).
|
|
909
|
+
if (key === 'Tab') return !!selectedEl;
|
|
906
910
|
if (key === 'Delete' || key === 'Backspace') return !primary;
|
|
907
911
|
if (/^Arrow/.test(key || '')) return !e.altKey;
|
|
908
912
|
if (primary) {
|
|
@@ -955,7 +959,11 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
955
959
|
|
|
956
960
|
function isInlineEditableDescendant(el) {
|
|
957
961
|
if (!el || !el.tagName) return false;
|
|
962
|
+
// Allowlist covers inline markup AND common block-level text containers
|
|
963
|
+
// (p, h1-h6, li, etc.) so that paragraphs with inline markup like
|
|
964
|
+
// <p>Hello <strong>world</strong></p> can be double-click edited.
|
|
958
965
|
return [
|
|
966
|
+
// Inline formatting
|
|
959
967
|
'a',
|
|
960
968
|
'abbr',
|
|
961
969
|
'b',
|
|
@@ -972,7 +980,25 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
972
980
|
'sup',
|
|
973
981
|
'time',
|
|
974
982
|
'u',
|
|
975
|
-
'wbr'
|
|
983
|
+
'wbr',
|
|
984
|
+
// Block-level text containers
|
|
985
|
+
'p',
|
|
986
|
+
'h1',
|
|
987
|
+
'h2',
|
|
988
|
+
'h3',
|
|
989
|
+
'h4',
|
|
990
|
+
'h5',
|
|
991
|
+
'h6',
|
|
992
|
+
'li',
|
|
993
|
+
'ul',
|
|
994
|
+
'ol',
|
|
995
|
+
'dl',
|
|
996
|
+
'dt',
|
|
997
|
+
'dd',
|
|
998
|
+
'label',
|
|
999
|
+
'caption',
|
|
1000
|
+
'td',
|
|
1001
|
+
'th'
|
|
976
1002
|
].indexOf(el.tagName.toLowerCase()) !== -1;
|
|
977
1003
|
}
|
|
978
1004
|
|
|
@@ -999,14 +1025,27 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
999
1025
|
if (selectedEl && node === selectedEl) break;
|
|
1000
1026
|
node = node.parentElement;
|
|
1001
1027
|
}
|
|
1002
|
-
|
|
1028
|
+
// Return null (not the raw hit) when no text-editable ancestor is found.
|
|
1029
|
+
// Falling back to the raw hit element makes non-text nodes like <img> or
|
|
1030
|
+
// <canvas> contenteditable, which leaves the editor in a broken state.
|
|
1031
|
+
return candidate || null;
|
|
1003
1032
|
}
|
|
1004
1033
|
|
|
1005
1034
|
function selectElementAtEvent(e) {
|
|
1006
1035
|
stopNativeInteraction(e);
|
|
1007
1036
|
blurActiveTextEditor();
|
|
1037
|
+
// Suppress the first click in a double-click sequence — the dblclick
|
|
1038
|
+
// handler (beginTextEditingFromEvent) will fire immediately after and a
|
|
1039
|
+
// spurious element-select would cause inspector flicker.
|
|
1040
|
+
if (e.detail >= 2) return;
|
|
1008
1041
|
var target = elementFromEditorPoint(e.clientX, e.clientY);
|
|
1009
|
-
if (!target)
|
|
1042
|
+
if (!target || target === document.body || target === document.documentElement) {
|
|
1043
|
+
// Click on empty canvas: clear the current selection (matches Figma).
|
|
1044
|
+
selectedEl = null;
|
|
1045
|
+
selectionOverlay.style.display = 'none';
|
|
1046
|
+
window.parent.postMessage({ type: 'clear-selection' }, '*');
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1010
1049
|
selectedEl = target;
|
|
1011
1050
|
var info = getElementInfo(selectedEl);
|
|
1012
1051
|
positionOverlay(selectionOverlay, selectedEl);
|
|
@@ -1225,7 +1264,12 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1225
1264
|
function parentFlowAxis(parent) {
|
|
1226
1265
|
var cs = window.getComputedStyle(parent);
|
|
1227
1266
|
if (cs.display === 'flex' || cs.display === 'inline-flex') {
|
|
1228
|
-
|
|
1267
|
+
var isRow = cs.flexDirection && cs.flexDirection.indexOf('row') === 0;
|
|
1268
|
+
// Wrapping row containers need Y-axis awareness for inter-row targeting;
|
|
1269
|
+
// fall back to column-axis insertion so the heuristic picks the right row.
|
|
1270
|
+
var wraps = cs.flexWrap === 'wrap' || cs.flexWrap === 'wrap-reverse';
|
|
1271
|
+
if (isRow && !wraps) return 'x';
|
|
1272
|
+
return 'y';
|
|
1229
1273
|
}
|
|
1230
1274
|
if (cs.display === 'grid' || cs.display === 'inline-grid') {
|
|
1231
1275
|
var cols = (cs.gridTemplateColumns || '').split(' ').filter(Boolean).length;
|
|
@@ -1243,6 +1287,7 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1243
1287
|
hit !== document.documentElement &&
|
|
1244
1288
|
hit !== el &&
|
|
1245
1289
|
!el.contains(hit) &&
|
|
1290
|
+
!hit.contains(el) &&
|
|
1246
1291
|
!isOverlayElement(hit)
|
|
1247
1292
|
) {
|
|
1248
1293
|
var hitChildren = draggableElementChildren(hit).filter(function(child) {
|
|
@@ -1383,10 +1428,13 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1383
1428
|
window.parent.postMessage({ type: 'element-select', payload: getElementInfo(selectedEl) }, '*');
|
|
1384
1429
|
}
|
|
1385
1430
|
if (isFlowReorderCandidate(selectedEl)) {
|
|
1386
|
-
|
|
1431
|
+
// Snapshot the element being reordered so a concurrent select-element or
|
|
1432
|
+
// clear-selection postMessage cannot mutate the wrong element mid-drag.
|
|
1433
|
+
var reorderEl = selectedEl;
|
|
1434
|
+
var currentTarget = reorderTargetForPoint(reorderEl, e.clientX, e.clientY);
|
|
1387
1435
|
showInsertionGuideFor(currentTarget);
|
|
1388
1436
|
function onReorderMove(ev) {
|
|
1389
|
-
currentTarget = reorderTargetForPoint(
|
|
1437
|
+
currentTarget = reorderTargetForPoint(reorderEl, ev.clientX, ev.clientY);
|
|
1390
1438
|
showInsertionGuideFor(currentTarget);
|
|
1391
1439
|
showTransformBadge(currentTarget ? 'Move layer' : 'Move', ev.clientX, ev.clientY);
|
|
1392
1440
|
}
|
|
@@ -1395,12 +1443,27 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1395
1443
|
document.removeEventListener('mouseup', onReorderUp, true);
|
|
1396
1444
|
hideTransformBadge();
|
|
1397
1445
|
hideInsertionGuide();
|
|
1398
|
-
if (!currentTarget)
|
|
1446
|
+
if (!currentTarget) {
|
|
1447
|
+
// No valid drop target — clean up the clone if one was inserted so
|
|
1448
|
+
// no ghost element is left in the DOM.
|
|
1449
|
+
if (duplicatedForDrag && reorderEl && reorderEl !== originalSelectedEl) {
|
|
1450
|
+
if (reorderEl.parentElement) reorderEl.parentElement.removeChild(reorderEl);
|
|
1451
|
+
selectedEl = originalSelectedEl;
|
|
1452
|
+
positionOverlay(selectionOverlay, selectedEl);
|
|
1453
|
+
window.parent.postMessage({ type: 'element-select', payload: getElementInfo(selectedEl) }, '*');
|
|
1454
|
+
}
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1399
1457
|
if (duplicatedForDrag) {
|
|
1400
|
-
applyRuntimeReorder(
|
|
1401
|
-
postVisualDuplicateChange(originalSelectedEl,
|
|
1458
|
+
applyRuntimeReorder(reorderEl, currentTarget);
|
|
1459
|
+
postVisualDuplicateChange(originalSelectedEl, reorderEl, currentTarget);
|
|
1460
|
+
} else {
|
|
1461
|
+
// Optimistically apply the reorder in the DOM for immediate
|
|
1462
|
+
// visual feedback; the visual-structure-ack handler will confirm
|
|
1463
|
+
// or revert once the parent processes the change.
|
|
1464
|
+
applyRuntimeReorder(reorderEl, currentTarget);
|
|
1465
|
+
postVisualStructureChange(reorderEl, currentTarget);
|
|
1402
1466
|
}
|
|
1403
|
-
else postVisualStructureChange(selectedEl, currentTarget);
|
|
1404
1467
|
}
|
|
1405
1468
|
document.addEventListener('mousemove', onReorderMove, true);
|
|
1406
1469
|
document.addEventListener('mouseup', onReorderUp, true);
|
|
@@ -1412,11 +1475,15 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1412
1475
|
var originTop = readPx(selectedEl.style.top || cs.top);
|
|
1413
1476
|
var startX = e.clientX;
|
|
1414
1477
|
var startY = e.clientY;
|
|
1478
|
+
// Snapshot the element being moved so that a concurrent select-element or
|
|
1479
|
+
// clear-selection postMessage cannot swap selectedEl mid-drag and cause
|
|
1480
|
+
// mutations on the wrong element or a null-deref in onUp.
|
|
1481
|
+
var dragEl = selectedEl;
|
|
1415
1482
|
function onMove(ev) {
|
|
1416
1483
|
var nextLeft = originLeft + ev.clientX - startX;
|
|
1417
1484
|
var nextTop = originTop + ev.clientY - startY;
|
|
1418
|
-
|
|
1419
|
-
|
|
1485
|
+
dragEl.style.left = Math.round(nextLeft) + 'px';
|
|
1486
|
+
dragEl.style.top = Math.round(nextTop) + 'px';
|
|
1420
1487
|
showTransformBadge('X ' + Math.round(nextLeft) + ' Y ' + Math.round(nextTop), ev.clientX, ev.clientY);
|
|
1421
1488
|
refreshOverlays();
|
|
1422
1489
|
}
|
|
@@ -1424,14 +1491,20 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1424
1491
|
document.removeEventListener('mousemove', onMove, true);
|
|
1425
1492
|
document.removeEventListener('mouseup', onUp, true);
|
|
1426
1493
|
hideTransformBadge();
|
|
1494
|
+
if (!dragEl) return;
|
|
1427
1495
|
if (duplicatedForDrag) {
|
|
1428
|
-
postVisualDuplicateChange(originalSelectedEl,
|
|
1496
|
+
postVisualDuplicateChange(originalSelectedEl, dragEl);
|
|
1429
1497
|
} else {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1498
|
+
window.parent.postMessage({
|
|
1499
|
+
type: 'visual-style-change',
|
|
1500
|
+
selector: getSelector(dragEl),
|
|
1501
|
+
styles: {
|
|
1502
|
+
position: dragEl.style.position,
|
|
1503
|
+
left: dragEl.style.left,
|
|
1504
|
+
top: dragEl.style.top,
|
|
1505
|
+
},
|
|
1506
|
+
payload: getElementInfo(dragEl),
|
|
1507
|
+
}, '*');
|
|
1435
1508
|
}
|
|
1436
1509
|
}
|
|
1437
1510
|
document.addEventListener('mousemove', onMove, true);
|
|
@@ -1445,15 +1518,23 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1445
1518
|
e.stopPropagation();
|
|
1446
1519
|
ensurePositionable(selectedEl);
|
|
1447
1520
|
var cs = window.getComputedStyle(selectedEl);
|
|
1521
|
+
// Bug fix: use CSS width/height (not getBoundingClientRect) for the resize
|
|
1522
|
+
// origin dimensions so that rotated elements don't use the inflated
|
|
1523
|
+
// axis-aligned bounding box as the starting size.
|
|
1524
|
+
var originW = readPx(selectedEl.style.width || cs.width);
|
|
1525
|
+
var originH = readPx(selectedEl.style.height || cs.height);
|
|
1448
1526
|
var origin = {
|
|
1449
1527
|
left: readPx(selectedEl.style.left || cs.left),
|
|
1450
1528
|
top: readPx(selectedEl.style.top || cs.top),
|
|
1451
|
-
width:
|
|
1452
|
-
height:
|
|
1453
|
-
ratio:
|
|
1529
|
+
width: originW,
|
|
1530
|
+
height: originH,
|
|
1531
|
+
ratio: originW / Math.max(1, originH),
|
|
1454
1532
|
};
|
|
1455
1533
|
var startX = e.clientX;
|
|
1456
1534
|
var startY = e.clientY;
|
|
1535
|
+
// Snapshot the element so a concurrent clear-selection postMessage cannot
|
|
1536
|
+
// cause a null-deref in onMove/onUp.
|
|
1537
|
+
var resizeEl = selectedEl;
|
|
1457
1538
|
function nextRect(ev) {
|
|
1458
1539
|
var dx = ev.clientX - startX;
|
|
1459
1540
|
var dy = ev.clientY - startY;
|
|
@@ -1471,12 +1552,32 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1471
1552
|
height = origin.height - dy;
|
|
1472
1553
|
}
|
|
1473
1554
|
if (handle.indexOf('s') !== -1) height = origin.height + dy;
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
if (
|
|
1555
|
+
// Apply Shift / scaleToolEnabled aspect-ratio lock BEFORE the min-size
|
|
1556
|
+
// clamp so the ratio is computed from unclamped values (bug fix).
|
|
1557
|
+
if (ev.shiftKey && handle.length === 2) {
|
|
1477
1558
|
if (Math.abs(dx) > Math.abs(dy)) height = width / origin.ratio;
|
|
1478
1559
|
else width = height * origin.ratio;
|
|
1479
1560
|
}
|
|
1561
|
+
if (scaleToolEnabled) {
|
|
1562
|
+
// Scale tool: enforce aspect ratio on all 8 handles, not just corners.
|
|
1563
|
+
if (handle === 'e' || handle === 'w') {
|
|
1564
|
+
height = width / origin.ratio;
|
|
1565
|
+
} else if (handle === 'n' || handle === 's') {
|
|
1566
|
+
width = height * origin.ratio;
|
|
1567
|
+
} else if (handle.length === 2) {
|
|
1568
|
+
if (Math.abs(dx) > Math.abs(dy)) height = width / origin.ratio;
|
|
1569
|
+
else width = height * origin.ratio;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
// Clamp after ratio correction.
|
|
1573
|
+
var rawWidth = width;
|
|
1574
|
+
var rawHeight = height;
|
|
1575
|
+
width = Math.max(8, width);
|
|
1576
|
+
height = Math.max(8, height);
|
|
1577
|
+
// Re-anchor the pinned edge for w/n handles after clamping so the
|
|
1578
|
+
// opposite edge doesn't drift when the element hits minimum size.
|
|
1579
|
+
if (handle.indexOf('w') !== -1) left += (rawWidth - width);
|
|
1580
|
+
if (handle.indexOf('n') !== -1) top += (rawHeight - height);
|
|
1480
1581
|
if (ev.altKey) {
|
|
1481
1582
|
if (handle.indexOf('w') !== -1 || handle.indexOf('e') !== -1) left = origin.left - (width - origin.width) / 2;
|
|
1482
1583
|
if (handle.indexOf('n') !== -1 || handle.indexOf('s') !== -1) top = origin.top - (height - origin.height) / 2;
|
|
@@ -1484,11 +1585,12 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1484
1585
|
return { left: left, top: top, width: width, height: height };
|
|
1485
1586
|
}
|
|
1486
1587
|
function onMove(ev) {
|
|
1588
|
+
if (!resizeEl) return;
|
|
1487
1589
|
var rect = nextRect(ev);
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1590
|
+
resizeEl.style.left = Math.round(rect.left) + 'px';
|
|
1591
|
+
resizeEl.style.top = Math.round(rect.top) + 'px';
|
|
1592
|
+
resizeEl.style.width = Math.round(rect.width) + 'px';
|
|
1593
|
+
resizeEl.style.height = Math.round(rect.height) + 'px';
|
|
1492
1594
|
showTransformBadge(Math.round(rect.width) + ' x ' + Math.round(rect.height), ev.clientX, ev.clientY);
|
|
1493
1595
|
refreshOverlays();
|
|
1494
1596
|
}
|
|
@@ -1496,13 +1598,19 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1496
1598
|
document.removeEventListener('mousemove', onMove, true);
|
|
1497
1599
|
document.removeEventListener('mouseup', onUp, true);
|
|
1498
1600
|
hideTransformBadge();
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1601
|
+
if (!resizeEl) return;
|
|
1602
|
+
window.parent.postMessage({
|
|
1603
|
+
type: 'visual-style-change',
|
|
1604
|
+
selector: getSelector(resizeEl),
|
|
1605
|
+
styles: {
|
|
1606
|
+
position: resizeEl.style.position,
|
|
1607
|
+
left: resizeEl.style.left,
|
|
1608
|
+
top: resizeEl.style.top,
|
|
1609
|
+
width: resizeEl.style.width,
|
|
1610
|
+
height: resizeEl.style.height,
|
|
1611
|
+
},
|
|
1612
|
+
payload: getElementInfo(resizeEl),
|
|
1613
|
+
}, '*');
|
|
1506
1614
|
}
|
|
1507
1615
|
document.addEventListener('mousemove', onMove, true);
|
|
1508
1616
|
document.addEventListener('mouseup', onUp, true);
|
|
@@ -1513,16 +1621,22 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1513
1621
|
if (isLayerInteractionBlocked(selectedEl)) return;
|
|
1514
1622
|
e.preventDefault();
|
|
1515
1623
|
e.stopPropagation();
|
|
1624
|
+
// getBoundingClientRect is correct here — we only need the element center
|
|
1625
|
+
// for angle math, and the element's visual position is what we want.
|
|
1516
1626
|
var rect = selectedEl.getBoundingClientRect();
|
|
1517
1627
|
var center = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
|
1518
1628
|
var originAngle = Math.atan2(e.clientY - center.y, e.clientX - center.x) * 180 / Math.PI;
|
|
1519
1629
|
var originRotation = currentRotation(selectedEl);
|
|
1630
|
+
// Snapshot so a concurrent clear-selection postMessage cannot cause a
|
|
1631
|
+
// null-deref in onMove/onUp.
|
|
1632
|
+
var rotateEl = selectedEl;
|
|
1520
1633
|
function onMove(ev) {
|
|
1634
|
+
if (!rotateEl) return;
|
|
1521
1635
|
var pointerAngle = Math.atan2(ev.clientY - center.y, ev.clientX - center.x) * 180 / Math.PI;
|
|
1522
1636
|
var next = originRotation + pointerAngle - originAngle;
|
|
1523
1637
|
if (ev.shiftKey) next = Math.round(next / 15) * 15;
|
|
1524
1638
|
next = Math.round(next);
|
|
1525
|
-
|
|
1639
|
+
rotateEl.style.transform = mergeRotation(rotateEl, next);
|
|
1526
1640
|
showTransformBadge(next + 'deg', ev.clientX, ev.clientY);
|
|
1527
1641
|
refreshOverlays();
|
|
1528
1642
|
}
|
|
@@ -1530,9 +1644,13 @@ const EDITOR_CHROME_BRIDGE_SCRIPT = `
|
|
|
1530
1644
|
document.removeEventListener('mousemove', onMove, true);
|
|
1531
1645
|
document.removeEventListener('mouseup', onUp, true);
|
|
1532
1646
|
hideTransformBadge();
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1647
|
+
if (!rotateEl) return;
|
|
1648
|
+
window.parent.postMessage({
|
|
1649
|
+
type: 'visual-style-change',
|
|
1650
|
+
selector: getSelector(rotateEl),
|
|
1651
|
+
styles: { transform: rotateEl.style.transform },
|
|
1652
|
+
payload: getElementInfo(rotateEl),
|
|
1653
|
+
}, '*');
|
|
1536
1654
|
}
|
|
1537
1655
|
document.addEventListener('mousemove', onMove, true);
|
|
1538
1656
|
document.addEventListener('mouseup', onUp, true);
|
|
@@ -2531,7 +2649,7 @@ export function DesignCanvas({
|
|
|
2531
2649
|
sandbox={
|
|
2532
2650
|
externalPreviewUrl
|
|
2533
2651
|
? "allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin"
|
|
2534
|
-
: "allow-scripts allow-popups allow-popups-to-escape-sandbox"
|
|
2652
|
+
: "allow-scripts allow-popups allow-popups-to-escape-sandbox allow-same-origin"
|
|
2535
2653
|
}
|
|
2536
2654
|
data-design-preview-iframe
|
|
2537
2655
|
className="block h-full w-full border-0 bg-transparent"
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "@tabler/icons-react";
|
|
17
17
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
18
18
|
import { useMemo, useState } from "react";
|
|
19
|
+
import { toast } from "sonner";
|
|
19
20
|
|
|
20
21
|
import { Button } from "@/components/ui/button";
|
|
21
22
|
import {
|
|
@@ -207,7 +208,7 @@ export function DesignExtensionsPanel({
|
|
|
207
208
|
const installExtension = async (extensionId: string) => {
|
|
208
209
|
setInstallingId(extensionId);
|
|
209
210
|
try {
|
|
210
|
-
await fetch(
|
|
211
|
+
const res = await fetch(
|
|
211
212
|
agentNativePath(
|
|
212
213
|
`/_agent-native/slots/${encodeURIComponent(slotId)}/install`,
|
|
213
214
|
),
|
|
@@ -217,20 +218,23 @@ export function DesignExtensionsPanel({
|
|
|
217
218
|
body: JSON.stringify({ extensionId }),
|
|
218
219
|
},
|
|
219
220
|
);
|
|
220
|
-
|
|
221
|
-
setInstallingId(null);
|
|
221
|
+
if (!res.ok) throw new Error(`Install failed: ${res.status}`);
|
|
222
222
|
queryClient.invalidateQueries({
|
|
223
223
|
queryKey: ["design-editor-extension-slot"],
|
|
224
224
|
});
|
|
225
225
|
queryClient.invalidateQueries({
|
|
226
226
|
queryKey: ["design-editor-extension-slot-available"],
|
|
227
227
|
});
|
|
228
|
+
} catch {
|
|
229
|
+
toast.error(t("designEditor.extensionsInstallError"));
|
|
230
|
+
} finally {
|
|
231
|
+
setInstallingId(null);
|
|
228
232
|
}
|
|
229
233
|
};
|
|
230
234
|
|
|
231
235
|
return (
|
|
232
236
|
<div className={cn("flex min-h-0 flex-1 flex-col", className)}>
|
|
233
|
-
{/* Section header — 32 px tall, matches PanelSection /
|
|
237
|
+
{/* Section header — 32 px tall, matches PanelSection / design inspector headers */}
|
|
234
238
|
<div className="flex min-h-8 shrink-0 items-center gap-1.5 border-b border-border/60 px-3">
|
|
235
239
|
<h3 className="min-w-0 flex-1 truncate text-xs font-semibold text-foreground">
|
|
236
240
|
{t("designEditor.extensions")}
|
|
@@ -172,56 +172,51 @@ export function DrawOverlay({ visible, onQueue, onSend }: DrawOverlayProps) {
|
|
|
172
172
|
const queueDrawing = () => {
|
|
173
173
|
if (strokes.length === 0) return;
|
|
174
174
|
|
|
175
|
-
// Convert
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
175
|
+
// Convert each stroke into its own annotation to preserve per-stroke color/lineWidth
|
|
176
|
+
const newAnnotations: DrawAnnotation[] = strokes.map((s) => {
|
|
177
|
+
const pathData = s.points
|
|
178
|
+
.map(
|
|
179
|
+
(p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`,
|
|
180
|
+
)
|
|
181
|
+
.join(" ");
|
|
182
|
+
return {
|
|
183
|
+
id: crypto.randomUUID(),
|
|
184
|
+
type: "path",
|
|
185
|
+
pathData,
|
|
186
|
+
position: { x: 0, y: 0 },
|
|
187
|
+
color: s.color,
|
|
188
|
+
lineWidth: s.lineWidth,
|
|
189
|
+
};
|
|
190
|
+
});
|
|
187
191
|
|
|
188
|
-
const annotation
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
position: { x: 0, y: 0 },
|
|
193
|
-
color,
|
|
194
|
-
lineWidth,
|
|
195
|
-
};
|
|
196
|
-
onQueue(annotation);
|
|
197
|
-
setQueued((prev) => [...prev, annotation]);
|
|
192
|
+
for (const annotation of newAnnotations) {
|
|
193
|
+
onQueue(annotation);
|
|
194
|
+
}
|
|
195
|
+
setQueued((prev) => [...prev, ...newAnnotations]);
|
|
198
196
|
setStrokes([]);
|
|
199
197
|
};
|
|
200
198
|
|
|
201
199
|
const sendAll = () => {
|
|
202
|
-
// Queue current drawing first if any
|
|
200
|
+
// Queue current drawing first if any; preserve per-stroke color/lineWidth
|
|
203
201
|
let allAnnotations = [...queued];
|
|
204
202
|
if (strokes.length > 0) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
(p
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
pathData,
|
|
221
|
-
position: { x: 0, y: 0 },
|
|
222
|
-
color,
|
|
223
|
-
lineWidth,
|
|
203
|
+
const strokeAnnotations: DrawAnnotation[] = strokes.map((s) => {
|
|
204
|
+
const pathData = s.points
|
|
205
|
+
.map(
|
|
206
|
+
(p, i) =>
|
|
207
|
+
`${i === 0 ? "M" : "L"}${p.x.toFixed(1)},${p.y.toFixed(1)}`,
|
|
208
|
+
)
|
|
209
|
+
.join(" ");
|
|
210
|
+
return {
|
|
211
|
+
id: crypto.randomUUID(),
|
|
212
|
+
type: "path",
|
|
213
|
+
pathData,
|
|
214
|
+
position: { x: 0, y: 0 },
|
|
215
|
+
color: s.color,
|
|
216
|
+
lineWidth: s.lineWidth,
|
|
217
|
+
};
|
|
224
218
|
});
|
|
219
|
+
allAnnotations = [...allAnnotations, ...strokeAnnotations];
|
|
225
220
|
}
|
|
226
221
|
|
|
227
222
|
if (allAnnotations.length > 0) {
|