@agent-native/core 0.79.27 → 0.80.0

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 (346) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +26 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +41 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +51 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +50 -0
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +49 -0
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +44 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +46 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +44 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +48 -0
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +36 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +38 -0
  13. package/corpus/core/docs/content/template-design.mdx +45 -0
  14. package/corpus/core/package.json +2 -1
  15. package/corpus/core/src/agent/engine/index.ts +1 -0
  16. package/corpus/core/src/agent/engine/registry.ts +40 -0
  17. package/corpus/core/src/agent/production-agent.ts +6 -2
  18. package/corpus/core/src/cli/design-connect.ts +490 -0
  19. package/corpus/core/src/cli/index.ts +16 -0
  20. package/corpus/core/src/cli/skills.ts +126 -3
  21. package/corpus/core/src/client/AssistantChat.tsx +43 -7
  22. package/corpus/core/src/client/agent-chat.ts +27 -3
  23. package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +1 -1
  24. package/corpus/core/src/client/blocks/library/diagram.tsx +2 -2
  25. package/corpus/core/src/client/blocks/library/wireframe.tsx +1 -1
  26. package/corpus/core/src/client/chat/message-components.tsx +1 -1
  27. package/corpus/core/src/client/chat-model-groups.ts +1 -2
  28. package/corpus/core/src/client/components/LiveCursorOverlay.tsx +33 -66
  29. package/corpus/core/src/client/composer/TiptapComposer.tsx +99 -24
  30. package/corpus/core/src/client/composer/useVoiceDictation.ts +429 -260
  31. package/corpus/core/src/client/frame-protocol.ts +17 -2
  32. package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +2 -2
  33. package/corpus/core/src/client/sharing/ShareButton.tsx +20 -15
  34. package/corpus/core/src/client/use-agent-engine-configured.ts +80 -28
  35. package/corpus/core/src/server/transcribe-voice.ts +57 -22
  36. package/corpus/core/src/shared/mcp-embed-headers.ts +23 -1
  37. package/corpus/core/src/styles/agent-native.css +56 -7
  38. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  39. package/corpus/core/src/vite/client.ts +2 -0
  40. package/corpus/core/src/voice/index.ts +18 -0
  41. package/corpus/core/src/voice/voice-cleanup-prompt.ts +38 -0
  42. package/corpus/core/src/voice/voice-context.ts +217 -0
  43. package/corpus/core/src/voice/voice-replacements.ts +75 -0
  44. package/corpus/templates/analytics/AGENTS.md +4 -3
  45. package/corpus/templates/analytics/actions/list-session-recordings.ts +6 -1
  46. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +557 -400
  47. package/corpus/templates/analytics/app/global.css +0 -4
  48. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  49. package/corpus/templates/analytics/app/i18n-data.ts +20 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +33 -8
  51. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +7 -0
  52. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +7 -0
  53. package/corpus/templates/analytics/changelog/2026-06-28-ask-tab-now-matches-the-darker-app-background.md +6 -0
  54. package/corpus/templates/analytics/changelog/2026-06-28-dashboard-email-reports-now-use-cleaner-light-mode-snapshots.md +6 -0
  55. package/corpus/templates/analytics/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  56. package/corpus/templates/analytics/changelog/2026-06-28-sessions-now-show-only-signed-in-recordings-with-playable-re.md +6 -0
  57. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
  58. package/corpus/templates/analytics/server/lib/dashboard-report.ts +29 -7
  59. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +5 -2
  60. package/corpus/templates/analytics/server/lib/session-replay.ts +24 -4
  61. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -4
  62. package/corpus/templates/assets/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  63. package/corpus/templates/brain/app/components/layout/Layout.tsx +29 -2
  64. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +131 -42
  65. package/corpus/templates/brain/app/i18n/zh-TW.ts +2 -0
  66. package/corpus/templates/brain/app/i18n-data.ts +20 -0
  67. package/corpus/templates/brain/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  68. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +29 -1
  69. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +417 -299
  70. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  71. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  72. package/corpus/templates/calendar/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  73. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +6 -19
  74. package/corpus/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  75. package/corpus/templates/clips/AGENTS.md +4 -0
  76. package/corpus/templates/clips/actions/cleanup-transcript.ts +39 -9
  77. package/corpus/templates/clips/actions/finalize-meeting.ts +81 -12
  78. package/corpus/templates/clips/actions/lib/agents-md-context.ts +4 -1
  79. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
  80. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +1 -1
  81. package/corpus/templates/clips/app/components/player/share-dialog.tsx +2 -2
  82. package/corpus/templates/clips/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  83. package/corpus/templates/clips/desktop/src/lib/personal-vocabulary.ts +13 -8
  84. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +60 -1
  85. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1 -1
  86. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -1
  87. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -5
  88. package/corpus/templates/content/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  89. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +137 -0
  90. package/corpus/templates/design/AGENTS.md +95 -5
  91. package/corpus/templates/design/DESIGN.md +82 -0
  92. package/corpus/templates/design/DEVELOPING.md +43 -0
  93. package/corpus/templates/design/actions/add-localhost-screens.ts +426 -0
  94. package/corpus/templates/design/actions/apply-shader.ts +277 -0
  95. package/corpus/templates/design/actions/apply-visual-edit.ts +303 -0
  96. package/corpus/templates/design/actions/connect-localhost.ts +183 -0
  97. package/corpus/templates/design/actions/edit-design.ts +195 -42
  98. package/corpus/templates/design/actions/generate-design.ts +71 -1
  99. package/corpus/templates/design/actions/generate-screens.ts +193 -0
  100. package/corpus/templates/design/actions/get-code-layer-projection.ts +191 -0
  101. package/corpus/templates/design/actions/get-shader.ts +119 -0
  102. package/corpus/templates/design/actions/list-localhost-connections.ts +95 -0
  103. package/corpus/templates/design/actions/navigate.ts +55 -2
  104. package/corpus/templates/design/actions/view-screen.ts +68 -1
  105. package/corpus/templates/design/agent-native.app-skill.json +10 -0
  106. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +761 -0
  107. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +2057 -103
  108. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +74 -38
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +399 -0
  110. package/corpus/templates/design/app/components/design/EditPanel.tsx +3185 -439
  111. package/corpus/templates/design/app/components/design/LayersPanel.tsx +1124 -0
  112. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3116 -147
  113. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +700 -13
  114. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +107 -63
  115. package/corpus/templates/design/app/components/design/index.ts +0 -5
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +286 -0
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +699 -0
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +461 -0
  119. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +166 -0
  120. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +1420 -0
  121. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +420 -0
  122. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +215 -0
  123. package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +71 -0
  124. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +518 -0
  125. package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +106 -0
  126. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +361 -0
  127. package/corpus/templates/design/app/components/design/inspector/index.ts +60 -0
  128. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +201 -0
  129. package/corpus/templates/design/app/components/design/types.ts +23 -0
  130. package/corpus/templates/design/app/components/layout/Layout.tsx +24 -13
  131. package/corpus/templates/design/app/components/layout/Sidebar.tsx +4 -4
  132. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +474 -36
  133. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +22 -5
  134. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +24 -11
  135. package/corpus/templates/design/app/global.css +121 -3
  136. package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -0
  137. package/corpus/templates/design/app/hooks/use-navigation-state.ts +130 -8
  138. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +329 -0
  139. package/corpus/templates/design/app/i18n/zh-TW.ts +264 -0
  140. package/corpus/templates/design/app/i18n-data.ts +2790 -1
  141. package/corpus/templates/design/app/pages/DesignEditor.tsx +5108 -851
  142. package/corpus/templates/design/changelog/2026-06-28-annotate-mode-now-combines-drawing-and-comment-pins-in-one-c.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-28-design-editor-panel-borders-are-cleaner-so-the-canvas-edge-s.md +6 -0
  144. package/corpus/templates/design/changelog/2026-06-28-drawing-prompts-now-reliably-open-and-submit-to-the-design-a.md +6 -0
  145. package/corpus/templates/design/changelog/2026-06-28-editor-app-menus-now-use-an-outline-agent-native-mark-with-b.md +6 -0
  146. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-28-layer-selection-now-updates-chat-context-without-opening-the.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-28-layer-selections-now-preserve-hidden-and-locked-canvas-state.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-handles-zooming-drawing-opening-and-dele.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-selects-screens-on-click-and-opens-them-.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-28-screen-overview-zooms-into-the-active-screen-with-smoother-e.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-28-selected-element-chips-in-chat-are-shorter-and-easier-to-sca.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-28-the-design-editor-toolbar-is-more-compact-and-the-app-menu-m.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-at-the-top-of-the-design-sidebar-instead-of-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-in-the-right-inspector-beside-the-design-tab.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-active-sidebar-rows-use-soft-highlights.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-29-agents-can-now-open-screen-overview-focus-screens-and-add.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-edit-broad-copy-changes-more-reliably.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-29-design-editor-extensions-now-run-inline-beside-the-artboard.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-29-sidebars-use-darker-chrome-and-chat-warns-immediately.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-29-visual-edit-can-open-localhost-routes-as-url-backed-screens.md +6 -0
  165. package/corpus/templates/design/package.json +1 -0
  166. package/corpus/templates/design/server/db/schema.ts +26 -0
  167. package/corpus/templates/design/server/lib/design-snapshot.ts +1 -1
  168. package/corpus/templates/design/server/plugins/agent-chat.ts +3 -0
  169. package/corpus/templates/design/shared/api.ts +27 -0
  170. package/corpus/templates/design/shared/canvas-frames.ts +103 -0
  171. package/corpus/templates/design/shared/canvas-math.ts +1058 -0
  172. package/corpus/templates/design/shared/code-layer.ts +2212 -0
  173. package/corpus/templates/design/shared/color-utils.ts +180 -0
  174. package/corpus/templates/design/shared/generation-session.ts +61 -0
  175. package/corpus/templates/design/shared/shader-presets.ts +782 -0
  176. package/corpus/templates/design/shared/shader-safety.ts +137 -0
  177. package/corpus/templates/design/shared/source-mode.ts +237 -0
  178. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +149 -6
  179. package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
  180. package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
  181. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  182. package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
  183. package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
  184. package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
  185. package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
  186. package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
  187. package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
  188. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  189. package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
  190. package/corpus/templates/forms/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  191. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  192. package/corpus/templates/macros/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  193. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +408 -247
  194. package/corpus/templates/mail/app/i18n/ar-SA.ts +4 -0
  195. package/corpus/templates/mail/app/i18n/de-DE.ts +4 -0
  196. package/corpus/templates/mail/app/i18n/en-US.ts +4 -0
  197. package/corpus/templates/mail/app/i18n/es-ES.ts +4 -0
  198. package/corpus/templates/mail/app/i18n/fr-FR.ts +4 -0
  199. package/corpus/templates/mail/app/i18n/hi-IN.ts +4 -0
  200. package/corpus/templates/mail/app/i18n/ja-JP.ts +4 -0
  201. package/corpus/templates/mail/app/i18n/ko-KR.ts +4 -0
  202. package/corpus/templates/mail/app/i18n/pt-BR.ts +4 -0
  203. package/corpus/templates/mail/app/i18n/zh-CN.ts +4 -0
  204. package/corpus/templates/mail/app/i18n/zh-TW.ts +4 -0
  205. package/corpus/templates/mail/changelog/2026-06-28-pinned-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  206. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +6 -8
  207. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
  208. package/corpus/templates/plan/app/global.css +61 -78
  209. package/corpus/templates/plan/app/pages/PlansPage.tsx +8 -0
  210. package/corpus/templates/plan/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  211. package/corpus/templates/plan/changelog/2026-06-28-plans-use-the-shared-neutral-light-and-dark-theme.md +6 -0
  212. package/corpus/templates/plan/changelog/2026-06-28-sending-open-feedback-from-a-plan-now-opens-the-inline-plan-.md +6 -0
  213. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +5 -5
  214. package/corpus/templates/slides/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  215. package/corpus/templates/videos/app/components/Sidebar.tsx +2 -2
  216. package/corpus/templates/videos/app/components/layout/Layout.tsx +29 -2
  217. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +113 -30
  218. package/corpus/templates/videos/app/i18n/ar-SA.ts +2 -0
  219. package/corpus/templates/videos/app/i18n/de-DE.ts +2 -0
  220. package/corpus/templates/videos/app/i18n/en-US.ts +2 -0
  221. package/corpus/templates/videos/app/i18n/es-ES.ts +2 -0
  222. package/corpus/templates/videos/app/i18n/fr-FR.ts +2 -0
  223. package/corpus/templates/videos/app/i18n/hi-IN.ts +2 -0
  224. package/corpus/templates/videos/app/i18n/ja-JP.ts +2 -0
  225. package/corpus/templates/videos/app/i18n/ko-KR.ts +2 -0
  226. package/corpus/templates/videos/app/i18n/pt-BR.ts +2 -0
  227. package/corpus/templates/videos/app/i18n/zh-CN.ts +2 -0
  228. package/corpus/templates/videos/app/i18n/zh-TW.ts +2 -0
  229. package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  230. package/dist/agent/engine/index.d.ts +1 -1
  231. package/dist/agent/engine/index.d.ts.map +1 -1
  232. package/dist/agent/engine/index.js +1 -1
  233. package/dist/agent/engine/index.js.map +1 -1
  234. package/dist/agent/engine/registry.d.ts +9 -0
  235. package/dist/agent/engine/registry.d.ts.map +1 -1
  236. package/dist/agent/engine/registry.js +37 -0
  237. package/dist/agent/engine/registry.js.map +1 -1
  238. package/dist/agent/production-agent.d.ts.map +1 -1
  239. package/dist/agent/production-agent.js +4 -3
  240. package/dist/agent/production-agent.js.map +1 -1
  241. package/dist/cli/design-connect.d.ts +52 -0
  242. package/dist/cli/design-connect.d.ts.map +1 -0
  243. package/dist/cli/design-connect.js +409 -0
  244. package/dist/cli/design-connect.js.map +1 -0
  245. package/dist/cli/index.js +15 -0
  246. package/dist/cli/index.js.map +1 -1
  247. package/dist/cli/skills.d.ts +3 -0
  248. package/dist/cli/skills.d.ts.map +1 -1
  249. package/dist/cli/skills.js +121 -3
  250. package/dist/cli/skills.js.map +1 -1
  251. package/dist/client/AssistantChat.d.ts.map +1 -1
  252. package/dist/client/AssistantChat.js +38 -8
  253. package/dist/client/AssistantChat.js.map +1 -1
  254. package/dist/client/agent-chat.d.ts +6 -0
  255. package/dist/client/agent-chat.d.ts.map +1 -1
  256. package/dist/client/agent-chat.js +17 -3
  257. package/dist/client/agent-chat.js.map +1 -1
  258. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  259. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  260. package/dist/client/blocks/library/diagram.js +1 -1
  261. package/dist/client/blocks/library/diagram.js.map +1 -1
  262. package/dist/client/blocks/library/wireframe.js +1 -1
  263. package/dist/client/blocks/library/wireframe.js.map +1 -1
  264. package/dist/client/chat/message-components.js +1 -1
  265. package/dist/client/chat/message-components.js.map +1 -1
  266. package/dist/client/chat-model-groups.d.ts.map +1 -1
  267. package/dist/client/chat-model-groups.js +1 -2
  268. package/dist/client/chat-model-groups.js.map +1 -1
  269. package/dist/client/components/LiveCursorOverlay.d.ts +1 -2
  270. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
  271. package/dist/client/components/LiveCursorOverlay.js +19 -40
  272. package/dist/client/components/LiveCursorOverlay.js.map +1 -1
  273. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  274. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  275. package/dist/client/composer/TiptapComposer.js +86 -24
  276. package/dist/client/composer/TiptapComposer.js.map +1 -1
  277. package/dist/client/composer/useVoiceDictation.d.ts +9 -0
  278. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  279. package/dist/client/composer/useVoiceDictation.js +154 -32
  280. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  281. package/dist/client/frame-protocol.d.ts +17 -2
  282. package/dist/client/frame-protocol.d.ts.map +1 -1
  283. package/dist/client/frame-protocol.js.map +1 -1
  284. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +2 -2
  285. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  286. package/dist/client/sharing/ShareButton.d.ts +2 -0
  287. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  288. package/dist/client/sharing/ShareButton.js +7 -6
  289. package/dist/client/sharing/ShareButton.js.map +1 -1
  290. package/dist/client/use-agent-engine-configured.d.ts +5 -0
  291. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  292. package/dist/client/use-agent-engine-configured.js +51 -25
  293. package/dist/client/use-agent-engine-configured.js.map +1 -1
  294. package/dist/collab/awareness.d.ts +2 -2
  295. package/dist/collab/awareness.d.ts.map +1 -1
  296. package/dist/collab/routes.d.ts +1 -1
  297. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  298. package/dist/notifications/routes.d.ts +3 -3
  299. package/dist/observability/routes.d.ts +8 -8
  300. package/dist/progress/routes.d.ts +1 -1
  301. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  302. package/dist/server/transcribe-voice.d.ts.map +1 -1
  303. package/dist/server/transcribe-voice.js +40 -24
  304. package/dist/server/transcribe-voice.js.map +1 -1
  305. package/dist/shared/mcp-embed-headers.d.ts +1 -0
  306. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  307. package/dist/shared/mcp-embed-headers.js +20 -1
  308. package/dist/shared/mcp-embed-headers.js.map +1 -1
  309. package/dist/styles/agent-native.css +56 -7
  310. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  311. package/dist/vite/client.d.ts.map +1 -1
  312. package/dist/vite/client.js +2 -0
  313. package/dist/vite/client.js.map +1 -1
  314. package/dist/voice/index.d.ts +5 -0
  315. package/dist/voice/index.d.ts.map +1 -0
  316. package/dist/voice/index.js +4 -0
  317. package/dist/voice/index.js.map +1 -0
  318. package/dist/voice/voice-cleanup-prompt.d.ts +6 -0
  319. package/dist/voice/voice-cleanup-prompt.d.ts.map +1 -0
  320. package/dist/voice/voice-cleanup-prompt.js +26 -0
  321. package/dist/voice/voice-cleanup-prompt.js.map +1 -0
  322. package/dist/voice/voice-context.d.ts +25 -0
  323. package/dist/voice/voice-context.d.ts.map +1 -0
  324. package/dist/voice/voice-context.js +156 -0
  325. package/dist/voice/voice-context.js.map +1 -0
  326. package/dist/voice/voice-replacements.d.ts +4 -0
  327. package/dist/voice/voice-replacements.d.ts.map +1 -0
  328. package/dist/voice/voice-replacements.js +52 -0
  329. package/dist/voice/voice-replacements.js.map +1 -0
  330. package/docs/content/locales/ar-SA/template-design.mdx +41 -0
  331. package/docs/content/locales/de-DE/template-design.mdx +51 -0
  332. package/docs/content/locales/es-ES/template-design.mdx +50 -0
  333. package/docs/content/locales/fr-FR/template-design.mdx +49 -0
  334. package/docs/content/locales/hi-IN/template-design.mdx +44 -0
  335. package/docs/content/locales/ja-JP/template-design.mdx +46 -0
  336. package/docs/content/locales/ko-KR/template-design.mdx +44 -0
  337. package/docs/content/locales/pt-BR/template-design.mdx +48 -0
  338. package/docs/content/locales/zh-CN/template-design.mdx +36 -0
  339. package/docs/content/locales/zh-TW/template-design.mdx +38 -0
  340. package/docs/content/template-design.mdx +45 -0
  341. package/package.json +2 -1
  342. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  343. package/corpus/templates/design/app/components/design/DesignToolbar.tsx +0 -339
  344. package/corpus/templates/design/app/components/design/PresentMode.tsx +0 -68
  345. package/corpus/templates/design/app/components/design/ViewportTabs.tsx +0 -149
  346. package/corpus/templates/design/app/components/design/ZoomControls.tsx +0 -157
