@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.
Files changed (102) hide show
  1. package/README.md +268 -0
  2. package/dist/index.d.ts +6 -0
  3. package/dist/lib/canvas/createCanvasObserver.d.ts +2 -0
  4. package/dist/lib/canvas/disableCanvasKeyboard.d.ts +1 -0
  5. package/dist/lib/canvas/enableCanvasKeyboard.d.ts +1 -0
  6. package/dist/lib/canvas/helpers/applyCanvasState.d.ts +1 -0
  7. package/dist/lib/canvas/helpers/getCanvasContainer.d.ts +1 -0
  8. package/dist/lib/canvas/helpers/getCanvasWindowValue.d.ts +1 -0
  9. package/dist/lib/helpers/index.d.ts +1 -0
  10. package/dist/lib/helpers/observer/connectMutationObserver.d.ts +1 -0
  11. package/dist/lib/helpers/observer/connectResizeObserver.d.ts +1 -0
  12. package/dist/lib/helpers/withRAF.d.ts +4 -0
  13. package/dist/lib/node-tools/createNodeTools.d.ts +2 -0
  14. package/dist/lib/node-tools/events/click/handleNodeClick.d.ts +1 -0
  15. package/dist/lib/node-tools/events/setupEventListener.d.ts +1 -0
  16. package/dist/lib/node-tools/highlight/clearHighlightFrame.d.ts +1 -0
  17. package/dist/lib/node-tools/highlight/createHighlightFrame.d.ts +1 -0
  18. package/dist/lib/node-tools/highlight/createTagLabel.d.ts +1 -0
  19. package/dist/lib/node-tools/highlight/createToolsContainer.d.ts +1 -0
  20. package/dist/lib/node-tools/highlight/helpers/getElementBounds.d.ts +6 -0
  21. package/dist/lib/node-tools/highlight/helpers/getHighlightFrameElement.d.ts +1 -0
  22. package/dist/lib/node-tools/highlight/highlightNode.d.ts +1 -0
  23. package/dist/lib/node-tools/highlight/refreshHighlightFrame.d.ts +1 -0
  24. package/dist/lib/node-tools/select/constants.d.ts +1 -0
  25. package/dist/lib/node-tools/select/helpers/getElementsFromPoint.d.ts +1 -0
  26. package/dist/lib/node-tools/select/helpers/targetSameCandidates.d.ts +1 -0
  27. package/dist/lib/node-tools/select/selectNode.d.ts +1 -0
  28. package/dist/lib/node-tools/text/events/setupKeydownHandler.d.ts +1 -0
  29. package/dist/lib/node-tools/text/events/setupMutationObserver.d.ts +1 -0
  30. package/dist/lib/node-tools/text/events/setupNodeListeners.d.ts +1 -0
  31. package/dist/lib/node-tools/text/helpers/hasTextContent.d.ts +1 -0
  32. package/dist/lib/node-tools/text/helpers/insertLineBreak.d.ts +1 -0
  33. package/dist/lib/node-tools/text/helpers/makeNodeEditable.d.ts +1 -0
  34. package/dist/lib/node-tools/text/helpers/makeNodeNonEditable.d.ts +1 -0
  35. package/dist/lib/node-tools/text/nodeText.d.ts +2 -0
  36. package/dist/lib/post-message/handlePostMessage.d.ts +1 -0
  37. package/dist/lib/post-message/sendPostMessage.d.ts +1 -0
  38. package/dist/lib/viewport/constants.d.ts +5 -0
  39. package/dist/lib/viewport/createViewport.d.ts +2 -0
  40. package/dist/lib/viewport/events/setupEventListener.d.ts +1 -0
  41. package/dist/lib/viewport/resize/createResizeHandle.d.ts +1 -0
  42. package/dist/lib/viewport/width/calcConstrainedWidth.d.ts +1 -0
  43. package/dist/lib/viewport/width/calcWidth.d.ts +1 -0
  44. package/dist/lib/viewport/width/updateWidth.d.ts +1 -0
  45. package/dist/lib/window/bindToWindow.d.ts +1 -0
  46. package/dist/node-edit-utils.cjs.js +588 -0
  47. package/dist/node-edit-utils.esm.js +584 -0
  48. package/dist/node-edit-utils.umd.js +594 -0
  49. package/dist/node-edit-utils.umd.min.js +1 -0
  50. package/dist/styles.css +1 -0
  51. package/dist/umd.d.ts +1 -0
  52. package/package.json +65 -0
  53. package/src/index.ts +9 -0
  54. package/src/lib/canvas/createCanvasObserver.ts +37 -0
  55. package/src/lib/canvas/disableCanvasKeyboard.ts +7 -0
  56. package/src/lib/canvas/enableCanvasKeyboard.ts +7 -0
  57. package/src/lib/canvas/helpers/applyCanvasState.ts +11 -0
  58. package/src/lib/canvas/helpers/getCanvasContainer.ts +3 -0
  59. package/src/lib/canvas/helpers/getCanvasWindowValue.ts +5 -0
  60. package/src/lib/canvas/types.d.ts +3 -0
  61. package/src/lib/helpers/index.ts +1 -0
  62. package/src/lib/helpers/observer/connectMutationObserver.ts +12 -0
  63. package/src/lib/helpers/observer/connectResizeObserver.ts +8 -0
  64. package/src/lib/helpers/withRAF.ts +39 -0
  65. package/src/lib/node-tools/createNodeTools.ts +88 -0
  66. package/src/lib/node-tools/events/click/handleNodeClick.ts +21 -0
  67. package/src/lib/node-tools/events/setupEventListener.ts +35 -0
  68. package/src/lib/node-tools/highlight/clearHighlightFrame.ts +12 -0
  69. package/src/lib/node-tools/highlight/createHighlightFrame.ts +37 -0
  70. package/src/lib/node-tools/highlight/createTagLabel.ts +7 -0
  71. package/src/lib/node-tools/highlight/createToolsContainer.ts +10 -0
  72. package/src/lib/node-tools/highlight/helpers/getElementBounds.ts +31 -0
  73. package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +5 -0
  74. package/src/lib/node-tools/highlight/highlightNode.ts +23 -0
  75. package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +23 -0
  76. package/src/lib/node-tools/select/constants.ts +1 -0
  77. package/src/lib/node-tools/select/helpers/getElementsFromPoint.ts +16 -0
  78. package/src/lib/node-tools/select/helpers/targetSameCandidates.ts +2 -0
  79. package/src/lib/node-tools/select/selectNode.ts +44 -0
  80. package/src/lib/node-tools/text/events/setupKeydownHandler.ts +18 -0
  81. package/src/lib/node-tools/text/events/setupMutationObserver.ts +10 -0
  82. package/src/lib/node-tools/text/events/setupNodeListeners.ts +20 -0
  83. package/src/lib/node-tools/text/helpers/hasTextContent.ts +3 -0
  84. package/src/lib/node-tools/text/helpers/insertLineBreak.ts +17 -0
  85. package/src/lib/node-tools/text/helpers/makeNodeEditable.ts +5 -0
  86. package/src/lib/node-tools/text/helpers/makeNodeNonEditable.ts +5 -0
  87. package/src/lib/node-tools/text/nodeText.ts +67 -0
  88. package/src/lib/node-tools/text/types.d.ts +6 -0
  89. package/src/lib/node-tools/types.d.ts +12 -0
  90. package/src/lib/post-message/handlePostMessage.ts +8 -0
  91. package/src/lib/post-message/sendPostMessage.ts +11 -0
  92. package/src/lib/styles/styles.css +133 -0
  93. package/src/lib/viewport/constants.ts +6 -0
  94. package/src/lib/viewport/createViewport.ts +70 -0
  95. package/src/lib/viewport/events/setupEventListener.ts +20 -0
  96. package/src/lib/viewport/resize/createResizeHandle.ts +9 -0
  97. package/src/lib/viewport/types.d.ts +8 -0
  98. package/src/lib/viewport/width/calcConstrainedWidth.ts +6 -0
  99. package/src/lib/viewport/width/calcWidth.ts +9 -0
  100. package/src/lib/viewport/width/updateWidth.ts +3 -0
  101. package/src/lib/window/bindToWindow.ts +6 -0
  102. 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,6 @@
