@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,594 @@
1
+ import { useT } from "@agent-native/core/client";
2
+ import {
3
+ parseCssColor,
4
+ rgbaToCss,
5
+ rgbaToHex,
6
+ withColorOpacity,
7
+ } from "@shared/color-utils";
8
+ import {
9
+ IconEye,
10
+ IconEyeOff,
11
+ IconLayoutGrid,
12
+ IconMinus,
13
+ IconPlus,
14
+ } from "@tabler/icons-react";
15
+
16
+ import {
17
+ Popover,
18
+ PopoverContent,
19
+ PopoverTrigger,
20
+ } from "@/components/ui/popover";
21
+
22
+ import { DesignColorPicker, imageFillToBackgroundStyles } from "../inspector";
23
+ import type { GlslShaderPanelContext } from "../inspector/GlslShaderPanel";
24
+ import type { ElementInfo } from "../types";
25
+ import { selectionColorValues } from "./document-colors";
26
+ import { isTextElement } from "./element-classification";
27
+ import { commitStylePatch, FieldTrailer } from "./field-primitives";
28
+ import {
29
+ averageGradientOpacity,
30
+ buildGradientLayer,
31
+ defaultGradientLayer,
32
+ gradientLabel,
33
+ isLayerHiddenBySize,
34
+ joinCssLayers,
35
+ parseGradientLayer,
36
+ removeFillLayerAtIndex,
37
+ splitCssLayers,
38
+ withLayerSizeMarker,
39
+ } from "./fill-gradient-helpers";
40
+ import {
41
+ RowDragHandle,
42
+ SectionIconButton,
43
+ useRowDragReorder,
44
+ } from "./inspector-controls";
45
+ import { ColorInput, PanelSection } from "./panel-primitives";
46
+ import {
47
+ colorHasVisibleAlpha,
48
+ compactCssValue,
49
+ cssColorOrFallback,
50
+ swatchStyle,
51
+ } from "./position-helpers";
52
+ import { isMixedValue } from "./selection-helpers";
53
+ import type {
54
+ BreakpointOverrideFieldContext,
55
+ MotionKeyframeFieldContext,
56
+ StyleChangeHandler,
57
+ StylesChangeHandler,
58
+ } from "./style-change-types";
59
+
60
+ export function FillProperties({
61
+ element,
62
+ onStyleChange,
63
+ onStylesChange,
64
+ documentColorPalette = [],
65
+ glslShaderContext,
66
+ motionKeyframeContext,
67
+ breakpointOverrideContext,
68
+ }: {
69
+ element: ElementInfo;
70
+ onStyleChange: StyleChangeHandler;
71
+ onStylesChange?: StylesChangeHandler;
72
+ /** Document-wide palette (see `extractDocumentColorPalette`), already
73
+ * capped/ordered by frequency. Merged with the current selection's own
74
+ * colors below so a real, always-populated "Document colors" row is
75
+ * available even before any file content has been scanned. */
76
+ documentColorPalette?: string[];
77
+ /**
78
+ * Persistence context for the code-backed Shader paint type (GLSL source
79
+ * saved into the screen HTML). Threaded into the fill picker so its
80
+ * Shader tab opens the GlslShaderPanel.
81
+ */
82
+ glslShaderContext?: GlslShaderPanelContext;
83
+ motionKeyframeContext?: MotionKeyframeFieldContext;
84
+ breakpointOverrideContext?: BreakpointOverrideFieldContext;
85
+ }) {
86
+ const t = useT();
87
+ const styles = element.computedStyles;
88
+ const isTextFillElement = isTextElement(element);
89
+ const fillProperty = isTextFillElement ? "color" : "backgroundColor";
90
+ const fillValue = isTextFillElement
91
+ ? styles.color || ""
92
+ : styles.backgroundColor || "";
93
+ const backgroundLayers = isTextFillElement
94
+ ? []
95
+ : splitCssLayers(styles.backgroundImage || "");
96
+ const backgroundSizeLayers = isTextFillElement
97
+ ? []
98
+ : splitCssLayers(styles.backgroundSize || "");
99
+ const backgroundRepeatLayers = isTextFillElement
100
+ ? []
101
+ : splitCssLayers(styles.backgroundRepeat || "");
102
+ const backgroundPositionLayers = isTextFillElement
103
+ ? []
104
+ : splitCssLayers(styles.backgroundPosition || "");
105
+ const fillIsMixed =
106
+ isMixedValue(fillValue) ||
107
+ isMixedValue(styles.backgroundImage) ||
108
+ isMixedValue(styles.backgroundSize) ||
109
+ isMixedValue(styles.backgroundRepeat) ||
110
+ isMixedValue(styles.backgroundPosition);
111
+ const hasBackgroundLayer = !isTextFillElement && backgroundLayers.length > 0;
112
+ const hasVisibleFill =
113
+ isTextFillElement || colorHasVisibleAlpha(fillValue) || hasBackgroundLayer;
114
+
115
+ // Non-destructive fill hide: instead of stashing the pre-hide color in
116
+ // React state (lost on unmount — e.g. deselect then reselect the same
117
+ // element, since FillProperties only mounts while something is selected),
118
+ // zero the alpha channel while preserving the RGB channels in the
119
+ // persisted CSS itself: rgba(r,g,b,0) renders identically to fully
120
+ // transparent, but getComputedStyle round-trips the r/g/b losslessly (CSS
121
+ // color-list channels are real data, unlike comments — verified
122
+ // separately: computed style strips comments but keeps rgba() channels).
123
+ // Showing again just restores alpha to 1 using those same channels, so no
124
+ // stash is required and the hide survives reselect/reload.
125
+ const isHidden = !colorHasVisibleAlpha(fillValue);
126
+ const handleFillVisibilityToggle = () => {
127
+ const parsed = parseCssColor(fillValue);
128
+ if (isHidden) {
129
+ const restored = parsed
130
+ ? rgbaToCss(withColorOpacity(parsed, 100))
131
+ : isTextFillElement
132
+ ? "#000000"
133
+ : "#ffffff";
134
+ onStyleChange(fillProperty, restored);
135
+ } else if (parsed) {
136
+ onStyleChange(fillProperty, rgbaToCss(withColorOpacity(parsed, 0)));
137
+ } else {
138
+ // Value wasn't a parseable color (e.g. already the literal
139
+ // "transparent") — nothing to preserve, transparent is the best we
140
+ // can do.
141
+ onStyleChange(fillProperty, "transparent");
142
+ }
143
+ };
144
+
145
+ // Reorder fill layers by dragging: permute all four index-aligned parallel
146
+ // arrays (image/size/repeat/position) together and commit them as one patch
147
+ // so stacking order changes in a single history step. Prefer onStylesChange
148
+ // (single call) when available; otherwise fall back to four sequential
149
+ // onStyleChange calls, matching the commit-path convention used elsewhere
150
+ // in this component (see commitStylePatch).
151
+ const reorderFillLayers = (from: number, to: number) => {
152
+ const reorder = (layers: string[]) => {
153
+ const next = [...layers];
154
+ const [moved] = next.splice(from, 1);
155
+ if (moved === undefined) return layers;
156
+ next.splice(to, 0, moved);
157
+ return next;
158
+ };
159
+ const patch = {
160
+ backgroundImage: joinCssLayers(reorder(backgroundLayers)),
161
+ backgroundSize: joinCssLayers(reorder(backgroundSizeLayers)),
162
+ backgroundRepeat: joinCssLayers(reorder(backgroundRepeatLayers)),
163
+ backgroundPosition: joinCssLayers(reorder(backgroundPositionLayers)),
164
+ };
165
+ if (onStylesChange) {
166
+ onStylesChange(patch);
167
+ return;
168
+ }
169
+ Object.entries(patch).forEach(([property, value]) =>
170
+ onStyleChange(property, value),
171
+ );
172
+ };
173
+ const fillDrag = useRowDragReorder(
174
+ backgroundLayers.length,
175
+ reorderFillLayers,
176
+ );
177
+
178
+ // Document colors: the selected element's own colors lead the row (so the
179
+ // colors most relevant to what's currently selected are immediately
180
+ // visible), followed by the real document-wide palette collected across
181
+ // every file in the design (see `extractDocumentColorPalette` /
182
+ // `documentColorPalette`, computed once in EditPanel and passed down —
183
+ // this is the actual "every distinct color used in the file" behavior;
184
+ // previously this row only ever showed the 4 lines below, mislabeled as
185
+ // document colors).
186
+ const selectionHexes = selectionColorValues(element)
187
+ .map((c) => {
188
+ const parsed = parseCssColor(c.value);
189
+ return parsed ? rgbaToHex(parsed) : null;
190
+ })
191
+ .filter((h): h is string => Boolean(h));
192
+ // Deduplicate (selectionColorValues already dedupes by raw CSS value, but
193
+ // hex normalisation may collapse additional entries e.g. rgb vs #hex; the
194
+ // document-wide palette is also normalized/deduped on its own, but may
195
+ // still repeat one of the selection's own colors).
196
+ const seenHex = new Set<string>();
197
+ const documentColors = [...selectionHexes, ...documentColorPalette].filter(
198
+ (h) => {
199
+ const key = h.toUpperCase();
200
+ if (seenHex.has(key)) return false;
201
+ seenHex.add(key);
202
+ return true;
203
+ },
204
+ );
205
+
206
+ return (
207
+ <PanelSection
208
+ title={t("editPanel.sections.fill")}
209
+ actions={
210
+ <>
211
+ {/* design color-styles affordance (grid icon) to the left of "+".
212
+ Not yet implemented — disabled with a "Coming soon" tooltip
213
+ rather than a dead, silently-no-op click. */}
214
+ <SectionIconButton
215
+ label={t("editPanel.labels.stylesComingSoon")}
216
+ disabled
217
+ >
218
+ <IconLayoutGrid className="size-3.5" />
219
+ </SectionIconButton>
220
+ <SectionIconButton
221
+ label={t("editPanel.labels.addLayer")}
222
+ onClick={() => {
223
+ if (fillIsMixed) {
224
+ commitStylePatch(
225
+ {
226
+ color: "#000000",
227
+ backgroundColor: "#ffffff",
228
+ backgroundImage: "none",
229
+ },
230
+ onStyleChange,
231
+ onStylesChange,
232
+ );
233
+ return;
234
+ }
235
+ if (isTextFillElement) {
236
+ onStyleChange(
237
+ "color",
238
+ cssColorOrFallback(styles.color, "#000000"),
239
+ );
240
+ return;
241
+ }
242
+ if (!colorHasVisibleAlpha(styles.backgroundColor)) {
243
+ onStyleChange(
244
+ "backgroundColor",
245
+ cssColorOrFallback(styles.backgroundColor, "#ffffff"),
246
+ );
247
+ return;
248
+ }
249
+ const current = compactCssValue(styles.backgroundImage, "");
250
+ const nextLayer = defaultGradientLayer(
251
+ "linear",
252
+ styles.backgroundColor || "#ffffff",
253
+ );
254
+ if (!current) {
255
+ onStyleChange("backgroundImage", nextLayer);
256
+ return;
257
+ }
258
+ // Prepending a layer without also prepending matching entries
259
+ // to the other three index-aligned parallel arrays
260
+ // (size/repeat/position) would shift every existing layer's
261
+ // index by one, silently re-pairing each of them with the
262
+ // *previous* layer's size/repeat/position (same class of bug
263
+ // as the removeLayer fix above). Commit a default entry for
264
+ // the new layer in all four arrays together, in one patch.
265
+ const patch = {
266
+ backgroundImage: `${nextLayer}, ${current}`,
267
+ backgroundSize: joinCssLayers([
268
+ "auto",
269
+ ...backgroundSizeLayers,
270
+ ]),
271
+ backgroundRepeat: joinCssLayers([
272
+ "no-repeat",
273
+ ...backgroundRepeatLayers,
274
+ ]),
275
+ backgroundPosition: joinCssLayers([
276
+ "0% 0%",
277
+ ...backgroundPositionLayers,
278
+ ]),
279
+ };
280
+ if (onStylesChange) {
281
+ onStylesChange(patch);
282
+ return;
283
+ }
284
+ Object.entries(patch).forEach(([property, value]) =>
285
+ onStyleChange(property, value),
286
+ );
287
+ }}
288
+ >
289
+ <IconPlus className="size-3.5" />
290
+ </SectionIconButton>
291
+ </>
292
+ }
293
+ >
294
+ {fillIsMixed ? (
295
+ <p className="px-1.5 py-2 !text-[11px] text-muted-foreground">
296
+ {
297
+ "Click + to replace mixed content" /* i18n-ignore figma mixed fill hint */
298
+ }
299
+ </p>
300
+ ) : hasVisibleFill ? (
301
+ <div className="space-y-1.5">
302
+ {isTextFillElement || colorHasVisibleAlpha(fillValue) ? (
303
+ /* design row: [swatch+hex trigger (flex-1)] [eye] [remove] */
304
+ <div className="group flex items-center gap-1.5">
305
+ <div className="min-w-0 flex-1">
306
+ <ColorInput
307
+ label=""
308
+ value={fillValue}
309
+ onChange={(v, meta) => onStyleChange(fillProperty, v, meta)}
310
+ // Pass the real layer stack (not "") so that switching this
311
+ // swatch's paint type to gradient/image composes a new
312
+ // layer on top of any existing backgroundImage layers
313
+ // (rendered as their own rows below) instead of clobbering
314
+ // them — ColorInput derives its add/replace-layer logic
315
+ // from this prop.
316
+ backgroundImage={
317
+ isTextFillElement ? "" : styles.backgroundImage
318
+ }
319
+ blendMode={
320
+ isTextFillElement
321
+ ? undefined
322
+ : styles.backgroundBlendMode || "normal"
323
+ }
324
+ onBlendModeChange={
325
+ isTextFillElement
326
+ ? undefined
327
+ : (v) => onStyleChange("backgroundBlendMode", v)
328
+ }
329
+ // Text fill ("color") can't hold a gradient/image paint —
330
+ // there is no background-clip:text support here — so never
331
+ // offer layered fills for it; the picker's Gradient/Image
332
+ // tabs remain reachable as raw UI (it manages that tab
333
+ // selection as local state independent of these props) but
334
+ // ColorInput's setNext guard rejects non-color writes back
335
+ // into `color` when supportsLayeredFills is false. For any
336
+ // other element the base fill is a real backgroundImage
337
+ // layer stack, so wire the same layered-fill handlers the
338
+ // page background row uses (see PageProperties above).
339
+ supportsLayeredFills={!isTextFillElement}
340
+ onBackgroundImageChange={
341
+ isTextFillElement
342
+ ? undefined
343
+ : (v) => onStyleChange("backgroundImage", v)
344
+ }
345
+ onImageFillChange={
346
+ isTextFillElement
347
+ ? undefined
348
+ : (value) =>
349
+ commitStylePatch(
350
+ imageFillToBackgroundStyles(value),
351
+ onStyleChange,
352
+ onStylesChange,
353
+ )
354
+ }
355
+ documentColors={documentColors}
356
+ pickerKey={[
357
+ element.sourceId ??
358
+ element.id ??
359
+ element.selector ??
360
+ element.tagName,
361
+ fillProperty,
362
+ ].join(":")}
363
+ // Code-backed GLSL Shader paint type — text fills can't
364
+ // host a shader canvas, so only container fills get it.
365
+ glslShaderContext={
366
+ isTextFillElement ? undefined : glslShaderContext
367
+ }
368
+ />
369
+ </div>
370
+ <SectionIconButton
371
+ label={
372
+ isHidden
373
+ ? t("editPanel.labels.showLayer")
374
+ : t("editPanel.labels.hideLayer")
375
+ }
376
+ onClick={handleFillVisibilityToggle}
377
+ activateOnPointerDown
378
+ >
379
+ {isHidden ? (
380
+ <IconEyeOff className="size-3.5" />
381
+ ) : (
382
+ <IconEye className="size-3.5" />
383
+ )}
384
+ </SectionIconButton>
385
+ <SectionIconButton
386
+ label={t("editPanel.labels.removeLayer")}
387
+ onClick={() => {
388
+ if (isTextFillElement) {
389
+ onStyleChange(fillProperty, "transparent");
390
+ return;
391
+ }
392
+ if (onStylesChange) {
393
+ onStylesChange({
394
+ backgroundColor: "transparent",
395
+ backgroundImage: "none",
396
+ });
397
+ } else {
398
+ onStyleChange(fillProperty, "transparent");
399
+ }
400
+ }}
401
+ >
402
+ <IconMinus className="size-3.5" />
403
+ </SectionIconButton>
404
+ {!isTextFillElement ? (
405
+ <FieldTrailer
406
+ element={element}
407
+ motionCssProperty="background-color"
408
+ motionKeyframeContext={motionKeyframeContext}
409
+ breakpointOverrideContext={breakpointOverrideContext}
410
+ hoverRevealClassName="opacity-0 group-hover:opacity-100"
411
+ />
412
+ ) : null}
413
+ </div>
414
+ ) : null}
415
+ {!isTextFillElement
416
+ ? backgroundLayers.map((layer, index) => {
417
+ const gradient = parseGradientLayer(layer);
418
+ // Hidden state lives in the real, persisted backgroundSize
419
+ // marker (see withLayerSizeMarker) rather than React state,
420
+ // so it survives deselect/reselect. Opacity still reflects
421
+ // the gradient's own stop opacities for display, but no
422
+ // longer drives hide/show — a layer can be a fully-opaque
423
+ // gradient and still be hidden via zero-size.
424
+ const hidden = isLayerHiddenBySize(backgroundSizeLayers[index]);
425
+ const opacity = gradient
426
+ ? averageGradientOpacity(gradient.stops)
427
+ : 100;
428
+ const label = gradient
429
+ ? `${gradientLabel(gradient.type)} ${index + 1}`
430
+ : `${"Image" /* i18n-ignore design inspector paint row */} ${
431
+ index + 1
432
+ }`;
433
+ const replaceLayer = (nextLayer: string) => {
434
+ const nextLayers = [...backgroundLayers];
435
+ nextLayers[index] = nextLayer;
436
+ onStyleChange("backgroundImage", joinCssLayers(nextLayers));
437
+ };
438
+ // Remove one fill layer by index. Mirrors reorderFillLayers:
439
+ // all four index-aligned parallel arrays (image/size/repeat/
440
+ // position) must be spliced together and committed as one
441
+ // patch (see removeFillLayerAtIndex), or the arrays fall out
442
+ // of alignment for every layer after the removed index (each
443
+ // remaining layer's size ends up paired with the next
444
+ // layer's repeat/position). The previous version only
445
+ // filtered backgroundImage and backgroundSize, silently
446
+ // leaving backgroundRepeat and backgroundPosition
447
+ // unfiltered/misaligned.
448
+ const removeLayer = () => {
449
+ const patch = removeFillLayerAtIndex(
450
+ {
451
+ backgroundImage: backgroundLayers,
452
+ backgroundSize: backgroundSizeLayers,
453
+ backgroundRepeat: backgroundRepeatLayers,
454
+ backgroundPosition: backgroundPositionLayers,
455
+ },
456
+ index,
457
+ );
458
+ if (onStylesChange) {
459
+ onStylesChange(patch);
460
+ return;
461
+ }
462
+ Object.entries(patch).forEach(([property, value]) =>
463
+ onStyleChange(property, value),
464
+ );
465
+ };
466
+ const setLayerHidden = (nextHidden: boolean) => {
467
+ onStyleChange(
468
+ "backgroundSize",
469
+ withLayerSizeMarker(
470
+ backgroundSizeLayers,
471
+ backgroundLayers.length,
472
+ index,
473
+ nextHidden,
474
+ ),
475
+ );
476
+ };
477
+
478
+ return (
479
+ /* design row: [grip] [swatch+label+opacity% trigger (flex-1)] [eye] [remove] */
480
+ <div
481
+ key={`${layer}-${index}`}
482
+ className="group relative flex items-center gap-1.5"
483
+ {...fillDrag.getRowProps(index)}
484
+ >
485
+ <RowDragHandle
486
+ label={t("editPanel.labels.reorderLayer")}
487
+ dropIndicator={
488
+ fillDrag.dragIndex != null &&
489
+ fillDrag.overIndex === index
490
+ ? fillDrag.overIndex > fillDrag.dragIndex
491
+ ? "after"
492
+ : "before"
493
+ : null
494
+ }
495
+ {...fillDrag.getHandleProps(index)}
496
+ />
497
+ <Popover>
498
+ <PopoverTrigger asChild>
499
+ <button
500
+ type="button"
501
+ className="flex h-6 min-w-0 flex-1 items-center gap-1.5 rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-1.5 text-left !text-[11px] hover:bg-[var(--design-editor-panel-raised-bg)]"
502
+ >
503
+ <span
504
+ className="size-4 shrink-0 rounded-sm border border-[var(--design-editor-control-border)]"
505
+ style={swatchStyle(layer)}
506
+ />
507
+ <span className="min-w-0 flex-1 truncate font-medium text-foreground">
508
+ {label}
509
+ </span>
510
+ <span className="shrink-0 tabular-nums text-muted-foreground">
511
+ {hidden ? 0 : opacity}%
512
+ </span>
513
+ </button>
514
+ </PopoverTrigger>
515
+ <PopoverContent
516
+ side="left"
517
+ align="start"
518
+ sideOffset={8}
519
+ className="w-80 p-0"
520
+ >
521
+ <DesignColorPicker
522
+ value={layer}
523
+ onPaintValueChange={replaceLayer}
524
+ onChange={(nextColor) => {
525
+ if (!gradient) return;
526
+ const firstStop = gradient.stops[0];
527
+ if (!firstStop) return;
528
+ replaceLayer(
529
+ buildGradientLayer(
530
+ gradient.type,
531
+ [
532
+ { ...firstStop, color: nextColor },
533
+ ...gradient.stops.slice(1),
534
+ ],
535
+ gradient.prefix,
536
+ ),
537
+ );
538
+ }}
539
+ paintType={gradient?.type ?? "image"}
540
+ backgroundImage={layer}
541
+ backgroundSize={backgroundSizeLayers[index]}
542
+ backgroundRepeat={backgroundRepeatLayers[index]}
543
+ backgroundPosition={backgroundPositionLayers[index]}
544
+ gradientType={gradient?.type}
545
+ onGradientTypeChange={(type) => {
546
+ if (!gradient) return;
547
+ replaceLayer(
548
+ buildGradientLayer(type, gradient.stops),
549
+ );
550
+ }}
551
+ fillRows={[
552
+ {
553
+ id: `layer-${index}`,
554
+ label,
555
+ value: layer,
556
+ type: gradient ? "gradient" : "image",
557
+ selected: true,
558
+ swatch: layer,
559
+ },
560
+ ]}
561
+ selectedFillId={`layer-${index}`}
562
+ />
563
+ </PopoverContent>
564
+ </Popover>
565
+ <SectionIconButton
566
+ label={
567
+ hidden
568
+ ? t("editPanel.labels.showLayer")
569
+ : t("editPanel.labels.hideLayer")
570
+ }
571
+ onClick={() => setLayerHidden(!hidden)}
572
+ activateOnPointerDown
573
+ >
574
+ {hidden ? (
575
+ <IconEyeOff className="size-3.5" />
576
+ ) : (
577
+ <IconEye className="size-3.5" />
578
+ )}
579
+ </SectionIconButton>
580
+ <SectionIconButton
581
+ label={t("editPanel.labels.removeLayer")}
582
+ onClick={removeLayer}
583
+ >
584
+ <IconMinus className="size-3.5" />
585
+ </SectionIconButton>
586
+ </div>
587
+ );
588
+ })
589
+ : null}
590
+ </div>
591
+ ) : null}
592
+ </PanelSection>
593
+ );
594
+ }