@agent-native/core 0.80.11 → 0.81.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 (225) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +47 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/cli/design-connect.ts +419 -19
  5. package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
  6. package/corpus/core/src/client/chat/index.ts +1 -0
  7. package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
  8. package/corpus/core/src/client/chat-view-transition.ts +33 -2
  9. package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
  10. package/corpus/core/src/client/index.ts +1 -0
  11. package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
  12. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
  13. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
  14. package/corpus/core/src/db/client.ts +29 -2
  15. package/corpus/core/src/provider-api/index.ts +29 -0
  16. package/corpus/core/src/server/core-routes-plugin.ts +58 -20
  17. package/corpus/core/src/styles/agent-native.css +54 -0
  18. package/corpus/core/src/usage/store.ts +2 -2
  19. package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
  20. package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
  21. package/corpus/templates/analytics/app/global.css +8 -0
  22. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
  23. package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
  24. package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
  25. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
  26. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
  27. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
  28. package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
  29. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
  33. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
  34. package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
  35. package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
  36. package/corpus/templates/assets/app/global.css +15 -0
  37. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
  38. package/corpus/templates/assets/app/routes/library.tsx +90 -16
  39. package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
  40. package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
  41. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
  42. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
  43. package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
  44. package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
  45. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  46. package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
  47. package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
  48. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
  49. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
  50. package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
  51. package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
  52. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
  53. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
  54. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
  55. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
  56. package/corpus/templates/design/AGENTS.md +27 -0
  57. package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
  58. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
  59. package/corpus/templates/design/actions/apply-component-prop-edit.ts +63 -20
  60. package/corpus/templates/design/actions/apply-motion-edit.ts +67 -69
  61. package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
  62. package/corpus/templates/design/actions/capture-design-state.ts +27 -4
  63. package/corpus/templates/design/actions/connect-localhost.ts +59 -22
  64. package/corpus/templates/design/actions/export-zip.ts +23 -8
  65. package/corpus/templates/design/actions/generate-design.ts +53 -1
  66. package/corpus/templates/design/actions/get-component-details.ts +5 -19
  67. package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
  68. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
  69. package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
  70. package/corpus/templates/design/actions/index-design-tokens.ts +10 -1
  71. package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
  72. package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
  73. package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
  74. package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
  75. package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
  76. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
  77. package/corpus/templates/design/actions/navigate.ts +18 -3
  78. package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
  79. package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
  80. package/corpus/templates/design/actions/provider-api-request.ts +3 -3
  81. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
  82. package/corpus/templates/design/actions/run-design-audit.ts +53 -4
  83. package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
  84. package/corpus/templates/design/actions/view-screen.ts +1 -1
  85. package/corpus/templates/design/actions/write-local-file.ts +213 -0
  86. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +230 -3308
  87. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
  88. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +776 -287
  89. package/corpus/templates/design/app/components/design/EditPanel.tsx +212 -208
  90. package/corpus/templates/design/app/components/design/LayersPanel.tsx +14 -2
  91. package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
  92. package/corpus/templates/design/app/components/design/MotionDock.tsx +235 -266
  93. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +490 -55
  94. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +43 -62
  95. package/corpus/templates/design/app/components/design/StatesPanel.tsx +34 -61
  96. package/corpus/templates/design/app/components/design/TokensPanel.tsx +251 -0
  97. package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
  98. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
  99. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
  100. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
  101. package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
  102. package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
  103. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
  104. package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
  105. package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
  106. package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
  107. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
  108. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
  109. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
  110. package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
  111. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  112. package/corpus/templates/design/app/global.css +7 -0
  113. package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
  114. package/corpus/templates/design/app/i18n/zh-TW.ts +21 -0
  115. package/corpus/templates/design/app/i18n-data.ts +358 -0
  116. package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
  117. package/corpus/templates/design/app/pages/DesignEditor.tsx +2402 -499
  118. package/corpus/templates/design/app/pages/Index.tsx +5 -1
  119. package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
  120. package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
  121. package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
  122. package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
  123. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
  124. package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
  125. package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
  126. package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
  127. package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
  128. package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
  129. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
  130. package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
  131. package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
  132. package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
  133. package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
  134. package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
  135. package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
  136. package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
  137. package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
  138. package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
  139. package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
  140. package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
  141. package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
  142. package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
  143. package/corpus/templates/design/e2e/helpers.ts +168 -65
  144. package/corpus/templates/design/package.json +3 -1
  145. package/corpus/templates/design/server/db/schema.ts +23 -0
  146. package/corpus/templates/design/server/handlers/uploads.ts +22 -1
  147. package/corpus/templates/design/server/lib/provider-api.ts +7 -4
  148. package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
  149. package/corpus/templates/design/server/plugins/db.ts +39 -0
  150. package/corpus/templates/design/server/register-secrets.ts +38 -0
  151. package/corpus/templates/design/shared/board-file.ts +228 -0
  152. package/corpus/templates/design/shared/board-objects.ts +288 -0
  153. package/corpus/templates/design/shared/code-layer.ts +52 -0
  154. package/corpus/templates/design/shared/motion-compiler.ts +58 -7
  155. package/corpus/templates/design/shared/motion-timeline.ts +2 -2
  156. package/corpus/templates/design/tsconfig.json +2 -1
  157. package/corpus/templates/slides/AGENTS.md +9 -0
  158. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
  159. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
  160. package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
  161. package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
  162. package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
  163. package/corpus/templates/slides/app/vite-env.d.ts +18 -0
  164. package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
  165. package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
  166. package/corpus/templates/slides/package.json +1 -0
  167. package/corpus/templates/slides/vite.config.ts +1 -0
  168. package/dist/cli/design-connect.d.ts +25 -0
  169. package/dist/cli/design-connect.d.ts.map +1 -1
  170. package/dist/cli/design-connect.js +357 -18
  171. package/dist/cli/design-connect.js.map +1 -1
  172. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  173. package/dist/client/ConnectBuilderCard.js +1 -0
  174. package/dist/client/ConnectBuilderCard.js.map +1 -1
  175. package/dist/client/chat/index.d.ts +1 -1
  176. package/dist/client/chat/index.d.ts.map +1 -1
  177. package/dist/client/chat/index.js +1 -1
  178. package/dist/client/chat/index.js.map +1 -1
  179. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  180. package/dist/client/chat/run-recovery.js +5 -5
  181. package/dist/client/chat/run-recovery.js.map +1 -1
  182. package/dist/client/chat-view-transition.d.ts +6 -0
  183. package/dist/client/chat-view-transition.d.ts.map +1 -1
  184. package/dist/client/chat-view-transition.js +23 -2
  185. package/dist/client/chat-view-transition.js.map +1 -1
  186. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  187. package/dist/client/composer/PromptComposer.js +3 -2
  188. package/dist/client/composer/PromptComposer.js.map +1 -1
  189. package/dist/client/index.d.ts +1 -1
  190. package/dist/client/index.d.ts.map +1 -1
  191. package/dist/client/index.js +1 -1
  192. package/dist/client/index.js.map +1 -1
  193. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  194. package/dist/client/org/OrgSwitcher.js +11 -4
  195. package/dist/client/org/OrgSwitcher.js.map +1 -1
  196. package/dist/client/sharing/ShareButton.js +3 -3
  197. package/dist/client/sharing/ShareButton.js.map +1 -1
  198. package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
  199. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  200. package/dist/client/use-agent-chat-home-handoff.js +20 -6
  201. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  202. package/dist/collab/awareness.d.ts +2 -2
  203. package/dist/collab/awareness.d.ts.map +1 -1
  204. package/dist/collab/routes.d.ts +2 -2
  205. package/dist/db/client.d.ts +1 -0
  206. package/dist/db/client.d.ts.map +1 -1
  207. package/dist/db/client.js +28 -2
  208. package/dist/db/client.js.map +1 -1
  209. package/dist/notifications/routes.d.ts +3 -3
  210. package/dist/observability/routes.d.ts +2 -2
  211. package/dist/progress/routes.d.ts +1 -1
  212. package/dist/provider-api/index.d.ts +5 -4
  213. package/dist/provider-api/index.d.ts.map +1 -1
  214. package/dist/provider-api/index.js +28 -0
  215. package/dist/provider-api/index.js.map +1 -1
  216. package/dist/resources/handlers.d.ts +3 -3
  217. package/dist/server/core-routes-plugin.d.ts +25 -0
  218. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  219. package/dist/server/core-routes-plugin.js +43 -18
  220. package/dist/server/core-routes-plugin.js.map +1 -1
  221. package/dist/server/transcribe-voice.d.ts +1 -1
  222. package/dist/styles/agent-native.css +54 -0
  223. package/dist/usage/store.js +2 -2
  224. package/dist/usage/store.js.map +1 -1
  225. package/package.json +1 -1
