@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.
- package/README.md +34 -7
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +20 -0
- package/corpus/core/docs/content/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/toolkit-agent-ux.mdx +1 -1
- package/corpus/core/docs/content/toolkit-app-adapters.mdx +1 -1
- package/corpus/core/docs/content/toolkit-collaboration-ui.mdx +1 -1
- package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
- package/corpus/core/docs/content/toolkit-command-navigation.mdx +2 -2
- package/corpus/core/docs/content/toolkit-comments-review.mdx +1 -1
- package/corpus/core/docs/content/toolkit-history.mdx +1 -1
- package/corpus/core/docs/content/toolkit-observability.mdx +1 -1
- package/corpus/core/docs/content/toolkit-org-team.mdx +1 -1
- package/corpus/core/docs/content/toolkit-resources.mdx +1 -1
- package/corpus/core/docs/content/toolkit-settings.mdx +1 -1
- package/corpus/core/docs/content/toolkit-setup-connections.mdx +1 -1
- package/corpus/core/docs/content/toolkit-sharing-ui.mdx +1 -1
- package/corpus/core/docs/content/toolkit-sharing.mdx +1 -1
- package/corpus/core/docs/content/toolkit-shell-hooks.mdx +1 -1
- package/corpus/core/docs/content/toolkit-ui.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/use-db-sync.ts +99 -1
- package/corpus/core/src/collab/client.ts +49 -4
- package/corpus/core/src/deploy/build.ts +156 -0
- package/corpus/core/src/server/core-routes-plugin.ts +137 -8
- package/corpus/templates/clips/changelog/2026-07-07-faster-local-whisper-dictation-start.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +311 -31
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +2 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +9 -0
- package/corpus/templates/design/actions/read-source-file.ts +28 -0
- package/corpus/templates/design/actions/update-file.ts +76 -7
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +181 -1
- package/corpus/templates/design/app/components/design/EditPanel.tsx +4 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +387 -25
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1110 -88
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +368 -16
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +24 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +27 -6
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +18 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +5 -4
- package/corpus/templates/design/app/components/design/multi-screen/handle-hit-zones.ts +124 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +23 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +19 -0
- package/corpus/templates/design/changelog/2026-07-07-dragging-a-free-floating-element-into-a-layout-column-or-row.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-dragging-a-repeated-list-item-like-a-to-do-card-generated-fr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-dragging-an-element-onto-a-button-or-chip-s-middle-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-elements-dropped-into-another-board-shape-now-stay-exactly-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-drag-reordering-elements-within-a-screen-no-longer-sil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-an-element-from-a-screen-onto-the-canvas-now-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-elements-between-screens-into-ai-generated-co.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-moving-elements-between-screens-no-longer-bakes-intern.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-the-cross-screen-drop-indicator-now-points-at-the-corr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-fixed-the-zoom-menu-no-longer-leaves-the-canvas-unresponsive.md +6 -0
- package/corpus/templates/design/changelog/2026-07-07-text-drawn-on-the-canvas-is-now-readable-white-instead-of-in.md +6 -0
- package/corpus/templates/design/server/source-workspace.ts +27 -3
- package/corpus/templates/design/shared/board-file.ts +359 -0
- package/corpus/templates/design/shared/breakpoint-media.ts +21 -3
- package/corpus/templates/design/shared/code-layer.ts +145 -10
- package/dist/client/use-db-sync.d.ts +18 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +88 -1
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +43 -4
- package/dist/collab/client.js.map +1 -1
- package/dist/deploy/build.d.ts +2 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +96 -0
- package/dist/deploy/build.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/server/core-routes-plugin.d.ts +10 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +103 -9
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/docs/content/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
- package/docs/content/toolkit-agent-ux.mdx +1 -1
- package/docs/content/toolkit-app-adapters.mdx +1 -1
- package/docs/content/toolkit-collaboration-ui.mdx +1 -1
- package/docs/content/toolkit-collaboration.mdx +1 -1
- package/docs/content/toolkit-command-navigation.mdx +2 -2
- package/docs/content/toolkit-comments-review.mdx +1 -1
- package/docs/content/toolkit-history.mdx +1 -1
- package/docs/content/toolkit-observability.mdx +1 -1
- package/docs/content/toolkit-org-team.mdx +1 -1
- package/docs/content/toolkit-resources.mdx +1 -1
- package/docs/content/toolkit-settings.mdx +1 -1
- package/docs/content/toolkit-setup-connections.mdx +1 -1
- package/docs/content/toolkit-sharing-ui.mdx +1 -1
- package/docs/content/toolkit-sharing.mdx +1 -1
- package/docs/content/toolkit-shell-hooks.mdx +1 -1
- package/docs/content/toolkit-ui.mdx +1 -1
- 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
|
},
|
|
@@ -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
|
|