@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
|
@@ -285,11 +285,18 @@ export function parseGradientCss(
|
|
|
285
285
|
interface AngleDialProps {
|
|
286
286
|
angle: number;
|
|
287
287
|
onChange: (angle: number) => void;
|
|
288
|
+
/** Fires once when a drag gesture ends (pointerup/pointercancel) — see GradientEditorProps.onCommit. */
|
|
289
|
+
onCommit?: () => void;
|
|
288
290
|
disabled?: boolean;
|
|
289
291
|
}
|
|
290
292
|
|
|
291
293
|
/** design-editor circular dial for rotating gradient angle. */
|
|
292
|
-
function AngleDial({
|
|
294
|
+
function AngleDial({
|
|
295
|
+
angle,
|
|
296
|
+
onChange,
|
|
297
|
+
onCommit,
|
|
298
|
+
disabled = false,
|
|
299
|
+
}: AngleDialProps) {
|
|
293
300
|
const dialRef = useRef<HTMLDivElement>(null);
|
|
294
301
|
const draggingRef = useRef(false);
|
|
295
302
|
|
|
@@ -319,10 +326,12 @@ function AngleDial({ angle, onChange, disabled = false }: AngleDialProps) {
|
|
|
319
326
|
};
|
|
320
327
|
|
|
321
328
|
const handlePointerUp = (e: ReactPointerEvent<HTMLDivElement>) => {
|
|
329
|
+
const wasDragging = draggingRef.current;
|
|
322
330
|
draggingRef.current = false;
|
|
323
331
|
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
324
332
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
325
333
|
}
|
|
334
|
+
if (wasDragging) onCommit?.();
|
|
326
335
|
};
|
|
327
336
|
|
|
328
337
|
const dotAngle = ((angle - 90) * Math.PI) / 180;
|
|
@@ -349,9 +358,11 @@ function AngleDial({ angle, onChange, disabled = false }: AngleDialProps) {
|
|
|
349
358
|
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
350
359
|
e.preventDefault();
|
|
351
360
|
onChange((angle + 1) % 360);
|
|
361
|
+
onCommit?.();
|
|
352
362
|
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
353
363
|
e.preventDefault();
|
|
354
364
|
onChange((angle - 1 + 360) % 360);
|
|
365
|
+
onCommit?.();
|
|
355
366
|
}
|
|
356
367
|
}}
|
|
357
368
|
className={cn(
|
|
@@ -394,6 +405,18 @@ function AngleDial({ angle, onChange, disabled = false }: AngleDialProps) {
|
|
|
394
405
|
export interface GradientEditorProps {
|
|
395
406
|
value: GradientValue;
|
|
396
407
|
onChange: (value: GradientValue) => void;
|
|
408
|
+
/**
|
|
409
|
+
* Fires once per discrete edit or drag gesture — mirrors the
|
|
410
|
+
* `onChangeComplete` convention used by `DesignColorPickerProps` (see the
|
|
411
|
+
* doc comment there): `onChange` alone fires on every stop-drag/angle-drag
|
|
412
|
+
* pointermove tick (cheap live preview), while `onCommit` fires exactly
|
|
413
|
+
* once (stop added, stop removed, stop-drag pointerup, angle-drag
|
|
414
|
+
* pointerup, or a position/angle field committed via blur/Enter) so a
|
|
415
|
+
* caller that persists through history only records one entry per gesture
|
|
416
|
+
* instead of one per tick. Optional so existing callers that only wired
|
|
417
|
+
* `onChange` keep their current every-tick-is-final behavior.
|
|
418
|
+
*/
|
|
419
|
+
onCommit?: () => void;
|
|
397
420
|
selectedStopId: string;
|
|
398
421
|
onSelectStop: (id: string) => void;
|
|
399
422
|
disabled?: boolean;
|
|
@@ -412,6 +435,7 @@ const WRAPPER_HEIGHT = BAR_HEIGHT + HANDLE_AREA; // total component height
|
|
|
412
435
|
export function GradientEditor({
|
|
413
436
|
value,
|
|
414
437
|
onChange,
|
|
438
|
+
onCommit,
|
|
415
439
|
selectedStopId,
|
|
416
440
|
onSelectStop,
|
|
417
441
|
disabled = false,
|
|
@@ -419,6 +443,10 @@ export function GradientEditor({
|
|
|
419
443
|
}: GradientEditorProps) {
|
|
420
444
|
const barRef = useRef<HTMLDivElement>(null);
|
|
421
445
|
const draggingStopRef = useRef<string | null>(null);
|
|
446
|
+
// Set once a stop-drag actually moves the pointer (vs a plain click that
|
|
447
|
+
// only selects the stop) — endStopDrag uses this to skip firing onCommit
|
|
448
|
+
// for a no-op "select" click where nothing actually changed.
|
|
449
|
+
const stopDragMovedRef = useRef(false);
|
|
422
450
|
// Track whether a pointerdown on the bar started a drag (vs click-to-add).
|
|
423
451
|
const barClickRef = useRef<{ moved: boolean; startX: number } | null>(null);
|
|
424
452
|
|
|
@@ -502,6 +530,7 @@ export function GradientEditor({
|
|
|
502
530
|
};
|
|
503
531
|
onChange({ ...value, stops: [...value.stops, newStop] });
|
|
504
532
|
onSelectStop(newStop.id);
|
|
533
|
+
onCommit?.();
|
|
505
534
|
};
|
|
506
535
|
|
|
507
536
|
const startStopDrag = (
|
|
@@ -513,6 +542,7 @@ export function GradientEditor({
|
|
|
513
542
|
event.preventDefault();
|
|
514
543
|
onSelectStop(id);
|
|
515
544
|
draggingStopRef.current = id;
|
|
545
|
+
stopDragMovedRef.current = false;
|
|
516
546
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
517
547
|
};
|
|
518
548
|
|
|
@@ -520,6 +550,7 @@ export function GradientEditor({
|
|
|
520
550
|
event: ReactPointerEvent<HTMLButtonElement>,
|
|
521
551
|
) => {
|
|
522
552
|
if (!draggingStopRef.current || disabled) return;
|
|
553
|
+
stopDragMovedRef.current = true;
|
|
523
554
|
updateStopPosition(
|
|
524
555
|
draggingStopRef.current,
|
|
525
556
|
positionFromPointer(event.clientX),
|
|
@@ -527,10 +558,14 @@ export function GradientEditor({
|
|
|
527
558
|
};
|
|
528
559
|
|
|
529
560
|
const endStopDrag = (event: ReactPointerEvent<HTMLButtonElement>) => {
|
|
561
|
+
const wasDragging =
|
|
562
|
+
draggingStopRef.current !== null && stopDragMovedRef.current;
|
|
530
563
|
draggingStopRef.current = null;
|
|
564
|
+
stopDragMovedRef.current = false;
|
|
531
565
|
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
532
566
|
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
533
567
|
}
|
|
568
|
+
if (wasDragging) onCommit?.();
|
|
534
569
|
};
|
|
535
570
|
|
|
536
571
|
const removeStop = (id: string) => {
|
|
@@ -541,6 +576,7 @@ export function GradientEditor({
|
|
|
541
576
|
if (selectedStopId === id) {
|
|
542
577
|
onSelectStop(nearestStopId(nextStops, removed?.position) ?? "");
|
|
543
578
|
}
|
|
579
|
+
onCommit?.();
|
|
544
580
|
};
|
|
545
581
|
|
|
546
582
|
const setAngle = (angle: number) => {
|
|
@@ -576,6 +612,7 @@ export function GradientEditor({
|
|
|
576
612
|
return;
|
|
577
613
|
}
|
|
578
614
|
updateStopPosition(selectedStopId, parsed);
|
|
615
|
+
onCommit?.();
|
|
579
616
|
};
|
|
580
617
|
|
|
581
618
|
const revertPositionDraft = () => {
|
|
@@ -651,6 +688,28 @@ export function GradientEditor({
|
|
|
651
688
|
e.stopPropagation();
|
|
652
689
|
removeStop(stop.id);
|
|
653
690
|
}}
|
|
691
|
+
onKeyDown={(e) => {
|
|
692
|
+
if (disabled) return;
|
|
693
|
+
// Figma parity: Delete/Backspace removes the focused stop,
|
|
694
|
+
// and Left/Right nudges its position (Shift for a bigger
|
|
695
|
+
// step) — mirrors the numeric position field's arrow-key
|
|
696
|
+
// behavior but works directly on the handle too.
|
|
697
|
+
if (e.key === "Delete" || e.key === "Backspace") {
|
|
698
|
+
e.preventDefault();
|
|
699
|
+
removeStop(stop.id);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
|
|
703
|
+
e.preventDefault();
|
|
704
|
+
const step = e.shiftKey ? 10 : 1;
|
|
705
|
+
const delta = e.key === "ArrowRight" ? step : -step;
|
|
706
|
+
updateStopPosition(
|
|
707
|
+
stop.id,
|
|
708
|
+
clamp(stop.position + delta, 0, 100),
|
|
709
|
+
);
|
|
710
|
+
onCommit?.();
|
|
711
|
+
}
|
|
712
|
+
}}
|
|
654
713
|
className={cn(
|
|
655
714
|
// Base: round handle with white border ring + outer accent ring
|
|
656
715
|
"absolute cursor-grab active:cursor-grabbing",
|
|
@@ -724,6 +783,7 @@ export function GradientEditor({
|
|
|
724
783
|
<AngleDial
|
|
725
784
|
angle={value.angle}
|
|
726
785
|
onChange={setAngle}
|
|
786
|
+
onCommit={onCommit}
|
|
727
787
|
disabled={disabled}
|
|
728
788
|
/>
|
|
729
789
|
<div className="flex h-6 w-14 items-center overflow-hidden rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)]">
|
|
@@ -744,7 +804,17 @@ export function GradientEditor({
|
|
|
744
804
|
setAngleInput(e.target.value);
|
|
745
805
|
}
|
|
746
806
|
}}
|
|
747
|
-
onBlur={() =>
|
|
807
|
+
onBlur={() => {
|
|
808
|
+
// `angleInput` is only non-null once the user has actually
|
|
809
|
+
// typed into this field (see onChange below) — mirrors the
|
|
810
|
+
// sibling stop-position field's commitPositionDraft, which
|
|
811
|
+
// only commits on an actual edit rather than unconditionally
|
|
812
|
+
// on every blur (tabbing through/refocusing without typing
|
|
813
|
+
// must not re-fire the commit).
|
|
814
|
+
const changed = angleInput !== null;
|
|
815
|
+
setAngleInput(null);
|
|
816
|
+
if (changed) onCommit?.();
|
|
817
|
+
}}
|
|
748
818
|
className="h-full min-w-0 flex-1 bg-transparent px-1.5 !text-[11px] tabular-nums focus-visible:outline-none"
|
|
749
819
|
/>
|
|
750
820
|
<span className="flex w-4 shrink-0 items-center justify-center text-[10px] text-muted-foreground">
|
|
@@ -78,6 +78,26 @@ export interface ScrubInputProps extends ScrubExpressionOptions {
|
|
|
78
78
|
tooltipLabel?: string;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
export interface PendingScrubCommit {
|
|
82
|
+
value: number;
|
|
83
|
+
/** Incoming prop value at commit time. While this exact value remains, the
|
|
84
|
+
* host has not acknowledged the write yet and the optimistic draft should
|
|
85
|
+
* stay visible. A different incoming value is authoritative host
|
|
86
|
+
* normalization/rejection and must supersede the optimistic draft. */
|
|
87
|
+
baseline: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function resolvePendingScrubCommit(
|
|
91
|
+
pending: PendingScrubCommit | null,
|
|
92
|
+
incomingValue: number,
|
|
93
|
+
options: ScrubExpressionOptions,
|
|
94
|
+
): "none" | "hold" | "confirmed" | "superseded" {
|
|
95
|
+
if (pending === null) return "none";
|
|
96
|
+
const incoming = normalizeScrubNumber(incomingValue, options);
|
|
97
|
+
if (incoming === pending.value) return "confirmed";
|
|
98
|
+
return incoming === pending.baseline ? "hold" : "superseded";
|
|
99
|
+
}
|
|
100
|
+
|
|
81
101
|
export function ScrubInput({
|
|
82
102
|
label,
|
|
83
103
|
value,
|
|
@@ -128,18 +148,27 @@ export function ScrubInput({
|
|
|
128
148
|
// value back to the old one the instant focus leaves the input, which
|
|
129
149
|
// reads as "Enter resets to the old value". Cleared as soon as a fresh
|
|
130
150
|
// `value` prop confirms (or supersedes) the pending commit.
|
|
131
|
-
const pendingCommitRef = useRef<
|
|
151
|
+
const pendingCommitRef = useRef<PendingScrubCommit | null>(null);
|
|
132
152
|
const options = { unit, min, max, precision };
|
|
133
153
|
|
|
134
154
|
useEffect(() => {
|
|
135
|
-
if (pendingCommitRef.current
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
155
|
+
if (mixed) pendingCommitRef.current = null;
|
|
156
|
+
const resolution = resolvePendingScrubCommit(
|
|
157
|
+
pendingCommitRef.current,
|
|
158
|
+
value,
|
|
159
|
+
options,
|
|
160
|
+
);
|
|
161
|
+
if (resolution !== "none") {
|
|
162
|
+
if (resolution === "confirmed" || resolution === "superseded") {
|
|
163
|
+
// The host either echoed exactly what we committed or returned a new,
|
|
164
|
+
// authoritative normalized/rejected value. In both cases resume prop
|
|
165
|
+
// synchronization. The old equality-only logic held forever on the
|
|
166
|
+
// second path, leaving the field permanently stuck on a value the
|
|
167
|
+
// canvas never accepted.
|
|
139
168
|
pendingCommitRef.current = null;
|
|
140
169
|
} else {
|
|
141
|
-
// Still
|
|
142
|
-
//
|
|
170
|
+
// Still seeing the exact pre-commit prop — don't stomp the optimistic
|
|
171
|
+
// draft while the source-write round trip is pending.
|
|
143
172
|
return;
|
|
144
173
|
}
|
|
145
174
|
}
|
|
@@ -151,7 +180,7 @@ export function ScrubInput({
|
|
|
151
180
|
setDraft(formatted);
|
|
152
181
|
}
|
|
153
182
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- `options` is a fresh object every render; the individual fields it's built from (unit/min/max/precision) are already listed below.
|
|
154
|
-
}, [focused, mixed, precision, unit, value]);
|
|
183
|
+
}, [focused, max, min, mixed, precision, unit, value]);
|
|
155
184
|
|
|
156
185
|
const resolvedTooltipLabel = tooltipLabel ?? ariaLabel ?? label;
|
|
157
186
|
|
|
@@ -162,7 +191,12 @@ export function ScrubInput({
|
|
|
162
191
|
// prop before the host's round-trip lands (see pendingCommitRef above).
|
|
163
192
|
// Preview ticks don't need this: they're expected to be superseded by
|
|
164
193
|
// the next tick or the gesture's own final commit almost immediately.
|
|
165
|
-
if (meta.phase === "commit")
|
|
194
|
+
if (meta.phase === "commit") {
|
|
195
|
+
pendingCommitRef.current = {
|
|
196
|
+
value: normalized,
|
|
197
|
+
baseline: normalizeScrubNumber(value, options),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
166
200
|
onChange(normalized, meta);
|
|
167
201
|
const formatted = formatScrubValue(normalized, options);
|
|
168
202
|
draftRef.current = formatted;
|
|
@@ -192,7 +226,10 @@ export function ScrubInput({
|
|
|
192
226
|
if (parsed.value !== value || mixed) {
|
|
193
227
|
// See setNextValue's pendingCommitRef comment — this text-commit path
|
|
194
228
|
// (Enter/blur) bypasses setNextValue, so mark it pending here too.
|
|
195
|
-
pendingCommitRef.current =
|
|
229
|
+
pendingCommitRef.current = {
|
|
230
|
+
value: parsed.value,
|
|
231
|
+
baseline: normalizeScrubNumber(value, options),
|
|
232
|
+
};
|
|
196
233
|
onChange(parsed.value, {
|
|
197
234
|
source: "commit",
|
|
198
235
|
expression: currentDraft,
|
|
@@ -348,7 +385,10 @@ export function ScrubInput({
|
|
|
348
385
|
// authoritative value as pending confirmation so releasing the drag
|
|
349
386
|
// can't be clobbered back to the pre-drag value by a slow host
|
|
350
387
|
// round-trip (same class of bug as the Enter/blur text-commit case).
|
|
351
|
-
pendingCommitRef.current =
|
|
388
|
+
pendingCommitRef.current = {
|
|
389
|
+
value: lastScrubValueRef.current,
|
|
390
|
+
baseline: normalizeScrubNumber(value, options),
|
|
391
|
+
};
|
|
352
392
|
onChange(lastScrubValueRef.current, {
|
|
353
393
|
source: "scrub",
|
|
354
394
|
phase: "commit",
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
IconSearch,
|
|
24
24
|
IconX,
|
|
25
25
|
} from "@tabler/icons-react";
|
|
26
|
-
import { Component, useMemo, useState, type ReactNode } from "react";
|
|
26
|
+
import { Component, useMemo, useRef, useState, type ReactNode } from "react";
|
|
27
27
|
|
|
28
28
|
import { Input } from "@/components/ui/input";
|
|
29
29
|
import {
|
|
@@ -169,8 +169,27 @@ function ShaderThumbnail({
|
|
|
169
169
|
export interface ShaderFillsPanelProps {
|
|
170
170
|
/** Currently-applied shader descriptor, if the fill is already a shader. */
|
|
171
171
|
descriptor?: ShaderDescriptor;
|
|
172
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* Cheap live preview — fires on every ShaderControls tuning tick (typing
|
|
174
|
+
* or dragging a uniform) as well as once for a discrete preset/create-new
|
|
175
|
+
* pick. Should only update the visual CSS fallback fill; never trigger
|
|
176
|
+
* expensive persistence work.
|
|
177
|
+
*/
|
|
173
178
|
onApply: (descriptor: ShaderDescriptor, css: string) => void;
|
|
179
|
+
/**
|
|
180
|
+
* Fires once per gesture/discrete action with the same final
|
|
181
|
+
* descriptor+css already reported via `onApply` — mirrors GradientEditor's
|
|
182
|
+
* `onCommit` convention (see GradientEditor.tsx): `onApply` alone fires on
|
|
183
|
+
* every tuning tick for live preview, `onCommit` fires exactly once when a
|
|
184
|
+
* drag/type gesture ends (detected via pointerup/blur bubbling out of the
|
|
185
|
+
* tuning area below — `ShaderControls` doesn't surface its own ScrubInput
|
|
186
|
+
* gesture phase upward) or immediately for a discrete preset/create-new
|
|
187
|
+
* pick, so a caller that persists through undo history and the
|
|
188
|
+
* `apply-shader` codegen mutation only does so once per edit instead of
|
|
189
|
+
* once per tick. Optional so an existing caller that only wires `onApply`
|
|
190
|
+
* keeps that prop as the single source of truth.
|
|
191
|
+
*/
|
|
192
|
+
onCommit?: (descriptor: ShaderDescriptor, css: string) => void;
|
|
174
193
|
/** Close the shader panel and return to the color picker. */
|
|
175
194
|
onBack: () => void;
|
|
176
195
|
/** Optional design context forwarded to the apply-shader action. */
|
|
@@ -186,6 +205,7 @@ export interface ShaderFillsPanelProps {
|
|
|
186
205
|
export function ShaderFillsPanel({
|
|
187
206
|
descriptor,
|
|
188
207
|
onApply,
|
|
208
|
+
onCommit,
|
|
189
209
|
onBack,
|
|
190
210
|
applyContext,
|
|
191
211
|
disabled = false,
|
|
@@ -195,6 +215,18 @@ export function ShaderFillsPanel({
|
|
|
195
215
|
descriptor ?? null,
|
|
196
216
|
);
|
|
197
217
|
const applyShader = useActionMutation("apply-shader");
|
|
218
|
+
// Last descriptor reported to `onApply`, so a bubbled pointerup/blur that
|
|
219
|
+
// ends a tuning gesture can re-commit that exact value once, without
|
|
220
|
+
// needing ShaderControls to surface its own gesture-end signal.
|
|
221
|
+
const lastAppliedRef = useRef<ShaderDescriptor | null>(descriptor ?? null);
|
|
222
|
+
// Whether `preview()` has applied a new descriptor since the last
|
|
223
|
+
// `commitNow()`. Any pointerup/blur that bubbles out of the tuning
|
|
224
|
+
// container — opening a Select, clicking a checkbox, tabbing between
|
|
225
|
+
// fields — would otherwise re-fire the real apply-shader mutation on an
|
|
226
|
+
// unchanged descriptor just because `lastAppliedRef` is seeded on mount.
|
|
227
|
+
// Gate `commitLastPreview` on this flag instead: only a real preview tick
|
|
228
|
+
// sets it, and every `commitNow` clears it.
|
|
229
|
+
const dirtyRef = useRef(false);
|
|
198
230
|
|
|
199
231
|
const filtered = useMemo(() => {
|
|
200
232
|
const query = search.trim().toLowerCase();
|
|
@@ -206,13 +238,26 @@ export function ShaderFillsPanel({
|
|
|
206
238
|
);
|
|
207
239
|
}, [search]);
|
|
208
240
|
|
|
209
|
-
/**
|
|
210
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Cheap live preview: updates the thumbnail/detail state and the caller's
|
|
243
|
+
* CSS fallback fill. Called on every ShaderControls tick — must never do
|
|
244
|
+
* the expensive apply-shader codegen mutation (see commitNow below).
|
|
245
|
+
*/
|
|
246
|
+
const preview = (next: ShaderDescriptor) => {
|
|
211
247
|
setActive(next);
|
|
248
|
+
lastAppliedRef.current = next;
|
|
249
|
+
dirtyRef.current = true;
|
|
250
|
+
onApply(next, shaderDescriptorToCss(next));
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/** Validate + surface the descriptor for the agent exactly once. */
|
|
254
|
+
const commitNow = (next: ShaderDescriptor) => {
|
|
255
|
+
dirtyRef.current = false;
|
|
212
256
|
const css = shaderDescriptorToCss(next);
|
|
213
|
-
|
|
257
|
+
onCommit?.(next, css);
|
|
214
258
|
// Fire-and-forget validation/codegen so the agent can write real shader
|
|
215
|
-
// code. The picker fill is applied
|
|
259
|
+
// code. The picker fill is already applied via `preview` above,
|
|
260
|
+
// regardless of this mutation's result.
|
|
216
261
|
applyShader.mutate(
|
|
217
262
|
{
|
|
218
263
|
surface: SHADER_PRESET_MAP[next.preset]?.isEffect ? "effect" : "fill",
|
|
@@ -250,6 +295,25 @@ export function ShaderFillsPanel({
|
|
|
250
295
|
);
|
|
251
296
|
};
|
|
252
297
|
|
|
298
|
+
/** Discrete, one-shot pick (preset thumbnail / create-new tile): preview + commit in the same tick, same as before this change. */
|
|
299
|
+
const pick = (next: ShaderDescriptor) => {
|
|
300
|
+
preview(next);
|
|
301
|
+
commitNow(next);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Ends a ShaderControls tuning gesture: pointerup/blur bubbling out of the
|
|
306
|
+
* tuning area (see the wrapping div below). Gated on `dirtyRef` so any
|
|
307
|
+
* pointerup/blur that bubbles out without an intervening `preview()` tick —
|
|
308
|
+
* opening a Select, clicking a checkbox, tabbing between fields — is a
|
|
309
|
+
* no-op instead of re-committing the unchanged descriptor.
|
|
310
|
+
*/
|
|
311
|
+
const commitLastPreview = () => {
|
|
312
|
+
if (dirtyRef.current && lastAppliedRef.current) {
|
|
313
|
+
commitNow(lastAppliedRef.current);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
253
317
|
// ── Detail view: a preset is selected → tune it with ShaderControls ───────
|
|
254
318
|
if (active) {
|
|
255
319
|
const preset = SHADER_PRESET_MAP[active.preset];
|
|
@@ -277,10 +341,19 @@ export function ShaderFillsPanel({
|
|
|
277
341
|
<IconX className="size-3" />
|
|
278
342
|
</button>
|
|
279
343
|
</div>
|
|
280
|
-
|
|
344
|
+
{/* onPointerUp/onBlur here catch the bubbled event that ends a
|
|
345
|
+
ShaderControls drag/type gesture (pointer capture redirects the
|
|
346
|
+
event's target but it still bubbles through this ancestor), so
|
|
347
|
+
the expensive apply-shader mutation commits exactly once per
|
|
348
|
+
gesture instead of once per preview tick. */}
|
|
349
|
+
<div
|
|
350
|
+
className="border-t border-border/70 p-2"
|
|
351
|
+
onPointerUp={commitLastPreview}
|
|
352
|
+
onBlur={commitLastPreview}
|
|
353
|
+
>
|
|
281
354
|
<ShaderControls
|
|
282
355
|
descriptor={active}
|
|
283
|
-
onChange={(next) =>
|
|
356
|
+
onChange={(next) => preview(next)}
|
|
284
357
|
/>
|
|
285
358
|
</div>
|
|
286
359
|
</div>
|
|
@@ -301,7 +374,7 @@ export function ShaderFillsPanel({
|
|
|
301
374
|
type="button"
|
|
302
375
|
aria-label={"Create new shader" /* i18n-ignore */}
|
|
303
376
|
disabled={disabled}
|
|
304
|
-
onClick={() =>
|
|
377
|
+
onClick={() => pick(descriptorFromPreset(SHADER_PRESETS[0]))}
|
|
305
378
|
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-[var(--design-editor-control-bg)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40"
|
|
306
379
|
>
|
|
307
380
|
<IconPlus className="size-3.5" />
|
|
@@ -358,7 +431,7 @@ export function ShaderFillsPanel({
|
|
|
358
431
|
<button
|
|
359
432
|
type="button"
|
|
360
433
|
disabled={disabled}
|
|
361
|
-
onClick={() =>
|
|
434
|
+
onClick={() => pick(descriptorFromPreset(SHADER_PRESETS[0]))}
|
|
362
435
|
className={cn(
|
|
363
436
|
"group relative flex aspect-[4/3] w-full flex-col items-center justify-center gap-1 rounded-md border border-dashed border-[var(--design-editor-control-border)] text-muted-foreground transition-colors",
|
|
364
437
|
"hover:border-foreground/40 hover:text-foreground",
|
|
@@ -399,7 +472,7 @@ export function ShaderFillsPanel({
|
|
|
399
472
|
type="button"
|
|
400
473
|
disabled={disabled}
|
|
401
474
|
aria-label={preset.label}
|
|
402
|
-
onClick={() =>
|
|
475
|
+
onClick={() => pick(descriptorFromPreset(preset))}
|
|
403
476
|
className={cn(
|
|
404
477
|
"group flex flex-col gap-1 text-left focus-visible:outline-none",
|
|
405
478
|
disabled && "pointer-events-none opacity-40",
|