@@ -52,7 +52,6 @@ import {
52
52
  IconLock,
53
53
  IconMaximize,
54
54
  IconMinus,
55
- IconPalette,
56
55
  IconPhoto,
57
56
  IconPlus,
58
57
  IconShadow,
@@ -111,10 +110,6 @@ import {
111
110
  } from "@/components/ui/tooltip";
112
111
  import { cn } from "@/lib/utils";
113
112
 
114
- import {
115
- DesignExtensionsPanel,
116
- type DesignExtensionSlotContext,
117
- } from "./DesignExtensionsPanel";
118
113
  import {
119
114
  AutoLayoutMatrix,
120
115
  ConstraintsWidget,
@@ -143,18 +138,10 @@ import { ReviewPanel } from "./ReviewPanel";
143
138
  import type { ReviewPanelProps } from "./ReviewPanel";
144
139
  import { StatesPanel } from "./StatesPanel";
145
140
  import type { StatesPanelProps } from "./StatesPanel";
146
- import { TokensPanel } from "./TokensPanel";
147
141
  import { TweaksPanelContent } from "./TweaksPanel";
148
142
  import type { ElementInfo } from "./types";
149
143
 
150
- export type InspectorTab = "design" | "tweaks" | "extensions";
151
-
152
- /**
153
- * Sub-tab within the Tweaks area: "tokens" = TokensPanel face (CSS-var
154
- * editing through the Tweaks loop); "tweaks" = raw TweakDefinition controls.
155
- * Defaults to "tokens" when a designId is provided, otherwise "tweaks".
156
- */
157
- type TweaksSubTab = "tokens" | "tweaks";
144
+ export type InspectorTab = "design" | "tweaks";
158
145
 
159
146
  interface EditPanelProps {
160
147
  selectedElement: ElementInfo | null;
@@ -166,7 +153,6 @@ interface EditPanelProps {
166
153
  onActiveTabChange?: (tab: InspectorTab) => void;
167
154
  tweaks?: TweakDefinition[];
168
155
  tweakValues?: Record<string, string | number | boolean>;
169
- extensionContext?: DesignExtensionSlotContext;
170
156
  onTweakChange?: (id: string, value: string | number | boolean) => void;
171
157
  onRequestTweaks?: (anchor: HTMLElement) => void;
172
158
  onStyleChange: (property: string, value: string) => void;
@@ -182,6 +168,10 @@ interface EditPanelProps {
182
168
  fileId?: string;
183
169
  /** Active file name (e.g. "index.html") — forwarded to InspectorAiActions. */
184
170
  filename?: string;
171
+ /** Latest active file HTML, used to compose rapid sequential source edits. */
172
+ activeContent?: string;
173
+ /** Server revision for activeContent. */
174
+ activeFileUpdatedAt?: string | null;
185
175
  // -------------------------------------------------------------------------
186
176
  // Design Studio panels (§6.2, §6.4, §6.5)
187
177
  // Pass `designId` to unlock Tokens, States, and Review sections.
@@ -192,7 +182,11 @@ interface EditPanelProps {
192
182
  * Called after a component prop edit returns the patched source so the parent
193
183
  * editor can sync local/Yjs content instead of waiting for query invalidation.
194
184
  */
195
- onComponentPropApplied?: (fileId: string, content: string) => void;
185
+ onComponentPropApplied?: (
186
+ fileId: string,
187
+ content: string,
188
+ updatedAt?: string,
189
+ ) => void;
196
190
  /**
197
191
  * Called after a token edit is applied so the parent can push the resolved
198
192
  * CSS-var map into the iframe via the tweak-values postMessage.
@@ -362,6 +356,9 @@ function ColorInput({
362
356
  value,
363
357
  onChange,
364
358
  backgroundImage,
359
+ backgroundSize,
360
+ backgroundRepeat,
361
+ backgroundPosition,
365
362
  onBackgroundImageChange,
366
363
  onImageFillChange,
367
364
  blendMode,
@@ -374,6 +371,9 @@ function ColorInput({
374
371
  value: string;
375
372
  onChange: (value: string) => void;
376
373
  backgroundImage?: string;
374
+ backgroundSize?: string;
375
+ backgroundRepeat?: string;
376
+ backgroundPosition?: string;
377
377
  onBackgroundImageChange?: (value: string) => void;
378
378
  onImageFillChange?: (value: ImageFillValue) => void;
379
379
  blendMode?: string;
@@ -392,6 +392,9 @@ function ColorInput({
392
392
  }, [value]);
393
393
 
394
394
  const backgroundLayers = splitCssLayers(backgroundImage || "");
395
+ const backgroundSizeLayers = splitCssLayers(backgroundSize || "");
396
+ const backgroundRepeatLayers = splitCssLayers(backgroundRepeat || "");
397
+ const backgroundPositionLayers = splitCssLayers(backgroundPosition || "");
395
398
  const selectedLayerIndex = fillLayerIndex(selectedFillId);
396
399
  const selectedGradient =
397
400
  selectedLayerIndex !== null
@@ -626,6 +629,8 @@ function ColorInput({
626
629
  selectedLayerIndex !== null
627
630
  ? (backgroundLayers[selectedLayerIndex] ?? draft ?? value ?? "#000000")
628
631
  : draft || "#000000";
632
+ const selectedBackgroundLayerValue = (layers: string[]): string | undefined =>
633
+ selectedLayerIndex !== null ? layers[selectedLayerIndex] : undefined;
629
634
  const handlePaintTypeChange = (type: DesignPaintType) => {
630
635
  const selectedLayer = fillLayerIndex(selectedFillId);
631
636
  if (type === "solid") {
@@ -686,6 +691,12 @@ function ColorInput({
686
691
  supportsLayeredFills ? handlePaintValueChange : undefined
687
692
  }
688
693
  onImageFillChange={onImageFillChange}
694
+ backgroundImage={selectedBackgroundLayerValue(backgroundLayers)}
695
+ backgroundSize={selectedBackgroundLayerValue(backgroundSizeLayers)}
696
+ backgroundRepeat={selectedBackgroundLayerValue(backgroundRepeatLayers)}
697
+ backgroundPosition={selectedBackgroundLayerValue(
698
+ backgroundPositionLayers,
699
+ )}
689
700
  blendMode={blendMode}
690
701
  onBlendModeChange={onBlendModeChange}
691
702
  showBlendMode={Boolean(onBlendModeChange)}
@@ -2663,12 +2674,6 @@ function InspectorTabsHeader({
2663
2674
  >
2664
2675
  {t("designEditor.tweaks")}
2665
2676
  </TabsTrigger>
2666
- <TabsTrigger
2667
- value="extensions"
2668
- className="h-6 rounded-md px-1.5 text-[11px] font-semibold text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-[var(--design-editor-panel-raised-bg)] data-[state=active]:text-foreground data-[state=active]:shadow-none"
2669
- >
2670
- {t("designEditor.extensions")}
2671
- </TabsTrigger>
2672
2677
  </TabsList>
2673
2678
  </Tabs>
2674
2679
  {trailing ? <div className="shrink-0">{trailing}</div> : null}
@@ -2680,15 +2685,19 @@ function SectionIconButton({
2680
2685
  label,
2681
2686
  onClick,
2682
2687
  children,
2688
+ activateOnPointerDown = false,
2683
2689
  disabled = false,
2684
2690
  className,
2685
2691
  }: {
2686
2692
  label: string;
2687
2693
  onClick?: () => void;
2688
2694
  children: ReactNode;
2695
+ activateOnPointerDown?: boolean;
2689
2696
  disabled?: boolean;
2690
2697
  className?: string;
2691
2698
  }) {
2699
+ const pointerActivatedRef = useRef(false);
2700
+
2692
2701
  return (
2693
2702
  <Tooltip>
2694
2703
  <TooltipTrigger asChild>
@@ -2701,7 +2710,22 @@ function SectionIconButton({
2701
2710
  className,
2702
2711
  )}
2703
2712
  disabled={disabled}
2704
- onClick={onClick}
2713
+ onPointerDown={(event) => {
2714
+ if (!activateOnPointerDown || disabled || event.button !== 0) {
2715
+ return;
2716
+ }
2717
+ pointerActivatedRef.current = true;
2718
+ event.preventDefault();
2719
+ event.stopPropagation();
2720
+ onClick?.();
2721
+ }}
2722
+ onClick={() => {
2723
+ if (pointerActivatedRef.current) {
2724
+ pointerActivatedRef.current = false;
2725
+ return;
2726
+ }
2727
+ onClick?.();
2728
+ }}
2705
2729
  aria-label={label}
2706
2730
  >
2707
2731
  {children}
@@ -3396,7 +3420,10 @@ function PageProperties({
3396
3420
  label={t("editPanel.labels.background")}
3397
3421
  value={styles.backgroundColor || ""}
3398
3422
  onChange={(v) => onStyleChange("backgroundColor", v)}
3399
- backgroundImage={styles.backgroundImage || ""}
3423
+ backgroundImage={styles.backgroundImage}
3424
+ backgroundSize={styles.backgroundSize}
3425
+ backgroundRepeat={styles.backgroundRepeat}
3426
+ backgroundPosition={styles.backgroundPosition}
3400
3427
  onBackgroundImageChange={(v) => onStyleChange("backgroundImage", v)}
3401
3428
  onImageFillChange={(value) =>
3402
3429
  commitStylePatch(
@@ -4533,6 +4560,15 @@ function FillProperties({
4533
4560
  const backgroundLayers = isTextElement
4534
4561
  ? []
4535
4562
  : splitCssLayers(styles.backgroundImage || "");
4563
+ const backgroundSizeLayers = isTextElement
4564
+ ? []
4565
+ : splitCssLayers(styles.backgroundSize || "");
4566
+ const backgroundRepeatLayers = isTextElement
4567
+ ? []
4568
+ : splitCssLayers(styles.backgroundRepeat || "");
4569
+ const backgroundPositionLayers = isTextElement
4570
+ ? []
4571
+ : splitCssLayers(styles.backgroundPosition || "");
4536
4572
  const hasBackgroundLayer = !isTextElement && backgroundLayers.length > 0;
4537
4573
  const hasVisibleFill =
4538
4574
  isTextElement || colorHasVisibleAlpha(fillValue) || hasBackgroundLayer;
@@ -4671,6 +4707,7 @@ function FillProperties({
4671
4707
  : t("editPanel.labels.hideLayer")
4672
4708
  }
4673
4709
  onClick={handleFillVisibilityToggle}
4710
+ activateOnPointerDown
4674
4711
  >
4675
4712
  {isHidden ? (
4676
4713
  <IconEyeOff className="size-3.5" />
@@ -4785,6 +4822,10 @@ function FillProperties({
4785
4822
  );
4786
4823
  }}
4787
4824
  paintType={gradient?.type ?? "image"}
4825
+ backgroundImage={layer}
4826
+ backgroundSize={backgroundSizeLayers[index]}
4827
+ backgroundRepeat={backgroundRepeatLayers[index]}
4828
+ backgroundPosition={backgroundPositionLayers[index]}
4788
4829
  gradientType={gradient?.type}
4789
4830
  onGradientTypeChange={(type) => {
4790
4831
  if (!gradient) return;
@@ -5529,8 +5570,8 @@ function MakeItRealCard({
5529
5570
  // height so the inspector doesn't jump when the data arrives.
5530
5571
  if (isLoading || !data) {
5531
5572
  return (
5532
- <div className="rounded-md border border-dashed border-[var(--design-editor-accent-color)]/20 bg-[var(--design-editor-accent-color)]/3 px-2.5 py-2">
5533
- <div className="h-3 w-32 animate-pulse rounded bg-muted/40" />
5573
+ <div className="flex h-7 items-center rounded-[5px] bg-[var(--design-editor-control-bg)] px-2">
5574
+ <div className="h-3 w-28 animate-pulse rounded bg-muted/40" />
5534
5575
  </div>
5535
5576
  );
5536
5577
  }
@@ -5575,85 +5616,86 @@ function MakeItRealCard({
5575
5616
 
5576
5617
  if (migrateResult?.status === "processing" && migrateResult.url) {
5577
5618
  return (
5578
- <div className="rounded-md border border-[var(--design-editor-accent-color)]/30 bg-[var(--design-editor-accent-color)]/8 px-2.5 py-2 space-y-1.5">
5579
- <p className="text-[10px] font-semibold text-[var(--design-editor-accent-color)]">
5580
- {"Builder is working on it" /* i18n-ignore make-it-real card */}
5581
- </p>
5582
- <p className="text-[10px] leading-snug text-muted-foreground">
5619
+ <div className="flex items-center gap-2 rounded-[5px] border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-2 py-1.5">
5620
+ <IconLoader2 className="size-3.5 shrink-0 animate-spin text-[var(--design-editor-accent-color)]" />
5621
+ <p className="min-w-0 flex-1 truncate text-[10px] text-muted-foreground">
5583
5622
  {migrateResult.message ??
5584
- `Branch "${migrateResult.branchName}" is being generated.`}
5623
+ `Generating ${migrateResult.branchName ?? "React app"}.`}
5585
5624
  </p>
5586
5625
  <a
5587
5626
  href={migrateResult.url}
5588
5627
  target="_blank"
5589
5628
  rel="noopener noreferrer"
5590
- className="inline-flex items-center gap-1 text-[10px] font-medium text-[var(--design-editor-accent-color)] hover:underline"
5629
+ 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)]"
5591
5630
  >
5592
- {"Open in Builder" /* i18n-ignore make-it-real card */}
5631
+ {"Open" /* i18n-ignore make-it-real card */}
5593
5632
  <IconExternalLink className="size-2.5" />
5594
5633
  </a>
5595
5634
  </div>
5596
5635
  );
5597
5636
  }
