@agent-native/core 0.117.1 → 0.117.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 (347) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +10 -0
  3. package/corpus/core/package.json +2 -1
  4. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  5. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +4 -4
  6. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
  7. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  8. package/corpus/core/src/client/extensions/delete-extension.ts +2 -2
  9. package/corpus/core/src/client/org/OrgSwitcher.tsx +25 -1
  10. package/corpus/core/src/client/settings/SettingsPanel.tsx +102 -10
  11. package/corpus/core/src/client/sharing/ShareButton.tsx +7 -6
  12. package/corpus/core/src/db/client.ts +13 -10
  13. package/corpus/core/src/extensions/actions.ts +13 -5
  14. package/corpus/core/src/extensions/local.ts +1 -0
  15. package/corpus/core/src/extensions/routes.ts +10 -5
  16. package/corpus/core/src/extensions/schema.ts +5 -0
  17. package/corpus/core/src/extensions/slots/store.ts +14 -4
  18. package/corpus/core/src/extensions/store.ts +55 -19
  19. package/corpus/core/src/extensions/theme.ts +1 -1
  20. package/corpus/core/src/file-upload/registry.ts +9 -0
  21. package/corpus/core/src/index.browser.ts +5 -0
  22. package/corpus/core/src/index.ts +1 -0
  23. package/corpus/core/src/localization/default-messages.ts +23 -6
  24. package/corpus/core/src/server/action-discovery.ts +8 -0
  25. package/corpus/core/src/server/better-auth-instance.ts +7 -2
  26. package/corpus/core/src/server/email-template.ts +18 -0
  27. package/corpus/core/src/server/email-templates.ts +3 -0
  28. package/corpus/core/src/server/email.ts +40 -4
  29. package/corpus/core/src/sharing/actions/share-resource.ts +1 -0
  30. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  31. package/corpus/core/src/templates/default/app/global.css +1 -1
  32. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
  33. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
  34. package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
  35. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
  36. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
  37. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
  38. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
  39. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
  40. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
  41. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +7 -7
  42. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +7 -7
  43. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  45. package/corpus/core/src/user-profile/actions/get-user-profile.ts +16 -0
  46. package/corpus/core/src/user-profile/actions/update-user-profile.ts +24 -0
  47. package/corpus/core/src/user-profile/index.ts +5 -0
  48. package/corpus/core/src/user-profile/shared.ts +14 -0
  49. package/corpus/core/src/user-profile/store.ts +50 -0
  50. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  51. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  52. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
  53. package/corpus/templates/assets/app/global.css +1 -1
  54. package/corpus/templates/assets/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  55. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  56. package/corpus/templates/brain/app/global.css +2 -2
  57. package/corpus/templates/brain/app/lib/brain.ts +2 -2
  58. package/corpus/templates/brain/app/root.tsx +2 -2
  59. package/corpus/templates/brain/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  60. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  61. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +6 -2
  62. package/corpus/templates/calendar/app/global.css +1 -1
  63. package/corpus/templates/calendar/app/root.tsx +2 -2
  64. package/corpus/templates/calendar/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  65. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  66. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  67. package/corpus/templates/chat/app/global.css +1 -1
  68. package/corpus/templates/chat/app/root.tsx +2 -2
  69. package/corpus/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  70. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  71. package/corpus/templates/clips/actions/export-to-brain.ts +1 -1
  72. package/corpus/templates/clips/actions/invite-member.ts +1 -0
  73. package/corpus/templates/clips/app/components/library/library-layout.tsx +2 -2
  74. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -11
  75. package/corpus/templates/clips/app/global.css +1 -1
  76. package/corpus/templates/clips/app/root.tsx +7 -2
  77. package/corpus/templates/clips/app/routes/record.tsx +2 -88
  78. package/corpus/templates/clips/changelog/2026-07-22-builder-connected-recordings-start-resumable-upload-sessions.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-22-clip-thumbnails-now-come-from-the-recording-instead-of-the-p.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-22-clips-emails-now-render-the-agent-native-logo-in-gmail-and-o.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-22-dismissed-zoom-and-teams-meeting-note-prompts-now-stay-dismi.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-22-quieter-permissions-and-rewind-controls.md +6 -0
  84. package/corpus/templates/clips/desktop/src/app.tsx +86 -52
  85. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +31 -0
  86. package/corpus/templates/clips/desktop/src/lib/recorder.ts +4 -167
  87. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +10 -1
  88. package/corpus/templates/clips/desktop/src/styles.css +98 -36
  89. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +67 -4
  90. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -1
  91. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +51 -0
  92. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +5 -1
  93. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +0 -189
  94. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -0
  95. package/corpus/templates/clips/server/plugins/db.ts +6 -2
  96. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  97. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -3
  98. package/corpus/templates/content/app/global.css +1 -1
  99. package/corpus/templates/content/app/root.tsx +2 -2
  100. package/corpus/templates/content/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  101. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  102. package/corpus/templates/crm/app/global.css +1 -1
  103. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  104. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +19 -1
  105. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +12 -1
  106. package/corpus/templates/design/app/components/design/EditPanel.tsx +177 -52
  107. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +179 -59
  108. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +74 -27
  109. package/corpus/templates/design/app/components/design/multi-screen/types.ts +2 -0
  110. package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -2
  111. package/corpus/templates/design/app/global.css +1 -1
  112. package/corpus/templates/design/app/hooks/use-navigation-state.ts +6 -5
  113. package/corpus/templates/design/app/root.tsx +2 -2
  114. package/corpus/templates/design/changelog/2026-07-22-design-owners-can-keep-editing-their-designs-after-switching.md +6 -0
  115. package/corpus/templates/design/changelog/2026-07-22-inspector-tabs-keep-their-text-labels-at-narrow-widths.md +6 -0
  116. package/corpus/templates/design/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  117. package/corpus/templates/design/changelog/2026-07-22-narrow-breakpoint-previews-keep-their-device-labels-readable.md +6 -0
  118. package/corpus/templates/design/changelog/2026-07-22-removed-the-draft-status-chip-from-the-design-editor.md +6 -0
  119. package/corpus/templates/design/changelog/2026-07-22-responsive-breakpoint-controls-stay-within-narrow-sidebars.md +6 -0
  120. package/corpus/templates/design/changelog/2026-07-22-responsive-peers-now-use-a-softer-selection-highlight-withou.md +6 -0
  121. package/corpus/templates/design/changelog/2026-07-22-rotate-from-context-menu.md +6 -0
  122. package/corpus/templates/design/changelog/2026-07-22-the-selection-outline-now-stays-attached-while-moving-screen.md +6 -0
  123. package/corpus/templates/design/changelog/2026-07-22-view-only-designs-now-support-figma-style-layer-inspection-w.md +6 -0
  124. package/corpus/templates/design/server/db/index.ts +4 -0
  125. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  126. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +2 -2
  127. package/corpus/templates/dispatch/app/global.css +1 -1
  128. package/corpus/templates/dispatch/app/root.tsx +2 -2
  129. package/corpus/templates/dispatch/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  130. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  131. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -1
  132. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +3 -3
  133. package/corpus/templates/forms/app/global.css +1 -1
  134. package/corpus/templates/forms/app/hooks/use-forms.ts +55 -2
  135. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  136. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +3 -3
  137. package/corpus/templates/forms/app/pages/FormsListPage.tsx +23 -6
  138. package/corpus/templates/forms/app/root.tsx +2 -2
  139. package/corpus/templates/forms/changelog/2026-07-22-forms-now-archive-with-optimistic-feedback.md +6 -0
  140. package/corpus/templates/forms/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  141. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
  142. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  143. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  144. package/corpus/templates/macros/app/root.tsx +2 -2
  145. package/corpus/templates/macros/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  146. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  147. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +3 -3
  148. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +2 -2
  149. package/corpus/templates/mail/app/global.css +1 -1
  150. package/corpus/templates/mail/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  151. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  152. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -2
  153. package/corpus/templates/plan/app/global.css +1 -1
  154. package/corpus/templates/plan/app/root.tsx +2 -2
  155. package/corpus/templates/plan/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  156. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  157. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +2 -2
  158. package/corpus/templates/slides/app/root.tsx +2 -2
  159. package/corpus/templates/slides/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  160. package/corpus/templates/slides/changelog/2026-07-22-slides-no-longer-fail-intermittently-on-fresh-server-instances.md +6 -0
  161. package/corpus/templates/slides/changelog/2026-07-22-uploaded-screenshots-can-now-be-analyzed-and-recreated-as-ed.md +6 -0
  162. package/corpus/templates/slides/server/lib/chat-attachments.ts +7 -3
  163. package/corpus/templates/slides/server/plugins/db.ts +44 -17
  164. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  165. package/corpus/templates/tasks/app/global.css +1 -1
  166. package/dist/cli/context-xray-local.js +1 -1
  167. package/dist/cli/context-xray-local.js.map +1 -1
  168. package/dist/client/extensions/ExtensionViewer.js +2 -2
  169. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  170. package/dist/client/extensions/ExtensionsSidebarSection.js +11 -11
  171. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  172. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  173. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  174. package/dist/client/extensions/delete-extension.d.ts +1 -1
  175. package/dist/client/extensions/delete-extension.d.ts.map +1 -1
  176. package/dist/client/extensions/delete-extension.js +1 -1
  177. package/dist/client/extensions/delete-extension.js.map +1 -1
  178. package/dist/client/org/OrgSwitcher.d.ts +3 -1
  179. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  180. package/dist/client/org/OrgSwitcher.js +12 -4
  181. package/dist/client/org/OrgSwitcher.js.map +1 -1
  182. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  183. package/dist/client/settings/SettingsPanel.js +37 -4
  184. package/dist/client/settings/SettingsPanel.js.map +1 -1
  185. package/dist/client/sharing/ShareButton.d.ts +3 -4
  186. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  187. package/dist/client/sharing/ShareButton.js +3 -2
  188. package/dist/client/sharing/ShareButton.js.map +1 -1
  189. package/dist/collab/awareness.d.ts +2 -2
  190. package/dist/collab/awareness.d.ts.map +1 -1
  191. package/dist/db/client.d.ts +7 -7
  192. package/dist/db/client.d.ts.map +1 -1
  193. package/dist/db/client.js +13 -10
  194. package/dist/db/client.js.map +1 -1
  195. package/dist/extensions/actions.d.ts.map +1 -1
  196. package/dist/extensions/actions.js +8 -5
  197. package/dist/extensions/actions.js.map +1 -1
  198. package/dist/extensions/local.d.ts.map +1 -1
  199. package/dist/extensions/local.js +1 -0
  200. package/dist/extensions/local.js.map +1 -1
  201. package/dist/extensions/routes.d.ts.map +1 -1
  202. package/dist/extensions/routes.js +9 -4
  203. package/dist/extensions/routes.js.map +1 -1
  204. package/dist/extensions/schema.d.ts +23 -2
  205. package/dist/extensions/schema.d.ts.map +1 -1
  206. package/dist/extensions/schema.js +5 -0
  207. package/dist/extensions/schema.js.map +1 -1
  208. package/dist/extensions/slots/store.d.ts +1 -1
  209. package/dist/extensions/slots/store.d.ts.map +1 -1
  210. package/dist/extensions/slots/store.js +4 -4
  211. package/dist/extensions/slots/store.js.map +1 -1
  212. package/dist/extensions/store.d.ts +1 -0
  213. package/dist/extensions/store.d.ts.map +1 -1
  214. package/dist/extensions/store.js +38 -21
  215. package/dist/extensions/store.js.map +1 -1
  216. package/dist/extensions/theme.js +1 -1
  217. package/dist/extensions/theme.js.map +1 -1
  218. package/dist/file-upload/registry.d.ts.map +1 -1
  219. package/dist/file-upload/registry.js +9 -0
  220. package/dist/file-upload/registry.js.map +1 -1
  221. package/dist/index.browser.d.ts +1 -0
  222. package/dist/index.browser.d.ts.map +1 -1
  223. package/dist/index.browser.js +1 -0
  224. package/dist/index.browser.js.map +1 -1
  225. package/dist/index.d.ts +1 -0
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +1 -0
  228. package/dist/index.js.map +1 -1
  229. package/dist/localization/default-messages.d.ts +16 -0
  230. package/dist/localization/default-messages.d.ts.map +1 -1
  231. package/dist/localization/default-messages.js +22 -6
  232. package/dist/localization/default-messages.js.map +1 -1
  233. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  234. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  235. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  236. package/dist/secrets/routes.d.ts +6 -6
  237. package/dist/server/action-discovery.d.ts.map +1 -1
  238. package/dist/server/action-discovery.js +8 -0
  239. package/dist/server/action-discovery.js.map +1 -1
  240. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  241. package/dist/server/better-auth-instance.d.ts +7 -2
  242. package/dist/server/better-auth-instance.d.ts.map +1 -1
  243. package/dist/server/better-auth-instance.js.map +1 -1
  244. package/dist/server/email-template.d.ts +3 -0
  245. package/dist/server/email-template.d.ts.map +1 -1
  246. package/dist/server/email-template.js +13 -0
  247. package/dist/server/email-template.js.map +1 -1
  248. package/dist/server/email-templates.d.ts.map +1 -1
  249. package/dist/server/email-templates.js +3 -0
  250. package/dist/server/email-templates.js.map +1 -1
  251. package/dist/server/email.d.ts.map +1 -1
  252. package/dist/server/email.js +27 -4
  253. package/dist/server/email.js.map +1 -1
  254. package/dist/sharing/actions/share-resource.js +1 -0
  255. package/dist/sharing/actions/share-resource.js.map +1 -1
  256. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  257. package/dist/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  258. package/dist/templates/chat/app/global.css +1 -1
  259. package/dist/templates/chat/app/root.tsx +2 -2
  260. package/dist/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  261. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  262. package/dist/templates/default/app/global.css +1 -1
  263. package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
  264. package/dist/templates/default/app/i18n/de-DE.ts +6 -6
  265. package/dist/templates/default/app/i18n/en-US.ts +6 -6
  266. package/dist/templates/default/app/i18n/es-ES.ts +6 -6
  267. package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
  268. package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
  269. package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
  270. package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
  271. package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
  272. package/dist/templates/default/app/i18n/zh-CN.ts +7 -7
  273. package/dist/templates/default/app/i18n/zh-TW.ts +7 -7
  274. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  275. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  276. package/dist/user-profile/actions/get-user-profile.d.ts +4 -0
  277. package/dist/user-profile/actions/get-user-profile.d.ts.map +1 -0
  278. package/dist/user-profile/actions/get-user-profile.js +14 -0
  279. package/dist/user-profile/actions/get-user-profile.js.map +1 -0
  280. package/dist/user-profile/actions/update-user-profile.d.ts +6 -0
  281. package/dist/user-profile/actions/update-user-profile.d.ts.map +1 -0
  282. package/dist/user-profile/actions/update-user-profile.js +20 -0
  283. package/dist/user-profile/actions/update-user-profile.js.map +1 -0
  284. package/dist/user-profile/index.d.ts +2 -0
  285. package/dist/user-profile/index.d.ts.map +1 -0
  286. package/dist/user-profile/index.js +2 -0
  287. package/dist/user-profile/index.js.map +1 -0
  288. package/dist/user-profile/shared.d.ts +7 -0
  289. package/dist/user-profile/shared.d.ts.map +1 -0
  290. package/dist/user-profile/shared.js +6 -0
  291. package/dist/user-profile/shared.js.map +1 -0
  292. package/dist/user-profile/store.d.ts +4 -0
  293. package/dist/user-profile/store.d.ts.map +1 -0
  294. package/dist/user-profile/store.js +38 -0
  295. package/dist/user-profile/store.js.map +1 -0
  296. package/package.json +2 -1
  297. package/src/cli/context-xray-local.ts +1 -1
  298. package/src/client/extensions/ExtensionViewer.tsx +4 -4
  299. package/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
  300. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  301. package/src/client/extensions/delete-extension.ts +2 -2
  302. package/src/client/org/OrgSwitcher.tsx +25 -1
  303. package/src/client/settings/SettingsPanel.tsx +102 -10
  304. package/src/client/sharing/ShareButton.tsx +7 -6
  305. package/src/db/client.ts +13 -10
  306. package/src/extensions/actions.ts +13 -5
  307. package/src/extensions/local.ts +1 -0
  308. package/src/extensions/routes.ts +10 -5
  309. package/src/extensions/schema.ts +5 -0
  310. package/src/extensions/slots/store.ts +14 -4
  311. package/src/extensions/store.ts +55 -19
  312. package/src/extensions/theme.ts +1 -1
  313. package/src/file-upload/registry.ts +9 -0
  314. package/src/index.browser.ts +5 -0
  315. package/src/index.ts +1 -0
  316. package/src/localization/default-messages.ts +23 -6
  317. package/src/server/action-discovery.ts +8 -0
  318. package/src/server/better-auth-instance.ts +7 -2
  319. package/src/server/email-template.ts +18 -0
  320. package/src/server/email-templates.ts +3 -0
  321. package/src/server/email.ts +40 -4
  322. package/src/sharing/actions/share-resource.ts +1 -0
  323. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  324. package/src/templates/chat/app/components/layout/Sidebar.tsx +2 -2
  325. package/src/templates/chat/app/global.css +1 -1
  326. package/src/templates/chat/app/root.tsx +2 -2
  327. package/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  328. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  329. package/src/templates/default/app/global.css +1 -1
  330. package/src/templates/default/app/i18n/ar-SA.ts +6 -6
  331. package/src/templates/default/app/i18n/de-DE.ts +6 -6
  332. package/src/templates/default/app/i18n/en-US.ts +6 -6
  333. package/src/templates/default/app/i18n/es-ES.ts +6 -6
  334. package/src/templates/default/app/i18n/fr-FR.ts +6 -6
  335. package/src/templates/default/app/i18n/hi-IN.ts +6 -6
  336. package/src/templates/default/app/i18n/ja-JP.ts +6 -6
  337. package/src/templates/default/app/i18n/ko-KR.ts +6 -6
  338. package/src/templates/default/app/i18n/pt-BR.ts +6 -6
  339. package/src/templates/default/app/i18n/zh-CN.ts +7 -7
  340. package/src/templates/default/app/i18n/zh-TW.ts +7 -7
  341. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  342. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  343. package/src/user-profile/actions/get-user-profile.ts +16 -0
  344. package/src/user-profile/actions/update-user-profile.ts +24 -0
  345. package/src/user-profile/index.ts +5 -0
  346. package/src/user-profile/shared.ts +14 -0
  347. package/src/user-profile/store.ts +50 -0
