@tangle-network/agent-app 0.26.0 → 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/brand-extraction/index.d.ts +212 -0
- package/dist/brand-extraction/index.js +446 -0
- package/dist/brand-extraction/index.js.map +1 -0
- 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-FSUR2752.js → chunk-7I37CO5D.js} +274 -388
- 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-LPAVBGVY.js → chunk-YEWTVDDT.js} +399 -860
- 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 +80 -618
- package/dist/design-canvas-react/index.js +85 -172
- 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 +33 -3
- package/dist/DesignCanvas-MA5EH324.js +0 -10
- package/dist/DesignCanvasEditor-YLCO7I5I.js +0 -9
- 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-FSUR2752.js.map +0 -1
- package/dist/chunk-JZAJE3JL.js.map +0 -1
- package/dist/chunk-LPAVBGVY.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-MA5EH324.js.map → DesignCanvas-AOIVN3SJ.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-YLCO7I5I.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,227 +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 marqueeSelect(page, rect, opts = {}) {
|
|
322
|
-
assertValidBounds(rect, "marqueeSelect rect");
|
|
323
|
-
const result = [];
|
|
324
|
-
collectMarqueeIds(page.elements, rect, opts.requireFullContainment ?? false, result);
|
|
325
|
-
return result;
|
|
326
|
-
}
|
|
327
|
-
function collectMarqueeIds(elements, rect, requireContainment, result) {
|
|
328
|
-
for (const el of elements) {
|
|
329
|
-
if (!el.visible || el.locked) continue;
|
|
330
|
-
const aabb = elementAabb(el);
|
|
331
|
-
if (el.kind === "group") {
|
|
332
|
-
if (boundsIntersect(rect, aabb)) {
|
|
333
|
-
collectMarqueeIds(el.children, rect, requireContainment, result);
|
|
334
|
-
}
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
const hit = requireContainment ? boundsContain(rect, aabb) : boundsIntersect(rect, aabb);
|
|
338
|
-
if (hit) result.push(el.id);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
function boundsContain(outer, inner) {
|
|
342
|
-
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;
|
|
343
|
-
}
|
|
344
|
-
var NUDGE_NORMAL_PX = 1;
|
|
345
|
-
var NUDGE_SHIFT_PX = 10;
|
|
346
|
-
function nudgeDelta(key, shift) {
|
|
347
|
-
const step = shift ? NUDGE_SHIFT_PX : NUDGE_NORMAL_PX;
|
|
348
|
-
switch (key) {
|
|
349
|
-
case "ArrowLeft":
|
|
350
|
-
return { dx: -step, dy: 0 };
|
|
351
|
-
case "ArrowRight":
|
|
352
|
-
return { dx: step, dy: 0 };
|
|
353
|
-
case "ArrowUp":
|
|
354
|
-
return { dx: 0, dy: -step };
|
|
355
|
-
case "ArrowDown":
|
|
356
|
-
return { dx: 0, dy: step };
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
var DUPLICATE_OFFSET = { dx: 10, dy: 10 };
|
|
360
|
-
function assertValidBounds(bounds, label) {
|
|
361
|
-
if (!Number.isFinite(bounds.x) || !Number.isFinite(bounds.y) || !Number.isFinite(bounds.width) || !Number.isFinite(bounds.height)) {
|
|
362
|
-
throw new Error(`${label}: all fields must be finite numbers`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
126
|
// src/design-canvas-react/components/ElementNode.tsx
|
|
367
|
-
import { useEffect, useRef, useState } from "react";
|
|
127
|
+
import { memo, useEffect, useRef, useState } from "react";
|
|
368
128
|
import { Group, Rect, Ellipse, Line, Text, Image as KonvaImage } from "react-konva";
|
|
369
129
|
|
|
370
130
|
// src/design-canvas-react/components/transform-math.ts
|
|
@@ -451,7 +211,7 @@ function snapRotation(angleDeg, thresholdDeg = 5) {
|
|
|
451
211
|
}
|
|
452
212
|
return bestDist <= thresholdDeg ? best : normalized;
|
|
453
213
|
}
|
|
454
|
-
function
|
|
214
|
+
function nudgeDelta(key, shift) {
|
|
455
215
|
const step = shift ? 10 : 1;
|
|
456
216
|
switch (key) {
|
|
457
217
|
case "ArrowLeft":
|
|
@@ -497,7 +257,7 @@ function useImage(src) {
|
|
|
497
257
|
}, [src]);
|
|
498
258
|
return imageCache.get(src) ?? null;
|
|
499
259
|
}
|
|
500
|
-
function
|
|
260
|
+
function ElementNodeImpl(props) {
|
|
501
261
|
const { element } = props;
|
|
502
262
|
if (!element.visible) return null;
|
|
503
263
|
switch (element.kind) {
|
|
@@ -517,33 +277,55 @@ function ElementNode(props) {
|
|
|
517
277
|
return /* @__PURE__ */ jsx(GroupNode, { ...props, element });
|
|
518
278
|
}
|
|
519
279
|
}
|
|
280
|
+
var ElementNode = memo(ElementNodeImpl);
|
|
520
281
|
function useDragBindings(props, originX, originY) {
|
|
521
282
|
const { element, onClick, onDragStart, onDragMove, onDragEnd, onDoubleClick } = props;
|
|
522
283
|
const isDraggable = !element.locked && !!onDragEnd;
|
|
523
284
|
const originRef = useRef({ x: originX, y: originY });
|
|
524
285
|
originRef.current = { x: originX, y: originY };
|
|
286
|
+
const [dragging, setDragging] = useState(false);
|
|
525
287
|
return {
|
|
526
288
|
draggable: isDraggable,
|
|
527
289
|
// locked elements still receive click for selection; listening must be true.
|
|
528
290
|
listening: true,
|
|
291
|
+
dragging,
|
|
529
292
|
onDragStart: isDraggable ? () => {
|
|
293
|
+
setDragging(true);
|
|
530
294
|
onDragStart?.(element.id);
|
|
531
295
|
} : void 0,
|
|
532
296
|
onDragMove: isDraggable ? (e) => {
|
|
533
297
|
onDragMove?.(element.id, e.target.x() - originRef.current.x, e.target.y() - originRef.current.y);
|
|
534
298
|
} : void 0,
|
|
535
299
|
onDragEnd: isDraggable ? (e) => {
|
|
300
|
+
setDragging(false);
|
|
536
301
|
onDragEnd?.(element.id, e.target.x(), e.target.y());
|
|
537
302
|
} : void 0,
|
|
538
303
|
onClick: () => onClick?.(element.id),
|
|
539
304
|
onDblClick: () => onDoubleClick?.(element.id)
|
|
540
305
|
};
|
|
541
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
|
+
}
|
|
542
321
|
function RectNode({ element, ...rest }) {
|
|
543
|
-
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);
|
|
544
325
|
return /* @__PURE__ */ jsx(
|
|
545
326
|
Rect,
|
|
546
327
|
{
|
|
328
|
+
ref,
|
|
547
329
|
name: element.id,
|
|
548
330
|
x: element.x,
|
|
549
331
|
y: element.y,
|
|
@@ -561,10 +343,13 @@ function RectNode({ element, ...rest }) {
|
|
|
561
343
|
}
|
|
562
344
|
function EllipseNode({ element, ...rest }) {
|
|
563
345
|
const { x: cx, y: cy, radiusX, radiusY } = ellipseCenterFromTopLeft(element);
|
|
564
|
-
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);
|
|
565
349
|
return /* @__PURE__ */ jsx(
|
|
566
350
|
Ellipse,
|
|
567
351
|
{
|
|
352
|
+
ref,
|
|
568
353
|
name: element.id,
|
|
569
354
|
x: cx,
|
|
570
355
|
y: cy,
|
|
@@ -580,10 +365,13 @@ function EllipseNode({ element, ...rest }) {
|
|
|
580
365
|
);
|
|
581
366
|
}
|
|
582
367
|
function LineNode({ element, ...rest }) {
|
|
583
|
-
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);
|
|
584
371
|
return /* @__PURE__ */ jsx(
|
|
585
372
|
Line,
|
|
586
373
|
{
|
|
374
|
+
ref,
|
|
587
375
|
name: element.id,
|
|
588
376
|
x: element.x,
|
|
589
377
|
y: element.y,
|
|
@@ -604,11 +392,14 @@ var FONT_STYLE_MAP = {
|
|
|
604
392
|
"bold italic": { fontStyle: "italic", fontVariant: "normal", fontWeight: "bold" }
|
|
605
393
|
};
|
|
606
394
|
function TextNode({ element, ...rest }) {
|
|
607
|
-
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);
|
|
608
398
|
const { fontStyle, fontWeight } = FONT_STYLE_MAP[element.fontStyle];
|
|
609
399
|
return /* @__PURE__ */ jsx(
|
|
610
400
|
Text,
|
|
611
401
|
{
|
|
402
|
+
ref,
|
|
612
403
|
name: element.id,
|
|
613
404
|
x: element.x,
|
|
614
405
|
y: element.y,
|
|
@@ -627,15 +418,24 @@ function TextNode({ element, ...rest }) {
|
|
|
627
418
|
}
|
|
628
419
|
);
|
|
629
420
|
}
|
|
630
|
-
var BROKEN_FILL = "#e5e7eb";
|
|
631
|
-
var BROKEN_STROKE = "#9ca3af";
|
|
632
421
|
function ImageNode({ element, ...rest }) {
|
|
422
|
+
const render = rest.render ?? lightTheme.canvasRender;
|
|
633
423
|
const img = useImage(element.src);
|
|
634
|
-
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
|
+
);
|
|
635
434
|
if (!img || !img.complete || img.naturalWidth === 0) {
|
|
636
435
|
return /* @__PURE__ */ jsx(
|
|
637
436
|
Rect,
|
|
638
437
|
{
|
|
438
|
+
ref,
|
|
639
439
|
name: element.id,
|
|
640
440
|
x: element.x,
|
|
641
441
|
y: element.y,
|
|
@@ -643,8 +443,8 @@ function ImageNode({ element, ...rest }) {
|
|
|
643
443
|
height: element.height,
|
|
644
444
|
rotation: element.rotation,
|
|
645
445
|
opacity: element.opacity,
|
|
646
|
-
fill:
|
|
647
|
-
stroke:
|
|
446
|
+
fill: render.brokenFill,
|
|
447
|
+
stroke: render.brokenStroke,
|
|
648
448
|
strokeWidth: 1,
|
|
649
449
|
...drag
|
|
650
450
|
}
|
|
@@ -679,6 +479,7 @@ function ImageNode({ element, ...rest }) {
|
|
|
679
479
|
return /* @__PURE__ */ jsx(
|
|
680
480
|
KonvaImage,
|
|
681
481
|
{
|
|
482
|
+
ref,
|
|
682
483
|
name: element.id,
|
|
683
484
|
x: element.x,
|
|
684
485
|
y: element.y,
|
|
@@ -693,12 +494,23 @@ function ImageNode({ element, ...rest }) {
|
|
|
693
494
|
);
|
|
694
495
|
}
|
|
695
496
|
function VideoNode({ element, ...rest }) {
|
|
497
|
+
const render = rest.render ?? lightTheme.canvasRender;
|
|
696
498
|
const img = useImage(element.posterSrc ?? "");
|
|
697
|
-
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
|
+
);
|
|
698
509
|
if (!element.posterSrc || !img || !img.complete || img.naturalWidth === 0) {
|
|
699
510
|
return /* @__PURE__ */ jsx(
|
|
700
511
|
Rect,
|
|
701
512
|
{
|
|
513
|
+
ref,
|
|
702
514
|
name: element.id,
|
|
703
515
|
x: element.x,
|
|
704
516
|
y: element.y,
|
|
@@ -706,8 +518,8 @@ function VideoNode({ element, ...rest }) {
|
|
|
706
518
|
height: element.height,
|
|
707
519
|
rotation: element.rotation,
|
|
708
520
|
opacity: element.opacity,
|
|
709
|
-
fill:
|
|
710
|
-
stroke:
|
|
521
|
+
fill: render.placeholderFill,
|
|
522
|
+
stroke: render.placeholderStroke,
|
|
711
523
|
strokeWidth: 1,
|
|
712
524
|
...drag
|
|
713
525
|
}
|
|
@@ -716,6 +528,7 @@ function VideoNode({ element, ...rest }) {
|
|
|
716
528
|
return /* @__PURE__ */ jsx(
|
|
717
529
|
KonvaImage,
|
|
718
530
|
{
|
|
531
|
+
ref,
|
|
719
532
|
name: element.id,
|
|
720
533
|
x: element.x,
|
|
721
534
|
y: element.y,
|
|
@@ -729,7 +542,8 @@ function VideoNode({ element, ...rest }) {
|
|
|
729
542
|
);
|
|
730
543
|
}
|
|
731
544
|
function GroupNode({ element, ...rest }) {
|
|
732
|
-
const drag = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
545
|
+
const { dragging: _dragging, ...drag } = useDragBindings({ element, ...rest }, element.x, element.y);
|
|
546
|
+
void _dragging;
|
|
733
547
|
return /* @__PURE__ */ jsx(
|
|
734
548
|
Group,
|
|
735
549
|
{
|
|
@@ -755,7 +569,8 @@ function SelectionLayer({
|
|
|
755
569
|
selectedElements,
|
|
756
570
|
canWrite,
|
|
757
571
|
onTransformEnd,
|
|
758
|
-
pageId
|
|
572
|
+
pageId,
|
|
573
|
+
render = lightTheme.canvasRender
|
|
759
574
|
}) {
|
|
760
575
|
const trRef = useRef2(null);
|
|
761
576
|
useEffect2(() => {
|
|
@@ -788,22 +603,35 @@ function SelectionLayer({
|
|
|
788
603
|
if (entries.length > 0) onTransformEnd(entries);
|
|
789
604
|
}
|
|
790
605
|
const multiSelect = selectedIds.length > 1;
|
|
791
|
-
return
|
|
792
|
-
Transformer
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
+
);
|
|
807
635
|
}
|
|
808
636
|
function elementToPriorAttrs(element) {
|
|
809
637
|
const base = {
|
|
@@ -896,78 +724,89 @@ function bakeNodeToAttrs(node, element) {
|
|
|
896
724
|
}
|
|
897
725
|
|
|
898
726
|
// src/design-canvas-react/components/GridLayer.tsx
|
|
899
|
-
import { Layer as Layer2,
|
|
900
|
-
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
|
+
}
|
|
901
741
|
function GridLayer({
|
|
902
742
|
pageWidth,
|
|
903
743
|
pageHeight,
|
|
904
744
|
gridSize,
|
|
905
745
|
zoom,
|
|
746
|
+
panX,
|
|
747
|
+
panY,
|
|
906
748
|
color = "#c0c0c0",
|
|
907
749
|
opacity = 0.5
|
|
908
750
|
}) {
|
|
909
751
|
if (!gridVisible(gridSize, zoom, 4)) return null;
|
|
910
|
-
const verticals =
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
opacity,
|
|
940
|
-
listening: false,
|
|
941
|
-
perfectDrawEnabled: false
|
|
942
|
-
},
|
|
943
|
-
`h-${y}`
|
|
944
|
-
))
|
|
945
|
-
] });
|
|
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
|
+
) }) });
|
|
946
781
|
}
|
|
947
782
|
|
|
948
783
|
// src/design-canvas-react/components/SnapGuidesOverlay.tsx
|
|
949
|
-
import { Layer as Layer3, Line as
|
|
950
|
-
import { jsx as jsx4, jsxs
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
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
|
+
}
|
|
959
796
|
function SnapGuidesOverlay({
|
|
960
797
|
pageWidth,
|
|
961
798
|
pageHeight,
|
|
962
799
|
activeVertical,
|
|
963
800
|
activeHorizontal,
|
|
964
|
-
zoom
|
|
801
|
+
zoom,
|
|
802
|
+
render = lightTheme.canvasRender
|
|
965
803
|
}) {
|
|
966
804
|
if (!activeVertical && !activeHorizontal) return null;
|
|
805
|
+
const KIND_COLOR = kindColors(render);
|
|
967
806
|
const strokeWidth = 1 / zoom;
|
|
968
|
-
return /* @__PURE__ */
|
|
807
|
+
return /* @__PURE__ */ jsxs(Layer3, { name: "overlay:snap", listening: false, children: [
|
|
969
808
|
activeVertical && /* @__PURE__ */ jsx4(
|
|
970
|
-
|
|
809
|
+
Line2,
|
|
971
810
|
{
|
|
972
811
|
name: "overlay:snap-vertical",
|
|
973
812
|
points: [activeVertical.position, -99999, activeVertical.position, 99999],
|
|
@@ -979,7 +818,7 @@ function SnapGuidesOverlay({
|
|
|
979
818
|
}
|
|
980
819
|
),
|
|
981
820
|
activeHorizontal && /* @__PURE__ */ jsx4(
|
|
982
|
-
|
|
821
|
+
Line2,
|
|
983
822
|
{
|
|
984
823
|
name: "overlay:snap-horizontal",
|
|
985
824
|
points: [-99999, activeHorizontal.position, 99999, activeHorizontal.position],
|
|
@@ -1080,9 +919,9 @@ function InlineTextEditor({
|
|
|
1080
919
|
}
|
|
1081
920
|
|
|
1082
921
|
// src/design-canvas-react/components/Workspace.tsx
|
|
1083
|
-
import { jsx as jsx6, jsxs as
|
|
922
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1084
923
|
var SNAP_THRESHOLD_SCREEN_PX = 8;
|
|
1085
|
-
var
|
|
924
|
+
var DUPLICATE_OFFSET = 10;
|
|
1086
925
|
var ZOOM_FACTOR_WHEEL = 0.998;
|
|
1087
926
|
var ZOOM_MIN = 0.05;
|
|
1088
927
|
var ZOOM_MAX = 32;
|
|
@@ -1098,7 +937,8 @@ function WorkspaceView({
|
|
|
1098
937
|
onExport,
|
|
1099
938
|
onExportRef,
|
|
1100
939
|
fitOnMount = true,
|
|
1101
|
-
onReady
|
|
940
|
+
onReady,
|
|
941
|
+
render = lightTheme.canvasRender
|
|
1102
942
|
}) {
|
|
1103
943
|
const [, setTick] = useState2(0);
|
|
1104
944
|
const forceRender = useCallback(() => setTick((t) => t + 1), []);
|
|
@@ -1195,19 +1035,17 @@ function WorkspaceView({
|
|
|
1195
1035
|
return;
|
|
1196
1036
|
}
|
|
1197
1037
|
if (e.button !== 0) return;
|
|
1198
|
-
const stage = stageRef.current;
|
|
1199
1038
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
1200
|
-
if (!
|
|
1039
|
+
if (!rect) return;
|
|
1201
1040
|
const screenX = e.clientX - rect.left;
|
|
1202
1041
|
const screenY = e.clientY - rect.top;
|
|
1203
|
-
const
|
|
1204
|
-
if (
|
|
1042
|
+
const docPos = zoomPanMath.screenToDocument({ zoom, panX, panY }, screenX, screenY);
|
|
1043
|
+
if (hitTestPoint(activePage, docPos.x, docPos.y) !== null) {
|
|
1205
1044
|
return;
|
|
1206
1045
|
}
|
|
1207
1046
|
e.preventDefault();
|
|
1208
1047
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1209
1048
|
gestureRef.current = "marquee";
|
|
1210
|
-
const docPos = zoomPanMath.screenToDocument({ zoom, panX, panY }, screenX, screenY);
|
|
1211
1049
|
const m = { active: true, startDocX: docPos.x, startDocY: docPos.y, endDocX: docPos.x, endDocY: docPos.y };
|
|
1212
1050
|
marqueeRef.current = m;
|
|
1213
1051
|
setMarquee(m);
|
|
@@ -1285,9 +1123,24 @@ function WorkspaceView({
|
|
|
1285
1123
|
setActiveSnap(null);
|
|
1286
1124
|
const origin = dragOriginRef.current.get(elementId);
|
|
1287
1125
|
if (!origin) return;
|
|
1288
|
-
const dx = finalX - origin.x;
|
|
1289
|
-
const dy = finalY - origin.y;
|
|
1290
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;
|
|
1291
1144
|
if (draggingIds.length === 1) {
|
|
1292
1145
|
const el = findElement(activePage, elementId)?.element;
|
|
1293
1146
|
if (!el) return;
|
|
@@ -1295,7 +1148,7 @@ function WorkspaceView({
|
|
|
1295
1148
|
setAttrsCommand({
|
|
1296
1149
|
pageId: activePageId,
|
|
1297
1150
|
elementId,
|
|
1298
|
-
attrs: { x:
|
|
1151
|
+
attrs: { x: snappedX, y: snappedY },
|
|
1299
1152
|
priorAttrs: { x: el.x, y: el.y }
|
|
1300
1153
|
})
|
|
1301
1154
|
);
|
|
@@ -1372,6 +1225,7 @@ function WorkspaceView({
|
|
|
1372
1225
|
if (editingElementId) return;
|
|
1373
1226
|
if ((e.key === "Delete" || e.key === "Backspace") && selectedElementIds.length > 0) {
|
|
1374
1227
|
e.preventDefault();
|
|
1228
|
+
e.stopPropagation();
|
|
1375
1229
|
for (const id of [...selectedElementIds]) {
|
|
1376
1230
|
try {
|
|
1377
1231
|
persist(deleteElementCommand({ document, pageId: activePageId, elementId: id }));
|
|
@@ -1383,11 +1237,13 @@ function WorkspaceView({
|
|
|
1383
1237
|
}
|
|
1384
1238
|
if (mod && e.key === "z" && !e.shiftKey) {
|
|
1385
1239
|
e.preventDefault();
|
|
1240
|
+
e.stopPropagation();
|
|
1386
1241
|
if (stack.canUndo()) stack.undo();
|
|
1387
1242
|
return;
|
|
1388
1243
|
}
|
|
1389
1244
|
if (mod && (e.key === "z" && e.shiftKey || e.key === "y")) {
|
|
1390
1245
|
e.preventDefault();
|
|
1246
|
+
e.stopPropagation();
|
|
1391
1247
|
if (stack.canRedo()) stack.redo();
|
|
1392
1248
|
return;
|
|
1393
1249
|
}
|
|
@@ -1405,8 +1261,8 @@ function WorkspaceView({
|
|
|
1405
1261
|
const clone = {
|
|
1406
1262
|
...structuredClone(found.element),
|
|
1407
1263
|
id: crypto.randomUUID(),
|
|
1408
|
-
x: found.element.x +
|
|
1409
|
-
y: found.element.y +
|
|
1264
|
+
x: found.element.x + DUPLICATE_OFFSET,
|
|
1265
|
+
y: found.element.y + DUPLICATE_OFFSET
|
|
1410
1266
|
};
|
|
1411
1267
|
persist(addElementCommand({ pageId: activePageId, element: clone }));
|
|
1412
1268
|
}
|
|
@@ -1442,7 +1298,7 @@ function WorkspaceView({
|
|
|
1442
1298
|
}
|
|
1443
1299
|
nudgeHeldRef.current = { key, ids: selectedElementIds.slice(), origin: origins };
|
|
1444
1300
|
}
|
|
1445
|
-
const { dx, dy } =
|
|
1301
|
+
const { dx, dy } = nudgeDelta(key, e.shiftKey);
|
|
1446
1302
|
const entries = [];
|
|
1447
1303
|
for (const [id, orig] of nudgeHeldRef.current.origin) {
|
|
1448
1304
|
const found = findElement(activePage, id);
|
|
@@ -1518,7 +1374,40 @@ function WorkspaceView({
|
|
|
1518
1374
|
const activeVerticalGuide = activeSnap?.activeVertical ?? null;
|
|
1519
1375
|
const activeHorizontalGuide = activeSnap?.activeHorizontal ?? null;
|
|
1520
1376
|
const normalizedMarquee = marquee.active ? normalizeMarquee(marquee.startDocX, marquee.startDocY, marquee.endDocX, marquee.endDocY) : null;
|
|
1521
|
-
|
|
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(
|
|
1522
1411
|
"div",
|
|
1523
1412
|
{
|
|
1524
1413
|
className: `design-canvas-workspace relative overflow-hidden bg-[var(--canvas-backdrop,#1a1a1a)] outline-none ${className ?? ""}`,
|
|
@@ -1532,7 +1421,7 @@ function WorkspaceView({
|
|
|
1532
1421
|
onKeyUp: handleKeyUp,
|
|
1533
1422
|
style: { cursor: spaceHeldRef.current ? "grab" : "default" },
|
|
1534
1423
|
children: [
|
|
1535
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsxs2(
|
|
1536
1425
|
Stage,
|
|
1537
1426
|
{
|
|
1538
1427
|
ref: stageRef,
|
|
@@ -1547,10 +1436,13 @@ function WorkspaceView({
|
|
|
1547
1436
|
pageWidth: activePage.width,
|
|
1548
1437
|
pageHeight: activePage.height,
|
|
1549
1438
|
gridSize,
|
|
1550
|
-
zoom
|
|
1439
|
+
zoom,
|
|
1440
|
+
panX,
|
|
1441
|
+
panY,
|
|
1442
|
+
color: render.grid
|
|
1551
1443
|
}
|
|
1552
1444
|
),
|
|
1553
|
-
/* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */
|
|
1445
|
+
/* @__PURE__ */ jsx6(Layer4, { children: /* @__PURE__ */ jsxs2(Group3, { x: panX, y: panY, scaleX: zoom, scaleY: zoom, children: [
|
|
1554
1446
|
/* @__PURE__ */ jsx6(
|
|
1555
1447
|
Rect2,
|
|
1556
1448
|
{
|
|
@@ -1567,37 +1459,39 @@ function WorkspaceView({
|
|
|
1567
1459
|
}
|
|
1568
1460
|
),
|
|
1569
1461
|
/* @__PURE__ */ jsx6(
|
|
1570
|
-
|
|
1462
|
+
Group3,
|
|
1571
1463
|
{
|
|
1572
1464
|
clipX: 0,
|
|
1573
1465
|
clipY: 0,
|
|
1574
1466
|
clipWidth: activePage.width,
|
|
1575
1467
|
clipHeight: activePage.height,
|
|
1576
|
-
children:
|
|
1468
|
+
children: visibleElements.map((element) => /* @__PURE__ */ jsx6(
|
|
1577
1469
|
ElementNode,
|
|
1578
1470
|
{
|
|
1579
1471
|
element,
|
|
1580
1472
|
isSelected: selectedElementIds.includes(element.id),
|
|
1581
1473
|
zoom,
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1474
|
+
render,
|
|
1475
|
+
onClick: onElementClick,
|
|
1476
|
+
onDragStart: onElementDragStart,
|
|
1477
|
+
onDragMove: onElementDragMove,
|
|
1478
|
+
onDragEnd: onElementDragEnd,
|
|
1479
|
+
onDoubleClick: onElementDoubleClick
|
|
1587
1480
|
},
|
|
1588
1481
|
element.id
|
|
1589
1482
|
))
|
|
1590
1483
|
}
|
|
1591
1484
|
)
|
|
1592
1485
|
] }) }),
|
|
1593
|
-
(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(
|
|
1594
1487
|
SnapGuidesOverlay,
|
|
1595
1488
|
{
|
|
1596
1489
|
pageWidth: activePage.width,
|
|
1597
1490
|
pageHeight: activePage.height,
|
|
1598
1491
|
activeVertical: activeVerticalGuide,
|
|
1599
1492
|
activeHorizontal: activeHorizontalGuide,
|
|
1600
|
-
zoom
|
|
1493
|
+
zoom,
|
|
1494
|
+
render
|
|
1601
1495
|
}
|
|
1602
1496
|
) }) }),
|
|
1603
1497
|
/* @__PURE__ */ jsx6(
|
|
@@ -1608,7 +1502,8 @@ function WorkspaceView({
|
|
|
1608
1502
|
selectedElements,
|
|
1609
1503
|
canWrite,
|
|
1610
1504
|
onTransformEnd: handleTransformEnd,
|
|
1611
|
-
pageId: activePageId
|
|
1505
|
+
pageId: activePageId,
|
|
1506
|
+
render
|
|
1612
1507
|
}
|
|
1613
1508
|
)
|
|
1614
1509
|
]
|
|
@@ -1691,7 +1586,8 @@ function Workspace(props) {
|
|
|
1691
1586
|
canWrite: props.canWrite,
|
|
1692
1587
|
onApplyOperations: props.onApplyOperations,
|
|
1693
1588
|
onSelectionChange: props.onSelectionChange,
|
|
1694
|
-
className: props.className
|
|
1589
|
+
className: props.className,
|
|
1590
|
+
render: props.render
|
|
1695
1591
|
}
|
|
1696
1592
|
);
|
|
1697
1593
|
}
|
|
@@ -1852,7 +1748,8 @@ function DesignCanvasEditor(props) {
|
|
|
1852
1748
|
onExport: props.onExport,
|
|
1853
1749
|
onExportRef: ctx.onExportRef,
|
|
1854
1750
|
fitOnMount: ctx.fitOnMount,
|
|
1855
|
-
onReady: ctx.onReady
|
|
1751
|
+
onReady: ctx.onReady,
|
|
1752
|
+
render: ctx.render
|
|
1856
1753
|
}
|
|
1857
1754
|
);
|
|
1858
1755
|
},
|
|
@@ -1862,17 +1759,6 @@ function DesignCanvasEditor(props) {
|
|
|
1862
1759
|
}
|
|
1863
1760
|
|
|
1864
1761
|
export {
|
|
1865
|
-
createSnapEngine,
|
|
1866
|
-
collectGridTargets,
|
|
1867
|
-
marqueeSelect,
|
|
1868
|
-
nudgeDelta,
|
|
1869
|
-
DUPLICATE_OFFSET,
|
|
1870
|
-
createZoomPanMath,
|
|
1871
|
-
isExportHiddenNodeName,
|
|
1872
|
-
resolveExportParams,
|
|
1873
|
-
identifyTaintedSrc,
|
|
1874
|
-
isCrossOriginSrc,
|
|
1875
|
-
documentCropToStageCoords,
|
|
1876
1762
|
exportPageDataUrl,
|
|
1877
1763
|
exportDocumentJson,
|
|
1878
1764
|
downloadDataUrl,
|
|
@@ -1886,4 +1772,4 @@ export {
|
|
|
1886
1772
|
Workspace,
|
|
1887
1773
|
DesignCanvasEditor
|
|
1888
1774
|
};
|
|
1889
|
-
//# sourceMappingURL=chunk-
|
|
1775
|
+
//# sourceMappingURL=chunk-7I37CO5D.js.map
|