@agent-native/core 0.92.10 → 0.92.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +23 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +181 -15
- package/corpus/core/src/agent/run-manager.ts +31 -4
- package/corpus/core/src/agent/run-store.ts +80 -0
- package/corpus/core/src/cli/design-connect.ts +433 -151
- package/corpus/core/src/cli/skills.ts +14 -0
- package/corpus/core/src/client/AssistantChat.tsx +25 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
- package/corpus/core/src/client/agent-chat.ts +165 -1
- package/corpus/core/src/client/chat/index.ts +9 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
- package/corpus/core/src/collab/awareness-store.ts +23 -12
- package/corpus/core/src/collab/client.ts +16 -5
- package/corpus/core/src/collab/index.ts +4 -0
- package/corpus/core/src/collab/recent-edits.ts +65 -2
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
- package/corpus/core/src/server/builder-design-systems.ts +30 -4
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/create-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
- package/corpus/templates/clips/actions/request-transcript.ts +102 -33
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +48 -4
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
- package/corpus/templates/clips/app/routes/record.tsx +17 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +12 -2
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +6 -3
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
- package/corpus/templates/clips/shared/recording-core.ts +12 -0
- package/corpus/templates/content/AGENTS.md +7 -6
- package/corpus/templates/content/actions/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/pull-document.ts +5 -7
- package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
- package/corpus/templates/content/actions/push-notion-page.ts +10 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
- package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/content/app/i18n-data.ts +18 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
- package/corpus/templates/design/AGENTS.md +45 -10
- package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
- package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
- package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
- package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
- package/corpus/templates/design/actions/generate-design.ts +79 -12
- package/corpus/templates/design/actions/generate-screens.ts +57 -12
- package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
- package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
- package/corpus/templates/design/actions/import-design-source.ts +4 -31
- package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
- package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/design/actions/list-design-components.ts +104 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
- package/corpus/templates/design/actions/open-component-source.ts +2 -4
- package/corpus/templates/design/actions/present-design-variants.ts +412 -16
- package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
- package/corpus/templates/design/actions/run-design-audit.ts +25 -3
- package/corpus/templates/design/actions/show-design-questions.ts +10 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
- package/corpus/templates/design/actions/write-local-file.ts +25 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
- package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
- package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
- package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
- package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
- package/corpus/templates/design/app/components/design/types.ts +33 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
- package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
- package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
- package/corpus/templates/design/app/i18n-data.ts +1217 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
- package/corpus/templates/design/app/lib/design-import.ts +24 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
- package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
- package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
- package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
- package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -6
- package/corpus/templates/design/e2e/helpers.ts +27 -6
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
- package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
- package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
- package/corpus/templates/design/server/plugins/db.ts +41 -0
- package/corpus/templates/design/server/source-workspace.ts +64 -0
- package/corpus/templates/design/shared/board-file.ts +13 -2
- package/corpus/templates/design/shared/canvas-math.ts +231 -33
- package/corpus/templates/design/shared/code-layer.ts +122 -8
- package/corpus/templates/design/shared/component-library.ts +161 -0
- package/corpus/templates/design/shared/db-conflict.ts +27 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
- package/corpus/templates/design/shared/figma-url.ts +149 -0
- package/corpus/templates/design/shared/pen-path.ts +16 -7
- package/corpus/templates/design/shared/source-mode.ts +1 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
- package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
- package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
- package/dist/agent/production-agent.d.ts +79 -6
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +161 -14
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +29 -5
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +46 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +61 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/design-connect.d.ts +6 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +336 -139
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +14 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +19 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +38 -18
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts +60 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +122 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +36 -2
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +5 -0
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +19 -12
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +13 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +3 -1
- package/dist/collab/recent-edits.d.ts.map +1 -1
- package/dist/collab/recent-edits.js +57 -2
- package/dist/collab/recent-edits.js.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +87 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +15 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -4
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,7 +19,7 @@ export function DesignEditorSkeleton({
|
|
|
19
19
|
<div className="flex h-full overflow-hidden bg-[var(--design-editor-canvas-bg)]">
|
|
20
20
|
{!embedded && (
|
|
21
21
|
<aside className="relative flex min-h-0 shrink-0 border-r border-[var(--design-editor-panel-divider-color)] bg-[var(--design-editor-panel-bg)]">
|
|
22
|
-
<div className="flex w-[
|
|
22
|
+
<div className="flex w-[57px] shrink-0 flex-col items-center p-3">
|
|
23
23
|
<Skeleton className={`size-8 rounded-md ${panelGhost}`} />
|
|
24
24
|
<div className="mt-8 flex w-full flex-col items-center gap-3">
|
|
25
25
|
<Skeleton className={`size-8 rounded-lg ${panelGhost}`} />
|
|
@@ -27,7 +27,7 @@ export function DesignEditorSkeleton({
|
|
|
27
27
|
<Skeleton className={`size-8 rounded-lg ${panelGhost}`} />
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
|
-
<div className="flex w-[
|
|
30
|
+
<div className="flex w-[280px] min-w-0 flex-col bg-[var(--design-editor-panel-bg)]">
|
|
31
31
|
<div className="border-b border-[var(--design-editor-panel-divider-color)] p-3">
|
|
32
32
|
<Skeleton className={`h-5 w-28 rounded ${panelGhost}`} />
|
|
33
33
|
</div>
|
|
@@ -60,8 +60,8 @@ export function DesignEditorSkeleton({
|
|
|
60
60
|
return (
|
|
61
61
|
<div className="flex h-full overflow-hidden bg-background">
|
|
62
62
|
{!embedded && (
|
|
63
|
-
<aside className="hidden w-
|
|
64
|
-
<div className="flex w-[
|
|
63
|
+
<aside className="hidden w-[337px] shrink-0 bg-[var(--design-editor-panel-bg)] lg:flex">
|
|
64
|
+
<div className="flex w-[57px] shrink-0 flex-col items-center p-3">
|
|
65
65
|
<Skeleton className={`size-8 rounded-md ${panelGhost}`} />
|
|
66
66
|
<Skeleton className={`mt-8 h-40 w-full rounded-lg ${panelGhost}`} />
|
|
67
67
|
</div>
|
|
@@ -89,7 +89,7 @@ export function DesignEditorSkeleton({
|
|
|
89
89
|
</main>
|
|
90
90
|
|
|
91
91
|
{!embedded && (
|
|
92
|
-
<aside className="hidden w-
|
|
92
|
+
<aside className="hidden w-[240px] shrink-0 flex-col bg-[var(--design-editor-panel-bg)] lg:flex">
|
|
93
93
|
<div className="flex h-12 shrink-0 items-center justify-end px-3">
|
|
94
94
|
<Skeleton className={`h-6 w-40 rounded-md ${panelGhost}`} />
|
|
95
95
|
</div>
|
|
@@ -271,7 +271,12 @@ function useSlotInstalls(slotId: string) {
|
|
|
271
271
|
`/_agent-native/slots/${encodeURIComponent(slotId)}/installs`,
|
|
272
272
|
),
|
|
273
273
|
);
|
|
274
|
-
|
|
274
|
+
// Surface fetch failures as a query error instead of swallowing them as
|
|
275
|
+
// an empty list — an empty list renders identically to "nothing
|
|
276
|
+
// installed", which hides real server/network errors from the user.
|
|
277
|
+
if (!res.ok) {
|
|
278
|
+
throw new Error(`Failed to load installed extensions: ${res.status}`);
|
|
279
|
+
}
|
|
275
280
|
return res.json();
|
|
276
281
|
},
|
|
277
282
|
placeholderData: (prev) => prev,
|
|
@@ -288,13 +293,59 @@ function useAvailableExtensions(slotId: string) {
|
|
|
288
293
|
`/_agent-native/slots/${encodeURIComponent(slotId)}/available`,
|
|
289
294
|
),
|
|
290
295
|
);
|
|
291
|
-
|
|
296
|
+
// See the matching note in useSlotInstalls above — don't mask a fetch
|
|
297
|
+
// failure as "no extensions available".
|
|
298
|
+
if (!res.ok) {
|
|
299
|
+
throw new Error(`Failed to load available extensions: ${res.status}`);
|
|
300
|
+
}
|
|
292
301
|
return res.json();
|
|
293
302
|
},
|
|
294
303
|
placeholderData: (prev) => prev,
|
|
295
304
|
});
|
|
296
305
|
}
|
|
297
306
|
|
|
307
|
+
/**
|
|
308
|
+
* POSTs the install request for `extensionId` and waits for both the
|
|
309
|
+
* "installed" and "available" slot queries to fully refetch before
|
|
310
|
+
* resolving.
|
|
311
|
+
*
|
|
312
|
+
* Exported so a test can verify the ordering directly: the previous
|
|
313
|
+
* implementation invalidated the queries without awaiting them, so the
|
|
314
|
+
* component's `finally` block re-enabled the Install button (by clearing
|
|
315
|
+
* `installingId`) while the "Available" list still listed the
|
|
316
|
+
* just-installed extension — a race that let a fast double-click fire a
|
|
317
|
+
* second install request before the list caught up. Awaiting here means the
|
|
318
|
+
* caller doesn't regain control (and hasn't cleared its "installing" state)
|
|
319
|
+
* until the lists are provably current.
|
|
320
|
+
*/
|
|
321
|
+
export async function installExtensionRequest(
|
|
322
|
+
slotId: string,
|
|
323
|
+
extensionId: string,
|
|
324
|
+
queryClient: {
|
|
325
|
+
invalidateQueries: (options: { queryKey: unknown[] }) => Promise<unknown>;
|
|
326
|
+
},
|
|
327
|
+
): Promise<void> {
|
|
328
|
+
const res = await fetch(
|
|
329
|
+
agentNativePath(
|
|
330
|
+
`/_agent-native/slots/${encodeURIComponent(slotId)}/install`,
|
|
331
|
+
),
|
|
332
|
+
{
|
|
333
|
+
method: "POST",
|
|
334
|
+
headers: { "Content-Type": "application/json" },
|
|
335
|
+
body: JSON.stringify({ extensionId }),
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
if (!res.ok) throw new Error(`Install failed: ${res.status}`);
|
|
339
|
+
await Promise.all([
|
|
340
|
+
queryClient.invalidateQueries({
|
|
341
|
+
queryKey: ["design-editor-extension-slot"],
|
|
342
|
+
}),
|
|
343
|
+
queryClient.invalidateQueries({
|
|
344
|
+
queryKey: ["design-editor-extension-slot-available"],
|
|
345
|
+
}),
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
|
|
298
349
|
// ─── First-party extension rows ───────────────────────────────────────────────
|
|
299
350
|
|
|
300
351
|
interface FirstPartyRowProps {
|
|
@@ -1390,8 +1441,13 @@ export function DesignExtensionsPanel({
|
|
|
1390
1441
|
null,
|
|
1391
1442
|
);
|
|
1392
1443
|
const slotId = DESIGN_EDITOR_EXTENSION_SLOT_ID;
|
|
1393
|
-
const {
|
|
1394
|
-
|
|
1444
|
+
const {
|
|
1445
|
+
data: installs = [],
|
|
1446
|
+
isLoading,
|
|
1447
|
+
isError: installsErrored,
|
|
1448
|
+
} = useSlotInstalls(slotId);
|
|
1449
|
+
const { data: available = [], isError: availableErrored } =
|
|
1450
|
+
useAvailableExtensions(slotId);
|
|
1395
1451
|
const installedIds = useMemo(
|
|
1396
1452
|
() => new Set(installs.map((install) => install.extensionId)),
|
|
1397
1453
|
[installs],
|
|
@@ -1420,23 +1476,12 @@ export function DesignExtensionsPanel({
|
|
|
1420
1476
|
const installExtension = async (extensionId: string) => {
|
|
1421
1477
|
setInstallingId(extensionId);
|
|
1422
1478
|
try {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
headers: { "Content-Type": "application/json" },
|
|
1430
|
-
body: JSON.stringify({ extensionId }),
|
|
1431
|
-
},
|
|
1432
|
-
);
|
|
1433
|
-
if (!res.ok) throw new Error(`Install failed: ${res.status}`);
|
|
1434
|
-
queryClient.invalidateQueries({
|
|
1435
|
-
queryKey: ["design-editor-extension-slot"],
|
|
1436
|
-
});
|
|
1437
|
-
queryClient.invalidateQueries({
|
|
1438
|
-
queryKey: ["design-editor-extension-slot-available"],
|
|
1439
|
-
});
|
|
1479
|
+
// Awaits both slot queries' refetch, not just firing invalidation —
|
|
1480
|
+
// see installExtensionRequest's doc comment for the duplicate-install
|
|
1481
|
+
// race this closes: installingId (and therefore the disabled Install
|
|
1482
|
+
// button) must stay set until the "Available" list has actually
|
|
1483
|
+
// dropped this extension, not just until the POST resolves.
|
|
1484
|
+
await installExtensionRequest(slotId, extensionId, queryClient);
|
|
1440
1485
|
} catch {
|
|
1441
1486
|
toast.error(t("designEditor.extensionsInstallError"));
|
|
1442
1487
|
} finally {
|
|
@@ -1570,6 +1615,13 @@ export function DesignExtensionsPanel({
|
|
|
1570
1615
|
/>
|
|
1571
1616
|
</div>
|
|
1572
1617
|
|
|
1618
|
+
{(installsErrored || availableErrored) && (
|
|
1619
|
+
<p className="mb-3 rounded border border-destructive/30 bg-destructive/5 px-2 py-1.5 text-[10px] leading-snug text-destructive">
|
|
1620
|
+
Couldn't load extensions. Built-in tools are still available
|
|
1621
|
+
below — check your connection and try again.
|
|
1622
|
+
</p>
|
|
1623
|
+
)}
|
|
1624
|
+
|
|
1573
1625
|
{isLoading ? (
|
|
1574
1626
|
<div className="space-y-3">
|
|
1575
1627
|
<Skeleton className="h-12 rounded-md" />
|
|
@@ -170,7 +170,6 @@ import {
|
|
|
170
170
|
componentNameForElementInfo,
|
|
171
171
|
cssElementSize,
|
|
172
172
|
displayLabel,
|
|
173
|
-
elementHasLayoutChildren,
|
|
174
173
|
elementIsComponentSelection,
|
|
175
174
|
horizontalToJustify,
|
|
176
175
|
inferElementSizing,
|
|
@@ -198,7 +197,6 @@ import {
|
|
|
198
197
|
} from "./edit-panel/field-primitives";
|
|
199
198
|
import {
|
|
200
199
|
averageGradientOpacity,
|
|
201
|
-
buildFillRows,
|
|
202
200
|
buildGradientLayer,
|
|
203
201
|
DEFAULT_EXPORT_SETTINGS,
|
|
204
202
|
defaultGradientLayer,
|
|
@@ -321,13 +319,10 @@ import {
|
|
|
321
319
|
type ExportSettingsValue,
|
|
322
320
|
type FrameSizePreset,
|
|
323
321
|
type FrameSizePresetCategoryKey,
|
|
324
|
-
imageFillToBackgroundStyles,
|
|
325
322
|
InteractionStatePanel,
|
|
326
323
|
type ActiveInteractionState,
|
|
327
324
|
type DesignFillRow,
|
|
328
|
-
type DesignFillRowPatch,
|
|
329
325
|
type DesignGradientStop,
|
|
330
|
-
type DesignGradientStopPatch,
|
|
331
326
|
type DesignGradientType,
|
|
332
327
|
type ImageFillValue,
|
|
333
328
|
type MotionKeyframeCssProperty,
|
|
@@ -459,6 +454,8 @@ interface EditPanelProps {
|
|
|
459
454
|
* and an Edit component action.
|
|
460
455
|
*/
|
|
461
456
|
componentNodeId?: string;
|
|
457
|
+
/** Increment to open the selected component's Swap instance picker. */
|
|
458
|
+
componentSwapPickerRequest?: number;
|
|
462
459
|
/**
|
|
463
460
|
* Source capabilities for the current design. Used to gate the Edit
|
|
464
461
|
* component / jump-to-source affordances. When absent all writes default
|
|
@@ -1153,12 +1150,17 @@ function PageProperties({
|
|
|
1153
1150
|
backgroundRepeat={styles.backgroundRepeat}
|
|
1154
1151
|
backgroundPosition={styles.backgroundPosition}
|
|
1155
1152
|
onBackgroundImageChange={(v) => onStyleChange("backgroundImage", v)}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1153
|
+
// Layer-index-aware: ColorInput merges the edited image into the
|
|
1154
|
+
// correct backgroundImage/backgroundSize/backgroundRepeat/
|
|
1155
|
+
// backgroundPosition index and hands back the full four-property
|
|
1156
|
+
// patch here, already preserving every other stacked
|
|
1157
|
+
// gradient/image layer (same pattern as FillProperties' base fill
|
|
1158
|
+
// row — see fill-properties.tsx). The single-layer
|
|
1159
|
+
// `onImageFillChange` this previously used always overwrote the
|
|
1160
|
+
// *whole* background stack via `imageFillToBackgroundStyles`,
|
|
1161
|
+
// silently wiping any other stacked background layer.
|
|
1162
|
+
onImageFillLayerChange={(patch) =>
|
|
1163
|
+
commitStylePatch(patch, onStyleChange, onStylesChange)
|
|
1162
1164
|
}
|
|
1163
1165
|
blendMode={styles.backgroundBlendMode || "normal"}
|
|
1164
1166
|
onBlendModeChange={(v) => onStyleChange("backgroundBlendMode", v)}
|
|
@@ -1351,6 +1353,7 @@ export const EditPanel = memo(function EditPanel({
|
|
|
1351
1353
|
onComponentPropApplied,
|
|
1352
1354
|
reviewPanelProps,
|
|
1353
1355
|
componentNodeId,
|
|
1356
|
+
componentSwapPickerRequest,
|
|
1354
1357
|
sourceCapabilities = [],
|
|
1355
1358
|
onCreateComponent,
|
|
1356
1359
|
selectedElementAlreadyComponent = false,
|
|
@@ -1761,6 +1764,7 @@ export const EditPanel = memo(function EditPanel({
|
|
|
1761
1764
|
activeContent={activeContent}
|
|
1762
1765
|
activeFileUpdatedAt={activeFileUpdatedAt}
|
|
1763
1766
|
nodeId={componentNodeId}
|
|
1767
|
+
swapPickerRequest={componentSwapPickerRequest}
|
|
1764
1768
|
onComponentPropApplied={onComponentPropApplied}
|
|
1765
1769
|
sourceCapabilities={sourceCapabilities}
|
|
1766
1770
|
/>
|
|
@@ -1805,6 +1809,7 @@ export const EditPanel = memo(function EditPanel({
|
|
|
1805
1809
|
<PositionLayoutProperties
|
|
1806
1810
|
element={inspectorElement}
|
|
1807
1811
|
onStyleChange={onStyleChange}
|
|
1812
|
+
onStylesChange={onStylesChange}
|
|
1808
1813
|
onAlignSelection={onAlignSelection}
|
|
1809
1814
|
motionKeyframeContext={motionKeyframeFieldContext}
|
|
1810
1815
|
breakpointOverrideContext={breakpointOverrideFieldContext}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client";
|
|
2
|
+
import {
|
|
3
|
+
IconArrowUpRight,
|
|
4
|
+
IconCircle,
|
|
5
|
+
IconFrame,
|
|
6
|
+
IconHandStop,
|
|
7
|
+
IconLine,
|
|
8
|
+
IconMessage,
|
|
9
|
+
IconPencil,
|
|
10
|
+
IconPointer,
|
|
11
|
+
IconScale,
|
|
12
|
+
IconScribble,
|
|
13
|
+
IconSquare,
|
|
14
|
+
IconTypography,
|
|
15
|
+
IconX,
|
|
16
|
+
} from "@tabler/icons-react";
|
|
17
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
18
|
+
|
|
19
|
+
import { createCoreCommands } from "@/components/design/code-workbench/commands";
|
|
20
|
+
import {
|
|
21
|
+
DESIGN_SHORTCUT_CATEGORIES,
|
|
22
|
+
DESIGN_SHORTCUTS,
|
|
23
|
+
type DesignShortcutCategory,
|
|
24
|
+
formatShortcutKeycaps,
|
|
25
|
+
} from "@/components/design/keyboard-shortcuts";
|
|
26
|
+
import { Button } from "@/components/ui/button";
|
|
27
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
28
|
+
|
|
29
|
+
interface KeyboardShortcutsPanelProps {
|
|
30
|
+
onClose: () => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const TOOL_ICON_BY_SHORTCUT: Record<string, typeof IconPointer> = {
|
|
34
|
+
"move-tool": IconPointer,
|
|
35
|
+
"frame-tool": IconFrame,
|
|
36
|
+
"text-tool": IconTypography,
|
|
37
|
+
"pen-tool": IconPencil,
|
|
38
|
+
"hand-tool": IconHandStop,
|
|
39
|
+
"scale-tool": IconScale,
|
|
40
|
+
"comment-tool": IconMessage,
|
|
41
|
+
"draw-tool": IconScribble,
|
|
42
|
+
rectangle: IconSquare,
|
|
43
|
+
ellipse: IconCircle,
|
|
44
|
+
line: IconLine,
|
|
45
|
+
arrow: IconArrowUpRight,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const ESSENTIAL_DESCRIPTION_KEY_BY_SHORTCUT = {
|
|
49
|
+
"toggle-ui": "designEditor.keyboardShortcuts.descriptions.toggleUi",
|
|
50
|
+
undo: "designEditor.keyboardShortcuts.descriptions.undo",
|
|
51
|
+
redo: "designEditor.keyboardShortcuts.descriptions.redo",
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
const CODE_CATEGORY_BY_COMMAND: Record<string, DesignShortcutCategory> = {
|
|
55
|
+
"workbench.save": "edit",
|
|
56
|
+
"workbench.saveAll": "edit",
|
|
57
|
+
"workbench.quickOpen": "edit",
|
|
58
|
+
"workbench.commandPalette": "edit",
|
|
59
|
+
"workbench.search": "edit",
|
|
60
|
+
"workbench.explorer": "view",
|
|
61
|
+
"workbench.toggleSidebar": "view",
|
|
62
|
+
"workbench.nextTab": "selection",
|
|
63
|
+
"workbench.previousTab": "selection",
|
|
64
|
+
"editor.gotoSymbol": "selection",
|
|
65
|
+
"editor.gotoLine": "selection",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const ACCESSIBLE_KEY_NAME_BY_TOKEN: Record<string, string> = {
|
|
69
|
+
alt: "alt",
|
|
70
|
+
arrowdown: "arrowDown",
|
|
71
|
+
arrowleft: "arrowLeft",
|
|
72
|
+
arrowright: "arrowRight",
|
|
73
|
+
arrowup: "arrowUp",
|
|
74
|
+
backspace: "backspace",
|
|
75
|
+
ctrl: "control",
|
|
76
|
+
delete: "delete",
|
|
77
|
+
enter: "enter",
|
|
78
|
+
shift: "shift",
|
|
79
|
+
tab: "tab",
|
|
80
|
+
"?": "questionMark",
|
|
81
|
+
"\\": "backslash",
|
|
82
|
+
"=": "equals",
|
|
83
|
+
"-": "minus",
|
|
84
|
+
"[": "leftBracket",
|
|
85
|
+
"]": "rightBracket",
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
function KeycapGroup({
|
|
89
|
+
binding,
|
|
90
|
+
applePlatform,
|
|
91
|
+
}: {
|
|
92
|
+
binding: string;
|
|
93
|
+
applePlatform: boolean;
|
|
94
|
+
}) {
|
|
95
|
+
return (
|
|
96
|
+
<span
|
|
97
|
+
data-keycap-group={binding}
|
|
98
|
+
aria-hidden="true"
|
|
99
|
+
className="inline-flex items-center gap-0.5 whitespace-nowrap"
|
|
100
|
+
>
|
|
101
|
+
{formatShortcutKeycaps(binding, applePlatform).map((keycap, index) => (
|
|
102
|
+
<kbd
|
|
103
|
+
key={`${keycap}-${index}`}
|
|
104
|
+
aria-hidden="true"
|
|
105
|
+
className="inline-flex min-w-5 items-center justify-center rounded-[3px] border border-neutral-500/70 bg-neutral-700/80 px-1 py-0.5 font-sans text-[10px] font-medium leading-none text-neutral-100 shadow-[0_1px_0_rgba(255,255,255,0.1)]"
|
|
106
|
+
>
|
|
107
|
+
{keycap}
|
|
108
|
+
</kbd>
|
|
109
|
+
))}
|
|
110
|
+
</span>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function ShortcutBindings({ bindings }: { bindings: readonly string[] }) {
|
|
115
|
+
const t = useT();
|
|
116
|
+
const applePlatform =
|
|
117
|
+
typeof navigator !== "undefined" &&
|
|
118
|
+
/Mac|iPhone|iPad/.test(navigator.platform);
|
|
119
|
+
const accessibleBindings = bindings.map((binding) =>
|
|
120
|
+
binding
|
|
121
|
+
.split("+")
|
|
122
|
+
.map((rawToken) => {
|
|
123
|
+
const token = rawToken.toLowerCase();
|
|
124
|
+
if (token === "$mod") {
|
|
125
|
+
return t(
|
|
126
|
+
`designEditor.keyboardShortcuts.keys.${applePlatform ? "command" : "control"}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
if (token === "alt" && applePlatform) {
|
|
130
|
+
return t("designEditor.keyboardShortcuts.keys.option");
|
|
131
|
+
}
|
|
132
|
+
const keyName = ACCESSIBLE_KEY_NAME_BY_TOKEN[token];
|
|
133
|
+
if (keyName) {
|
|
134
|
+
return t(`designEditor.keyboardShortcuts.keys.${keyName}`);
|
|
135
|
+
}
|
|
136
|
+
return rawToken.length === 1 ? rawToken.toLocaleUpperCase() : rawToken;
|
|
137
|
+
})
|
|
138
|
+
.join(" "),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<span
|
|
143
|
+
data-shortcut-bindings
|
|
144
|
+
role="group"
|
|
145
|
+
aria-label={accessibleBindings.join(
|
|
146
|
+
` ${t("designEditor.keyboardShortcuts.keys.or")} `,
|
|
147
|
+
)}
|
|
148
|
+
className="flex shrink-0 items-center gap-1.5"
|
|
149
|
+
>
|
|
150
|
+
{bindings.map((binding) => (
|
|
151
|
+
<KeycapGroup
|
|
152
|
+
key={binding}
|
|
153
|
+
binding={binding}
|
|
154
|
+
applePlatform={applePlatform}
|
|
155
|
+
/>
|
|
156
|
+
))}
|
|
157
|
+
</span>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function KeyboardShortcutsPanel({
|
|
162
|
+
onClose,
|
|
163
|
+
}: KeyboardShortcutsPanelProps) {
|
|
164
|
+
const t = useT();
|
|
165
|
+
const [category, setCategory] = useState<DesignShortcutCategory>("essential");
|
|
166
|
+
const initialTabRef = useRef<HTMLButtonElement | null>(null);
|
|
167
|
+
const codeShortcuts = useMemo(
|
|
168
|
+
() =>
|
|
169
|
+
createCoreCommands().flatMap((command) => {
|
|
170
|
+
const commandCategory = CODE_CATEGORY_BY_COMMAND[command.id];
|
|
171
|
+
return commandCategory && command.keybindings?.length
|
|
172
|
+
? [{ ...command, shortcutCategory: commandCategory }]
|
|
173
|
+
: [];
|
|
174
|
+
}),
|
|
175
|
+
[],
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
// Radix Menu restores focus to its trigger in its own close frame. Wait
|
|
180
|
+
// through that frame before moving focus into the newly-opened dock so
|
|
181
|
+
// menu invocation and the global shortcut share the same focus contract.
|
|
182
|
+
let focusFrame = 0;
|
|
183
|
+
const menuCloseFrame = window.requestAnimationFrame(() => {
|
|
184
|
+
focusFrame = window.requestAnimationFrame(() => {
|
|
185
|
+
initialTabRef.current?.focus({ preventScroll: true });
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
return () => {
|
|
189
|
+
window.cancelAnimationFrame(menuCloseFrame);
|
|
190
|
+
if (focusFrame) window.cancelAnimationFrame(focusFrame);
|
|
191
|
+
};
|
|
192
|
+
}, []);
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<section
|
|
196
|
+
data-keyboard-shortcuts-panel
|
|
197
|
+
role="region"
|
|
198
|
+
aria-label={t("designEditor.keyboardShortcuts.title")}
|
|
199
|
+
className="absolute inset-x-0 bottom-0 z-[60] flex h-[241px] flex-col border-t border-neutral-700 bg-neutral-900 text-neutral-100 shadow-[0_-12px_28px_rgba(0,0,0,0.28)]"
|
|
200
|
+
>
|
|
201
|
+
<Tabs
|
|
202
|
+
value={category}
|
|
203
|
+
onValueChange={(value) => setCategory(value as DesignShortcutCategory)}
|
|
204
|
+
className="flex min-h-0 flex-1 flex-col"
|
|
205
|
+
>
|
|
206
|
+
<div
|
|
207
|
+
data-shortcuts-tab-row
|
|
208
|
+
className="flex h-[38px] shrink-0 items-center border-b border-neutral-700"
|
|
209
|
+
>
|
|
210
|
+
<div className="min-w-0 flex-1 overflow-x-auto pl-[124px] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
|
211
|
+
<TabsList
|
|
212
|
+
data-shortcuts-tab-strip
|
|
213
|
+
className="h-9 w-max justify-start rounded-none bg-transparent p-0"
|
|
214
|
+
>
|
|
215
|
+
{DESIGN_SHORTCUT_CATEGORIES.map((categoryId) => (
|
|
216
|
+
<TabsTrigger
|
|
217
|
+
key={categoryId}
|
|
218
|
+
value={categoryId}
|
|
219
|
+
ref={categoryId === "essential" ? initialTabRef : undefined}
|
|
220
|
+
className="h-9 rounded-none border-x-0 border-b-2 border-t-0 border-transparent bg-transparent px-2.5 text-[11px] font-medium text-neutral-400 shadow-none data-[state=active]:border-blue-400 data-[state=active]:bg-transparent data-[state=active]:text-white data-[state=active]:shadow-none"
|
|
221
|
+
>
|
|
222
|
+
{t(`designEditor.keyboardShortcuts.categories.${categoryId}`)}
|
|
223
|
+
</TabsTrigger>
|
|
224
|
+
))}
|
|
225
|
+
</TabsList>
|
|
226
|
+
</div>
|
|
227
|
+
<Button
|
|
228
|
+
data-keyboard-shortcuts-close
|
|
229
|
+
type="button"
|
|
230
|
+
variant="ghost"
|
|
231
|
+
size="icon"
|
|
232
|
+
className="ml-2 size-7 shrink-0 text-neutral-300 hover:bg-neutral-700 hover:text-white"
|
|
233
|
+
aria-label={t("designEditor.keyboardShortcuts.close")}
|
|
234
|
+
onClick={onClose}
|
|
235
|
+
>
|
|
236
|
+
<IconX className="size-4" />
|
|
237
|
+
</Button>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
{DESIGN_SHORTCUT_CATEGORIES.map((categoryId) => {
|
|
241
|
+
const designRows = DESIGN_SHORTCUTS.filter((item) =>
|
|
242
|
+
categoryId === "tools"
|
|
243
|
+
? item.category === "tools" || item.category === "shape"
|
|
244
|
+
: item.category === categoryId,
|
|
245
|
+
);
|
|
246
|
+
const codeRows = codeShortcuts.filter(
|
|
247
|
+
(item) => item.shortcutCategory === categoryId,
|
|
248
|
+
);
|
|
249
|
+
return (
|
|
250
|
+
<TabsContent
|
|
251
|
+
key={categoryId}
|
|
252
|
+
value={categoryId}
|
|
253
|
+
data-shortcuts-tabpanel={categoryId}
|
|
254
|
+
className="m-0 min-h-0 flex-1 overflow-y-auto px-4 py-2 data-[state=inactive]:hidden"
|
|
255
|
+
>
|
|
256
|
+
{categoryId === "essential" ? (
|
|
257
|
+
<div
|
|
258
|
+
data-shortcuts-content-column
|
|
259
|
+
className="mx-auto max-w-[400px]"
|
|
260
|
+
>
|
|
261
|
+
<h2
|
|
262
|
+
data-essential-shortcuts-heading
|
|
263
|
+
className="mb-2 text-[13px] font-semibold text-white"
|
|
264
|
+
>
|
|
265
|
+
{`${t("designEditor.keyboardShortcuts.categories.essential")} ${t("designEditor.keyboardShortcuts.title").toLocaleLowerCase()}`}
|
|
266
|
+
</h2>
|
|
267
|
+
<div className="space-y-6">
|
|
268
|
+
{[
|
|
269
|
+
DESIGN_SHORTCUTS.find((item) => item.id === "toggle-ui"),
|
|
270
|
+
DESIGN_SHORTCUTS.find((item) => item.id === "undo"),
|
|
271
|
+
DESIGN_SHORTCUTS.find((item) => item.id === "redo"),
|
|
272
|
+
].map((item, index) =>
|
|
273
|
+
item ? (
|
|
274
|
+
<section
|
|
275
|
+
data-essential-shortcut-card
|
|
276
|
+
data-shortcut-id={item.id}
|
|
277
|
+
key={item.id}
|
|
278
|
+
className="relative pt-7"
|
|
279
|
+
>
|
|
280
|
+
<div className="absolute left-0 top-0">
|
|
281
|
+
<span className="flex size-5 items-center justify-center rounded-full bg-neutral-700 text-[10px] font-semibold text-white">
|
|
282
|
+
{index + 1}
|
|
283
|
+
</span>
|
|
284
|
+
</div>
|
|
285
|
+
<div className="mt-7 flex min-h-[58px] items-center justify-between gap-6 border-b border-neutral-700 pb-3">
|
|
286
|
+
<div className="min-w-0 flex-1">
|
|
287
|
+
<div className="text-[11px] font-medium text-neutral-100">
|
|
288
|
+
{t(item.labelKey)}
|
|
289
|
+
</div>
|
|
290
|
+
<p
|
|
291
|
+
data-essential-shortcut-description
|
|
292
|
+
className="mt-1 text-[10px] leading-4 text-neutral-400"
|
|
293
|
+
>
|
|
294
|
+
{t(
|
|
295
|
+
ESSENTIAL_DESCRIPTION_KEY_BY_SHORTCUT[
|
|
296
|
+
item.id as keyof typeof ESSENTIAL_DESCRIPTION_KEY_BY_SHORTCUT
|
|
297
|
+
],
|
|
298
|
+
)}
|
|
299
|
+
</p>
|
|
300
|
+
</div>
|
|
301
|
+
<ShortcutBindings bindings={item.bindings} />
|
|
302
|
+
</div>
|
|
303
|
+
</section>
|
|
304
|
+
) : null,
|
|
305
|
+
)}
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
) : (
|
|
309
|
+
<div
|
|
310
|
+
data-shortcut-grid={categoryId}
|
|
311
|
+
data-shortcuts-content-column
|
|
312
|
+
className="mx-auto max-w-[400px]"
|
|
313
|
+
>
|
|
314
|
+
{designRows.map((item) => (
|
|
315
|
+
<div
|
|
316
|
+
data-shortcut-id={item.id}
|
|
317
|
+
key={item.id}
|
|
318
|
+
className="flex min-h-8 items-center gap-3 border-b border-neutral-800 py-1"
|
|
319
|
+
>
|
|
320
|
+
<span className="flex min-w-0 flex-1 items-center gap-2 truncate text-[11px] text-neutral-200">
|
|
321
|
+
{(() => {
|
|
322
|
+
const ToolIcon = TOOL_ICON_BY_SHORTCUT[item.id];
|
|
323
|
+
return ToolIcon ? (
|
|
324
|
+
<ToolIcon className="size-3.5 shrink-0 text-neutral-400" />
|
|
325
|
+
) : null;
|
|
326
|
+
})()}
|
|
327
|
+
<span className="truncate">
|
|
328
|
+
{t(item.labelKey)}
|
|
329
|
+
{item.context === "screen" ? (
|
|
330
|
+
<span className="ml-1.5 rounded bg-neutral-700 px-1 py-0.5 text-[9px] uppercase tracking-wide text-neutral-300">
|
|
331
|
+
{t(
|
|
332
|
+
"designEditor.keyboardShortcuts.screenContext",
|
|
333
|
+
)}
|
|
334
|
+
</span>
|
|
335
|
+
) : null}
|
|
336
|
+
</span>
|
|
337
|
+
</span>
|
|
338
|
+
<ShortcutBindings bindings={item.bindings} />
|
|
339
|
+
</div>
|
|
340
|
+
))}
|
|
341
|
+
{codeRows.map((item) => (
|
|
342
|
+
<div
|
|
343
|
+
data-code-shortcut-id={item.id}
|
|
344
|
+
key={item.id}
|
|
345
|
+
className="flex min-h-8 items-center gap-3 border-b border-neutral-800 py-1"
|
|
346
|
+
>
|
|
347
|
+
<span className="min-w-0 flex-1 truncate text-[11px] text-neutral-200">
|
|
348
|
+
{item.title}
|
|
349
|
+
<span className="ml-1.5 rounded bg-blue-500/20 px-1 py-0.5 text-[9px] uppercase tracking-wide text-blue-200">
|
|
350
|
+
{t("designEditor.keyboardShortcuts.codeContext")}
|
|
351
|
+
</span>
|
|
352
|
+
</span>
|
|
353
|
+
<ShortcutBindings bindings={item.keybindings ?? []} />
|
|
354
|
+
</div>
|
|
355
|
+
))}
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
</TabsContent>
|
|
359
|
+
);
|
|
360
|
+
})}
|
|
361
|
+
</Tabs>
|
|
362
|
+
</section>
|
|
363
|
+
);
|
|
364
|
+
}
|