@agent-native/core 0.92.10 → 0.92.12

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.
Files changed (354) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +214 -17
  5. package/corpus/core/src/agent/run-manager.ts +72 -14
  6. package/corpus/core/src/agent/run-store.ts +152 -27
  7. package/corpus/core/src/cli/design-connect.ts +433 -151
  8. package/corpus/core/src/cli/skills.ts +14 -0
  9. package/corpus/core/src/client/AssistantChat.tsx +25 -0
  10. package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
  11. package/corpus/core/src/client/agent-chat-adapter.ts +56 -12
  12. package/corpus/core/src/client/agent-chat.ts +165 -1
  13. package/corpus/core/src/client/chat/index.ts +9 -1
  14. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
  15. package/corpus/core/src/client/index.ts +5 -0
  16. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
  17. package/corpus/core/src/collab/awareness-store.ts +23 -12
  18. package/corpus/core/src/collab/client.ts +16 -5
  19. package/corpus/core/src/collab/index.ts +4 -0
  20. package/corpus/core/src/collab/recent-edits.ts +65 -2
  21. package/corpus/core/src/index.browser.ts +1 -0
  22. package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
  23. package/corpus/core/src/server/builder-design-systems.ts +30 -4
  24. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
  25. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
  26. package/corpus/templates/clips/AGENTS.md +4 -0
  27. package/corpus/templates/clips/actions/create-recording.ts +2 -0
  28. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
  29. package/corpus/templates/clips/actions/request-transcript.ts +102 -33
  30. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
  31. package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
  32. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +75 -9
  33. package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
  34. package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
  35. package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
  36. package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
  37. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  38. package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
  39. package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
  40. package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
  41. package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
  42. package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
  43. package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
  44. package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
  45. package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
  46. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
  47. package/corpus/templates/clips/app/routes/record.tsx +17 -4
  48. package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
  49. package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
  52. package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
  53. package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
  54. package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
  55. package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
  56. package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
  57. package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
  58. package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
  59. package/corpus/templates/clips/desktop/src/app.tsx +12 -2
  60. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
  61. package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
  62. package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
  63. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
  64. package/corpus/templates/clips/desktop/src/styles.css +6 -3
  65. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
  66. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
  67. package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
  68. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
  69. package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
  70. package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
  71. package/corpus/templates/clips/shared/recording-core.ts +12 -0
  72. package/corpus/templates/content/AGENTS.md +7 -6
  73. package/corpus/templates/content/actions/_builder-cms-read-client.ts +82 -7
  74. package/corpus/templates/content/actions/_database-source-utils.ts +149 -30
  75. package/corpus/templates/content/actions/_document-flush.ts +132 -17
  76. package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
  77. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +4 -7
  78. package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
  79. package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
  80. package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
  81. package/corpus/templates/content/actions/link-notion-page.ts +2 -0
  82. package/corpus/templates/content/actions/pull-document.ts +5 -7
  83. package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
  84. package/corpus/templates/content/actions/push-notion-page.ts +10 -0
  85. package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
  86. package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
  87. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
  88. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
  89. package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
  90. package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
  91. package/corpus/templates/content/app/i18n-data.ts +18 -0
  92. package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
  93. package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
  94. package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
  95. package/corpus/templates/content/shared/api.ts +1 -0
  96. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
  97. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
  98. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
  99. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
  100. package/corpus/templates/design/AGENTS.md +45 -10
  101. package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
  102. package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
  103. package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
  104. package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
  105. package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
  106. package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
  107. package/corpus/templates/design/actions/generate-design.ts +79 -12
  108. package/corpus/templates/design/actions/generate-screens.ts +57 -12
  109. package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
  110. package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
  111. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
  112. package/corpus/templates/design/actions/import-design-source.ts +4 -31
  113. package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
  114. package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
  115. package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
  116. package/corpus/templates/design/actions/list-design-components.ts +104 -0
  117. package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
  118. package/corpus/templates/design/actions/open-component-source.ts +2 -4
  119. package/corpus/templates/design/actions/present-design-variants.ts +412 -16
  120. package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
  121. package/corpus/templates/design/actions/run-design-audit.ts +25 -3
  122. package/corpus/templates/design/actions/show-design-questions.ts +10 -0
  123. package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
  124. package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
  125. package/corpus/templates/design/actions/write-local-file.ts +25 -1
  126. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
  127. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
  128. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
  129. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
  130. package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
  131. package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
  132. package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
  133. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
  134. package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
  135. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
  136. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
  137. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
  138. package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
  139. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
  140. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
  141. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
  142. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
  143. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
  144. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
  145. package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
  146. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
  147. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
  148. package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
  149. package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
  150. package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
  151. package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
  152. package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
  153. package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
  154. package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
  155. package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
  156. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
  157. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
  158. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
  159. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
  160. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
  161. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
  162. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
  163. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
  164. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
  165. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
  166. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
  167. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
  168. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
  169. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
  170. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
  171. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
  172. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
  173. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
  174. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
  175. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
  176. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
  177. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
  178. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
  179. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
  180. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
  181. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
  182. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
  183. package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
  184. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
  185. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
  186. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
  187. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
  188. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
  189. package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
  190. package/corpus/templates/design/app/components/design/types.ts +33 -0
  191. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
  192. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
  193. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
  194. package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
  195. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
  196. package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
  197. package/corpus/templates/design/app/i18n-data.ts +1217 -10
  198. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
  199. package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
  200. package/corpus/templates/design/app/lib/design-import.ts +24 -0
  201. package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
  202. package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
  203. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
  204. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
  205. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
  206. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
  207. package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
  208. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
  209. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
  210. package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
  211. package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
  212. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
  213. package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
  239. package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
  240. package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
  241. package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
  242. package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
  243. package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
  244. package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
  245. package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
  246. package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
  247. package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
  249. package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
  250. package/corpus/templates/design/e2e/global-setup.ts +3 -6
  251. package/corpus/templates/design/e2e/helpers.ts +27 -6
  252. package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
  253. package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
  254. package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
  255. package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
  256. package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
  257. package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
  258. package/corpus/templates/design/server/plugins/db.ts +41 -0
  259. package/corpus/templates/design/server/source-workspace.ts +64 -0
  260. package/corpus/templates/design/shared/board-file.ts +13 -2
  261. package/corpus/templates/design/shared/canvas-math.ts +231 -33
  262. package/corpus/templates/design/shared/code-layer.ts +122 -8
  263. package/corpus/templates/design/shared/component-library.ts +161 -0
  264. package/corpus/templates/design/shared/db-conflict.ts +27 -0
  265. package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
  266. package/corpus/templates/design/shared/figma-url.ts +149 -0
  267. package/corpus/templates/design/shared/pen-path.ts +16 -7
  268. package/corpus/templates/design/shared/source-mode.ts +1 -0
  269. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
  270. package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
  271. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
  272. package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
  273. package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
  274. package/dist/agent/production-agent.d.ts +82 -7
  275. package/dist/agent/production-agent.d.ts.map +1 -1
  276. package/dist/agent/production-agent.js +180 -17
  277. package/dist/agent/production-agent.js.map +1 -1
  278. package/dist/agent/run-manager.d.ts.map +1 -1
  279. package/dist/agent/run-manager.js +63 -14
  280. package/dist/agent/run-manager.js.map +1 -1
  281. package/dist/agent/run-store.d.ts +46 -0
  282. package/dist/agent/run-store.d.ts.map +1 -1
  283. package/dist/agent/run-store.js +129 -22
  284. package/dist/agent/run-store.js.map +1 -1
  285. package/dist/cli/design-connect.d.ts +6 -0
  286. package/dist/cli/design-connect.d.ts.map +1 -1
  287. package/dist/cli/design-connect.js +336 -139
  288. package/dist/cli/design-connect.js.map +1 -1
  289. package/dist/cli/skills.d.ts.map +1 -1
  290. package/dist/cli/skills.js +14 -0
  291. package/dist/cli/skills.js.map +1 -1
  292. package/dist/client/AssistantChat.d.ts +2 -0
  293. package/dist/client/AssistantChat.d.ts.map +1 -1
  294. package/dist/client/AssistantChat.js +19 -3
  295. package/dist/client/AssistantChat.js.map +1 -1
  296. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  297. package/dist/client/MultiTabAssistantChat.js +38 -18
  298. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  299. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  300. package/dist/client/agent-chat-adapter.js +48 -12
  301. package/dist/client/agent-chat-adapter.js.map +1 -1
  302. package/dist/client/agent-chat.d.ts +60 -0
  303. package/dist/client/agent-chat.d.ts.map +1 -1
  304. package/dist/client/agent-chat.js +122 -1
  305. package/dist/client/agent-chat.js.map +1 -1
  306. package/dist/client/chat/index.d.ts +1 -1
  307. package/dist/client/chat/index.d.ts.map +1 -1
  308. package/dist/client/chat/index.js +1 -1
  309. package/dist/client/chat/index.js.map +1 -1
  310. package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
  311. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  312. package/dist/client/extensions/EmbeddedExtension.js +36 -2
  313. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  314. package/dist/client/index.d.ts +1 -1
  315. package/dist/client/index.d.ts.map +1 -1
  316. package/dist/client/index.js +1 -1
  317. package/dist/client/index.js.map +1 -1
  318. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  319. package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
  320. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  321. package/dist/collab/awareness-store.d.ts +5 -0
  322. package/dist/collab/awareness-store.d.ts.map +1 -1
  323. package/dist/collab/awareness-store.js +19 -12
  324. package/dist/collab/awareness-store.js.map +1 -1
  325. package/dist/collab/awareness.d.ts +2 -2
  326. package/dist/collab/awareness.d.ts.map +1 -1
  327. package/dist/collab/client.d.ts.map +1 -1
  328. package/dist/collab/client.js +13 -5
  329. package/dist/collab/client.js.map +1 -1
  330. package/dist/collab/index.d.ts +1 -0
  331. package/dist/collab/index.d.ts.map +1 -1
  332. package/dist/collab/index.js +1 -0
  333. package/dist/collab/index.js.map +1 -1
  334. package/dist/collab/recent-edits.d.ts +3 -1
  335. package/dist/collab/recent-edits.d.ts.map +1 -1
  336. package/dist/collab/recent-edits.js +57 -2
  337. package/dist/collab/recent-edits.js.map +1 -1
  338. package/dist/collab/struct-routes.d.ts +1 -1
  339. package/dist/index.browser.d.ts +1 -1
  340. package/dist/index.browser.d.ts.map +1 -1
  341. package/dist/index.browser.js +1 -1
  342. package/dist/index.browser.js.map +1 -1
  343. package/dist/observability/routes.d.ts +5 -5
  344. package/dist/progress/routes.d.ts +1 -1
  345. package/dist/resources/handlers.d.ts +3 -3
  346. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  347. package/dist/server/agent-chat-plugin.js +87 -10
  348. package/dist/server/agent-chat-plugin.js.map +1 -1
  349. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  350. package/dist/server/builder-design-systems.d.ts +15 -0
  351. package/dist/server/builder-design-systems.d.ts.map +1 -1
  352. package/dist/server/builder-design-systems.js +9 -4
  353. package/dist/server/builder-design-systems.js.map +1 -1
  354. package/package.json +1 -1
