@node-edit-utils/core 2.2.6 → 2.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/node-tools/events/click/handleNodeClick.d.ts +2 -1
- package/dist/lib/node-tools/events/setupEventListener.d.ts +2 -1
- package/dist/lib/node-tools/highlight/createCornerHandles.d.ts +1 -1
- package/dist/lib/node-tools/highlight/createHighlightFrame.d.ts +1 -1
- package/dist/lib/node-tools/highlight/createToolsContainer.d.ts +1 -1
- package/dist/lib/node-tools/select/selectNode.d.ts +2 -1
- package/dist/lib/node-tools/text/helpers/enterTextEditMode.d.ts +2 -0
- package/dist/lib/node-tools/text/helpers/handleTextChange.d.ts +1 -0
- package/dist/lib/node-tools/text/helpers/shouldEnterTextEditMode.d.ts +1 -0
- package/dist/node-edit-utils.cjs.js +227 -90
- package/dist/node-edit-utils.esm.js +227 -90
- package/dist/node-edit-utils.umd.js +227 -90
- package/dist/node-edit-utils.umd.min.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +4 -2
- package/src/index.ts +0 -2
- package/src/lib/node-tools/createNodeTools.ts +3 -16
- package/src/lib/node-tools/events/click/handleNodeClick.ts +3 -2
- package/src/lib/node-tools/events/setupEventListener.ts +3 -2
- package/src/lib/node-tools/highlight/clearHighlightFrame.ts +7 -2
- package/src/lib/node-tools/highlight/createCornerHandles.ts +12 -6
- package/src/lib/node-tools/highlight/createHighlightFrame.ts +25 -7
- package/src/lib/node-tools/highlight/createTagLabel.ts +25 -1
- package/src/lib/node-tools/highlight/createToolsContainer.ts +4 -1
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +5 -1
- package/src/lib/node-tools/highlight/highlightNode.ts +21 -11
- package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +40 -7
- package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.ts +6 -1
- package/src/lib/node-tools/select/selectNode.ts +24 -5
- package/src/lib/node-tools/text/events/setupMutationObserver.ts +17 -3
- package/src/lib/node-tools/text/helpers/enterTextEditMode.ts +9 -0
- package/src/lib/node-tools/text/helpers/handleTextChange.ts +27 -0
- package/src/lib/node-tools/text/helpers/shouldEnterTextEditMode.ts +9 -0
- package/src/lib/styles/styles.css +28 -8
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { getCanvasContainer } from "@/lib/canvas/helpers/getCanvasContainer";
|
|
1
2
|
import { getHighlightFrameElement } from "./helpers/getHighlightFrameElement";
|
|
2
3
|
|
|
3
4
|
export const updateHighlightFrameVisibility = (node: HTMLElement): void => {
|
|
4
5
|
const frame = getHighlightFrameElement();
|
|
5
6
|
if (!frame) return;
|
|
6
7
|
|
|
8
|
+
// Batch DOM reads
|
|
7
9
|
const hasHiddenClass = node.classList.contains("hidden") || node.classList.contains("select-none");
|
|
8
10
|
const displayValue = hasHiddenClass ? "none" : "";
|
|
9
11
|
|
|
12
|
+
// Batch DOM writes
|
|
10
13
|
frame.style.display = displayValue;
|
|
11
14
|
|
|
12
|
-
const
|
|
15
|
+
const canvasContainer = getCanvasContainer();
|
|
16
|
+
const container = canvasContainer || document.body;
|
|
17
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper") as HTMLElement | null;
|
|
13
18
|
if (toolsWrapper) {
|
|
14
19
|
toolsWrapper.style.display = displayValue;
|
|
15
20
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { enterTextEditMode } from "../text/helpers/enterTextEditMode";
|
|
2
|
+
import type { NodeText } from "../text/types";
|
|
1
3
|
import { IGNORED_DOM_ELEMENTS } from "./constants";
|
|
2
4
|
import { getElementsFromPoint } from "./helpers/getElementsFromPoint";
|
|
3
5
|
import { isInsideComponent } from "./helpers/isInsideComponent";
|
|
@@ -6,7 +8,9 @@ import { targetSameCandidates } from "./helpers/targetSameCandidates";
|
|
|
6
8
|
let candidateCache: Element[] = [];
|
|
7
9
|
let attempt = 0;
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
let lastSelectedNode: HTMLElement | null = null;
|
|
12
|
+
|
|
13
|
+
export const selectNode = (event: MouseEvent, nodeProvider: HTMLElement | null, text: NodeText): HTMLElement | null => {
|
|
10
14
|
let selectedNode: HTMLElement | null = null;
|
|
11
15
|
|
|
12
16
|
const clickX = event.clientX;
|
|
@@ -21,19 +25,29 @@ export const selectNode = (event: MouseEvent, editableNode: HTMLElement | null):
|
|
|
21
25
|
!isInsideComponent(element)
|
|
22
26
|
);
|
|
23
27
|
|
|
28
|
+
const editableNode = text.getEditableNode();
|
|
24
29
|
if (editableNode && candidates.includes(editableNode)) {
|
|
25
|
-
|
|
30
|
+
selectedNode = editableNode;
|
|
31
|
+
lastSelectedNode = selectedNode;
|
|
32
|
+
|
|
33
|
+
return selectedNode;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
if (clickThrough) {
|
|
29
37
|
candidateCache = [];
|
|
30
|
-
|
|
31
38
|
selectedNode = candidates[0] as HTMLElement;
|
|
39
|
+
|
|
40
|
+
if (lastSelectedNode && lastSelectedNode === selectedNode) {
|
|
41
|
+
enterTextEditMode(selectedNode, nodeProvider, text);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
lastSelectedNode = selectedNode;
|
|
45
|
+
|
|
32
46
|
return selectedNode;
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
if (targetSameCandidates(candidateCache, candidates)) {
|
|
36
|
-
attempt <= candidates.length && attempt++;
|
|
50
|
+
attempt <= candidates.length - 2 && attempt++;
|
|
37
51
|
} else {
|
|
38
52
|
attempt = 0;
|
|
39
53
|
}
|
|
@@ -41,8 +55,13 @@ export const selectNode = (event: MouseEvent, editableNode: HTMLElement | null):
|
|
|
41
55
|
const nodeIndex = candidates.length - 1 - attempt;
|
|
42
56
|
|
|
43
57
|
selectedNode = candidates[nodeIndex] as HTMLElement;
|
|
44
|
-
|
|
45
58
|
candidateCache = candidates;
|
|
46
59
|
|
|
60
|
+
if (lastSelectedNode && lastSelectedNode === selectedNode) {
|
|
61
|
+
enterTextEditMode(selectedNode, nodeProvider, text);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
lastSelectedNode = selectedNode;
|
|
65
|
+
|
|
47
66
|
return selectedNode;
|
|
48
67
|
};
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { connectMutationObserver } from "../../../helpers/observer/connectMutationObserver";
|
|
2
|
+
import { withRAFThrottle } from "../../../helpers/withRAF";
|
|
2
3
|
import { refreshHighlightFrame } from "../../highlight/refreshHighlightFrame";
|
|
4
|
+
import { handleTextChange } from "../helpers/handleTextChange";
|
|
3
5
|
|
|
4
|
-
export const setupMutationObserver = (
|
|
5
|
-
|
|
6
|
+
export const setupMutationObserver = (
|
|
7
|
+
node: HTMLElement,
|
|
8
|
+
nodeProvider: HTMLElement,
|
|
9
|
+
canvasName: string = "canvas"
|
|
10
|
+
): (() => void) | undefined => {
|
|
11
|
+
const throttledHandleTextChange = withRAFThrottle((mutations: MutationRecord[]) => {
|
|
12
|
+
handleTextChange(node, mutations);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const mutationObserver = connectMutationObserver(node, (mutations) => {
|
|
16
|
+
throttledHandleTextChange(mutations);
|
|
6
17
|
refreshHighlightFrame(node, nodeProvider, canvasName);
|
|
7
18
|
});
|
|
8
19
|
|
|
9
|
-
return () =>
|
|
20
|
+
return () => {
|
|
21
|
+
mutationObserver.disconnect();
|
|
22
|
+
throttledHandleTextChange.cleanup();
|
|
23
|
+
};
|
|
10
24
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { sendPostMessage } from "@/lib/post-message/sendPostMessage";
|
|
2
|
+
|
|
3
|
+
export const handleTextChange = (node: HTMLElement, mutations: MutationRecord[]): void => {
|
|
4
|
+
// Check if any mutation is a text content change
|
|
5
|
+
const hasTextChange = mutations.some((mutation) => {
|
|
6
|
+
return (
|
|
7
|
+
mutation.type === "characterData" ||
|
|
8
|
+
(mutation.type === "childList" && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0))
|
|
9
|
+
);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (!hasTextChange) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Get the text content of the node
|
|
17
|
+
const textContent = node.textContent ?? "";
|
|
18
|
+
|
|
19
|
+
// Get the node ID
|
|
20
|
+
const nodeId = node.getAttribute("data-node-id");
|
|
21
|
+
|
|
22
|
+
// Send postMessage with the text change
|
|
23
|
+
sendPostMessage("textContentChanged", {
|
|
24
|
+
nodeId,
|
|
25
|
+
textContent,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
--primary-color: oklch(0.6235 0.22 294);
|
|
3
3
|
--uncode-color: oklch(45.7% 0.24 277.023);
|
|
4
4
|
--component-color: oklch(65.6% 0.241 354.308);
|
|
5
|
+
--text-edit-color: oklch(62.3% 0.214 259.815);
|
|
6
|
+
--text-edit-selection-color: oklch(62.3% 0.214 259.815 / 0.2);
|
|
5
7
|
|
|
6
8
|
--handle-color: oklch(55.2% 0.016 285.938);
|
|
7
9
|
--handle-color-transparent: oklch(55.2% 0.016 285.938 / 0.7);
|
|
@@ -19,7 +21,7 @@
|
|
|
19
21
|
--transition-medium: 0.2s ease-in-out;
|
|
20
22
|
|
|
21
23
|
--z-index-high: 10000;
|
|
22
|
-
--z-index-highlight:
|
|
24
|
+
--z-index-highlight: 500;
|
|
23
25
|
--z-index-medium: 1000;
|
|
24
26
|
|
|
25
27
|
--letter-spacing: 0.02em;
|
|
@@ -54,16 +56,19 @@
|
|
|
54
56
|
padding-top: var(--spacing-2xs);
|
|
55
57
|
display: flex;
|
|
56
58
|
justify-content: center;
|
|
59
|
+
contain: layout style;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
.highlight-frame-overlay {
|
|
60
|
-
position:
|
|
63
|
+
position: absolute;
|
|
61
64
|
inset: 0;
|
|
62
65
|
width: 100vw;
|
|
63
66
|
height: 100vh;
|
|
64
67
|
pointer-events: none;
|
|
65
68
|
z-index: var(--z-index-highlight);
|
|
66
69
|
overflow: visible;
|
|
70
|
+
contain: layout style paint;
|
|
71
|
+
will-change: transform;
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
.highlight-frame-rect {
|
|
@@ -76,6 +81,10 @@
|
|
|
76
81
|
stroke: var(--component-color);
|
|
77
82
|
}
|
|
78
83
|
|
|
84
|
+
.highlight-frame-overlay.is-text-edit .highlight-frame-rect {
|
|
85
|
+
stroke: var(--text-edit-color);
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
.highlight-frame-handle {
|
|
80
89
|
fill: white;
|
|
81
90
|
stroke: var(--primary-color);
|
|
@@ -88,6 +97,10 @@
|
|
|
88
97
|
stroke: var(--component-color);
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
.highlight-frame-overlay.is-text-edit .highlight-frame-handle {
|
|
101
|
+
stroke: var(--text-edit-color);
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
.highlight-frame-handle.handle-top-left {
|
|
92
105
|
cursor: nwse-resize;
|
|
93
106
|
}
|
|
@@ -105,7 +118,9 @@
|
|
|
105
118
|
}
|
|
106
119
|
|
|
107
120
|
.highlight-frame-tools-wrapper {
|
|
108
|
-
position:
|
|
121
|
+
position: absolute;
|
|
122
|
+
left: 0;
|
|
123
|
+
top: 0;
|
|
109
124
|
pointer-events: none;
|
|
110
125
|
z-index: var(--z-index-highlight);
|
|
111
126
|
contain: layout style;
|
|
@@ -116,14 +131,14 @@
|
|
|
116
131
|
color: var(--text-color-white);
|
|
117
132
|
font-size: 0.575rem;
|
|
118
133
|
font-weight: 500;
|
|
119
|
-
text-transform: uppercase;
|
|
120
134
|
height: 1rem;
|
|
121
135
|
padding: 0.5625rem var(--spacing-sm);
|
|
122
|
-
line-height: 1;
|
|
136
|
+
line-height: 1.4;
|
|
123
137
|
border-radius: var(--spacing-sm);
|
|
124
138
|
display: flex;
|
|
125
139
|
align-items: center;
|
|
126
140
|
justify-content: center;
|
|
141
|
+
white-space: nowrap;
|
|
127
142
|
}
|
|
128
143
|
|
|
129
144
|
.highlight-frame-tools-wrapper.is-instance .tag-label,
|
|
@@ -131,6 +146,11 @@
|
|
|
131
146
|
background-color: var(--component-color);
|
|
132
147
|
}
|
|
133
148
|
|
|
149
|
+
.highlight-frame-tools-wrapper.is-text-edit .tag-label,
|
|
150
|
+
.node-tools.is-text-edit .tag-label {
|
|
151
|
+
background-color: var(--text-edit-color);
|
|
152
|
+
}
|
|
153
|
+
|
|
134
154
|
.viewport {
|
|
135
155
|
position: relative;
|
|
136
156
|
width: var(--container-width);
|
|
@@ -228,14 +248,14 @@
|
|
|
228
248
|
user-select: text;
|
|
229
249
|
|
|
230
250
|
&::selection {
|
|
231
|
-
background: var(--
|
|
251
|
+
background: var(--text-edit-selection-color);
|
|
232
252
|
}
|
|
233
253
|
|
|
234
254
|
&::-moz-selection {
|
|
235
|
-
background: var(--
|
|
255
|
+
background: var(--text-edit-selection-color);
|
|
236
256
|
}
|
|
237
257
|
|
|
238
258
|
&::-webkit-selection {
|
|
239
|
-
background: var(--
|
|
259
|
+
background: var(--text-edit-selection-color);
|
|
240
260
|
}
|
|
241
261
|
}
|