@agent-native/core 0.92.10 → 0.92.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +23 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +181 -15
- package/corpus/core/src/agent/run-manager.ts +31 -4
- package/corpus/core/src/agent/run-store.ts +80 -0
- package/corpus/core/src/cli/design-connect.ts +433 -151
- package/corpus/core/src/cli/skills.ts +14 -0
- package/corpus/core/src/client/AssistantChat.tsx +25 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
- package/corpus/core/src/client/agent-chat.ts +165 -1
- package/corpus/core/src/client/chat/index.ts +9 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
- package/corpus/core/src/collab/awareness-store.ts +23 -12
- package/corpus/core/src/collab/client.ts +16 -5
- package/corpus/core/src/collab/index.ts +4 -0
- package/corpus/core/src/collab/recent-edits.ts +65 -2
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
- package/corpus/core/src/server/builder-design-systems.ts +30 -4
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/create-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
- package/corpus/templates/clips/actions/request-transcript.ts +102 -33
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +48 -4
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
- package/corpus/templates/clips/app/routes/record.tsx +17 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +12 -2
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +6 -3
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
- package/corpus/templates/clips/shared/recording-core.ts +12 -0
- package/corpus/templates/content/AGENTS.md +7 -6
- package/corpus/templates/content/actions/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/pull-document.ts +5 -7
- package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
- package/corpus/templates/content/actions/push-notion-page.ts +10 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
- package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/content/app/i18n-data.ts +18 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
- package/corpus/templates/design/AGENTS.md +45 -10
- package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
- package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
- package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
- package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
- package/corpus/templates/design/actions/generate-design.ts +79 -12
- package/corpus/templates/design/actions/generate-screens.ts +57 -12
- package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
- package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
- package/corpus/templates/design/actions/import-design-source.ts +4 -31
- package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
- package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/design/actions/list-design-components.ts +104 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
- package/corpus/templates/design/actions/open-component-source.ts +2 -4
- package/corpus/templates/design/actions/present-design-variants.ts +412 -16
- package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
- package/corpus/templates/design/actions/run-design-audit.ts +25 -3
- package/corpus/templates/design/actions/show-design-questions.ts +10 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
- package/corpus/templates/design/actions/write-local-file.ts +25 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
- package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
- package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
- package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
- package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
- package/corpus/templates/design/app/components/design/types.ts +33 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
- package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
- package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
- package/corpus/templates/design/app/i18n-data.ts +1217 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
- package/corpus/templates/design/app/lib/design-import.ts +24 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
- package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
- package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
- package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
- package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -6
- package/corpus/templates/design/e2e/helpers.ts +27 -6
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
- package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
- package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
- package/corpus/templates/design/server/plugins/db.ts +41 -0
- package/corpus/templates/design/server/source-workspace.ts +64 -0
- package/corpus/templates/design/shared/board-file.ts +13 -2
- package/corpus/templates/design/shared/canvas-math.ts +231 -33
- package/corpus/templates/design/shared/code-layer.ts +122 -8
- package/corpus/templates/design/shared/component-library.ts +161 -0
- package/corpus/templates/design/shared/db-conflict.ts +27 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
- package/corpus/templates/design/shared/figma-url.ts +149 -0
- package/corpus/templates/design/shared/pen-path.ts +16 -7
- package/corpus/templates/design/shared/source-mode.ts +1 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
- package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
- package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
- package/dist/agent/production-agent.d.ts +79 -6
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +161 -14
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +29 -5
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +46 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +61 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/design-connect.d.ts +6 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +336 -139
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +14 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +19 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +38 -18
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts +60 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +122 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +36 -2
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +5 -0
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +19 -12
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +13 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +3 -1
- package/dist/collab/recent-edits.d.ts.map +1 -1
- package/dist/collab/recent-edits.js +57 -2
- package/dist/collab/recent-edits.js.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +87 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +15 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -4
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +1 -1
|
@@ -152,6 +152,27 @@ const LEAF_TAGS = new Set([
|
|
|
152
152
|
"iframe",
|
|
153
153
|
]);
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Explicit, unambiguous signals that an element IS a text object: a real
|
|
157
|
+
* text tag, an authoritative `primitiveKind === "text"` marker, or a
|
|
158
|
+
* `draft-text-*` tool-drawn id. Deliberately excludes `isTextElement()`'s
|
|
159
|
+
* last-resort fallback for payloads with no primitive marker at all (a
|
|
160
|
+
* childless div with its own text content) — that heuristic exists to catch
|
|
161
|
+
* genuine T-tool text primitives whose payload happens to be missing
|
|
162
|
+
* `primitiveKind`, but it also matches ordinary content divs with no
|
|
163
|
+
* relation to the T-tool at all (Tailwind pill/badge/button-label markup is
|
|
164
|
+
* routinely a childless `<div>` with its own text). Used by
|
|
165
|
+
* `isContainerElement()` below, which must not misclassify those ordinary
|
|
166
|
+
* divs as text just because they're childless and have text content.
|
|
167
|
+
*/
|
|
168
|
+
function hasExplicitTextIdentity(element: ElementInfo): boolean {
|
|
169
|
+
const tag = (element.tagName || "").toLowerCase();
|
|
170
|
+
if (TEXT_TAGS.has(tag)) return true;
|
|
171
|
+
if (element.primitiveKind) return element.primitiveKind === "text";
|
|
172
|
+
const nodeId = element.sourceId || element.pendingNodeId || "";
|
|
173
|
+
return nodeId.startsWith("draft-text-");
|
|
174
|
+
}
|
|
175
|
+
|
|
155
176
|
/**
|
|
156
177
|
* Whether the element should expose the Auto layout section. True for anything
|
|
157
178
|
* already laid out with flexbox, or any block-level container tag that isn't a
|
|
@@ -159,6 +180,26 @@ const LEAF_TAGS = new Set([
|
|
|
159
180
|
* children show the full Auto layout section the same way does.
|
|
160
181
|
*/
|
|
161
182
|
export function isContainerElement(element: ElementInfo): boolean {
|
|
183
|
+
// T-tool text primitives are divs and use `display:flex` for vertical text
|
|
184
|
+
// alignment, but they are still leaf text layers rather than auto-layout
|
|
185
|
+
// containers, so check text identity before the flex/container shortcuts
|
|
186
|
+
// (fixing empty frame controls must not expose Flow/Padding on text
|
|
187
|
+
// layers). This short-circuit must only fire on an EXPLICIT text signal
|
|
188
|
+
// (see `hasExplicitTextIdentity`) rather than `isTextElement()`'s generic
|
|
189
|
+
// childless-div-with-text fallback: that fallback alone would also match
|
|
190
|
+
// ordinary text-only divs with no primitive/tag/id marker at all —
|
|
191
|
+
// ubiquitous in generated markup (Tailwind pills/badges/button-label
|
|
192
|
+
// divs) — stripping the Flow/Padding/Auto-layout sections from every one
|
|
193
|
+
// of them even though they're legitimate flex/block containers.
|
|
194
|
+
if (hasExplicitTextIdentity(element)) return false;
|
|
195
|
+
// Canvas primitive markers are authoritative. This code-backed editor lets
|
|
196
|
+
// rectangles act as lightweight containers (nest-on-drop promotes them to
|
|
197
|
+
// auto layout), and frames are containers by definition. Other drawn
|
|
198
|
+
// shapes remain leaves even though several are represented by a plain div.
|
|
199
|
+
const primitiveKind = element.primitiveKind?.trim().toLowerCase();
|
|
200
|
+
if (primitiveKind) {
|
|
201
|
+
return ["frame", "rectangle", "rect"].includes(primitiveKind);
|
|
202
|
+
}
|
|
162
203
|
if (element.isFlexContainer || element.isGridContainer) return true;
|
|
163
204
|
const tag = (element.tagName || "").toLowerCase();
|
|
164
205
|
if (TEXT_TAGS.has(tag) || LEAF_TAGS.has(tag)) return false;
|
|
@@ -176,13 +217,6 @@ export function isParentGrid(element: ElementInfo): boolean {
|
|
|
176
217
|
return Boolean(element.parentDisplay?.toLowerCase().includes("grid"));
|
|
177
218
|
}
|
|
178
219
|
|
|
179
|
-
export function elementHasLayoutChildren(element: ElementInfo): boolean {
|
|
180
|
-
if (typeof element.childElementCount === "number") {
|
|
181
|
-
return element.childElementCount > 0;
|
|
182
|
-
}
|
|
183
|
-
return Boolean(element.htmlContent?.match(/<\s*[a-zA-Z][^>]*>/));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
220
|
export function parentFlexDirection(
|
|
187
221
|
element: ElementInfo,
|
|
188
222
|
): AutoLayoutSizingAxis {
|
|
@@ -5,7 +5,7 @@ import { roundToOneDecimal } from "./position-helpers";
|
|
|
5
5
|
|
|
6
6
|
export function elementIdentityKey(element: ElementInfo): string {
|
|
7
7
|
return [
|
|
8
|
-
element
|
|
8
|
+
elementStableKey(element),
|
|
9
9
|
Math.round(element.boundingRect.x),
|
|
10
10
|
Math.round(element.boundingRect.y),
|
|
11
11
|
Math.round(element.boundingRect.width),
|
|
@@ -18,9 +18,22 @@ export function elementIdentityKey(element: ElementInfo): string {
|
|
|
18
18
|
* resizing (unlike elementIdentityKey, which folds in the bounding rect and
|
|
19
19
|
* therefore changes on every resize — exactly what an aspect-ratio lock needs
|
|
20
20
|
* to persist across). Falls back through the same id chain.
|
|
21
|
+
*
|
|
22
|
+
* Uses `||`, not `??`, between the fallback candidates: the bridge
|
|
23
|
+
* (editor-chrome.bridge.ts getElementInfo) reports `sourceId` as the empty
|
|
24
|
+
* string `""` — not `undefined` — for any element that isn't source-backed
|
|
25
|
+
* (e.g. a runtime-only DOM node in a connected localhost/fusion screen). `??`
|
|
26
|
+
* only skips a nullish left-hand side, so an empty-string `sourceId` short-
|
|
27
|
+
* circuited the whole chain and every non-source-backed element collapsed to
|
|
28
|
+
* the SAME key ("" here, and just the rounded bounding rect in
|
|
29
|
+
* elementIdentityKey). For this hook that meant locking the aspect ratio on
|
|
30
|
+
* one such element silently applied its captured ratio to every other
|
|
31
|
+
* non-source-backed element too. `||` falls through empty strings the same
|
|
32
|
+
* way the bridge itself already does (`getSourceId(el) || getSelector(el)`),
|
|
33
|
+
* reaching the real per-element `selector` instead. Exported for tests.
|
|
21
34
|
*/
|
|
22
|
-
function elementStableKey(element: ElementInfo): string {
|
|
23
|
-
return element.sourceId
|
|
35
|
+
export function elementStableKey(element: ElementInfo): string {
|
|
36
|
+
return element.sourceId || element.id || element.selector || element.tagName;
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
/**
|
|
@@ -20,16 +20,29 @@ import {
|
|
|
20
20
|
type ScrubInputChangeMeta,
|
|
21
21
|
} from "../inspector";
|
|
22
22
|
import type { ElementInfo } from "../types";
|
|
23
|
+
import { roundToOneDecimal } from "./position-helpers";
|
|
23
24
|
import { isMixedValue } from "./selection-helpers";
|
|
24
25
|
import {
|
|
25
26
|
resolveBreakpointOverride,
|
|
26
27
|
type BreakpointOverrideFieldContext,
|
|
27
28
|
type MotionKeyframeFieldContext,
|
|
29
|
+
type StyleChangeMeta,
|
|
28
30
|
type StyleChangeHandler,
|
|
29
31
|
type StylesChangeHandler,
|
|
30
32
|
} from "./style-change-types";
|
|
31
33
|
import { parseNumericValue, sidesAreLinked } from "./style-options";
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The CSS length DesignSpacingControl commits for one side's scrub/typed
|
|
37
|
+
* value. Rounds to one decimal place (not a whole pixel) to match the
|
|
38
|
+
* `precision={1}` the four per-side ScrubInput fields below advertise — see
|
|
39
|
+
* `roundToOneDecimal`'s docstring on why 0.5-unit values must survive the
|
|
40
|
+
* round trip. Exported so the precision contract is unit-testable directly.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveSpacingSideValue(value: number): string {
|
|
43
|
+
return `${roundToOneDecimal(value)}px`;
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
export function DesignSpacingControl({
|
|
34
47
|
label,
|
|
35
48
|
values,
|
|
@@ -47,14 +60,19 @@ export function DesignSpacingControl({
|
|
|
47
60
|
bottom: parseNumericValue(values.bottom || "0"),
|
|
48
61
|
left: parseNumericValue(values.left || "0"),
|
|
49
62
|
};
|
|
50
|
-
const linkedValue =
|
|
63
|
+
const linkedValue = roundToOneDecimal(
|
|
51
64
|
(numeric.top + numeric.right + numeric.bottom + numeric.left) / 4,
|
|
52
65
|
);
|
|
53
66
|
const setSide = (
|
|
54
67
|
side: "Top" | "Right" | "Bottom" | "Left",
|
|
55
68
|
value: number,
|
|
56
69
|
) => {
|
|
57
|
-
|
|
70
|
+
// Was `Math.round(value)`, which silently floored every typed/scrubbed
|
|
71
|
+
// 0.5px value to a whole pixel — contradicting the `precision={1}` these
|
|
72
|
+
// fields advertise (below) and diverging from every other ScrubInput
|
|
73
|
+
// commit site in this panel (position X/Y, stroke weight, font size all
|
|
74
|
+
// use roundToOneDecimal).
|
|
75
|
+
onChange(side, resolveSpacingSideValue(value));
|
|
58
76
|
};
|
|
59
77
|
const setAll = (value: number) => {
|
|
60
78
|
(["Top", "Right", "Bottom", "Left"] as const).forEach((side) =>
|
|
@@ -98,6 +116,7 @@ export function DesignSpacingControl({
|
|
|
98
116
|
onChange={setAll}
|
|
99
117
|
unit="px"
|
|
100
118
|
min={0}
|
|
119
|
+
precision={1}
|
|
101
120
|
labelClassName="w-16"
|
|
102
121
|
inputClassName="h-6"
|
|
103
122
|
/>
|
|
@@ -304,12 +323,13 @@ export function commitStylePatch(
|
|
|
304
323
|
styles: Record<string, string>,
|
|
305
324
|
onStyleChange: StyleChangeHandler,
|
|
306
325
|
onStylesChange?: StylesChangeHandler,
|
|
326
|
+
meta?: StyleChangeMeta,
|
|
307
327
|
) {
|
|
308
328
|
if (onStylesChange) {
|
|
309
|
-
onStylesChange(styles);
|
|
329
|
+
onStylesChange(styles, meta);
|
|
310
330
|
return;
|
|
311
331
|
}
|
|
312
332
|
Object.entries(styles).forEach(([property, value]) => {
|
|
313
|
-
onStyleChange(property, value);
|
|
333
|
+
onStyleChange(property, value, meta);
|
|
314
334
|
});
|
|
315
335
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type DesignGradientType,
|
|
12
12
|
type ExportSettingsValue,
|
|
13
13
|
} from "../inspector";
|
|
14
|
-
import { cssColorOrFallback } from "./position-helpers";
|
|
14
|
+
import { colorHasVisibleAlpha, cssColorOrFallback } from "./position-helpers";
|
|
15
15
|
|
|
16
16
|
export const SOLID_FILL_ID = "solid";
|
|
17
17
|
export const FILL_LAYER_PREFIX = "layer:";
|
|
@@ -113,24 +113,45 @@ export function isLayerHiddenBySize(sizeEntry: string | undefined): boolean {
|
|
|
113
113
|
* Rewrites the background-size list so `index` is hidden/shown via the
|
|
114
114
|
* zero-size marker, padding shorter lists with "auto" (the CSS default) so
|
|
115
115
|
* every other layer keeps rendering at its current/default size.
|
|
116
|
+
*
|
|
117
|
+
* `restoreValue` is the size to bring back when un-hiding (`hidden: false`).
|
|
118
|
+
* Without it, re-showing always reset the layer to "auto", permanently
|
|
119
|
+
* discarding whatever custom cover/contain/percentage size the layer had
|
|
120
|
+
* before it was hidden — callers should capture the layer's own size entry
|
|
121
|
+
* before hiding it (it's about to be overwritten with the marker) and pass
|
|
122
|
+
* it back in here on the show path. Defaults to "auto" so existing callers
|
|
123
|
+
* that don't have a stashed value keep today's behavior.
|
|
116
124
|
*/
|
|
117
125
|
export function withLayerSizeMarker(
|
|
118
126
|
sizeLayers: string[],
|
|
119
127
|
layerCount: number,
|
|
120
128
|
index: number,
|
|
121
129
|
hidden: boolean,
|
|
130
|
+
restoreValue?: string,
|
|
122
131
|
): string {
|
|
123
132
|
const next = Array.from(
|
|
124
133
|
{ length: layerCount },
|
|
125
134
|
(_, i) => sizeLayers[i] || "auto",
|
|
126
135
|
);
|
|
127
|
-
next[index] = hidden ? HIDDEN_LAYER_SIZE_MARKER : "auto";
|
|
136
|
+
next[index] = hidden ? HIDDEN_LAYER_SIZE_MARKER : restoreValue || "auto";
|
|
128
137
|
return joinCssLayers(next);
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
export function splitCssLayers(value: string): string[] {
|
|
132
141
|
const trimmed = value.trim();
|
|
133
|
-
|
|
142
|
+
// CSS-wide keywords represent the property's default/inherited value as a
|
|
143
|
+
// whole; they are not real comma-stack layers and cannot legally be
|
|
144
|
+
// preserved beside a new gradient/image (`url(...), initial` invalidates
|
|
145
|
+
// the entire declaration). Shorthand-authored page backgrounds commonly
|
|
146
|
+
// surface as `initial` through CSSStyleDeclaration, so normalize these to
|
|
147
|
+
// an empty editable layer stack before adding a real fill.
|
|
148
|
+
if (
|
|
149
|
+
!trimmed ||
|
|
150
|
+
trimmed === "none" ||
|
|
151
|
+
/^(?:initial|inherit|unset|revert|revert-layer)$/i.test(trimmed)
|
|
152
|
+
) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
134
155
|
const layers: string[] = [];
|
|
135
156
|
let depth = 0;
|
|
136
157
|
let start = 0;
|
|
@@ -197,6 +218,189 @@ export function removeFillLayerAtIndex(
|
|
|
197
218
|
};
|
|
198
219
|
}
|
|
199
220
|
|
|
221
|
+
/** One image-fill layer's four index-aligned CSS values. */
|
|
222
|
+
export interface ImageFillLayerStyles {
|
|
223
|
+
backgroundImage: string;
|
|
224
|
+
backgroundSize: string;
|
|
225
|
+
backgroundRepeat: string;
|
|
226
|
+
backgroundPosition: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Sets one image-fill layer's four index-aligned CSS values at `index`,
|
|
231
|
+
* preserving every sibling layer's own image/size/repeat/position — the
|
|
232
|
+
* image-fill analog of `removeFillLayerAtIndex`/`reorderFillLayers`. `index`
|
|
233
|
+
* may be one past the current layer count to append a new layer. Shorter
|
|
234
|
+
* parallel arrays are padded with each property's CSS default (mirrors
|
|
235
|
+
* `addFillLayerPatch`'s defaults) so sibling layers keep rendering unchanged.
|
|
236
|
+
*/
|
|
237
|
+
export function setImageFillLayerPatch(
|
|
238
|
+
layers: FillLayerArrays,
|
|
239
|
+
index: number,
|
|
240
|
+
imageStyles: ImageFillLayerStyles,
|
|
241
|
+
): Record<
|
|
242
|
+
| "backgroundImage"
|
|
243
|
+
| "backgroundSize"
|
|
244
|
+
| "backgroundRepeat"
|
|
245
|
+
| "backgroundPosition",
|
|
246
|
+
string
|
|
247
|
+
> {
|
|
248
|
+
const layerCount = Math.max(layers.backgroundImage.length, index + 1);
|
|
249
|
+
const buildLayer = (existing: string[], fallback: string, override: string) =>
|
|
250
|
+
joinCssLayers(
|
|
251
|
+
Array.from({ length: layerCount }, (_, i) =>
|
|
252
|
+
i === index ? override : existing[i] || fallback,
|
|
253
|
+
),
|
|
254
|
+
);
|
|
255
|
+
return {
|
|
256
|
+
backgroundImage: buildLayer(
|
|
257
|
+
layers.backgroundImage,
|
|
258
|
+
"none",
|
|
259
|
+
imageStyles.backgroundImage,
|
|
260
|
+
),
|
|
261
|
+
backgroundSize: buildLayer(
|
|
262
|
+
layers.backgroundSize,
|
|
263
|
+
"auto",
|
|
264
|
+
imageStyles.backgroundSize,
|
|
265
|
+
),
|
|
266
|
+
backgroundRepeat: buildLayer(
|
|
267
|
+
layers.backgroundRepeat,
|
|
268
|
+
"no-repeat",
|
|
269
|
+
imageStyles.backgroundRepeat,
|
|
270
|
+
),
|
|
271
|
+
backgroundPosition: buildLayer(
|
|
272
|
+
layers.backgroundPosition,
|
|
273
|
+
"0% 0%",
|
|
274
|
+
imageStyles.backgroundPosition,
|
|
275
|
+
),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Full patch-building logic behind `ColorInput`'s image-fill handler.
|
|
281
|
+
*
|
|
282
|
+
* Previously, editing the base fill row's image (via `ImageFillControls` ->
|
|
283
|
+
* `DesignColorPicker.onImageFillChange`) always replaced the *whole*
|
|
284
|
+
* `backgroundImage`/`backgroundSize`/`backgroundRepeat`/`backgroundPosition`
|
|
285
|
+
* properties with a single-layer patch (see `imageFillToBackgroundStyles`),
|
|
286
|
+
* silently discarding any other gradient/image layers already stacked below
|
|
287
|
+
* it — there was no layer-index-aware merge at all.
|
|
288
|
+
*
|
|
289
|
+
* When `layerIndex` is a real index (editing an existing layer's own image),
|
|
290
|
+
* only that layer's four values are overwritten, preserving every sibling —
|
|
291
|
+
* see `setImageFillLayerPatch`. When `layerIndex` is `null` (the base
|
|
292
|
+
* solid/text row switching its paint type to Image, with no layer selected
|
|
293
|
+
* yet), the image becomes a new layer PREPENDED above the existing layer
|
|
294
|
+
* stack — mirroring `solidToGradientPatch`'s solid -> gradient conversion —
|
|
295
|
+
* instead of clobbering the whole background stack.
|
|
296
|
+
*/
|
|
297
|
+
export function imageFillChangePatch(
|
|
298
|
+
layers: FillLayerArrays,
|
|
299
|
+
layerIndex: number | null,
|
|
300
|
+
imageStyles: ImageFillLayerStyles,
|
|
301
|
+
): Record<
|
|
302
|
+
| "backgroundImage"
|
|
303
|
+
| "backgroundSize"
|
|
304
|
+
| "backgroundRepeat"
|
|
305
|
+
| "backgroundPosition",
|
|
306
|
+
string
|
|
307
|
+
> {
|
|
308
|
+
if (layerIndex !== null) {
|
|
309
|
+
return setImageFillLayerPatch(layers, layerIndex, imageStyles);
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
backgroundImage: joinCssLayers([
|
|
313
|
+
imageStyles.backgroundImage,
|
|
314
|
+
...layers.backgroundImage,
|
|
315
|
+
]),
|
|
316
|
+
backgroundSize: joinCssLayers([
|
|
317
|
+
imageStyles.backgroundSize,
|
|
318
|
+
...layers.backgroundSize,
|
|
319
|
+
]),
|
|
320
|
+
backgroundRepeat: joinCssLayers([
|
|
321
|
+
imageStyles.backgroundRepeat,
|
|
322
|
+
...layers.backgroundRepeat,
|
|
323
|
+
]),
|
|
324
|
+
backgroundPosition: joinCssLayers([
|
|
325
|
+
imageStyles.backgroundPosition,
|
|
326
|
+
...layers.backgroundPosition,
|
|
327
|
+
]),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Patch for the Fill panel's "+" (add fill) action.
|
|
333
|
+
*
|
|
334
|
+
* Figma parity: clicking "+" always adds a new fill on top of whatever is
|
|
335
|
+
* already there. The only exception is a genuinely empty fill state (no
|
|
336
|
+
* visible base solid AND no existing background layers) — there "+" just
|
|
337
|
+
* reveals the hidden base solid instead of stacking an empty default
|
|
338
|
+
* gradient on top of nothing.
|
|
339
|
+
*
|
|
340
|
+
* Previously the caller only checked whether the base solid had visible
|
|
341
|
+
* alpha, so an element with an existing gradient/image layer stack but a
|
|
342
|
+
* *hidden* base solid (e.g. right after `solidToGradientPatch` converts
|
|
343
|
+
* solid -> gradient and clears backgroundColor to "transparent") had "+"
|
|
344
|
+
* silently un-hide the base solid instead of adding a new layer — the
|
|
345
|
+
* opposite of what "+" is supposed to do, and it reintroduced the exact
|
|
346
|
+
* phantom-second-fill problem `solidToGradientPatch` exists to avoid.
|
|
347
|
+
*/
|
|
348
|
+
export function addFillLayerPatch(params: {
|
|
349
|
+
backgroundColor: string | undefined;
|
|
350
|
+
backgroundLayers: string[];
|
|
351
|
+
backgroundSizeLayers: string[];
|
|
352
|
+
backgroundRepeatLayers: string[];
|
|
353
|
+
backgroundPositionLayers: string[];
|
|
354
|
+
}): Record<string, string> {
|
|
355
|
+
const {
|
|
356
|
+
backgroundColor,
|
|
357
|
+
backgroundLayers,
|
|
358
|
+
backgroundSizeLayers,
|
|
359
|
+
backgroundRepeatLayers,
|
|
360
|
+
backgroundPositionLayers,
|
|
361
|
+
} = params;
|
|
362
|
+
|
|
363
|
+
if (!colorHasVisibleAlpha(backgroundColor) && backgroundLayers.length === 0) {
|
|
364
|
+
return { backgroundColor: cssColorOrFallback(backgroundColor, "#ffffff") };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const nextLayer = defaultGradientLayer(
|
|
368
|
+
"linear",
|
|
369
|
+
backgroundColor || "#ffffff",
|
|
370
|
+
);
|
|
371
|
+
if (backgroundLayers.length === 0) {
|
|
372
|
+
return { backgroundImage: nextLayer };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Prepending a layer without also prepending matching entries to the
|
|
376
|
+
// other three index-aligned parallel arrays (size/repeat/position) would
|
|
377
|
+
// shift every existing layer's index by one, silently re-pairing each of
|
|
378
|
+
// them with the *previous* layer's size/repeat/position (same class of
|
|
379
|
+
// bug `removeFillLayerAtIndex` above fixes for removal).
|
|
380
|
+
return {
|
|
381
|
+
backgroundImage: joinCssLayers([nextLayer, ...backgroundLayers]),
|
|
382
|
+
backgroundSize: joinCssLayers(["auto", ...backgroundSizeLayers]),
|
|
383
|
+
backgroundRepeat: joinCssLayers(["no-repeat", ...backgroundRepeatLayers]),
|
|
384
|
+
backgroundPosition: joinCssLayers(["0% 0%", ...backgroundPositionLayers]),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Patch for removing just the base solid/text fill row — the row shown when
|
|
390
|
+
* the base color has visible alpha, or always for a text fill. Must only
|
|
391
|
+
* clear that one property, never `backgroundImage`, so any other stacked
|
|
392
|
+
* gradient/image layers (each rendered as its own row with its own
|
|
393
|
+
* independent remove button — see `removeFillLayerAtIndex`) are left
|
|
394
|
+
* untouched. This used to also zero `backgroundImage` whenever the caller
|
|
395
|
+
* had `onStylesChange` available, silently deleting every other fill layer
|
|
396
|
+
* any time the base row's own remove button was clicked.
|
|
397
|
+
*/
|
|
398
|
+
export function removeBaseFillPatch(
|
|
399
|
+
fillProperty: "color" | "backgroundColor",
|
|
400
|
+
): Record<string, string> {
|
|
401
|
+
return { [fillProperty]: "transparent" };
|
|
402
|
+
}
|
|
403
|
+
|
|
200
404
|
export function parseGradientLayer(layer: string): ParsedGradientLayer | null {
|
|
201
405
|
const match = layer.trim().match(/^(linear|radial|conic)-gradient\((.*)\)$/i);
|
|
202
406
|
if (!match) return null;
|
|
@@ -247,7 +451,21 @@ function readLeadingColor(part: string): { raw: string; value: string } | null {
|
|
|
247
451
|
return { raw: transparent[0], value: "rgba(0, 0, 0, 0)" };
|
|
248
452
|
}
|
|
249
453
|
const functionName = trimmed.match(/^[a-z][a-z0-9-]*\(/i);
|
|
250
|
-
if (!functionName)
|
|
454
|
+
if (!functionName) {
|
|
455
|
+
// Bare CSS color keyword — e.g. `linear-gradient(red, blue)` — not just
|
|
456
|
+
// hex/rgb/hsl/function colors. Gradients written by hand or generated
|
|
457
|
+
// from named-color CSS are common, and without this branch the leading
|
|
458
|
+
// stop was silently misread as a gradient *prefix* (the first stop's
|
|
459
|
+
// color was dropped, corrupting an otherwise-valid 2-stop gradient into
|
|
460
|
+
// a broken 1-stop one with a garbage prefix). Require the matched word to
|
|
461
|
+
// actually parse as a color so direction/shape prefix keywords ("to",
|
|
462
|
+
// "circle", "closest-side", "from", "at", …) are never misclassified.
|
|
463
|
+
const word = trimmed.match(/^[a-z]+\b/i);
|
|
464
|
+
if (word && parseCssColor(word[0])) {
|
|
465
|
+
return { raw: word[0], value: word[0] };
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
251
469
|
let depth = 0;
|
|
252
470
|
for (let index = 0; index < trimmed.length; index += 1) {
|
|
253
471
|
const char = trimmed[index];
|