@agent-native/core 0.90.1 → 0.90.2

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 (295) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  5. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
  6. package/corpus/core/src/client/use-action.ts +39 -2
  7. package/corpus/core/src/client/use-db-sync.ts +44 -18
  8. package/corpus/core/src/db/create-get-db.ts +32 -2
  9. package/corpus/core/src/server/framework-request-handler.ts +52 -4
  10. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
  11. package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
  12. package/corpus/templates/assets/AGENTS.md +23 -4
  13. package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
  14. package/corpus/templates/assets/actions/_helpers.ts +8 -1
  15. package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
  16. package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
  17. package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
  18. package/corpus/templates/assets/actions/generate-image.ts +342 -25
  19. package/corpus/templates/assets/actions/get-library.ts +4 -3
  20. package/corpus/templates/assets/actions/navigate.ts +2 -1
  21. package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
  22. package/corpus/templates/assets/actions/update-asset.ts +1 -0
  23. package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
  24. package/corpus/templates/assets/actions/view-screen.ts +8 -1
  25. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
  26. package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
  27. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
  28. package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
  29. package/corpus/templates/assets/app/i18n-data.ts +650 -0
  30. package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
  31. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
  32. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
  33. package/corpus/templates/assets/app/routes/library.tsx +43 -1
  34. package/corpus/templates/assets/server/lib/generation.ts +366 -44
  35. package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
  36. package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
  37. package/corpus/templates/assets/shared/api.ts +47 -0
  38. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
  39. package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
  40. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
  41. package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
  42. package/corpus/templates/clips/app/routes/record.tsx +157 -68
  43. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
  44. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
  45. package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
  46. package/corpus/templates/content/AGENTS.md +52 -52
  47. package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
  48. package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
  49. package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
  50. package/corpus/templates/content/actions/_database-utils.ts +44 -4
  51. package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
  52. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
  53. package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
  54. package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
  55. package/corpus/templates/content/actions/delete-content-database.ts +1 -0
  56. package/corpus/templates/content/actions/get-document.ts +11 -2
  57. package/corpus/templates/content/actions/list-content-databases.ts +57 -9
  58. package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
  59. package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
  60. package/corpus/templates/content/actions/restore-content-database.ts +1 -0
  61. package/corpus/templates/content/actions/update-document.ts +43 -0
  62. package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
  63. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
  64. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
  65. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
  66. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
  67. package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
  68. package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
  69. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
  70. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
  71. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
  72. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
  73. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
  74. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
  75. package/corpus/templates/content/app/global.css +41 -0
  76. package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
  77. package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
  78. package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
  79. package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
  80. package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
  81. package/corpus/templates/content/app/i18n-data.ts +355 -0
  82. package/corpus/templates/content/app/root.tsx +22 -0
  83. package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
  84. package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
  85. package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
  86. package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
  87. package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
  88. package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
  89. package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
  90. package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
  91. package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
  92. package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
  93. package/corpus/templates/content/shared/api.ts +13 -0
  94. package/corpus/templates/content/shared/builder-mdx.ts +16 -3
  95. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
  96. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
  97. package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
  98. package/corpus/templates/design/AGENTS.md +9 -2
  99. package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
  100. package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
  101. package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
  102. package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
  103. package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
  104. package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
  105. package/corpus/templates/design/actions/create-component.ts +29 -60
  106. package/corpus/templates/design/actions/create-file.ts +9 -2
  107. package/corpus/templates/design/actions/duplicate-design.ts +31 -2
  108. package/corpus/templates/design/actions/edit-design.ts +36 -38
  109. package/corpus/templates/design/actions/generate-design-title.ts +87 -0
  110. package/corpus/templates/design/actions/generate-design.ts +53 -18
  111. package/corpus/templates/design/actions/generate-screens.ts +108 -4
  112. package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
  113. package/corpus/templates/design/actions/insert-asset.ts +34 -29
  114. package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
  115. package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
  116. package/corpus/templates/design/actions/present-design-variants.ts +7 -2
  117. package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
  118. package/corpus/templates/design/actions/update-file.ts +190 -75
  119. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
  120. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
  121. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
  122. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
  123. package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
  124. package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
  125. package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
  126. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
  127. package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
  129. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
  130. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
  131. package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
  132. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
  133. package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
  134. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
  135. package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
  136. package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
  137. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
  138. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
  139. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
  140. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
  141. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
  142. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
  143. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
  144. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
  145. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
  146. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
  147. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
  148. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
  149. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
  150. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
  151. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
  152. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
  153. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
  154. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
  155. package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
  156. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
  157. package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
  158. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
  159. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
  160. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
  161. package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
  162. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
  163. package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
  164. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
  165. package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
  166. package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
  167. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
  168. package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
  169. package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
  170. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
  171. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
  172. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
  173. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
  174. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
  175. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
  176. package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
  177. package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
  178. package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
  179. package/corpus/templates/design/app/components/design/types.ts +15 -0
  180. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
  181. package/corpus/templates/design/app/global.css +8 -8
  182. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
  183. package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
  184. package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
  185. package/corpus/templates/design/app/i18n-data.ts +1664 -152
  186. package/corpus/templates/design/app/i18n-motion.ts +563 -0
  187. package/corpus/templates/design/app/lib/design-import.ts +73 -0
  188. package/corpus/templates/design/app/pages/Index.tsx +41 -22
  189. package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
  190. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
  191. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
  192. package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
  193. package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
  194. package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
  195. package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
  196. package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
  197. package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
  198. package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
  199. package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
  239. package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
  240. package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
  241. package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
  242. package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
  243. package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
  244. package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
  245. package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
  246. package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
  247. package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
  249. package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
  250. package/corpus/templates/design/server/source-workspace.ts +139 -59
  251. package/corpus/templates/design/shared/board-file.ts +11 -2
  252. package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
  253. package/corpus/templates/design/shared/canvas-math.ts +354 -35
  254. package/corpus/templates/design/shared/code-layer.ts +277 -8
  255. package/corpus/templates/design/shared/design-state.ts +11 -4
  256. package/corpus/templates/design/shared/interaction-states.ts +548 -0
  257. package/corpus/templates/design/shared/motion-compiler.ts +186 -23
  258. package/corpus/templates/design/shared/motion-easing.ts +294 -0
  259. package/corpus/templates/design/shared/motion-timeline.ts +400 -34
  260. package/corpus/templates/design/shared/prompt-title.ts +95 -0
  261. package/corpus/templates/design/shared/responsive-classes.ts +448 -10
  262. package/corpus/templates/design/shared/screen-annotation.ts +46 -0
  263. package/corpus/templates/design/shared/shader-fills.ts +1009 -0
  264. package/corpus/templates/design/shared/shader-presets.ts +852 -4
  265. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
  266. package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
  267. package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
  268. package/dist/client/AgentPanel.js +1 -1
  269. package/dist/client/AgentPanel.js.map +1 -1
  270. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  271. package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
  272. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  273. package/dist/client/use-action.d.ts +3 -0
  274. package/dist/client/use-action.d.ts.map +1 -1
  275. package/dist/client/use-action.js +34 -3
  276. package/dist/client/use-action.js.map +1 -1
  277. package/dist/client/use-db-sync.d.ts +4 -0
  278. package/dist/client/use-db-sync.d.ts.map +1 -1
  279. package/dist/client/use-db-sync.js +37 -18
  280. package/dist/client/use-db-sync.js.map +1 -1
  281. package/dist/collab/routes.d.ts +1 -1
  282. package/dist/collab/struct-routes.d.ts +1 -1
  283. package/dist/db/create-get-db.d.ts +25 -0
  284. package/dist/db/create-get-db.d.ts.map +1 -1
  285. package/dist/db/create-get-db.js +25 -2
  286. package/dist/db/create-get-db.js.map +1 -1
  287. package/dist/observability/routes.d.ts +3 -3
  288. package/dist/secrets/routes.d.ts +9 -9
  289. package/dist/server/framework-request-handler.d.ts.map +1 -1
  290. package/dist/server/framework-request-handler.js +37 -1
  291. package/dist/server/framework-request-handler.js.map +1 -1
  292. package/package.json +1 -1
  293. package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
  294. package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
  295. package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