@@ -406,6 +406,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
406
406
  pendingReviewScreenIds = EMPTY_SCREEN_IDS,
407
407
  onReviewPendingScreen,
408
408
  interactMode = false,
409
+ readOnly = false,
409
410
  activeScreenHasHoveredChild = false,
410
411
  hoveredChildScreenId,
411
412
  directlyHoveredScreenId,
@@ -487,6 +488,13 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
487
488
  const [surfaceSize, setSurfaceSize] = useState({ width: 0, height: 0 });
488
489
  const [frameGeometry, setFrameGeometry] = useState<FrameGeometryById>({});
489
490
  const frameGeometryRef = useRef(frameGeometry);
491
+ const liveFrameDragPositionsRef = useRef(
492
+ new Map<string, { left: number; top: number }>(),
493
+ );
494
+ const liveFrameDragSelectionPositionRef = useRef<{
495
+ left: number;
496
+ top: number;
497
+ } | null>(null);
490
498
  const onGeometryChangeRef = useRef(onGeometryChange);
491
499
  const onGeometryCommitRef = useRef(onGeometryCommit);
492
500
  const screensRef = useRef(screens);
@@ -1162,6 +1170,29 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
1162
1170
  frameGeometryRef.current = frameGeometry;
1163
1171
  }, [frameGeometry]);