5598
5637
 
5599
- return (
5600
- <div className="rounded-md border border-dashed border-[var(--design-editor-accent-color)]/30 bg-[var(--design-editor-accent-color)]/5 px-2.5 py-2 space-y-1.5">
5601
- {/* Header */}
5602
- <p className="text-[10px] font-semibold text-foreground">
5603
- {"Make this a real app" /* i18n-ignore make-it-real card */}
5604
- </p>
5605
-
5606
- {/* Body */}
5607
- <p className="text-[10px] leading-snug text-muted-foreground">
5608
- {cta.description}
5609
- {featureLabel ? (
5610
- <>
5611
- {" "}
5612
- <span className="italic">{featureLabel}</span>
5613
- {" requires a real-app source."}
5614
- </>
5615
- ) : null}
5616
- </p>
5638
+ const summary =
5639
+ cta.kind === "configure-project"
5640
+ ? `Configure Builder to enable ${featureLabel}.`
5641
+ : `Connect Builder to enable ${featureLabel}.`;
5642
+ const primaryLabel =
5643
+ cta.kind === "configure-project"
5644
+ ? "Configure" /* i18n-ignore make-it-real card */
5645
+ : "Connect"; /* i18n-ignore make-it-real card */
5617
5646
 
5618
- {/* Error */}
5619
- {migrateError ? (
5620
- <p className="text-[10px] text-destructive">
5621
- {migrateError instanceof Error
5622
- ? migrateError.message
5623
- : "Migration failed. Please try again."}
5647
+ return (
5648
+ <div className="space-y-1">
5649
+ <div className="flex items-center gap-2 rounded-[5px] border border-dashed border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)]/70 px-2 py-1.5">
5650
+ <span
5651
+ className="size-1.5 shrink-0 rounded-full bg-[var(--design-editor-accent-color)]"
5652
+ aria-hidden="true"
5653
+ />
5654
+ <p
5655
+ className="min-w-0 flex-1 truncate text-[10px] text-muted-foreground"
5656
+ title={summary}
5657
+ >
5658
+ {summary}
5624
5659
  </p>
5625
- ) : null}
5626
-
5627
- {/* Actions */}
5628
- <div className="flex items-center gap-1.5 flex-wrap">
5629
- <button
5660
+ <Button
5630
5661
  type="button"
5662
+ size="sm"
5631
5663
  onClick={handlePrimary}
5632
- className="inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium bg-[var(--design-editor-accent-color)] text-white hover:opacity-90 transition-opacity"
5664
+ title={cta.primaryAction}
5665
+ className="h-6 shrink-0 gap-1 rounded-md bg-[var(--design-editor-accent-color)] px-1.5 text-[10px] font-semibold text-white hover:bg-[var(--design-editor-accent-hover-color)]"
5633
5666
  >
5634
- {cta.primaryAction}
5667
+ {primaryLabel}
5635
5668
  <IconArrowRight className="size-2.5" />
5636
- </button>
5669
+ </Button>
5637
5670
 
5638
5671
  {/* When Builder is fully connected, also offer direct migration */}
5639
5672
  {data.connected && data.builderEnabled && (
5640
- <button
5673
+ <Button
5641
5674
  type="button"
5675
+ variant="ghost"
5676
+ size="sm"
5642
5677
  onClick={handleMigrate}
5643
5678
  disabled={isPending}
5644
- className="inline-flex items-center gap-1 rounded border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground transition-colors disabled:cursor-wait disabled:opacity-60"
5679
+ className="h-6 shrink-0 gap-1 rounded-md px-1.5 text-[10px] font-semibold text-muted-foreground hover:text-foreground disabled:cursor-wait disabled:opacity-60"
5645
5680
  >
5646
5681
  {isPending ? (
5647
5682
  <>
5648
5683
  <IconLoader2 className="size-2.5 animate-spin" />
5649
- {"Migrating…" /* i18n-ignore make-it-real card */}
5684
+ {"Generating" /* i18n-ignore make-it-real card */}
5650
5685
  </>
5651
5686
  ) : (
5652
- <>{"Generate React app" /* i18n-ignore make-it-real card */}</>
5687
+ <>{"Generate" /* i18n-ignore make-it-real card */}</>
5653
5688
  )}
5654
- </button>
5689
+ </Button>
5655
5690
  )}
5656
5691
  </div>
5692
+ {migrateError ? (
5693
+ <p className="px-2 text-[10px] text-destructive">
5694
+ {migrateError instanceof Error
5695
+ ? migrateError.message
5696
+ : "Migration failed. Please try again."}
5697
+ </p>
5698
+ ) : null}
5657
5699
  </div>
5658
5700
  );
5659
5701
  }