@@ -0,0 +1,693 @@
1
+ import { useT } from "@agent-native/core/client";
2
+ import {
3
+ IconLayoutGrid,
4
+ IconLink,
5
+ IconLinkOff,
6
+ IconMinus,
7
+ IconPlus,
8
+ } from "@tabler/icons-react";
9
+ import { useEffect, useState } from "react";
10
+
11
+ import {
12
+ Tooltip,
13
+ TooltipContent,
14
+ TooltipTrigger,
15
+ } from "@/components/ui/tooltip";
16
+ import { cn } from "@/lib/utils";
17
+
18
+ import {
19
+ AutoLayoutMatrix,
20
+ ScrubInput,
21
+ SizingField,
22
+ type AutoLayoutMatrixValue,
23
+ type ScrubInputChangeMeta,
24
+ } from "../inspector";
25
+ import type { ElementInfo } from "../types";
26
+ import {
27
+ autoLayoutAlignmentFromStyles,
28
+ availableSizingForElement,
29
+ commitElementMinMax,
30
+ commitElementSizing,
31
+ cssElementSize,
32
+ elementHasLayoutChildren,
33
+ horizontalToJustify,
34
+ inferElementSizing,
35
+ isContainerElement,
36
+ isParentFlex,
37
+ isParentGrid,
38
+ readElementMinMax,
39
+ verticalToAlign,
40
+ } from "./element-classification";
41
+ import {
42
+ deriveLockedAspectSize,
43
+ elementIdentityKey,
44
+ useAspectRatioLock,
45
+ } from "./element-identity";
46
+ import { FieldTrailer, ScrubStyleInput } from "./field-primitives";
47
+ import { joinCssLayers, splitCssLayers } from "./fill-gradient-helpers";
48
+ import { SectionIconButton } from "./inspector-controls";
49
+ import {
50
+ PanelSection,
51
+ PropInput,
52
+ PropSelect,
53
+ SubsectionLabel,
54
+ } from "./panel-primitives";
55
+ import { compactCssValue, fourValuesEqual } from "./position-helpers";
56
+ import { isMixedValue } from "./selection-helpers";
57
+ import type {
58
+ BreakpointOverrideFieldContext,
59
+ MotionKeyframeFieldContext,
60
+ StyleChangeHandler,
61
+ StylesChangeHandler,
62
+ } from "./style-change-types";
63
+ import {
64
+ ALIGN_SELF_OPTIONS,
65
+ optionValue,
66
+ parseNumericValue,
67
+ } from "./style-options";
68
+
69
+ /** Flex container properties */
70
+ function FlexContainerControls({
71
+ element,
72
+ onStyleChange,
73
+ onStylesChange,
74
+ }: {
75
+ element: ElementInfo;
76
+ onStyleChange: StyleChangeHandler;
77
+ onStylesChange?: StylesChangeHandler;
78
+ }) {
79
+ const t = useT();
80
+ const styles = element.computedStyles;
81
+ // The element's CURRENT layout flow as authored in code, read from its own
82
+ // computed `display`: block/flow-root/grid/etc. = "normal flow",
83
+ // flex/inline-flex = auto layout. We forward it so the AutoLayoutMatrix Flow
84
+ // control can show the right state (normal vs horizontal/vertical/wrap)
85
+ // instead of an empty "add" affordance.
86
+ const display = (styles.display || "").toLowerCase();
87
+ const isFlex = element.isFlexContainer || display.includes("flex");
88
+ const displayMode: AutoLayoutMatrixValue["display"] = isFlex
89
+ ? "flex"
90
+ : "block";
91
+ const hasLayoutChildren = elementHasLayoutChildren(element);
92
+ const flexDirection: AutoLayoutMatrixValue["direction"] =
93
+ styles.flexDirection?.includes("column") ? "vertical" : "horizontal";
94
+ const mainGapAxis =
95
+ flexDirection === "horizontal" ? "horizontal" : "vertical";
96
+ // When the element is in normal flow (not flex yet), picking any flow option
97
+ // must first turn it into a flex container; otherwise setting flex-direction
98
+ // alone is a no-op against a block element.
99
+ const ensureFlex = () => {
100
+ if (!isFlex) onStyleChange("display", "flex");
101
+ };
102
+
103
+ /**
104
+ * Handle the Flow control switching between flex and normal-flow (block).
105
+ *
106
+ * For 'flex': ensures display:flex is set (ensureFlex path).
107
+ * For 'block': sets display:block and leaves children unchanged — mirrors
108
+ * the { kind:"autoLayout", enabled:false } substrate intent exactly.
109
+ */
110
+ const handleDisplayChange = (nextDisplay: "flex" | "block") => {
111
+ if (nextDisplay === "flex") {
112
+ ensureFlex();
113
+ return;
114
+ }
115
+ // Turn auto-layout off: set display:block, leaving children unchanged.
116
+ // This is the direct equivalent of the autoLayout substrate with enabled:false.
117
+ onStyleChange("display", "block");
118
+ };
119
+
120
+ const padding = {
121
+ top: parseNumericValue(styles.paddingTop || "0"),
122
+ right: parseNumericValue(styles.paddingRight || "0"),
123
+ bottom: parseNumericValue(styles.paddingBottom || "0"),
124
+ left: parseNumericValue(styles.paddingLeft || "0"),
125
+ };
126
+ const allPaddingEqual = fourValuesEqual([
127
+ padding.top,
128
+ padding.right,
129
+ padding.bottom,
130
+ padding.left,
131
+ ]);
132
+ // Seeds the linked/unlinked view once per selection (this component is
133
+ // remounted per element via the `key={elementIdentityKey(element)}` at its
134
+ // call site, matching CornerRadiusControl's pattern) and is otherwise a
135
+ // pure user-controlled toggle (see onPaddingLinkedChange below). Do NOT add
136
+ // a useEffect that re-derives this from `allPaddingEqual` on every render:
137
+ // that previously auto-unlinked as soon as the four sides became unequal,
138
+ // which fires mid-drag the instant a user scrubs one axis of the linked
139
+ // horizontal/vertical fields (e.g. changing left/right while top/bottom
140
+ // stay put) — collapsing the linked 2-field view into the unlinked 4-field
141
+ // view *during* the gesture and destroying the drag (STEVE TEST BATCH 4 #4).
142
+ const [paddingLinked, setPaddingLinked] = useState(allPaddingEqual);
143
+
144
+ const autoLayoutValue: AutoLayoutMatrixValue = {
145
+ direction: flexDirection,
146
+ wrap: styles.flexWrap === "wrap" ? "wrap" : "nowrap",
147
+ alignment: autoLayoutAlignmentFromStyles(styles, flexDirection),
148
+ gap: parseNumericValue(styles.gap || "0"),
149
+ padding,
150
+ paddingLinked,
151
+ childSizing: {
152
+ horizontal: inferElementSizing(element, "horizontal"),
153
+ vertical: inferElementSizing(element, "vertical"),
154
+ },
155
+ childMinMax: {
156
+ horizontal: readElementMinMax(element, "horizontal"),
157
+ vertical: readElementMinMax(element, "vertical"),
158
+ },
159
+ clipContent: styles.overflow === "hidden",
160
+ resolvedSize: {
161
+ horizontal: cssElementSize(element, "horizontal"),
162
+ vertical: cssElementSize(element, "vertical"),
163
+ },
164
+ mixedSize: {
165
+ horizontal: isMixedValue(styles.width),
166
+ vertical: isMixedValue(styles.height),
167
+ },
168
+ display: displayMode,
169
+ spaceBetween: styles.justifyContent === "space-between",
170
+ };
171
+
172
+ return (
173
+ <div className="space-y-2">
174
+ <AutoLayoutMatrix
175
+ value={autoLayoutValue}
176
+ onDisplayChange={handleDisplayChange}
177
+ onDirectionChange={(direction) => {
178
+ ensureFlex();
179
+ onStyleChange(
180
+ "flexDirection",
181
+ direction === "vertical" ? "column" : "row",
182
+ );
183
+ }}
184
+ onWrapChange={(wrap) => {
185
+ ensureFlex();
186
+ onStyleChange("flexWrap", wrap);
187
+ }}
188
+ onAlignmentChange={(alignment) => {
189
+ if (autoLayoutValue.direction === "vertical") {
190
+ onStyleChange(
191
+ "alignItems",
192
+ horizontalToJustify(alignment.horizontal),
193
+ );
194
+ onStyleChange(
195
+ "justifyContent",
196
+ verticalToAlign(alignment.vertical),
197
+ );
198
+ return;
199
+ }
200
+ onStyleChange(
201
+ "justifyContent",
202
+ horizontalToJustify(alignment.horizontal),
203
+ );
204
+ onStyleChange("alignItems", verticalToAlign(alignment.vertical));
205
+ }}
206
+ onGapChange={(gap, meta) => onStyleChange("gap", `${gap}px`, meta)}
207
+ onPaddingChange={(nextPadding, meta) => {
208
+ // Forward ScrubInput's gesture meta so preview ticks ride the host's
209
+ // live fast path and only the release commit persists (B5-14:
210
+ // dropping it here made padding scrubs invisible until reselect).
211
+ // Batch all four sides into one styles change when the host
212
+ // supports it so each tick/commit is a single message instead of
213
+ // four.
214
+ const patch = {
215
+ paddingTop: `${nextPadding.top}px`,
216
+ paddingRight: `${nextPadding.right}px`,
217
+ paddingBottom: `${nextPadding.bottom}px`,
218
+ paddingLeft: `${nextPadding.left}px`,
219
+ };
220
+ if (onStylesChange) {
221
+ onStylesChange(patch, meta);
222
+ return;
223
+ }
224
+ Object.entries(patch).forEach(([property, value]) =>
225
+ onStyleChange(property, value, meta),
226
+ );
227
+ }}
228
+ onPaddingLinkedChange={(linked) => {
229
+ setPaddingLinked(linked);
230
+ if (!linked) return;
231
+ const avg = Math.round(
232
+ (padding.top + padding.right + padding.bottom + padding.left) / 4,
233
+ );
234
+ onStyleChange("paddingTop", `${avg}px`);
235
+ onStyleChange("paddingRight", `${avg}px`);
236
+ onStyleChange("paddingBottom", `${avg}px`);
237
+ onStyleChange("paddingLeft", `${avg}px`);
238
+ }}
239
+ onClipContentChange={(clipContent) =>
240
+ onStyleChange("overflow", clipContent ? "hidden" : "visible")
241
+ }
242
+ onDistribute={(axis) => {
243
+ if (axis === mainGapAxis) {
244
+ onStyleChange("justifyContent", "space-between");
245
+ } else if (autoLayoutValue.wrap === "wrap") {
246
+ onStyleChange("alignContent", "space-between");
247
+ }
248
+ }}
249
+ onGapModeChange={(gapMode, axis) => {
250
+ if (axis !== mainGapAxis) return;
251
+ ensureFlex();
252
+ onStyleChange(
253
+ "justifyContent",
254
+ gapMode === "auto" ? "space-between" : "flex-start",
255
+ );
256
+ }}
257
+ availableChildSizing={availableSizingForElement(element)}
258
+ onChildSizingChange={(axis, sizing) => {
259
+ commitElementSizing(
260
+ element,
261
+ axis,
262
+ sizing,
263
+ onStyleChange,
264
+ onStylesChange,
265
+ );
266
+ }}
267
+ onChildSizeChange={(axis, px, meta) =>
268
+ onStyleChange(
269
+ axis === "horizontal" ? "width" : "height",
270
+ `${px}px`,
271
+ meta,
272
+ )
273
+ }
274
+ onChildMinMaxChange={(axis, kind, val, meta) =>
275
+ commitElementMinMax(axis, kind, val, onStyleChange, meta)
276
+ }
277
+ showChildLayoutControls={hasLayoutChildren}
278
+ />
279
+ </div>
280
+ );
281
+ }
282
+
283
+ function FlexChildControls({
284
+ element,
285
+ onStyleChange,
286
+ }: {
287
+ element: ElementInfo;
288
+ onStyleChange: StyleChangeHandler;
289
+ }) {
290
+ const t = useT();
291
+ const styles = element.computedStyles;
292
+ const alignSelfOptions = ALIGN_SELF_OPTIONS.map((option) => ({
293
+ value: option.value,
294
+ label: t(`editPanel.alignSelfOptions.${option.key}`),
295
+ }));
296
+
297
+ return (
298
+ <div className="space-y-2">
299
+ <SubsectionLabel>{t("editPanel.layoutContext.child")}</SubsectionLabel>
300
+ <PropInput
301
+ label={t("editPanel.labels.flexGrow")}
302
+ value={styles.flexGrow || ""}
303
+ onChange={(v) => onStyleChange("flexGrow", v)}
304
+ placeholder="0"
305
+ />
306
+ <PropInput
307
+ label={t("editPanel.labels.flexShrink")}
308
+ value={styles.flexShrink || ""}
309
+ onChange={(v) => onStyleChange("flexShrink", v)}
310
+ placeholder="1"
311
+ />
312
+ <PropInput
313
+ label={t("editPanel.labels.flexBasis")}
314
+ value={styles.flexBasis || ""}
315
+ onChange={(v) => onStyleChange("flexBasis", v)}
316
+ placeholder="auto"
317
+ defaultUnit="px"
318
+ />
319
+ <PropInput
320
+ label={t("editPanel.labels.order")}
321
+ value={styles.order || ""}
322
+ onChange={(v) => onStyleChange("order", v)}
323
+ placeholder="0"
324
+ />
325
+ <PropSelect
326
+ label={t("editPanel.labels.alignSelf")}
327
+ value={optionValue(ALIGN_SELF_OPTIONS, styles.alignSelf, "auto")}
328
+ onChange={(v) => onStyleChange("alignSelf", v)}
329
+ options={alignSelfOptions}
330
+ />
331
+ </div>
332
+ );
333
+ }
334
+
335
+ function GridChildControls({
336
+ element,
337
+ onStyleChange,
338
+ }: {
339
+ element: ElementInfo;
340
+ onStyleChange: StyleChangeHandler;
341
+ }) {
342
+ const t = useT();
343
+ const styles = element.computedStyles;
344
+ const alignSelfOptions = ALIGN_SELF_OPTIONS.map((option) => ({
345
+ value: option.value,
346
+ label: t(`editPanel.alignSelfOptions.${option.key}`),
347
+ }));
348
+
349
+ return (
350
+ <div className="space-y-2">
351
+ <SubsectionLabel>
352
+ {t("editPanel.layoutContext.gridChild")}
353
+ </SubsectionLabel>
354
+ <PropInput
355
+ label={t("editPanel.labels.gridColumn")}
356
+ value={styles.gridColumn || ""}
357
+ onChange={(v) => onStyleChange("gridColumn", v)}
358
+ placeholder="auto"
359
+ />
360
+ <PropInput
361
+ label={t("editPanel.labels.gridRow")}
362
+ value={styles.gridRow || ""}
363
+ onChange={(v) => onStyleChange("gridRow", v)}
364
+ placeholder="auto"
365
+ />
366
+ <PropSelect
367
+ label={t("editPanel.labels.alignSelf")}
368
+ value={optionValue(ALIGN_SELF_OPTIONS, styles.alignSelf, "auto")}
369
+ onChange={(v) => onStyleChange("alignSelf", v)}
370
+ options={alignSelfOptions}
371
+ />
372
+ </div>
373
+ );
374
+ }
375
+
376
+ export function LayoutContextProperties({
377
+ element,
378
+ onStyleChange,
379
+ onStylesChange,
380
+ motionKeyframeContext,
381
+ breakpointOverrideContext,
382
+ }: {
383
+ element: ElementInfo;
384
+ onStyleChange: StyleChangeHandler;
385
+ onStylesChange?: StylesChangeHandler;
386
+ motionKeyframeContext?: MotionKeyframeFieldContext;
387
+ breakpointOverrideContext?: BreakpointOverrideFieldContext;
388
+ }) {
389
+ const t = useT();
390
+ const flexChild = isParentFlex(element);
391
+ const gridChild = isParentGrid(element);
392
+ const availableSizing = availableSizingForElement(element);
393
+ const isContainer = isContainerElement(element);
394
+ const aspectLock = useAspectRatioLock(element);
395
+
396
+ const childControls = (
397
+ <>
398
+ {flexChild ? (
399
+ <div className="border-t border-border/70 pt-2">
400
+ <FlexChildControls element={element} onStyleChange={onStyleChange} />
401
+ </div>
402
+ ) : null}
403
+ {gridChild ? (
404
+ <div className="border-t border-border/70 pt-2">
405
+ <GridChildControls element={element} onStyleChange={onStyleChange} />
406
+ </div>
407
+ ) : null}
408
+ </>
409
+ );
410
+
411
+ // Leaf elements (text, img, svg, etc.) never get auto layout — show the plain
412
+ // design W/H sizing block instead.
413
+ if (!isContainer) {
414
+ const widthSizing = inferElementSizing(element, "horizontal");
415
+ const heightSizing = inferElementSizing(element, "vertical");
416
+ // The aspect lock only makes sense between two fixed numeric dimensions —
417
+ // hug/fill don't have an independent px value to scale. Match Figma: the
418
+ // toggle is disabled (not hidden) otherwise, so its state/affordance stays
419
+ // visible but inert.
420
+ const canLockAspect = widthSizing === "fixed" && heightSizing === "fixed";
421
+ const resolvedWidth = cssElementSize(element, "horizontal");
422
+ const resolvedHeight = cssElementSize(element, "vertical");
423
+
424
+ const toggleAspectLock = () => {
425
+ if (!canLockAspect) return;
426
+ aspectLock.setLocked(
427
+ !aspectLock.locked,
428
+ resolvedHeight > 0 ? resolvedWidth / resolvedHeight : undefined,
429
+ );
430
+ };
431
+
432
+ // Shared W/H commit path: when locked, derive the other axis from the
433
+ // captured ratio and commit both in one patch/history step; otherwise
434
+ // fall back to the existing single-property write. `meta` is the
435
+ // ScrubInput gesture-coalescing metadata forwarded from SizingField's
436
+ // onSizeChange (see AutoLayoutMatrix.tsx) — threading it through here,
437
+ // exactly like the X/Y ScrubStyleInput fields already do, is what lets a
438
+ // W/H drag-scrub coalesce into one undo step instead of one per tick.
439
+ // When locked, the same single `meta` describes the *one* combined
440
+ // gesture driving both axes, so it's forwarded unchanged to whichever
441
+ // commit call carries the patch (StylesChangeHandler/StyleChangeHandler
442
+ // both accept an optional meta already).
443
+ const commitWidth = (px: number, meta?: ScrubInputChangeMeta) => {
444
+ if (aspectLock.locked && canLockAspect && aspectLock.ratio) {
445
+ const nextHeight = deriveLockedAspectSize(
446
+ "width",
447
+ px,
448
+ aspectLock.ratio,
449
+ );
450
+ const patch = { width: `${px}px`, height: `${nextHeight}px` };
451
+ if (onStylesChange) onStylesChange(patch, meta);
452
+ else {
453
+ onStyleChange("width", patch.width, meta);
454
+ onStyleChange("height", patch.height, meta);
455
+ }
456
+ return;
457
+ }
458
+ onStyleChange("width", `${px}px`, meta);
459
+ };
460
+ const commitHeight = (px: number, meta?: ScrubInputChangeMeta) => {
461
+ if (aspectLock.locked && canLockAspect && aspectLock.ratio) {
462
+ const nextWidth = deriveLockedAspectSize(
463
+ "height",
464
+ px,
465
+ aspectLock.ratio,
466
+ );
467
+ const patch = { width: `${nextWidth}px`, height: `${px}px` };
468
+ if (onStylesChange) onStylesChange(patch, meta);
469
+ else {
470
+ onStyleChange("width", patch.width, meta);
471
+ onStyleChange("height", patch.height, meta);
472
+ }
473
+ return;
474
+ }
475
+ onStyleChange("height", `${px}px`, meta);
476
+ };
477
+
478
+ return (
479
+ <PanelSection title={t("editPanel.sections.layout")}>
480
+ {/* design-editor single-row-per-axis: [W | value | Fixed/Hug/Fill ▾]
481
+ with the full sizing menu (modes + min/max + variable) per axis,
482
+ plus a chain-link aspect-ratio lock at the FAR RIGHT of the row
483
+ (Figma parity — the constrain-proportions link sits after both W
484
+ and H, not between them). */}
485
+ <div className="grid grid-cols-[1fr_1fr_auto] items-start gap-1.5">
486
+ <div className="group/field relative min-w-0">
487
+ <SizingField
488
+ axis="W"
489
+ sizingAxis="horizontal"
490
+ value={widthSizing}
491
+ resolvedSize={resolvedWidth}
492
+ mixed={isMixedValue(element.computedStyles.width)}
493
+ minMax={readElementMinMax(element, "horizontal")}
494
+ options={availableSizing.horizontal ?? ["fixed"]}
495
+ disabled={false}
496
+ onChange={(mode) =>
497
+ commitElementSizing(
498
+ element,
499
+ "horizontal",
500
+ mode,
501
+ onStyleChange,
502
+ onStylesChange,
503
+ )
504
+ }
505
+ onSizeChange={commitWidth}
506
+ onMinMaxChange={(axis, kind, val, meta) =>
507
+ commitElementMinMax(axis, kind, val, onStyleChange, meta)
508
+ }
509
+ />
510
+ <FieldTrailer
511
+ element={element}
512
+ overrideProperty="width"
513
+ motionKeyframeContext={motionKeyframeContext}
514
+ breakpointOverrideContext={breakpointOverrideContext}
515
+ className="absolute -top-3.5 right-0"
516
+ />
517
+ </div>
518
+ <div className="group/field relative min-w-0">
519
+ <SizingField
520
+ axis="H"
521
+ sizingAxis="vertical"
522
+ value={heightSizing}
523
+ resolvedSize={resolvedHeight}
524
+ mixed={isMixedValue(element.computedStyles.height)}
525
+ minMax={readElementMinMax(element, "vertical")}
526
+ options={availableSizing.vertical ?? ["fixed"]}
527
+ disabled={false}
528
+ onChange={(mode) =>
529
+ commitElementSizing(
530
+ element,
531
+ "vertical",
532
+ mode,
533
+ onStyleChange,
534
+ onStylesChange,
535
+ )
536
+ }
537
+ onSizeChange={commitHeight}
538
+ onMinMaxChange={(axis, kind, val, meta) =>
539
+ commitElementMinMax(axis, kind, val, onStyleChange, meta)
540
+ }
541
+ />
542
+ <FieldTrailer
543
+ element={element}
544
+ overrideProperty="height"
545
+ motionKeyframeContext={motionKeyframeContext}
546
+ breakpointOverrideContext={breakpointOverrideContext}
547
+ className="absolute -top-3.5 right-0"
548
+ />
549
+ </div>
550
+ <Tooltip>
551
+ <TooltipTrigger asChild>
552
+ <button
553
+ type="button"
554
+ aria-label={
555
+ aspectLock.locked
556
+ ? t("editPanel.labels.unlockAspectRatio")
557
+ : t("editPanel.labels.lockAspectRatio")
558
+ }
559
+ aria-pressed={aspectLock.locked}
560
+ disabled={!canLockAspect}
561
+ onClick={toggleAspectLock}
562
+ className={cn(
563
+ "mt-0.5 flex size-6 shrink-0 items-center justify-center self-start rounded-md text-muted-foreground transition-colors",
564
+ "hover:bg-[var(--design-editor-control-bg)] hover:text-foreground",
565
+ aspectLock.locked &&
566
+ "text-[var(--design-editor-accent-color)] hover:text-[var(--design-editor-accent-color)]",
567
+ !canLockAspect && "pointer-events-none opacity-40",
568
+ )}
569
+ >
570
+ {aspectLock.locked ? (
571
+ <IconLink className="size-3.5" />
572
+ ) : (
573
+ <IconLinkOff className="size-3.5" />
574
+ )}
575
+ </button>
576
+ </TooltipTrigger>
577
+ <TooltipContent>
578
+ {aspectLock.locked
579
+ ? t("editPanel.labels.unlockAspectRatio")
580
+ : t("editPanel.labels.lockAspectRatio")}
581
+ </TooltipContent>
582
+ </Tooltip>
583
+ </div>
584
+ {childControls}
585
+ </PanelSection>
586
+ );
587
+ }
588
+
589
+ // Any container element ALREADY has a layout in code — normal flow (block) by
590
+ // default, or flex when it uses flexbox. the design editor never makes you "add" auto
591
+ // layout for a frame, so we always render the full layout controls and let
592
+ // the Flow control reflect/switch the element's current `display`. Choosing a
593
+ // horizontal/vertical/wrap/grid flow applies `display:flex`; choosing the
594
+ // normal-flow option resets to `display:block`.
595
+ return (
596
+ <PanelSection title={t("editPanel.sections.autoLayout")}>
597
+ {/* Selection-stable key so per-selection UI state (paddingLinked, which
598
+ must not silently flip while the user is mid-scrub — see the
599
+ FlexContainerControls comment) resets on selection change instead of
600
+ leaking to the next element — same pattern as CornerRadiusControl /
601
+ ExportSettingsPanel. */}
602
+ <FlexContainerControls
603
+ key={elementIdentityKey(element)}
604
+ element={element}
605
+ onStyleChange={onStyleChange}
606
+ onStylesChange={onStylesChange}
607
+ />
608
+ {childControls}
609
+ </PanelSection>
610
+ );
611
+ }
612
+
613
+ /**
614
+ * design layout-guide section. Shown for frame/container
615
+ * elements. Renders an overlay column/row guide by applying a non-destructive
616
+ * `backgroundImage` repeating gradient layer tagged so it can be toggled off
617
+ * without disturbing real fills.
618
+ */
619
+ const LAYOUT_GUIDE_MARKER = "/* an-layout-guide */";
620
+
621
+ function hasLayoutGuide(styles: Record<string, string>): boolean {
622
+ return Boolean(styles.backgroundImage?.includes(LAYOUT_GUIDE_MARKER));
623
+ }
624
+
625
+ export function LayoutGuideProperties({
626
+ element,
627
+ onStyleChange,
628
+ }: {
629
+ element: ElementInfo;
630
+ onStyleChange: StyleChangeHandler;
631
+ }) {
632
+ const styles = element.computedStyles;
633
+ const active = hasLayoutGuide(styles);
634
+
635
+ const addGuide = () => {
636
+ // 12-column overlay guide — the design editor's default columns layout grid.
637
+ // The LAYOUT_GUIDE_MARKER comment is embedded so hasLayoutGuide and removeGuide
638
+ // can detect/remove it without touching unrelated repeating-linear-gradient fills.
639
+ const guide = `repeating-linear-gradient(to right, color-mix(in srgb, var(--design-editor-accent-color) 22%, transparent) 0 1px, transparent 1px calc(100% / 12)) ${LAYOUT_GUIDE_MARKER}`;
640
+ const existing = compactCssValue(styles.backgroundImage, "");
641
+ onStyleChange(
642
+ "backgroundImage",
643
+ existing ? `${guide}, ${existing}` : guide,
644
+ );
645
+ };
646
+
647
+ const removeGuide = () => {
648
+ const layers = splitCssLayers(styles.backgroundImage || "").filter(
649
+ (layer) => !layer.includes(LAYOUT_GUIDE_MARKER),
650
+ );
651
+ onStyleChange(
652
+ "backgroundImage",
653
+ layers.length ? joinCssLayers(layers) : "none",
654
+ );
655
+ };
656
+
657
+ return (
658
+ <PanelSection
659
+ title={"Layout guide" /* i18n-ignore design inspector label */}
660
+ defaultCollapsed
661
+ actions={
662
+ <SectionIconButton
663
+ label={
664
+ active
665
+ ? "Remove layout guide" /* i18n-ignore design inspector action */
666
+ : "Add layout guide" /* i18n-ignore design inspector action */
667
+ }
668
+ onClick={active ? removeGuide : addGuide}
669
+ >
670
+ {active ? (
671
+ <IconMinus className="size-3.5" />
672
+ ) : (
673
+ <IconPlus className="size-3.5" />
674
+ )}
675
+ </SectionIconButton>
676
+ }
677
+ >
678
+ {active ? (
679
+ <div className="flex items-center gap-2 rounded-md bg-[var(--design-editor-control-bg)] px-2 py-1.5 !text-[11px] text-muted-foreground">
680
+ <IconLayoutGrid className="size-3.5 shrink-0" />
681
+ <span className="min-w-0 flex-1 truncate text-foreground">
682
+ {"Columns" /* i18n-ignore design inspector label */}
683
+ </span>
684
+ <span className="shrink-0 tabular-nums">12</span>
685
+ </div>
686
+ ) : (
687
+ <p className="!text-[11px] text-muted-foreground">
688
+ {"No layout guides" /* i18n-ignore design inspector empty state */}
689
+ </p>
690
+ )}
691
+ </PanelSection>
692
+ );
693
+ }