@@ -0,0 +1,461 @@
1
+ import {
2
+ Select,
3
+ SelectContent,
4
+ SelectItem,
5
+ SelectTrigger,
6
+ SelectValue,
7
+ } from "@/components/ui/select";
8
+ import { cn } from "@/lib/utils";
9
+
10
+ export type HorizontalConstraint =
11
+ | "left"
12
+ | "right"
13
+ | "left-right"
14
+ | "center"
15
+ | "scale";
16
+ export type VerticalConstraint =
17
+ | "top"
18
+ | "bottom"
19
+ | "top-bottom"
20
+ | "center"
21
+ | "scale";
22
+
23
+ export interface ConstraintsValue {
24
+ horizontal: HorizontalConstraint;
25
+ vertical: VerticalConstraint;
26
+ }
27
+
28
+ export interface ConstraintsWidgetLabels {
29
+ title: string;
30
+ horizontal: string;
31
+ vertical: string;
32
+ left: string;
33
+ right: string;
34
+ leftRight: string;
35
+ top: string;
36
+ bottom: string;
37
+ topBottom: string;
38
+ center: string;
39
+ scale: string;
40
+ }
41
+
42
+ export interface ConstraintsWidgetProps {
43
+ value: ConstraintsValue;
44
+ onChange: (value: ConstraintsValue) => void;
45
+ labels?: Partial<ConstraintsWidgetLabels>;
46
+ disabled?: boolean;
47
+ className?: string;
48
+ }
49
+
50
+ const DEFAULT_LABELS: ConstraintsWidgetLabels = {
51
+ title: "Constraints", // i18n-ignore fallback component label
52
+ horizontal: "Horizontal", // i18n-ignore fallback component label
53
+ vertical: "Vertical", // i18n-ignore fallback component label
54
+ left: "Left", // i18n-ignore fallback component label
55
+ right: "Right", // i18n-ignore fallback component label
56
+ leftRight: "Left and right", // i18n-ignore fallback component label
57
+ top: "Top", // i18n-ignore fallback component label
58
+ bottom: "Bottom", // i18n-ignore fallback component label
59
+ topBottom: "Top and bottom", // i18n-ignore fallback component label
60
+ center: "Center", // i18n-ignore fallback component label
61
+ scale: "Scale", // i18n-ignore fallback component label
62
+ };
63
+
64
+ // ── pin-box geometry ────────────────────────────────────────────────────────
65
+ // The preview box is 40×40px (size-10). Inside it sits a 16×16px inner rect
66
+ // (representing the element) centered at (20,20). The four edge pins are thin
67
+ // bars that can be toggled on/off; a center-cross appears for "center" mode.
68
+ //
69
+ // Edge pins: 6px long, 1.5px wide, placed 2px from the box edge.
70
+ // left : x=2..8, y center=20
71
+ // right : x=32..38, y center=20
72
+ // top : x center=20, y=2..8
73
+ // bottom: x center=20, y=32..38
74
+ //
75
+ // Center marker: a 4px dot at (20,20) for h=center or v=center.
76
+
77
+ const BOX = 40; // viewBox width/height (matches size-10 = 40px)
78
+ const INNER = 16; // inner rect size
79
+ const INNER_X = (BOX - INNER) / 2; // 12
80
+ const INNER_Y = (BOX - INNER) / 2; // 12
81
+ const PIN_LEN = 6;
82
+ const PIN_W = 1.5;
83
+ const MARGIN = 2; // gap between box edge and pin start
84
+ const CENTER = BOX / 2; // 20
85
+
86
+ // Returns whether a given horizontal pin should be active.
87
+ function hPinActive(side: "left" | "right", h: HorizontalConstraint): boolean {
88
+ if (side === "left") return h === "left" || h === "left-right";
89
+ return h === "right" || h === "left-right";
90
+ }
91
+
92
+ function vPinActive(side: "top" | "bottom", v: VerticalConstraint): boolean {
93
+ if (side === "top") return v === "top" || v === "top-bottom";
94
+ return v === "bottom" || v === "top-bottom";
95
+ }
96
+
97
+ // Clicking a left/right pin cycles: if that side is the only active one →
98
+ // "left-right"; if "left-right" → single side; if neither → single side.
99
+ function toggleHPin(
100
+ side: "left" | "right",
101
+ current: HorizontalConstraint,
102
+ ): HorizontalConstraint {
103
+ const leftOn = current === "left" || current === "left-right";
104
+ const rightOn = current === "right" || current === "left-right";
105
+ if (side === "left") {
106
+ const nextLeft = !leftOn;
107
+ if (nextLeft && rightOn) return "left-right";
108
+ if (nextLeft) return "left";
109
+ if (rightOn) return "right";
110
+ return "left"; // can't clear both — revert to left
111
+ } else {
112
+ const nextRight = !rightOn;
113
+ if (leftOn && nextRight) return "left-right";
114
+ if (nextRight) return "right";
115
+ if (leftOn) return "left";
116
+ return "right"; // can't clear both — revert to right
117
+ }
118
+ }
119
+
120
+ function toggleVPin(
121
+ side: "top" | "bottom",
122
+ current: VerticalConstraint,
123
+ ): VerticalConstraint {
124
+ const topOn = current === "top" || current === "top-bottom";
125
+ const bottomOn = current === "bottom" || current === "top-bottom";
126
+ if (side === "top") {
127
+ const nextTop = !topOn;
128
+ if (nextTop && bottomOn) return "top-bottom";
129
+ if (nextTop) return "top";
130
+ if (bottomOn) return "bottom";
131
+ return "top";
132
+ } else {
133
+ const nextBottom = !bottomOn;
134
+ if (topOn && nextBottom) return "top-bottom";
135
+ if (nextBottom) return "bottom";
136
+ if (topOn) return "top";
137
+ return "bottom";
138
+ }
139
+ }
140
+
141
+ // ── PinBox SVG ───────────────────────────────────────────────────────────────
142
+
143
+ interface PinBoxProps {
144
+ value: ConstraintsValue;
145
+ disabled: boolean;
146
+ labels: Pick<ConstraintsWidgetLabels, "left" | "right" | "top" | "bottom">;
147
+ onToggleH: (side: "left" | "right") => void;
148
+ onToggleV: (side: "top" | "bottom") => void;
149
+ }
150
+
151
+ function PinBox({
152
+ value,
153
+ disabled,
154
+ labels,
155
+ onToggleH,
156
+ onToggleV,
157
+ }: PinBoxProps) {
158
+ const leftOn = hPinActive("left", value.horizontal);
159
+ const rightOn = hPinActive("right", value.horizontal);
160
+ const topOn = vPinActive("top", value.vertical);
161
+ const bottomOn = vPinActive("bottom", value.vertical);
162
+ const hCenter = value.horizontal === "center";
163
+ const vCenter = value.vertical === "center";
164
+ const hScale = value.horizontal === "scale";
165
+ const vScale = value.vertical === "scale";
166
+
167
+ // Hit-area size for each pin button (larger than the visual stroke for
168
+ // easy clicking — 8×8 centered on the pin midpoint).
169
+ const HIT = 8;
170
+
171
+ return (
172
+ <svg
173
+ width={BOX}
174
+ height={BOX}
175
+ viewBox={`0 0 ${BOX} ${BOX}`}
176
+ aria-hidden="true"
177
+ className={cn(
178
+ "shrink-0 rounded-sm",
179
+ disabled && "pointer-events-none opacity-40",
180
+ )}
181
+ style={{ background: "hsl(var(--muted) / 0.3)" }}
182
+ >
183
+ {/* outer border */}
184
+ <rect
185
+ x={0.75}
186
+ y={0.75}
187
+ width={BOX - 1.5}
188
+ height={BOX - 1.5}
189
+ rx={3}
190
+ fill="none"
191
+ stroke="hsl(var(--border))"
192
+ strokeWidth={1.5}
193
+ />
194
+
195
+ {/* inner element rect */}
196
+ <rect
197
+ x={INNER_X}
198
+ y={INNER_Y}
199
+ width={INNER}
200
+ height={INNER}
201
+ rx={1.5}
202
+ fill="hsl(var(--background))"
203
+ stroke="hsl(var(--foreground) / 0.5)"
204
+ strokeWidth={1}
205
+ />
206
+
207
+ {/* scale dashed overlay */}
208
+ {(hScale || vScale) && (
209
+ <rect
210
+ x={INNER_X + 1}
211
+ y={INNER_Y + 1}
212
+ width={INNER - 2}
213
+ height={INNER - 2}
214
+ rx={1}
215
+ fill="none"
216
+ stroke="hsl(var(--primary) / 0.8)"
217
+ strokeWidth={1}
218
+ strokeDasharray="2 1.5"
219
+ />
220
+ )}
221
+
222
+ {/* center cross for h-center or v-center */}
223
+ {(hCenter || vCenter) && (
224
+ <>
225
+ {hCenter && (
226
+ <line
227
+ x1={INNER_X - 2}
228
+ y1={CENTER}
229
+ x2={INNER_X + INNER + 2}
230
+ y2={CENTER}
231
+ stroke="hsl(var(--primary))"
232
+ strokeWidth={1.5}
233
+ />
234
+ )}
235
+ {vCenter && (
236
+ <line
237
+ x1={CENTER}
238
+ y1={INNER_Y - 2}
239
+ x2={CENTER}
240
+ y2={INNER_Y + INNER + 2}
241
+ stroke="hsl(var(--primary))"
242
+ strokeWidth={1.5}
243
+ />
244
+ )}
245
+ </>
246
+ )}
247
+
248
+ {/* edge pins — visual strokes */}
249
+ {/* left pin */}
250
+ <line
251
+ x1={MARGIN}
252
+ y1={CENTER}
253
+ x2={MARGIN + PIN_LEN}
254
+ y2={CENTER}
255
+ stroke={
256
+ leftOn ? "hsl(var(--primary))" : "hsl(var(--foreground) / 0.35)"
257
+ }
258
+ strokeWidth={PIN_W}
259
+ strokeLinecap="round"
260
+ />
261
+ {/* right pin */}
262
+ <line
263
+ x1={BOX - MARGIN}
264
+ y1={CENTER}
265
+ x2={BOX - MARGIN - PIN_LEN}
266
+ y2={CENTER}
267
+ stroke={
268
+ rightOn ? "hsl(var(--primary))" : "hsl(var(--foreground) / 0.35)"
269
+ }
270
+ strokeWidth={PIN_W}
271
+ strokeLinecap="round"
272
+ />
273
+ {/* top pin */}
274
+ <line
275
+ x1={CENTER}
276
+ y1={MARGIN}
277
+ x2={CENTER}
278
+ y2={MARGIN + PIN_LEN}
279
+ stroke={topOn ? "hsl(var(--primary))" : "hsl(var(--foreground) / 0.35)"}
280
+ strokeWidth={PIN_W}
281
+ strokeLinecap="round"
282
+ />
283
+ {/* bottom pin */}
284
+ <line
285
+ x1={CENTER}
286
+ y1={BOX - MARGIN}
287
+ x2={CENTER}
288
+ y2={BOX - MARGIN - PIN_LEN}
289
+ stroke={
290
+ bottomOn ? "hsl(var(--primary))" : "hsl(var(--foreground) / 0.35)"
291
+ }
292
+ strokeWidth={PIN_W}
293
+ strokeLinecap="round"
294
+ />
295
+
296
+ {/* invisible click targets — rendered on top of strokes */}
297
+ {!disabled && (
298
+ <>
299
+ {/* left pin hit area */}
300
+ <rect
301
+ x={MARGIN - HIT / 2}
302
+ y={CENTER - HIT / 2}
303
+ width={PIN_LEN + HIT}
304
+ height={HIT}
305
+ fill="transparent"
306
+ className="cursor-pointer"
307
+ onClick={() => onToggleH("left")}
308
+ role="button"
309
+ aria-label={labels.left}
310
+ />
311
+ {/* right pin hit area */}
312
+ <rect
313
+ x={BOX - MARGIN - PIN_LEN - HIT / 2}
314
+ y={CENTER - HIT / 2}
315
+ width={PIN_LEN + HIT}
316
+ height={HIT}
317
+ fill="transparent"
318
+ className="cursor-pointer"
319
+ onClick={() => onToggleH("right")}
320
+ role="button"
321
+ aria-label={labels.right}
322
+ />
323
+ {/* top pin hit area */}
324
+ <rect
325
+ x={CENTER - HIT / 2}
326
+ y={MARGIN - HIT / 2}
327
+ width={HIT}
328
+ height={PIN_LEN + HIT}
329
+ fill="transparent"
330
+ className="cursor-pointer"
331
+ onClick={() => onToggleV("top")}
332
+ role="button"
333
+ aria-label={labels.top}
334
+ />
335
+ {/* bottom pin hit area */}
336
+ <rect
337
+ x={CENTER - HIT / 2}
338
+ y={BOX - MARGIN - PIN_LEN - HIT / 2}
339
+ width={HIT}
340
+ height={PIN_LEN + HIT}
341
+ fill="transparent"
342
+ className="cursor-pointer"
343
+ onClick={() => onToggleV("bottom")}
344
+ role="button"
345
+ aria-label={labels.bottom}
346
+ />
347
+ </>
348
+ )}
349
+ </svg>
350
+ );
351
+ }
352
+
353
+ // ── Main widget ──────────────────────────────────────────────────────────────
354
+
355
+ export function ConstraintsWidget({
356
+ value,
357
+ onChange,
358
+ labels,
359
+ disabled = false,
360
+ className,
361
+ }: ConstraintsWidgetProps) {
362
+ const copy = { ...DEFAULT_LABELS, ...labels };
363
+
364
+ function handleToggleH(side: "left" | "right") {
365
+ onChange({ ...value, horizontal: toggleHPin(side, value.horizontal) });
366
+ }
367
+
368
+ function handleToggleV(side: "top" | "bottom") {
369
+ onChange({ ...value, vertical: toggleVPin(side, value.vertical) });
370
+ }
371
+
372
+ return (
373
+ <div className={cn("space-y-1.5", className)}>
374
+ {/* section label */}
375
+ <span className="text-[11px] font-medium text-muted-foreground">
376
+ {copy.title}
377
+ </span>
378
+
379
+ {/* main row: pin-box LEFT + dropdowns RIGHT */}
380
+ <div className="flex items-center gap-2">
381
+ {/* pin box */}
382
+ <PinBox
383
+ value={value}
384
+ disabled={disabled}
385
+ labels={copy}
386
+ onToggleH={handleToggleH}
387
+ onToggleV={handleToggleV}
388
+ />
389
+
390
+ {/* dropdowns column */}
391
+ <div className="flex min-w-0 flex-1 flex-col gap-1">
392
+ {/* horizontal constraint */}
393
+ <Select
394
+ value={value.horizontal}
395
+ onValueChange={(next) =>
396
+ onChange({ ...value, horizontal: next as HorizontalConstraint })
397
+ }
398
+ disabled={disabled}
399
+ >
400
+ <SelectTrigger
401
+ className="h-6 w-full px-1.5 text-[11px]"
402
+ aria-label={copy.horizontal}
403
+ >
404
+ <SelectValue />
405
+ </SelectTrigger>
406
+ <SelectContent>
407
+ <SelectItem value="left" className="text-[11px]">
408
+ {copy.left}
409
+ </SelectItem>
410
+ <SelectItem value="right" className="text-[11px]">
411
+ {copy.right}
412
+ </SelectItem>
413
+ <SelectItem value="left-right" className="text-[11px]">
414
+ {copy.leftRight}
415
+ </SelectItem>
416
+ <SelectItem value="center" className="text-[11px]">
417
+ {copy.center}
418
+ </SelectItem>
419
+ <SelectItem value="scale" className="text-[11px]">
420
+ {copy.scale}
421
+ </SelectItem>
422
+ </SelectContent>
423
+ </Select>
424
+
425
+ {/* vertical constraint */}
426
+ <Select
427
+ value={value.vertical}
428
+ onValueChange={(next) =>
429
+ onChange({ ...value, vertical: next as VerticalConstraint })
430
+ }
431
+ disabled={disabled}
432
+ >
433
+ <SelectTrigger
434
+ className="h-6 w-full px-1.5 text-[11px]"
435
+ aria-label={copy.vertical}
436
+ >
437
+ <SelectValue />
438
+ </SelectTrigger>
439
+ <SelectContent>
440
+ <SelectItem value="top" className="text-[11px]">
441
+ {copy.top}
442
+ </SelectItem>
443
+ <SelectItem value="bottom" className="text-[11px]">
444
+ {copy.bottom}
445
+ </SelectItem>
446
+ <SelectItem value="top-bottom" className="text-[11px]">
447
+ {copy.topBottom}
448
+ </SelectItem>
449
+ <SelectItem value="center" className="text-[11px]">
450
+ {copy.center}
451
+ </SelectItem>
452
+ <SelectItem value="scale" className="text-[11px]">
453
+ {copy.scale}
454
+ </SelectItem>
455
+ </SelectContent>
456
+ </Select>
457
+ </div>
458
+ </div>
459
+ </div>
460
+ );
461
+ }
@@ -0,0 +1,166 @@
1
+ import { IconDownload, IconPlus, IconX } from "@tabler/icons-react";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { Input } from "@/components/ui/input";
5
+ import {
6
+ Select,
7
+ SelectContent,
8
+ SelectGroup,
9
+ SelectItem,
10
+ SelectTrigger,
11
+ SelectValue,
12
+ } from "@/components/ui/select";
13
+ import { cn } from "@/lib/utils";
14
+
15
+ import { ScrubInput } from "./ScrubInput";
16
+
17
+ export type ExportFormat = "png" | "jpg" | "svg" | "pdf";
18
+
19
+ export interface ExportSettingsValue {
20
+ scale: number;
21
+ format: ExportFormat;
22
+ suffix: string;
23
+ }
24
+
25
+ export interface ExportSettingsPanelLabels {
26
+ title: string;
27
+ scale: string;
28
+ format: string;
29
+ suffix: string;
30
+ export: string;
31
+ }
32
+
33
+ export interface ExportSettingsPanelProps {
34
+ value: ExportSettingsValue;
35
+ onChange: (patch: Partial<ExportSettingsValue>) => void;
36
+ onExport: (settings: ExportSettingsValue) => void;
37
+ formats?: ExportFormat[];
38
+ labels?: Partial<ExportSettingsPanelLabels>;
39
+ disabled?: boolean;
40
+ exporting?: boolean;
41
+ className?: string;
42
+ }
43
+
44
+ const DEFAULT_LABELS: ExportSettingsPanelLabels = {
45
+ title: "Export", // i18n-ignore fallback component label
46
+ scale: "Scale", // i18n-ignore fallback component label
47
+ format: "Format", // i18n-ignore fallback component label
48
+ suffix: "Suffix", // i18n-ignore fallback component label
49
+ export: "Export", // i18n-ignore fallback component label
50
+ };
51
+
52
+ const DEFAULT_FORMATS: ExportFormat[] = ["png", "jpg", "svg", "pdf"];
53
+
54
+ export function ExportSettingsPanel({
55
+ value,
56
+ onChange,
57
+ onExport,
58
+ formats = DEFAULT_FORMATS,
59
+ labels,
60
+ disabled = false,
61
+ exporting = false,
62
+ className,
63
+ }: ExportSettingsPanelProps) {
64
+ const copy = { ...DEFAULT_LABELS, ...labels };
65
+ const isDisabled = disabled || exporting;
66
+
67
+ return (
68
+ <div className={cn("space-y-1.5", className)}>
69
+ {/* Section header: title left, "+" right — matches Figma export header */}
70
+ <div className="flex h-6 items-center justify-between">
71
+ <span className="text-[11px] font-medium text-muted-foreground">
72
+ {copy.title}
73
+ </span>
74
+ <button
75
+ type="button"
76
+ aria-label={copy.export}
77
+ disabled={isDisabled}
78
+ className="flex size-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
79
+ onClick={() => {
80
+ /* single-value interface: noop — the setting already exists */
81
+ }}
82
+ >
83
+ <IconPlus className="size-3.5" />
84
+ </button>
85
+ </div>
86
+
87
+ {/* Export row: [scale] [format] [suffix] [×] — Figma compact inline layout */}
88
+ <div className="flex items-center gap-1">
89
+ {/* Scale scrub — compact, no label, unit "x" shown inline */}
90
+ <ScrubInput
91
+ label=""
92
+ value={value.scale}
93
+ onChange={(scale) => onChange({ scale })}
94
+ unit="x"
95
+ min={0.1}
96
+ max={10}
97
+ step={0.5}
98
+ precision={2}
99
+ disabled={isDisabled}
100
+ inputClassName="h-6 w-12 text-[11px]"
101
+ className="shrink-0"
102
+ />
103
+
104
+ {/* Format dropdown */}
105
+ <Select
106
+ value={value.format}
107
+ disabled={isDisabled}
108
+ onValueChange={(format) =>
109
+ onChange({ format: format as ExportFormat })
110
+ }
111
+ >
112
+ <SelectTrigger className="h-6 min-w-0 flex-1 px-1.5 text-[11px]">
113
+ <SelectValue />
114
+ </SelectTrigger>
115
+ <SelectContent>
116
+ <SelectGroup>
117
+ {formats.map((format) => (
118
+ <SelectItem
119
+ key={format}
120
+ value={format}
121
+ className="text-[11px] uppercase"
122
+ >
123
+ {format.toUpperCase()}
124
+ </SelectItem>
125
+ ))}
126
+ </SelectGroup>
127
+ </SelectContent>
128
+ </Select>
129
+
130
+ {/* Suffix input */}
131
+ <Input
132
+ value={value.suffix}
133
+ disabled={isDisabled}
134
+ onChange={(event) => onChange({ suffix: event.target.value })}
135
+ placeholder="@2x"
136
+ className="h-6 min-w-0 flex-1 px-1.5 text-[11px]"
137
+ />
138
+
139
+ {/* Remove row button — matches Figma's × on each export entry */}
140
+ <button
141
+ type="button"
142
+ aria-label={copy.export}
143
+ disabled={isDisabled}
144
+ className="flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
145
+ onClick={() => {
146
+ /* single-value interface: noop */
147
+ }}
148
+ >
149
+ <IconX className="size-3" />
150
+ </button>
151
+ </div>
152
+
153
+ {/* Export button — full width at bottom, Figma style */}
154
+ <Button
155
+ type="button"
156
+ variant="outline"
157
+ disabled={isDisabled}
158
+ onClick={() => onExport(value)}
159
+ className="h-6 w-full px-2 text-[11px]"
160
+ >
161
+ <IconDownload className="size-3.5" />
162
+ {copy.export}
163
+ </Button>
164
+ </div>
165
+ );
166
+ }