@agent-native/core 0.80.2 → 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 +66 -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 +32 -0
- package/corpus/core/src/agent/durable-background.ts +32 -11
- package/corpus/core/src/agent/production-agent.ts +14 -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/plan-local.ts +445 -108
- package/corpus/core/src/cli/skills.ts +32 -8
- 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/action-routes.ts +14 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
- package/corpus/core/src/vite/client.ts +15 -1
- 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/player/timestamped-comment-button.tsx +162 -0
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +42 -18
- 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/skills/visual-plan/references/local-files.md +14 -5
- package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +14 -5
- 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 +110 -0
- 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/lib/plan-connector-catalog.ts +1 -0
- package/corpus/templates/plan/server/lib/public-action-paths.ts +1 -0
- 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 +23 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +9 -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 +10 -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/plan-local.d.ts +30 -0
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +281 -56
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +32 -8
- 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/file-upload/actions/upload-image.d.ts +2 -2
- 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/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- 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/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +14 -0
- package/dist/server/action-routes.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/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +12 -1
- package/dist/vite/client.js.map +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
|
@@ -52,10 +52,10 @@ import { ShaderFillsPanel, shaderDescriptorToCss } from "./ShaderFillsPanel";
|
|
|
52
52
|
|
|
53
53
|
// ─── Public types ──────────────────────────────────────────────────────────────
|
|
54
54
|
|
|
55
|
-
export type
|
|
56
|
-
export type
|
|
57
|
-
export type
|
|
58
|
-
export type
|
|
55
|
+
export type DesignColorMode = "hex" | "rgb" | "hsl" | "hsb";
|
|
56
|
+
export type DesignGradientType = "linear" | "radial" | "angular" | "diamond";
|
|
57
|
+
export type DesignFillType = "solid" | "gradient" | "image";
|
|
58
|
+
export type DesignPaintType =
|
|
59
59
|
| "solid"
|
|
60
60
|
| "linear"
|
|
61
61
|
| "radial"
|
|
@@ -70,22 +70,22 @@ export type FigmaPaintType =
|
|
|
70
70
|
|
|
71
71
|
// These interfaces remain so EditPanel's prop types don't break, even though
|
|
72
72
|
// the popover no longer renders the fills/gradient-stops list.
|
|
73
|
-
export interface
|
|
73
|
+
export interface DesignFillRow {
|
|
74
74
|
id: string;
|
|
75
75
|
label: string;
|
|
76
76
|
value: string;
|
|
77
|
-
type:
|
|
77
|
+
type: DesignFillType;
|
|
78
78
|
opacity?: number;
|
|
79
79
|
swatch?: string;
|
|
80
80
|
selected?: boolean;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
export interface
|
|
83
|
+
export interface DesignFillRowPatch {
|
|
84
84
|
value?: string;
|
|
85
85
|
opacity?: number;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export interface
|
|
88
|
+
export interface DesignGradientStop {
|
|
89
89
|
id: string;
|
|
90
90
|
color: string;
|
|
91
91
|
position: number;
|
|
@@ -93,13 +93,13 @@ export interface FigmaGradientStop {
|
|
|
93
93
|
label?: string;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
export interface
|
|
96
|
+
export interface DesignGradientStopPatch {
|
|
97
97
|
color?: string;
|
|
98
98
|
position?: number;
|
|
99
99
|
opacity?: number;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
export interface
|
|
102
|
+
export interface DesignColorPickerLabels {
|
|
103
103
|
trigger: string;
|
|
104
104
|
hex: string;
|
|
105
105
|
red: string;
|
|
@@ -126,7 +126,7 @@ export interface FigmaColorPickerLabels {
|
|
|
126
126
|
diamond: string;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
export interface
|
|
129
|
+
export interface DesignColorPickerProps {
|
|
130
130
|
value: string;
|
|
131
131
|
onChange: (value: string) => void;
|
|
132
132
|
onPaintValueChange?: (value: string) => void;
|
|
@@ -137,21 +137,21 @@ export interface FigmaColorPickerProps {
|
|
|
137
137
|
onBlendModeChange?: (mode: string) => void;
|
|
138
138
|
showBlendMode?: boolean;
|
|
139
139
|
// Accepted but unused in the popover — list management lives in the sidebar.
|
|
140
|
-
fillRows?:
|
|
140
|
+
fillRows?: DesignFillRow[];
|
|
141
141
|
selectedFillId?: string;
|
|
142
142
|
onFillSelect?: (id: string) => void;
|
|
143
|
-
onFillChange?: (id: string, patch:
|
|
143
|
+
onFillChange?: (id: string, patch: DesignFillRowPatch) => void;
|
|
144
144
|
onAddFill?: () => void;
|
|
145
145
|
onRemoveFill?: (id: string) => void;
|
|
146
|
-
paintType?:
|
|
147
|
-
onPaintTypeChange?: (type:
|
|
148
|
-
gradientType?:
|
|
149
|
-
onGradientTypeChange?: (type:
|
|
146
|
+
paintType?: DesignPaintType;
|
|
147
|
+
onPaintTypeChange?: (type: DesignPaintType) => void;
|
|
148
|
+
gradientType?: DesignGradientType;
|
|
149
|
+
onGradientTypeChange?: (type: DesignGradientType) => void;
|
|
150
150
|
// Accepted but unused in the popover — gradient stop handles belong on canvas.
|
|
151
|
-
gradientStops?:
|
|
151
|
+
gradientStops?: DesignGradientStop[];
|
|
152
152
|
selectedStopId?: string;
|
|
153
153
|
onGradientStopSelect?: (id: string) => void;
|
|
154
|
-
onGradientStopChange?: (id: string, patch:
|
|
154
|
+
onGradientStopChange?: (id: string, patch: DesignGradientStopPatch) => void;
|
|
155
155
|
onAddGradientStop?: () => void;
|
|
156
156
|
onRemoveGradientStop?: (id: string) => void;
|
|
157
157
|
/**
|
|
@@ -173,7 +173,7 @@ export interface FigmaColorPickerProps {
|
|
|
173
173
|
};
|
|
174
174
|
/** Notified when a shader fill is applied/tuned (descriptor + CSS fallback). */
|
|
175
175
|
onShaderChange?: (descriptor: ShaderDescriptor, css: string) => void;
|
|
176
|
-
labels?: Partial<
|
|
176
|
+
labels?: Partial<DesignColorPickerLabels>;
|
|
177
177
|
disabled?: boolean;
|
|
178
178
|
className?: string;
|
|
179
179
|
}
|
|
@@ -191,7 +191,7 @@ interface HsvaColor {
|
|
|
191
191
|
|
|
192
192
|
const FALLBACK_COLOR: RgbaColor = { r: 0, g: 0, b: 0, a: 1 };
|
|
193
193
|
|
|
194
|
-
const DEFAULT_LABELS:
|
|
194
|
+
const DEFAULT_LABELS: DesignColorPickerLabels = {
|
|
195
195
|
trigger: "Open color picker", // i18n-ignore fallback component label
|
|
196
196
|
hex: "Hex", // i18n-ignore fallback component label
|
|
197
197
|
red: "R", // i18n-ignore fallback component label
|
|
@@ -218,7 +218,7 @@ const DEFAULT_LABELS: FigmaColorPickerLabels = {
|
|
|
218
218
|
diamond: "Diamond", // i18n-ignore fallback component label
|
|
219
219
|
};
|
|
220
220
|
|
|
221
|
-
//
|
|
221
|
+
// checkerboard: explicit light/dark tiles for legibility.
|
|
222
222
|
const CHECKER_A = "#d4d4d4";
|
|
223
223
|
const CHECKER_B = "#a3a3a3";
|
|
224
224
|
const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
|
|
@@ -448,7 +448,7 @@ function IconNoneFill({ className }: { className?: string }) {
|
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
function IconShaderFill({ className }: { className?: string }) {
|
|
451
|
-
// Droplet —
|
|
451
|
+
// Droplet — the design editor uses a teardrop for shader/blur-type fills.
|
|
452
452
|
return (
|
|
453
453
|
<svg
|
|
454
454
|
viewBox="0 0 24 24"
|
|
@@ -534,7 +534,7 @@ function IconPatternFill({ className }: { className?: string }) {
|
|
|
534
534
|
// ─── Paint type definitions (only supported types rendered) ────────────────────
|
|
535
535
|
|
|
536
536
|
const PAINT_TYPES: Array<{
|
|
537
|
-
type:
|
|
537
|
+
type: DesignPaintType;
|
|
538
538
|
label: string;
|
|
539
539
|
Icon: (props: { className?: string }) => JSX.Element;
|
|
540
540
|
}> = [
|
|
@@ -555,7 +555,7 @@ const PAINT_TYPES: Array<{
|
|
|
555
555
|
// Both point at the same member set — keep reads using this name so the
|
|
556
556
|
// component body compiles even though the exported constant is declared
|
|
557
557
|
// at the bottom of the file (hoisting doesn't apply to const).
|
|
558
|
-
const GRADIENT_TYPES = new Set<
|
|
558
|
+
const GRADIENT_TYPES = new Set<DesignPaintType>([
|
|
559
559
|
"linear",
|
|
560
560
|
"radial",
|
|
561
561
|
"angular",
|
|
@@ -571,7 +571,7 @@ const PATTERN_FALLBACK_CSS =
|
|
|
571
571
|
|
|
572
572
|
// ─── Main component ────────────────────────────────────────────────────────────
|
|
573
573
|
|
|
574
|
-
export function
|
|
574
|
+
export function DesignColorPicker({
|
|
575
575
|
value,
|
|
576
576
|
onChange,
|
|
577
577
|
onPaintValueChange,
|
|
@@ -603,24 +603,28 @@ export function FigmaColorPicker({
|
|
|
603
603
|
labels,
|
|
604
604
|
disabled = false,
|
|
605
605
|
className,
|
|
606
|
-
}:
|
|
606
|
+
}: DesignColorPickerProps) {
|
|
607
607
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
608
608
|
const color = parseCssColor(value) ?? FALLBACK_COLOR;
|
|
609
609
|
const hsv = rgbaToHsv(color);
|
|
610
610
|
const hsl = rgbaToHsl(color);
|
|
611
611
|
const effectiveOpacity = opacity ?? alphaToOpacity(color.a);
|
|
612
612
|
|
|
613
|
-
const [mode, setMode] = useState<
|
|
613
|
+
const [mode, setMode] = useState<DesignColorMode>("hex");
|
|
614
614
|
const [hexDraft, setHexDraft] = useState(() => toDisplayHex(color));
|
|
615
615
|
const [open, setOpen] = useState(false);
|
|
616
616
|
const [picking, setPicking] = useState(false);
|
|
617
617
|
const skipNextHexBlurCommitRef = useRef(false);
|
|
618
|
+
// Preserve the last non-zero hue so dragging through an achromatic point
|
|
619
|
+
// (s=0 or v=0) doesn't snap hue to 0° when the user drags back to a
|
|
620
|
+
// saturated region. Matches Figma's hue-preservation behavior.
|
|
621
|
+
const lastHueRef = useRef<number>(0);
|
|
618
622
|
|
|
619
|
-
// Whole-popover view: the standard picker, or the
|
|
623
|
+
// Whole-popover view: the standard picker, or the shader fills panel.
|
|
620
624
|
const [view, setView] = useState<"picker" | "shader">("picker");
|
|
621
625
|
|
|
622
626
|
// Self-managed paint-type fallback for when EditPanel doesn't drive it.
|
|
623
|
-
const [localPaintType, setLocalPaintType] = useState<
|
|
627
|
+
const [localPaintType, setLocalPaintType] = useState<DesignPaintType | null>(
|
|
624
628
|
null,
|
|
625
629
|
);
|
|
626
630
|
|
|
@@ -642,7 +646,7 @@ export function FigmaColorPicker({
|
|
|
642
646
|
// engages its editor even when EditPanel doesn't complete the structural
|
|
643
647
|
// fill switch. localPaintType is reset below when the prop changes (i.e. a
|
|
644
648
|
// different element/fill is selected) so the picker still follows selection.
|
|
645
|
-
const effectivePaintType:
|
|
649
|
+
const effectivePaintType: DesignPaintType =
|
|
646
650
|
localPaintType ?? paintType ?? inferPaintType(value, effectiveOpacity);
|
|
647
651
|
|
|
648
652
|
// Resolve the active gradient: prefer EditPanel-driven props; otherwise parse
|
|
@@ -739,7 +743,7 @@ export function FigmaColorPicker({
|
|
|
739
743
|
const emitGradient = (next: GradientValue) => {
|
|
740
744
|
setLocalGradient(next);
|
|
741
745
|
if (onGradientTypeChange && next.kind !== gradientType) {
|
|
742
|
-
onGradientTypeChange(next.kind as
|
|
746
|
+
onGradientTypeChange(next.kind as DesignGradientType);
|
|
743
747
|
}
|
|
744
748
|
emitPaintValue(gradientToCss(next));
|
|
745
749
|
};
|
|
@@ -752,7 +756,15 @@ export function FigmaColorPicker({
|
|
|
752
756
|
const fieldColor: RgbaColor = activeGradient
|
|
753
757
|
? (parseCssColor(selectedStop?.color ?? "#000000") ?? FALLBACK_COLOR)
|
|
754
758
|
: color;
|
|
755
|
-
const
|
|
759
|
+
const rawFieldHsv = rgbaToHsv(fieldColor);
|
|
760
|
+
// Preserve the last non-zero hue so dragging through gray doesn't lose it.
|
|
761
|
+
if (rawFieldHsv.s > 0 && rawFieldHsv.v > 0) {
|
|
762
|
+
lastHueRef.current = rawFieldHsv.h;
|
|
763
|
+
}
|
|
764
|
+
const fieldHsv: HsvaColor =
|
|
765
|
+
rawFieldHsv.s === 0
|
|
766
|
+
? { ...rawFieldHsv, h: lastHueRef.current }
|
|
767
|
+
: rawFieldHsv;
|
|
756
768
|
const fieldHsl = rgbaToHsl(fieldColor);
|
|
757
769
|
|
|
758
770
|
// In gradient mode, mirror the selected stop's color into the hex draft.
|
|
@@ -808,10 +820,10 @@ export function FigmaColorPicker({
|
|
|
808
820
|
|
|
809
821
|
// ── Paint-type switching (does real work for every type) ──────────────────────
|
|
810
822
|
|
|
811
|
-
const setPaintType = (nextType:
|
|
823
|
+
const setPaintType = (nextType: DesignPaintType) => {
|
|
812
824
|
if (disabled) return;
|
|
813
825
|
|
|
814
|
-
// Shader opens the dedicated
|
|
826
|
+
// Shader opens the dedicated shader fills panel.
|
|
815
827
|
if (nextType === "shader") {
|
|
816
828
|
setLocalPaintType("shader");
|
|
817
829
|
setView("shader");
|
|
@@ -1007,7 +1019,7 @@ export function FigmaColorPicker({
|
|
|
1007
1019
|
<div className={cn("space-y-1.5", className)}>
|
|
1008
1020
|
<Popover open={open} onOpenChange={setOpen}>
|
|
1009
1021
|
<PopoverTrigger asChild>
|
|
1010
|
-
{/* Trigger: compact swatch + hex + opacity% — matches
|
|
1022
|
+
{/* Trigger: compact swatch + hex + opacity% — matches the design editor's fill row */}
|
|
1011
1023
|
<button
|
|
1012
1024
|
type="button"
|
|
1013
1025
|
disabled={disabled}
|
|
@@ -1018,7 +1030,7 @@ export function FigmaColorPicker({
|
|
|
1018
1030
|
disabled && "pointer-events-none opacity-50",
|
|
1019
1031
|
)}
|
|
1020
1032
|
>
|
|
1021
|
-
{/* Flat swatch chip — no shadow-inner (
|
|
1033
|
+
{/* Flat swatch chip — no shadow-inner (the design editor uses a flat chip) */}
|
|
1022
1034
|
<span
|
|
1023
1035
|
className="size-4 shrink-0 rounded-[3px] border border-border/60"
|
|
1024
1036
|
style={triggerSwatchStyle(value, color)}
|
|
@@ -1032,7 +1044,7 @@ export function FigmaColorPicker({
|
|
|
1032
1044
|
</button>
|
|
1033
1045
|
</PopoverTrigger>
|
|
1034
1046
|
|
|
1035
|
-
{/*
|
|
1047
|
+
{/* design popover: ~240px wide, uniform 12px padding, tight controls */}
|
|
1036
1048
|
<PopoverContent
|
|
1037
1049
|
side="left"
|
|
1038
1050
|
align="start"
|
|
@@ -1056,7 +1068,7 @@ export function FigmaColorPicker({
|
|
|
1056
1068
|
/>
|
|
1057
1069
|
) : (
|
|
1058
1070
|
<>
|
|
1059
|
-
{/* ── Paint-type icon row (
|
|
1071
|
+
{/* ── Paint-type icon row (design-editor, full-width tabs) ─── */}
|
|
1060
1072
|
{/* 11 types → two rows: first 6, then 5. Each icon is a
|
|
1061
1073
|
clearly-hittable 36×32px target with a distinct active
|
|
1062
1074
|
accent so the selected mode is immediately obvious. */}
|
|
@@ -1210,7 +1222,7 @@ export function FigmaColorPicker({
|
|
|
1210
1222
|
emitStopColor(
|
|
1211
1223
|
hsvToRgba({
|
|
1212
1224
|
...nextHsv,
|
|
1213
|
-
a:
|
|
1225
|
+
a: fieldColor.a,
|
|
1214
1226
|
}),
|
|
1215
1227
|
);
|
|
1216
1228
|
} else {
|
|
@@ -1286,7 +1298,7 @@ export function FigmaColorPicker({
|
|
|
1286
1298
|
}}
|
|
1287
1299
|
/>
|
|
1288
1300
|
|
|
1289
|
-
{/* Current-color swatch left of alpha (matches
|
|
1301
|
+
{/* Current-color swatch left of alpha (matches the design editor's layout) */}
|
|
1290
1302
|
<div className="flex items-center gap-2">
|
|
1291
1303
|
<span
|
|
1292
1304
|
className="size-[18px] shrink-0 rounded-[3px] border border-border/60"
|
|
@@ -1330,11 +1342,11 @@ export function FigmaColorPicker({
|
|
|
1330
1342
|
activeGradient) && (
|
|
1331
1343
|
<div className="mt-2.5 px-3 pb-3">
|
|
1332
1344
|
<div className="grid grid-cols-[4.5rem_1fr_3rem] items-center gap-1">
|
|
1333
|
-
{/* Model pill — bare text+chevron, no border or bg box (
|
|
1345
|
+
{/* Model pill — bare text+chevron, no border or bg box (design-editor) */}
|
|
1334
1346
|
<ColorModelPill
|
|
1335
1347
|
value={mode}
|
|
1336
1348
|
disabled={disabled}
|
|
1337
|
-
onChange={(v) => setMode(v as
|
|
1349
|
+
onChange={(v) => setMode(v as DesignColorMode)}
|
|
1338
1350
|
/>
|
|
1339
1351
|
|
|
1340
1352
|
{/* Value field(s) — adapts to mode */}
|
|
@@ -1379,9 +1391,9 @@ export function FigmaColorPicker({
|
|
|
1379
1391
|
otherwise falls back to the single current color so the
|
|
1380
1392
|
section is never empty. */}
|
|
1381
1393
|
<div className="border-t border-border/70 px-3 py-2.5">
|
|
1382
|
-
{/* Source label — matches
|
|
1394
|
+
{/* Source label — matches the design editor layout */}
|
|
1383
1395
|
<div className="mb-2 flex h-6 w-full items-center justify-between px-0.5 text-[11px] text-muted-foreground">
|
|
1384
|
-
{"Document colors" /* i18n-ignore
|
|
1396
|
+
{"Document colors" /* i18n-ignore design picker source */}
|
|
1385
1397
|
</div>
|
|
1386
1398
|
|
|
1387
1399
|
{/* Swatch grid: document palette when available, else current color */}
|
|
@@ -1434,7 +1446,7 @@ export function FigmaColorPicker({
|
|
|
1434
1446
|
|
|
1435
1447
|
// ─── Sub-components ────────────────────────────────────────────────────────────
|
|
1436
1448
|
|
|
1437
|
-
const COLOR_MODES: Array<{ value:
|
|
1449
|
+
const COLOR_MODES: Array<{ value: DesignColorMode; label: string }> = [
|
|
1438
1450
|
{ value: "hex", label: "Hex" }, // i18n-ignore color mode
|
|
1439
1451
|
{ value: "rgb", label: "RGB" }, // i18n-ignore color mode
|
|
1440
1452
|
{ value: "hsl", label: "HSL" }, // i18n-ignore color mode
|
|
@@ -1442,7 +1454,7 @@ const COLOR_MODES: Array<{ value: FigmaColorMode; label: string }> = [
|
|
|
1442
1454
|
];
|
|
1443
1455
|
|
|
1444
1456
|
/**
|
|
1445
|
-
*
|
|
1457
|
+
* design-editor bare color-model selector: text + small chevron, no border/bg box.
|
|
1446
1458
|
* Hover reveals a subtle bg tint; active mode is font-semibold.
|
|
1447
1459
|
* Renders its own lightweight dropdown (no Radix Select overhead).
|
|
1448
1460
|
*/
|
|
@@ -1451,9 +1463,9 @@ function ColorModelPill({
|
|
|
1451
1463
|
disabled,
|
|
1452
1464
|
onChange,
|
|
1453
1465
|
}: {
|
|
1454
|
-
value:
|
|
1466
|
+
value: DesignColorMode;
|
|
1455
1467
|
disabled: boolean;
|
|
1456
|
-
onChange: (mode:
|
|
1468
|
+
onChange: (mode: DesignColorMode) => void;
|
|
1457
1469
|
}) {
|
|
1458
1470
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
1459
1471
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
@@ -1720,7 +1732,7 @@ function ColorTrack({
|
|
|
1720
1732
|
)}
|
|
1721
1733
|
style={{ backgroundImage, backgroundSize, backgroundPosition }}
|
|
1722
1734
|
>
|
|
1723
|
-
{/* Thumb overhangs the track slightly, matching
|
|
1735
|
+
{/* Thumb overhangs the track slightly, matching the design editor */}
|
|
1724
1736
|
<span
|
|
1725
1737
|
className="pointer-events-none absolute top-1/2 size-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_hsl(var(--foreground)/0.6)]"
|
|
1726
1738
|
style={{ left: `${clamp(percent, 0, 100)}%` }}
|
|
@@ -1799,12 +1811,16 @@ function ScrubbyNumberInput({
|
|
|
1799
1811
|
if (e.key === "ArrowUp") {
|
|
1800
1812
|
e.preventDefault();
|
|
1801
1813
|
const step = e.shiftKey ? 10 : 1;
|
|
1802
|
-
|
|
1814
|
+
const parsed = Number(draft);
|
|
1815
|
+
const base = Number.isFinite(parsed) ? parsed : value;
|
|
1816
|
+
onChange(clamp(base + step, min, max));
|
|
1803
1817
|
}
|
|
1804
1818
|
if (e.key === "ArrowDown") {
|
|
1805
1819
|
e.preventDefault();
|
|
1806
1820
|
const step = e.shiftKey ? 10 : 1;
|
|
1807
|
-
|
|
1821
|
+
const parsed = Number(draft);
|
|
1822
|
+
const base = Number.isFinite(parsed) ? parsed : value;
|
|
1823
|
+
onChange(clamp(base - step, min, max));
|
|
1808
1824
|
}
|
|
1809
1825
|
}}
|
|
1810
1826
|
onBlur={() => {
|
|
@@ -1820,11 +1836,22 @@ function ScrubbyNumberInput({
|
|
|
1820
1836
|
|
|
1821
1837
|
// ─── Utilities ─────────────────────────────────────────────────────────────────
|
|
1822
1838
|
|
|
1823
|
-
export function inferPaintType(
|
|
1839
|
+
export function inferPaintType(
|
|
1840
|
+
value: string,
|
|
1841
|
+
opacity: number,
|
|
1842
|
+
): DesignPaintType {
|
|
1824
1843
|
const lower = value.trim().toLowerCase();
|
|
1825
1844
|
if (lower.includes("gradient(")) {
|
|
1826
|
-
if (
|
|
1827
|
-
|
|
1845
|
+
if (
|
|
1846
|
+
lower.startsWith("radial-gradient") ||
|
|
1847
|
+
lower.startsWith("repeating-radial-gradient")
|
|
1848
|
+
)
|
|
1849
|
+
return "radial";
|
|
1850
|
+
if (
|
|
1851
|
+
lower.startsWith("conic-gradient") ||
|
|
1852
|
+
lower.startsWith("repeating-conic-gradient")
|
|
1853
|
+
)
|
|
1854
|
+
return "angular";
|
|
1828
1855
|
return "linear";
|
|
1829
1856
|
}
|
|
1830
1857
|
if (lower.startsWith("url(")) return "image";
|
|
@@ -1836,7 +1863,7 @@ export function inferPaintType(value: string, opacity: number): FigmaPaintType {
|
|
|
1836
1863
|
}
|
|
1837
1864
|
|
|
1838
1865
|
/** The set of paint types that render a gradient editor. */
|
|
1839
|
-
export const GRADIENT_PAINT_TYPES: ReadonlySet<
|
|
1866
|
+
export const GRADIENT_PAINT_TYPES: ReadonlySet<DesignPaintType> = new Set([
|
|
1840
1867
|
"linear",
|
|
1841
1868
|
"radial",
|
|
1842
1869
|
"angular",
|
|
@@ -1860,17 +1887,17 @@ export const GRADIENT_PAINT_TYPES: ReadonlySet<FigmaPaintType> = new Set([
|
|
|
1860
1887
|
* @param opacity The current opacity (0–100).
|
|
1861
1888
|
*/
|
|
1862
1889
|
export function resolveActivePaint(
|
|
1863
|
-
paintType:
|
|
1864
|
-
localPaintType:
|
|
1890
|
+
paintType: DesignPaintType | undefined,
|
|
1891
|
+
localPaintType: DesignPaintType | null,
|
|
1865
1892
|
value: string,
|
|
1866
1893
|
opacity: number,
|
|
1867
1894
|
): {
|
|
1868
|
-
effectivePaintType:
|
|
1895
|
+
effectivePaintType: DesignPaintType;
|
|
1869
1896
|
showGradientEditor: boolean;
|
|
1870
1897
|
showImageControls: boolean;
|
|
1871
1898
|
showShaderPanel: boolean;
|
|
1872
1899
|
} {
|
|
1873
|
-
const effectivePaintType:
|
|
1900
|
+
const effectivePaintType: DesignPaintType =
|
|
1874
1901
|
localPaintType ?? paintType ?? inferPaintType(value, opacity);
|
|
1875
1902
|
return {
|
|
1876
1903
|
effectivePaintType,
|
|
@@ -1884,12 +1911,12 @@ function toCssColor(color: RgbaColor): string {
|
|
|
1884
1911
|
return rgbaToCss(color);
|
|
1885
1912
|
}
|
|
1886
1913
|
|
|
1887
|
-
/** Show hex without the leading # for the display field (matches
|
|
1914
|
+
/** Show hex without the leading # for the display field (matches the design editor). */
|
|
1888
1915
|
function toDisplayHex(color: RgbaColor): string {
|
|
1889
1916
|
return rgbaToHex(color).replace(/^#/, "").toUpperCase();
|
|
1890
1917
|
}
|
|
1891
1918
|
|
|
1892
|
-
function triggerLabel(type:
|
|
1919
|
+
function triggerLabel(type: DesignPaintType, color: RgbaColor): string {
|
|
1893
1920
|
if (type === "solid") return toDisplayHex(color);
|
|
1894
1921
|
if (type === "none") return "None";
|
|
1895
1922
|
if (type === "image") return "Image";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IconDownload, IconPlus, IconX } from "@tabler/icons-react";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
|
|
4
4
|
import { Button } from "@/components/ui/button";
|
|
5
5
|
import { Input } from "@/components/ui/input";
|
|
@@ -37,7 +37,7 @@ export interface ExportSettingsPanelLabels {
|
|
|
37
37
|
export interface ExportSettingsPanelProps {
|
|
38
38
|
value: ExportSettingsValue;
|
|
39
39
|
onChange: (patch: Partial<ExportSettingsValue>) => void;
|
|
40
|
-
onExport: (settings: ExportSettingsValue) => void;
|
|
40
|
+
onExport: (settings: ExportSettingsValue[]) => void;
|
|
41
41
|
formats?: ExportFormat[];
|
|
42
42
|
labels?: Partial<ExportSettingsPanelLabels>;
|
|
43
43
|
disabled?: boolean;
|
|
@@ -57,7 +57,7 @@ const DEFAULT_LABELS: ExportSettingsPanelLabels = {
|
|
|
57
57
|
|
|
58
58
|
const DEFAULT_FORMATS: ExportFormat[] = ["png", "jpg", "svg", "pdf", "webp"];
|
|
59
59
|
|
|
60
|
-
/** Preset scale options shown in the scale dropdown — matches
|
|
60
|
+
/** Preset scale options shown in the scale dropdown — matches the design editor's presets */
|
|
61
61
|
const SCALE_PRESETS: { label: string; value: ExportScale }[] = [
|
|
62
62
|
{ label: "0.5x", value: "0.5" },
|
|
63
63
|
{ label: "1x", value: "1" },
|
|
@@ -103,7 +103,7 @@ function rowFromValue(v: ExportSettingsValue): ExportRow {
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
/** Scale dropdown — shows
|
|
106
|
+
/** Scale dropdown — shows the design editor's 0.5x/1x/2x/3x/4x presets + Custom */
|
|
107
107
|
function ScaleSelect({
|
|
108
108
|
scale,
|
|
109
109
|
customScale,
|
|
@@ -162,15 +162,7 @@ export function ExportSettingsPanel({
|
|
|
162
162
|
// Multi-row internal state — primary row is kept in sync with the `value` prop
|
|
163
163
|
const [rows, setRows] = useState<ExportRow[]>(() => [rowFromValue(value)]);
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
const primaryValue = rows[0];
|
|
167
|
-
const needsSync =
|
|
168
|
-
!primaryValue.customScale &&
|
|
169
|
-
(primaryValue.scale !== value.scale ||
|
|
170
|
-
primaryValue.format !== value.format ||
|
|
171
|
-
primaryValue.suffix !== value.suffix);
|
|
172
|
-
|
|
173
|
-
if (needsSync) {
|
|
165
|
+
useEffect(() => {
|
|
174
166
|
setRows((prev) => [
|
|
175
167
|
{
|
|
176
168
|
...prev[0],
|
|
@@ -180,7 +172,7 @@ export function ExportSettingsPanel({
|
|
|
180
172
|
},
|
|
181
173
|
...prev.slice(1),
|
|
182
174
|
]);
|
|
183
|
-
}
|
|
175
|
+
}, [value.format, value.scale, value.suffix]);
|
|
184
176
|
|
|
185
177
|
function patchRow(id: number, patch: Partial<ExportRow>) {
|
|
186
178
|
setRows((prev) => prev.map((r) => (r.id === id ? { ...r, ...patch } : r)));
|
|
@@ -226,19 +218,15 @@ export function ExportSettingsPanel({
|
|
|
226
218
|
}
|
|
227
219
|
|
|
228
220
|
function handleExport() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
scale: primary.scale,
|
|
234
|
-
format: primary.format,
|
|
235
|
-
suffix: primary.suffix,
|
|
236
|
-
});
|
|
221
|
+
if (rows.length === 0) return;
|
|
222
|
+
onExport(
|
|
223
|
+
rows.map((r) => ({ scale: r.scale, format: r.format, suffix: r.suffix })),
|
|
224
|
+
);
|
|
237
225
|
}
|
|
238
226
|
|
|
239
227
|
return (
|
|
240
228
|
<div className={cn("space-y-1.5", className)}>
|
|
241
|
-
{/* Section header: title left, "+" right — matches
|
|
229
|
+
{/* Section header: title left, "+" right — matches the design editor export header */}
|
|
242
230
|
<div className="flex h-6 items-center justify-between">
|
|
243
231
|
<span className="text-[11px] font-medium text-muted-foreground">
|
|
244
232
|
{copy.title}
|
|
@@ -254,7 +242,7 @@ export function ExportSettingsPanel({
|
|
|
254
242
|
</button>
|
|
255
243
|
</div>
|
|
256
244
|
|
|
257
|
-
{/* Export rows: [scale ▾] [format ▾] [suffix] [×] —
|
|
245
|
+
{/* Export rows: [scale ▾] [format ▾] [suffix] [×] — design-editor compact inline layout */}
|
|
258
246
|
{rows.map((row) => (
|
|
259
247
|
<ExportRow
|
|
260
248
|
key={row.id}
|
|
@@ -268,7 +256,7 @@ export function ExportSettingsPanel({
|
|
|
268
256
|
/>
|
|
269
257
|
))}
|
|
270
258
|
|
|
271
|
-
{/* Export button — full width at bottom,
|
|
259
|
+
{/* Export button — full width at bottom, design-editor style */}
|
|
272
260
|
<Button
|
|
273
261
|
type="button"
|
|
274
262
|
variant="outline"
|
|
@@ -380,7 +368,7 @@ function ExportRow({
|
|
|
380
368
|
aria-label={labels.suffix}
|
|
381
369
|
/>
|
|
382
370
|
|
|
383
|
-
{/* Remove row button — matches
|
|
371
|
+
{/* Remove row button — matches the design editor's × on each export entry */}
|
|
384
372
|
<button
|
|
385
373
|
type="button"
|
|
386
374
|
aria-label={labels.removeExport}
|
|
@@ -27,7 +27,7 @@ export interface GradientValue {
|
|
|
27
27
|
stops: GradientStopValue[];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// ─── Checkerboard (matches
|
|
30
|
+
// ─── Checkerboard (matches DesignColorPicker) ───────────────────────────────────
|
|
31
31
|
|
|
32
32
|
const CHECKER_A = "#d4d4d4";
|
|
33
33
|
const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
|
|
@@ -53,7 +53,7 @@ export function gradientToCss(value: GradientValue): string {
|
|
|
53
53
|
return `radial-gradient(circle at center, ${stops})`;
|
|
54
54
|
case "diamond":
|
|
55
55
|
// CSS has no diamond gradient; a radial gradient with closest-side on a
|
|
56
|
-
// non-circular ellipse reads as the diamond falloff
|
|
56
|
+
// non-circular ellipse reads as the diamond falloff the design editor shows.
|
|
57
57
|
return `radial-gradient(ellipse closest-side at center, ${stops})`;
|
|
58
58
|
case "angular":
|
|
59
59
|
return `conic-gradient(from ${round(value.angle)}deg at center, ${stops})`;
|
|
@@ -155,7 +155,7 @@ export function parseGradientCss(
|
|
|
155
155
|
: false;
|
|
156
156
|
|
|
157
157
|
if (fn === "linear") {
|
|
158
|
-
kind =
|
|
158
|
+
kind = "linear";
|
|
159
159
|
const angleMatch = first.match(ANGLE_RE);
|
|
160
160
|
if (angleMatch) {
|
|
161
161
|
angle = Number(angleMatch[1]);
|
|
@@ -166,7 +166,10 @@ export function parseGradientCss(
|
|
|
166
166
|
stopStart = 1;
|
|
167
167
|
}
|
|
168
168
|
} else if (fn === "radial") {
|
|
169
|
-
kind =
|
|
169
|
+
kind =
|
|
170
|
+
/ellipse\s+closest-side/i.test(first) || fallbackKind === "diamond"
|
|
171
|
+
? "diamond"
|
|
172
|
+
: "radial";
|
|
170
173
|
if (/circle|ellipse|at\s/i.test(first)) stopStart = 1;
|
|
171
174
|
} else if (fn === "conic") {
|
|
172
175
|
kind = "angular";
|
|
@@ -199,7 +202,7 @@ interface AngleDialProps {
|
|
|
199
202
|
disabled?: boolean;
|
|
200
203
|
}
|
|
201
204
|
|
|
202
|
-
/**
|
|
205
|
+
/** design-editor circular dial for rotating gradient angle. */
|
|
203
206
|
function AngleDial({ angle, onChange, disabled = false }: AngleDialProps) {
|
|
204
207
|
const dialRef = useRef<HTMLDivElement>(null);
|
|
205
208
|
const draggingRef = useRef(false);
|
|
@@ -210,7 +213,7 @@ function AngleDial({ angle, onChange, disabled = false }: AngleDialProps) {
|
|
|
210
213
|
const cx = rect.left + rect.width / 2;
|
|
211
214
|
const cy = rect.top + rect.height / 2;
|
|
212
215
|
const rad = Math.atan2(clientY - cy, clientX - cx);
|
|
213
|
-
// atan2 gives angle from east;
|
|
216
|
+
// atan2 gives angle from east; the design editor's 0° is north (up), clockwise.
|
|
214
217
|
let deg = (rad * 180) / Math.PI + 90;
|
|
215
218
|
if (deg < 0) deg += 360;
|
|
216
219
|
if (deg >= 360) deg -= 360;
|
|
@@ -311,7 +314,7 @@ export interface GradientEditorProps {
|
|
|
311
314
|
className?: string;
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
// Stop handle dimensions —
|
|
317
|
+
// Stop handle dimensions — the design editor uses ~12px handles with white ring.
|
|
315
318
|
const STOP_SIZE = 12; // px, the colored circle diameter
|
|
316
319
|
const STOP_RING = 2; // px, white border thickness
|
|
317
320
|
const STOP_OUTER = STOP_SIZE + STOP_RING * 2; // 16px total outer
|
|
@@ -372,9 +375,29 @@ export function GradientEditor({
|
|
|
372
375
|
barClickRef.current = null;
|
|
373
376
|
const position = positionFromPointer(event.clientX);
|
|
374
377
|
const ordered = sortedStops(value.stops);
|
|
375
|
-
// Interpolate the color from the
|
|
378
|
+
// Interpolate the color from the adjacent stops for a natural insert.
|
|
376
379
|
const before = [...ordered].reverse().find((s) => s.position <= position);
|
|
377
|
-
const
|
|
380
|
+
const after = ordered.find((s) => s.position > position);
|
|
381
|
+
let newColor: string;
|
|
382
|
+
if (before && after) {
|
|
383
|
+
const range = after.position - before.position;
|
|
384
|
+
const t = range === 0 ? 0 : (position - before.position) / range;
|
|
385
|
+
const cb = parseCssColor(before.color);
|
|
386
|
+
const ca = parseCssColor(after.color);
|
|
387
|
+
if (cb && ca) {
|
|
388
|
+
newColor = rgbaToCss({
|
|
389
|
+
r: Math.round(cb.r + t * (ca.r - cb.r)),
|
|
390
|
+
g: Math.round(cb.g + t * (ca.g - cb.g)),
|
|
391
|
+
b: Math.round(cb.b + t * (ca.b - cb.b)),
|
|
392
|
+
a: cb.a + t * (ca.a - cb.a),
|
|
393
|
+
});
|
|
394
|
+
} else {
|
|
395
|
+
newColor = before.color;
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
newColor =
|
|
399
|
+
before?.color ?? after?.color ?? ordered[0]?.color ?? "#000000";
|
|
400
|
+
}
|
|
378
401
|
const newStop: GradientStopValue = {
|
|
379
402
|
id: nextStopId(),
|
|
380
403
|
color: newColor,
|
|
@@ -501,7 +524,7 @@ export function GradientEditor({
|
|
|
501
524
|
"absolute cursor-grab active:cursor-grabbing",
|
|
502
525
|
"rounded-full border-[2px] border-white",
|
|
503
526
|
"focus-visible:outline-none",
|
|
504
|
-
// Selected: accent-colored outer ring (
|
|
527
|
+
// Selected: accent-colored outer ring (the same way's blue ring)
|
|
505
528
|
isSelected
|
|
506
529
|
? "shadow-[0_0_0_1.5px_var(--primary),0_1px_3px_rgba(0,0,0,0.35)]"
|
|
507
530
|
: "shadow-[0_0_0_1px_rgba(0,0,0,0.25),0_1px_3px_rgba(0,0,0,0.25)]",
|
|
@@ -560,9 +583,14 @@ export function GradientEditor({
|
|
|
560
583
|
disabled={disabled}
|
|
561
584
|
value={angleInput ?? Math.round(value.angle)}
|
|
562
585
|
onChange={(e) => {
|
|
563
|
-
setAngleInput(e.target.value);
|
|
564
586
|
const next = Number(e.target.value);
|
|
565
|
-
if (Number.isFinite(next))
|
|
587
|
+
if (Number.isFinite(next)) {
|
|
588
|
+
const normalised = ((next % 360) + 360) % 360;
|
|
589
|
+
setAngle(next);
|
|
590
|
+
setAngleInput(String(Math.round(normalised)));
|
|
591
|
+
} else {
|
|
592
|
+
setAngleInput(e.target.value);
|
|
593
|
+
}
|
|
566
594
|
}}
|
|
567
595
|
onBlur={() => setAngleInput(null)}
|
|
568
596
|
className="h-full min-w-0 flex-1 bg-transparent px-1.5 text-[11px] tabular-nums focus-visible:outline-none"
|