@agent-native/core 0.92.7 → 0.92.8

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 (289) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/docs/content/a2a-protocol.mdx +12 -0
  4. package/corpus/core/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
  5. package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
  6. package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
  7. package/corpus/core/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
  8. package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
  9. package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
  10. package/corpus/core/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
  11. package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
  12. package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
  13. package/corpus/core/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
  14. package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
  15. package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
  16. package/corpus/core/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
  17. package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
  18. package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
  19. package/corpus/core/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
  20. package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
  21. package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
  22. package/corpus/core/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
  23. package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
  24. package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
  25. package/corpus/core/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
  26. package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
  27. package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
  28. package/corpus/core/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
  29. package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
  30. package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
  31. package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
  32. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
  33. package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
  34. package/corpus/core/docs/content/pr-visual-recap.mdx +3 -3
  35. package/corpus/core/docs/content/pure-agent-apps.mdx +22 -0
  36. package/corpus/core/package.json +1 -1
  37. package/corpus/core/src/agent/engine/builtin.ts +1 -1
  38. package/corpus/core/src/agent/model-config.ts +30 -30
  39. package/corpus/core/src/agent/production-agent.ts +129 -7
  40. package/corpus/core/src/cli/design-connect.ts +438 -83
  41. package/corpus/core/src/cli/recap.ts +2 -2
  42. package/corpus/core/src/client/AgentPanel.tsx +8 -1
  43. package/corpus/core/src/client/agent-chat-adapter.ts +12 -7
  44. package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
  45. package/corpus/core/src/client/index.ts +4 -0
  46. package/corpus/core/src/client/org/TeamPage.tsx +41 -26
  47. package/corpus/core/src/client/use-action.ts +113 -1
  48. package/corpus/core/src/db/client.ts +12 -2
  49. package/corpus/core/src/db/create-get-db.ts +4 -1
  50. package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
  51. package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
  52. package/corpus/core/src/server/transcribe-voice.ts +1 -1
  53. package/corpus/core/src/usage/store.ts +13 -4
  54. package/corpus/core/src/vite/client.ts +38 -1
  55. package/corpus/templates/analytics/AGENTS.md +3 -0
  56. package/corpus/templates/analytics/actions/get-data-program.ts +78 -0
  57. package/corpus/templates/analytics/actions/list-data-programs.ts +49 -0
  58. package/corpus/templates/analytics/app/global.css +11 -0
  59. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +163 -17
  60. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  61. package/corpus/templates/analytics/app/i18n-data.ts +20 -0
  62. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +96 -3
  63. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -1
  64. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +61 -4
  65. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +40 -2
  66. package/corpus/templates/analytics/changelog/2026-07-09-analytics-no-longer-forgets-successful-data-queries-when-a-l.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-keep-consistent-spacing-when-they-stack-ver.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-tables-and-extensions-can-be-selected-and-d.md +6 -0
  69. package/corpus/templates/analytics/changelog/2026-07-09-long-running-analytics-requests-now-recover-automatically-wh.md +6 -0
  70. package/corpus/templates/analytics/server/db/index.ts +6 -0
  71. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +1 -7
  72. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +102 -15
  73. package/corpus/templates/content/app/hooks/use-content-database.ts +52 -0
  74. package/corpus/templates/content/app/hooks/use-document-properties.ts +50 -6
  75. package/corpus/templates/content/app/i18n/zh-TW.ts +2 -0
  76. package/corpus/templates/content/app/i18n-data.ts +28 -0
  77. package/corpus/templates/content/changelog/2026-07-09-notion-conflict-warnings-no-longer-flash-during-normal-synce.md +6 -0
  78. package/corpus/templates/content/changelog/2026-07-09-property-menus-and-delete-confirmations-now-open-visibly-and.md +6 -0
  79. package/corpus/templates/content/server/lib/notion-sync.ts +130 -28
  80. package/corpus/templates/design/actions/add-breakpoint.ts +48 -68
  81. package/corpus/templates/design/actions/add-localhost-screens.ts +496 -61
  82. package/corpus/templates/design/actions/apply-component-prop-edit.ts +2 -18
  83. package/corpus/templates/design/actions/apply-design-token-edit.ts +51 -82
  84. package/corpus/templates/design/actions/apply-tweaks.ts +63 -41
  85. package/corpus/templates/design/actions/capture-design-state.ts +2 -2
  86. package/corpus/templates/design/actions/connect-localhost.ts +58 -12
  87. package/corpus/templates/design/actions/create-component.ts +2 -18
  88. package/corpus/templates/design/actions/create-design-branch.ts +38 -18
  89. package/corpus/templates/design/actions/create-fusion-app.ts +15 -11
  90. package/corpus/templates/design/actions/delete-file.ts +19 -34
  91. package/corpus/templates/design/actions/deploy-design-preview.ts +59 -27
  92. package/corpus/templates/design/actions/deploy-fusion-app.ts +22 -15
  93. package/corpus/templates/design/actions/export-pdf.ts +2 -1
  94. package/corpus/templates/design/actions/export-zip.ts +9 -3
  95. package/corpus/templates/design/actions/generate-design.ts +107 -70
  96. package/corpus/templates/design/actions/get-component-details.ts +2 -18
  97. package/corpus/templates/design/actions/get-design-branch-diff.ts +2 -3
  98. package/corpus/templates/design/actions/get-design-surface-index.ts +2 -18
  99. package/corpus/templates/design/actions/get-design.ts +2 -1
  100. package/corpus/templates/design/actions/grant-localhost-write-consent.ts +7 -1
  101. package/corpus/templates/design/actions/import-design-tokens.ts +114 -76
  102. package/corpus/templates/design/actions/index-components.ts +2 -18
  103. package/corpus/templates/design/actions/list-design-source-capabilities.ts +23 -28
  104. package/corpus/templates/design/actions/list-local-files.ts +9 -2
  105. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +82 -98
  106. package/corpus/templates/design/actions/open-component-source.ts +2 -18
  107. package/corpus/templates/design/actions/open-visual-edit.ts +19 -1
  108. package/corpus/templates/design/actions/present-design-variants.ts +70 -70
  109. package/corpus/templates/design/actions/preview-component-prop-edit.ts +4 -14
  110. package/corpus/templates/design/actions/read-local-file.ts +9 -2
  111. package/corpus/templates/design/actions/remove-breakpoint.ts +40 -61
  112. package/corpus/templates/design/actions/rename-screen.ts +425 -0
  113. package/corpus/templates/design/actions/request-localhost-write-consent.ts +12 -2
  114. package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +9 -2
  115. package/corpus/templates/design/actions/sync-fusion-app.ts +56 -39
  116. package/corpus/templates/design/actions/update-design.ts +376 -61
  117. package/corpus/templates/design/actions/update-file.ts +455 -188
  118. package/corpus/templates/design/actions/write-local-file.ts +10 -2
  119. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +685 -608
  120. package/corpus/templates/design/app/components/design/LayersPanel.tsx +43 -15
  121. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +576 -2015
  122. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +62 -14
  123. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +263 -25
  124. package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +34 -0
  125. package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +40 -0
  126. package/corpus/templates/design/app/components/design/design-canvas/creation.ts +47 -0
  127. package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +27 -0
  128. package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +62 -0
  129. package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +137 -0
  130. package/corpus/templates/design/app/components/design/design-canvas/file-drop.ts +10 -0
  131. package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +23 -0
  132. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +23 -0
  133. package/corpus/templates/design/app/components/design/design-canvas/iframe-pan.ts +177 -0
  134. package/corpus/templates/design/app/components/design/design-canvas/motion-types.ts +7 -0
  135. package/corpus/templates/design/app/components/design/design-canvas/pending-text-edit.ts +62 -0
  136. package/corpus/templates/design/app/components/design/index.ts +2 -2
  137. package/corpus/templates/design/app/components/design/multi-screen/canvas-tools.ts +100 -0
  138. package/corpus/templates/design/app/components/design/multi-screen/coordinate-transforms.ts +81 -0
  139. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +23 -13
  140. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +238 -19
  141. package/corpus/templates/design/app/components/design/multi-screen/draft-primitives.ts +424 -0
  142. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +341 -0
  143. package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +52 -0
  144. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +62 -0
  145. package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +283 -0
  146. package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +272 -0
  147. package/corpus/templates/design/app/components/design/multi-screen/types.ts +5 -1
  148. package/corpus/templates/design/app/components/design/multi-screen/wheel-gesture-state.ts +12 -0
  149. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +325 -84
  150. package/corpus/templates/design/app/hooks/use-navigation-state.ts +15 -1
  151. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +119 -47
  152. package/corpus/templates/design/app/i18n/zh-TW.ts +9 -0
  153. package/corpus/templates/design/app/i18n-data.ts +223 -0
  154. package/corpus/templates/design/app/lib/design-save-outbox.ts +379 -0
  155. package/corpus/templates/design/app/lib/png-clipboard.ts +113 -0
  156. package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +229 -0
  157. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +918 -0
  158. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +43 -0
  159. package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +336 -0
  160. package/corpus/templates/design/app/pages/design-editor/data-operations.ts +270 -0
  161. package/corpus/templates/design/app/pages/design-editor/dom-guards.ts +24 -0
  162. package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +11 -0
  163. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +20 -0
  164. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +408 -0
  165. package/corpus/templates/design/app/pages/design-editor/export-capture.ts +115 -0
  166. package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +93 -0
  167. package/corpus/templates/design/app/pages/design-editor/history.ts +169 -0
  168. package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +185 -0
  169. package/corpus/templates/design/app/pages/design-editor/motion-state.ts +309 -0
  170. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +438 -0
  171. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +510 -0
  172. package/corpus/templates/design/app/pages/design-editor/portable-style.ts +115 -0
  173. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +337 -0
  174. package/corpus/templates/design/app/pages/design-editor/style-utils.ts +5 -0
  175. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +92 -0
  176. package/corpus/templates/design/app/pages/design-editor/tweak-save.ts +87 -0
  177. package/corpus/templates/design/app/pages/design-editor/types.ts +36 -0
  178. package/corpus/templates/design/app/routes/design.$id.tsx +11 -1
  179. package/corpus/templates/design/changelog/2026-07-09-design-edits-canvas-positions-tools-and-tab-context-now-pers.md +6 -0
  180. package/corpus/templates/design/changelog/2026-07-09-figma-style-shortcuts-drawing-annotations-and-cross-screen-d.md +6 -0
  181. package/corpus/templates/design/changelog/2026-07-09-hand-and-scale-tools-now-keep-their-active-toolbar-identity-.md +6 -0
  182. package/corpus/templates/design/changelog/2026-07-09-large-multi-screen-designs-now-stay-responsive-during-long-c.md +6 -0
  183. package/corpus/templates/design/changelog/2026-07-09-layer-drags-now-land-exactly-where-the-insertion-indicator-s.md +6 -0
  184. package/corpus/templates/design/server/db/index.ts +2 -52
  185. package/corpus/templates/design/server/db/schema.ts +16 -0
  186. package/corpus/templates/design/server/lib/design-data-access.ts +70 -0
  187. package/corpus/templates/design/server/lib/design-data-mutation.ts +249 -0
  188. package/corpus/templates/design/server/lib/fusion-screens.ts +89 -76
  189. package/corpus/templates/design/server/lib/import-design-files.ts +76 -35
  190. package/corpus/templates/design/server/lib/verify-write-grant.ts +7 -2
  191. package/corpus/templates/design/server/plugins/db.ts +19 -0
  192. package/corpus/templates/design/server/source-workspace.ts +12 -13
  193. package/corpus/templates/design/shared/resolve-tweaks.ts +15 -0
  194. package/corpus/templates/design/shared/screen-rename.ts +42 -0
  195. package/corpus/templates/design/shared/source-mode.ts +84 -4
  196. package/dist/agent/engine/builder-engine.d.ts +1 -1
  197. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  198. package/dist/agent/engine/builtin.js +1 -1
  199. package/dist/agent/engine/builtin.js.map +1 -1
  200. package/dist/agent/model-config.d.ts +9 -9
  201. package/dist/agent/model-config.d.ts.map +1 -1
  202. package/dist/agent/model-config.js +30 -30
  203. package/dist/agent/model-config.js.map +1 -1
  204. package/dist/agent/production-agent.d.ts +60 -1
  205. package/dist/agent/production-agent.d.ts.map +1 -1
  206. package/dist/agent/production-agent.js +106 -7
  207. package/dist/agent/production-agent.js.map +1 -1
  208. package/dist/cli/design-connect.d.ts +30 -1
  209. package/dist/cli/design-connect.d.ts.map +1 -1
  210. package/dist/cli/design-connect.js +359 -75
  211. package/dist/cli/design-connect.js.map +1 -1
  212. package/dist/cli/recap.js +2 -2
  213. package/dist/cli/recap.js.map +1 -1
  214. package/dist/client/AgentPanel.d.ts.map +1 -1
  215. package/dist/client/AgentPanel.js +6 -1
  216. package/dist/client/AgentPanel.js.map +1 -1
  217. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  218. package/dist/client/agent-chat-adapter.js +10 -5
  219. package/dist/client/agent-chat-adapter.js.map +1 -1
  220. package/dist/client/composer/TiptapComposer.js +1 -1
  221. package/dist/client/composer/TiptapComposer.js.map +1 -1
  222. package/dist/client/index.d.ts +1 -1
  223. package/dist/client/index.d.ts.map +1 -1
  224. package/dist/client/index.js +1 -1
  225. package/dist/client/index.js.map +1 -1
  226. package/dist/client/org/TeamPage.d.ts.map +1 -1
  227. package/dist/client/org/TeamPage.js +6 -5
  228. package/dist/client/org/TeamPage.js.map +1 -1
  229. package/dist/client/use-action.d.ts +32 -0
  230. package/dist/client/use-action.d.ts.map +1 -1
  231. package/dist/client/use-action.js +68 -1
  232. package/dist/client/use-action.js.map +1 -1
  233. package/dist/collab/struct-routes.d.ts +1 -1
  234. package/dist/db/client.d.ts +3 -0
  235. package/dist/db/client.d.ts.map +1 -1
  236. package/dist/db/client.js +7 -2
  237. package/dist/db/client.js.map +1 -1
  238. package/dist/db/create-get-db.d.ts.map +1 -1
  239. package/dist/db/create-get-db.js +2 -2
  240. package/dist/db/create-get-db.js.map +1 -1
  241. package/dist/notifications/routes.d.ts +3 -3
  242. package/dist/resources/handlers.d.ts +2 -2
  243. package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
  244. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
  245. package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
  246. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  247. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  248. package/dist/server/transcribe-voice.js +1 -1
  249. package/dist/server/transcribe-voice.js.map +1 -1
  250. package/dist/usage/store.d.ts.map +1 -1
  251. package/dist/usage/store.js +13 -4
  252. package/dist/usage/store.js.map +1 -1
  253. package/dist/vite/client.d.ts.map +1 -1
  254. package/dist/vite/client.js +36 -1
  255. package/dist/vite/client.js.map +1 -1
  256. package/docs/content/a2a-protocol.mdx +12 -0
  257. package/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
  258. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
  259. package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
  260. package/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
  261. package/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
  262. package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
  263. package/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
  264. package/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
  265. package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
  266. package/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
  267. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
  268. package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
  269. package/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
  270. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
  271. package/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
  272. package/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
  273. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
  274. package/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
  275. package/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
  276. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
  277. package/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
  278. package/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
  279. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
  280. package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
  281. package/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
  282. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
  283. package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
  284. package/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
  285. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
  286. package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
  287. package/docs/content/pr-visual-recap.mdx +3 -3
  288. package/docs/content/pure-agent-apps.mdx +22 -0
  289. package/package.json +2 -2
