@agent-native/core 0.90.5 → 0.90.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 (113) hide show
  1. package/README.md +34 -7
  2. package/corpus/README.md +1 -1
  3. package/corpus/core/CHANGELOG.md +20 -0
  4. package/corpus/core/docs/content/agent-native-toolkit.mdx +1 -1
  5. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  6. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  8. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  9. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  10. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  11. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  12. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  13. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  14. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  15. package/corpus/core/docs/content/toolkit-agent-ux.mdx +1 -1
  16. package/corpus/core/docs/content/toolkit-app-adapters.mdx +1 -1
  17. package/corpus/core/docs/content/toolkit-collaboration-ui.mdx +1 -1
  18. package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
  19. package/corpus/core/docs/content/toolkit-command-navigation.mdx +2 -2
  20. package/corpus/core/docs/content/toolkit-comments-review.mdx +1 -1
  21. package/corpus/core/docs/content/toolkit-history.mdx +1 -1
  22. package/corpus/core/docs/content/toolkit-observability.mdx +1 -1
  23. package/corpus/core/docs/content/toolkit-org-team.mdx +1 -1
  24. package/corpus/core/docs/content/toolkit-resources.mdx +1 -1
  25. package/corpus/core/docs/content/toolkit-settings.mdx +1 -1
  26. package/corpus/core/docs/content/toolkit-setup-connections.mdx +1 -1
  27. package/corpus/core/docs/content/toolkit-sharing-ui.mdx +1 -1
  28. package/corpus/core/docs/content/toolkit-sharing.mdx +1 -1
  29. package/corpus/core/docs/content/toolkit-shell-hooks.mdx +1 -1
  30. package/corpus/core/docs/content/toolkit-ui.mdx +1 -1
  31. package/corpus/core/package.json +1 -1
  32. package/corpus/core/src/client/use-db-sync.ts +99 -1
  33. package/corpus/core/src/collab/client.ts +49 -4
  34. package/corpus/core/src/deploy/build.ts +156 -0
  35. package/corpus/core/src/server/core-routes-plugin.ts +137 -8
  36. package/corpus/templates/clips/changelog/2026-07-07-faster-local-whisper-dictation-start.md +6 -0
  37. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +311 -31
  38. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +2 -0
  39. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +9 -0
  40. package/corpus/templates/design/actions/read-source-file.ts +28 -0
  41. package/corpus/templates/design/actions/update-file.ts +76 -7
  42. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +181 -1
  43. package/corpus/templates/design/app/components/design/EditPanel.tsx +4 -0
  44. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +387 -25
  45. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1110 -88
  46. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +368 -16
  47. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +24 -0
  48. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +27 -6
  49. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +18 -0
  50. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +5 -4
  51. package/corpus/templates/design/app/components/design/multi-screen/handle-hit-zones.ts +124 -0
  52. package/corpus/templates/design/app/components/design/multi-screen/types.ts +23 -0
  53. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  54. package/corpus/templates/design/app/i18n-data.ts +19 -0
  55. package/corpus/templates/design/changelog/2026-07-07-dragging-a-free-floating-element-into-a-layout-column-or-row.md +6 -0
  56. package/corpus/templates/design/changelog/2026-07-07-dragging-a-repeated-list-item-like-a-to-do-card-generated-fr.md +6 -0
  57. package/corpus/templates/design/changelog/2026-07-07-dragging-an-element-onto-a-button-or-chip-s-middle-no-longer.md +6 -0
  58. package/corpus/templates/design/changelog/2026-07-07-elements-dropped-into-another-board-shape-now-stay-exactly-w.md +6 -0
  59. package/corpus/templates/design/changelog/2026-07-07-fixed-drag-reordering-elements-within-a-screen-no-longer-sil.md +6 -0
  60. package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-an-element-from-a-screen-onto-the-canvas-now-.md +6 -0
  61. package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-elements-between-screens-into-ai-generated-co.md +6 -0
  62. package/corpus/templates/design/changelog/2026-07-07-fixed-moving-elements-between-screens-no-longer-bakes-intern.md +6 -0
  63. package/corpus/templates/design/changelog/2026-07-07-fixed-the-cross-screen-drop-indicator-now-points-at-the-corr.md +6 -0
  64. package/corpus/templates/design/changelog/2026-07-07-fixed-the-zoom-menu-no-longer-leaves-the-canvas-unresponsive.md +6 -0
  65. package/corpus/templates/design/changelog/2026-07-07-text-drawn-on-the-canvas-is-now-readable-white-instead-of-in.md +6 -0
  66. package/corpus/templates/design/server/source-workspace.ts +27 -3
  67. package/corpus/templates/design/shared/board-file.ts +359 -0
  68. package/corpus/templates/design/shared/breakpoint-media.ts +21 -3
  69. package/corpus/templates/design/shared/code-layer.ts +145 -10
  70. package/dist/client/use-db-sync.d.ts +18 -0
  71. package/dist/client/use-db-sync.d.ts.map +1 -1
  72. package/dist/client/use-db-sync.js +88 -1
  73. package/dist/client/use-db-sync.js.map +1 -1
  74. package/dist/collab/client.d.ts.map +1 -1
  75. package/dist/collab/client.js +43 -4
  76. package/dist/collab/client.js.map +1 -1
  77. package/dist/deploy/build.d.ts +2 -0
  78. package/dist/deploy/build.d.ts.map +1 -1
  79. package/dist/deploy/build.js +96 -0
  80. package/dist/deploy/build.js.map +1 -1
  81. package/dist/observability/routes.d.ts +3 -3
  82. package/dist/server/core-routes-plugin.d.ts +10 -0
  83. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  84. package/dist/server/core-routes-plugin.js +103 -9
  85. package/dist/server/core-routes-plugin.js.map +1 -1
  86. package/docs/content/agent-native-toolkit.mdx +1 -1
  87. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  88. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  89. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  90. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  91. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  92. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  93. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  94. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  95. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  96. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  97. package/docs/content/toolkit-agent-ux.mdx +1 -1
  98. package/docs/content/toolkit-app-adapters.mdx +1 -1
  99. package/docs/content/toolkit-collaboration-ui.mdx +1 -1
  100. package/docs/content/toolkit-collaboration.mdx +1 -1
  101. package/docs/content/toolkit-command-navigation.mdx +2 -2
  102. package/docs/content/toolkit-comments-review.mdx +1 -1
  103. package/docs/content/toolkit-history.mdx +1 -1
  104. package/docs/content/toolkit-observability.mdx +1 -1
  105. package/docs/content/toolkit-org-team.mdx +1 -1
  106. package/docs/content/toolkit-resources.mdx +1 -1
  107. package/docs/content/toolkit-settings.mdx +1 -1
  108. package/docs/content/toolkit-setup-connections.mdx +1 -1
  109. package/docs/content/toolkit-sharing-ui.mdx +1 -1
  110. package/docs/content/toolkit-sharing.mdx +1 -1
  111. package/docs/content/toolkit-shell-hooks.mdx +1 -1
  112. package/docs/content/toolkit-ui.mdx +1 -1
  113. package/package.json +1 -1