@@ -5702,20 +5744,42 @@ interface ComponentDetailsResult {
5702
5744
  export function ComponentSection({
5703
5745
  designId,
5704
5746
  fileId,
5747
+ activeContent,
5748
+ activeFileUpdatedAt,
5705
5749
  nodeId,
5706
5750
  onComponentPropApplied,
5707
5751
  sourceCapabilities = [],
5708
5752
  }: {
5709
5753
  designId: string;
5710
5754
  fileId?: string;
5755
+ activeContent?: string;
5756
+ activeFileUpdatedAt?: string | null;
5711
5757
  nodeId: string;
5712
- onComponentPropApplied?: (fileId: string, content: string) => void;
5758
+ onComponentPropApplied?: (
5759
+ fileId: string,
5760
+ content: string,
5761
+ updatedAt?: string,
5762
+ ) => void;
5713
5763
  /** Capability names advertised by the current source. */
5714
5764
  sourceCapabilities?: string[];
5715
5765
  }) {
5716
5766
  const queryClient = useQueryClient();
5717
5767
  const detailsParams = { designId, nodeId, ...(fileId ? { fileId } : {}) };
5718
5768
  const detailsKey = ["action", "get-component-details", detailsParams];
5769
+ const latestSourceRef = useRef<{
5770
+ content: string;
5771
+ revision?: string | null;
5772
+ }>({
5773
+ content: activeContent ?? "",
5774
+ revision: activeFileUpdatedAt ?? null,
5775
+ });
5776
+
5777
+ useEffect(() => {
5778
+ latestSourceRef.current = {
5779
+ content: activeContent ?? "",
5780
+ revision: activeFileUpdatedAt ?? null,
5781
+ };
5782
+ }, [activeContent, activeFileUpdatedAt, fileId, nodeId]);
5719
5783
 
5720
5784
  const { data, isLoading, error, refetch } =
5721
5785
  useActionQuery<ComponentDetailsResult>(
@@ -5762,19 +5826,58 @@ export function ComponentSection({
5762
5826
  if (edit.kind === "attribute") {
5763
5827
  postComponentPropPreview(edit.attribute, edit.value);
5764
5828
  }
5829
+ const latestSource = latestSourceRef.current;
5765
5830
  applyPropMutation.mutate(
5766
- { designId, nodeId, ...(fileId ? { fileId } : {}), edit },
5831
+ {
5832
+ designId,
5833
+ nodeId,
5834
+ ...(fileId ? { fileId } : {}),
5835
+ edit,
5836
+ ...(latestSource.content
5837
+ ? {
5838
+ source: {
5839
+ currentContent: latestSource.content,
5840
+ ...(latestSource.revision
5841
+ ? { revision: latestSource.revision }
5842
+ : {}),
5843
+ },
5844
+ }
5845
+ : {}),
5846
+ },
5767
5847
  {
5768
5848
  onSuccess: (result) => {
5769
5849
  const response = result as {
5770
5850
  content?: unknown;
5771
5851
  fileId?: unknown;
5852
+ updatedAt?: unknown;
5853
+ conflict?: unknown;
5854
+ error?: unknown;
5772
5855
  };
5856
+ if (response.conflict) {
5857
+ toast.error(
5858
+ typeof response.error === "string"
5859
+ ? response.error
5860
+ : "This file changed since this component prop edit was prepared. Refresh and try again.",
5861
+ );
5862
+ return;
5863
+ }
5773
5864
  if (
5774
5865
  typeof response.fileId === "string" &&
5775
5866
  typeof response.content === "string"
5776
5867
  ) {
5777
- onComponentPropApplied?.(response.fileId, response.content);
5868
+ const updatedAt =
5869
+ typeof response.updatedAt === "string"
5870
+ ? response.updatedAt
5871
+ : undefined;
5872
+ latestSourceRef.current = {
5873
+ content: response.content,
5874
+ revision: updatedAt ?? latestSourceRef.current.revision,
5875
+ };
5876
+ onComponentPropApplied?.(
5877
+ response.fileId,
5878
+ response.content,
5879
+ updatedAt,
5880
+ );
5778
5881
  }
5779
5882
  },
5780
5883
  onSettled: () => {
@@ -6136,7 +6239,6 @@ export function EditPanel({
6136
6239
  onActiveTabChange,
6137
6240
  tweaks = [],
6138
6241
  tweakValues = {},
6139
- extensionContext,
6140
6242
  onTweakChange,
6141
6243
  onRequestTweaks,
6142
6244
  onStyleChange,
@@ -6147,9 +6249,10 @@ export function EditPanel({
6147
6249
  readOnly = false,
6148
6250
  fileId,
6149
6251
  filename,
6252
+ activeContent,
6253
+ activeFileUpdatedAt,
6150
6254
  designId,
6151
6255
  onComponentPropApplied,
6152
- onTokensApplied,
6153
6256
  statesPanelProps,
6154
6257
  reviewPanelProps,
6155
6258
  componentNodeId,
@@ -6164,12 +6267,6 @@ export function EditPanel({
6164
6267
  DEFAULT_EXPORT_SETTINGS,
6165
6268
  );
6166
6269
  const [showExportPreview, setShowExportPreview] = useState(false);
6167
- // Sub-tab within the Tweaks area: "tokens" (TokensPanel face) or "tweaks"
6168
- // (raw TweakDefinition controls). Always default to the existing "tweaks"
6169
- // controls so opening Tweaks lands on the user's TweakDefinition controls
6170
- // (and the + affordance) rather than auto-firing token indexing. "Tokens"
6171
- // remains available as a sub-tab the user can click when designId is set.
6172
- const [tweaksSubTab, setTweaksSubTab] = useState<TweaksSubTab>("tweaks");
6173
6270
 
6174
6271
  const selectedElementKey = selectedElement
6175
6272
  ? elementIdentityKey(selectedElement)
@@ -6187,12 +6284,8 @@ export function EditPanel({
6187
6284
  },
6188
6285
  [onTweakChange],
6189
6286
  );
6190
- // The "Add Tweaks" (+) flow lives only on the "tweaks" sub-tab. Switch to it
6191
- // before opening the prompt so the + button and the newly added control are
6192
- // visible (avoids leaving the user on the Tokens sub-tab where + isn't shown).
6193
6287
  const handleRequestTweaks = useCallback(
6194
6288
  (anchor: HTMLElement) => {
6195
- setTweaksSubTab("tweaks");
6196
6289
  onRequestTweaks?.(anchor);
6197
6290
  },
6198
6291
  [onRequestTweaks],
@@ -6367,6 +6460,8 @@ export function EditPanel({
6367
6460
  <ComponentSection
6368
6461
  designId={designId}
6369
6462
  fileId={fileId}
6463
+ activeContent={activeContent}
6464
+ activeFileUpdatedAt={activeFileUpdatedAt}
6370
6465
  nodeId={componentNodeId}
6371
6466
  onComponentPropApplied={onComponentPropApplied}
6372
6467
  sourceCapabilities={sourceCapabilities}
@@ -6557,132 +6652,41 @@ export function EditPanel({
6557
6652
  </>
6558
6653
  ) : activeTab === "tweaks" ? (
6559
6654
  <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
6560
- {/* Tweaks tab header: when designId is present show a Tokens | Tweaks
6561
- sub-tab switcher so the TokensPanel is the first-class face of
6562
- this area per §6.2. When there is no designId only the raw tweaks
6563
- title is shown (original behaviour). */}
6564
- {designId ? (
6565
- <div className="flex h-9 shrink-0 items-center gap-0.5 border-b border-border/90 px-2">
6566
- <Button
6567
- type="button"
6568
- variant="ghost"
6569
- size="sm"
6570
- className={cn(
6571
- "h-6 rounded-md px-2 text-[11px] font-semibold text-muted-foreground transition-colors hover:text-foreground",
6572
- tweaksSubTab === "tokens" &&
6573
- "bg-[var(--design-editor-panel-raised-bg)] text-foreground",
6574
- )}
6575
- onClick={() => setTweaksSubTab("tokens")}
6576
- >
6577
- <IconPalette className="mr-1 size-3" />
6578
- {"Tokens" /* i18n-ignore design inspector sub-tab */}
6579
- </Button>
6580
- <Button
6581
- type="button"
6582
- variant="ghost"
6583
- size="sm"
6584
- className={cn(
6585
- "h-6 rounded-md px-2 text-[11px] font-semibold text-muted-foreground transition-colors hover:text-foreground",
6586
- tweaksSubTab === "tweaks" &&
6587
- "bg-[var(--design-editor-panel-raised-bg)] text-foreground",
6588
- )}
6589
- onClick={() => setTweaksSubTab("tweaks")}
6590
- >
6591
- {t("designEditor.tweaks")}
6592
- </Button>
6593
- </div>
6594
- ) : (
6595
- <div className="flex h-10 shrink-0 items-center justify-between gap-2 border-b border-border/90 px-3">
6596
- <h3 className="min-w-0 flex-1 truncate text-[13px] font-semibold text-foreground">
6597
- {t("designEditor.tweaks")}
6598
- </h3>
6599
- {onRequestTweaks ? (
6600
- <Tooltip>
6601
- <TooltipTrigger asChild>
6602
- <Button
6603
- type="button"
6604
- variant="ghost"
6605
- size="icon"
6606
- className="size-7 rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground"
6607
- aria-label={t("designEditor.addTweaks")}
6608
- onClick={(event) =>
6609
- handleRequestTweaks(event.currentTarget)
6610
- }
6611
- >
6612
- <IconPlus className="size-3.5" />
6613
- </Button>
6614
- </TooltipTrigger>
6615
- <TooltipContent>{t("designEditor.addTweaks")}</TooltipContent>
6616
- </Tooltip>
6617
- ) : null}
6618
- </div>
6619
- )}
6655
+ <div className="flex h-10 shrink-0 items-center justify-between gap-2 border-b border-border/90 px-3">
6656
+ <h3 className="min-w-0 flex-1 truncate text-[13px] font-semibold text-foreground">
6657
+ {t("designEditor.tweaks")}
6658
+ </h3>
6659
+ {onRequestTweaks ? (
6660
+ <Tooltip>
6661
+ <TooltipTrigger asChild>
6662
+ <Button
6663
+ type="button"
6664
+ variant="ghost"
6665
+ size="icon"
6666
+ className="size-7 rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground"
6667
+ aria-label={t("designEditor.addTweaks")}
6668
+ onClick={(event) =>
6669
+ handleRequestTweaks(event.currentTarget)
6670
+ }
6671
+ >
6672
+ <IconPlus className="size-3.5" />
6673
+ </Button>
6674
+ </TooltipTrigger>
6675
+ <TooltipContent>{t("designEditor.addTweaks")}</TooltipContent>
6676
+ </Tooltip>
6677
+ ) : null}
6678
+ </div>
6620
6679
 
6621
6680
  <div className="design-inspector-scroll min-h-0 flex-1 overflow-y-auto overscroll-contain">
6622
- {designId && tweaksSubTab === "tokens" ? (
6623
- /* §6.2 Tokens face — first-class view of the Tweaks area.
6624
- TokensPanel calls apply-design-token-edit which routes through
6625
- the Tweaks loop (designs.data.tweakSelections persist). */
6626
- <>
6627
- <TokensPanel
6628
- designId={designId}
6629
- onTokensApplied={onTokensApplied}
6630
- />
6631
- {/* §5 / §6.6 — token write-back to source is a real-app
6632
- capability. On inline sources (sourceCapabilities lacks
6633
- "writeFile") show a compact "Make it real" CTA after the
6634
- token list so the user knows write-back is one step away. */}
6635
- {!sourceCapabilities.includes("writeFile") && (
6636
- <div className="px-3 pb-3 pt-1">
6637
- <MakeItRealCard
6638
- designId={designId}
6639
- featureLabel="token write-back to source files"
6640
- />
6641
- </div>
6642
- )}
6643
- </>
6644
- ) : (
6645
- /* Raw TweakDefinition controls — shown when no designId, or when
6646
- the user switches to the Tweaks sub-tab. */
6647
- <>
6648
- {designId && onRequestTweaks ? (
6649
- /* When in sub-tab mode, show the add-tweaks action in the
6650
- scrollable content area above the raw controls. */
6651
- <div className="flex items-center justify-end px-3 pt-2">
6652
- <Tooltip>
6653
- <TooltipTrigger asChild>
6654
- <Button
6655
- type="button"
6656
- variant="ghost"
6657
- size="icon"
6658
- className="size-7 rounded-sm text-muted-foreground hover:bg-accent hover:text-foreground"
6659
- aria-label={t("designEditor.addTweaks")}
6660
- onClick={(event) =>
6661
- handleRequestTweaks(event.currentTarget)
6662
- }
6663
- >
6664
- <IconPlus className="size-3.5" />
6665
- </Button>
6666
- </TooltipTrigger>
6667
- <TooltipContent>
6668
- {t("designEditor.addTweaks")}
6669
- </TooltipContent>
6670
- </Tooltip>
6671
- </div>
6672
- ) : null}
6673
- <TweaksPanelContent
6674
- tweaks={tweaks}
6675
- values={tweakValues}
6676
- onChange={handleTweakChange}
6677
- onRequestTweaks={!designId ? handleRequestTweaks : undefined}
6678
- className="px-3 py-3"
6679
- />
6680
- </>
6681
- )}
6681
+ <TweaksPanelContent
6682
+ tweaks={tweaks}
6683
+ values={tweakValues}
6684
+ onChange={handleTweakChange}
6685
+ onRequestTweaks={handleRequestTweaks}
6686
+ className="px-3 py-3"
6687
+ />
6682
6688
  </div>
6683
6689
  </div>
6684
- ) : extensionContext ? (
6685
- <DesignExtensionsPanel context={extensionContext} />
6686
6690
  ) : null}
6687
6691
  </div>
6688
6692
  );