@node-edit-utils/core 1.2.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/README.md +268 -0
- package/dist/index.d.ts +6 -0
- package/dist/lib/canvas/createCanvasObserver.d.ts +2 -0
- package/dist/lib/canvas/disableCanvasKeyboard.d.ts +1 -0
- package/dist/lib/canvas/enableCanvasKeyboard.d.ts +1 -0
- package/dist/lib/canvas/helpers/applyCanvasState.d.ts +1 -0
- package/dist/lib/canvas/helpers/getCanvasContainer.d.ts +1 -0
- package/dist/lib/canvas/helpers/getCanvasWindowValue.d.ts +1 -0
- package/dist/lib/helpers/index.d.ts +1 -0
- package/dist/lib/helpers/observer/connectMutationObserver.d.ts +1 -0
- package/dist/lib/helpers/observer/connectResizeObserver.d.ts +1 -0
- package/dist/lib/helpers/withRAF.d.ts +4 -0
- package/dist/lib/node-tools/createNodeTools.d.ts +2 -0
- package/dist/lib/node-tools/events/click/handleNodeClick.d.ts +1 -0
- package/dist/lib/node-tools/events/setupEventListener.d.ts +1 -0
- package/dist/lib/node-tools/highlight/clearHighlightFrame.d.ts +1 -0
- package/dist/lib/node-tools/highlight/createHighlightFrame.d.ts +1 -0
- package/dist/lib/node-tools/highlight/createTagLabel.d.ts +1 -0
- package/dist/lib/node-tools/highlight/createToolsContainer.d.ts +1 -0
- package/dist/lib/node-tools/highlight/helpers/getElementBounds.d.ts +6 -0
- package/dist/lib/node-tools/highlight/helpers/getHighlightFrameElement.d.ts +1 -0
- package/dist/lib/node-tools/highlight/highlightNode.d.ts +1 -0
- package/dist/lib/node-tools/highlight/refreshHighlightFrame.d.ts +1 -0
- package/dist/lib/node-tools/select/constants.d.ts +1 -0
- package/dist/lib/node-tools/select/helpers/getElementsFromPoint.d.ts +1 -0
- package/dist/lib/node-tools/select/helpers/targetSameCandidates.d.ts +1 -0
- package/dist/lib/node-tools/select/selectNode.d.ts +1 -0
- package/dist/lib/node-tools/text/events/setupKeydownHandler.d.ts +1 -0
- package/dist/lib/node-tools/text/events/setupMutationObserver.d.ts +1 -0
- package/dist/lib/node-tools/text/events/setupNodeListeners.d.ts +1 -0
- package/dist/lib/node-tools/text/helpers/hasTextContent.d.ts +1 -0
- package/dist/lib/node-tools/text/helpers/insertLineBreak.d.ts +1 -0
- package/dist/lib/node-tools/text/helpers/makeNodeEditable.d.ts +1 -0
- package/dist/lib/node-tools/text/helpers/makeNodeNonEditable.d.ts +1 -0
- package/dist/lib/node-tools/text/nodeText.d.ts +2 -0
- package/dist/lib/post-message/handlePostMessage.d.ts +1 -0
- package/dist/lib/post-message/sendPostMessage.d.ts +1 -0
- package/dist/lib/viewport/constants.d.ts +5 -0
- package/dist/lib/viewport/createViewport.d.ts +2 -0
- package/dist/lib/viewport/events/setupEventListener.d.ts +1 -0
- package/dist/lib/viewport/resize/createResizeHandle.d.ts +1 -0
- package/dist/lib/viewport/width/calcConstrainedWidth.d.ts +1 -0
- package/dist/lib/viewport/width/calcWidth.d.ts +1 -0
- package/dist/lib/viewport/width/updateWidth.d.ts +1 -0
- package/dist/lib/window/bindToWindow.d.ts +1 -0
- package/dist/node-edit-utils.cjs.js +588 -0
- package/dist/node-edit-utils.esm.js +584 -0
- package/dist/node-edit-utils.umd.js +594 -0
- package/dist/node-edit-utils.umd.min.js +1 -0
- package/dist/styles.css +1 -0
- package/dist/umd.d.ts +1 -0
- package/package.json +65 -0
- package/src/index.ts +9 -0
- package/src/lib/canvas/createCanvasObserver.ts +37 -0
- package/src/lib/canvas/disableCanvasKeyboard.ts +7 -0
- package/src/lib/canvas/enableCanvasKeyboard.ts +7 -0
- package/src/lib/canvas/helpers/applyCanvasState.ts +11 -0
- package/src/lib/canvas/helpers/getCanvasContainer.ts +3 -0
- package/src/lib/canvas/helpers/getCanvasWindowValue.ts +5 -0
- package/src/lib/canvas/types.d.ts +3 -0
- package/src/lib/helpers/index.ts +1 -0
- package/src/lib/helpers/observer/connectMutationObserver.ts +12 -0
- package/src/lib/helpers/observer/connectResizeObserver.ts +8 -0
- package/src/lib/helpers/withRAF.ts +39 -0
- package/src/lib/node-tools/createNodeTools.ts +88 -0
- package/src/lib/node-tools/events/click/handleNodeClick.ts +21 -0
- package/src/lib/node-tools/events/setupEventListener.ts +35 -0
- package/src/lib/node-tools/highlight/clearHighlightFrame.ts +12 -0
- package/src/lib/node-tools/highlight/createHighlightFrame.ts +37 -0
- package/src/lib/node-tools/highlight/createTagLabel.ts +7 -0
- package/src/lib/node-tools/highlight/createToolsContainer.ts +10 -0
- package/src/lib/node-tools/highlight/helpers/getElementBounds.ts +31 -0
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +5 -0
- package/src/lib/node-tools/highlight/highlightNode.ts +23 -0
- package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +23 -0
- package/src/lib/node-tools/select/constants.ts +1 -0
- package/src/lib/node-tools/select/helpers/getElementsFromPoint.ts +16 -0
- package/src/lib/node-tools/select/helpers/targetSameCandidates.ts +2 -0
- package/src/lib/node-tools/select/selectNode.ts +44 -0
- package/src/lib/node-tools/text/events/setupKeydownHandler.ts +18 -0
- package/src/lib/node-tools/text/events/setupMutationObserver.ts +10 -0
- package/src/lib/node-tools/text/events/setupNodeListeners.ts +20 -0
- package/src/lib/node-tools/text/helpers/hasTextContent.ts +3 -0
- package/src/lib/node-tools/text/helpers/insertLineBreak.ts +17 -0
- package/src/lib/node-tools/text/helpers/makeNodeEditable.ts +5 -0
- package/src/lib/node-tools/text/helpers/makeNodeNonEditable.ts +5 -0
- package/src/lib/node-tools/text/nodeText.ts +67 -0
- package/src/lib/node-tools/text/types.d.ts +6 -0
- package/src/lib/node-tools/types.d.ts +12 -0
- package/src/lib/post-message/handlePostMessage.ts +8 -0
- package/src/lib/post-message/sendPostMessage.ts +11 -0
- package/src/lib/styles/styles.css +133 -0
- package/src/lib/viewport/constants.ts +6 -0
- package/src/lib/viewport/createViewport.ts +70 -0
- package/src/lib/viewport/events/setupEventListener.ts +20 -0
- package/src/lib/viewport/resize/createResizeHandle.ts +9 -0
- package/src/lib/viewport/types.d.ts +8 -0
- package/src/lib/viewport/width/calcConstrainedWidth.ts +6 -0
- package/src/lib/viewport/width/calcWidth.ts +9 -0
- package/src/lib/viewport/width/updateWidth.ts +3 -0
- package/src/lib/window/bindToWindow.ts +6 -0
- package/src/umd.ts +1 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { disableCanvasKeyboard } from "../../canvas/disableCanvasKeyboard";
|
|
2
|
+
import { enableCanvasKeyboard } from "../../canvas/enableCanvasKeyboard";
|
|
3
|
+
import { setupNodeListeners } from "./events/setupNodeListeners";
|
|
4
|
+
import { hasTextContent } from "./helpers/hasTextContent";
|
|
5
|
+
import { makeNodeEditable } from "./helpers/makeNodeEditable";
|
|
6
|
+
import { makeNodeNonEditable } from "./helpers/makeNodeNonEditable";
|
|
7
|
+
import type { NodeText } from "./types";
|
|
8
|
+
|
|
9
|
+
export const nodeText = (): NodeText => {
|
|
10
|
+
let editableNode: HTMLElement | null = null;
|
|
11
|
+
let blurInProgress: boolean = false;
|
|
12
|
+
let cleanup: (() => void) | null = null;
|
|
13
|
+
|
|
14
|
+
const enableEditMode = (node: HTMLElement, nodeProvider: HTMLElement | null) => {
|
|
15
|
+
if (editableNode === node) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (editableNode && editableNode !== node) {
|
|
20
|
+
blurEditMode();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const editable = hasTextContent(node);
|
|
24
|
+
|
|
25
|
+
if (editable) {
|
|
26
|
+
editableNode = node;
|
|
27
|
+
|
|
28
|
+
makeNodeEditable(node);
|
|
29
|
+
disableCanvasKeyboard();
|
|
30
|
+
|
|
31
|
+
cleanup = setupNodeListeners(node, nodeProvider, blurEditMode);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const getEditableNode = () => {
|
|
36
|
+
return editableNode;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const isEditing = () => {
|
|
40
|
+
return editableNode !== null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const blurEditMode = () => {
|
|
44
|
+
if (blurInProgress || !editableNode) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
blurInProgress = true;
|
|
49
|
+
|
|
50
|
+
const nodeToCleanup = editableNode;
|
|
51
|
+
|
|
52
|
+
makeNodeNonEditable(nodeToCleanup);
|
|
53
|
+
enableCanvasKeyboard();
|
|
54
|
+
|
|
55
|
+
cleanup?.();
|
|
56
|
+
|
|
57
|
+
editableNode = null;
|
|
58
|
+
blurInProgress = false;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
enableEditMode,
|
|
63
|
+
blurEditMode,
|
|
64
|
+
getEditableNode,
|
|
65
|
+
isEditing,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface NodeTools {
|
|
2
|
+
selectNode(node: HTMLElement | null): void;
|
|
3
|
+
getSelectedNode(): HTMLElement | null;
|
|
4
|
+
getEditableNode(): HTMLElement | null;
|
|
5
|
+
refreshHighlightFrame(): void;
|
|
6
|
+
clearSelectedNode(): void;
|
|
7
|
+
cleanup(): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NodeToolsRef extends HTMLDivElement {
|
|
11
|
+
nodeTools?: NodeTools;
|
|
12
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
.node-provider {
|
|
2
|
+
::selection {
|
|
3
|
+
background: transparent;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
::-moz-selection {
|
|
7
|
+
background: transparent;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
::-webkit-selection {
|
|
11
|
+
background: transparent;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.node-tools {
|
|
16
|
+
position: absolute;
|
|
17
|
+
left: 0;
|
|
18
|
+
bottom: 0;
|
|
19
|
+
gap: 0.25rem;
|
|
20
|
+
z-index: 10000;
|
|
21
|
+
transform: scale(calc(1 / var(--zoom))) translate3d(0, 100%, 0);
|
|
22
|
+
transform-origin: bottom left;
|
|
23
|
+
transition:
|
|
24
|
+
transform 0.025s ease,
|
|
25
|
+
opacity 0.1s ease;
|
|
26
|
+
opacity: var(--tool-opacity);
|
|
27
|
+
padding-top: 0.25rem;
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.highlight-frame {
|
|
33
|
+
position: absolute;
|
|
34
|
+
top: var(--frame-top);
|
|
35
|
+
left: var(--frame-left);
|
|
36
|
+
width: var(--frame-width);
|
|
37
|
+
height: var(--frame-height);
|
|
38
|
+
z-index: 1000;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
/* outline: calc(0.125em / var(--zoom)) solid oklch(62.7% 0.265 303.9); */
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.highlight-frame-svg {
|
|
44
|
+
position: absolute;
|
|
45
|
+
top: 0;
|
|
46
|
+
left: 0;
|
|
47
|
+
width: 100%;
|
|
48
|
+
height: 100%;
|
|
49
|
+
overflow: visible;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.highlight-frame-rect {
|
|
53
|
+
fill: none;
|
|
54
|
+
stroke: oklch(62.7% 0.265 303.9);
|
|
55
|
+
stroke-width: var(--stroke-width);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tag-label {
|
|
59
|
+
background-color: oklch(62.7% 0.265 303.9);
|
|
60
|
+
color: white;
|
|
61
|
+
font-size: 0.575rem;
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
text-transform: uppercase;
|
|
64
|
+
height: 1.25rem;
|
|
65
|
+
padding: 0 0.375rem;
|
|
66
|
+
line-height: 1;
|
|
67
|
+
border-radius: 0.375rem;
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.viewport {
|
|
74
|
+
position: relative;
|
|
75
|
+
width: var(--container-width);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.resize-handle {
|
|
79
|
+
position: absolute;
|
|
80
|
+
top: 1.25rem;
|
|
81
|
+
right: -12px;
|
|
82
|
+
width: 12px;
|
|
83
|
+
height: 40px;
|
|
84
|
+
cursor: ew-resize;
|
|
85
|
+
z-index: 10000;
|
|
86
|
+
display: flex;
|
|
87
|
+
opacity: 0;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
pointer-events: auto;
|
|
91
|
+
transform: scale(calc(1 / var(--zoom)));
|
|
92
|
+
transform-origin: top left;
|
|
93
|
+
transition:
|
|
94
|
+
transform 0.025s ease,
|
|
95
|
+
opacity 0.2s ease-in-out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.viewport:hover .resize-handle {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.resize-handle::before {
|
|
103
|
+
content: "";
|
|
104
|
+
position: relative;
|
|
105
|
+
top: 0;
|
|
106
|
+
right: 0;
|
|
107
|
+
width: 3px;
|
|
108
|
+
height: 32px;
|
|
109
|
+
background: oklch(55.2% 0.016 285.938);
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
transition: transform 0.2s ease-in-out;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.resize-handle:hover::before {
|
|
115
|
+
transform: scaleY(1.3);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.is-editable {
|
|
119
|
+
outline: none;
|
|
120
|
+
user-select: text;
|
|
121
|
+
|
|
122
|
+
&::selection {
|
|
123
|
+
background: oklch(62.7% 0.265 303.9 / 0.3);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&::-moz-selection {
|
|
127
|
+
background: oklch(62.7% 0.265 303.9 / 0.3);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&::-webkit-selection {
|
|
131
|
+
background: oklch(62.7% 0.265 303.9 / 0.3);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getCanvasContainer } from "../canvas/helpers/getCanvasContainer";
|
|
2
|
+
import { withRAFThrottle } from "../helpers";
|
|
3
|
+
import { DEFAULT_WIDTH } from "./constants";
|
|
4
|
+
import { setupEventListener } from "./events/setupEventListener";
|
|
5
|
+
import { createResizeHandle } from "./resize/createResizeHandle";
|
|
6
|
+
import type { Viewport } from "./types";
|
|
7
|
+
import { calcWidth } from "./width/calcWidth";
|
|
8
|
+
import { updateWidth } from "./width/updateWidth";
|
|
9
|
+
|
|
10
|
+
export const createViewport = (container: HTMLElement): Viewport => {
|
|
11
|
+
const canvas: HTMLElement | null = getCanvasContainer();
|
|
12
|
+
const resizeHandle = createResizeHandle(container);
|
|
13
|
+
container.style.setProperty("--container-width", `${DEFAULT_WIDTH}px`);
|
|
14
|
+
|
|
15
|
+
let isDragging: boolean = false;
|
|
16
|
+
let startX: number = 0;
|
|
17
|
+
let startWidth: number = 0;
|
|
18
|
+
|
|
19
|
+
const startResize = (event: MouseEvent): void => {
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
event.stopPropagation();
|
|
22
|
+
|
|
23
|
+
isDragging = true;
|
|
24
|
+
startX = event.clientX;
|
|
25
|
+
startWidth = container.offsetWidth;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleResize = (event: MouseEvent): void => {
|
|
29
|
+
if (!isDragging) return;
|
|
30
|
+
|
|
31
|
+
if (canvas) {
|
|
32
|
+
canvas.style.cursor = "ew-resize";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const width = calcWidth(event, startX, startWidth);
|
|
36
|
+
updateWidth(container, width);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const throttledHandleResize = withRAFThrottle(handleResize);
|
|
40
|
+
|
|
41
|
+
const stopResize = (event: MouseEvent): void => {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
event.stopPropagation();
|
|
44
|
+
|
|
45
|
+
if (canvas) {
|
|
46
|
+
canvas.style.cursor = "default";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
isDragging = false;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const blurResize = (): void => {
|
|
53
|
+
isDragging = false;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const removeListeners = setupEventListener(resizeHandle, startResize, throttledHandleResize, stopResize, blurResize);
|
|
57
|
+
|
|
58
|
+
const cleanup = (): void => {
|
|
59
|
+
isDragging = false;
|
|
60
|
+
throttledHandleResize?.cleanup();
|
|
61
|
+
removeListeners();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
setWidth: (width: number): void => {
|
|
66
|
+
updateWidth(container, width);
|
|
67
|
+
},
|
|
68
|
+
cleanup,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const setupEventListener = (
|
|
2
|
+
resizeHandle: HTMLElement,
|
|
3
|
+
startResize: (event: MouseEvent) => void,
|
|
4
|
+
handleResize: (event: MouseEvent) => void,
|
|
5
|
+
stopResize: (event: MouseEvent) => void,
|
|
6
|
+
blurResize: () => void
|
|
7
|
+
): (() => void) => {
|
|
8
|
+
resizeHandle.addEventListener("mousedown", startResize);
|
|
9
|
+
document.addEventListener("mousemove", handleResize);
|
|
10
|
+
document.addEventListener("mouseup", stopResize);
|
|
11
|
+
|
|
12
|
+
window.addEventListener("blur", blurResize);
|
|
13
|
+
|
|
14
|
+
return () => {
|
|
15
|
+
resizeHandle.removeEventListener("mousedown", startResize);
|
|
16
|
+
document.removeEventListener("mousemove", handleResize);
|
|
17
|
+
document.removeEventListener("mouseup", stopResize);
|
|
18
|
+
window.removeEventListener("blur", blurResize);
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { RESIZE_CONFIG } from "../constants";
|
|
2
|
+
|
|
3
|
+
export const calcConstrainedWidth = (startWidth: number, deltaX: number): number => {
|
|
4
|
+
const newWidth = startWidth + Math.round(deltaX);
|
|
5
|
+
return Math.max(RESIZE_CONFIG.minWidth, Math.min(RESIZE_CONFIG.maxWidth, newWidth));
|
|
6
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { calcConstrainedWidth } from "./calcConstrainedWidth";
|
|
2
|
+
|
|
3
|
+
export const calcWidth = (event: MouseEvent, startX: number, startWidth: number): number => {
|
|
4
|
+
const zoom = parseFloat(document.body.dataset.zoom || "1");
|
|
5
|
+
const deltaX = (event.clientX - startX) / zoom;
|
|
6
|
+
const width = calcConstrainedWidth(startWidth, deltaX);
|
|
7
|
+
|
|
8
|
+
return width;
|
|
9
|
+
};
|
package/src/umd.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index";
|