@tangle-network/agent-app 0.27.2 → 0.28.0
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/dist/DesignCanvas-AOIVN3SJ.js +12 -0
- package/dist/DesignCanvasEditor-TN7CWUJW.js +13 -0
- package/dist/{TimelineEditor-JDG54OBP.js → TimelineEditor-Z7C6BFP5.js} +2 -2
- package/dist/{apply-Cp8c3K9D.d.ts → apply-Gk4raT2j.d.ts} +3 -1
- package/dist/{chunk-AFDROJ64.js → chunk-2QI7XV2T.js} +1 -1
- package/dist/chunk-2QI7XV2T.js.map +1 -0
- package/dist/{chunk-LUE4HO5C.js → chunk-4IQMTTNE.js} +10 -10
- package/dist/chunk-4IQMTTNE.js.map +1 -0
- package/dist/{chunk-HABVCJJT.js → chunk-7I37CO5D.js} +271 -404
- package/dist/chunk-7I37CO5D.js.map +1 -0
- package/dist/{chunk-5RT6KY4G.js → chunk-GQRL6VNU.js} +1 -1
- package/dist/chunk-GQRL6VNU.js.map +1 -0
- package/dist/{chunk-SCG5JJ4C.js → chunk-HFC4BTWJ.js} +32 -4
- package/dist/chunk-HFC4BTWJ.js.map +1 -0
- package/dist/{chunk-7QCIYDGC.js → chunk-IOREXWLM.js} +2 -2
- package/dist/chunk-J7JNV5BH.js +14 -0
- package/dist/chunk-J7JNV5BH.js.map +1 -0
- package/dist/{chunk-6UOE5CTA.js → chunk-JT6HHO5P.js} +5 -10
- package/dist/chunk-JT6HHO5P.js.map +1 -0
- package/dist/{chunk-JZAJE3JL.js → chunk-M2EBUDZ7.js} +19 -5
- package/dist/chunk-M2EBUDZ7.js.map +1 -0
- package/dist/{chunk-RJ2ZHK5D.js → chunk-S6WS2B32.js} +132 -7
- package/dist/chunk-S6WS2B32.js.map +1 -0
- package/dist/chunk-SQV7NUEM.js +136 -0
- package/dist/chunk-SQV7NUEM.js.map +1 -0
- package/dist/chunk-UAKFCMWK.js +1 -0
- package/dist/chunk-UAKFCMWK.js.map +1 -0
- package/dist/chunk-V5XZKHCL.js +296 -0
- package/dist/chunk-V5XZKHCL.js.map +1 -0
- package/dist/chunk-XWJXZ6WE.js +604 -0
- package/dist/chunk-XWJXZ6WE.js.map +1 -0
- package/dist/chunk-Y2SZVW35.js +125 -0
- package/dist/chunk-Y2SZVW35.js.map +1 -0
- package/dist/{chunk-27LQXQSS.js → chunk-YEWTVDDT.js} +224 -767
- package/dist/chunk-YEWTVDDT.js.map +1 -0
- package/dist/{chunk-UDXMR3AD.js → chunk-YNALYIQ3.js} +56 -18
- package/dist/chunk-YNALYIQ3.js.map +1 -0
- package/dist/command-stack-CkjelfK_.d.ts +267 -0
- package/dist/design-canvas/drizzle.d.ts +2 -2
- package/dist/design-canvas/index.d.ts +7 -6
- package/dist/design-canvas/index.js +3 -2
- package/dist/design-canvas-react/engine.d.ts +349 -0
- package/dist/design-canvas-react/engine.js +86 -0
- package/dist/design-canvas-react/engine.js.map +1 -0
- package/dist/design-canvas-react/index.d.ts +69 -649
- package/dist/design-canvas-react/index.js +84 -173
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/design-canvas-react/lazy.d.ts +6 -0
- package/dist/design-canvas-react/lazy.js +9 -0
- package/dist/design-canvas-react/lazy.js.map +1 -0
- package/dist/{export-presets-Dl5Aa5xj.d.ts → export-presets-DAsU5Wal.d.ts} +2 -143
- package/dist/flow-types-Cb_AblZs.d.ts +25 -0
- package/dist/index.d.ts +11 -8
- package/dist/index.js +21 -8
- package/dist/lazy-BHHqS8-j.d.ts +72 -0
- package/dist/missions/index.d.ts +12 -0
- package/dist/missions/index.js +1 -1
- package/dist/{model-BHLN208Z.d.ts → model-BBwyOuWG.d.ts} +3 -1
- package/dist/operations-DLIvvD00.d.ts +144 -0
- package/dist/platform/index.js +1 -1
- package/dist/runtime/index.d.ts +33 -33
- package/dist/runtime/index.js +1 -1
- package/dist/sequences/index.d.ts +1 -1
- package/dist/sequences/index.js +2 -1
- package/dist/sequences-react/index.d.ts +15 -1
- package/dist/sequences-react/index.js +2 -2
- package/dist/{store-CUStmtdH.d.ts → store-CFyxgTlD.d.ts} +1 -1
- package/dist/theme/index.d.ts +80 -0
- package/dist/theme/index.js +14 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/tailwind-preset.d.ts +65 -0
- package/dist/theme/tailwind-preset.js +33 -0
- package/dist/theme/tailwind-preset.js.map +1 -0
- package/dist/theme/tokens.css +95 -0
- package/dist/trace/index.d.ts +2 -18
- package/dist/trace/index.js +2 -2
- package/dist/web/index.d.ts +25 -2
- package/dist/web/index.js +3 -1
- package/dist/web-react/index.d.ts +71 -31
- package/dist/web-react/index.js +625 -486
- package/dist/web-react/index.js.map +1 -1
- package/package.json +28 -3
- package/dist/DesignCanvas-73IUJJUP.js +0 -10
- package/dist/DesignCanvasEditor-6F2UTOSW.js +0 -9
- package/dist/chunk-27LQXQSS.js.map +0 -1
- package/dist/chunk-5RT6KY4G.js.map +0 -1
- package/dist/chunk-6UOE5CTA.js.map +0 -1
- package/dist/chunk-AFDROJ64.js.map +0 -1
- package/dist/chunk-HABVCJJT.js.map +0 -1
- package/dist/chunk-JZAJE3JL.js.map +0 -1
- package/dist/chunk-LUE4HO5C.js.map +0 -1
- package/dist/chunk-RJ2ZHK5D.js.map +0 -1
- package/dist/chunk-SCG5JJ4C.js.map +0 -1
- package/dist/chunk-UDXMR3AD.js.map +0 -1
- /package/dist/{DesignCanvas-73IUJJUP.js.map → DesignCanvas-AOIVN3SJ.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-6F2UTOSW.js.map → DesignCanvasEditor-TN7CWUJW.js.map} +0 -0
- /package/dist/{TimelineEditor-JDG54OBP.js.map → TimelineEditor-Z7C6BFP5.js.map} +0 -0
- /package/dist/{chunk-7QCIYDGC.js.map → chunk-IOREXWLM.js.map} +0 -0
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BleedTrimOverlay,
|
|
3
|
-
DesignCanvas
|
|
3
|
+
DesignCanvas
|
|
4
|
+
} from "./chunk-YEWTVDDT.js";
|
|
5
|
+
import {
|
|
6
|
+
collectGridTargets,
|
|
7
|
+
createSnapEngine,
|
|
8
|
+
createZoomPanMath,
|
|
9
|
+
documentCropToStageCoords,
|
|
10
|
+
hitTestPoint,
|
|
11
|
+
identifyTaintedSrc,
|
|
12
|
+
isExportHiddenNodeName,
|
|
13
|
+
marqueeSelect,
|
|
14
|
+
resolveExportParams
|
|
15
|
+
} from "./chunk-V5XZKHCL.js";
|
|
16
|
+
import {
|
|
4
17
|
addElementCommand,
|
|
5
18
|
createSceneCommandStack,
|
|
6
19
|
deleteElementCommand,
|
|
@@ -8,15 +21,16 @@ import {
|
|
|
8
21
|
multiSetAttrsCommand,
|
|
9
22
|
setAttrsCommand,
|
|
10
23
|
ungroupElementCommand
|
|
11
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-XWJXZ6WE.js";
|
|
12
25
|
import {
|
|
13
26
|
SCENE_SCHEMA_VERSION,
|
|
14
|
-
bleedAwareExportBounds,
|
|
15
27
|
boundsIntersect,
|
|
16
28
|
elementAabb,
|
|
17
|
-
findElement
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
findElement
|
|
30
|
+
} from "./chunk-M2EBUDZ7.js";
|
|
31
|
+
import {
|
|
32
|
+
lightTheme
|
|
33
|
+
} from "./chunk-Y2SZVW35.js";
|
|
20
34
|
|
|
21
35
|
// src/design-canvas-react/components/Workspace.tsx
|
|
22
36
|
import {
|
|
@@ -27,42 +41,7 @@ import {
|
|
|
27
41
|
useRef as useRef4,
|
|
28
42
|
useState as useState2
|
|
29
43
|
} from "react";
|
|
30
|
-
import { Stage, Layer as Layer4, Rect as Rect2, Group as
|
|
31
|
-
|
|
32
|
-
// src/design-canvas-react/export-math.ts
|
|
33
|
-
function isExportHiddenNodeName(name) {
|
|
34
|
-
return name.startsWith("overlay:") || name === "Transformer";
|
|
35
|
-
}
|
|
36
|
-
function resolveExportParams(page, opts) {
|
|
37
|
-
const includeBleed = opts.preset !== void 0 ? opts.preset.includeBleed : opts.includeBleed ?? false;
|
|
38
|
-
const cropRect = bleedAwareExportBounds(page, includeBleed);
|
|
39
|
-
const pixelRatio = opts.preset !== void 0 ? scaleForPreset(opts.preset, cropRect) : opts.pixelRatio ?? 1;
|
|
40
|
-
const format = opts.preset !== void 0 ? opts.preset.format : opts.format;
|
|
41
|
-
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
42
|
-
return {
|
|
43
|
-
cropRect,
|
|
44
|
-
pixelRatio,
|
|
45
|
-
mimeType,
|
|
46
|
-
quality: format === "jpeg" ? 0.92 : void 0
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function identifyTaintedSrc(imageSrcs) {
|
|
50
|
-
for (const { src } of imageSrcs) {
|
|
51
|
-
if (isCrossOriginSrc(src)) return src;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
function isCrossOriginSrc(src) {
|
|
56
|
-
return /^https?:\/\//i.test(src);
|
|
57
|
-
}
|
|
58
|
-
function documentCropToStageCoords(cropRect, stageScale, stageX, stageY) {
|
|
59
|
-
return {
|
|
60
|
-
x: stageX + cropRect.x * stageScale,
|
|
61
|
-
y: stageY + cropRect.y * stageScale,
|
|
62
|
-
width: cropRect.width * stageScale,
|
|
63
|
-
height: cropRect.height * stageScale
|
|
64
|
-
};
|
|
65
|
-
}
|
|
44
|
+
import { Stage, Layer as Layer4, Rect as Rect2, Group as Group3 } from "react-konva";
|
|
66
45
|
|
|
67
46
|
// src/design-canvas-react/export.ts
|
|
68
47
|
async function exportPageDataUrl(stage, page, opts) {
|
|
@@ -144,247 +123,8 @@ function downloadDataUrl(dataUrl, filename) {
|
|
|
144
123
|
globalThis.document.body.removeChild(a);
|
|
145
124
|
}
|
|
146
125
|
|
|
147
|
-
// src/design-canvas-react/engine/snap.ts
|
|
148
|
-
var KIND_PRIORITY = {
|
|
149
|
-
"guide": 0,
|
|
150
|
-
"page-edge": 1,
|
|
151
|
-
"page-center": 2,
|
|
152
|
-
"element-edge": 3,
|
|
153
|
-
"element-center": 4,
|
|
154
|
-
"grid": 5
|
|
155
|
-
};
|
|
156
|
-
function createSnapEngine() {
|
|
157
|
-
return {
|
|
158
|
-
collectTargets(state, excludeIds) {
|
|
159
|
-
const page = state.document.pages.find((p) => p.id === state.activePageId);
|
|
160
|
-
if (!page) throw new Error(`collectTargets: active page ${state.activePageId} not found`);
|
|
161
|
-
const vertical = [];
|
|
162
|
-
const horizontal = [];
|
|
163
|
-
const excludeSet = new Set(excludeIds);
|
|
164
|
-
vertical.push({ position: 0, kind: "page-edge" });
|
|
165
|
-
vertical.push({ position: page.width, kind: "page-edge" });
|
|
166
|
-
vertical.push({ position: page.width / 2, kind: "page-center" });
|
|
167
|
-
horizontal.push({ position: 0, kind: "page-edge" });
|
|
168
|
-
horizontal.push({ position: page.height, kind: "page-edge" });
|
|
169
|
-
horizontal.push({ position: page.height / 2, kind: "page-center" });
|
|
170
|
-
for (const pos of page.guides.vertical) {
|
|
171
|
-
vertical.push({ position: pos, kind: "guide" });
|
|
172
|
-
}
|
|
173
|
-
for (const pos of page.guides.horizontal) {
|
|
174
|
-
horizontal.push({ position: pos, kind: "guide" });
|
|
175
|
-
}
|
|
176
|
-
collectElementTargets(page.elements, excludeSet, vertical, horizontal);
|
|
177
|
-
return { vertical, horizontal };
|
|
178
|
-
},
|
|
179
|
-
apply(bounds, targets, thresholdPx, zoom) {
|
|
180
|
-
if (!Number.isFinite(zoom) || zoom <= 0) {
|
|
181
|
-
throw new Error(`snap.apply: zoom must be a positive finite number, got ${zoom}`);
|
|
182
|
-
}
|
|
183
|
-
if (!Number.isFinite(thresholdPx) || thresholdPx < 0) {
|
|
184
|
-
throw new Error(`snap.apply: thresholdPx must be a non-negative finite number, got ${thresholdPx}`);
|
|
185
|
-
}
|
|
186
|
-
const threshold = thresholdPx / zoom;
|
|
187
|
-
const snappedX = snapAxis(bounds.x, bounds.x + bounds.width / 2, bounds.x + bounds.width, targets.vertical, threshold);
|
|
188
|
-
const snappedY = snapAxis(bounds.y, bounds.y + bounds.height / 2, bounds.y + bounds.height, targets.horizontal, threshold);
|
|
189
|
-
return {
|
|
190
|
-
x: snappedX !== null ? snappedX.docPosition - snappedX.elementOffset : bounds.x,
|
|
191
|
-
y: snappedY !== null ? snappedY.docPosition - snappedY.elementOffset : bounds.y,
|
|
192
|
-
activeVertical: snappedX !== null ? snappedX.target : null,
|
|
193
|
-
activeHorizontal: snappedY !== null ? snappedY.target : null
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
function collectGridTargets(bounds, gridSize, page, thresholdDocPx) {
|
|
199
|
-
if (!Number.isFinite(gridSize) || gridSize <= 0) {
|
|
200
|
-
throw new Error(`collectGridTargets: gridSize must be positive finite, got ${gridSize}`);
|
|
201
|
-
}
|
|
202
|
-
const vertical = [];
|
|
203
|
-
const horizontal = [];
|
|
204
|
-
const xMin = Math.floor((bounds.x - thresholdDocPx) / gridSize) * gridSize;
|
|
205
|
-
const xMax = Math.ceil((bounds.x + bounds.width + thresholdDocPx) / gridSize) * gridSize;
|
|
206
|
-
for (let x = xMin; x <= xMax; x += gridSize) {
|
|
207
|
-
if (x >= 0 && x <= page.width) vertical.push({ position: x, kind: "grid" });
|
|
208
|
-
}
|
|
209
|
-
const yMin = Math.floor((bounds.y - thresholdDocPx) / gridSize) * gridSize;
|
|
210
|
-
const yMax = Math.ceil((bounds.y + bounds.height + thresholdDocPx) / gridSize) * gridSize;
|
|
211
|
-
for (let y = yMin; y <= yMax; y += gridSize) {
|
|
212
|
-
if (y >= 0 && y <= page.height) horizontal.push({ position: y, kind: "grid" });
|
|
213
|
-
}
|
|
214
|
-
return { vertical, horizontal };
|
|
215
|
-
}
|
|
216
|
-
function snapAxis(start, center, end, targets, threshold) {
|
|
217
|
-
const candidates = [
|
|
218
|
-
{ value: start, offset: 0 },
|
|
219
|
-
{ value: center, offset: center - start },
|
|
220
|
-
{ value: end, offset: end - start }
|
|
221
|
-
];
|
|
222
|
-
let best = null;
|
|
223
|
-
let bestDistance = Infinity;
|
|
224
|
-
let bestPriority = Infinity;
|
|
225
|
-
for (const { value, offset } of candidates) {
|
|
226
|
-
for (const target of targets) {
|
|
227
|
-
const distance = Math.abs(target.position - value);
|
|
228
|
-
if (distance > threshold) continue;
|
|
229
|
-
const priority = KIND_PRIORITY[target.kind];
|
|
230
|
-
if (distance < bestDistance || distance === bestDistance && priority < bestPriority) {
|
|
231
|
-
bestDistance = distance;
|
|
232
|
-
bestPriority = priority;
|
|
233
|
-
best = { target, docPosition: target.position, elementOffset: offset };
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return best;
|
|
238
|
-
}
|
|
239
|
-
function collectElementTargets(elements, excludeIds, vertical, horizontal) {
|
|
240
|
-
for (const el of elements) {
|
|
241
|
-
if (!el.visible || el.locked) continue;
|
|
242
|
-
if (excludeIds.has(el.id)) continue;
|
|
243
|
-
const aabb = elementAabb(el);
|
|
244
|
-
vertical.push({ position: aabb.x, kind: "element-edge" });
|
|
245
|
-
vertical.push({ position: aabb.x + aabb.width / 2, kind: "element-center" });
|
|
246
|
-
vertical.push({ position: aabb.x + aabb.width, kind: "element-edge" });
|
|
247
|
-
horizontal.push({ position: aabb.y, kind: "element-edge" });
|
|
248
|
-
horizontal.push({ position: aabb.y + aabb.height / 2, kind: "element-center" });
|
|
249
|
-
horizontal.push({ position: aabb.y + aabb.height, kind: "element-edge" });
|
|
250
|
-
if (el.kind === "group") {
|
|
251
|
-
collectElementTargets(el.children, excludeIds, vertical, horizontal);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// src/design-canvas-react/engine/zoom-pan.ts
|
|
257
|
-
function createZoomPanMath(config) {
|
|
258
|
-
const { minZoom, maxZoom } = config;
|
|
259
|
-
if (!Number.isFinite(minZoom) || minZoom <= 0) {
|
|
260
|
-
throw new Error(`minZoom must be a positive finite number, got ${minZoom}`);
|
|
261
|
-
}
|
|
262
|
-
if (!Number.isFinite(maxZoom) || maxZoom <= minZoom) {
|
|
263
|
-
throw new Error(`maxZoom must be finite and greater than minZoom (${minZoom}), got ${maxZoom}`);
|
|
264
|
-
}
|
|
265
|
-
return {
|
|
266
|
-
minZoom,
|
|
267
|
-
maxZoom,
|
|
268
|
-
zoomAtPoint(state, factor, screenX, screenY) {
|
|
269
|
-
if (!Number.isFinite(factor) || factor <= 0) {
|
|
270
|
-
throw new Error(`zoomAtPoint: factor must be a positive finite number, got ${factor}`);
|
|
271
|
-
}
|
|
272
|
-
if (!Number.isFinite(screenX) || !Number.isFinite(screenY)) {
|
|
273
|
-
throw new Error(`zoomAtPoint: screenX/screenY must be finite numbers`);
|
|
274
|
-
}
|
|
275
|
-
if (!Number.isFinite(state.zoom) || state.zoom <= 0) {
|
|
276
|
-
throw new Error(`zoomAtPoint: state.zoom must be a positive finite number, got ${state.zoom}`);
|
|
277
|
-
}
|
|
278
|
-
const newZoom = Math.min(maxZoom, Math.max(minZoom, state.zoom * factor));
|
|
279
|
-
const docX = (screenX - state.panX) / state.zoom;
|
|
280
|
-
const docY = (screenY - state.panY) / state.zoom;
|
|
281
|
-
const panX = screenX - docX * newZoom;
|
|
282
|
-
const panY = screenY - docY * newZoom;
|
|
283
|
-
return { zoom: newZoom, panX, panY };
|
|
284
|
-
},
|
|
285
|
-
fitPage(page, viewport, paddingPx = 48) {
|
|
286
|
-
if (!Number.isFinite(page.width) || page.width <= 0) {
|
|
287
|
-
throw new Error(`fitPage: page.width must be a positive finite number, got ${page.width}`);
|
|
288
|
-
}
|
|
289
|
-
if (!Number.isFinite(page.height) || page.height <= 0) {
|
|
290
|
-
throw new Error(`fitPage: page.height must be a positive finite number, got ${page.height}`);
|
|
291
|
-
}
|
|
292
|
-
if (!Number.isFinite(viewport.width) || viewport.width <= 0) {
|
|
293
|
-
throw new Error(`fitPage: viewport.width must be a positive finite number, got ${viewport.width}`);
|
|
294
|
-
}
|
|
295
|
-
if (!Number.isFinite(viewport.height) || viewport.height <= 0) {
|
|
296
|
-
throw new Error(`fitPage: viewport.height must be a positive finite number, got ${viewport.height}`);
|
|
297
|
-
}
|
|
298
|
-
if (!Number.isFinite(paddingPx) || paddingPx < 0) {
|
|
299
|
-
throw new Error(`fitPage: paddingPx must be a non-negative finite number, got ${paddingPx}`);
|
|
300
|
-
}
|
|
301
|
-
const availW = viewport.width - paddingPx * 2;
|
|
302
|
-
const availH = viewport.height - paddingPx * 2;
|
|
303
|
-
const zoom = Math.min(maxZoom, Math.max(minZoom, Math.min(availW / page.width, availH / page.height)));
|
|
304
|
-
const panX = (viewport.width - page.width * zoom) / 2;
|
|
305
|
-
const panY = (viewport.height - page.height * zoom) / 2;
|
|
306
|
-
return { zoom, panX, panY };
|
|
307
|
-
},
|
|
308
|
-
documentToScreen(state, x, y) {
|
|
309
|
-
return { x: x * state.zoom + state.panX, y: y * state.zoom + state.panY };
|
|
310
|
-
},
|
|
311
|
-
screenToDocument(state, x, y) {
|
|
312
|
-
if (!Number.isFinite(state.zoom) || state.zoom === 0) {
|
|
313
|
-
throw new Error(`screenToDocument: zoom must be a non-zero finite number, got ${state.zoom}`);
|
|
314
|
-
}
|
|
315
|
-
return { x: (x - state.panX) / state.zoom, y: (y - state.panY) / state.zoom };
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// src/design-canvas-react/engine/selection.ts
|
|
321
|
-
function hitTestPoint(page, x, y) {
|
|
322
|
-
return hitTestIn(page.elements, x, y, null);
|
|
323
|
-
}
|
|
324
|
-
function hitTestIn(elements, x, y, resolveTo) {
|
|
325
|
-
for (let i = elements.length - 1; i >= 0; i -= 1) {
|
|
326
|
-
const el = elements[i];
|
|
327
|
-
if (!el.visible || el.locked) continue;
|
|
328
|
-
const aabb = elementAabb(el);
|
|
329
|
-
if (!pointInBounds(aabb, x, y)) continue;
|
|
330
|
-
if (el.kind === "group") {
|
|
331
|
-
const child = hitTestIn(el.children, x, y, el.id);
|
|
332
|
-
return child ?? el.id;
|
|
333
|
-
}
|
|
334
|
-
return resolveTo ?? el.id;
|
|
335
|
-
}
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
function pointInBounds(b, x, y) {
|
|
339
|
-
return x >= b.x && x <= b.x + b.width && y >= b.y && y <= b.y + b.height;
|
|
340
|
-
}
|
|
341
|
-
function marqueeSelect(page, rect, opts = {}) {
|
|
342
|
-
assertValidBounds(rect, "marqueeSelect rect");
|
|
343
|
-
const result = [];
|
|
344
|
-
collectMarqueeIds(page.elements, rect, opts.requireFullContainment ?? false, result);
|
|
345
|
-
return result;
|
|
346
|
-
}
|
|
347
|
-
function collectMarqueeIds(elements, rect, requireContainment, result) {
|
|
348
|
-
for (const el of elements) {
|
|
349
|
-
if (!el.visible || el.locked) continue;
|
|
350
|
-
const aabb = elementAabb(el);
|
|
351
|
-
if (el.kind === "group") {
|
|
352
|
-
if (boundsIntersect(rect, aabb)) {
|
|
353
|
-
collectMarqueeIds(el.children, rect, requireContainment, result);
|
|
354
|
-
}
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
const hit = requireContainment ? boundsContain(rect, aabb) : boundsIntersect(rect, aabb);
|
|
358
|
-
if (hit) result.push(el.id);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
function boundsContain(outer, inner) {
|
|
362
|
-
return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.width <= outer.x + outer.width && inner.y + inner.height <= outer.y + outer.height;
|
|
363
|
-
}
|
|
364
|
-
var NUDGE_NORMAL_PX = 1;
|
|
365
|
-
var NUDGE_SHIFT_PX = 10;
|
|
366
|
-
function nudgeDelta(key, shift) {
|
|
367
|
-
const step = shift ? NUDGE_SHIFT_PX : NUDGE_NORMAL_PX;
|
|
368
|
-
switch (key) {
|
|
369
|
-
case "ArrowLeft":
|
|
370
|
-
return { dx: -step, dy: 0 };
|
|
371
|
-
case "ArrowRight":
|
|
372
|
-
return { dx: step, dy: 0 };
|
|
373
|
-
case "ArrowUp":
|
|
374
|
-
return { dx: 0, dy: -step };
|
|
375
|
-
case "ArrowDown":
|
|
376
|
-
return { dx: 0, dy: step };
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
var DUPLICATE_OFFSET = { dx: 10, dy: 10 };
|
|
380
|
-
function assertValidBounds(bounds, label) {
|
|
381
|
-
if (!Number.isFinite(bounds.x) || !Number.isFinite(bounds.y) || !Number.isFinite(bounds.width) || !Number.isFinite(bounds.height)) {
|
|
382
|
-
throw new Error(`${label}: all fields must be finite numbers`);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
126
|
// src/design-canvas-react/components/ElementNode.tsx
|
|
387
|
-
import { useEffect, useRef, useState } from "react";
|
|
127
|
+
import { memo, useEffect, useRef, useState } from "react";
|
|
388
128
|
import { Group, Rect, Ellipse, Line, Text, Image as KonvaImage } from "react-konva";
|
|
389
129
|
|
|
390
130
|
// src/design-canvas-react/components/transform-math.ts
|
|
@@ -471,7 +211,7 @@ function snapRotation(angleDeg, thresholdDeg = 5) {
|
|
|
471
211
|
}
|
|
472
212
|
return bestDist <= thresholdDeg ? best : normalized;
|
|
473
213
|
}
|
|
474
|
-
function
|
|
214
|
+
function nudgeDelta(key, shift) {
|
|
475
215
|
const step = shift ? 10 : 1;
|
|
476
216
|
switch (key) {
|
|
477
217
|
case "ArrowLeft":
|
|
@@ -517,7 +257,7 @@ function useImage(src) {
|
|
|
517
257
|
}, [src]);
|
|
518
258
|
return imageCache.get(src) ?? null;
|
|
519
259
|
}
|
|
520
|
-
function
|
|
260
|
+
function ElementNodeImpl(props) {
|
|
521
261
|
const { element } = props;
|
|
522
262
|
if (!element.visible) return null;
|
|
523
263
|
switch (element.kind) {
|
|
@@ -537,33 +277,55 @@ function ElementNode(props) {
|
|
|
537
277
|
return /* @__PURE__ */ jsx(GroupNode, { ...props, element });
|
|
538
278
|
}
|
|
539
279
|
}
|
|
280
|
+
var ElementNode = memo(ElementNodeImpl);
|
|
540
281
|
function useDragBindings(props, originX, originY) {
|
|
541
282
|
const { element, onClick, onDragStart, onDragMove, onDragEnd, onDoubleClick } = props;
|
|
542
283
|
const isDraggable = !element.locked && !!onDragEnd;
|
|
543
284
|
const originRef = useRef({ x: originX, y: originY });
|
|
544
285
|
originRef.current = { x: originX, y: originY };
|
|
286
|
+
const [dragging, setDragging] = useState(false);
|
|
545
287
|
return {
|
|
546
288
|
draggable: isDraggable,
|
|
547
289
|
// locked elements still receive click for selection; listening must be true.
|
|
548
290
|
listening: true,
|
|
291
|
+
dragging,
|
|
549
292
|
onDragStart: isDraggable ? () => {
|
|
293
|
+
setDragging(true);
|
|
550
294
|
onDragStart?.(element.id);
|
|
551
295
|
} : void 0,
|
|
552
296
|
onDragMove: isDraggable ? (e) => {
|
|
553
297
|
onDragMove?.(element.id, e.target.x() - originRef.current.x, e.target.y() - originRef.current.y);
|
|
554
298
|
} : void 0,
|
|
555
299
|
onDragEnd: isDraggable ? (e) => {
|
|
300
|
+
setDragging(false);
|
|
556
301
|
onDragEnd?.(element.id, e.target.x(), e.target.y());
|
|
557
302
|
} : void 0,
|
|
558
303
|
onClick: () => onClick?.(element.id),
|
|
559
304
|
onDblClick: () => onDoubleClick?.(element.id)
|
|
560
305
|
};
|
|
561
306
|
}
|
|
307
|
+
function useNodeCache(ref, isSelected, dragging, zoom, invalidateKey) {
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
const node = ref.current;
|
|
310
|
+
if (!node) return;
|
|
311
|
+
if (isSelected || dragging) {
|
|
312
|
+
node.clearCache();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
node.cache();
|
|
316
|
+
return () => {
|
|
317
|
+
node.clearCache();
|
|
318
|
+
};
|
|
319
|
+
}, [ref, isSelected, dragging, zoom, invalidateKey]);
|
|
320
|
+
}
|
|
562
321
|
function RectNode({ element, ...rest }) {
|
|
563
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
322
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
323
|
+
const ref = useRef(null);
|
|
324
|
+
useNodeCache(ref, rest.isSelected, dragging, rest.zoom, element);
|
|
564
325
|
return /* @__PURE__ */ jsx(
|
|
565
326
|
Rect,
|
|
566
327
|
{
|
|
328
|
+
ref,
|
|
567
329
|
name: element.id,
|
|
568
330
|
x: element.x,
|
|
569
331
|
y: element.y,
|
|
@@ -581,10 +343,13 @@ function RectNode({ element, ...rest }) {
|
|
|
581
343
|
}
|
|
582
344
|
function EllipseNode({ element, ...rest }) {
|
|
583
345
|
const { x: cx, y: cy, radiusX, radiusY } = ellipseCenterFromTopLeft(element);
|
|
584
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
346
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
347
|
+
const ref = useRef(null);
|
|
348
|
+
useNodeCache(ref, rest.isSelected, dragging, rest.zoom, element);
|
|
585
349
|
return /* @__PURE__ */ jsx(
|
|
586
350
|
Ellipse,
|
|
587
351
|
{
|
|
352
|
+
ref,
|
|
588
353
|
name: element.id,
|
|
589
354
|
x: cx,
|
|
590
355
|
y: cy,
|
|
@@ -600,10 +365,13 @@ function EllipseNode({ element, ...rest }) {
|
|
|
600
365
|
);
|
|
601
366
|
}
|
|
602
367
|
function LineNode({ element, ...rest }) {
|
|
603
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
368
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
369
|
+
const ref = useRef(null);
|
|
370
|
+
useNodeCache(ref, rest.isSelected, dragging, rest.zoom, element);
|
|
604
371
|
return /* @__PURE__ */ jsx(
|
|
605
372
|
Line,
|
|
606
373
|
{
|
|
374
|
+
ref,
|
|
607
375
|
name: element.id,
|
|
608
376
|
x: element.x,
|
|
609
377
|
y: element.y,
|
|
@@ -624,11 +392,14 @@ var FONT_STYLE_MAP = {
|
|
|
624
392
|
"bold italic": { fontStyle: "italic", fontVariant: "normal", fontWeight: "bold" }
|
|
625
393
|
};
|
|
626
394
|
function TextNode({ element, ...rest }) {
|
|
627
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
395
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
396
|
+
const ref = useRef(null);
|
|
397
|
+
useNodeCache(ref, rest.isSelected, dragging, rest.zoom, element);
|
|
628
398
|
const { fontStyle, fontWeight } = FONT_STYLE_MAP[element.fontStyle];
|
|
629
399
|
return /* @__PURE__ */ jsx(
|
|
630
400
|
Text,
|
|
631
401
|
{
|
|
402
|
+
ref,
|
|
632
403
|
name: element.id,
|
|
633
404
|
x: element.x,
|
|
634
405
|
y: element.y,
|
|
@@ -647,15 +418,24 @@ function TextNode({ element, ...rest }) {
|
|
|
647
418
|
}
|
|
648
419
|
);
|
|
649
420
|
}
|
|
650
|
-
var BROKEN_FILL = "#e5e7eb";
|
|
651
|
-
var BROKEN_STROKE = "#9ca3af";
|
|
652
421
|
function ImageNode({ element, ...rest }) {
|
|
422
|
+
const render = rest.render ?? lightTheme.canvasRender;
|
|
653
423
|
const img = useImage(element.src);
|
|
654
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
424
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
425
|
+
const ref = useRef(null);
|
|
426
|
+
const imgReady = !!img && img.complete && img.naturalWidth > 0;
|
|
427
|
+
useNodeCache(
|
|
428
|
+
ref,
|
|
429
|
+
rest.isSelected,
|
|
430
|
+
dragging,
|
|
431
|
+
rest.zoom,
|
|
432
|
+
`${imgReady}:${element.src}:${element.width}x${element.height}:${element.fit}`
|
|
433
|
+
);
|
|
655
434
|
if (!img || !img.complete || img.naturalWidth === 0) {
|
|
656
435
|
return /* @__PURE__ */ jsx(
|
|
657
436
|
Rect,
|
|
658
437
|
{
|
|
438
|
+
ref,
|
|
659
439
|
name: element.id,
|
|
660
440
|
x: element.x,
|
|
661
441
|
y: element.y,
|
|
@@ -663,8 +443,8 @@ function ImageNode({ element, ...rest }) {
|
|
|
663
443
|
height: element.height,
|
|
664
444
|
rotation: element.rotation,
|
|
665
445
|
opacity: element.opacity,
|
|
666
|
-
fill:
|
|
667
|
-
stroke:
|
|
446
|
+
fill: render.brokenFill,
|
|
447
|
+
stroke: render.brokenStroke,
|
|
668
448
|
strokeWidth: 1,
|
|
669
449
|
...drag
|
|
670
450
|
}
|
|
@@ -699,6 +479,7 @@ function ImageNode({ element, ...rest }) {
|
|
|
699
479
|
return /* @__PURE__ */ jsx(
|
|
700
480
|
KonvaImage,
|
|
701
481
|
{
|
|
482
|
+
ref,
|
|
702
483
|
name: element.id,
|
|
703
484
|
x: element.x,
|
|
704
485
|
y: element.y,
|
|
@@ -713,12 +494,23 @@ function ImageNode({ element, ...rest }) {
|
|
|
713
494
|
);
|
|
714
495
|
}
|
|
715
496
|
function VideoNode({ element, ...rest }) {
|
|
497
|
+
const render = rest.render ?? lightTheme.canvasRender;
|
|
716
498
|
const img = useImage(element.posterSrc ?? "");
|
|
717
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
499
|
+
const { dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
500
|
+
const ref = useRef(null);
|
|
501
|
+
const posterReady = !!element.posterSrc && !!img && img.complete && img.naturalWidth > 0;
|
|
502
|
+
useNodeCache(
|
|
503
|
+
ref,
|
|
504
|
+
rest.isSelected,
|
|
505
|
+
dragging,
|
|
506
|
+
rest.zoom,
|
|
507
|
+
`${posterReady}:${element.posterSrc ?? ""}:${element.width}x${element.height}`
|
|
508
|
+
);
|
|
718
509
|
if (!element.posterSrc || !img || !img.complete || img.naturalWidth === 0) {
|
|
719
510
|
return /* @__PURE__ */ jsx(
|
|
720
511
|
Rect,
|
|
721
512
|
{
|
|
513
|
+
ref,
|
|
722
514
|
name: element.id,
|
|
723
515
|
x: element.x,
|
|
724
516
|
y: element.y,
|
|
@@ -726,8 +518,8 @@ function VideoNode({ element, ...rest }) {
|
|
|
726
518
|
height: element.height,
|
|
727
519
|
rotation: element.rotation,
|
|
728
520
|
opacity: element.opacity,
|
|
729
|
-
fill:
|
|
730
|
-
stroke:
|
|
521
|
+
fill: render.placeholderFill,
|
|
522
|
+
stroke: render.placeholderStroke,
|
|
731
523
|
strokeWidth: 1,
|
|
732
524
|
...drag
|
|
733
525
|
}
|
|
@@ -736,6 +528,7 @@ function VideoNode({ element, ...rest }) {
|
|
|
736
528
|
return /* @__PURE__ */ jsx(
|
|
737
529
|
KonvaImage,
|
|
738
530
|
{
|
|
531
|
+
ref,
|
|
739
532
|
name: element.id,
|
|
740
533
|
x: element.x,
|
|
741
534
|
y: element.y,
|
|
@@ -749,7 +542,8 @@ function VideoNode({ element, ...rest }) {
|
|
|
749
542
|
);
|
|
750
543
|
}
|
|
751
544
|
function GroupNode({ element, ...rest }) {
|
|
752
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
545
|
+
const { dragging: _dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
546
|
+
void _dragging;
|
|
753
547
|
return /* @__PURE__ */ jsx(
|
|
754
548
|
Group,
|
|
755
549
|
{
|
|
@@ -775,7 +569,8 @@ function SelectionLayer({
|
|
|
775
569
|
selectedElements,
|
|
776
570
|
canWrite,
|
|
777
571
|
onTransformEnd,
|
|
778
|
-
pageId
|
|
572
|
+
pageId,
|
|
573
|
+
render = lightTheme.canvasRender
|
|
779
574
|
}) {
|
|
780
575
|
const trRef = useRef2(null);
|
|
781
576
|
useEffect2(() => {
|
|
@@ -808,22 +603,35 @@ function SelectionLayer({
|
|
|
808
603
|
if (entries.length > 0) onTransformEnd(entries);
|
|
809
604
|
}
|
|
810
605
|
const multiSelect = selectedIds.length > 1;
|
|
811
|
-
return
|
|
812
|
-
Transformer
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
606
|
+
return (
|
|
607
|
+
// The Layer must participate in the hit graph (listening) or the Transformer
|
|
608
|
+
// anchors below receive no pointer events and resize/rotate is dead. We scope
|
|
609
|
+
// listening to canWrite so a read-only canvas stays fully click-through.
|
|
610
|
+
// Click-through to elements for selection is preserved: this layer paints
|
|
611
|
+
// only the Transformer, whose anchors are the sole hit targets — empty
|
|
612
|
+
// regions have no shapes, so pointer hits fall through to the content layer.
|
|
613
|
+
// Export exclusion is unaffected: export.ts hides nodes by the 'overlay:'
|
|
614
|
+
// name prefix, not by `listening` (see export-math.isExportHiddenNodeName).
|
|
615
|
+
/* @__PURE__ */ jsx2(Layer, { name: "overlay:selection", listening: canWrite, children: /* @__PURE__ */ jsx2(
|
|
616
|
+
Transformer,
|
|
617
|
+
{
|
|
618
|
+
ref: trRef,
|
|
619
|
+
name: "overlay:transformer",
|
|
620
|
+
keepRatio: multiSelect,
|
|
621
|
+
rotationSnaps: [0, 45, 90, 135, 180, 225, 270, 315],
|
|
622
|
+
rotationSnapTolerance: 5,
|
|
623
|
+
borderStroke: render.selectionStroke,
|
|
624
|
+
anchorStroke: render.selectionStroke,
|
|
625
|
+
anchorFill: render.selectionAnchorFill,
|
|
626
|
+
boundBoxFunc: (oldBox, newBox) => {
|
|
627
|
+
if (newBox.width < MIN_SIZE || newBox.height < MIN_SIZE) return oldBox;
|
|
628
|
+
return newBox;
|
|
629
|
+
},
|
|
630
|
+
listening: canWrite,
|
|
631
|
+
onTransformEnd: canWrite ? handleTransformEnd : void 0
|
|
632
|
+
}
|
|
633
|
+
) })
|
|
634
|
+
);
|
|
827
635
|
}
|
|
828
636
|
function elementToPriorAttrs(element) {
|
|
829
637
|
const base = {
|
|
@@ -916,78 +724,89 @@ function bakeNodeToAttrs(node, element) {
|
|
|
916
724
|
}
|
|
917
725
|
|
|
918
726
|
// src/design-canvas-react/components/GridLayer.tsx
|
|
919
|
-
import { Layer as Layer2,
|
|
920
|
-
import { jsx as jsx3
|
|
727
|
+
import { Layer as Layer2, Group as Group2, Shape } from "react-konva";
|
|
728
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
729
|
+
function gridVerticalLines(pageWidth, gridSize) {
|
|
730
|
+
const out = [];
|
|
731
|
+
if (gridSize <= 0) return out;
|
|
732
|
+
for (let x = gridSize; x < pageWidth; x += gridSize) out.push(x);
|
|
733
|
+
return out;
|
|
734
|
+
}
|
|
735
|
+
function gridHorizontalLines(pageHeight, gridSize) {
|
|
736
|
+
const out = [];
|
|
737
|
+
if (gridSize <= 0) return out;
|
|
738
|
+
for (let y = gridSize; y < pageHeight; y += gridSize) out.push(y);
|
|
739
|
+
return out;
|
|
740
|
+
}
|
|
921
741
|
function GridLayer({
|
|
922
742
|
pageWidth,
|
|
923
743
|
pageHeight,
|
|
924
744
|
gridSize,
|
|
925
745
|
zoom,
|
|
746
|
+
panX,
|
|
747
|
+
panY,
|
|
926
748
|
color = "#c0c0c0",
|
|
927
749
|
opacity = 0.5
|
|
928
750
|
}) {
|
|
929
751
|
if (!gridVisible(gridSize, zoom, 4)) return null;
|
|
930
|
-
const verticals =
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
opacity,
|
|
960
|
-
listening: false,
|
|
961
|
-
perfectDrawEnabled: false
|
|
962
|
-
},
|
|
963
|
-
`h-${y}`
|
|
964
|
-
))
|
|
965
|
-
] });
|
|
752
|
+
const verticals = gridVerticalLines(pageWidth, gridSize);
|
|
753
|
+
const horizontals = gridHorizontalLines(pageHeight, gridSize);
|
|
754
|
+
const sceneFunc = (ctx, shape) => {
|
|
755
|
+
ctx.beginPath();
|
|
756
|
+
for (const x of verticals) {
|
|
757
|
+
ctx.moveTo(x, 0);
|
|
758
|
+
ctx.lineTo(x, pageHeight);
|
|
759
|
+
}
|
|
760
|
+
for (const y of horizontals) {
|
|
761
|
+
ctx.moveTo(0, y);
|
|
762
|
+
ctx.lineTo(pageWidth, y);
|
|
763
|
+
}
|
|
764
|
+
ctx.setAttr("strokeStyle", color);
|
|
765
|
+
ctx.setAttr("lineWidth", 1 / zoom);
|
|
766
|
+
ctx.stroke();
|
|
767
|
+
void shape;
|
|
768
|
+
};
|
|
769
|
+
return /* @__PURE__ */ jsx3(Layer2, { name: "overlay:grid", listening: false, children: /* @__PURE__ */ jsx3(Group2, { x: panX, y: panY, scaleX: zoom, scaleY: zoom, children: /* @__PURE__ */ jsx3(
|
|
770
|
+
Shape,
|
|
771
|
+
{
|
|
772
|
+
name: "overlay:grid-shape",
|
|
773
|
+
sceneFunc,
|
|
774
|
+
stroke: color,
|
|
775
|
+
strokeWidth: 1 / zoom,
|
|
776
|
+
opacity,
|
|
777
|
+
listening: false,
|
|
778
|
+
perfectDrawEnabled: false
|
|
779
|
+
}
|
|
780
|
+
) }) });
|
|
966
781
|
}
|
|
967
782
|
|
|
968
783
|
// src/design-canvas-react/components/SnapGuidesOverlay.tsx
|
|
969
|
-
import { Layer as Layer3, Line as
|
|
970
|
-
import { jsx as jsx4, jsxs
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
784
|
+
import { Layer as Layer3, Line as Line2 } from "react-konva";
|
|
785
|
+
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
786
|
+
function kindColors(render) {
|
|
787
|
+
return {
|
|
788
|
+
"grid": render.snapGrid,
|
|
789
|
+
"guide": render.snapGuide,
|
|
790
|
+
"page-edge": render.snapPage,
|
|
791
|
+
"page-center": render.snapPage,
|
|
792
|
+
"element-edge": render.snapElement,
|
|
793
|
+
"element-center": render.snapElement
|
|
794
|
+
};
|
|
795
|
+
}
|
|
979
796
|
function SnapGuidesOverlay({
|
|
980
797
|
pageWidth,
|
|
981
798
|
pageHeight,
|
|
982
799
|
activeVertical,
|
|
983
800
|
activeHorizontal,
|
|
984
|
-
zoom
|
|
801
|
+
zoom,
|
|
802
|
+
render = lightTheme.canvasRender
|
|
985
803
|
}) {
|
|
986
804
|
if (!activeVertical && !activeHorizontal) return null;
|
|
805
|
+
const KIND_COLOR = kindColors(render);
|
|
987
806
|
const strokeWidth = 1 / zoom;
|
|
988
|
-
return /* @__PURE__ */
|
|
807
|
+
return /* @__PURE__ */ jsxs(Layer3, { name: "overlay:snap", listening: false, children: [
|
|
989
808
|
activeVertical && /* @__PURE__ */ jsx4(
|
|
990
|
-
|
|
809
|
+
Line2,
|
|
991
810
|
{
|
|
992
811
|
name: "overlay:snap-vertical",
|
|
993
812
|
points: [activeVertical.position, -99999, activeVertical.position, 99999],
|
|
@@ -999,7 +818,7 @@ function SnapGuidesOverlay({
|
|
|
999
818
|
}
|
|
1000
819
|
),
|
|
1001
820
|
activeHorizontal && /* @__PURE__ */ jsx4(
|
|
1002
|
-
|
|
821
|
+
Line2,
|
|
1003
822
|
{
|
|
1004
823
|
name: "overlay:snap-horizontal",
|
|
1005
824
|
points: [-99999, activeHorizontal.position, 99999, activeHorizontal.position],
|
|
@@ -1100,9 +919,9 @@ function InlineTextEditor({
|
|
|
1100
919
|
}
|
|
1101
920
|
|
|
1102
921
|
// src/design-canvas-react/components/Workspace.tsx
|
|
1103
|
-
import { jsx as jsx6, jsxs as
|
|
922
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1104
923
|
var SNAP_THRESHOLD_SCREEN_PX = 8;
|
|
1105
|
-
var
|
|
924
|
+
var DUPLICATE_OFFSET = 10;
|
|
1106
925
|
var ZOOM_FACTOR_WHEEL = 0.998;
|
|
1107
926
|
var ZOOM_MIN = 0.05;
|
|
1108
927
|
var ZOOM_MAX = 32;
|
|
@@ -1118,7 +937,8 @@ function WorkspaceView({
|
|
|
1118
937
|
onExport,
|
|
1119
938
|
onExportRef,
|
|
1120
939
|
fitOnMount = true,
|
|
1121
|
-
onReady
|
|
940
|
+
onReady,
|
|
941
|
+
render = lightTheme.canvasRender
|
|
1122
942
|
}) {
|
|
1123
943
|
const [, setTick] = useState2(0);
|
|
1124
944
|
const forceRender = useCallback(() => setTick((t) => t + 1), []);
|
|
@@ -1303,9 +1123,24 @@ function WorkspaceView({
|
|
|
1303
1123
|
setActiveSnap(null);
|
|
1304
1124
|
const origin = dragOriginRef.current.get(elementId);
|
|
1305
1125
|
if (!origin) return;
|
|
1306
|
-
const dx = finalX - origin.x;
|
|
1307
|
-
const dy = finalY - origin.y;
|
|
1308
1126
|
const draggingIds = selectedElementIds.includes(elementId) ? selectedElementIds : [elementId];
|
|
1127
|
+
let snappedX = finalX;
|
|
1128
|
+
let snappedY = finalY;
|
|
1129
|
+
if (snapEnabled) {
|
|
1130
|
+
const snapBounds = { x: finalX, y: finalY, width: origin.width, height: origin.height };
|
|
1131
|
+
const targets = snapEngine.collectTargets(state, draggingIds);
|
|
1132
|
+
if (gridEnabled) {
|
|
1133
|
+
const thresholdDoc = SNAP_THRESHOLD_SCREEN_PX / zoom;
|
|
1134
|
+
const gt = collectGridTargets(snapBounds, gridSize, activePage, thresholdDoc);
|
|
1135
|
+
targets.vertical.push(...gt.vertical);
|
|
1136
|
+
targets.horizontal.push(...gt.horizontal);
|
|
1137
|
+
}
|
|
1138
|
+
const snapResult = snapEngine.apply(snapBounds, targets, SNAP_THRESHOLD_SCREEN_PX, zoom);
|
|
1139
|
+
snappedX = snapResult.x;
|
|
1140
|
+
snappedY = snapResult.y;
|
|
1141
|
+
}
|
|
1142
|
+
const dx = snappedX - origin.x;
|
|
1143
|
+
const dy = snappedY - origin.y;
|
|
1309
1144
|
if (draggingIds.length === 1) {
|
|
1310
1145
|
const el = findElement(activePage, elementId)?.element;
|
|
1311
1146
|
if (!el) return;
|
|
@@ -1313,7 +1148,7 @@ function WorkspaceView({
|
|
|
1313
1148
|
setAttrsCommand({
|
|
1314
1149
|
pageId: activePageId,
|
|
1315
1150
|
elementId,
|
|
1316
|
-
attrs: { x:
|
|
1151
|
+
attrs: { x: snappedX, y: snappedY },
|
|
1317
1152
|
priorAttrs: { x: el.x, y: el.y }
|
|
1318
1153
|
})
|
|
1319
1154
|
);
|
|
@@ -1390,6 +1225,7 @@ function WorkspaceView({
|
|
|
1390
1225
|
if (editingElementId) return;
|
|
1391
1226
|
if ((e.key === "Delete" || e.key === "Backspace") && selectedElementIds.length > 0) {
|
|
1392
1227
|
e.preventDefault();
|
|
1228
|
+
e.stopPropagation();
|
|
1393
1229
|
for (const id of [...selectedElementIds]) {
|
|
1394
1230
|
try {
|
|
1395
1231
|
persist(deleteElementCommand({ document, pageId: activePageId, elementId: id }));
|
|
@@ -1401,11 +1237,13 @@ function WorkspaceView({
|
|
|
1401
1237
|
}
|
|
1402
1238
|
if (mod && e.key === "z" && !e.shiftKey) {
|
|
1403
1239
|
e.preventDefault();
|
|
1240
|
+
e.stopPropagation();
|
|
1404
1241
|
if (stack.canUndo()) stack.undo();
|
|
1405
1242
|
return;
|
|
1406
1243
|
}
|
|
1407
1244
|
if (mod && (e.key === "z" && e.shiftKey || e.key === "y")) {
|
|
1408
1245
|
e.preventDefault();
|
|
1246
|
+
e.stopPropagation();
|
|
1409
1247
|
if (stack.canRedo()) stack.redo();
|
|
1410
1248
|
return;
|
|
1411
1249
|
}
|
|
@@ -1423,8 +1261,8 @@ function WorkspaceView({
|
|
|
1423
1261
|
const clone = {
|
|
1424
1262
|
...structuredClone(found.element),
|
|
1425
1263
|
id: crypto.randomUUID(),
|
|
1426
|
-
x: found.element.x +
|
|
1427
|
-
y: found.element.y +
|
|
1264
|
+
x: found.element.x + DUPLICATE_OFFSET,
|
|
1265
|
+
y: found.element.y + DUPLICATE_OFFSET
|
|
1428
1266
|
};
|
|
1429
1267
|
persist(addElementCommand({ pageId: activePageId, element: clone }));
|
|
1430
1268
|
}
|
|
@@ -1460,7 +1298,7 @@ function WorkspaceView({
|
|
|
1460
1298
|
}
|
|
1461
1299
|
nudgeHeldRef.current = { key, ids: selectedElementIds.slice(), origin: origins };
|
|
1462
1300
|
}
|
|
1463
|
-
const { dx, dy } =
|
|
1301
|
+
const { dx, dy } = nudgeDelta(key, e.shiftKey);
|
|
1464
1302
|
const entries = [];
|
|
1465
1303
|
for (const [id, orig] of nudgeHeldRef.current.origin) {
|
|
1466
1304
|
const found = findElement(activePage, id);
|
|
@@ -1536,7 +1374,40 @@ function WorkspaceView({
|
|
|
1536
1374
|
const activeVerticalGuide = activeSnap?.activeVertical ?? null;
|
|
1537
1375
|
const activeHorizontalGuide = activeSnap?.activeHorizontal ?? null;
|
|
1538
1376
|
const normalizedMarquee = marquee.active ? normalizeMarquee(marquee.startDocX, marquee.startDocY, marquee.endDocX, marquee.endDocY) : null;
|
|
1539
|
-
|
|
1377
|
+
const handlerImplRef = useRef4({
|
|
1378
|
+
onClick: handleElementClick,
|
|
1379
|
+
onDragStart: handleElementDragStart,
|
|
1380
|
+
onDragMove: handleElementDragMove,
|
|
1381
|
+
onDragEnd: handleElementDragEnd,
|
|
1382
|
+
onDoubleClick: handleElementDoubleClick
|
|
1383
|
+
});
|
|
1384
|
+
handlerImplRef.current = {
|
|
1385
|
+
onClick: handleElementClick,
|
|
1386
|
+
onDragStart: handleElementDragStart,
|
|
1387
|
+
onDragMove: handleElementDragMove,
|
|
1388
|
+
onDragEnd: handleElementDragEnd,
|
|
1389
|
+
onDoubleClick: handleElementDoubleClick
|
|
1390
|
+
};
|
|
1391
|
+
const onElementClick = useCallback((id) => handlerImplRef.current.onClick(id), []);
|
|
1392
|
+
const onElementDragStart = useCallback((id) => handlerImplRef.current.onDragStart(id), []);
|
|
1393
|
+
const onElementDragMove = useCallback(
|
|
1394
|
+
(id, dx, dy) => handlerImplRef.current.onDragMove(id, dx, dy),
|
|
1395
|
+
[]
|
|
1396
|
+
);
|
|
1397
|
+
const onElementDragEnd = useCallback(
|
|
1398
|
+
(id, x, y) => handlerImplRef.current.onDragEnd(id, x, y),
|
|
1399
|
+
[]
|
|
1400
|
+
);
|
|
1401
|
+
const onElementDoubleClick = useCallback((id) => handlerImplRef.current.onDoubleClick(id), []);
|
|
1402
|
+
const visibleElements = useMemo(() => {
|
|
1403
|
+
const pageRect = { x: 0, y: 0, width: activePage.width, height: activePage.height };
|
|
1404
|
+
const pinned = new Set(selectedElementIds);
|
|
1405
|
+
if (editingElementId) pinned.add(editingElementId);
|
|
1406
|
+
return activePage.elements.filter(
|
|
1407
|
+
(el) => pinned.has(el.id) || boundsIntersect(elementAabb(el), pageRect)
|
|
1408
|
+
);
|
|
1409
|
+
}, [activePage.elements, activePage.width, activePage.height, selectedElementIds, editingElementId]);
|
|
1410
|
+
return /* @__PURE__ */ jsxs2(
|
|
1540
1411
|
"div",
|
|
1541
1412
|
{
|
|
1542
1413
|
className: `design-canvas-workspace relative overflow-hidden bg-[var(--canvas-backdrop,#1a1a1a)] outline-none ${className ?? ""}`,
|
|
@@ -1550,7 +1421,7 @@ function WorkspaceView({
|
|
|
1550
1421
|
onKeyUp: handleKeyUp,
|
|
1551
1422
|
style: { cursor: spaceHeldRef.current ? "grab" : "default" },
|
|
1552
1423
|
children: [
|
|
1553
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsxs2(
|
|
1554
1425
|
Stage,
|
|
1555
1426
|
{
|
|
1556
1427
|
ref: stageRef,
|
|
@@ -1565,10 +1436,13 @@ function WorkspaceView({
|
|
|
1565
1436
|
pageWidth: activePage.width,
|
|
1566
1437
|
pageHeight: activePage.height,
|
|
1567
1438
|
gridSize,
|
|
1568
|
-
zoom
|
|
1439
|
+
zoom,
|
|
1440
|
+
panX,
|
|
1441
|
+
panY,
|
|
1442
|
+
color: render.grid
|
|
1569
1443
|
}
|
|
1570
1444
|
),
|
|
1571
|
-
/* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */
|
|
1445
|
+
/* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */ jsxs2(Group3, { x: panX, y: panY, scaleX: zoom, scaleY: zoom, children: [
|
|
1572
1446
|
/* @__PURE__ */ jsx6(
|
|
1573
1447
|
Rect2,
|
|
1574
1448
|
{
|
|
@@ -1585,37 +1459,39 @@ function WorkspaceView({
|
|
|
1585
1459
|
}
|
|
1586
1460
|
),
|
|
1587
1461
|
/* @__PURE__ */ jsx6(
|
|
1588
|
-
|
|
1462
|
+
Group3,
|
|
1589
1463
|
{
|
|
1590
1464
|
clipX: 0,
|
|
1591
1465
|
clipY: 0,
|
|
1592
1466
|
clipWidth: activePage.width,
|
|
1593
1467
|
clipHeight: activePage.height,
|
|
1594
|
-
children:
|
|
1468
|
+
children: visibleElements.map((element) => /* @__PURE__ */ jsx6(
|
|
1595
1469
|
ElementNode,
|
|
1596
1470
|
{
|
|
1597
1471
|
element,
|
|
1598
1472
|
isSelected: selectedElementIds.includes(element.id),
|
|
1599
1473
|
zoom,
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1474
|
+
render,
|
|
1475
|
+
onClick: onElementClick,
|
|
1476
|
+
onDragStart: onElementDragStart,
|
|
1477
|
+
onDragMove: onElementDragMove,
|
|
1478
|
+
onDragEnd: onElementDragEnd,
|
|
1479
|
+
onDoubleClick: onElementDoubleClick
|
|
1605
1480
|
},
|
|
1606
1481
|
element.id
|
|
1607
1482
|
))
|
|
1608
1483
|
}
|
|
1609
1484
|
)
|
|
1610
1485
|
] }) }),
|
|
1611
|
-
(activeVerticalGuide || activeHorizontalGuide) && /* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */ jsx6(
|
|
1486
|
+
(activeVerticalGuide || activeHorizontalGuide) && /* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */ jsx6(Group3, { x: panX, y: panY, scaleX: zoom, scaleY: zoom, children: /* @__PURE__ */ jsx6(
|
|
1612
1487
|
SnapGuidesOverlay,
|
|
1613
1488
|
{
|
|
1614
1489
|
pageWidth: activePage.width,
|
|
1615
1490
|
pageHeight: activePage.height,
|
|
1616
1491
|
activeVertical: activeVerticalGuide,
|
|
1617
1492
|
activeHorizontal: activeHorizontalGuide,
|
|
1618
|
-
zoom
|
|
1493
|
+
zoom,
|
|
1494
|
+
render
|
|
1619
1495
|
}
|
|
1620
1496
|
) }) }),
|
|
1621
1497
|
/* @__PURE__ */ jsx6(
|
|
@@ -1626,7 +1502,8 @@ function WorkspaceView({
|
|
|
1626
1502
|
selectedElements,
|
|
1627
1503
|
canWrite,
|
|
1628
1504
|
onTransformEnd: handleTransformEnd,
|
|
1629
|
-
pageId: activePageId
|
|
1505
|
+
pageId: activePageId,
|
|
1506
|
+
render
|
|
1630
1507
|
}
|
|
1631
1508
|
)
|
|
1632
1509
|
]
|
|
@@ -1709,7 +1586,8 @@ function Workspace(props) {
|
|
|
1709
1586
|
canWrite: props.canWrite,
|
|
1710
1587
|
onApplyOperations: props.onApplyOperations,
|
|
1711
1588
|
onSelectionChange: props.onSelectionChange,
|
|
1712
|
-
className: props.className
|
|
1589
|
+
className: props.className,
|
|
1590
|
+
render: props.render
|
|
1713
1591
|
}
|
|
1714
1592
|
);
|
|
1715
1593
|
}
|
|
@@ -1870,7 +1748,8 @@ function DesignCanvasEditor(props) {
|
|
|
1870
1748
|
onExport: props.onExport,
|
|
1871
1749
|
onExportRef: ctx.onExportRef,
|
|
1872
1750
|
fitOnMount: ctx.fitOnMount,
|
|
1873
|
-
onReady: ctx.onReady
|
|
1751
|
+
onReady: ctx.onReady,
|
|
1752
|
+
render: ctx.render
|
|
1874
1753
|
}
|
|
1875
1754
|
);
|
|
1876
1755
|
},
|
|
@@ -1880,18 +1759,6 @@ function DesignCanvasEditor(props) {
|
|
|
1880
1759
|
}
|
|
1881
1760
|
|
|
1882
1761
|
export {
|
|
1883
|
-
createSnapEngine,
|
|
1884
|
-
collectGridTargets,
|
|
1885
|
-
hitTestPoint,
|
|
1886
|
-
marqueeSelect,
|
|
1887
|
-
nudgeDelta,
|
|
1888
|
-
DUPLICATE_OFFSET,
|
|
1889
|
-
createZoomPanMath,
|
|
1890
|
-
isExportHiddenNodeName,
|
|
1891
|
-
resolveExportParams,
|
|
1892
|
-
identifyTaintedSrc,
|
|
1893
|
-
isCrossOriginSrc,
|
|
1894
|
-
documentCropToStageCoords,
|
|
1895
1762
|
exportPageDataUrl,
|
|
1896
1763
|
exportDocumentJson,
|
|
1897
1764
|
downloadDataUrl,
|
|
@@ -1905,4 +1772,4 @@ export {
|
|
|
1905
1772
|
Workspace,
|
|
1906
1773
|
DesignCanvasEditor
|
|
1907
1774
|
};
|
|
1908
|
-
//# sourceMappingURL=chunk-
|
|
1775
|
+
//# sourceMappingURL=chunk-7I37CO5D.js.map
|