@@ -0,0 +1,124 @@
1
+ // Resize-handle hit-zone geometry for the host-side selection chrome
2
+ // (SelectionBox / screen-frame / draft-primitive handles in
3
+ // MultiScreenCanvas.tsx).
4
+ //
5
+ // The chrome is drawn inside the pan/zoom-scaled world container, so every
6
+ // screen-space size is multiplied by chromeScale (= 1 / zoomScale) to stay a
7
+ // constant size on screen. That compensation is correct for the VISUAL chrome,
8
+ // but it makes handle HIT zones grow without bound in local (board) units as
9
+ // you zoom out: at 19% zoom a nominal 14px edge bar is ~74 local px thick,
10
+ // reaching ~37 local px into the frame from each edge. For any frame shorter
11
+ // than twice that reach, the opposing N/S (or W/E) hit bars overlap and
12
+ // jointly cover the ENTIRE frame body — every press resolves to a resize and
13
+ // the frame can never be grabbed for a move drag (dnd finding: "scale-
14
+ // compensated resize-handle hit-zones can completely cover a selected
15
+ // element's body at low zoom").
16
+ //
17
+ // Figma bar: handles keep their constant on-screen size, but their hit slop
18
+ // must never eat the element's own body — a press near the element's center
19
+ // engages a MOVE at any zoom. These helpers implement that by clamping only
20
+ // the INWARD reach of each hit zone to a fraction of the frame's own
21
+ // dimension, leaving the outward reach (which can never occlude the body)
22
+ // untouched. With HANDLE_MAX_INWARD_FRACTION = 0.25, two opposing handles
23
+ // consume at most half of the frame's dimension, so the central 50% band of
24
+ // each axis is always body-grabbable.
25
+ //
26
+ // Keep in sync with the in-iframe selection chrome's mirror of this clamp in
27
+ // bridge/editor-chrome.bridge.ts (applySelectionHandleHitGeometry /
28
+ // clampHandleInwardReach — bridge files are self-contained, so it ports these
29
+ // pure functions locally with its own nominal handle sizes).
30
+
31
+ /** Nominal hit slop of an invisible edge-resize bar beyond the frame edge,
32
+ * in screen px. Never clamped: space outside the frame can't occlude it. */
33
+ export const EDGE_HANDLE_HIT_OUTWARD_PX = 7;
34
+
35
+ /** Nominal hit slop of an invisible edge-resize bar into the frame body, in
36
+ * screen px. Clamped by clampHandleInwardReach on small/zoomed-out frames. */
37
+ export const EDGE_HANDLE_HIT_INWARD_PX = 7;
38
+
39
+ /** Visible corner-handle square size, in screen px. The square is also its
40
+ * own hit target, so its inward quadrant is subject to the same clamp. */
41
+ export const CORNER_HANDLE_SIZE_PX = 10;
42
+
43
+ /** Maximum fraction of the frame's own dimension a single handle's hit zone
44
+ * may reach inward past the frame edge. 0.25 guarantees the central 50% of
45
+ * each axis stays free of handle hit zones (opposing handles reach 25% each),
46
+ * so a center press always engages a body move, matching Figma. */
47
+ export const HANDLE_MAX_INWARD_FRACTION = 0.25;
48
+
49
+ /**
50
+ * Clamps a handle hit zone's inward reach (local px past the frame edge,
51
+ * toward the frame center) so it never exceeds HANDLE_MAX_INWARD_FRACTION of
52
+ * the frame's own dimension on that axis.
53
+ *
54
+ * Non-finite or non-positive dimensions (unknown frame size, degenerate
55
+ * zero-size frames mid-creation) return the nominal reach unchanged — that is
56
+ * exactly the pre-clamp behavior, and a zero-size frame has no body to
57
+ * protect.
58
+ */
59
+ export function clampHandleInwardReach(
60
+ nominalInward: number,
61
+ frameDimension: number,
62
+ ): number {
63
+ if (!Number.isFinite(frameDimension) || frameDimension <= 0) {
64
+ return nominalInward;
65
+ }
66
+ return Math.min(nominalInward, frameDimension * HANDLE_MAX_INWARD_FRACTION);
67
+ }
68
+
69
+ export interface EdgeHandleHitGeometry {
70
+ /** Total bar thickness along its resize axis, in local px. */
71
+ thickness: number;
72
+ /** Offset of the bar's outward side from the frame edge, in local px
73
+ * (negative: starts outside the frame). Apply as `top` for the N bar,
74
+ * `bottom` for S, `left` for W, `right` for E. */
75
+ outwardOffset: number;
76
+ }
77
+
78
+ /**
79
+ * Hit geometry for an invisible edge-resize bar. `frameDimension` is the
80
+ * frame's size in local px along the bar's resize axis (height for N/S bars,
81
+ * width for W/E bars). On large frames this returns the historical geometry
82
+ * exactly: 14 * chromeScale thick, centered on the edge.
83
+ */
84
+ export function getEdgeHandleHitGeometry(
85
+ chromeScale: number,
86
+ frameDimension: number,
87
+ ): EdgeHandleHitGeometry {
88
+ const outward = EDGE_HANDLE_HIT_OUTWARD_PX * chromeScale;
89
+ const inward = clampHandleInwardReach(
90
+ EDGE_HANDLE_HIT_INWARD_PX * chromeScale,
91
+ frameDimension,
92
+ );
93
+ return { thickness: outward + inward, outwardOffset: -outward };
94
+ }
95
+
96
+ export interface CornerHandleGeometry {
97
+ /** Square side length in local px (constant CORNER_HANDLE_SIZE_PX on
98
+ * screen — the visual size is never clamped, only its placement). */
99
+ size: number;
100
+ /** Offset from the frame's vertical edge, in local px (negative: outside).
101
+ * Apply as `left` for W-side corners, `right` for E-side corners. */
102
+ offsetX: number;
103
+ /** Offset from the frame's horizontal edge, in local px (negative:
104
+ * outside). Apply as `top` for N-side corners, `bottom` for S-side. */
105
+ offsetY: number;
106
+ }
107
+
108
+ /**
109
+ * Geometry for a visible corner-handle square. The square keeps its constant
110
+ * on-screen size, but when its nominal half-inward overlap would exceed the
111
+ * per-axis clamp (tiny frame and/or low zoom), the square shifts outward so
112
+ * only the clamped reach overlaps the body. On large frames this returns the
113
+ * historical geometry exactly: centered on the corner (offset -size / 2).
114
+ */
115
+ export function getCornerHandleGeometry(
116
+ chromeScale: number,
117
+ frameWidth: number,
118
+ frameHeight: number,
119
+ ): CornerHandleGeometry {
120
+ const size = CORNER_HANDLE_SIZE_PX * chromeScale;
121
+ const inwardX = clampHandleInwardReach(size / 2, frameWidth);
122
+ const inwardY = clampHandleInwardReach(size / 2, frameHeight);
123
+ return { size, offsetX: inwardX - size, offsetY: inwardY - size };
124
+ }
@@ -222,6 +222,12 @@ export interface MultiScreenCanvasProps {
222
222
  /** data-agent-native-node-id of the deepest container at the drop point
223
223
  * inside the target screen iframe (undefined when hit-test timed out). */
224
224
  targetAnchorNodeId?: string;
225
+ /** Pending node id minted by the hit-test bridge for an id-less anchor —
226
+ * see CrossScreenHitTestResult.pendingNodeId's doc for the handshake. */
227
+ targetAnchorPendingNodeId?: string;
228
+ /** Source-equivalent structural selector locating the pending anchor in
229
+ * the persisted dest document (CrossScreenHitTestResult.anchorSelector). */
230
+ targetAnchorSelector?: string;
225
231
  /** DOM insertion placement relative to the anchor node. */
226
232
  targetAnchorPlacement?: "before" | "after" | "inside";
227
233
  /** Whether the target should receive an in-flow insert or an absolute child. */
@@ -793,6 +799,23 @@ export interface CrossScreenHitTestAnchorRect {
793
799
 
794
800
  export interface CrossScreenHitTestResult {
795
801
  anchorNodeId?: string;
802
+ /**
803
+ * Minted by the hit-test bridge when the resolved anchor has no stable id
804
+ * (AI-generated screens): the anchor's live DOM carries it as
805
+ * `data-an-pending-node-id`, and `anchorSelector` (below) locates the same
806
+ * element in the PERSISTED source so a host can stamp the pending id as
807
+ * the real `data-agent-native-node-id` before resolving the drop — the
808
+ * two-step id-on-demand handshake mirroring editor-chrome's selection
809
+ * contract. Without passing these through, drops into id-less screens
810
+ * silently degrade to absolute placement.
811
+ */
812
+ pendingNodeId?: string;
813
+ /**
814
+ * Body-rooted source-equivalent structural path for the pending anchor
815
+ * (skips Alpine-generated runtime nodes + editor overlays). Absent when
816
+ * the anchor is itself an Alpine-generated instance with no source node.
817
+ */
818
+ anchorSelector?: string;
796
819
  placement?: CrossScreenDropPlacement;
797
820
  axis?: CrossScreenDropAxis;
798
821
  dropMode?: CrossScreenDropMode;
@@ -648,6 +648,7 @@ const messages = {
648
648
  propsPasted: "屬性已貼上",
649
649
  primitiveInsertFailed: "無法將該圖層新增到畫面",
650
650
  layerMoveFailed: "無法移動該圖層",
651
+ layerMoveRedirected: "已移至原位置附近——精確的放置目標無法編輯",
651
652
  duplicateElementFailed: "無法複製該元素",
652
653
  eyedropperUnsupported: "此瀏覽器不支援取色器",
653
654
  saveCopyError: "無法儲存這個設計的副本",
@@ -665,6 +665,8 @@ const enUS = {
665
665
  propsPasted: "Properties pasted",
666
666
  primitiveInsertFailed: "Could not add that layer to the screen",
667
667
  layerMoveFailed: "Could not move that layer",
668
+ layerMoveRedirected:
669
+ "Moved next to its original spot — the exact drop target isn't editable",
668
670
  duplicateElementFailed: "Could not duplicate that element",
669
671
  eyedropperUnsupported: "Eyedropper isn't supported in this browser",
670
672
  saveCopyError: "Could not save a copy of this design",
@@ -8447,6 +8449,7 @@ const designCanvasFeatureOverrides = {
8447
8449
  propsPasted: "属性已粘贴",
8448
8450
  primitiveInsertFailed: "无法将该图层添加到画面",
8449
8451
  layerMoveFailed: "无法移动该图层",
8452
+ layerMoveRedirected: "已移动到原位置附近——精确的放置目标不可编辑",
8450
8453
  duplicateElementFailed: "无法复制该元素",
8451
8454
  eyedropperUnsupported: "此浏览器不支持取色器",
8452
8455
  },
@@ -8522,6 +8525,8 @@ const designCanvasFeatureOverrides = {
8522
8525
  propsPasted: "Propiedades pegadas",
8523
8526
  primitiveInsertFailed: "No se pudo añadir esa capa a la pantalla",
8524
8527
  layerMoveFailed: "No se pudo mover esa capa",
8528
+ layerMoveRedirected:
8529
+ "Se movió cerca de su lugar original — el destino exacto no es editable",
8525
8530
  duplicateElementFailed: "No se pudo duplicar ese elemento",
8526
8531
  eyedropperUnsupported:
8527
8532
  "El cuentagotas no es compatible con este navegador",
@@ -8598,6 +8603,8 @@ const designCanvasFeatureOverrides = {
8598
8603
  propsPasted: "Propriétés collées",
8599
8604
  primitiveInsertFailed: "Impossible d’ajouter ce calque à l’écran",
8600
8605
  layerMoveFailed: "Impossible de déplacer ce calque",
8606
+ layerMoveRedirected:
8607
+ "Déplacé à proximité de son emplacement d’origine — la cible exacte n’est pas modifiable",
8601
8608
  duplicateElementFailed: "Impossible de dupliquer cet élément",
8602
8609
  eyedropperUnsupported:
8603
8610
  "La pipette n'est pas prise en charge par ce navigateur",
@@ -8675,6 +8682,8 @@ const designCanvasFeatureOverrides = {
8675
8682
  primitiveInsertFailed:
8676
8683
  "Diese Ebene konnte nicht zur Ansicht hinzugefügt werden",
8677
8684
  layerMoveFailed: "Diese Ebene konnte nicht verschoben werden",
8685
+ layerMoveRedirected:
8686
+ "In die Nähe der ursprünglichen Stelle verschoben — das genaue Ziel ist nicht bearbeitbar",
8678
8687
  duplicateElementFailed: "Dieses Element konnte nicht dupliziert werden",
8679
8688
  eyedropperUnsupported:
8680
8689
  "Die Pipette wird von diesem Browser nicht unterstützt",
@@ -8751,6 +8760,8 @@ const designCanvasFeatureOverrides = {
8751
8760
  propsPasted: "プロパティを貼り付けました",
8752
8761
  primitiveInsertFailed: "そのレイヤーを画面に追加できませんでした",
8753
8762
  layerMoveFailed: "そのレイヤーを移動できませんでした",
8763
+ layerMoveRedirected:
8764
+ "元の位置の近くに移動しました — 正確なドロップ先は編集できません",
8754
8765
  duplicateElementFailed: "その要素を複製できませんでした",
8755
8766
  eyedropperUnsupported: "このブラウザではスポイトツールを使用できません",
8756
8767
  },
@@ -8826,6 +8837,8 @@ const designCanvasFeatureOverrides = {
8826
8837
  propsPasted: "속성이 붙여넣어짐",
8827
8838
  primitiveInsertFailed: "해당 레이어를 화면에 추가할 수 없습니다",
8828
8839
  layerMoveFailed: "해당 레이어를 이동할 수 없습니다",
8840
+ layerMoveRedirected:
8841
+ "원래 위치 근처로 이동되었습니다 — 정확한 놓기 대상은 편집할 수 없습니다",
8829
8842
  duplicateElementFailed: "해당 요소를 복제할 수 없습니다",
8830
8843
  eyedropperUnsupported: "이 브라우저에서는 스포이드를 지원하지 않습니다",
8831
8844
  },
@@ -8901,6 +8914,8 @@ const designCanvasFeatureOverrides = {
8901
8914
  propsPasted: "Propriedades coladas",
8902
8915
  primitiveInsertFailed: "Não foi possível adicionar essa camada à tela",
8903
8916
  layerMoveFailed: "Não foi possível mover essa camada",
8917
+ layerMoveRedirected:
8918
+ "Movido para perto do local original — o destino exato não é editável",
8904
8919
  duplicateElementFailed: "Não foi possível duplicar esse elemento",
8905
8920
  eyedropperUnsupported:
8906
8921
  "O conta-gotas não é compatível com este navegador",
@@ -8977,6 +8992,8 @@ const designCanvasFeatureOverrides = {
8977
8992
  propsPasted: "गुण चिपकाए गए",
8978
8993
  primitiveInsertFailed: "उस परत को स्क्रीन में नहीं जोड़ा जा सका",
8979
8994
  layerMoveFailed: "उस परत को स्थानांतरित नहीं किया जा सका",
8995
+ layerMoveRedirected:
8996
+ "मूल स्थान के पास ले जाया गया — सटीक ड्रॉप लक्ष्य संपादन योग्य नहीं है",
8980
8997
  duplicateElementFailed: "उस तत्व की प्रतिलिपि नहीं बनाई जा सकी",
8981
8998
  eyedropperUnsupported: "इस ब्राउज़र में आई-ड्रॉपर समर्थित नहीं है",
8982
8999
  },
@@ -9052,6 +9069,8 @@ const designCanvasFeatureOverrides = {
9052
9069
  propsPasted: "تم لصق الخصائص",
9053
9070
  primitiveInsertFailed: "تعذرت إضافة تلك الطبقة إلى الشاشة",
9054
9071
  layerMoveFailed: "تعذر نقل تلك الطبقة",
9072
+ layerMoveRedirected:
9073
+ "تم النقل بالقرب من الموضع الأصلي — الهدف الدقيق للإفلات غير قابل للتحرير",
9055
9074
  duplicateElementFailed: "تعذّر تكرار هذا العنصر",
9056
9075
  eyedropperUnsupported: "أداة القطارة غير مدعومة في هذا المتصفح",
9057
9076
  },
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Dragging a free-floating element into a layout column or row no longer leaves it stranded far from the drop point; it now lands cleanly in the indicated slot.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Dragging a repeated list item (like a to-do card generated from data) now shows a clear "Can't reorder repeated items" message instead of silently snapping back after the drop.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Dragging an element onto a button or chip's middle no longer merges it inside the button's label; it now reorders as a sibling like other layout containers.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Elements dropped into another board shape now stay exactly where you dropped them, render inside their parent, and previously misplaced nested elements are repaired automatically
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed drag-reordering elements within a screen no longer silently loses edits after the first one when a reload happens shortly after
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed dragging an element from a screen onto the canvas now drops it exactly under the cursor instead of drifting away
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed dragging elements between screens into AI-generated content no longer corrupts the layout by landing inside hidden template markup
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed moving elements between screens no longer bakes internal editor styling into the design's HTML
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed the cross-screen drop indicator now points at the correct spot for duplicated or newly created screens
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Fixed the zoom menu no longer leaves the canvas unresponsive to clicks and scrolling after choosing a zoom preset
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Text drawn on the canvas is now readable white instead of invisible black when the app is in light theme
@@ -94,6 +94,16 @@ export interface SourceWorkspaceContext {
94
94
  sourceType: DesignSourceType;
95
95
  canEdit: boolean;
96
96
  files: SourceWorkspaceFile[];
97
+ /**
98
+ * The design's reserved board overlay file id (designs.data.boardFileId),
99
+ * when one has been created. The board file is deliberately excluded from
100
+ * `files` above (see isBoardFile filter below) since it isn't a source
101
+ * file the code workbench edits — callers that need to recognize "this id
102
+ * is the board, not a missing file" (e.g. read-source-file's graceful
103
+ * no-op) should check against this instead of treating an unresolved id
104
+ * as an error.
105
+ */
106
+ boardFileId: string | null;
97
107
  }
98
108
 
99
109
  function parseDesignDataSourceType(value: unknown): DesignSourceType {
@@ -110,6 +120,20 @@ function parseDesignDataSourceType(value: unknown): DesignSourceType {
110
120
  return "inline";
111
121
  }
112
122
 
123
+ function parseDesignDataBoardFileId(value: unknown): string | null {
124
+ if (typeof value !== "string") return null;
125
+ try {
126
+ const parsed: unknown = JSON.parse(value);
127
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
128
+ const raw = (parsed as Record<string, unknown>).boardFileId;
129
+ return typeof raw === "string" && raw.length > 0 ? raw : null;
130
+ }
131
+ } catch {
132
+ // Invalid design data — no board file id available.
133
+ }
134
+ return null;
135
+ }
136
+
113
137
  function roleCanEdit(role: unknown): boolean {
114
138
  return role === "owner" || role === "admin" || role === "editor";
115
139
  }
@@ -147,13 +171,13 @@ export async function resolveSourceWorkspace(
147
171
  .from(schema.designFiles)
148
172
  .where(eq(schema.designFiles.designId, designId));
149
173
 
174
+ const resourceData = (access.resource as { data?: unknown }).data;
150
175
  return {
151
176
  designId,
152
- sourceType: parseDesignDataSourceType(
153
- (access.resource as { data?: unknown }).data,
154
- ),
177
+ sourceType: parseDesignDataSourceType(resourceData),
155
178
  canEdit: roleCanEdit(access.role),
156
179
  files: files.filter((file) => !isBoardFile(file.filename)),
180
+ boardFileId: parseDesignDataBoardFileId(resourceData),
157
181
  };
158
182
  }
159
183