@node-edit-utils/core 2.3.0 → 2.3.2
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/lib/node-tools/select/helpers/isInsideViewport.d.ts +1 -0
- package/dist/lib/viewport/constants.d.ts +2 -2
- package/dist/lib/viewport/createViewport.d.ts +1 -1
- package/dist/lib/viewport/label/getViewportLabelsOverlay.d.ts +1 -0
- package/dist/lib/viewport/label/helpers/getLabelPosition.d.ts +4 -0
- package/dist/lib/viewport/label/helpers/getTransformValues.d.ts +4 -0
- package/dist/lib/viewport/label/helpers/getZoomValue.d.ts +1 -0
- package/dist/lib/viewport/label/index.d.ts +4 -0
- package/dist/lib/viewport/label/isViewportLabelDragging.d.ts +2 -0
- package/dist/lib/viewport/label/refreshViewportLabels.d.ts +1 -0
- package/dist/lib/viewport/label/setupViewportLabelDrag.d.ts +1 -0
- package/dist/node-edit-utils.cjs.js +288 -63
- package/dist/node-edit-utils.esm.js +288 -63
- package/dist/node-edit-utils.umd.js +288 -63
- package/dist/node-edit-utils.umd.min.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/lib/canvas/createCanvasObserver.ts +14 -0
- package/src/lib/node-tools/createNodeTools.ts +12 -5
- package/src/lib/node-tools/select/helpers/isInsideViewport.ts +19 -0
- package/src/lib/node-tools/select/selectNode.ts +13 -1
- package/src/lib/node-tools/text/events/setupMutationObserver.ts +1 -0
- package/src/lib/styles/styles.css +48 -1
- package/src/lib/viewport/constants.ts +2 -2
- package/src/lib/viewport/createViewport.ts +26 -7
- package/src/lib/viewport/events/setupEventListener.ts +9 -0
- package/src/lib/viewport/label/getViewportLabelsOverlay.ts +33 -0
- package/src/lib/viewport/label/helpers/getLabelPosition.ts +8 -0
- package/src/lib/viewport/label/helpers/getTransformValues.ts +8 -0
- package/src/lib/viewport/label/helpers/getZoomValue.ts +4 -0
- package/src/lib/viewport/label/index.ts +4 -0
- package/src/lib/viewport/label/isViewportLabelDragging.ts +9 -0
- package/src/lib/viewport/label/refreshViewportLabels.ts +69 -0
- package/src/lib/viewport/label/setupViewportLabelDrag.ts +98 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 2.3.
|
|
4
|
+
* @version 2.3.2
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
@@ -9,6 +9,214 @@
|
|
|
9
9
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MarkupCanvas = {}));
|
|
10
10
|
})(this, (function (exports) { 'use strict';
|
|
11
11
|
|
|
12
|
+
function getScreenBounds(element) {
|
|
13
|
+
const rect = element.getBoundingClientRect();
|
|
14
|
+
return {
|
|
15
|
+
top: rect.top,
|
|
16
|
+
left: rect.left,
|
|
17
|
+
width: rect.width,
|
|
18
|
+
height: rect.height,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const getCanvasContainer = () => {
|
|
23
|
+
return document.querySelector(".canvas-container");
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const getViewportLabelsOverlay = () => {
|
|
27
|
+
const canvasContainer = getCanvasContainer();
|
|
28
|
+
const container = canvasContainer || document.body;
|
|
29
|
+
// Check if overlay already exists
|
|
30
|
+
let overlay = container.querySelector(".viewport-labels-overlay");
|
|
31
|
+
if (!overlay) {
|
|
32
|
+
// Create new SVG overlay
|
|
33
|
+
overlay = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
34
|
+
overlay.classList.add("viewport-labels-overlay");
|
|
35
|
+
// Set fixed positioning
|
|
36
|
+
overlay.style.position = "absolute";
|
|
37
|
+
overlay.style.top = "0";
|
|
38
|
+
overlay.style.left = "0";
|
|
39
|
+
overlay.style.width = "100vw";
|
|
40
|
+
overlay.style.height = "100vh";
|
|
41
|
+
overlay.style.pointerEvents = "none";
|
|
42
|
+
overlay.style.zIndex = "500";
|
|
43
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
44
|
+
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
45
|
+
overlay.setAttribute("width", viewportWidth.toString());
|
|
46
|
+
overlay.setAttribute("height", viewportHeight.toString());
|
|
47
|
+
container.appendChild(overlay);
|
|
48
|
+
}
|
|
49
|
+
return overlay;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Global flag to prevent refreshViewportLabels during drag
|
|
53
|
+
let globalIsDragging = false;
|
|
54
|
+
const isViewportLabelDragging = () => globalIsDragging;
|
|
55
|
+
const setViewportLabelDragging = (isDragging) => {
|
|
56
|
+
globalIsDragging = isDragging;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function sendPostMessage(action, data) {
|
|
60
|
+
window.parent.postMessage({
|
|
61
|
+
source: "node-edit-utils",
|
|
62
|
+
action,
|
|
63
|
+
data,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
}, "*");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const getLabelPosition = (labelGroup) => {
|
|
69
|
+
const transform = labelGroup.getAttribute("transform");
|
|
70
|
+
const match = transform?.match(/translate\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);
|
|
71
|
+
if (match) {
|
|
72
|
+
return { x: parseFloat(match[1]), y: parseFloat(match[2]) };
|
|
73
|
+
}
|
|
74
|
+
return { x: 0, y: 0 };
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getTransformValues = (element) => {
|
|
78
|
+
const style = element.style.transform;
|
|
79
|
+
const match = style.match(/translate3d\((-?\d+(?:\.\d+)?)px,\s*(-?\d+(?:\.\d+)?)px,\s*(-?\d+(?:\.\d+)?)px\)/);
|
|
80
|
+
if (match) {
|
|
81
|
+
return { x: parseFloat(match[1]), y: parseFloat(match[2]) };
|
|
82
|
+
}
|
|
83
|
+
return { x: 0, y: 0 };
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const getZoomValue = () => {
|
|
87
|
+
const zoomValue = getComputedStyle(document.body).getPropertyValue("--zoom").trim();
|
|
88
|
+
return zoomValue ? parseFloat(zoomValue) : 1;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const setupViewportLabelDrag = (labelElement, viewportElement, viewportName) => {
|
|
92
|
+
let isDragging = false;
|
|
93
|
+
let startX = 0;
|
|
94
|
+
let startY = 0;
|
|
95
|
+
let initialTransform = { x: 0, y: 0 };
|
|
96
|
+
let initialLabelPosition = { x: 0, y: 0 };
|
|
97
|
+
// Get the parent group element that contains the label
|
|
98
|
+
const labelGroup = labelElement.parentElement;
|
|
99
|
+
const startDrag = (event) => {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
event.stopPropagation();
|
|
102
|
+
isDragging = true;
|
|
103
|
+
setViewportLabelDragging(true);
|
|
104
|
+
startX = event.clientX;
|
|
105
|
+
startY = event.clientY;
|
|
106
|
+
initialTransform = getTransformValues(viewportElement);
|
|
107
|
+
initialLabelPosition = getLabelPosition(labelGroup);
|
|
108
|
+
};
|
|
109
|
+
const handleDrag = (event) => {
|
|
110
|
+
if (!isDragging)
|
|
111
|
+
return;
|
|
112
|
+
const zoom = getZoomValue();
|
|
113
|
+
// Calculate mouse delta
|
|
114
|
+
const rawDeltaX = event.clientX - startX;
|
|
115
|
+
const rawDeltaY = event.clientY - startY;
|
|
116
|
+
// Adjust delta for zoom level
|
|
117
|
+
const deltaX = rawDeltaX / zoom;
|
|
118
|
+
const deltaY = rawDeltaY / zoom;
|
|
119
|
+
const newX = initialTransform.x + deltaX;
|
|
120
|
+
const newY = initialTransform.y + deltaY;
|
|
121
|
+
// Update label position with raw delta (labels are in screen space)
|
|
122
|
+
const newLabelX = initialLabelPosition.x + rawDeltaX;
|
|
123
|
+
const newLabelY = initialLabelPosition.y + rawDeltaY;
|
|
124
|
+
labelGroup.setAttribute("transform", `translate(${newLabelX}, ${newLabelY})`);
|
|
125
|
+
// Update viewport position with zoom-adjusted delta
|
|
126
|
+
viewportElement.style.transform = `translate3d(${newX}px, ${newY}px, 0)`;
|
|
127
|
+
};
|
|
128
|
+
const stopDrag = (event) => {
|
|
129
|
+
if (!isDragging)
|
|
130
|
+
return;
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
event.stopPropagation();
|
|
133
|
+
isDragging = false;
|
|
134
|
+
setViewportLabelDragging(false);
|
|
135
|
+
const finalTransform = getTransformValues(viewportElement);
|
|
136
|
+
// Trigger refresh after drag completes to update highlight frame and labels
|
|
137
|
+
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
138
|
+
const nodeTools = window.nodeTools;
|
|
139
|
+
if (nodeTools?.refreshHighlightFrame) {
|
|
140
|
+
nodeTools.refreshHighlightFrame();
|
|
141
|
+
}
|
|
142
|
+
// Notify parent about the new position
|
|
143
|
+
sendPostMessage("viewport-position-changed", {
|
|
144
|
+
viewportName,
|
|
145
|
+
x: finalTransform.x,
|
|
146
|
+
y: finalTransform.y,
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
const cancelDrag = () => {
|
|
150
|
+
isDragging = false;
|
|
151
|
+
setViewportLabelDragging(false);
|
|
152
|
+
};
|
|
153
|
+
// Attach event listeners
|
|
154
|
+
labelElement.addEventListener("mousedown", startDrag);
|
|
155
|
+
document.addEventListener("mousemove", handleDrag);
|
|
156
|
+
document.addEventListener("mouseup", stopDrag);
|
|
157
|
+
window.addEventListener("blur", cancelDrag);
|
|
158
|
+
// Return cleanup function
|
|
159
|
+
return () => {
|
|
160
|
+
labelElement.removeEventListener("mousedown", startDrag);
|
|
161
|
+
document.removeEventListener("mousemove", handleDrag);
|
|
162
|
+
document.removeEventListener("mouseup", stopDrag);
|
|
163
|
+
window.removeEventListener("blur", cancelDrag);
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Store cleanup functions for drag listeners
|
|
168
|
+
const dragCleanupFunctions = new Map();
|
|
169
|
+
const refreshViewportLabels = () => {
|
|
170
|
+
// Skip refresh if a viewport label is being dragged
|
|
171
|
+
if (isViewportLabelDragging()) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const overlay = getViewportLabelsOverlay();
|
|
175
|
+
// Update SVG dimensions to match current viewport
|
|
176
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
177
|
+
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
178
|
+
overlay.setAttribute("width", viewportWidth.toString());
|
|
179
|
+
overlay.setAttribute("height", viewportHeight.toString());
|
|
180
|
+
// Find all viewports with names
|
|
181
|
+
const viewports = document.querySelectorAll(".viewport[data-viewport-name]");
|
|
182
|
+
// Clean up existing drag listeners
|
|
183
|
+
dragCleanupFunctions.forEach((cleanup) => {
|
|
184
|
+
cleanup();
|
|
185
|
+
});
|
|
186
|
+
dragCleanupFunctions.clear();
|
|
187
|
+
// Remove existing label groups
|
|
188
|
+
const existingGroups = overlay.querySelectorAll(".viewport-label-group");
|
|
189
|
+
existingGroups.forEach((group) => {
|
|
190
|
+
group.remove();
|
|
191
|
+
});
|
|
192
|
+
// Create/update labels for each viewport
|
|
193
|
+
viewports.forEach((viewport) => {
|
|
194
|
+
const viewportElement = viewport;
|
|
195
|
+
const viewportName = viewportElement.getAttribute("data-viewport-name");
|
|
196
|
+
if (!viewportName)
|
|
197
|
+
return;
|
|
198
|
+
const bounds = getScreenBounds(viewportElement);
|
|
199
|
+
// Create group for this viewport label
|
|
200
|
+
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
201
|
+
group.classList.add("viewport-label-group");
|
|
202
|
+
group.setAttribute("data-viewport-name", viewportName);
|
|
203
|
+
group.setAttribute("transform", `translate(${bounds.left}, ${bounds.top})`);
|
|
204
|
+
// Create text element
|
|
205
|
+
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
206
|
+
text.classList.add("viewport-label-text");
|
|
207
|
+
text.setAttribute("x", "0");
|
|
208
|
+
text.setAttribute("y", "-8");
|
|
209
|
+
text.setAttribute("vector-effect", "non-scaling-stroke");
|
|
210
|
+
text.setAttribute("pointer-events", "auto");
|
|
211
|
+
text.textContent = viewportName;
|
|
212
|
+
group.appendChild(text);
|
|
213
|
+
overlay.appendChild(group);
|
|
214
|
+
// Setup drag functionality for this label
|
|
215
|
+
const cleanup = setupViewportLabelDrag(text, viewportElement, viewportName);
|
|
216
|
+
dragCleanupFunctions.set(viewportName, cleanup);
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
12
220
|
const getCanvasWindowValue = (path, canvasName = "canvas") => {
|
|
13
221
|
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
14
222
|
const canvas = window[canvasName];
|
|
@@ -38,6 +246,8 @@
|
|
|
38
246
|
if (nodeTools?.refreshHighlightFrame) {
|
|
39
247
|
nodeTools.refreshHighlightFrame();
|
|
40
248
|
}
|
|
249
|
+
// Refresh viewport labels
|
|
250
|
+
refreshViewportLabels();
|
|
41
251
|
});
|
|
42
252
|
observer.observe(transformLayer, {
|
|
43
253
|
attributes: true,
|
|
@@ -45,8 +255,16 @@
|
|
|
45
255
|
subtree: true,
|
|
46
256
|
childList: true,
|
|
47
257
|
});
|
|
258
|
+
// Handle window resize for viewport labels
|
|
259
|
+
const handleResize = () => {
|
|
260
|
+
refreshViewportLabels();
|
|
261
|
+
};
|
|
262
|
+
window.addEventListener("resize", handleResize);
|
|
263
|
+
// Initial refresh of viewport labels
|
|
264
|
+
refreshViewportLabels();
|
|
48
265
|
function disconnect() {
|
|
49
266
|
observer.disconnect();
|
|
267
|
+
window.removeEventListener("resize", handleResize);
|
|
50
268
|
}
|
|
51
269
|
return {
|
|
52
270
|
disconnect,
|
|
@@ -61,15 +279,6 @@
|
|
|
61
279
|
return resizeObserver;
|
|
62
280
|
};
|
|
63
281
|
|
|
64
|
-
function sendPostMessage(action, data) {
|
|
65
|
-
window.parent.postMessage({
|
|
66
|
-
source: "node-edit-utils",
|
|
67
|
-
action,
|
|
68
|
-
data,
|
|
69
|
-
timestamp: Date.now(),
|
|
70
|
-
}, "*");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
282
|
const bindToWindow = (key, value) => {
|
|
74
283
|
if (typeof window !== "undefined") {
|
|
75
284
|
// biome-ignore lint/suspicious/noExplicitAny: global window extension requires flexibility
|
|
@@ -97,10 +306,6 @@
|
|
|
97
306
|
}
|
|
98
307
|
};
|
|
99
308
|
|
|
100
|
-
const getCanvasContainer = () => {
|
|
101
|
-
return document.querySelector(".canvas-container");
|
|
102
|
-
};
|
|
103
|
-
|
|
104
309
|
const clearHighlightFrame = () => {
|
|
105
310
|
const canvasContainer = getCanvasContainer();
|
|
106
311
|
const container = canvasContainer || document.body;
|
|
@@ -152,6 +357,21 @@
|
|
|
152
357
|
return false;
|
|
153
358
|
};
|
|
154
359
|
|
|
360
|
+
const isInsideViewport = (element) => {
|
|
361
|
+
let current = element;
|
|
362
|
+
while (current) {
|
|
363
|
+
if (current.classList.contains("viewport")) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
// Stop at node-provider to avoid checking beyond the editable area
|
|
367
|
+
if (current.getAttribute("data-role") === "node-provider") {
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
current = current.parentElement;
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
};
|
|
374
|
+
|
|
155
375
|
const targetSameCandidates = (cache, current) => cache.length === current.length && cache.every((el, i) => el === current[i]);
|
|
156
376
|
|
|
157
377
|
let candidateCache = [];
|
|
@@ -164,7 +384,16 @@
|
|
|
164
384
|
const clickThrough = event.metaKey || event.ctrlKey;
|
|
165
385
|
const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()) &&
|
|
166
386
|
!element.classList.contains("select-none") &&
|
|
167
|
-
!
|
|
387
|
+
!element.classList.contains("content-layer") &&
|
|
388
|
+
!element.classList.contains("resize-handle") &&
|
|
389
|
+
!element.classList.contains("resize-presets") &&
|
|
390
|
+
!isInsideComponent(element) &&
|
|
391
|
+
isInsideViewport(element));
|
|
392
|
+
console.log("candidates", candidates);
|
|
393
|
+
if (candidates.length === 0) {
|
|
394
|
+
lastSelectedNode = null;
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
168
397
|
const editableNode = text.getEditableNode();
|
|
169
398
|
if (editableNode && candidates.includes(editableNode)) {
|
|
170
399
|
selectedNode = editableNode;
|
|
@@ -269,16 +498,6 @@
|
|
|
269
498
|
createCornerHandle(group, 0, height, "handle-bottom-left", isInstance, isTextEdit);
|
|
270
499
|
};
|
|
271
500
|
|
|
272
|
-
function getScreenBounds(element) {
|
|
273
|
-
const rect = element.getBoundingClientRect();
|
|
274
|
-
return {
|
|
275
|
-
top: rect.top,
|
|
276
|
-
left: rect.left,
|
|
277
|
-
width: rect.width,
|
|
278
|
-
height: rect.height,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
501
|
const getComponentColor$1 = () => {
|
|
283
502
|
return getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim() || "oklch(65.6% 0.241 354.308)";
|
|
284
503
|
};
|
|
@@ -711,6 +930,7 @@
|
|
|
711
930
|
// Accumulate mutations instead of replacing
|
|
712
931
|
pendingMutations.push(...mutations);
|
|
713
932
|
scheduleProcess();
|
|
933
|
+
console.log("refreshHighlightFrame in mutationObserver");
|
|
714
934
|
refreshHighlightFrame(node, nodeProvider, canvasName);
|
|
715
935
|
});
|
|
716
936
|
return () => {
|
|
@@ -848,14 +1068,15 @@
|
|
|
848
1068
|
checkNodeExists();
|
|
849
1069
|
if (!document.contains(node))
|
|
850
1070
|
return;
|
|
1071
|
+
console.log("refreshHighlightFrame in mutationObserver 2");
|
|
851
1072
|
refreshHighlightFrame(node, nodeProvider, canvasName);
|
|
852
1073
|
updateHighlightFrameVisibility(node);
|
|
853
1074
|
});
|
|
854
1075
|
mutationObserver.observe(node, {
|
|
855
1076
|
attributes: true,
|
|
856
1077
|
characterData: true,
|
|
857
|
-
childList: true,
|
|
858
|
-
subtree: true,
|
|
1078
|
+
//childList: true,
|
|
1079
|
+
//subtree: true,
|
|
859
1080
|
});
|
|
860
1081
|
// Also observe parent node to catch when this node is removed
|
|
861
1082
|
const parentNode = node.parentElement;
|
|
@@ -884,15 +1105,22 @@
|
|
|
884
1105
|
if (!document.contains(node))
|
|
885
1106
|
return; // Exit early if node was removed
|
|
886
1107
|
refreshHighlightFrame(node, nodeProvider, canvasName);
|
|
1108
|
+
console.log("refreshHighlightFrame in resizeObserver");
|
|
887
1109
|
updateHighlightFrameVisibility(node);
|
|
888
1110
|
});
|
|
889
1111
|
}
|
|
890
1112
|
selectedNode = node;
|
|
891
1113
|
sendPostMessage("selectedNodeChanged", node?.getAttribute("data-node-id") ?? null);
|
|
892
1114
|
highlightNode(node) ?? null;
|
|
893
|
-
if (node
|
|
894
|
-
|
|
895
|
-
|
|
1115
|
+
if (node) {
|
|
1116
|
+
highlightNode(node);
|
|
1117
|
+
if (nodeProvider) {
|
|
1118
|
+
updateHighlightFrameVisibility(node);
|
|
1119
|
+
updateHighlightFrameVisibility(node);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
clearHighlightFrame();
|
|
896
1124
|
}
|
|
897
1125
|
};
|
|
898
1126
|
// Setup event listener
|
|
@@ -931,36 +1159,10 @@
|
|
|
931
1159
|
return nodeTools;
|
|
932
1160
|
};
|
|
933
1161
|
|
|
934
|
-
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
935
|
-
function withRAFThrottle(func) {
|
|
936
|
-
let rafId = null;
|
|
937
|
-
let lastArgs = null;
|
|
938
|
-
const throttled = (...args) => {
|
|
939
|
-
lastArgs = args;
|
|
940
|
-
if (rafId === null) {
|
|
941
|
-
rafId = requestAnimationFrame(() => {
|
|
942
|
-
if (lastArgs) {
|
|
943
|
-
func(...lastArgs);
|
|
944
|
-
}
|
|
945
|
-
rafId = null;
|
|
946
|
-
lastArgs = null;
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
};
|
|
950
|
-
throttled.cleanup = () => {
|
|
951
|
-
if (rafId !== null) {
|
|
952
|
-
cancelAnimationFrame(rafId);
|
|
953
|
-
rafId = null;
|
|
954
|
-
lastArgs = null;
|
|
955
|
-
}
|
|
956
|
-
};
|
|
957
|
-
return throttled;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
1162
|
const DEFAULT_WIDTH = 400;
|
|
961
1163
|
const RESIZE_CONFIG = {
|
|
962
|
-
minWidth:
|
|
963
|
-
maxWidth:
|
|
1164
|
+
minWidth: 4,
|
|
1165
|
+
maxWidth: 2560,
|
|
964
1166
|
};
|
|
965
1167
|
const RESIZE_PRESETS = [
|
|
966
1168
|
{
|
|
@@ -991,14 +1193,22 @@
|
|
|
991
1193
|
];
|
|
992
1194
|
|
|
993
1195
|
const setupEventListener = (resizeHandle, startResize, handleResize, stopResize, blurResize) => {
|
|
1196
|
+
const handleMouseLeave = (event) => {
|
|
1197
|
+
// Check if mouse is leaving the window/document
|
|
1198
|
+
if (!event.relatedTarget && (event.target === document || event.target === document.documentElement)) {
|
|
1199
|
+
blurResize();
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
994
1202
|
resizeHandle.addEventListener("mousedown", startResize);
|
|
995
1203
|
document.addEventListener("mousemove", handleResize);
|
|
996
1204
|
document.addEventListener("mouseup", stopResize);
|
|
1205
|
+
document.addEventListener("mouseleave", handleMouseLeave);
|
|
997
1206
|
window.addEventListener("blur", blurResize);
|
|
998
1207
|
return () => {
|
|
999
1208
|
resizeHandle.removeEventListener("mousedown", startResize);
|
|
1000
1209
|
document.removeEventListener("mousemove", handleResize);
|
|
1001
1210
|
document.removeEventListener("mouseup", stopResize);
|
|
1211
|
+
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
1002
1212
|
window.removeEventListener("blur", blurResize);
|
|
1003
1213
|
};
|
|
1004
1214
|
};
|
|
@@ -1058,7 +1268,7 @@
|
|
|
1058
1268
|
updateActivePreset(container, width);
|
|
1059
1269
|
};
|
|
1060
1270
|
|
|
1061
|
-
const createViewport = (container) => {
|
|
1271
|
+
const createViewport = (container, initialWidth) => {
|
|
1062
1272
|
const canvas = getCanvasContainer();
|
|
1063
1273
|
// Remove any existing resize handle to prevent duplicates
|
|
1064
1274
|
const existingHandle = container.querySelector(".resize-handle");
|
|
@@ -1066,7 +1276,8 @@
|
|
|
1066
1276
|
existingHandle.remove();
|
|
1067
1277
|
}
|
|
1068
1278
|
const resizeHandle = createResizeHandle(container);
|
|
1069
|
-
|
|
1279
|
+
const width = initialWidth ?? DEFAULT_WIDTH;
|
|
1280
|
+
container.style.setProperty("--container-width", `${width}px`);
|
|
1070
1281
|
createResizePresets(resizeHandle, container, updateWidth);
|
|
1071
1282
|
let isDragging = false;
|
|
1072
1283
|
let startX = 0;
|
|
@@ -1087,7 +1298,6 @@
|
|
|
1087
1298
|
const width = calcWidth(event, startX, startWidth);
|
|
1088
1299
|
updateWidth(container, width);
|
|
1089
1300
|
};
|
|
1090
|
-
const throttledHandleResize = withRAFThrottle(handleResize);
|
|
1091
1301
|
const stopResize = (event) => {
|
|
1092
1302
|
event.preventDefault();
|
|
1093
1303
|
event.stopPropagation();
|
|
@@ -1097,18 +1307,33 @@
|
|
|
1097
1307
|
isDragging = false;
|
|
1098
1308
|
};
|
|
1099
1309
|
const blurResize = () => {
|
|
1310
|
+
if (canvas) {
|
|
1311
|
+
canvas.style.cursor = "default";
|
|
1312
|
+
}
|
|
1100
1313
|
isDragging = false;
|
|
1101
1314
|
};
|
|
1102
|
-
const removeListeners = setupEventListener(resizeHandle, startResize,
|
|
1315
|
+
const removeListeners = setupEventListener(resizeHandle, startResize, handleResize, stopResize, blurResize);
|
|
1316
|
+
// Refresh viewport labels when viewport is created
|
|
1317
|
+
refreshViewportLabels();
|
|
1103
1318
|
const cleanup = () => {
|
|
1104
1319
|
isDragging = false;
|
|
1105
|
-
throttledHandleResize?.cleanup();
|
|
1106
1320
|
removeListeners();
|
|
1107
1321
|
resizeHandle.remove();
|
|
1322
|
+
// Refresh labels after cleanup to remove this viewport's label if needed
|
|
1323
|
+
refreshViewportLabels();
|
|
1108
1324
|
};
|
|
1109
1325
|
return {
|
|
1110
1326
|
setWidth: (width) => {
|
|
1111
1327
|
updateWidth(container, width);
|
|
1328
|
+
refreshViewportLabels();
|
|
1329
|
+
// Refresh highlight frame when viewport width changes to update node positions
|
|
1330
|
+
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
1331
|
+
const nodeTools = window.nodeTools;
|
|
1332
|
+
const selectedNode = nodeTools?.getSelectedNode?.();
|
|
1333
|
+
const nodeProvider = document.querySelector('[data-role="node-provider"]');
|
|
1334
|
+
if (selectedNode && nodeProvider) {
|
|
1335
|
+
refreshHighlightFrame(selectedNode, nodeProvider);
|
|
1336
|
+
}
|
|
1112
1337
|
},
|
|
1113
1338
|
cleanup,
|
|
1114
1339
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas={})}(this,function(e){"use strict";const t=(e,t="canvas")=>{const n=window[t];return e.reduce((e,t)=>e?.[t],n)};function n(e,t){window.parent.postMessage({source:"node-edit-utils",action:e,data:t,timestamp:Date.now()},"*")}const o=()=>document.querySelector(".canvas-container"),r=()=>{const e=o()||document.body,t=e.querySelector(".highlight-frame-overlay");t&&t.remove();const n=e.querySelector(".highlight-frame-tools-wrapper");n&&n.remove()},i=(e,t,n)=>{e&&t&&n.enableEditMode(e,t)},s=["path","rect","circle","ellipse","polygon","line","polyline","text","text-noci"];let a=[],l=0,d=null;const c=(e,t,n)=>{let o=null;const r=e.clientX,c=e.clientY,u=e.metaKey||e.ctrlKey,m=((e,t)=>{const n=document.elementsFromPoint(e,t);return Array.from(n).reduce((e,t)=>e.found?e:"node-provider"===t.getAttribute("data-role")?(e.found=!0,e):(e.elements.push(t),e),{elements:[],found:!1}).elements})(r,c).filter(e=>!s.includes(e.tagName.toLowerCase())&&!e.classList.contains("select-none")&&!(e=>{let t=e.parentElement;for(;t;){if("true"===t.getAttribute("data-instance"))return!0;if("node-provider"===t.getAttribute("data-role"))break;t=t.parentElement}return!1})(e)),h=n.getEditableNode();if(h&&m.includes(h))return o=h,d=o,o;if(u)return a=[],o=m[0],d&&d===o&&i(o,t,n),d=o,o;var g,p;p=m,(g=a).length===p.length&&g.every((e,t)=>e===p[t])?l<=m.length-2&&l++:l=0;return o=m[m.length-1-l],a=m,d&&d===o&&i(o,t,n),d=o,o},u=(e,t,n,o)=>{const i=e=>{((e,t)=>{if("application"===e.data.source&&"selectedNodeChanged"===e.data.action){const o=e.data.data,r=document.querySelector(`[data-node-id="${o}"]`);if(n=r,n?.classList.contains("select-none"))return void t?.(null);r&&t?.(r)}var n})(e,t)},s=n=>{((e,t,n,o)=>{if(e.preventDefault(),e.stopPropagation(),t&&!t.contains(e.target))return r(),void o(null);o(c(e,t,n))})(n,e,o,t)},a=e=>{"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),n?.())};return window.addEventListener("message",i),document.addEventListener("click",s),document.addEventListener("keydown",a),()=>{window.removeEventListener("message",i),document.removeEventListener("click",s),document.removeEventListener("keydown",a)}},m=e=>"true"===e.getAttribute("data-instance"),h=(e,t,n,o,r=!1,i=!1)=>{const s=document.createElementNS("http://www.w3.org/2000/svg","rect");return s.setAttribute("x",(t-3).toString()),s.setAttribute("y",(n-3).toString()),s.setAttribute("width",6..toString()),s.setAttribute("height",6..toString()),s.setAttribute("vector-effect","non-scaling-stroke"),s.classList.add("highlight-frame-handle",o),r?s.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)"):i&&s.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)"),e.appendChild(s),s};function g(e){const t=e.getBoundingClientRect();return{top:t.top,left:t.left,width:t.width,height:t.height}}const p=(e,t=!1,n=!1)=>{const{top:r,left:i,width:s,height:a}=g(e),l=Math.max(s,3),d=document.createElementNS("http://www.w3.org/2000/svg","svg");d.classList.add("highlight-frame-overlay"),t&&d.classList.add("is-instance"),n&&d.classList.add("is-text-edit"),d.setAttribute("data-node-id",e.getAttribute("data-node-id")||""),d.style.position="absolute",d.style.top="0",d.style.left="0",d.style.width="100vw",d.style.height="100vh",d.style.pointerEvents="none",d.style.zIndex="500";const c=document.documentElement.clientWidth||window.innerWidth,u=document.documentElement.clientHeight||window.innerHeight;d.setAttribute("width",c.toString()),d.setAttribute("height",u.toString());const m=document.createElementNS("http://www.w3.org/2000/svg","g");m.classList.add("highlight-frame-group"),m.setAttribute("transform",`translate(${i}, ${r})`);const p=document.createElementNS("http://www.w3.org/2000/svg","rect");p.setAttribute("x","0"),p.setAttribute("y","0"),p.setAttribute("width",l.toString()),p.setAttribute("height",a.toString()),p.setAttribute("vector-effect","non-scaling-stroke"),p.classList.add("highlight-frame-rect"),t?p.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)"):n&&p.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)"),m.appendChild(p),((e,t,n,o=!1,r=!1)=>{h(e,0,0,"handle-top-left",o,r),h(e,t,0,"handle-top-right",o,r),h(e,t,n,"handle-bottom-right",o,r),h(e,0,n,"handle-bottom-left",o,r)})(m,l,a,t,n),d.appendChild(m);const b=o();return b?b.appendChild(d):document.body.appendChild(d),d},b={div:"Container",h1:"Heading 1",h2:"Heading 2",h3:"Heading 3",h4:"Heading 4",h5:"Heading 5",h6:"Heading 6",p:"Text",li:"List Item",ul:"Unordered List",ol:"Ordered List",img:"Image",a:"Link"},v=(e,t,n=!1,o=!1)=>{const r=document.createElement("div");r.className="node-tools",n&&r.classList.add("is-instance"),o&&r.classList.add("is-text-edit"),t.appendChild(r),((e,t)=>{const n=document.createElement("div");n.className="tag-label";const o=e.getAttribute("data-instance-name"),r=e.tagName.toLowerCase(),i=o||b[r]||r;var s;n.textContent=(s=i)?s.charAt(0).toUpperCase()+s.slice(1):s,t.appendChild(n)})(e,r)};function y(){return(o()||document.body).querySelector(".highlight-frame-overlay")}const f=()=>getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)",w=()=>getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)",E=(e,n,r="canvas")=>{const i=y();if(!i)return;const s=m(e),a="true"===e.contentEditable,l=document.documentElement.clientWidth||window.innerWidth,d=document.documentElement.clientHeight||window.innerHeight;i.setAttribute("width",l.toString()),i.setAttribute("height",d.toString()),s?i.classList.add("is-instance"):i.classList.remove("is-instance"),a?i.classList.add("is-text-edit"):i.classList.remove("is-text-edit");const c=i.querySelector(".highlight-frame-group");if(!c)return;const u=c.querySelector("rect");if(!u)return;s?u.setAttribute("stroke",f()):a?u.setAttribute("stroke",w()):u.removeAttribute("stroke");const h=(o()||document.body).querySelector(".highlight-frame-tools-wrapper"),p=h?.querySelector(".node-tools"),b=t(["zoom","current"],r)??1,v=g(e),{top:E,left:L,width:A,height:x}=v,S=Math.max(A,3),C=E+x;h&&(s?h.classList.add("is-instance"):h.classList.remove("is-instance"),a?h.classList.add("is-text-edit"):h.classList.remove("is-text-edit")),p&&(s?p.classList.add("is-instance"):p.classList.remove("is-instance"),a?p.classList.add("is-text-edit"):p.classList.remove("is-text-edit")),c.setAttribute("transform",`translate(${L}, ${E})`),u.setAttribute("width",S.toString()),u.setAttribute("height",x.toString());const k=c.querySelector(".handle-top-left"),N=c.querySelector(".handle-top-right"),q=c.querySelector(".handle-bottom-right"),M=c.querySelector(".handle-bottom-left");[k,N,q,M].forEach(e=>{e&&(s?e.setAttribute("stroke",f()):a?e.setAttribute("stroke",w()):e.removeAttribute("stroke"))}),k&&(k.setAttribute("x",(-3).toString()),k.setAttribute("y",(-3).toString())),N&&(N.setAttribute("x",(S-3).toString()),N.setAttribute("y",(-3).toString())),q&&(q.setAttribute("x",(S-3).toString()),q.setAttribute("y",(x-3).toString())),M&&(M.setAttribute("x",(-3).toString()),M.setAttribute("y",(x-3).toString())),h&&(h.style.transform=`translate(${L}px, ${C}px)`),b<=10?n.style.setProperty("--tool-opacity","1"):n.style.setProperty("--tool-opacity","0")},L=e=>{const t=y();if(!t)return;const n=e.classList.contains("hidden")||e.classList.contains("select-none")?"none":"";t.style.display=n;const r=(o()||document.body).querySelector(".highlight-frame-tools-wrapper");r&&(r.style.display=n)},A=e=>{const t=e=>{"Enter"===e.key&&(e.preventDefault(),e.stopPropagation(),(()=>{const e=window.getSelection();if(e&&e.rangeCount>0){const t=e.getRangeAt(0);t.deleteContents();const n=document.createElement("br");t.insertNode(n),t.setStartAfter(n),t.setEndAfter(n),e.removeAllRanges(),e.addRange(t)}})())};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}},x=(e,t,o=!1)=>{if(!t.some(e=>"characterData"===e.type||"childList"===e.type&&(e.addedNodes.length>0||e.removedNodes.length>0))&&!o)return;const r=e.textContent??"",i=e.getAttribute("data-node-id");console.log("textContentChanged",r,o),n("textContentChanged",{nodeId:i,textContent:r,final:o})},S=(e,t,n="canvas")=>{let o=[],r=null,i=null;const s=()=>{null===r&&(r=requestAnimationFrame(()=>{i=requestAnimationFrame(()=>{(()=>{if(o.length>0){const t=[...o];o=[],x(e,t,!1)}})(),r=null,i=null})}))},a=((e,t)=>{const n=new MutationObserver(e=>{t(e)});return n.observe(e,{subtree:!0,childList:!0,characterData:!0}),n})(e,r=>{o.push(...r),s(),E(e,t,n)});return()=>{a.disconnect(),null!==r&&(cancelAnimationFrame(r),r=null),null!==i&&(cancelAnimationFrame(i),i=null),o=[]}},C=(e="canvas")=>{let n=null,o=!1,r=null;const i=()=>{if(o||!n)return;o=!0;const i=n;var s;x(i,[],!0),(s=i).contentEditable="false",s.classList.remove("is-editable"),s.style.outline="none",((e="canvas")=>{const n=t(["keyboard","disableTextEditMode"],e);n?.()})(e),r?.(),n=null,o=!1};return{enableEditMode:(o,s)=>{if(n===o)return;n&&n!==o&&i();const a=(e=>Array.from(e.childNodes).some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim()))(o);a&&(n=o,(e=>{e.contentEditable="true",e.classList.add("is-editable"),e.style.outline="none"})(o),((e="canvas")=>{const n=t(["keyboard","enableTextEditMode"],e);n?.()})(e),r=((e,t,n,o="canvas")=>{if(!t)return()=>{};e.addEventListener("blur",n);const r=A(e),i=S(e,t,o);return()=>{e.removeEventListener("blur",n),r(),i?.()}})(o,s,i,e))},blurEditMode:i,getEditableNode:()=>n,isEditing:()=>null!==n}};const k=320,N=1680,q=[{name:"Mobile",rawValue:390,value:"320px"},{name:"Tablet Portrait",rawValue:768,value:"768px"},{name:"Tablet Landscape",rawValue:1024,value:"1024px"},{name:"Notebook",rawValue:1280,value:"1280px"},{name:"Desktop",rawValue:1680,value:"1680px"}],M=(e,t,n)=>{const o=parseFloat(document.body.dataset.zoom||"1"),r=((e,t)=>{const n=e+Math.round(t);return Math.max(k,Math.min(N,n))})(n,(e.clientX-t)/o);return r},P=(e,t)=>{e.style.setProperty("--container-width",`${t}px`),((e,t)=>{e.querySelectorAll(".resize-preset-button").forEach((e,n)=>{n<q.length&&(q[n].rawValue===t?e.classList.add("is-active"):e.classList.remove("is-active"))})})(e,t)};e.createCanvasObserver=function(e="canvas"){const n=document.querySelector(".transform-layer");if(!n)return{disconnect:()=>{}};const o=new MutationObserver(()=>{((e="canvas")=>{const n=t(["zoom","current"],e)??1;document.body.style.setProperty("--zoom",n.toFixed(5)),document.body.style.setProperty("--stroke-width",(2/n).toFixed(3)),document.body.dataset.zoom=n.toFixed(5),document.body.dataset.strokeWidth=(2/n).toFixed(3)})(e);const n=window.nodeTools;n?.refreshHighlightFrame&&n.refreshHighlightFrame()});return o.observe(n,{attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0}),{disconnect:function(){o.disconnect()}}},e.createNodeTools=(e,t="canvas")=>{const i=e;let s=null,a=null,l=null,d=null;const c=C(t),h=e=>{if(d!==e){if(c.isEditing()){const t=c.getEditableNode();t&&t!==e&&c.blurEditMode()}if(s?.disconnect(),a?.disconnect(),l?.disconnect(),e&&i){const o=()=>{if(!document.contains(e))return r(),d=null,s?.disconnect(),a?.disconnect(),l?.disconnect(),void n("selectedNodeChanged",null)};a=new MutationObserver(()=>{o(),document.contains(e)&&(E(e,i,t),L(e))}),a.observe(e,{attributes:!0,characterData:!0,childList:!0,subtree:!0});const c=e.parentElement;c&&(l=new MutationObserver(t=>{for(const n of t)if("childList"===n.type)for(const t of Array.from(n.removedNodes))if(t===e||t instanceof Node&&t.contains(e))return void o()}),l.observe(c,{childList:!0,subtree:!1})),s=((e,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n})(e,()=>{o(),document.contains(e)&&(E(e,i,t),L(e))})}d=e,n("selectedNodeChanged",e?.getAttribute("data-node-id")??null),(e=>{if(!e)return;const t=y(),n=o(),r=n?.querySelector(".highlight-frame-tools-wrapper")||document.body.querySelector(".highlight-frame-tools-wrapper");t&&t.remove(),r&&r.remove();const i=m(e),s="true"===e.contentEditable,a=p(e,i,s);"true"===e.contentEditable&&a.classList.add("is-editable");const{left:l,top:d,height:c}=g(e),u=d+c,h=document.createElement("div");h.classList.add("highlight-frame-tools-wrapper"),i&&h.classList.add("is-instance"),s&&h.classList.add("is-text-edit"),h.style.position="absolute",h.style.transform=`translate(${l}px, ${u}px)`,h.style.transformOrigin="left center",h.style.pointerEvents="none",h.style.zIndex="500",v(e,h,i,s),n?n.appendChild(h):document.body.appendChild(h)})(e),e&&i&&(L(e),L(e))}},b=u(i,h,()=>{c.isEditing()&&c.blurEditMode(),d&&i&&(r(),d=null,s?.disconnect(),a?.disconnect(),l?.disconnect())},c),f={selectNode:h,getSelectedNode:()=>d,refreshHighlightFrame:()=>{d&&i&&(E(d,i,t),L(d))},clearSelectedNode:()=>{r(),d=null,s?.disconnect(),a?.disconnect(),l?.disconnect()},getEditableNode:()=>c.getEditableNode(),cleanup:()=>{b(),s?.disconnect(),a?.disconnect(),l?.disconnect(),c.blurEditMode(),r(),d=null,n("selectedNodeChanged",null)}};var w,A;return w="nodeTools",A=f,"undefined"!=typeof window&&(window[w]=A),f},e.createViewport=e=>{const t=o(),n=e.querySelector(".resize-handle");n&&n.remove();const r=(e=>{const t=document.createElement("div");return t.className="resize-handle",e.appendChild(t),t})(e);e.style.setProperty("--container-width","400px"),((e,t,n)=>{const o=document.createElement("div");o.className="resize-presets",q.forEach(e=>{const r=document.createElement("button");r.textContent=e.name,r.className="resize-preset-button",r.addEventListener("click",()=>{n(t,e.rawValue)}),o.appendChild(r)}),e.appendChild(o)})(r,e,P);let i=!1,s=0,a=0;const l=function(e){let t=null,n=null;const o=(...o)=>{n=o,null===t&&(t=requestAnimationFrame(()=>{n&&e(...n),t=null,n=null}))};return o.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null,n=null)},o}(n=>{if(!i)return;t&&(t.style.cursor="ew-resize");const o=M(n,s,a);P(e,o)}),d=((e,t,n,o,r)=>(e.addEventListener("mousedown",t),document.addEventListener("mousemove",n),document.addEventListener("mouseup",o),window.addEventListener("blur",r),()=>{e.removeEventListener("mousedown",t),document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o),window.removeEventListener("blur",r)}))(r,t=>{t.preventDefault(),t.stopPropagation(),i=!0,s=t.clientX,a=e.offsetWidth},l,e=>{e.preventDefault(),e.stopPropagation(),t&&(t.style.cursor="default"),i=!1},()=>{i=!1});return{setWidth:t=>{P(e,t)},cleanup:()=>{i=!1,l?.cleanup(),d(),r.remove()}}}});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas={})}(this,function(e){"use strict";function t(e){const t=e.getBoundingClientRect();return{top:t.top,left:t.left,width:t.width,height:t.height}}const n=()=>document.querySelector(".canvas-container");let o=!1;const r=e=>{o=e};function s(e,t){window.parent.postMessage({source:"node-edit-utils",action:e,data:t,timestamp:Date.now()},"*")}const i=e=>{const t=e.style.transform.match(/translate3d\((-?\d+(?:\.\d+)?)px,\s*(-?\d+(?:\.\d+)?)px,\s*(-?\d+(?:\.\d+)?)px\)/);return t?{x:parseFloat(t[1]),y:parseFloat(t[2])}:{x:0,y:0}},a=(e,t,n)=>{let o=!1,a=0,d=0,l={x:0,y:0},c={x:0,y:0};const u=e.parentElement,m=e=>{e.preventDefault(),e.stopPropagation(),o=!0,r(!0),a=e.clientX,d=e.clientY,l=i(t),c=(e=>{const t=e.getAttribute("transform"),n=t?.match(/translate\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);return n?{x:parseFloat(n[1]),y:parseFloat(n[2])}:{x:0,y:0}})(u)},h=e=>{if(!o)return;const n=(()=>{const e=getComputedStyle(document.body).getPropertyValue("--zoom").trim();return e?parseFloat(e):1})(),r=e.clientX-a,s=e.clientY-d,i=r/n,m=s/n,h=l.x+i,g=l.y+m,p=c.x+r,v=c.y+s;u.setAttribute("transform",`translate(${p}, ${v})`),t.style.transform=`translate3d(${h}px, ${g}px, 0)`},g=e=>{if(!o)return;e.preventDefault(),e.stopPropagation(),o=!1,r(!1);const a=i(t),d=window.nodeTools;d?.refreshHighlightFrame&&d.refreshHighlightFrame(),s("viewport-position-changed",{viewportName:n,x:a.x,y:a.y})},p=()=>{o=!1,r(!1)};return e.addEventListener("mousedown",m),document.addEventListener("mousemove",h),document.addEventListener("mouseup",g),window.addEventListener("blur",p),()=>{e.removeEventListener("mousedown",m),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",g),window.removeEventListener("blur",p)}},d=new Map,l=()=>{if(o)return;const e=(()=>{const e=n()||document.body;let t=e.querySelector(".viewport-labels-overlay");if(!t){t=document.createElementNS("http://www.w3.org/2000/svg","svg"),t.classList.add("viewport-labels-overlay"),t.style.position="absolute",t.style.top="0",t.style.left="0",t.style.width="100vw",t.style.height="100vh",t.style.pointerEvents="none",t.style.zIndex="500";const n=document.documentElement.clientWidth||window.innerWidth,o=document.documentElement.clientHeight||window.innerHeight;t.setAttribute("width",n.toString()),t.setAttribute("height",o.toString()),e.appendChild(t)}return t})(),r=document.documentElement.clientWidth||window.innerWidth,s=document.documentElement.clientHeight||window.innerHeight;e.setAttribute("width",r.toString()),e.setAttribute("height",s.toString());const i=document.querySelectorAll(".viewport[data-viewport-name]");d.forEach(e=>{e()}),d.clear();e.querySelectorAll(".viewport-label-group").forEach(e=>{e.remove()}),i.forEach(n=>{const o=n,r=o.getAttribute("data-viewport-name");if(!r)return;const s=t(o),i=document.createElementNS("http://www.w3.org/2000/svg","g");i.classList.add("viewport-label-group"),i.setAttribute("data-viewport-name",r),i.setAttribute("transform",`translate(${s.left}, ${s.top})`);const l=document.createElementNS("http://www.w3.org/2000/svg","text");l.classList.add("viewport-label-text"),l.setAttribute("x","0"),l.setAttribute("y","-8"),l.setAttribute("vector-effect","non-scaling-stroke"),l.setAttribute("pointer-events","auto"),l.textContent=r,i.appendChild(l),e.appendChild(i);const c=a(l,o,r);d.set(r,c)})},c=(e,t="canvas")=>{const n=window[t];return e.reduce((e,t)=>e?.[t],n)};const u=()=>{const e=n()||document.body,t=e.querySelector(".highlight-frame-overlay");t&&t.remove();const o=e.querySelector(".highlight-frame-tools-wrapper");o&&o.remove()},m=(e,t,n)=>{e&&t&&n.enableEditMode(e,t)},h=["path","rect","circle","ellipse","polygon","line","polyline","text","text-noci"];let g=[],p=0,v=null;const b=(e,t,n)=>{let o=null;const r=e.clientX,s=e.clientY,i=e.metaKey||e.ctrlKey,a=((e,t)=>{const n=document.elementsFromPoint(e,t);return Array.from(n).reduce((e,t)=>e.found?e:"node-provider"===t.getAttribute("data-role")?(e.found=!0,e):(e.elements.push(t),e),{elements:[],found:!1}).elements})(r,s).filter(e=>!h.includes(e.tagName.toLowerCase())&&!e.classList.contains("select-none")&&!e.classList.contains("content-layer")&&!e.classList.contains("resize-handle")&&!e.classList.contains("resize-presets")&&!(e=>{let t=e.parentElement;for(;t;){if("true"===t.getAttribute("data-instance"))return!0;if("node-provider"===t.getAttribute("data-role"))break;t=t.parentElement}return!1})(e)&&(e=>{let t=e;for(;t;){if(t.classList.contains("viewport"))return!0;if("node-provider"===t.getAttribute("data-role"))break;t=t.parentElement}return!1})(e));if(console.log("candidates",a),0===a.length)return v=null,null;const d=n.getEditableNode();if(d&&a.includes(d))return o=d,v=o,o;if(i)return g=[],o=a[0],v&&v===o&&m(o,t,n),v=o,o;var l,c;c=a,(l=g).length===c.length&&l.every((e,t)=>e===c[t])?p<=a.length-2&&p++:p=0;return o=a[a.length-1-p],g=a,v&&v===o&&m(o,t,n),v=o,o},y=(e,t,n,o)=>{const r=e=>{((e,t)=>{if("application"===e.data.source&&"selectedNodeChanged"===e.data.action){const o=e.data.data,r=document.querySelector(`[data-node-id="${o}"]`);if(n=r,n?.classList.contains("select-none"))return void t?.(null);r&&t?.(r)}var n})(e,t)},s=n=>{((e,t,n,o)=>{if(e.preventDefault(),e.stopPropagation(),t&&!t.contains(e.target))return u(),void o(null);o(b(e,t,n))})(n,e,o,t)},i=e=>{"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),n?.())};return window.addEventListener("message",r),document.addEventListener("click",s),document.addEventListener("keydown",i),()=>{window.removeEventListener("message",r),document.removeEventListener("click",s),document.removeEventListener("keydown",i)}},f=e=>"true"===e.getAttribute("data-instance"),w=(e,t,n,o,r=!1,s=!1)=>{const i=document.createElementNS("http://www.w3.org/2000/svg","rect");return i.setAttribute("x",(t-3).toString()),i.setAttribute("y",(n-3).toString()),i.setAttribute("width",6..toString()),i.setAttribute("height",6..toString()),i.setAttribute("vector-effect","non-scaling-stroke"),i.classList.add("highlight-frame-handle",o),r?i.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)"):s&&i.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)"),e.appendChild(i),i},E=(e,o=!1,r=!1)=>{const{top:s,left:i,width:a,height:d}=t(e),l=Math.max(a,3),c=document.createElementNS("http://www.w3.org/2000/svg","svg");c.classList.add("highlight-frame-overlay"),o&&c.classList.add("is-instance"),r&&c.classList.add("is-text-edit"),c.setAttribute("data-node-id",e.getAttribute("data-node-id")||""),c.style.position="absolute",c.style.top="0",c.style.left="0",c.style.width="100vw",c.style.height="100vh",c.style.pointerEvents="none",c.style.zIndex="500";const u=document.documentElement.clientWidth||window.innerWidth,m=document.documentElement.clientHeight||window.innerHeight;c.setAttribute("width",u.toString()),c.setAttribute("height",m.toString());const h=document.createElementNS("http://www.w3.org/2000/svg","g");h.classList.add("highlight-frame-group"),h.setAttribute("transform",`translate(${i}, ${s})`);const g=document.createElementNS("http://www.w3.org/2000/svg","rect");g.setAttribute("x","0"),g.setAttribute("y","0"),g.setAttribute("width",l.toString()),g.setAttribute("height",d.toString()),g.setAttribute("vector-effect","non-scaling-stroke"),g.classList.add("highlight-frame-rect"),o?g.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)"):r&&g.setAttribute("stroke",getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)"),h.appendChild(g),((e,t,n,o=!1,r=!1)=>{w(e,0,0,"handle-top-left",o,r),w(e,t,0,"handle-top-right",o,r),w(e,t,n,"handle-bottom-right",o,r),w(e,0,n,"handle-bottom-left",o,r)})(h,l,d,o,r),c.appendChild(h);const p=n();return p?p.appendChild(c):document.body.appendChild(c),c},L={div:"Container",h1:"Heading 1",h2:"Heading 2",h3:"Heading 3",h4:"Heading 4",h5:"Heading 5",h6:"Heading 6",p:"Text",li:"List Item",ul:"Unordered List",ol:"Ordered List",img:"Image",a:"Link"},A=(e,t,n=!1,o=!1)=>{const r=document.createElement("div");r.className="node-tools",n&&r.classList.add("is-instance"),o&&r.classList.add("is-text-edit"),t.appendChild(r),((e,t)=>{const n=document.createElement("div");n.className="tag-label";const o=e.getAttribute("data-instance-name"),r=e.tagName.toLowerCase(),s=o||L[r]||r;var i;n.textContent=(i=s)?i.charAt(0).toUpperCase()+i.slice(1):i,t.appendChild(n)})(e,r)};function x(){return(n()||document.body).querySelector(".highlight-frame-overlay")}const S=e=>{if(!e)return;const o=x(),r=n(),s=r?.querySelector(".highlight-frame-tools-wrapper")||document.body.querySelector(".highlight-frame-tools-wrapper");o&&o.remove(),s&&s.remove();const i=f(e),a="true"===e.contentEditable,d=E(e,i,a);"true"===e.contentEditable&&d.classList.add("is-editable");const{left:l,top:c,height:u}=t(e),m=c+u,h=document.createElement("div");h.classList.add("highlight-frame-tools-wrapper"),i&&h.classList.add("is-instance"),a&&h.classList.add("is-text-edit"),h.style.position="absolute",h.style.transform=`translate(${l}px, ${m}px)`,h.style.transformOrigin="left center",h.style.pointerEvents="none",h.style.zIndex="500",A(e,h,i,a),r?r.appendChild(h):document.body.appendChild(h)},C=()=>getComputedStyle(document.documentElement).getPropertyValue("--component-color").trim()||"oklch(65.6% 0.241 354.308)",k=()=>getComputedStyle(document.documentElement).getPropertyValue("--text-edit-color").trim()||"oklch(62.3% 0.214 259.815)",N=(e,o,r="canvas")=>{const s=x();if(!s)return;const i=f(e),a="true"===e.contentEditable,d=document.documentElement.clientWidth||window.innerWidth,l=document.documentElement.clientHeight||window.innerHeight;s.setAttribute("width",d.toString()),s.setAttribute("height",l.toString()),i?s.classList.add("is-instance"):s.classList.remove("is-instance"),a?s.classList.add("is-text-edit"):s.classList.remove("is-text-edit");const u=s.querySelector(".highlight-frame-group");if(!u)return;const m=u.querySelector("rect");if(!m)return;i?m.setAttribute("stroke",C()):a?m.setAttribute("stroke",k()):m.removeAttribute("stroke");const h=(n()||document.body).querySelector(".highlight-frame-tools-wrapper"),g=h?.querySelector(".node-tools"),p=c(["zoom","current"],r)??1,v=t(e),{top:b,left:y,width:w,height:E}=v,L=Math.max(w,3),A=b+E;h&&(i?h.classList.add("is-instance"):h.classList.remove("is-instance"),a?h.classList.add("is-text-edit"):h.classList.remove("is-text-edit")),g&&(i?g.classList.add("is-instance"):g.classList.remove("is-instance"),a?g.classList.add("is-text-edit"):g.classList.remove("is-text-edit")),u.setAttribute("transform",`translate(${y}, ${b})`),m.setAttribute("width",L.toString()),m.setAttribute("height",E.toString());const S=u.querySelector(".handle-top-left"),N=u.querySelector(".handle-top-right"),q=u.querySelector(".handle-bottom-right"),F=u.querySelector(".handle-bottom-left");[S,N,q,F].forEach(e=>{e&&(i?e.setAttribute("stroke",C()):a?e.setAttribute("stroke",k()):e.removeAttribute("stroke"))}),S&&(S.setAttribute("x",(-3).toString()),S.setAttribute("y",(-3).toString())),N&&(N.setAttribute("x",(L-3).toString()),N.setAttribute("y",(-3).toString())),q&&(q.setAttribute("x",(L-3).toString()),q.setAttribute("y",(E-3).toString())),F&&(F.setAttribute("x",(-3).toString()),F.setAttribute("y",(E-3).toString())),h&&(h.style.transform=`translate(${y}px, ${A}px)`),p<=10?o.style.setProperty("--tool-opacity","1"):o.style.setProperty("--tool-opacity","0")},q=e=>{const t=x();if(!t)return;const o=e.classList.contains("hidden")||e.classList.contains("select-none")?"none":"";t.style.display=o;const r=(n()||document.body).querySelector(".highlight-frame-tools-wrapper");r&&(r.style.display=o)},F=e=>{const t=e=>{"Enter"===e.key&&(e.preventDefault(),e.stopPropagation(),(()=>{const e=window.getSelection();if(e&&e.rangeCount>0){const t=e.getRangeAt(0);t.deleteContents();const n=document.createElement("br");t.insertNode(n),t.setStartAfter(n),t.setEndAfter(n),e.removeAllRanges(),e.addRange(t)}})())};return e.addEventListener("keydown",t),()=>{e.removeEventListener("keydown",t)}},H=(e,t,n=!1)=>{if(!t.some(e=>"characterData"===e.type||"childList"===e.type&&(e.addedNodes.length>0||e.removedNodes.length>0))&&!n)return;const o=e.textContent??"",r=e.getAttribute("data-node-id");console.log("textContentChanged",o,n),s("textContentChanged",{nodeId:r,textContent:o,final:n})},P=(e,t,n="canvas")=>{let o=[],r=null,s=null;const i=()=>{null===r&&(r=requestAnimationFrame(()=>{s=requestAnimationFrame(()=>{(()=>{if(o.length>0){const t=[...o];o=[],H(e,t,!1)}})(),r=null,s=null})}))},a=((e,t)=>{const n=new MutationObserver(e=>{t(e)});return n.observe(e,{subtree:!0,childList:!0,characterData:!0}),n})(e,r=>{o.push(...r),i(),console.log("refreshHighlightFrame in mutationObserver"),N(e,t,n)});return()=>{a.disconnect(),null!==r&&(cancelAnimationFrame(r),r=null),null!==s&&(cancelAnimationFrame(s),s=null),o=[]}},z=(e="canvas")=>{let t=null,n=!1,o=null;const r=()=>{if(n||!t)return;n=!0;const r=t;var s;H(r,[],!0),(s=r).contentEditable="false",s.classList.remove("is-editable"),s.style.outline="none",((e="canvas")=>{const t=c(["keyboard","disableTextEditMode"],e);t?.()})(e),o?.(),t=null,n=!1};return{enableEditMode:(n,s)=>{if(t===n)return;t&&t!==n&&r();const i=(e=>Array.from(e.childNodes).some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim()))(n);i&&(t=n,(e=>{e.contentEditable="true",e.classList.add("is-editable"),e.style.outline="none"})(n),((e="canvas")=>{const t=c(["keyboard","enableTextEditMode"],e);t?.()})(e),o=((e,t,n,o="canvas")=>{if(!t)return()=>{};e.addEventListener("blur",n);const r=F(e),s=P(e,t,o);return()=>{e.removeEventListener("blur",n),r(),s?.()}})(n,s,r,e))},blurEditMode:r,getEditableNode:()=>t,isEditing:()=>null!==t}},M=4,$=2560,T=[{name:"Mobile",rawValue:390,value:"320px"},{name:"Tablet Portrait",rawValue:768,value:"768px"},{name:"Tablet Landscape",rawValue:1024,value:"1024px"},{name:"Notebook",rawValue:1280,value:"1280px"},{name:"Desktop",rawValue:1680,value:"1680px"}],V=(e,t,n)=>{const o=parseFloat(document.body.dataset.zoom||"1"),r=((e,t)=>{const n=e+Math.round(t);return Math.max(M,Math.min($,n))})(n,(e.clientX-t)/o);return r},D=(e,t)=>{e.style.setProperty("--container-width",`${t}px`),((e,t)=>{e.querySelectorAll(".resize-preset-button").forEach((e,n)=>{n<T.length&&(T[n].rawValue===t?e.classList.add("is-active"):e.classList.remove("is-active"))})})(e,t)};e.createCanvasObserver=function(e="canvas"){const t=document.querySelector(".transform-layer");if(!t)return{disconnect:()=>{}};const n=new MutationObserver(()=>{((e="canvas")=>{const t=c(["zoom","current"],e)??1;document.body.style.setProperty("--zoom",t.toFixed(5)),document.body.style.setProperty("--stroke-width",(2/t).toFixed(3)),document.body.dataset.zoom=t.toFixed(5),document.body.dataset.strokeWidth=(2/t).toFixed(3)})(e);const t=window.nodeTools;t?.refreshHighlightFrame&&t.refreshHighlightFrame(),l()});n.observe(t,{attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0});const o=()=>{l()};return window.addEventListener("resize",o),l(),{disconnect:function(){n.disconnect(),window.removeEventListener("resize",o)}}},e.createNodeTools=(e,t="canvas")=>{const n=e;let o=null,r=null,i=null,a=null;const d=z(t),l=e=>{if(a!==e){if(d.isEditing()){const t=d.getEditableNode();t&&t!==e&&d.blurEditMode()}if(o?.disconnect(),r?.disconnect(),i?.disconnect(),e&&n){const d=()=>{if(!document.contains(e))return u(),a=null,o?.disconnect(),r?.disconnect(),i?.disconnect(),void s("selectedNodeChanged",null)};r=new MutationObserver(()=>{d(),document.contains(e)&&(console.log("refreshHighlightFrame in mutationObserver 2"),N(e,n,t),q(e))}),r.observe(e,{attributes:!0,characterData:!0});const l=e.parentElement;l&&(i=new MutationObserver(t=>{for(const n of t)if("childList"===n.type)for(const t of Array.from(n.removedNodes))if(t===e||t instanceof Node&&t.contains(e))return void d()}),i.observe(l,{childList:!0,subtree:!1})),o=((e,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n})(e,()=>{d(),document.contains(e)&&(N(e,n,t),console.log("refreshHighlightFrame in resizeObserver"),q(e))})}a=e,s("selectedNodeChanged",e?.getAttribute("data-node-id")??null),S(e),e?(S(e),n&&(q(e),q(e))):u()}},c=y(n,l,()=>{d.isEditing()&&d.blurEditMode(),a&&n&&(u(),a=null,o?.disconnect(),r?.disconnect(),i?.disconnect())},d),m={selectNode:l,getSelectedNode:()=>a,refreshHighlightFrame:()=>{a&&n&&(N(a,n,t),q(a))},clearSelectedNode:()=>{u(),a=null,o?.disconnect(),r?.disconnect(),i?.disconnect()},getEditableNode:()=>d.getEditableNode(),cleanup:()=>{c(),o?.disconnect(),r?.disconnect(),i?.disconnect(),d.blurEditMode(),u(),a=null,s("selectedNodeChanged",null)}};var h,g;return h="nodeTools",g=m,"undefined"!=typeof window&&(window[h]=g),m},e.createViewport=(e,t)=>{const o=n(),r=e.querySelector(".resize-handle");r&&r.remove();const s=(e=>{const t=document.createElement("div");return t.className="resize-handle",e.appendChild(t),t})(e),i=t??400;e.style.setProperty("--container-width",`${i}px`),((e,t,n)=>{const o=document.createElement("div");o.className="resize-presets",T.forEach(e=>{const r=document.createElement("button");r.textContent=e.name,r.className="resize-preset-button",r.addEventListener("click",()=>{n(t,e.rawValue)}),o.appendChild(r)}),e.appendChild(o)})(s,e,D);let a=!1,d=0,c=0;const u=((e,t,n,o,r)=>{const s=e=>{e.relatedTarget||e.target!==document&&e.target!==document.documentElement||r()};return e.addEventListener("mousedown",t),document.addEventListener("mousemove",n),document.addEventListener("mouseup",o),document.addEventListener("mouseleave",s),window.addEventListener("blur",r),()=>{e.removeEventListener("mousedown",t),document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o),document.removeEventListener("mouseleave",s),window.removeEventListener("blur",r)}})(s,t=>{t.preventDefault(),t.stopPropagation(),a=!0,d=t.clientX,c=e.offsetWidth},t=>{if(!a)return;o&&(o.style.cursor="ew-resize");const n=V(t,d,c);D(e,n)},e=>{e.preventDefault(),e.stopPropagation(),o&&(o.style.cursor="default"),a=!1},()=>{o&&(o.style.cursor="default"),a=!1});l();return{setWidth:t=>{D(e,t),l();const n=window.nodeTools,o=n?.getSelectedNode?.(),r=document.querySelector('[data-role="node-provider"]');o&&r&&N(o,r)},cleanup:()=>{a=!1,u(),s.remove(),l()}}}});
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--primary-color:oklch(0.6235 0.22 294);--uncode-color:oklch(45.7% 0.24 277.023);--component-color:oklch(65.6% 0.241 354.308);--text-edit-color:oklch(62.3% 0.214 259.815);--text-edit-selection-color:oklch(62.3% 0.214 259.815/0.2);--handle-color:oklch(55.2% 0.016 285.938);--handle-color-transparent:oklch(55.2% 0.016 285.938/0.7);--primary-color-selection:oklch(0.59 0.18 294/0.3);--text-color-white:#fff;--spacing-2xs:0.1875rem;--spacing-xs:0.25rem;--spacing-sm:0.375rem;--spacing-md:0.5rem;--spacing-lg:1.25rem;--transition-fast:0.1s ease-in-out;--transition-medium:0.2s ease-in-out;--z-index-high:10000;--z-index-highlight:500;--z-index-medium:1000;--letter-spacing:0.02em;--font-family-primary:"Manrope",sans-serif}.node-provider{::selection{background:transparent}::-moz-selection{background:transparent}::-webkit-selection{background:transparent}}.node-tools{bottom:0;contain:layout style;display:flex;gap:var(--spacing-xs);justify-content:center;left:0;opacity:var(--tool-opacity);padding-top:var(--spacing-2xs);position:absolute;top:0;transform:translate3d(0,100%,0);transform-origin:bottom center;transition:opacity var(--transition-fast);z-index:var(--z-index-high)}.highlight-frame-overlay{contain:layout style paint;height:100vh;inset:0;overflow:visible;pointer-events:none;position:absolute;width:100vw;will-change:transform;z-index:var(--z-index-highlight)}.highlight-frame-rect{fill:none;stroke:var(--primary-color);stroke-width:2px}.highlight-frame-overlay.is-instance .highlight-frame-rect{stroke:var(--component-color)}.highlight-frame-overlay.is-text-edit .highlight-frame-rect{stroke:var(--text-edit-color)}.highlight-frame-handle{fill:#fff;stroke:var(--primary-color);stroke-width:1px;cursor:nwse-resize;pointer-events:auto}.highlight-frame-overlay.is-instance .highlight-frame-handle{stroke:var(--component-color)}.highlight-frame-overlay.is-text-edit .highlight-frame-handle{stroke:var(--text-edit-color)}.highlight-frame-handle.handle-top-left{cursor:nwse-resize}.highlight-frame-handle.handle-top-right{cursor:nesw-resize}.highlight-frame-handle.handle-bottom-right{cursor:nwse-resize}.highlight-frame-handle.handle-bottom-left{cursor:nesw-resize}.highlight-frame-tools-wrapper{contain:layout style;left:0;pointer-events:none;position:absolute;top:0;z-index:var(--z-index-highlight)}.tag-label{align-items:center;background-color:var(--primary-color);border-radius:var(--spacing-sm);color:var(--text-color-white);display:flex;font-size:.575rem;font-weight:500;height:1rem;justify-content:center;line-height:1.4;padding:.5625rem var(--spacing-sm);white-space:nowrap}.highlight-frame-tools-wrapper.is-instance .tag-label,.node-tools.is-instance .tag-label{background-color:var(--component-color)}.highlight-frame-tools-wrapper.is-text-edit .tag-label,.node-tools.is-text-edit .tag-label{background-color:var(--text-edit-color)}.viewport{position:
|
|
1
|
+
:root{--primary-color:oklch(0.6235 0.22 294);--uncode-color:oklch(45.7% 0.24 277.023);--component-color:oklch(65.6% 0.241 354.308);--text-edit-color:oklch(62.3% 0.214 259.815);--text-edit-selection-color:oklch(62.3% 0.214 259.815/0.2);--handle-color:oklch(55.2% 0.016 285.938);--handle-color-transparent:oklch(55.2% 0.016 285.938/0.7);--primary-color-selection:oklch(0.59 0.18 294/0.3);--text-color-white:#fff;--spacing-2xs:0.1875rem;--spacing-xs:0.25rem;--spacing-sm:0.375rem;--spacing-md:0.5rem;--spacing-lg:1.25rem;--transition-fast:0.1s ease-in-out;--transition-medium:0.2s ease-in-out;--z-index-high:10000;--z-index-highlight:500;--z-index-medium:1000;--letter-spacing:0.02em;--font-family-primary:"Manrope",sans-serif}.node-provider{::selection{background:transparent}::-moz-selection{background:transparent}::-webkit-selection{background:transparent}}.node-tools{bottom:0;contain:layout style;display:flex;gap:var(--spacing-xs);justify-content:center;left:0;opacity:var(--tool-opacity);padding-top:var(--spacing-2xs);position:absolute;top:0;transform:translate3d(0,100%,0);transform-origin:bottom center;transition:opacity var(--transition-fast);z-index:var(--z-index-high)}.highlight-frame-overlay,.viewport-labels-overlay{contain:layout style paint;height:100vh;inset:0;overflow:visible;pointer-events:none;position:absolute;width:100vw;will-change:transform;z-index:var(--z-index-highlight)}.viewport-label-text{fill:oklch(.5 0 0);font-family:var(--font-family-primary);font-size:.6875rem;font-weight:500;letter-spacing:var(--letter-spacing);pointer-events:auto;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}@media (prefers-color-scheme:dark){.viewport-label-text{fill:oklch(.3 0 0)}.viewport-label-text:hover{fill:oklch(0 0 0)}}@media (prefers-color-scheme:light){.viewport-label-text{fill:oklch(.7 0 0)}.viewport-label-text:hover{fill:oklch(.3 0 0)}}.highlight-frame-rect{fill:none;stroke:var(--primary-color);stroke-width:2px}.highlight-frame-overlay.is-instance .highlight-frame-rect{stroke:var(--component-color)}.highlight-frame-overlay.is-text-edit .highlight-frame-rect{stroke:var(--text-edit-color)}.highlight-frame-handle{fill:#fff;stroke:var(--primary-color);stroke-width:1px;cursor:nwse-resize;pointer-events:auto}.highlight-frame-overlay.is-instance .highlight-frame-handle{stroke:var(--component-color)}.highlight-frame-overlay.is-text-edit .highlight-frame-handle{stroke:var(--text-edit-color)}.highlight-frame-handle.handle-top-left{cursor:nwse-resize}.highlight-frame-handle.handle-top-right{cursor:nesw-resize}.highlight-frame-handle.handle-bottom-right{cursor:nwse-resize}.highlight-frame-handle.handle-bottom-left{cursor:nesw-resize}.highlight-frame-tools-wrapper{contain:layout style;left:0;pointer-events:none;position:absolute;top:0;z-index:var(--z-index-highlight)}.tag-label{align-items:center;background-color:var(--primary-color);border-radius:var(--spacing-sm);color:var(--text-color-white);display:flex;font-size:.575rem;font-weight:500;height:1rem;justify-content:center;line-height:1.4;padding:.5625rem var(--spacing-sm);white-space:nowrap}.highlight-frame-tools-wrapper.is-instance .tag-label,.node-tools.is-instance .tag-label{background-color:var(--component-color)}.highlight-frame-tools-wrapper.is-text-edit .tag-label,.node-tools.is-text-edit .tag-label{background-color:var(--text-edit-color)}.viewport{left:0;position:absolute;top:0;width:var(--container-width)}.resize-handle{align-items:center;cursor:ew-resize;display:flex;height:40px;justify-content:center;opacity:0;pointer-events:auto;position:absolute;right:-12px;top:var(--spacing-lg);transform:scale(calc(1/var(--zoom)));transform-origin:top left;transition:opacity var(--transition-fast),visibility var(--transition-fast);visibility:hidden;width:12px;z-index:var(--z-index-high)}.viewport:hover .resize-handle{opacity:1;visibility:visible}.resize-handle:before{background:var(--handle-color);border-radius:4px;content:"";height:32px;position:relative;right:0;top:0;transition:transform var(--transition-medium);width:3px}.resize-handle:hover:before{transform:scaleY(1.3)}.resize-presets{display:flex;flex-direction:column;font-family:var(--font-family-primary);gap:var(--spacing-xs);left:0;letter-spacing:var(--letter-spacing);opacity:0;padding-left:var(--spacing-lg);position:absolute;top:0;transition:visibility var(--transition-fast),opacity var(--transition-fast);visibility:hidden}.resize-handle:hover .resize-presets{opacity:1;visibility:visible}.resize-preset-button{text-wrap:nowrap;backdrop-filter:blur(8px);background:var(--handle-color-transparent);border:none;border-radius:var(--spacing-md);color:var(--text-color-white);cursor:pointer;font-size:.625rem;padding:var(--spacing-xs) var(--spacing-md);text-align:left;transition:background var(--transition-fast);width:fit-content;&:hover{background:var(--handle-color)}&.is-active{background:var(--uncode-color)}}.is-editable{outline:none;user-select:text;&::selection{background:var(--text-edit-selection-color)}&::-moz-selection{background:var(--text-edit-selection-color)}&::-webkit-selection{background:var(--text-edit-selection-color)}}
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { refreshViewportLabels } from "../viewport/label/refreshViewportLabels";
|
|
1
2
|
import { applyCanvasState } from "./helpers/applyCanvasState";
|
|
2
3
|
import type { CanvasObserver } from "./types";
|
|
3
4
|
|
|
@@ -20,6 +21,9 @@ export function createCanvasObserver(canvasName: string = "canvas"): CanvasObser
|
|
|
20
21
|
if (nodeTools?.refreshHighlightFrame) {
|
|
21
22
|
nodeTools.refreshHighlightFrame();
|
|
22
23
|
}
|
|
24
|
+
|
|
25
|
+
// Refresh viewport labels
|
|
26
|
+
refreshViewportLabels();
|
|
23
27
|
});
|
|
24
28
|
|
|
25
29
|
observer.observe(transformLayer, {
|
|
@@ -29,8 +33,18 @@ export function createCanvasObserver(canvasName: string = "canvas"): CanvasObser
|
|
|
29
33
|
childList: true,
|
|
30
34
|
});
|
|
31
35
|
|
|
36
|
+
// Handle window resize for viewport labels
|
|
37
|
+
const handleResize = (): void => {
|
|
38
|
+
refreshViewportLabels();
|
|
39
|
+
};
|
|
40
|
+
window.addEventListener("resize", handleResize);
|
|
41
|
+
|
|
42
|
+
// Initial refresh of viewport labels
|
|
43
|
+
refreshViewportLabels();
|
|
44
|
+
|
|
32
45
|
function disconnect(): void {
|
|
33
46
|
observer.disconnect();
|
|
47
|
+
window.removeEventListener("resize", handleResize);
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
return {
|