@@ -1,18 +1,30 @@
1
- import { useActionMutation, useActionQuery } from "@agent-native/core/client";
1
+ import {
2
+ useActionMutation,
3
+ useActionQuery,
4
+ useT,
5
+ } from "@agent-native/core/client";
2
6
  import { propNameToDataAttribute } from "@shared/component-model";
3
7
  import {
4
8
  IconArrowRight,
9
+ IconArrowsLeftRight,
5
10
  IconCode,
11
+ IconComponents,
6
12
  IconExternalLink,
7
13
  IconLoader2,
14
+ IconUnlink,
8
15
  } from "@tabler/icons-react";
9
16
  import { useQueryClient } from "@tanstack/react-query";
10
- import { useCallback, useEffect, useRef } from "react";
17
+ import { useCallback, useEffect, useRef, useState } from "react";
11
18
  import { toast } from "sonner";
12
19
 
13
20
  import { Button } from "@/components/ui/button";
14
21
  import { Input } from "@/components/ui/input";
15
22
  import { Label } from "@/components/ui/label";
23
+ import {
24
+ Popover,
25
+ PopoverContent,
26
+ PopoverTrigger,
27
+ } from "@/components/ui/popover";
16
28
  import {
17
29
  Select,
18
30
  SelectContent,
@@ -91,6 +103,7 @@ function MakeItRealCard({
91
103
  */
92
104
  featureLabel: string;
93
105
  }) {
106
+ const t = useT();
94
107
  const { data, isLoading } = useActionQuery<ConnectBuilderAppResult>(
95
108
  "connect-builder-app",
96
109
  { designId },
@@ -160,7 +173,7 @@ function MakeItRealCard({
160
173
  rel="noopener noreferrer"
161
174
  className="inline-flex h-6 shrink-0 items-center gap-1 rounded-md px-1.5 text-[10px] font-semibold text-[var(--design-editor-accent-color)] hover:bg-[var(--design-editor-panel-raised-bg)]"
162
175
  >
163
- {"Open" /* i18n-ignore make-it-real card */}
176
+ {t("designEditor.makeItRealCard.open")}
164
177
  <IconExternalLink className="size-2.5" />
165
178
  </a>
166
179
  </div>
@@ -173,8 +186,8 @@ function MakeItRealCard({
173
186
  : `Connect Builder to enable ${featureLabel}.`;
174
187
  const primaryLabel =
175
188
  cta.kind === "configure-project"
176
- ? "Choose" /* i18n-ignore make-it-real card */
177
- : "Connect"; /* i18n-ignore make-it-real card */
189
+ ? t("designEditor.makeItRealCard.choose")
190
+ : t("designEditor.makeItRealCard.connect");
178
191
 
179
192
  return (
180
193
  <div className="space-y-1">
@@ -213,10 +226,10 @@ function MakeItRealCard({
213
226
  {isPending ? (
214
227
  <>
215
228
  <IconLoader2 className="size-2.5 animate-spin" />
216
- {"Generating" /* i18n-ignore make-it-real card */}
229
+ {t("designEditor.makeItRealCard.generating")}
217
230
  </>
218
231
  ) : (
219
- <>{"Generate" /* i18n-ignore make-it-real card */}</>
232
+ <>{t("designEditor.makeItRealCard.generate")}</>
220
233
  )}
221
234
  </Button>
222
235
  )}
@@ -225,7 +238,7 @@ function MakeItRealCard({
225
238
  <p className="px-2 text-[10px] text-destructive">
226
239
  {migrateError instanceof Error
227
240
  ? migrateError.message
228
- : /* i18n-ignore make-it-real card */ "Migration failed. Please try again."}
241
+ : t("designEditor.makeItRealCard.migrationFailed")}
229
242
  </p>
230
243
  ) : null}
231
244
  </div>
@@ -260,6 +273,150 @@ interface ComponentDetailsResult {
260
273
  };
261
274
  }
262
275
 
276
+ /** Shape returned by `go-to-main-component`. */
277
+ interface GoToMainComponentResult {
278
+ isMain?: boolean;
279
+ ctaRequired?: boolean;
280
+ ctaMessage?: string;
281
+ note?: string;
282
+ }
283
+
284
+ /** Shape returned by `swap-component-instance`. */
285
+ interface SwapComponentInstanceResult {
286
+ swapped?: boolean;
287
+ conflict?: boolean;
288
+ ctaRequired?: boolean;
289
+ ctaMessage?: string;
290
+ error?: string;
291
+ note?: string;
292
+ fromComponent?: string;
293
+ toComponent?: string;
294
+ fileId?: string;
295
+ content?: string;
296
+ updatedAt?: string;
297
+ }
298
+
299
+ /** Shape returned by `detach-component-instance`. */
300
+ interface DetachComponentInstanceResult {
301
+ detached?: boolean;
302
+ conflict?: boolean;
303
+ ctaRequired?: boolean;
304
+ ctaMessage?: string;
305
+ error?: string;
306
+ note?: string;
307
+ fileId?: string;
308
+ content?: string;
309
+ updatedAt?: string;
310
+ }
311
+
312
+ /** Each editable row: name + current value + how it persists + its options. */
313
+ export type PropRow = {
314
+ name: string;
315
+ value: string;
316
+ /** Variant/enum options when the prop is a known group. */
317
+ options?: string[];
318
+ /** Persist surface for this prop. */
319
+ surface: "alpineData" | "attribute";
320
+ };
321
+
322
+ /**
323
+ * Build the editable prop rows for a component instance from
324
+ * `get-component-details`'s response: Alpine `x-data` keys first (they drive
325
+ * the live variant/state), then observed `data-agent-native-prop-*`
326
+ * attributes not already covered by x-data, then any persisted variant group
327
+ * that has never been observed on this instance at all (seeded to its first
328
+ * option).
329
+ *
330
+ * Pure — exported for tests.
331
+ */
332
+ export function buildComponentPropRows(data: {
333
+ instance?: { alpineData?: string | null } | null;
334
+ observedProps: Array<{ name: string; value: string }>;
335
+ persistedVariants: Record<string, string[]>;
336
+ }): PropRow[] {
337
+ const { observedProps, persistedVariants, instance } = data;
338
+ const alpineData = parseAlpineDataObject(instance?.alpineData);
339
+
340
+ const rows: PropRow[] = [];
341
+ const seen = new Set<string>();
342
+
343
+ // 1) Alpine x-data keys come first — they drive the live variant/state.
344
+ if (alpineData) {
345
+ for (const [key, value] of Object.entries(alpineData)) {
346
+ rows.push({
347
+ name: key,
348
+ value,
349
+ options: persistedVariants[key],
350
+ surface: "alpineData",
351
+ });
352
+ seen.add(key);
353
+ }
354
+ }
355
+
356
+ // 2) data-agent-native-prop-* attributes not already covered by x-data.
357
+ for (const prop of observedProps) {
358
+ if (seen.has(prop.name)) continue;
359
+ rows.push({
360
+ name: prop.name,
361
+ value: prop.value,
362
+ options: persistedVariants[prop.name],
363
+ surface: "attribute",
364
+ });
365
+ seen.add(prop.name);
366
+ }
367
+
368
+ // 3) persistedVariant groups with no observed value yet (default to first).
369
+ // Surface is always "attribute" here, NOT "alpineData" even when this
370
+ // instance's x-data happens to be non-empty for other keys: x-data blocks
371
+ // for a real component instance are written with every prop the component
372
+ // declares initialized up front (e.g. `{ variant: 'solid', size: 'md' }`),
373
+ // so a group that never showed up in step 1 was never a x-data key on this
374
+ // instance in the first place — it is attribute-driven. Guessing
375
+ // "alpineData" from unrelated sibling keys used to route the very first
376
+ // edit of such a prop into a surgical/rebuild x-data write that either
377
+ // silently wrote a key nothing in the template reads, or hit the "can't
378
+ // safely edit this prop inline" bail-out when the sibling x-data content
379
+ // was too complex to rebuild — even though the plain attribute write would
380
+ // have worked fine.
381
+ for (const [group, options] of Object.entries(persistedVariants)) {
382
+ if (seen.has(group)) continue;
383
+ rows.push({
384
+ name: group,
385
+ value: options[0] ?? "",
386
+ options,
387
+ surface: "attribute",
388
+ });
389
+ seen.add(group);
390
+ }
391
+
392
+ return rows;
393
+ }
394
+
395
+ /**
396
+ * True when a "message" event's source window matches one of this document's
397
+ * own embedded design-preview iframes.
398
+ *
399
+ * `postMessage` has no origin/source check built in, so without this any
400
+ * window — including a spoofed one from a compromised/unrelated frame — could
401
+ * post `{ type: "element-select" }` at the parent and force this section to
402
+ * refetch. Mirrors the DOM-identity check DesignCanvas's
403
+ * `isTrustedCanvasBridgeMessage` and MultiScreenCanvas's cross-screen-drag
404
+ * handler use: trust comes from matching `iframe.contentWindow` against
405
+ * `event.source`, not from anything in the message payload.
406
+ *
407
+ * Exported for tests.
408
+ */
409
+ export function isMessageFromOwnPreviewIframe(
410
+ source: MessageEventSource | null,
411
+ ): boolean {
412
+ if (typeof document === "undefined" || !source) return false;
413
+ return Array.from(
414
+ document.querySelectorAll<HTMLIFrameElement>(
415
+ "iframe[data-design-preview-iframe]",
416
+ ),
417
+ ).some((iframe) => iframe.contentWindow === source);
418
+ }
419
+
263
420
  /**
264
421
  * Contextual COMPONENT section rendered inside the Design tab when the
265
422
  * selected element is a component instance (carries
@@ -279,6 +436,7 @@ export function ComponentSection({
279
436
  activeContent,
280
437
  activeFileUpdatedAt,
281
438
  nodeId,
439
+ swapPickerRequest = 0,
282
440
  onComponentPropApplied,
283
441
  sourceCapabilities = [],
284
442
  }: {
@@ -287,6 +445,8 @@ export function ComponentSection({
287
445
  activeContent?: string;
288
446
  activeFileUpdatedAt?: string | null;
289
447
  nodeId: string;
448
+ /** Increment to open the Swap instance picker from another UI entry point. */
449
+ swapPickerRequest?: number;
290
450
  onComponentPropApplied?: (
291
451
  fileId: string,
292
452
  content: string,
@@ -295,6 +455,7 @@ export function ComponentSection({
295
455
  /** Capability names advertised by the current source. */
296
456
  sourceCapabilities?: string[];
297
457
  }) {
458
+ const t = useT();
298
459
  const queryClient = useQueryClient();
299
460
  const detailsParams = { designId, nodeId, ...(fileId ? { fileId } : {}) };
300
461
  const detailsKey = ["action", "get-component-details", detailsParams];
@@ -322,6 +483,153 @@ export function ComponentSection({
322
483
 
323
484
  const openSourceMutation = useActionMutation("open-component-source");
324
485
  const applyPropMutation = useActionMutation("apply-component-prop-edit");
486
+ const goToMainMutation = useActionMutation("go-to-main-component");
487
+ const detachMutation = useActionMutation("detach-component-instance");
488
+ const swapMutation = useActionMutation("swap-component-instance");
489
+
490
+ // ── Swap instance picker (searchable popover) ─────────────────────────────
491
+ const [swapPickerOpen, setSwapPickerOpen] = useState(false);
492
+ const [swapQuery, setSwapQuery] = useState("");
493
+ useEffect(() => {
494
+ if (swapPickerRequest > 0) setSwapPickerOpen(true);
495
+ }, [swapPickerRequest]);
496
+ const componentName = data?.name;
497
+ const { data: swapCatalog, isLoading: swapCatalogLoading } = useActionQuery(
498
+ "list-design-components",
499
+ { designId, excludeName: componentName },
500
+ { enabled: swapPickerOpen && Boolean(componentName) },
501
+ );
502
+ const swapCandidates = (swapCatalog?.components ?? []).filter((c) =>
503
+ c.name.toLowerCase().includes(swapQuery.trim().toLowerCase()),
504
+ );
505
+
506
+ // Refresh the component section + design canvas after a detach/swap
507
+ // mutates the design file, mirroring persistPropEdit's onSettled below.
508
+ // Plain function (not memoized) — matches this file's existing
509
+ // persistPropEdit/commitProp convention of re-creating handlers per render
510
+ // rather than threading useCallback dependency arrays through them.
511
+ const refreshAfterInstanceMutation = (result: {
512
+ fileId?: string;
513
+ content?: string;
514
+ updatedAt?: string;
515
+ }) => {
516
+ if (
517
+ typeof result.fileId === "string" &&
518
+ typeof result.content === "string"
519
+ ) {
520
+ latestSourceRef.current = {
521
+ content: result.content,
522
+ revision: result.updatedAt ?? latestSourceRef.current.revision,
523
+ };
524
+ onComponentPropApplied?.(result.fileId, result.content, result.updatedAt);
525
+ }
526
+ void queryClient.invalidateQueries({ queryKey: ["action", "get-design"] });
527
+ void queryClient.invalidateQueries({ queryKey: detailsKey });
528
+ void refetch();
529
+ };
530
+
531
+ const sourceForMutation = () => {
532
+ const latestSource = latestSourceRef.current;
533
+ return latestSource.content
534
+ ? {
535
+ currentContent: latestSource.content,
536
+ ...(latestSource.revision ? { revision: latestSource.revision } : {}),
537
+ }
538
+ : undefined;
539
+ };
540
+
541
+ const handleGoToMainComponent = () => {
542
+ goToMainMutation.mutate(
543
+ { designId, nodeId, ...(fileId ? { fileId } : {}) },
544
+ {
545
+ onSuccess: (result: GoToMainComponentResult) => {
546
+ if (result.ctaRequired) {
547
+ toast.error(
548
+ result.ctaMessage ??
549
+ t("designEditor.componentInstances.goToMainUnavailable"),
550
+ );
551
+ return;
552
+ }
553
+ if (result.isMain) {
554
+ toast(
555
+ result.note ??
556
+ t("designEditor.componentInstances.onlyKnownInstance"),
557
+ );
558
+ }
559
+ },
560
+ onError: () =>
561
+ toast.error(t("designEditor.componentInstances.resolveMainFailed")),
562
+ },
563
+ );
564
+ };
565
+
566
+ const handleDetachInstance = () => {
567
+ const source = sourceForMutation();
568
+ detachMutation.mutate(
569
+ {
570
+ designId,
571
+ nodeId,
572
+ ...(fileId ? { fileId } : {}),
573
+ ...(source ? { source } : {}),
574
+ },
575
+ {
576
+ onSuccess: (result: DetachComponentInstanceResult) => {
577
+ if (result.conflict || result.ctaRequired) {
578
+ toast.error(
579
+ result.error ??
580
+ result.ctaMessage ??
581
+ t("designEditor.componentInstances.detachFailed"),
582
+ );
583
+ return;
584
+ }
585
+ if (result.detached) {
586
+ toast(result.note ?? t("designEditor.componentInstances.detached"));
587
+ refreshAfterInstanceMutation(result);
588
+ }
589
+ },
590
+ onError: () =>
591
+ toast.error(t("designEditor.componentInstances.detachFailed")),
592
+ },
593
+ );
594
+ };
595
+
596
+ const handleSwapInstance = (targetComponentName: string) => {
597
+ const source = sourceForMutation();
598
+ swapMutation.mutate(
599
+ {
600
+ designId,
601
+ nodeId,
602
+ ...(fileId ? { fileId } : {}),
603
+ targetComponentName,
604
+ ...(source ? { source } : {}),
605
+ },
606
+ {
607
+ onSuccess: (result: SwapComponentInstanceResult) => {
608
+ if (result.conflict || result.ctaRequired) {
609
+ toast.error(
610
+ result.error ??
611
+ result.ctaMessage ??
612
+ t("designEditor.componentInstances.swapFailed"),
613
+ );
614
+ return;
615
+ }
616
+ if (result.swapped) {
617
+ toast(
618
+ result.note ??
619
+ t("designEditor.componentInstances.swappedFor", {
620
+ name: targetComponentName,
621
+ }),
622
+ );
623
+ setSwapPickerOpen(false);
624
+ setSwapQuery("");
625
+ refreshAfterInstanceMutation(result);
626
+ }
627
+ },
628
+ onError: () =>
629
+ toast.error(t("designEditor.componentInstances.swapFailed")),
630
+ },
631
+ );
632
+ };
325
633
 
326
634
  const postComponentPropPreview = useCallback(
327
635
  (attribute: string, value: string) => {
@@ -428,10 +736,12 @@ export function ComponentSection({
428
736
 
429
737
  const handleMessage = (event: MessageEvent) => {
430
738
  if (
431
- (event.data as { type?: unknown } | null)?.type === "element-select"
739
+ (event.data as { type?: unknown } | null)?.type !== "element-select"
432
740
  ) {
433
- void refetch();
741
+ return;
434
742
  }
743
+ if (!isMessageFromOwnPreviewIframe(event.source)) return;
744
+ void refetch();
435
745
  };
436
746
  window.addEventListener("message", handleMessage);
437
747
  return () => {
@@ -479,55 +789,11 @@ export function ComponentSection({
479
789
  const editingEnabled = isInline && capabilities.canEditProps; // gated; real-app stays read-only for now
480
790
  const alpineData = parseAlpineDataObject(instance?.alpineData);
481
791
 
482
- // Each editable row: name + current value + how it persists + its options.
483
- type PropRow = {
484
- name: string;
485
- value: string;
486
- /** Variant/enum options when the prop is a known group. */
487
- options?: string[];
488
- /** Persist surface for this prop. */
489
- surface: "alpineData" | "attribute";
490
- };
491
-
492
- const rows: PropRow[] = [];
493
- const seen = new Set<string>();
494
-
495
- // 1) Alpine x-data keys come first — they drive the live variant/state.
496
- if (alpineData) {
497
- for (const [key, value] of Object.entries(alpineData)) {
498
- rows.push({
499
- name: key,
500
- value,
501
- options: persistedVariants[key],
502
- surface: "alpineData",
503
- });
504
- seen.add(key);
505
- }
506
- }
507
-
508
- // 2) data-agent-native-prop-* attributes not already covered by x-data.
509
- for (const prop of observedProps) {
510
- if (seen.has(prop.name)) continue;
511
- rows.push({
512
- name: prop.name,
513
- value: prop.value,
514
- options: persistedVariants[prop.name],
515
- surface: "attribute",
516
- });
517
- seen.add(prop.name);
518
- }
519
-
520
- // 3) persistedVariant groups with no observed value yet (default to first).
521
- for (const [group, options] of Object.entries(persistedVariants)) {
522
- if (seen.has(group)) continue;
523
- rows.push({
524
- name: group,
525
- value: options[0] ?? "",
526
- options,
527
- surface: alpineData ? "alpineData" : "attribute",
528
- });
529
- seen.add(group);
530
- }
792
+ const rows: PropRow[] = buildComponentPropRows({
793
+ instance,
794
+ observedProps,
795
+ persistedVariants,
796
+ });
531
797
 
532
798
  const hasRows = rows.length > 0;
533
799
 
@@ -559,10 +825,7 @@ export function ComponentSection({
559
825
  // can't rewrite for this key without dropping it. Fail safe: skip the
560
826
  // edit rather than persist a lossy rewrite, and tell the user why so
561
827
  // the change doesn't silently vanish.
562
- toast.error(
563
- // i18n-ignore
564
- "Can’t safely edit this prop inline — this component’s Alpine state is too complex. Edit the source instead.",
565
- );
828
+ toast.error(t("designEditor.componentProps.alpineTooComplexToEdit"));
566
829
  return;
567
830
  }
568
831
 
@@ -625,6 +888,125 @@ export function ComponentSection({
625
888
  <h3 className="min-w-0 flex-1 truncate !text-[11px] font-semibold text-foreground">
626
889
  {name}
627
890
  </h3>
891
+ {/* Instance operations: Go to main component / Swap instance /
892
+ Detach instance (Figma's instance-only affordances). Inline/Alpine
893
+ designs only — the underlying actions fail closed for real-app
894
+ sources, so hide them entirely there rather than show a
895
+ perpetually-disabled button. */}
896
+ {isInline && (
897
+ <>
898
+ <Tooltip>
899
+ <TooltipTrigger asChild>
900
+ <Button
901
+ type="button"
902
+ variant="ghost"
903
+ size="icon"
904
+ className="size-6 rounded-md text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
905
+ disabled={goToMainMutation.isPending}
906
+ aria-label={t("designEditor.componentInstances.goToMain")}
907
+ onClick={handleGoToMainComponent}
908
+ >
909
+ <IconComponents className="size-3.5" />
910
+ </Button>
911
+ </TooltipTrigger>
912
+ <TooltipContent>
913
+ {t("designEditor.componentInstances.goToMain")}
914
+ </TooltipContent>
915
+ </Tooltip>
916
+
917
+ <Popover
918
+ open={swapPickerOpen}
919
+ onOpenChange={(open) => {
920
+ setSwapPickerOpen(open);
921
+ if (!open) setSwapQuery("");
922
+ }}
923
+ >
924
+ <Tooltip>
925
+ <TooltipTrigger asChild>
926
+ <PopoverTrigger asChild>
927
+ <Button
928
+ type="button"
929
+ variant="ghost"
930
+ size="icon"
931
+ className="size-6 rounded-md text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
932
+ disabled={!editingEnabled || swapMutation.isPending}
933
+ aria-label={t("designEditor.componentInstances.swap")}
934
+ >
935
+ <IconArrowsLeftRight className="size-3.5" />
936
+ </Button>
937
+ </PopoverTrigger>
938
+ </TooltipTrigger>
939
+ <TooltipContent>
940
+ {t("designEditor.componentInstances.swap")}
941
+ </TooltipContent>
942
+ </Tooltip>
943
+ <PopoverContent
944
+ align="end"
945
+ className="w-56 rounded-md border-[var(--design-editor-control-border)] bg-[var(--design-editor-panel-bg)] p-1.5 text-[11px]"
946
+ >
947
+ <Input
948
+ autoFocus
949
+ value={swapQuery}
950
+ onChange={(e) => setSwapQuery(e.target.value)}
951
+ placeholder={t(
952
+ "designEditor.componentInstances.searchComponents",
953
+ )}
954
+ className="mb-1.5 h-7 !text-[11px]"
955
+ />
956
+ <div className="max-h-52 overflow-y-auto">
957
+ {swapCatalogLoading ? (
958
+ <div className="px-2 py-1.5 text-muted-foreground">
959
+ {t("designEditor.componentInstances.loading")}
960
+ </div>
961
+ ) : swapCandidates.length === 0 ? (
962
+ <div className="px-2 py-1.5 text-muted-foreground">
963
+ {t("designEditor.componentInstances.noOtherComponents")}
964
+ </div>
965
+ ) : (
966
+ swapCandidates.map((candidate) => (
967
+ <button
968
+ key={candidate.name}
969
+ type="button"
970
+ disabled={swapMutation.isPending}
971
+ onClick={() => handleSwapInstance(candidate.name)}
972
+ className="flex w-full items-center justify-between gap-2 rounded-[4px] px-2 py-1.5 text-left hover:bg-[var(--design-editor-selection-color)] hover:text-white disabled:cursor-wait disabled:opacity-60"
973
+ >
974
+ <span className="min-w-0 flex-1 truncate">
975
+ {candidate.name}
976
+ </span>
977
+ <span className="shrink-0 text-[10px] text-muted-foreground">
978
+ {candidate.instanceCount}
979
+ </span>
980
+ </button>
981
+ ))
982
+ )}
983
+ </div>
984
+ </PopoverContent>
985
+ </Popover>
986
+
987
+ <Tooltip>
988
+ <TooltipTrigger asChild>
989
+ <Button
990
+ type="button"
991
+ variant="ghost"
992
+ size="icon"
993
+ className="size-6 rounded-md text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
994
+ disabled={!editingEnabled || detachMutation.isPending}
995
+ aria-label={t("designEditor.componentInstances.detach")}
996
+ onClick={handleDetachInstance}
997
+ >
998
+ <IconUnlink className="size-3.5" />
999
+ </Button>
1000
+ </TooltipTrigger>
1001
+ <TooltipContent>
1002
+ {t("designEditor.componentInstances.detach")}
1003
+ <span className="ms-1.5 text-muted-foreground/70">
1004
+ {"⌥⌘B" /* i18n-ignore keyboard shortcut */}
1005
+ </span>
1006
+ </TooltipContent>
1007
+ </Tooltip>
1008
+ </>
1009
+ )}
628
1010
  {/* Jump-to-source action */}
629
1011
  <Tooltip>
630
1012
  <TooltipTrigger asChild>
@@ -634,9 +1016,7 @@ export function ComponentSection({
634
1016
  size="icon"
635
1017
  className="size-6 rounded-md text-muted-foreground hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
636
1018
  disabled={!canJumpToSource}
637
- aria-label={
638
- "Edit component source" /* i18n-ignore design inspector action */
639
- }
1019
+ aria-label={t("designEditor.componentSource.editSource")}
640
1020
  onClick={() => {
641
1021
  openSourceMutation.mutate({
642
1022
  designId,
@@ -649,12 +1029,10 @@ export function ComponentSection({
649
1029
  </Button>
650
1030
  </TooltipTrigger>
651
1031
  <TooltipContent>
652
- {
653
- canJumpToSource
654
- ? "Edit component source" /* i18n-ignore design inspector action */
655
- : (capabilities.ctaMessage ??
656
- "Source jump needs a connected app") /* i18n-ignore design inspector tooltip */
657
- }
1032
+ {canJumpToSource
1033
+ ? t("designEditor.componentSource.editSource")
1034
+ : (capabilities.ctaMessage ??
1035
+ t("designEditor.componentSource.needsConnectedApp"))}
658
1036
  </TooltipContent>
659
1037
  </Tooltip>
660
1038
  </div>
@@ -680,7 +1058,7 @@ export function ComponentSection({
680
1058
  {hasRows && (
681
1059
  <div className="space-y-1">
682
1060
  <p className="text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70">
683
- {"Props" /* i18n-ignore design inspector label */}
1061
+ {t("designEditor.componentProps.label")}
684
1062
  </p>
685
1063
  {rows.map((row) => {
686
1064
  const hasOptions = (row.options?.length ?? 0) > 0;
@@ -74,10 +74,18 @@ export function selectionColorValues(
74
74
  return rawValues
75
75
  .map((color) => ({ ...color, value: color.value?.trim() }))
76
76
  .filter((color): color is SelectionColorValue => Boolean(color.value))
77
- .filter(
78
- (color) =>
79
- color.value !== "transparent" && color.value !== "rgba(0, 0, 0, 0)",
80
- )
77
+ .filter((color) => {
78
+ // Skip fully transparent colors — not a meaningful "selection color"
79
+ // swatch (matches extractDocumentColorPalette's same alpha check
80
+ // below). Parsed via parseCssColor rather than compared against the
81
+ // two literal spellings "transparent"/"rgba(0, 0, 0, 0)" — a border/
82
+ // outline color can be zero-alpha in many other forms (e.g.
83
+ // "rgba(255, 0, 0, 0)", "hsla(0, 0%, 0%, 0)", no-space formatting)
84
+ // and those previously slipped through as a bogus opaque-looking
85
+ // swatch instead of being hidden like every other invisible color.
86
+ const parsed = parseCssColor(color.value);
87
+ return !parsed || parsed.a > 0;
88
+ })
81
89
  .filter((color) => {
82
90
  const key = color.value.toLowerCase();
83
91
  if (seen.has(key)) return false;