@@ -1925,8 +1925,14 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
1925
1925
  var persistentNodes = Array.prototype.slice.call(
1926
1926
  document.querySelectorAll("[data-agent-native-edit-overlay]"),
1927
1927
  );
1928
- var activeSelector =
1929
- preferredSelector || (selectedEl ? getSelector(selectedEl) : "");
1928
+ // A forced whole-document replace is used for structural edits (duplicate,
1929
+ // delete, cut/paste, undo/redo). Never fall back to the current selection
1930
+ // in that mode: doing so activates the single-subtree fast path below,
1931
+ // which can faithfully replace the selected node while silently omitting
1932
+ // newly inserted or removed siblings elsewhere in the document.
1933
+ var activeSelector = forceFullDocument
1934
+ ? ""
1935
+ : preferredSelector || (selectedEl ? getSelector(selectedEl) : "");
1930
1936
  var activeCandidates: string[] = [];
1931
1937
  if (Array.isArray(selectorCandidates)) {
1932
1938
  selectorCandidates.forEach(function (selector) {
@@ -8378,6 +8384,7 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
8378
8384
  target.removeEventListener("keyup", onSelectionChange, true);
8379
8385
  target.removeEventListener("mouseup", onSelectionChange, true);
8380
8386
  document.removeEventListener("selectionchange", onSelectionChange);
8387
+ window.removeEventListener("blur", onWindowBlur, true);
8381
8388
  target.removeAttribute("contenteditable");
8382
8389
  target.removeAttribute("data-agent-native-text-editing");
8383
8390
  document.documentElement.removeAttribute(
@@ -8443,19 +8450,39 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
8443
8450
  // Escape/blur would take, instead of only resetting activeTextEditEl.
8444
8451
  finishActiveTextEdit = finish;
8445
8452
 
8446
- function onBlur() {
8447
- if (programmaticTextEdit && !(target.textContent || "").trim()) {
8448
- window.setTimeout(function () {
8449
- if (committed || (target.textContent || "").trim()) return;
8450
- target.focus();
8451
- updateTextEditingChrome(target, originalMinWidth, originalMinHeight);
8452
- postTextEditingState(target, true);
8453
- }, 0);
8454
- return;
8453
+ var emptyProgrammaticRefocusScheduled = false;
8454
+ function refocusEmptyProgrammaticEdit() {
8455
+ if (
8456
+ emptyProgrammaticRefocusScheduled ||
8457
+ !programmaticTextEdit ||
8458
+ (target.textContent || "").trim()
8459
+ ) {
8460
+ return false;
8455
8461
  }
8462
+ emptyProgrammaticRefocusScheduled = true;
8463
+ window.setTimeout(function () {
8464
+ emptyProgrammaticRefocusScheduled = false;
8465
+ if (committed || (target.textContent || "").trim()) return;
8466
+ target.focus();
8467
+ updateTextEditingChrome(target, originalMinWidth, originalMinHeight);
8468
+ postTextEditingState(target, true);
8469
+ }, 0);
8470
+ return true;
8471
+ }
8472
+
8473
+ function onBlur() {
8474
+ if (refocusEmptyProgrammaticEdit()) return;
8456
8475
  finish(true);
8457
8476
  }
8458
8477
 
8478
+ // Moving focus from a child browsing context back to the host canvas does
8479
+ // not consistently blur the iframe's activeElement in Chromium. Listen at
8480
+ // the window boundary too so the newly created empty text field keeps the
8481
+ // keyboard until the user types or explicitly exits.
8482
+ function onWindowBlur() {
8483
+ refocusEmptyProgrammaticEdit();
8484
+ }
8485
+
8459
8486
  function onKeyDown(ev) {
8460
8487
  // T3: bail out on IME composition input (e.g. CJK/Korean input method
8461
8488
  // candidate selection) so a composing Enter/Escape keystroke isn't
@@ -8525,6 +8552,7 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
8525
8552
  target.addEventListener("keyup", onSelectionChange, true);
8526
8553
  target.addEventListener("mouseup", onSelectionChange, true);
8527
8554
  document.addEventListener("selectionchange", onSelectionChange);
8555
+ window.addEventListener("blur", onWindowBlur, true);
8528
8556
  target.focus();
8529
8557
  if (programmaticTextEdit) {
8530
8558
  // The synthesized point sits at the (0×0) node's edge and resolves to the
@@ -8560,8 +8588,27 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
8560
8588
  textTarget: HTMLElement,
8561
8589
  force: boolean,
8562
8590
  ): void {
8563
- // If we are already editing this element, do nothing.
8564
- if (activeTextEditEl && activeTextEditEl === textTarget) return;
8591
+ // The host canvas can reclaim keyboard focus while React settles a newly
8592
+ // created layer. In that case this document still reports the same
8593
+ // activeElement even though its browsing context no longer has focus, so
8594
+ // treating the session as already active makes every retry a no-op and the
8595
+ // user's first keystroke hits host shortcuts. Re-focus the existing
8596
+ // session instead of rebuilding it.
8597
+ if (activeTextEditEl && activeTextEditEl === textTarget) {
8598
+ if (document.activeElement !== textTarget || !document.hasFocus()) {
8599
+ textTarget.focus();
8600
+ try {
8601
+ var refocusRange = document.createRange();
8602
+ refocusRange.selectNodeContents(textTarget);
8603
+ refocusRange.collapse(false);
8604
+ var refocusSelection = window.getSelection();
8605
+ refocusSelection.removeAllRanges();
8606
+ refocusSelection.addRange(refocusRange);
8607
+ } catch {}
8608
+ postTextEditingState(textTarget, true);
8609
+ }
8610
+ return;
8611
+ }
8565
8612
  // Synthesise coordinates at the end of the element content so the caret
8566
8613
  // lands at the insertion point (right after any placeholder text).
8567
8614
  var bteRect = textTarget.getBoundingClientRect();
@@ -9019,7 +9066,8 @@ declare var __DESIGN_CANVAS_BOARD_SURFACE__: boolean;
9019
9066
  );
9020
9067
  if (
9021
9068
  textEditStatusEditingEl &&
9022
- document.activeElement === textEditStatusEditingEl
9069
+ document.activeElement === textEditStatusEditingEl &&
9070
+ document.hasFocus()
9023
9071
  ) {
9024
9072
  textEditStatus = "active";
9025
9073
  } else if (
@@ -1,62 +1,300 @@
1
1
  /**
2
- * Embedded overview bridge — injected into every canvas iframe.
2
+ * Embedded canvas gesture bridge — injected into every canvas iframe.
3
3
  *
4
- * A screen preview is a real iframe, so normal wheel events never bubble to
5
- * the overview canvas underneath. In embedded mode we forward a bounded wheel
6
- * payload to the parent so the existing canvas wheel handler can pan/zoom
7
- * exactly as if the pointer were over empty canvas.
4
+ * A screen preview is a real iframe, so wheel and pointer-drag events never
5
+ * bubble to the canvas underneath. In embedded mode we forward bounded wheel
6
+ * payloads to the parent. In every canvas mode we also forward middle-button
7
+ * drags, plus left-button drags while the host's hand/Space tool is armed, so
8
+ * the parent can reuse its existing single/overview pan implementation.
8
9
  *
9
10
  * Runtime placeholder (replaced by DesignCanvas.tsx before injection):
10
11
  * __EMBEDDED_WHEEL_FORWARDING_ENABLED__ — boolean literal "true"/"false"
12
+ * __EMBEDDED_SPACE_KEY_FORWARDING_ENABLED__ — boolean literal; true only
13
+ * when the editor-chrome bridge is absent (Interact mode)
11
14
  *
12
15
  * Protocol (iframe → parent, only when enabled):
13
16
  *
14
17
  * { type: 'embedded-canvas-wheel', deltaX, deltaY, deltaZ, deltaMode,
15
18
  * clientX, clientY, ctrlKey, metaKey, shiftKey, altKey }
16
19
  *
20
+ * { type: 'embedded-canvas-pan', phase: 'start'|'move'|'end'|'cancel',
21
+ * pointerId, button, buttons, clientX, clientY,
22
+ * ctrlKey, metaKey, shiftKey, altKey }
23
+ *
24
+ * Protocol (parent → iframe):
25
+ *
26
+ * { type: 'embedded-canvas-pan-mode', leftButtonEnabled }
27
+ * { type: 'embedded-canvas-pan-cancel' }
28
+ *
17
29
  * Rules:
18
30
  * • No import/require of any module (DOM globals only).
19
31
  * • No references to outer/module scope (the code runs inside an iframe).
20
32
  * • Wrap everything in a self-executing IIFE.
21
33
  */
22
34
  declare var __EMBEDDED_WHEEL_FORWARDING_ENABLED__: boolean;
35
+ declare var __EMBEDDED_SPACE_KEY_FORWARDING_ENABLED__: boolean;
23
36
 
24
37
  (function () {
25
- var enabled = __EMBEDDED_WHEEL_FORWARDING_ENABLED__;
26
- if (!enabled) return;
38
+ var wheelEnabled = __EMBEDDED_WHEEL_FORWARDING_ENABLED__;
39
+ var spaceKeyForwardingEnabled = __EMBEDDED_SPACE_KEY_FORWARDING_ENABLED__;
40
+ var leftButtonEnabled = false;
41
+ var temporarySpacePanEnabled = false;
42
+ var activePointerId: number | null = null;
43
+ var activeButton: 0 | 1 | null = null;
44
+ var captureTarget: Element | null = null;
45
+ var suppressClick = false;
46
+ var clearSuppressClickTimer: number | null = null;
47
+ var lastClientX = 0;
48
+ var lastClientY = 0;
49
+ var lastCtrlKey = false;
50
+ var lastMetaKey = false;
51
+ var lastShiftKey = false;
52
+ var lastAltKey = false;
53
+
27
54
  function clamp(value: number, limit: number): number {
28
55
  var number = Number(value) || 0;
29
56
  if (number > limit) return limit;
30
57
  if (number < -limit) return -limit;
31
58
  return number;
32
59
  }
33
- function onWheel(e: WheelEvent): void {
60
+
61
+ function stopNativeInteraction(e: Event): void {
34
62
  e.preventDefault();
35
63
  e.stopPropagation();
36
64
  if (e.stopImmediatePropagation) e.stopImmediatePropagation();
65
+ }
66
+
67
+ function postToParent(message: Record<string, unknown>): void {
68
+ try {
69
+ (window.parent as Window).postMessage(message, "*");
70
+ } catch {}
71
+ }
72
+
73
+ function onWheel(e: WheelEvent): void {
74
+ if (!wheelEnabled) return;
75
+ stopNativeInteraction(e);
76
+ postToParent({
77
+ type: "embedded-canvas-wheel",
78
+ deltaX: clamp(e.deltaX, 240),
79
+ deltaY: clamp(e.deltaY, 240),
80
+ deltaZ: clamp(e.deltaZ, 240),
81
+ deltaMode: e.deltaMode,
82
+ clientX: clamp(e.clientX, 100000),
83
+ clientY: clamp(e.clientY, 100000),
84
+ ctrlKey: !!e.ctrlKey,
85
+ metaKey: !!e.metaKey,
86
+ shiftKey: !!e.shiftKey,
87
+ altKey: !!e.altKey,
88
+ });
89
+ }
90
+
91
+ function shouldStartPan(e: PointerEvent): boolean {
92
+ if (e.button === 1) return true;
93
+ return e.button === 0 && (leftButtonEnabled || temporarySpacePanEnabled);
94
+ }
95
+
96
+ function postPan(
97
+ phase: "start" | "move" | "end" | "cancel",
98
+ e: PointerEvent,
99
+ ): void {
100
+ if (activeButton === null) return;
101
+ lastClientX = clamp(e.clientX, 100000);
102
+ lastClientY = clamp(e.clientY, 100000);
103
+ lastCtrlKey = !!e.ctrlKey;
104
+ lastMetaKey = !!e.metaKey;
105
+ lastShiftKey = !!e.shiftKey;
106
+ lastAltKey = !!e.altKey;
107
+ postToParent({
108
+ type: "embedded-canvas-pan",
109
+ phase: phase,
110
+ pointerId: Math.max(0, Math.min(0x7fffffff, Math.trunc(e.pointerId))),
111
+ button: activeButton,
112
+ buttons: phase === "end" || phase === "cancel" ? 0 : e.buttons,
113
+ clientX: lastClientX,
114
+ clientY: lastClientY,
115
+ ctrlKey: lastCtrlKey,
116
+ metaKey: lastMetaKey,
117
+ shiftKey: lastShiftKey,
118
+ altKey: lastAltKey,
119
+ });
120
+ }
121
+
122
+ function releasePointerCapture(pointerId: number): void {
123
+ if (!captureTarget) return;
124
+ try {
125
+ if (captureTarget.hasPointerCapture(pointerId)) {
126
+ captureTarget.releasePointerCapture(pointerId);
127
+ }
128
+ } catch {}
129
+ captureTarget = null;
130
+ }
131
+
132
+ function scheduleClickSuppressionReset(): void {
133
+ if (clearSuppressClickTimer !== null) {
134
+ window.clearTimeout(clearSuppressClickTimer);
135
+ }
136
+ clearSuppressClickTimer = window.setTimeout(function () {
137
+ suppressClick = false;
138
+ clearSuppressClickTimer = null;
139
+ }, 0);
140
+ }
141
+
142
+ function onPointerDown(e: PointerEvent): void {
143
+ if (activePointerId !== null || !shouldStartPan(e)) return;
144
+ activePointerId = e.pointerId;
145
+ activeButton = e.button === 1 ? 1 : 0;
146
+ suppressClick = true;
147
+ captureTarget =
148
+ e.target instanceof Element ? e.target : document.documentElement;
37
149
  try {
38
- (window.parent as Window).postMessage(
39
- {
40
- type: "embedded-canvas-wheel",
41
- deltaX: clamp(e.deltaX, 240),
42
- deltaY: clamp(e.deltaY, 240),
43
- deltaZ: clamp(e.deltaZ, 240),
44
- deltaMode: e.deltaMode,
45
- clientX: e.clientX,
46
- clientY: e.clientY,
47
- ctrlKey: !!e.ctrlKey,
48
- metaKey: !!e.metaKey,
49
- shiftKey: !!e.shiftKey,
50
- altKey: !!e.altKey,
51
- },
52
- "*",
53
- );
54
- } catch (_err) {}
150
+ captureTarget.setPointerCapture(e.pointerId);
151
+ } catch {}
152
+ stopNativeInteraction(e);
153
+ postPan("start", e);
55
154
  }
155
+
156
+ function onPointerMove(e: PointerEvent): void {
157
+ if (activePointerId !== e.pointerId || activeButton === null) return;
158
+ stopNativeInteraction(e);
159
+ postPan("move", e);
160
+ }
161
+
162
+ function finishPan(phase: "end" | "cancel", e: PointerEvent): void {
163
+ if (activePointerId !== e.pointerId || activeButton === null) return;
164
+ stopNativeInteraction(e);
165
+ postPan(phase, e);
166
+ releasePointerCapture(e.pointerId);
167
+ activePointerId = null;
168
+ activeButton = null;
169
+ scheduleClickSuppressionReset();
170
+ }
171
+
172
+ function onPointerUp(e: PointerEvent): void {
173
+ finishPan("end", e);
174
+ }
175
+
176
+ function onPointerCancel(e: PointerEvent): void {
177
+ finishPan("cancel", e);
178
+ }
179
+
180
+ function suppressTrailingClick(e: MouseEvent): void {
181
+ if (!suppressClick) return;
182
+ stopNativeInteraction(e);
183
+ suppressClick = false;
184
+ if (clearSuppressClickTimer !== null) {
185
+ window.clearTimeout(clearSuppressClickTimer);
186
+ clearSuppressClickTimer = null;
187
+ }
188
+ }
189
+
190
+ function isTypingTarget(target: EventTarget | null): boolean {
191
+ return !!(
192
+ target instanceof Element &&
193
+ target.closest(
194
+ 'input, textarea, select, [contenteditable], [role="textbox"], [data-agent-native-text-editing]',
195
+ )
196
+ );
197
+ }
198
+
199
+ function onKeyDown(e: KeyboardEvent): void {
200
+ if (
201
+ !spaceKeyForwardingEnabled ||
202
+ e.key !== " " ||
203
+ e.code !== "Space" ||
204
+ e.metaKey ||
205
+ e.ctrlKey ||
206
+ e.altKey ||
207
+ e.shiftKey ||
208
+ isTypingTarget(e.target)
209
+ ) {
210
+ return;
211
+ }
212
+ temporarySpacePanEnabled = true;
213
+ stopNativeInteraction(e);
214
+ if (e.repeat) return;
215
+ postToParent({
216
+ type: "design-hotkey",
217
+ key: e.key,
218
+ code: e.code,
219
+ metaKey: false,
220
+ ctrlKey: false,
221
+ shiftKey: false,
222
+ altKey: false,
223
+ repeat: false,
224
+ });
225
+ }
226
+
227
+ function onKeyUp(e: KeyboardEvent): void {
228
+ if (!spaceKeyForwardingEnabled || e.key !== " " || e.code !== "Space") {
229
+ return;
230
+ }
231
+ var wasTemporarySpacePanEnabled = temporarySpacePanEnabled;
232
+ temporarySpacePanEnabled = false;
233
+ if (!wasTemporarySpacePanEnabled && isTypingTarget(e.target)) return;
234
+ stopNativeInteraction(e);
235
+ postToParent({ type: "design-hotkey-up", key: e.key, code: e.code });
236
+ }
237
+
238
+ function onHostMessage(e: MessageEvent): void {
239
+ if (e.source !== window.parent) return;
240
+ if (!e.data) return;
241
+ if (e.data.type === "embedded-canvas-pan-cancel") {
242
+ cancelActivePan();
243
+ return;
244
+ }
245
+ if (e.data.type === "embedded-canvas-pan-mode") {
246
+ leftButtonEnabled = !!e.data.leftButtonEnabled;
247
+ }
248
+ }
249
+
250
+ function cancelActivePan(): void {
251
+ temporarySpacePanEnabled = false;
252
+ if (activePointerId === null || activeButton === null) return;
253
+ var pointerId = activePointerId;
254
+ postToParent({
255
+ type: "embedded-canvas-pan",
256
+ phase: "cancel",
257
+ pointerId: pointerId,
258
+ button: activeButton,
259
+ buttons: 0,
260
+ clientX: lastClientX,
261
+ clientY: lastClientY,
262
+ ctrlKey: lastCtrlKey,
263
+ metaKey: lastMetaKey,
264
+ shiftKey: lastShiftKey,
265
+ altKey: lastAltKey,
266
+ });
267
+ releasePointerCapture(pointerId);
268
+ activePointerId = null;
269
+ activeButton = null;
270
+ suppressClick = false;
271
+ }
272
+
273
+ function onWindowBlur(): void {
274
+ // Moving focus from an iframe gesture into the parent canvas can blur the
275
+ // child window while the top-level Design window is still active. The
276
+ // parent separately sends embedded-canvas-pan-cancel on a real top-level
277
+ // blur; this local guard handles page/tab hiding without killing that
278
+ // intentional in-app focus transfer.
279
+ if (document.visibilityState === "hidden") cancelActivePan();
280
+ }
281
+
56
282
  var wheelTarget: EventTarget =
57
283
  document.documentElement || document.body || document;
58
284
  wheelTarget.addEventListener("wheel", onWheel as EventListener, {
59
285
  passive: false,
60
286
  capture: true,
61
287
  });
288
+ document.addEventListener("pointerdown", onPointerDown, true);
289
+ document.addEventListener("pointermove", onPointerMove, true);
290
+ document.addEventListener("pointerup", onPointerUp, true);
291
+ document.addEventListener("pointercancel", onPointerCancel, true);
292
+ document.addEventListener("click", suppressTrailingClick, true);
293
+ document.addEventListener("auxclick", suppressTrailingClick, true);
294
+ document.addEventListener("keydown", onKeyDown, true);
295
+ document.addEventListener("keyup", onKeyUp, true);
296
+ window.addEventListener("message", onHostMessage);
297
+ window.addEventListener("blur", onWindowBlur);
298
+ document.addEventListener("visibilitychange", onWindowBlur);
299
+ window.addEventListener("pagehide", cancelActivePan);
62
300
  })();
@@ -0,0 +1,34 @@
1
+ interface SubmitDesignAnnotationsOptions {
2
+ message: string;
3
+ hasQueuedPins: boolean;
4
+ send: (message: string) => void;
5
+ markQueuedPinsSubmitted: () => void;
6
+ exitDrawMode: () => void;
7
+ onError: (error: unknown) => void;
8
+ }
9
+
10
+ /**
11
+ * Submit a drawing/comment batch as one atomic UI transition.
12
+ *
13
+ * The overlay and queued pins must remain intact when chat handoff fails so the
14
+ * user can retry without recreating their annotation work.
15
+ */
16
+ export function submitDesignAnnotations({
17
+ message,
18
+ hasQueuedPins,
19
+ send,
20
+ markQueuedPinsSubmitted,
21
+ exitDrawMode,
22
+ onError,
23
+ }: SubmitDesignAnnotationsOptions): boolean {
24
+ try {
25
+ send(message);
26
+ } catch (error) {
27
+ onError(error);
28
+ return false;
29
+ }
30
+
31
+ if (hasQueuedPins) markQueuedPinsSubmitted();
32
+ exitDrawMode();
33
+ return true;
34
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Converts a viewport point into the iframe's unscaled content coordinates.
3
+ */
4
+ export function getScreenContentPointFromClient(
5
+ clientX: number,
6
+ clientY: number,
7
+ iframeRect: { left: number; top: number; width: number; height: number },
8
+ iframeContentSize: { width: number; height: number },
9
+ ): { x: number; y: number } {
10
+ const scaleX =
11
+ iframeContentSize.width > 0
12
+ ? iframeRect.width / iframeContentSize.width
13
+ : 1;
14
+ const scaleY =
15
+ iframeContentSize.height > 0
16
+ ? iframeRect.height / iframeContentSize.height
17
+ : 1;
18
+ return {
19
+ x: (clientX - iframeRect.left) / (scaleX || 1),
20
+ y: (clientY - iframeRect.top) / (scaleY || 1),
21
+ };
22
+ }
23
+
24
+ /**
25
+ * Computes the scroll delta needed to keep a viewport point anchored while
26
+ * zooming a top-left-origin canvas layer.
27
+ */
28
+ export function getZoomToCursorScrollDelta(
29
+ anchorClient: { x: number; y: number },
30
+ containerRect: { left: number; top: number },
31
+ scrollOffset: { scrollLeft: number; scrollTop: number },
32
+ zoomRatio: number,
33
+ ): { dx: number; dy: number } {
34
+ const cx = anchorClient.x - containerRect.left + scrollOffset.scrollLeft;
35
+ const cy = anchorClient.y - containerRect.top + scrollOffset.scrollTop;
36
+ return {
37
+ dx: cx * (zoomRatio - 1),
38
+ dy: cy * (zoomRatio - 1),
39
+ };
40
+ }
@@ -0,0 +1,47 @@
1
+ import type { PenPath } from "@shared/pen-path";
2
+
3
+ export type CreationTool =
4
+ | "rectangle"
5
+ | "ellipse"
6
+ | "line"
7
+ | "arrow"
8
+ | "text"
9
+ | "pen"
10
+ | "frame";
11
+
12
+ export interface CreatePrimitiveSpec {
13
+ tool: CreationTool;
14
+ rect?: { x: number; y: number; width: number; height: number };
15
+ points?: Array<{ x: number; y: number }>;
16
+ /** Structured pen geometry, including Bezier handles and closed state. */
17
+ penPath?: PenPath;
18
+ fromClick: boolean;
19
+ /** Commit an in-progress pen path without overriding a newly chosen tool. */
20
+ preserveActiveTool?: boolean;
21
+ }
22
+
23
+ /**
24
+ * A browser double-click is two complete pointer gestures followed by a
25
+ * `dblclick` event. Both gestures therefore add the final pen anchor before
26
+ * the overlay commits. Collapse only the coincident trailing pair, retaining
27
+ * the anchor from the second gesture so the final clicked point is never
28
+ * omitted from the committed path.
29
+ */
30
+ export function collapseDoubleClickPenAnchor(path: PenPath): PenPath {
31
+ const last = path.nodes[path.nodes.length - 1];
32
+ const previous = path.nodes[path.nodes.length - 2];
33
+ if (
34
+ !last ||
35
+ !previous ||
36
+ Math.hypot(
37
+ last.point.x - previous.point.x,
38
+ last.point.y - previous.point.y,
39
+ ) > 0.5
40
+ ) {
41
+ return path;
42
+ }
43
+ return {
44
+ nodes: [...path.nodes.slice(0, -2), last],
45
+ closed: false,
46
+ };
47
+ }
@@ -0,0 +1,27 @@
1
+ import type { ElementInfo } from "../types";
2
+
3
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
4
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
5
+ }
6
+
7
+ function isFiniteRect(value: unknown): value is ElementInfo["boundingRect"] {
8
+ if (!isPlainRecord(value)) return false;
9
+ return (
10
+ Number.isFinite(value.x) &&
11
+ Number.isFinite(value.y) &&
12
+ Number.isFinite(value.width) &&
13
+ Number.isFinite(value.height)
14
+ );
15
+ }
16
+
17
+ export function isElementInfoPayload(value: unknown): value is ElementInfo {
18
+ if (!isPlainRecord(value)) return false;
19
+ return (
20
+ typeof value.tagName === "string" &&
21
+ Array.isArray(value.classes) &&
22
+ isPlainRecord(value.computedStyles) &&
23
+ isFiniteRect(value.boundingRect) &&
24
+ typeof value.isFlexChild === "boolean" &&
25
+ typeof value.isFlexContainer === "boolean"
26
+ );
27
+ }
@@ -0,0 +1,62 @@
1
+ const TRANSPARENT_EMBEDDED_FRAME_STYLE =
2
+ "<style data-agent-native-transparent-frame>html,body{background:transparent!important;}body{background-color:transparent!important;}</style>";
3
+
4
+ function embeddedFrameBackgroundStyle(background: string | undefined): string {
5
+ const trimmed = background?.trim();
6
+ if (!trimmed || /[;{}<>]/.test(trimmed)) return "";
7
+ return `<style data-agent-native-frame-background>html,body{background:${trimmed}!important;}body{background-color:${trimmed}!important;}</style>`;
8
+ }
9
+
10
+ export function getEmbeddedFrameBackgroundStyle(args: {
11
+ embeddedFrameBackground?: string;
12
+ transparentBackground?: boolean;
13
+ }): string {
14
+ return args.transparentBackground
15
+ ? TRANSPARENT_EMBEDDED_FRAME_STYLE
16
+ : embeddedFrameBackgroundStyle(args.embeddedFrameBackground);
17
+ }
18
+
19
+ export function getEmbeddedIframeBackgroundColor(args: {
20
+ embeddedFrameBackground?: string;
21
+ transparentBackground?: boolean;
22
+ }): string {
23
+ return args.transparentBackground
24
+ ? "transparent"
25
+ : (args.embeddedFrameBackground ?? "transparent");
26
+ }
27
+
28
+ export function embeddedContentOffsetStyle(x: number, y: number): string {
29
+ if (x === 0 && y === 0) return "";
30
+ return `<style data-agent-native-content-offset>body > [data-agent-native-node-id]{translate:${Math.round(x)}px ${Math.round(y)}px;}</style>`;
31
+ }
32
+
33
+ function injectEmbeddedFrameStyle(content: string, style: string): string {
34
+ if (!style) return content;
35
+ if (/<\/head>/i.test(content)) {
36
+ return content.replace(/<\/head>/i, `${style}</head>`);
37
+ }
38
+ if (/<body\b/i.test(content)) {
39
+ return content.replace(/<body\b/i, `${style}<body`);
40
+ }
41
+ return `${style}${content}`;
42
+ }
43
+
44
+ export function getEmbeddedFrameDocumentContent(args: {
45
+ content: string;
46
+ embeddedFrameBackground?: string;
47
+ transparentBackground?: boolean;
48
+ contentOffsetX?: number;
49
+ contentOffsetY?: number;
50
+ }): string {
51
+ const frameStyle = [
52
+ getEmbeddedFrameBackgroundStyle({
53
+ embeddedFrameBackground: args.embeddedFrameBackground,
54
+ transparentBackground: args.transparentBackground,
55
+ }),
56
+ embeddedContentOffsetStyle(
57
+ args.contentOffsetX ?? 0,
58
+ args.contentOffsetY ?? 0,
59
+ ),
60
+ ].join("");
61
+ return injectEmbeddedFrameStyle(args.content, frameStyle);
62
+ }