1164
1172
 
1173
+ // Frame drags update the shell and selection box imperatively between React
1174
+ // commits. Reapply the live box position after any feedback-driven commit
1175
+ // so alignment guides or transform badges cannot paint stale geometry over
1176
+ // the moving outline.
1177
+ useLayoutEffect(() => {
1178
+ for (const [id, position] of liveFrameDragPositionsRef.current) {
1179
+ const frame = surfaceRef.current?.querySelector<HTMLElement>(
1180
+ `[data-frame-id="${CSS.escape(id)}"]`,
1181
+ );
1182
+ if (!frame) continue;
1183
+ frame.style.left = `${position.left}px`;
1184
+ frame.style.top = `${position.top}px`;
1185
+ }
1186
+ const position = liveFrameDragSelectionPositionRef.current;
1187
+ if (!position) return;
1188
+ const selectionBox = surfaceRef.current?.querySelector<HTMLElement>(
1189
+ "[data-frame-selection-box]",
1190
+ );
1191
+ if (!selectionBox) return;
1192
+ selectionBox.style.left = `${position.left}px`;
1193
+ selectionBox.style.top = `${position.top}px`;
1194
+ });
1195
+
1165
1196
  const onSelectionChangeRef = useRef(onSelectionChange);
1166
1197
  useEffect(() => {
1167
1198
  onSelectionChangeRef.current = onSelectionChange;
@@ -2524,6 +2555,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
2524
2555
  ]);
