@agent-native/core 0.92.9 → 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 +29 -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/deploy/build.ts +133 -5
- 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/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.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/collab/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +24 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +102 -5
- package/dist/deploy/build.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/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +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
|
@@ -15,13 +15,15 @@ export type HorizontalConstraint =
|
|
|
15
15
|
| "right"
|
|
16
16
|
| "left-right"
|
|
17
17
|
| "center"
|
|
18
|
-
| "scale"
|
|
18
|
+
| "scale"
|
|
19
|
+
| "mixed";
|
|
19
20
|
export type VerticalConstraint =
|
|
20
21
|
| "top"
|
|
21
22
|
| "bottom"
|
|
22
23
|
| "top-bottom"
|
|
23
24
|
| "center"
|
|
24
|
-
| "scale"
|
|
25
|
+
| "scale"
|
|
26
|
+
| "mixed";
|
|
25
27
|
|
|
26
28
|
export interface ConstraintsValue {
|
|
27
29
|
horizontal: HorizontalConstraint;
|
|
@@ -40,6 +42,7 @@ export interface ConstraintsWidgetLabels {
|
|
|
40
42
|
topBottom: string;
|
|
41
43
|
center: string;
|
|
42
44
|
scale: string;
|
|
45
|
+
mixed: string;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export interface ConstraintsWidgetProps {
|
|
@@ -71,6 +74,7 @@ const DEFAULT_LABELS: ConstraintsWidgetLabels = {
|
|
|
71
74
|
topBottom: "Top and bottom", // i18n-ignore fallback component label
|
|
72
75
|
center: "Center", // i18n-ignore fallback component label
|
|
73
76
|
scale: "Scale", // i18n-ignore fallback component label
|
|
77
|
+
mixed: "Mixed", // i18n-ignore fallback component label
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
// ── pin-box geometry ────────────────────────────────────────────────────────
|
|
@@ -479,6 +483,10 @@ function ConstraintSelect({
|
|
|
479
483
|
{ value: "center", label: labels.center },
|
|
480
484
|
{ value: "scale", label: labels.scale },
|
|
481
485
|
];
|
|
486
|
+
const renderedOptions =
|
|
487
|
+
value === "mixed"
|
|
488
|
+
? [{ value: "mixed", label: labels.mixed, disabled: true }, ...options]
|
|
489
|
+
: options;
|
|
482
490
|
|
|
483
491
|
return (
|
|
484
492
|
<Select
|
|
@@ -492,14 +500,15 @@ function ConstraintSelect({
|
|
|
492
500
|
className="h-8 rounded-md border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-2 text-[12px] shadow-none focus:ring-1 focus:ring-[var(--design-editor-accent-color)] focus:ring-offset-0 [&>svg]:size-3"
|
|
493
501
|
aria-label={axis === "horizontal" ? labels.horizontal : labels.vertical}
|
|
494
502
|
>
|
|
495
|
-
<SelectValue />
|
|
503
|
+
{value === "mixed" ? labels.mixed : <SelectValue />}
|
|
496
504
|
</SelectTrigger>
|
|
497
505
|
<SelectContent className="z-[270]">
|
|
498
506
|
<SelectGroup>
|
|
499
|
-
{
|
|
507
|
+
{renderedOptions.map((option) => (
|
|
500
508
|
<SelectItem
|
|
501
509
|
key={option.value}
|
|
502
510
|
value={option.value}
|
|
511
|
+
disabled={"disabled" in option && option.disabled}
|
|
503
512
|
className="text-[12px]"
|
|
504
513
|
>
|
|
505
514
|
{option.label}
|
|
@@ -691,22 +691,17 @@ export function DesignColorPicker({
|
|
|
691
691
|
blendMode,
|
|
692
692
|
onBlendModeChange,
|
|
693
693
|
showBlendMode = false,
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
694
|
+
// Note: fillRows/selectedFillId/onFillSelect/onFillChange/onAddFill/
|
|
695
|
+
// onRemoveFill and gradientStops/selectedStopId/onGradientStopSelect/
|
|
696
|
+
// onGradientStopChange/onAddGradientStop/onRemoveGradientStop are
|
|
697
|
+
// deliberately NOT destructured here — see the "These interfaces remain…"
|
|
698
|
+
// comment on DesignColorPickerProps above. The popover doesn't render a
|
|
699
|
+
// fills/gradient-stops list (fill-properties.tsx in edit-panel owns that
|
|
700
|
+
// UI directly), so binding them to local variables here was dead code.
|
|
700
701
|
paintType,
|
|
701
702
|
onPaintTypeChange,
|
|
702
703
|
gradientType,
|
|
703
704
|
onGradientTypeChange,
|
|
704
|
-
gradientStops: _gradientStops,
|
|
705
|
-
selectedStopId: _selectedStopId,
|
|
706
|
-
onGradientStopSelect: _onGradientStopSelect,
|
|
707
|
-
onGradientStopChange: _onGradientStopChange,
|
|
708
|
-
onAddGradientStop: _onAddGradientStop,
|
|
709
|
-
onRemoveGradientStop: _onRemoveGradientStop,
|
|
710
705
|
documentColors,
|
|
711
706
|
supportedPaintTypes,
|
|
712
707
|
shaderContext,
|
|
@@ -752,6 +747,18 @@ export function DesignColorPicker({
|
|
|
752
747
|
const [hexDraft, setHexDraft] = useState(() => toDisplayHex(color));
|
|
753
748
|
const hexDraftRef = useRef(hexDraft);
|
|
754
749
|
const [open, setOpen] = useState(false);
|
|
750
|
+
// Snapshot of value/opacity/paintType captured the instant the popover
|
|
751
|
+
// opens, so Escape can cancel the whole editing session — matching Figma:
|
|
752
|
+
// dragging hue/sat/alpha/gradient stops live-previews the color, but
|
|
753
|
+
// Escaping out reverts everything back to how it was before the popover
|
|
754
|
+
// opened, not just whatever field happens to be focused. Re-snapshotted
|
|
755
|
+
// only on the open transition (see the effect below), never while already
|
|
756
|
+
// open, so it doesn't chase the user's own edits.
|
|
757
|
+
const openSnapshotRef = useRef({
|
|
758
|
+
value,
|
|
759
|
+
opacity: effectiveOpacity,
|
|
760
|
+
paintType,
|
|
761
|
+
});
|
|
755
762
|
const [picking, setPicking] = useState(false);
|
|
756
763
|
const skipNextHexBlurCommitRef = useRef(false);
|
|
757
764
|
// Preserve the last non-zero hue so dragging through an achromatic point
|
|
@@ -835,6 +842,16 @@ export function DesignColorPicker({
|
|
|
835
842
|
setHexDraft(nextHex);
|
|
836
843
|
}, [color.r, color.g, color.b]);
|
|
837
844
|
|
|
845
|
+
useEffect(() => {
|
|
846
|
+
if (open) {
|
|
847
|
+
openSnapshotRef.current = { value, opacity: effectiveOpacity, paintType };
|
|
848
|
+
}
|
|
849
|
+
// Deliberately only depends on `open`: this must capture the value as of
|
|
850
|
+
// the open transition, not re-run on every edit made while already open
|
|
851
|
+
// (that would defeat the point of an Escape-to-cancel snapshot).
|
|
852
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
853
|
+
}, [open]);
|
|
854
|
+
|
|
838
855
|
// The local override (the user's explicit paint-type click) persists for the
|
|
839
856
|
// life of the open popover so EditPanel bouncing `paintType` back to solid
|
|
840
857
|
// can't wipe a just-selected gradient/image/shader. A new element selection
|
|
@@ -1015,15 +1032,31 @@ export function DesignColorPicker({
|
|
|
1015
1032
|
onImageFillChange(next);
|
|
1016
1033
|
return;
|
|
1017
1034
|
}
|
|
1035
|
+
// ImageFillControls has no drag surface of its own (URL entry, file
|
|
1036
|
+
// pick, and fit selection are each already a discrete, complete action),
|
|
1037
|
+
// so — unlike the SV field / hue / alpha tracks — every onChange call
|
|
1038
|
+
// here is itself a final commit, never a live-preview tick.
|
|
1018
1039
|
emitPaintValue(imageFillToCss(next));
|
|
1040
|
+
notifyChangeComplete();
|
|
1019
1041
|
};
|
|
1020
1042
|
|
|
1021
1043
|
// ── Shader editing ──────────────────────────────────────────────────────────────
|
|
1022
1044
|
|
|
1023
|
-
|
|
1045
|
+
// Cheap live preview — fires on every ShaderFillsPanel tuning tick. Must
|
|
1046
|
+
// not call notifyChangeComplete (that's the expensive-commit signal), or
|
|
1047
|
+
// every drag tick would dirty undo history the same way an un-split
|
|
1048
|
+
// onChange/onChangeComplete would for color/gradient dragging.
|
|
1049
|
+
const previewShader = (descriptor: ShaderDescriptor, css: string) => {
|
|
1050
|
+
setShaderDescriptor(descriptor);
|
|
1051
|
+
emitPaintValue(css);
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
// Fires once per gesture/discrete pick (see ShaderFillsPanel's onCommit).
|
|
1055
|
+
const commitShader = (descriptor: ShaderDescriptor, css: string) => {
|
|
1024
1056
|
setShaderDescriptor(descriptor);
|
|
1025
1057
|
onShaderChange?.(descriptor, css);
|
|
1026
1058
|
emitPaintValue(css);
|
|
1059
|
+
notifyChangeComplete();
|
|
1027
1060
|
};
|
|
1028
1061
|
|
|
1029
1062
|
// ── Paint-type switching (does real work for every type) ──────────────────────
|
|
@@ -1134,6 +1167,29 @@ export function DesignColorPicker({
|
|
|
1134
1167
|
|
|
1135
1168
|
const hasEyeDropper = hasEyeDropperSupport();
|
|
1136
1169
|
|
|
1170
|
+
// Cancels the whole editing session back to the snapshot captured when the
|
|
1171
|
+
// popover opened — the Escape-key contract (matches Figma: any live-preview
|
|
1172
|
+
// dragging done while the popover was open gets thrown away, not just
|
|
1173
|
+
// whatever field currently has focus). Resets every local override so the
|
|
1174
|
+
// effective paint type / gradient / shader recompute cleanly from the
|
|
1175
|
+
// reverted props on the next render.
|
|
1176
|
+
const revertToOpenSnapshot = () => {
|
|
1177
|
+
if (disabled) return;
|
|
1178
|
+
const snapshot = openSnapshotRef.current;
|
|
1179
|
+
setLocalPaintType(null);
|
|
1180
|
+
setLocalGradient(null);
|
|
1181
|
+
setSelectedStopId("");
|
|
1182
|
+
setShaderDescriptor(null);
|
|
1183
|
+
setView("picker");
|
|
1184
|
+
if (onPaintTypeChange && snapshot.paintType !== undefined) {
|
|
1185
|
+
onPaintTypeChange(snapshot.paintType);
|
|
1186
|
+
}
|
|
1187
|
+
if (onOpacityChange) onOpacityChange(snapshot.opacity);
|
|
1188
|
+
lastEmittedValueRef.current = snapshot.value;
|
|
1189
|
+
onChange(snapshot.value);
|
|
1190
|
+
onChangeComplete?.(snapshot.value);
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1137
1193
|
// ── Value row inputs by mode ─────────────────────────────────────────────────
|
|
1138
1194
|
|
|
1139
1195
|
function renderValueInputs() {
|
|
@@ -1185,6 +1241,7 @@ export function DesignColorPicker({
|
|
|
1185
1241
|
max={255}
|
|
1186
1242
|
disabled={disabled}
|
|
1187
1243
|
onChange={(next) => emitFieldColor({ ...fieldColor, [ch]: next })}
|
|
1244
|
+
onCommit={notifyChangeComplete}
|
|
1188
1245
|
/>
|
|
1189
1246
|
))}
|
|
1190
1247
|
</div>
|
|
@@ -1200,6 +1257,7 @@ export function DesignColorPicker({
|
|
|
1200
1257
|
max={360}
|
|
1201
1258
|
disabled={disabled}
|
|
1202
1259
|
onChange={(h) => emitFieldHsl({ ...fieldHsl, h })}
|
|
1260
|
+
onCommit={notifyChangeComplete}
|
|
1203
1261
|
/>
|
|
1204
1262
|
<ScrubbyNumberInput
|
|
1205
1263
|
aria-label={copy.saturation}
|
|
@@ -1208,6 +1266,7 @@ export function DesignColorPicker({
|
|
|
1208
1266
|
max={100}
|
|
1209
1267
|
disabled={disabled}
|
|
1210
1268
|
onChange={(s) => emitFieldHsl({ ...fieldHsl, s })}
|
|
1269
|
+
onCommit={notifyChangeComplete}
|
|
1211
1270
|
/>
|
|
1212
1271
|
<ScrubbyNumberInput
|
|
1213
1272
|
aria-label={copy.lightness}
|
|
@@ -1216,6 +1275,7 @@ export function DesignColorPicker({
|
|
|
1216
1275
|
max={100}
|
|
1217
1276
|
disabled={disabled}
|
|
1218
1277
|
onChange={(l) => emitFieldHsl({ ...fieldHsl, l })}
|
|
1278
|
+
onCommit={notifyChangeComplete}
|
|
1219
1279
|
/>
|
|
1220
1280
|
</div>
|
|
1221
1281
|
);
|
|
@@ -1230,6 +1290,7 @@ export function DesignColorPicker({
|
|
|
1230
1290
|
max={360}
|
|
1231
1291
|
disabled={disabled}
|
|
1232
1292
|
onChange={(h) => emitFieldHsv({ ...fieldHsv, h })}
|
|
1293
|
+
onCommit={notifyChangeComplete}
|
|
1233
1294
|
/>
|
|
1234
1295
|
<ScrubbyNumberInput
|
|
1235
1296
|
aria-label={copy.saturation}
|
|
@@ -1238,6 +1299,7 @@ export function DesignColorPicker({
|
|
|
1238
1299
|
max={100}
|
|
1239
1300
|
disabled={disabled}
|
|
1240
1301
|
onChange={(s) => emitFieldHsv({ ...fieldHsv, s })}
|
|
1302
|
+
onCommit={notifyChangeComplete}
|
|
1241
1303
|
/>
|
|
1242
1304
|
<ScrubbyNumberInput
|
|
1243
1305
|
aria-label={copy.brightness}
|
|
@@ -1246,6 +1308,7 @@ export function DesignColorPicker({
|
|
|
1246
1308
|
max={100}
|
|
1247
1309
|
disabled={disabled}
|
|
1248
1310
|
onChange={(v) => emitFieldHsv({ ...fieldHsv, v })}
|
|
1311
|
+
onCommit={notifyChangeComplete}
|
|
1249
1312
|
/>
|
|
1250
1313
|
</div>
|
|
1251
1314
|
);
|
|
@@ -1298,6 +1361,11 @@ export function DesignColorPicker({
|
|
|
1298
1361
|
// re-projection can't close the popover. Genuine pointer clicks
|
|
1299
1362
|
// outside still close it via the default onInteractOutside behavior.
|
|
1300
1363
|
onFocusOutside={(e) => e.preventDefault()}
|
|
1364
|
+
// Escape cancels the whole editing session (see revertToOpenSnapshot)
|
|
1365
|
+
// and then still closes the popover via Radix's default dismiss
|
|
1366
|
+
// behavior — this only reverts the color/opacity/paint-type state,
|
|
1367
|
+
// it doesn't call `e.preventDefault()`, so the close still happens.
|
|
1368
|
+
onEscapeKeyDown={revertToOpenSnapshot}
|
|
1301
1369
|
>
|
|
1302
1370
|
<div className="rounded-md bg-popover text-popover-foreground">
|
|
1303
1371
|
{view === "shader" && glslShaderContext ? (
|
|
@@ -1320,7 +1388,8 @@ export function DesignColorPicker({
|
|
|
1320
1388
|
descriptor={shaderDescriptor ?? undefined}
|
|
1321
1389
|
applyContext={shaderContext}
|
|
1322
1390
|
disabled={disabled}
|
|
1323
|
-
onApply={
|
|
1391
|
+
onApply={previewShader}
|
|
1392
|
+
onCommit={commitShader}
|
|
1324
1393
|
onBack={() => {
|
|
1325
1394
|
setView("picker");
|
|
1326
1395
|
if (effectivePaintType === "shader") {
|
|
@@ -1452,19 +1521,23 @@ export function DesignColorPicker({
|
|
|
1452
1521
|
if (e.key === "Enter") {
|
|
1453
1522
|
e.preventDefault();
|
|
1454
1523
|
const url = e.currentTarget.value.trim();
|
|
1455
|
-
if (url)
|
|
1524
|
+
if (url) {
|
|
1456
1525
|
emitPaintValue(
|
|
1457
1526
|
`url("${url}") center / cover no-repeat`,
|
|
1458
1527
|
);
|
|
1528
|
+
notifyChangeComplete();
|
|
1529
|
+
}
|
|
1459
1530
|
e.currentTarget.blur();
|
|
1460
1531
|
}
|
|
1461
1532
|
}}
|
|
1462
1533
|
onBlur={(e) => {
|
|
1463
1534
|
const url = e.currentTarget.value.trim();
|
|
1464
|
-
if (url)
|
|
1535
|
+
if (url) {
|
|
1465
1536
|
emitPaintValue(
|
|
1466
1537
|
`url("${url}") center / cover no-repeat`,
|
|
1467
1538
|
);
|
|
1539
|
+
notifyChangeComplete();
|
|
1540
|
+
}
|
|
1468
1541
|
}}
|
|
1469
1542
|
/>
|
|
1470
1543
|
</div>
|
|
@@ -1479,6 +1552,7 @@ export function DesignColorPicker({
|
|
|
1479
1552
|
disabled={disabled}
|
|
1480
1553
|
onSelectStop={setSelectedStopId}
|
|
1481
1554
|
onChange={emitGradient}
|
|
1555
|
+
onCommit={notifyChangeComplete}
|
|
1482
1556
|
/>
|
|
1483
1557
|
</div>
|
|
1484
1558
|
)}
|
|
@@ -1660,6 +1734,7 @@ export function DesignColorPicker({
|
|
|
1660
1734
|
setOpacity(next);
|
|
1661
1735
|
}
|
|
1662
1736
|
}}
|
|
1737
|
+
onCommit={notifyChangeComplete}
|
|
1663
1738
|
className="h-full min-w-0 flex-1 rounded-none border-0 bg-transparent px-1 !text-[11px] tabular-nums shadow-none focus-visible:ring-0"
|
|
1664
1739
|
compact
|
|
1665
1740
|
/>
|
|
@@ -1959,7 +2034,7 @@ function SaturationBrightnessField({
|
|
|
1959
2034
|
}}
|
|
1960
2035
|
onKeyDown={stepWithKeyboard}
|
|
1961
2036
|
className={cn(
|
|
1962
|
-
"relative h-48 w-full cursor-crosshair overflow-hidden outline-none",
|
|
2037
|
+
"relative h-48 w-full touch-none cursor-crosshair overflow-hidden outline-none",
|
|
1963
2038
|
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
|
|
1964
2039
|
"active:cursor-grabbing",
|
|
1965
2040
|
disabled && "cursor-not-allowed opacity-60",
|
|
@@ -2080,7 +2155,7 @@ function ColorTrack({
|
|
|
2080
2155
|
if (ended.shouldCommit) onCommit?.();
|
|
2081
2156
|
}}
|
|
2082
2157
|
className={cn(
|
|
2083
|
-
"relative h-3.5 cursor-pointer rounded-full border border-border/60 outline-none",
|
|
2158
|
+
"relative h-3.5 touch-none cursor-pointer rounded-full border border-border/60 outline-none",
|
|
2084
2159
|
"ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
2085
2160
|
"active:cursor-grabbing",
|
|
2086
2161
|
disabled && "cursor-not-allowed opacity-60",
|
|
@@ -2097,7 +2172,14 @@ function ColorTrack({
|
|
|
2097
2172
|
}
|
|
2098
2173
|
|
|
2099
2174
|
/**
|
|
2100
|
-
* A number input with select-on-focus
|
|
2175
|
+
* A number input with select-on-focus, Esc-to-revert, arrow-key nudging, and
|
|
2176
|
+
* Figma-style click-drag "scrubbing": pressing down and dragging left/right
|
|
2177
|
+
* decrements/increments the value continuously (Shift = 10x coarser step,
|
|
2178
|
+
* matching the same shift convention as arrow-key nudges and the SV/hue/alpha
|
|
2179
|
+
* tracks) without needing to type. A short press-release with no meaningful
|
|
2180
|
+
* movement is treated as an ordinary click so focus + select-on-focus (and
|
|
2181
|
+
* therefore typing) keep working exactly as before.
|
|
2182
|
+
*
|
|
2101
2183
|
* The `compact` prop removes inner padding for use inside bordered wrappers.
|
|
2102
2184
|
*/
|
|
2103
2185
|
function ScrubbyNumberInput({
|
|
@@ -2107,6 +2189,7 @@ function ScrubbyNumberInput({
|
|
|
2107
2189
|
max,
|
|
2108
2190
|
disabled,
|
|
2109
2191
|
onChange,
|
|
2192
|
+
onCommit,
|
|
2110
2193
|
className,
|
|
2111
2194
|
compact = false,
|
|
2112
2195
|
}: {
|
|
@@ -2116,12 +2199,22 @@ function ScrubbyNumberInput({
|
|
|
2116
2199
|
max: number;
|
|
2117
2200
|
disabled: boolean;
|
|
2118
2201
|
onChange: (value: number) => void;
|
|
2202
|
+
/**
|
|
2203
|
+
* Fires once per discrete, complete edit: a blur/Enter commit (only when
|
|
2204
|
+
* the draft actually parsed — not on a revert), each arrow-key step, and
|
|
2205
|
+
* once at the end of a scrub drag (not per pointermove tick). Mirrors the
|
|
2206
|
+
* `onCommit` contract used by SaturationBrightnessField/ColorTrack so every
|
|
2207
|
+
* draggable/steppable control in this picker notifies
|
|
2208
|
+
* `onChangeComplete` exactly once per gesture.
|
|
2209
|
+
*/
|
|
2210
|
+
onCommit?: () => void;
|
|
2119
2211
|
className?: string;
|
|
2120
2212
|
compact?: boolean;
|
|
2121
2213
|
}) {
|
|
2122
2214
|
const [draft, setDraft] = useState<string>(() => String(value));
|
|
2123
2215
|
const draftRef = useRef(draft);
|
|
2124
2216
|
const skipBlurRef = useRef(false);
|
|
2217
|
+
const scrubRef = useRef<ScrubGestureState>(SCRUB_GESTURE_IDLE);
|
|
2125
2218
|
|
|
2126
2219
|
useEffect(() => {
|
|
2127
2220
|
const nextDraft = String(value);
|
|
@@ -2138,6 +2231,7 @@ function ScrubbyNumberInput({
|
|
|
2138
2231
|
return;
|
|
2139
2232
|
}
|
|
2140
2233
|
onChange(clamp(parsed, min, max));
|
|
2234
|
+
onCommit?.();
|
|
2141
2235
|
};
|
|
2142
2236
|
|
|
2143
2237
|
return (
|
|
@@ -2149,8 +2243,15 @@ function ScrubbyNumberInput({
|
|
|
2149
2243
|
max={max}
|
|
2150
2244
|
disabled={disabled}
|
|
2151
2245
|
className={cn(
|
|
2152
|
-
"h-6 w-full rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] text-center !text-[11px] tabular-nums",
|
|
2246
|
+
"h-6 w-full touch-none rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] text-center !text-[11px] tabular-nums",
|
|
2153
2247
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2248
|
+
// Figma's numeric fields never show the native up/down spinner —
|
|
2249
|
+
// hide it in both engines so this reads as a plain scrubbable value,
|
|
2250
|
+
// not a browser default number input. (The spinner buttons also
|
|
2251
|
+
// bypassed this component's onChange/onCommit contract entirely,
|
|
2252
|
+
// since native stepper clicks only mutate the draft string, not the
|
|
2253
|
+
// color — hiding them removes that dead, contract-violating path.)
|
|
2254
|
+
"[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
|
2154
2255
|
compact && "border-0 shadow-none focus-visible:ring-0",
|
|
2155
2256
|
className,
|
|
2156
2257
|
)}
|
|
@@ -2179,6 +2280,7 @@ function ScrubbyNumberInput({
|
|
|
2179
2280
|
const parsed = Number(draftRef.current);
|
|
2180
2281
|
const base = Number.isFinite(parsed) ? parsed : value;
|
|
2181
2282
|
onChange(clamp(base + step, min, max));
|
|
2283
|
+
onCommit?.();
|
|
2182
2284
|
}
|
|
2183
2285
|
if (e.key === "ArrowDown") {
|
|
2184
2286
|
e.preventDefault();
|
|
@@ -2186,6 +2288,7 @@ function ScrubbyNumberInput({
|
|
|
2186
2288
|
const parsed = Number(draftRef.current);
|
|
2187
2289
|
const base = Number.isFinite(parsed) ? parsed : value;
|
|
2188
2290
|
onChange(clamp(base - step, min, max));
|
|
2291
|
+
onCommit?.();
|
|
2189
2292
|
}
|
|
2190
2293
|
}}
|
|
2191
2294
|
onBlur={() => {
|
|
@@ -2195,6 +2298,58 @@ function ScrubbyNumberInput({
|
|
|
2195
2298
|
}
|
|
2196
2299
|
commit();
|
|
2197
2300
|
}}
|
|
2301
|
+
onPointerDown={(e) => {
|
|
2302
|
+
if (disabled) return;
|
|
2303
|
+
// Don't preventDefault here — a plain click (no subsequent movement
|
|
2304
|
+
// past the threshold) must still focus the input normally so typing
|
|
2305
|
+
// keeps working. Pointer capture just ensures a real drag keeps
|
|
2306
|
+
// routing to this element even once the cursor leaves its bounds.
|
|
2307
|
+
scrubRef.current = startScrubGesture(e.clientX, value);
|
|
2308
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2309
|
+
}}
|
|
2310
|
+
onPointerMove={(e) => {
|
|
2311
|
+
if (disabled || !scrubRef.current.active) return;
|
|
2312
|
+
const deltaX = e.clientX - scrubRef.current.startX;
|
|
2313
|
+
if (!scrubRef.current.dragging) {
|
|
2314
|
+
if (Math.abs(deltaX) < SCRUB_DRAG_THRESHOLD_PX) return;
|
|
2315
|
+
scrubRef.current = { ...scrubRef.current, dragging: true };
|
|
2316
|
+
// Now that this is a genuine drag (not a click), stop the browser
|
|
2317
|
+
// from turning the pointer move into a text-selection drag.
|
|
2318
|
+
window.getSelection?.()?.removeAllRanges();
|
|
2319
|
+
}
|
|
2320
|
+
e.preventDefault();
|
|
2321
|
+
onChange(
|
|
2322
|
+
computeScrubbedValue(
|
|
2323
|
+
scrubRef.current.startValue,
|
|
2324
|
+
deltaX,
|
|
2325
|
+
min,
|
|
2326
|
+
max,
|
|
2327
|
+
e.shiftKey,
|
|
2328
|
+
),
|
|
2329
|
+
);
|
|
2330
|
+
}}
|
|
2331
|
+
onPointerUp={(e) => {
|
|
2332
|
+
const wasDragging = scrubRef.current.dragging;
|
|
2333
|
+
scrubRef.current = SCRUB_GESTURE_IDLE;
|
|
2334
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
2335
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
2336
|
+
}
|
|
2337
|
+
if (wasDragging) {
|
|
2338
|
+
onCommit?.();
|
|
2339
|
+
// A drag ended without focusing the field for text entry — match
|
|
2340
|
+
// Figma (dragging a number field doesn't leave it in edit mode).
|
|
2341
|
+
skipBlurRef.current = true;
|
|
2342
|
+
e.currentTarget.blur();
|
|
2343
|
+
}
|
|
2344
|
+
}}
|
|
2345
|
+
onPointerCancel={(e) => {
|
|
2346
|
+
const wasDragging = scrubRef.current.dragging;
|
|
2347
|
+
scrubRef.current = SCRUB_GESTURE_IDLE;
|
|
2348
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
2349
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
2350
|
+
}
|
|
2351
|
+
if (wasDragging) onCommit?.();
|
|
2352
|
+
}}
|
|
2198
2353
|
/>
|
|
2199
2354
|
);
|
|
2200
2355
|
}
|
|
@@ -2230,6 +2385,61 @@ export function endPointerGesture(state: PointerGestureState): {
|
|
|
2230
2385
|
return { state: POINTER_GESTURE_IDLE, shouldCommit: state };
|
|
2231
2386
|
}
|
|
2232
2387
|
|
|
2388
|
+
// ─── Click-drag "scrub" tracking for ScrubbyNumberInput ────────────────────────
|
|
2389
|
+
//
|
|
2390
|
+
// A plain pointerdown+pointerup with no meaningful movement must behave like
|
|
2391
|
+
// an ordinary click (focus the input, select-on-focus, allow typing) — it
|
|
2392
|
+
// only becomes a scrub once the pointer has moved past a small pixel
|
|
2393
|
+
// threshold, matching Figma's numeric fields (click to type, click-drag to
|
|
2394
|
+
// scrub). `dragging` flips true exactly once per gesture, the first time the
|
|
2395
|
+
// threshold is crossed.
|
|
2396
|
+
|
|
2397
|
+
const SCRUB_DRAG_THRESHOLD_PX = 3;
|
|
2398
|
+
/** Pixels of drag per 1 unit of value change at the normal (non-Shift) rate. */
|
|
2399
|
+
const SCRUB_PIXELS_PER_STEP = 4;
|
|
2400
|
+
|
|
2401
|
+
export interface ScrubGestureState {
|
|
2402
|
+
/** True from pointerdown until the matching pointerup/pointercancel. */
|
|
2403
|
+
active: boolean;
|
|
2404
|
+
/** True once the drag has crossed the click-vs-drag threshold. */
|
|
2405
|
+
dragging: boolean;
|
|
2406
|
+
startX: number;
|
|
2407
|
+
startValue: number;
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
export const SCRUB_GESTURE_IDLE: ScrubGestureState = {
|
|
2411
|
+
active: false,
|
|
2412
|
+
dragging: false,
|
|
2413
|
+
startX: 0,
|
|
2414
|
+
startValue: 0,
|
|
2415
|
+
};
|
|
2416
|
+
|
|
2417
|
+
/** Call on pointerdown: starts tracking a new potential scrub gesture. */
|
|
2418
|
+
export function startScrubGesture(
|
|
2419
|
+
startX: number,
|
|
2420
|
+
startValue: number,
|
|
2421
|
+
): ScrubGestureState {
|
|
2422
|
+
return { active: true, dragging: false, startX, startValue };
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
/**
|
|
2426
|
+
* Pure math for one scrub tick: converts total horizontal drag distance
|
|
2427
|
+
* (from the gesture's start position) into a new clamped value. Shift scales
|
|
2428
|
+
* the rate 10x coarser, matching the same shift convention as arrow-key
|
|
2429
|
+
* nudges and the SV/hue/alpha track keyboard steps.
|
|
2430
|
+
*/
|
|
2431
|
+
export function computeScrubbedValue(
|
|
2432
|
+
startValue: number,
|
|
2433
|
+
deltaX: number,
|
|
2434
|
+
min: number,
|
|
2435
|
+
max: number,
|
|
2436
|
+
shiftKey: boolean,
|
|
2437
|
+
): number {
|
|
2438
|
+
const rate = shiftKey ? 10 : 1;
|
|
2439
|
+
const delta = Math.round(deltaX / SCRUB_PIXELS_PER_STEP) * rate;
|
|
2440
|
+
return clamp(startValue + delta, min, max);
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2233
2443
|
// ─── Utilities ─────────────────────────────────────────────────────────────────
|
|
2234
2444
|
|
|
2235
2445
|
export function inferPaintType(
|
|
@@ -2388,7 +2598,7 @@ function alphaTrackBackground(color: RgbaColor): string {
|
|
|
2388
2598
|
return `${CHECKERBOARD_IMAGE}, linear-gradient(90deg, rgba(${color.r}, ${color.g}, ${color.b}, 0), rgba(${color.r}, ${color.g}, ${color.b}, 1))`;
|
|
2389
2599
|
}
|
|
2390
2600
|
|
|
2391
|
-
function rgbaToHsv(color: RgbaColor): HsvaColor {
|
|
2601
|
+
export function rgbaToHsv(color: RgbaColor): HsvaColor {
|
|
2392
2602
|
const r = clampFloat(color.r / 255, 0, 1);
|
|
2393
2603
|
const g = clampFloat(color.g / 255, 0, 1);
|
|
2394
2604
|
const b = clampFloat(color.b / 255, 0, 1);
|
|
@@ -2413,7 +2623,7 @@ function rgbaToHsv(color: RgbaColor): HsvaColor {
|
|
|
2413
2623
|
};
|
|
2414
2624
|
}
|
|
2415
2625
|
|
|
2416
|
-
function hsvToRgba(color: HsvaColor): RgbaColor {
|
|
2626
|
+
export function hsvToRgba(color: HsvaColor): RgbaColor {
|
|
2417
2627
|
const h = ((color.h % 360) + 360) % 360;
|
|
2418
2628
|
const s = clampFloat(color.s, 0, 100) / 100;
|
|
2419
2629
|
const v = clampFloat(color.v, 0, 100) / 100;
|
|
@@ -2449,7 +2659,7 @@ function clampFloat(value: number, min: number, max: number): number {
|
|
|
2449
2659
|
return Math.max(min, Math.min(max, value));
|
|
2450
2660
|
}
|
|
2451
2661
|
|
|
2452
|
-
function hasHexAlpha(value: string): boolean {
|
|
2662
|
+
export function hasHexAlpha(value: string): boolean {
|
|
2453
2663
|
return /^#?(?:[0-9a-f]{4}|[0-9a-f]{8})$/i.test(value.trim());
|
|
2454
2664
|
}
|
|
2455
2665
|
|