1
+ export interface NodeText {
2
+ enableEditMode: (node: HTMLElement, nodeProvider: HTMLElement | null) => void;
3
+ blurEditMode: () => void;
4
+ getEditableNode: () => HTMLElement | null;
5
+ isEditing: () => boolean;
6
+ }
@@ -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,8 @@
1
+ export const handlePostMessage = (event: MessageEvent) => {
2
+ if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
3
+ if (event.data.action === "zoom") {
4
+ const zoom = event.data.data;
5
+ console.log("zoom", zoom);
6
+ }
7
+ }
8
+ };
@@ -0,0 +1,11 @@
1
+ export function sendPostMessage(action: string, data: unknown): void {
2
+ window.parent.postMessage(
3
+ {
4
+ source: "node-edit-utils",
5
+ action,
6
+ data,
7
+ timestamp: Date.now(),
8
+ },
9
+ "*"
10
+ );
11
+ }
@@ -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,6 @@
1
+ export const DEFAULT_WIDTH = 400;
2
+
3
+ export const RESIZE_CONFIG = {
4
+ minWidth: 320,
5
+ maxWidth: 1680,
6
+ } as const;
@@ -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,9 @@
1
+ export const createResizeHandle = (container: HTMLElement): HTMLElement => {
2
+ const handle = document.createElement("div");
3
+
4
+ handle.className = "component-resize-handle resize-handle";
5
+
6
+ container.appendChild(handle);
7
+
8
+ return handle;
9
+ };
@@ -0,0 +1,8 @@
1
+ export interface Viewport {
2
+ setWidth: (width: number) => void;
3
+ cleanup: () => void;
4
+ }
5
+
6
+ export interface ViewportRef extends HTMLDivElement {
7
+ viewport?: Viewport;
8
+ }
@@ -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
+ };
@@ -0,0 +1,3 @@
1
+ export const updateWidth = (container: HTMLElement, width: number): void => {
2
+ container.style.setProperty("--container-width", `${width}px`);
3
+ };
@@ -0,0 +1,6 @@
1
+ export const bindToWindow = <T>(key: string, value: T): void => {
2
+ if (typeof window !== "undefined") {
3
+ // biome-ignore lint/suspicious/noExplicitAny: global window extension requires flexibility
4
+ (window as any)[key] = value;
5
+ }
6
+ };
package/src/umd.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./index";