2525
2556
 
2526
2557
  const deleteSelectedItems = useCallback(() => {
2558
+ if (readOnly) return false;
2527
2559
  const frameIds = selectedIdsRef.current.filter(
2528
2560
  (id) => frameGeometryRef.current[id],
2529
2561
  );
@@ -2563,6 +2595,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
2563
2595
  return true;
2564
2596
  }, [
2565
2597
  onDeleteSelection,
2598
+ readOnly,
2566
2599
  updateDraftPrimitives,
2567
2600
  updateFrameGeometry,
2568
2601
  updateSelectedDraftIds,
@@ -2939,6 +2972,8 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
2939
2972
  feedbackTimerRef.current = null;
2940
2973
  }
2941
2974
  dragState.current = null;
2975
+ liveFrameDragPositionsRef.current.clear();
2976
+ liveFrameDragSelectionPositionRef.current = null;
2942
2977
  setIsDragging(false);
2943
2978
  setIsPanning(false);
2944
2979
  setMarquee(null);
@@ -4303,6 +4338,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
4303
4338
 
4304
4339
  const beginDraftDrag = useCallback(
4305
4340
  (id: string, e: React.MouseEvent) => {
4341
+ if (readOnly) return;
4306
4342
  if (e.button !== 0 || e.shiftKey) return;
4307
4343
  e.preventDefault();
4308
4344
  e.stopPropagation();
@@ -4622,6 +4658,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
4622
4658
 
4623
4659
  const beginDraftResize = useCallback(
4624
4660
  (id: string, handle: ResizeHandle, e: React.MouseEvent) => {
4661
+ if (readOnly) return;
4625
4662
  if (e.button !== 0) return;
4626
4663
  e.preventDefault();
4627
4664
  e.stopPropagation();
@@ -4863,6 +4900,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
4863
4900
 
4864
4901
  const beginFrameDrag = useCallback(
4865
4902
  (id: string, e: React.MouseEvent) => {
4903
+ if (readOnly) return;
4866
4904
  if (e.button !== 0 || e.shiftKey || lockedScreenIdSet.has(id)) return;
4867
4905
  e.preventDefault();
4868
4906
  e.stopPropagation();
@@ -4931,15 +4969,23 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
4931
4969
  const frameLabelHeight =
4932
4970
  FRAME_LABEL_HEIGHT * chromeScaleFromZoom(zoomRef.current);
4933
4971
  const draggedFrameEls = new Map<string, HTMLElement>();
4972
+ const draggedFrameOriginPositions = new Map<
4973
+ string,
4974
+ { left: number; top: number }
4975
+ >();
4934
4976
  targetIds.forEach((targetId) => {
4935
4977
  const el = surfaceRef.current?.querySelector<HTMLElement>(
4936
4978
  `[data-frame-id="${CSS.escape(targetId)}"]`,
4937
4979
  );
4938
- if (el) draggedFrameEls.set(targetId, el);
4980
+ if (!el) return;
4981
+ draggedFrameEls.set(targetId, el);
4939
4982
  });
4940
- const selectionBoxEl = surfaceRef.current?.querySelector<HTMLElement>(
4941
- "[data-frame-selection-box]",
4942
- );
4983
+ // Selecting an unselected screen mounts the SelectionBox after this
4984
+ // callback returns. Resolve it on the first live move instead of
4985
+ // caching null at drag start, then keep the lookup out of later ticks.
4986
+ let selectionBoxEl: HTMLElement | null = null;
4987
+ let selectionBoxOriginPosition: { left: number; top: number } | null =
4988
+ null;
4943
4989
 
4944
4990
  const handleMouseMove = (ev: MouseEvent) => {
4945
4991
  const state = dragState.current;
@@ -5023,42 +5069,60 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5023
5069
  const geometry = settledGeometryById[targetId];
5024
5070
  const el = draggedFrameEls.get(targetId);
5025
5071
  if (!geometry || !el) return;
5026
- const { left, top } = frameStyleLeftTop(geometry, frameLabelHeight);
5027
- el.style.left = `${left}px`;
5028
- el.style.top = `${top}px`;
5072
+ let originPosition = draggedFrameOriginPositions.get(targetId);
5073
+ if (!originPosition) {
5074
+ const fallback = frameStyleLeftTop(
5075
+ state.originFrames[targetId],
5076
+ frameLabelHeight,
5077
+ );
5078
+ const renderedLeft = Number.parseFloat(el.style.left);
5079
+ const renderedTop = Number.parseFloat(el.style.top);
5080
+ originPosition = {
5081
+ left: Number.isFinite(renderedLeft)
5082
+ ? renderedLeft
5083
+ : fallback.left,
5084
+ top: Number.isFinite(renderedTop) ? renderedTop : fallback.top,
5085
+ };
5086
+ draggedFrameOriginPositions.set(targetId, originPosition);
5087
+ }
5088
+ if (!originPosition) return;
5089
+ const moveX = dx + snap.dx;
5090
+ const moveY = dy + snap.dy;
5091
+ const nextPosition = {
5092
+ left: originPosition.left + moveX,
5093
+ top: originPosition.top + moveY,
5094
+ };
5095
+ liveFrameDragPositionsRef.current.set(targetId, nextPosition);
5096
+ el.style.left = `${nextPosition.left}px`;
5097
+ el.style.top = `${nextPosition.top}px`;
5029
5098
  });
5030
5099
  // Keep the selection outline + resize/rotate handles glued to the
5031
5100
  // dragged frame — SelectionBox's own `geometry` prop only updates
5032
5101
  // on the next real React render, which this tick intentionally
5033
5102
  // skips (see above), so without this it would visually detach and
5034
5103
  // trail behind during the drag.
5104
+ if (!selectionBoxEl) {
5105
+ selectionBoxEl =
5106
+ surfaceRef.current?.querySelector<HTMLElement>(
5107
+ "[data-frame-selection-box]",
5108
+ ) ?? null;
5109
+ }
5035
5110
  if (selectionBoxEl) {
5036
- const targetGeometries = state.targetIds.map(
5037
- (targetId) => settledGeometryById[targetId],
5038
- );
5039
- const bounds =
5040
- targetGeometries.length === 1
5041
- ? targetGeometries[0]
5042
- : (() => {
5043
- const groupBounds = getFrameGroupBounds(
5044
- targetGeometries.map((geometry) => ({
5045
- id: "",
5046
- geometry,
5047
- })),
5048
- );
5049
- return groupBounds
5050
- ? {
5051
- x: groupBounds.left,
5052
- y: groupBounds.top,
5053
- width: groupBounds.width,
5054
- height: groupBounds.height,
5055
- }
5056
- : null;
5057
- })();
5058
- if (bounds) {
5059
- const { left, top } = frameStyleLeftTop(bounds);
5060
- selectionBoxEl.style.left = `${left}px`;
5061
- selectionBoxEl.style.top = `${top}px`;
5111
+ if (!selectionBoxOriginPosition) {
5112
+ const left = Number.parseFloat(selectionBoxEl.style.left);
5113
+ const top = Number.parseFloat(selectionBoxEl.style.top);
5114
+ if (Number.isFinite(left) && Number.isFinite(top)) {
5115
+ selectionBoxOriginPosition = { left, top };
5116
+ }
5117
+ }
5118
+ if (selectionBoxOriginPosition) {
5119
+ const nextPosition = {
5120
+ left: selectionBoxOriginPosition.left + dx + snap.dx,
5121
+ top: selectionBoxOriginPosition.top + dy + snap.dy,
5122
+ };
5123
+ liveFrameDragSelectionPositionRef.current = nextPosition;
5124
+ selectionBoxEl.style.left = `${nextPosition.left}px`;
5125
+ selectionBoxEl.style.top = `${nextPosition.top}px`;
5062
5126
  }
5063
5127
  }
5064
5128
  }
@@ -5196,6 +5260,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5196
5260
  installDragListeners,
5197
5261
  lockedScreenIdSet,
5198
5262
  onPick,
5263
+ readOnly,
5199
5264
  resolvePrimitiveScreenId,
5200
5265
  showTransformFeedback,
5201
5266
  updateFrameGeometry,
@@ -5208,6 +5273,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5208
5273
 
5209
5274
  const beginResize = useCallback(
5210
5275
  (id: string, handle: ResizeHandle, e: React.MouseEvent) => {
5276
+ if (readOnly) return;
5211
5277
  if (e.button !== 0 || lockedScreenIdSet.has(id)) return;
5212
5278
  e.preventDefault();
5213
5279
  e.stopPropagation();
@@ -5597,6 +5663,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5597
5663
 
5598
5664
  const beginRotate = useCallback(
5599
5665
  (id: string, e: React.MouseEvent) => {
5666
+ if (readOnly) return;
5600
5667
  if (e.button !== 0 || lockedScreenIdSet.has(id)) return;
5601
5668
  e.preventDefault();
5602
5669
  e.stopPropagation();
@@ -5739,6 +5806,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5739
5806
  // beginRotate above — single-frame rotate is unaffected.
5740
5807
  const beginGroupRotate = useCallback(
5741
5808
  (e: React.MouseEvent) => {
5809
+ if (readOnly) return;
5742
5810
  if (e.button !== 0) return;
5743
5811
  e.preventDefault();
5744
5812
  e.stopPropagation();
@@ -5981,6 +6049,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
5981
6049
 
5982
6050
  const beginDuplicateGesture = useCallback(
5983
6051
  (screen: ScreenFile, display: string, e: React.MouseEvent<HTMLElement>) => {
6052
+ if (readOnly) return;
5984
6053
  if (e.button !== 0 || !e.altKey || lockedScreenIdSet.has(screen.id)) {
5985
6054
  return;
5986
6055
  }
@@ -6808,6 +6877,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
6808
6877
  useEffect(() => {
6809
6878
  const handleKeyDown = (event: KeyboardEvent) => {
6810
6879
  if (activePenPathRef.current) return;
6880
+ if (readOnly) return;
6811
6881
  if (!isArrowNudgeKey(event.key) || isEditableHotkeyTarget(event.target)) {
6812
6882
  return;
6813
6883
  }
@@ -6901,6 +6971,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
6901
6971
  };
6902
6972
  }, [
6903
6973
  getCurrentCanvasEntries,
6974
+ readOnly,
6904
6975
  scheduleFeedbackClear,
6905
6976
  updateDraftPrimitives,
6906
6977
  updateFrameGeometry,
@@ -6909,6 +6980,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
6909
6980
  useEffect(() => {
6910
6981
  const handleKeyDown = (event: KeyboardEvent) => {
6911
6982
  if (activePenPathRef.current) return;
6983
+ if (readOnly) return;
6912
6984
  if (
6913
6985
  (event.key !== "Delete" && event.key !== "Backspace") ||
6914
6986
  event.metaKey ||
@@ -6927,7 +6999,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
6927
6999
  return () => {
6928
7000
  window.removeEventListener("keydown", handleKeyDown, true);
6929
7001
  };
6930
- }, [deleteSelectedItems]);
7002
+ }, [deleteSelectedItems, readOnly]);
6931
7003
 
6932
7004
  useEffect(() => {
6933
7005
  const handleKeyDown = (event: KeyboardEvent) => {
@@ -7018,6 +7090,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7018
7090
  useEffect(() => {
7019
7091
  if (!onDuplicate) return;
7020
7092
  const handleKeyDown = (event: KeyboardEvent) => {
7093
+ if (readOnly) return;
7021
7094
  if (activePenPathRef.current) return;
7022
7095
  if (
7023
7096
  !(event.metaKey || event.ctrlKey) ||
@@ -7077,7 +7150,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7077
7150
  return () => {
7078
7151
  window.removeEventListener("keydown", handleKeyDown, true);
7079
7152
  };
7080
- }, [onDuplicate, screens]);
7153
+ }, [onDuplicate, readOnly, screens]);
7081
7154
 
7082
7155
  // Releasing Alt should clear the alt-hover measurement immediately even if
7083
7156
  // the mouse never moves again (e.g. the user just lifts the Alt key while
@@ -7101,8 +7174,9 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7101
7174
  useEffect(() => {
7102
7175
  effectiveToolRef.current = effectiveTool;
7103
7176
  }, [effectiveTool]);
7104
- const penActive = effectiveTool === "pen";
7105
- const creationToolActive = Boolean(getDraftCreationTool(effectiveTool));
7177
+ const penActive = !readOnly && effectiveTool === "pen";
7178
+ const creationToolActive =
7179
+ !readOnly && Boolean(getDraftCreationTool(effectiveTool));
7106
7180
  // PERF9-WHEEL: an in-flight wheel pan/zoom also mutes iframe pointer
7107
7181
  // events, but imperatively (see markWheelGestureActive) rather than via
7108
7182
  // this flag — flipping React state here at gesture start re-rendered every
@@ -7559,7 +7633,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7559
7633
  editorChromeScaleY={canvasZoom / 100}
7560
7634
  editMode={boardEditMode && !interactMode}
7561
7635
  interactMode={interactMode}
7562
- scaleMode={boardIsActive && effectiveTool === "scale"}
7636
+ scaleMode={
7637
+ !readOnly && boardIsActive && effectiveTool === "scale"
7638
+ }
7639
+ readOnly={readOnly}
7563
7640
  clearSelectionRequest={boardClearSelectionRequest}
7564
7641
  selectedSelector={
7565
7642
  boardIsActive ? (boardSelectedSelector ?? null) : null
@@ -7641,7 +7718,8 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7641
7718
  screen.id === hoveredChildScreenId
7642
7719
  }
7643
7720
  groupSelected={hasGroupSelection}
7644
- handlesEnabled={!hasGroupSelection}
7721
+ handlesEnabled={!hasGroupSelection && !readOnly}
7722
+ readOnly={readOnly}
7645
7723
  penActive={penActive}
7646
7724
  creationToolActive={creationToolActive}
7647
7725
  canvasGestureActive={canvasGestureActive}
@@ -7674,6 +7752,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7674
7752
  isSelected={selectedDraftIdSet.has(draft.id)}
7675
7753
  groupSelected={Boolean(selectedDraftGroupBounds)}
7676
7754
  penActive={penActive}
7755
+ readOnly={readOnly}
7677
7756
  chromeScale={chromeScale}
7678
7757
  chromeSettling={chromeSettling}
7679
7758
  onClick={handleDraftClick}
@@ -7689,6 +7768,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7689
7768
  preview
7690
7769
  groupSelected={false}
7691
7770
  penActive={penActive}
7771
+ readOnly={readOnly}
7692
7772
  chromeScale={chromeScale}
7693
7773
  chromeSettling={chromeSettling}
7694
7774
  onClick={() => {}}
@@ -7704,6 +7784,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7704
7784
  geometry={entry.geometry}
7705
7785
  chromeScale={chromeScale}
7706
7786
  chromeSettling={chromeSettling}
7787
+ showHandles={!readOnly}
7707
7788
  />
7708
7789
  ))
7709
7790
  : null}
@@ -7715,6 +7796,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7715
7796
  geometry={entry.geometry}
7716
7797
  chromeScale={chromeScale}
7717
7798
  chromeSettling={chromeSettling}
7799
+ showHandles={!readOnly}
7718
7800
  />
7719
7801
  ))
7720
7802
  : null}
@@ -7747,6 +7829,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7747
7829
  geometry={singleSelectedFrame.geometry}
7748
7830
  chromeScale={chromeScale}
7749
7831
  chromeSettling={chromeSettling}
7832
+ handlesEnabled={!readOnly}
7750
7833
  showRotate
7751
7834
  onStartResize={(handle, event) =>
7752
7835
  beginResize(singleSelectedFrame.id, handle, event)
@@ -7762,6 +7845,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7762
7845
  geometry={singleSelectedDraft.geometry}
7763
7846
  chromeScale={chromeScale}
7764
7847
  chromeSettling={chromeSettling}
7848
+ handlesEnabled={!readOnly}
7765
7849
  showRotate={false}
7766
7850
  onStartResize={(handle, event) =>
7767
7851
  beginDraftResize(singleSelectedDraft.id, handle, event)
@@ -7775,6 +7859,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7775
7859
  bounds={selectedGroupBounds}
7776
7860
  chromeScale={chromeScale}
7777
7861
  chromeSettling={chromeSettling}
7862
+ handlesEnabled={!readOnly}
7778
7863
  onStartResize={beginGroupResize}
7779
7864
  onStartRotate={beginGroupRotate}
7780
7865
  />
@@ -7785,6 +7870,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
7785
7870
  bounds={selectedDraftGroupBounds}
7786
7871
  chromeScale={chromeScale}
7787
7872
  chromeSettling={chromeSettling}
7873
+ handlesEnabled={!readOnly}
7788
7874
  onStartResize={beginDraftGroupResize}
7789
7875
  />
7790
7876
  ) : null}
@@ -8126,6 +8212,7 @@ function DraftPrimitiveLayer({
8126
8212
  isSelected,
8127
8213
  groupSelected,
8128
8214
  penActive,
8215
+ readOnly,
8129
8216
  chromeScale,
8130
8217
  chromeSettling,
8131
8218
  preview = false,
@@ -8137,6 +8224,7 @@ function DraftPrimitiveLayer({
8137
8224
  isSelected: boolean;
8138
8225
  groupSelected: boolean;
8139
8226
  penActive: boolean;
8227
+ readOnly: boolean;
8140
8228
  chromeScale: number;
8141
8229
  chromeSettling: boolean;
8142
8230
  preview?: boolean;
@@ -8180,6 +8268,10 @@ function DraftPrimitiveLayer({
8180
8268
  }}
8181
8269
  onMouseDown={(event) => {
8182
8270
  if (penActive) return;
8271
+ if (readOnly) {
8272
+ event.stopPropagation();
8273
+ return;
8274
+ }
8183
8275
  if (!preview) onStartDrag(draft.id, event);
8184
8276
  }}
8185
8277
  >
@@ -8206,7 +8298,7 @@ function DraftPrimitiveLayer({
8206
8298
  />
8207
8299
  <ResizeHandles
8208
8300
  active={preview}
8209
- enabled={!penActive && preview}
8301
+ enabled={!readOnly && !penActive && preview}
8210
8302
  showRotate={false}
8211
8303
  chromeScale={chromeScale}
8212
8304
  chromeSettling={chromeSettling}
@@ -8922,6 +9014,7 @@ interface ScreenProps {
8922
9014
  pendingReview: boolean;
8923
9015
  onReviewPendingScreen?: (screenId: string) => void;
8924
9016
  interactMode: boolean;
9017
+ readOnly: boolean;
8925
9018
  isDirectlyHovered: boolean;
8926
9019
  /** True while a native OS file drag is hovering this frame (Figma parity §1). */
8927
9020
  isFileDragOver: boolean;
@@ -8992,6 +9085,7 @@ const Screen = memo(function Screen({
8992
9085
  pendingReview,
8993
9086
  onReviewPendingScreen,
8994
9087
  interactMode,
9088
+ readOnly,
8995
9089
  isDirectlyHovered,
8996
9090
  isFileDragOver,
8997
9091
  hasHoveredChild,
@@ -9150,6 +9244,10 @@ const Screen = memo(function Screen({
9150
9244
  onMouseDown={(e) => {
9151
9245
  if (e.button !== 0) return;
9152
9246
  if (penActive || creationToolActive) return;
9247
+ if (readOnly) {
9248
+ e.stopPropagation();
9249
+ return;
9250
+ }
9153
9251
  if (e.altKey) {
9154
9252
  // Matches the data-screen-card mousedown handler below: without
9155
9253
  // this, a trailing click after the alt-drag/duplicate gesture
@@ -9307,6 +9405,10 @@ const Screen = memo(function Screen({
9307
9405
  return;
9308
9406
  }
9309
9407
  if (penActive) return;
9408
+ if (readOnly) {
9409
+ e.stopPropagation();
9410
+ return;
9411
+ }
9310
9412
  if (e.altKey && e.button === 0) {
9311
9413
  suppressNextClick.current = true;
9312
9414
  onStartDuplicateGesture(screen, display, e);
@@ -9555,6 +9657,7 @@ function areScreenPropsEqual(prev: ScreenProps, next: ScreenProps) {
9555
9657
  prev.isFileDragOver === next.isFileDragOver &&
9556
9658
  prev.hasHoveredChild === next.hasHoveredChild &&
9557
9659
  prev.groupSelected === next.groupSelected &&
9660
+ prev.readOnly === next.readOnly &&
9558
9661
  prev.handlesEnabled === next.handlesEnabled &&
9559
9662
  prev.penActive === next.penActive &&
9560
9663
  prev.creationToolActive === next.creationToolActive &&
@@ -9583,6 +9686,7 @@ function areScreenPropsEqual(prev: ScreenProps, next: ScreenProps) {
9583
9686
 
9584
9687
  /** Gap between adjacent breakpoint frames in canvas pixels. */
9585
9688
  const BREAKPOINT_FRAME_GAP = 24;
9689
+ const BREAKPOINT_LABEL_WITH_WIDTH_MIN_FRAME_WIDTH = 128;
9586
9690
 
9587
9691
  /**
9588
9692
  * Pure geometry helper for one breakpoint sub-frame (BP-DEEP item 3a): the
@@ -9733,6 +9837,8 @@ function BreakpointPreviewRow({
9733
9837
  });
9734
9838
  const currentOffsetX = offsetX;
9735
9839
  offsetX += frameWidth + BREAKPOINT_FRAME_GAP;
9840
+ const showBreakpointWidth =
9841
+ frameWidth >= BREAKPOINT_LABEL_WITH_WIDTH_MIN_FRAME_WIDTH;
9736
9842
  // BP-DEEP item 5 — clicking a frame in the group always SELECTS it
9737
9843
  // (never toggles it off): the Framer click-to-target model returns to
9738
9844
  // Base by clicking the base frame / empty canvas / Escape, not by
@@ -9839,9 +9945,14 @@ function BreakpointPreviewRow({
9839
9945
  >
9840
9946
  {breakpointLabel(widthPx)}
9841
9947
  </span>
9842
- <span className="shrink-0 text-[10px] tabular-nums text-muted-foreground/50">
9843
- {widthPx}px
9844
- </span>
9948
+ {showBreakpointWidth ? (
9949
+ <span
9950
+ data-breakpoint-width
9951
+ className="shrink-0 text-[10px] tabular-nums text-muted-foreground/50"
9952
+ >
9953
+ {widthPx}px
9954
+ </span>
9955
+ ) : null}
9845
9956
  </div>
9846
9957
  {/* Item 8b — "…" menu (Change width / Remove), reusing the
9847
9958
  exact affordance BreakpointDeviceControl already offers per
@@ -10152,6 +10263,7 @@ function GroupSelectionBox({
10152
10263
  chromeSettling,
10153
10264
  onStartResize,
10154
10265
  onStartRotate,
10266
+ handlesEnabled = true,
10155
10267
  }: {
10156
10268
  bounds: NonNullable<ReturnType<typeof getFrameGroupBounds>>;
10157
10269
  chromeScale: number;
@@ -10161,6 +10273,7 @@ function GroupSelectionBox({
10161
10273
  * rotate handle shown) — used by callers whose selection kind doesn't
10162
10274
  * support group rotate yet (e.g. draft primitives). */
10163
10275
  onStartRotate?: (e: React.MouseEvent) => void;
10276
+ handlesEnabled?: boolean;
10164
10277
  }) {
10165
10278
  return (
10166
10279
  <SelectionBox
@@ -10173,6 +10286,7 @@ function GroupSelectionBox({
10173
10286
  chromeScale={chromeScale}
10174
10287
  chromeSettling={chromeSettling}
10175
10288
  showRotate={!!onStartRotate}
10289
+ handlesEnabled={handlesEnabled}
10176
10290
  filled
10177
10291
  onStartResize={onStartResize}
10178
10292
  onStartRotate={onStartRotate ?? (() => {})}
@@ -10184,10 +10298,12 @@ function PassiveSelectionBox({
10184
10298
  geometry,
10185
10299
  chromeScale,
10186
10300
  chromeSettling,
10301
+ showHandles = true,
10187
10302
  }: {
10188
10303
  geometry: FrameGeometry;
10189
10304
  chromeScale: number;
10190
10305
  chromeSettling: boolean;
10306
+ showHandles?: boolean;
10191
10307
  }) {
10192
10308
  return (
10193
10309
  <div
@@ -10208,21 +10324,23 @@ function PassiveSelectionBox({
10208
10324
  zIndex: 999_999,
10209
10325
  }}
10210
10326
  >
10211
- {CORNER_RESIZE_HANDLE_CONFIGS.map((config) => (
10212
- <span
10213
- key={config.handle}
10214
- data-passive-resize-handle={config.handle}
10215
- className="pointer-events-none absolute z-20 rounded-[2px] border border-[var(--design-editor-accent-color)] bg-[var(--design-editor-accent-contrast-color)] shadow"
10216
- style={cornerHandleStyle(
10217
- config.handle,
10218
- config.cursor,
10219
- chromeScale,
10220
- chromeSettling,
10221
- geometry.width,
10222
- geometry.height,
10223
- )}
10224
- />
10225
- ))}
10327
+ {showHandles
10328
+ ? CORNER_RESIZE_HANDLE_CONFIGS.map((config) => (
10329
+ <span
10330
+ key={config.handle}
10331
+ data-passive-resize-handle={config.handle}
10332
+ className="pointer-events-none absolute z-20 rounded-[2px] border border-[var(--design-editor-accent-color)] bg-[var(--design-editor-accent-contrast-color)] shadow"
10333
+ style={cornerHandleStyle(
10334
+ config.handle,
10335
+ config.cursor,
10336
+ chromeScale,
10337
+ chromeSettling,
10338
+ geometry.width,
10339
+ geometry.height,
10340
+ )}
10341
+ />
10342
+ ))
10343
+ : null}
10226
10344
  </div>
10227
10345
  );
10228
10346
  }
@@ -10233,6 +10351,7 @@ function SelectionBox({
10233
10351
  chromeSettling,
10234
10352
  filled = false,
10235
10353
  showRotate = true,
10354
+ handlesEnabled = true,
10236
10355
  onStartResize,
10237
10356
  onStartRotate,
10238
10357
  }: {
@@ -10241,6 +10360,7 @@ function SelectionBox({
10241
10360
  chromeSettling: boolean;
10242
10361
  filled?: boolean;
10243
10362
  showRotate?: boolean;
10363
+ handlesEnabled?: boolean;
10244
10364
  onStartResize: (handle: ResizeHandle, e: React.MouseEvent) => void;
10245
10365
  onStartRotate: (e: React.MouseEvent) => void;
10246
10366
  }) {
@@ -10269,7 +10389,7 @@ function SelectionBox({
10269
10389
  >
10270
10390
  <ResizeHandles
10271
10391
  active
10272
- enabled
10392
+ enabled={handlesEnabled}
10273
10393
  showRotate={showRotate}
10274
10394
  chromeScale={chromeScale}
10275
10395
  chromeSettling={chromeSettling}