@node-edit-utils/core 2.0.7 → 2.0.9

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.
@@ -0,0 +1 @@
1
+ export declare const isLocked: (node: HTMLElement | null) => boolean;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Markup Canvas
3
3
  * High-performance markup canvas with zoom and pan capabilities
4
- * @version 2.0.7
4
+ * @version 2.0.9
5
5
  */
6
6
  'use strict';
7
7
 
@@ -97,16 +97,24 @@ const bindToWindow = (key, value) => {
97
97
  }
98
98
  };
99
99
 
100
+ const isLocked = (node) => {
101
+ return node?.classList.contains("select-none") ?? false;
102
+ };
103
+
100
104
  const processPostMessage = (event, onNodeSelected) => {
101
- if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
102
- if (event.data.action === "zoom") {
103
- event.data.data;
104
- }
105
- }
105
+ // if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
106
+ // if (event.data.action === "zoom") {
107
+ // // Zoom handling can be implemented here if needed
108
+ // }
109
+ // }
106
110
  if (event.data.source === "application") {
107
111
  if (event.data.action === "selectedNodeChanged") {
108
112
  const nodeId = event.data.data;
109
113
  const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`);
114
+ if (isLocked(selectedNode)) {
115
+ onNodeSelected?.(null);
116
+ return;
117
+ }
110
118
  if (selectedNode) {
111
119
  onNodeSelected?.(selectedNode);
112
120
  }
@@ -153,13 +161,19 @@ const selectNode = (event, editableNode) => {
153
161
  const clickX = event.clientX;
154
162
  const clickY = event.clientY;
155
163
  const clickThrough = event.metaKey || event.ctrlKey;
156
- const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()) && !element.classList.contains("select-none"));
164
+ const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()));
157
165
  if (editableNode && candidates.includes(editableNode)) {
166
+ if (isLocked(editableNode)) {
167
+ return null;
168
+ }
158
169
  return editableNode;
159
170
  }
160
171
  if (clickThrough) {
161
172
  candidateCache = [];
162
173
  selectedNode = candidates[0];
174
+ if (isLocked(selectedNode)) {
175
+ return null;
176
+ }
163
177
  return selectedNode;
164
178
  }
165
179
  if (targetSameCandidates(candidateCache, candidates)) {
@@ -171,6 +185,9 @@ const selectNode = (event, editableNode) => {
171
185
  const nodeIndex = candidates.length - 1 - attempt;
172
186
  selectedNode = candidates[nodeIndex];
173
187
  candidateCache = candidates;
188
+ if (isLocked(selectedNode)) {
189
+ return null;
190
+ }
174
191
  return selectedNode;
175
192
  };
176
193
 
@@ -196,6 +213,8 @@ const setupEventListener$1 = (nodeProvider, onNodeSelected, onEscapePressed, get
196
213
  const documentKeydownHandler = (event) => {
197
214
  console.log("Esacpe Handler", event);
198
215
  if (event.key === "Escape") {
216
+ event.preventDefault();
217
+ event.stopPropagation();
199
218
  onEscapePressed?.();
200
219
  }
201
220
  };
@@ -465,6 +484,7 @@ const createNodeTools = (element) => {
465
484
  if (selectedNode === node) {
466
485
  return;
467
486
  }
487
+ selectedNode = node;
468
488
  if (text.isEditing()) {
469
489
  const currentEditable = text.getEditableNode();
470
490
  if (currentEditable && currentEditable !== node) {
@@ -487,7 +507,6 @@ const createNodeTools = (element) => {
487
507
  attributeFilter: ["class"],
488
508
  });
489
509
  }
490
- selectedNode = node;
491
510
  sendPostMessage("selectedNodeChanged", node?.getAttribute("data-node-id") ?? null);
492
511
  highlightNode(node, nodeProvider) ?? null;
493
512
  if (node && nodeProvider) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Markup Canvas
3
3
  * High-performance markup canvas with zoom and pan capabilities
4
- * @version 2.0.7
4
+ * @version 2.0.9
5
5
  */
6
6
  // biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
7
7
  function withRAFThrottle(func) {
@@ -95,16 +95,24 @@ const bindToWindow = (key, value) => {
95
95
  }
96
96
  };
97
97
 
98
+ const isLocked = (node) => {
99
+ return node?.classList.contains("select-none") ?? false;
100
+ };
101
+
98
102
  const processPostMessage = (event, onNodeSelected) => {
99
- if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
100
- if (event.data.action === "zoom") {
101
- event.data.data;
102
- }
103
- }
103
+ // if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
104
+ // if (event.data.action === "zoom") {
105
+ // // Zoom handling can be implemented here if needed
106
+ // }
107
+ // }
104
108
  if (event.data.source === "application") {
105
109
  if (event.data.action === "selectedNodeChanged") {
106
110
  const nodeId = event.data.data;
107
111
  const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`);
112
+ if (isLocked(selectedNode)) {
113
+ onNodeSelected?.(null);
114
+ return;
115
+ }
108
116
  if (selectedNode) {
109
117
  onNodeSelected?.(selectedNode);
110
118
  }
@@ -151,13 +159,19 @@ const selectNode = (event, editableNode) => {
151
159
  const clickX = event.clientX;
152
160
  const clickY = event.clientY;
153
161
  const clickThrough = event.metaKey || event.ctrlKey;
154
- const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()) && !element.classList.contains("select-none"));
162
+ const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()));
155
163
  if (editableNode && candidates.includes(editableNode)) {
164
+ if (isLocked(editableNode)) {
165
+ return null;
166
+ }
156
167
  return editableNode;
157
168
  }
158
169
  if (clickThrough) {
159
170
  candidateCache = [];
160
171
  selectedNode = candidates[0];
172
+ if (isLocked(selectedNode)) {
173
+ return null;
174
+ }
161
175
  return selectedNode;
162
176
  }
163
177
  if (targetSameCandidates(candidateCache, candidates)) {
@@ -169,6 +183,9 @@ const selectNode = (event, editableNode) => {
169
183
  const nodeIndex = candidates.length - 1 - attempt;
170
184
  selectedNode = candidates[nodeIndex];
171
185
  candidateCache = candidates;
186
+ if (isLocked(selectedNode)) {
187
+ return null;
188
+ }
172
189
  return selectedNode;
173
190
  };
174
191
 
@@ -194,6 +211,8 @@ const setupEventListener$1 = (nodeProvider, onNodeSelected, onEscapePressed, get
194
211
  const documentKeydownHandler = (event) => {
195
212
  console.log("Esacpe Handler", event);
196
213
  if (event.key === "Escape") {
214
+ event.preventDefault();
215
+ event.stopPropagation();
197
216
  onEscapePressed?.();
198
217
  }
199
218
  };
@@ -463,6 +482,7 @@ const createNodeTools = (element) => {
463
482
  if (selectedNode === node) {
464
483
  return;
465
484
  }
485
+ selectedNode = node;
466
486
  if (text.isEditing()) {
467
487
  const currentEditable = text.getEditableNode();
468
488
  if (currentEditable && currentEditable !== node) {
@@ -485,7 +505,6 @@ const createNodeTools = (element) => {
485
505
  attributeFilter: ["class"],
486
506
  });
487
507
  }
488
- selectedNode = node;
489
508
  sendPostMessage("selectedNodeChanged", node?.getAttribute("data-node-id") ?? null);
490
509
  highlightNode(node, nodeProvider) ?? null;
491
510
  if (node && nodeProvider) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Markup Canvas
3
3
  * High-performance markup canvas with zoom and pan capabilities
4
- * @version 2.0.7
4
+ * @version 2.0.9
5
5
  */
6
6
  (function (global, factory) {
7
7
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
@@ -101,16 +101,24 @@
101
101
  }
102
102
  };
103
103
 
104
+ const isLocked = (node) => {
105
+ return node?.classList.contains("select-none") ?? false;
106
+ };
107
+
104
108
  const processPostMessage = (event, onNodeSelected) => {
105
- if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
106
- if (event.data.action === "zoom") {
107
- event.data.data;
108
- }
109
- }
109
+ // if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
110
+ // if (event.data.action === "zoom") {
111
+ // // Zoom handling can be implemented here if needed
112
+ // }
113
+ // }
110
114
  if (event.data.source === "application") {
111
115
  if (event.data.action === "selectedNodeChanged") {
112
116
  const nodeId = event.data.data;
113
117
  const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`);
118
+ if (isLocked(selectedNode)) {
119
+ onNodeSelected?.(null);
120
+ return;
121
+ }
114
122
  if (selectedNode) {
115
123
  onNodeSelected?.(selectedNode);
116
124
  }
@@ -157,13 +165,19 @@
157
165
  const clickX = event.clientX;
158
166
  const clickY = event.clientY;
159
167
  const clickThrough = event.metaKey || event.ctrlKey;
160
- const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()) && !element.classList.contains("select-none"));
168
+ const candidates = getElementsFromPoint(clickX, clickY).filter((element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()));
161
169
  if (editableNode && candidates.includes(editableNode)) {
170
+ if (isLocked(editableNode)) {
171
+ return null;
172
+ }
162
173
  return editableNode;
163
174
  }
164
175
  if (clickThrough) {
165
176
  candidateCache = [];
166
177
  selectedNode = candidates[0];
178
+ if (isLocked(selectedNode)) {
179
+ return null;
180
+ }
167
181
  return selectedNode;
168
182
  }
169
183
  if (targetSameCandidates(candidateCache, candidates)) {
@@ -175,6 +189,9 @@
175
189
  const nodeIndex = candidates.length - 1 - attempt;
176
190
  selectedNode = candidates[nodeIndex];
177
191
  candidateCache = candidates;
192
+ if (isLocked(selectedNode)) {
193
+ return null;
194
+ }
178
195
  return selectedNode;
179
196
  };
180
197
 
@@ -200,6 +217,8 @@
200
217
  const documentKeydownHandler = (event) => {
201
218
  console.log("Esacpe Handler", event);
202
219
  if (event.key === "Escape") {
220
+ event.preventDefault();
221
+ event.stopPropagation();
203
222
  onEscapePressed?.();
204
223
  }
205
224
  };
@@ -469,6 +488,7 @@
469
488
  if (selectedNode === node) {
470
489
  return;
471
490
  }
491
+ selectedNode = node;
472
492
  if (text.isEditing()) {
473
493
  const currentEditable = text.getEditableNode();
474
494
  if (currentEditable && currentEditable !== node) {
@@ -491,7 +511,6 @@
491
511
  attributeFilter: ["class"],
492
512
  });
493
513
  }
494
- selectedNode = node;
495
514
  sendPostMessage("selectedNodeChanged", node?.getAttribute("data-node-id") ?? null);
496
515
  highlightNode(node, nodeProvider) ?? null;
497
516
  if (node && nodeProvider) {
@@ -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";function t(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}const n=e=>{const t=window.canvas;return e.reduce((e,t)=>e?.[t],t)};function o(e){return e.querySelector(".highlight-frame")}const r=e=>{if(!e)return;const t=o(e);t&&t.remove()},s=["path","rect","circle","ellipse","polygon","line","polyline","text","text-noci"];let a=[],i=0;const d=(e,t)=>{let n=null;const o=e.clientX,r=e.clientY,d=e.metaKey||e.ctrlKey,l=((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})(o,r).filter(e=>!s.includes(e.tagName.toLowerCase())&&!e.classList.contains("select-none"));if(t&&l.includes(t))return t;if(d)return a=[],n=l[0],n;var c,u;u=l,(c=a).length===u.length&&c.every((e,t)=>e===u[t])?i<=l.length&&i++:i=0;return n=l[l.length-1-i],a=l,n},l=(e,t,n,o)=>{const s=e=>{((e,t)=>{if("markup-canvas"===e.data.source&&"canvas"===e.data.canvasName&&"zoom"===e.data.action&&e.data.data,"application"===e.data.source&&"selectedNodeChanged"===e.data.action){const n=e.data.data,o=document.querySelector(`[data-node-id="${n}"]`);o&&t?.(o)}})(e,t)},a=n=>{((e,t,n,o)=>{if(e.preventDefault(),e.stopPropagation(),t&&!t.contains(e.target))return r(t),void o(null);o(d(e,n))})(n,e,o(),t)},i=e=>{console.log("Esacpe Handler",e),"Escape"===e.key&&n?.()};return window.addEventListener("message",s),document.addEventListener("click",a),document.addEventListener("keydown",i),()=>{window.removeEventListener("message",s),document.removeEventListener("click",a),document.removeEventListener("keydown",i)}};function c(e,t){const o=e.getBoundingClientRect(),r=t.getBoundingClientRect(),s=o.top-r.top,a=o.left-r.left,i=n(["zoom","current"])??1;return{top:parseFloat((s/i).toFixed(5)),left:parseFloat((a/i).toFixed(5)),width:Math.max(4,parseFloat((o.width/i).toFixed(5))),height:parseFloat((o.height/i).toFixed(5))}}const u=(e,t)=>{const n=document.createElement("div");n.className="node-tools",t.appendChild(n),((e,t)=>{const n=document.createElement("div");n.className="tag-label",n.textContent=e.tagName.toLowerCase(),t.appendChild(n)})(e,n)},m=(e,t)=>{if(!e)return;const r=o(t);r&&r.remove();const s=((e,t)=>{const{top:o,left:r,width:s,height:a}=c(e,t),i=n(["zoom","current"])??1;document.body.style.setProperty("--zoom",i.toString()),document.body.style.setProperty("--stroke-width",(2/i).toFixed(3));const d=document.createElement("div");d.classList.add("highlight-frame"),d.style.setProperty("--frame-top",`${o}px`),d.style.setProperty("--frame-left",`${r}px`),d.style.setProperty("--frame-width",`${s}px`),d.style.setProperty("--frame-height",`${a}px`);const l=document.createElementNS("http://www.w3.org/2000/svg","svg");l.classList.add("highlight-frame-svg");const u=document.createElementNS("http://www.w3.org/2000/svg","rect");return u.setAttribute("x","0"),u.setAttribute("y","0"),u.setAttribute("width","100%"),u.setAttribute("height","100%"),u.classList.add("highlight-frame-rect"),l.appendChild(u),d.appendChild(l),d})(e,t);"true"===e.contentEditable&&s.classList.add("is-editable"),u(e,s),t.appendChild(s)},p=(e,t)=>{const r=o(t),s=n(["zoom","current"])??1;if(!r)return;s>=.3?t.style.setProperty("--tool-opacity","1"):t.style.setProperty("--tool-opacity","0");const{top:a,left:i,width:d,height:l}=c(e,t);r.style.setProperty("--frame-top",`${a}px`),r.style.setProperty("--frame-left",`${i}px`),r.style.setProperty("--frame-width",`${d}px`),r.style.setProperty("--frame-height",`${l}px`)},v=(e,t)=>{const n=o(t);if(!n)return;const r=e.classList.contains("hidden")||e.classList.contains("select-none");n.style.display=r?"none":""},h=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)}},y=(e,t)=>{const n=((e,t)=>{const n=new MutationObserver(e=>{t(e)});return n.observe(e,{subtree:!0,childList:!0,characterData:!0}),n})(e,()=>{p(e,t)});return()=>n.disconnect()},f=()=>{let e=null,t=!1,o=null;const r=()=>{if(t||!e)return;t=!0;var r;(r=e).contentEditable="false",r.classList.remove("is-editable"),r.style.outline="none",(()=>{const e=n(["keyboard","disableTextEditMode"]);e?.()})(),o?.(),e=null,t=!1};return{enableEditMode:(t,s)=>{if(e===t)return;e&&e!==t&&r();const a=(e=>Array.from(e.childNodes).some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim()))(t);a&&(e=t,(e=>{e.contentEditable="true",e.classList.add("is-editable"),e.style.outline="none"})(t),(()=>{const e=n(["keyboard","enableTextEditMode"]);e?.()})(),o=((e,t,n)=>{if(!t)return()=>{};e.addEventListener("blur",n);const o=h(e),r=y(e,t);return()=>{e.removeEventListener("blur",n),o(),r?.()}})(t,s,r))},blurEditMode:r,getEditableNode:()=>e,isEditing:()=>null!==e}},g=320,b=1680,w=[{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"}],E=(e,t,n)=>{const o=parseFloat(document.body.dataset.zoom||"1"),r=((e,t)=>{const n=e+Math.round(t);return Math.max(g,Math.min(b,n))})(n,(e.clientX-t)/o);return r},x=(e,t)=>{e.style.setProperty("--container-width",`${t}px`),((e,t)=>{e.querySelectorAll(".resize-preset-button").forEach((e,n)=>{n<w.length&&(w[n].rawValue===t?e.classList.add("is-active"):e.classList.remove("is-active"))})})(e,t)};e.createCanvasObserver=function(){const e=document.querySelector(".transform-layer");if(!e)return{disconnect:()=>{}};const o=t(()=>{(()=>{const e=n(["zoom","current"]);document.body.style.setProperty("--zoom",e.toFixed(5)),document.body.style.setProperty("--stroke-width",(2/e).toFixed(3)),document.body.dataset.zoom=e.toFixed(5),document.body.dataset.strokeWidth=(2/e).toFixed(3)})()}),r=new MutationObserver(()=>{o()});return r.observe(e,{attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0}),{disconnect:function(){o.cleanup(),r.disconnect()}}},e.createNodeTools=e=>{const n=e;let o=null,s=null,a=null;const i=f(),d=t(p),c=e=>{if(a!==e){if(i.isEditing()){const t=i.getEditableNode();t&&t!==e&&i.blurEditMode()}var t,r;o?.disconnect(),s?.disconnect(),e&&n&&(i.enableEditMode(e,n),o=((e,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n})(n,()=>{d(e,n)}),s=new MutationObserver(()=>{d(e,n),v(e,n)}),s.observe(e,{attributes:!0,attributeFilter:["class"]})),a=e,t="selectedNodeChanged",r=e?.getAttribute("data-node-id")??null,window.parent.postMessage({source:"node-edit-utils",action:t,data:r,timestamp:Date.now()},"*"),m(e,n),e&&n&&v(e,n)}},u=l(n,c,()=>{i.isEditing()&&i.blurEditMode(),a&&n&&(r(n),a=null,o?.disconnect(),s?.disconnect())},i.getEditableNode),h={selectNode:c,getSelectedNode:()=>a,refreshHighlightFrame:()=>{d(a,n)},clearSelectedNode:()=>{r(n),a=null,o?.disconnect(),s?.disconnect()},getEditableNode:()=>i.getEditableNode(),cleanup:()=>{u(),o?.disconnect(),s?.disconnect(),i.blurEditMode(),d.cleanup()}};var y,g;return y="nodeTools",g=h,"undefined"!=typeof window&&(window[y]=g),h},e.createViewport=e=>{const n=document.querySelector(".canvas-container"),o=e.querySelector(".resize-handle");o&&o.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",w.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,x);let s=!1,a=0,i=0;const d=t(t=>{if(!s)return;n&&(n.style.cursor="ew-resize");const o=E(t,a,i);x(e,o)}),l=((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(),s=!0,a=t.clientX,i=e.offsetWidth},d,e=>{e.preventDefault(),e.stopPropagation(),n&&(n.style.cursor="default"),s=!1},()=>{s=!1});return{setWidth:t=>{x(e,t)},cleanup:()=>{s=!1,d?.cleanup(),l(),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){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}const n=e=>{const t=window.canvas;return e.reduce((e,t)=>e?.[t],t)};const o=e=>e?.classList.contains("select-none")??!1;function r(e){return e.querySelector(".highlight-frame")}const s=e=>{if(!e)return;const t=r(e);t&&t.remove()},a=["path","rect","circle","ellipse","polygon","line","polyline","text","text-noci"];let i=[],l=0;const d=(e,t)=>{let n=null;const r=e.clientX,s=e.clientY,d=e.metaKey||e.ctrlKey,c=((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=>!a.includes(e.tagName.toLowerCase()));if(t&&c.includes(t))return o(t)?null:t;if(d)return i=[],n=c[0],o(n)?null:n;var u,m;m=c,(u=i).length===m.length&&u.every((e,t)=>e===m[t])?l<=c.length&&l++:l=0;return n=c[c.length-1-l],i=c,o(n)?null:n},c=(e,t,n,r)=>{const a=e=>{((e,t)=>{if("application"===e.data.source&&"selectedNodeChanged"===e.data.action){const n=e.data.data,r=document.querySelector(`[data-node-id="${n}"]`);if(o(r))return void t?.(null);r&&t?.(r)}})(e,t)},i=n=>{((e,t,n,o)=>{if(e.preventDefault(),e.stopPropagation(),t&&!t.contains(e.target))return s(t),void o(null);o(d(e,n))})(n,e,r(),t)},l=e=>{console.log("Esacpe Handler",e),"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),n?.())};return window.addEventListener("message",a),document.addEventListener("click",i),document.addEventListener("keydown",l),()=>{window.removeEventListener("message",a),document.removeEventListener("click",i),document.removeEventListener("keydown",l)}};function u(e,t){const o=e.getBoundingClientRect(),r=t.getBoundingClientRect(),s=o.top-r.top,a=o.left-r.left,i=n(["zoom","current"])??1;return{top:parseFloat((s/i).toFixed(5)),left:parseFloat((a/i).toFixed(5)),width:Math.max(4,parseFloat((o.width/i).toFixed(5))),height:parseFloat((o.height/i).toFixed(5))}}const m=(e,t)=>{const n=document.createElement("div");n.className="node-tools",t.appendChild(n),((e,t)=>{const n=document.createElement("div");n.className="tag-label",n.textContent=e.tagName.toLowerCase(),t.appendChild(n)})(e,n)},p=(e,t)=>{if(!e)return;const o=r(t);o&&o.remove();const s=((e,t)=>{const{top:o,left:r,width:s,height:a}=u(e,t),i=n(["zoom","current"])??1;document.body.style.setProperty("--zoom",i.toString()),document.body.style.setProperty("--stroke-width",(2/i).toFixed(3));const l=document.createElement("div");l.classList.add("highlight-frame"),l.style.setProperty("--frame-top",`${o}px`),l.style.setProperty("--frame-left",`${r}px`),l.style.setProperty("--frame-width",`${s}px`),l.style.setProperty("--frame-height",`${a}px`);const d=document.createElementNS("http://www.w3.org/2000/svg","svg");d.classList.add("highlight-frame-svg");const c=document.createElementNS("http://www.w3.org/2000/svg","rect");return c.setAttribute("x","0"),c.setAttribute("y","0"),c.setAttribute("width","100%"),c.setAttribute("height","100%"),c.classList.add("highlight-frame-rect"),d.appendChild(c),l.appendChild(d),l})(e,t);"true"===e.contentEditable&&s.classList.add("is-editable"),m(e,s),t.appendChild(s)},v=(e,t)=>{const o=r(t),s=n(["zoom","current"])??1;if(!o)return;s>=.3?t.style.setProperty("--tool-opacity","1"):t.style.setProperty("--tool-opacity","0");const{top:a,left:i,width:l,height:d}=u(e,t);o.style.setProperty("--frame-top",`${a}px`),o.style.setProperty("--frame-left",`${i}px`),o.style.setProperty("--frame-width",`${l}px`),o.style.setProperty("--frame-height",`${d}px`)},h=(e,t)=>{const n=r(t);if(!n)return;const o=e.classList.contains("hidden")||e.classList.contains("select-none");n.style.display=o?"none":""},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)}},y=(e,t)=>{const n=((e,t)=>{const n=new MutationObserver(e=>{t(e)});return n.observe(e,{subtree:!0,childList:!0,characterData:!0}),n})(e,()=>{v(e,t)});return()=>n.disconnect()},g=()=>{let e=null,t=!1,o=null;const r=()=>{if(t||!e)return;t=!0;var r;(r=e).contentEditable="false",r.classList.remove("is-editable"),r.style.outline="none",(()=>{const e=n(["keyboard","disableTextEditMode"]);e?.()})(),o?.(),e=null,t=!1};return{enableEditMode:(t,s)=>{if(e===t)return;e&&e!==t&&r();const a=(e=>Array.from(e.childNodes).some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim()))(t);a&&(e=t,(e=>{e.contentEditable="true",e.classList.add("is-editable"),e.style.outline="none"})(t),(()=>{const e=n(["keyboard","enableTextEditMode"]);e?.()})(),o=((e,t,n)=>{if(!t)return()=>{};e.addEventListener("blur",n);const o=f(e),r=y(e,t);return()=>{e.removeEventListener("blur",n),o(),r?.()}})(t,s,r))},blurEditMode:r,getEditableNode:()=>e,isEditing:()=>null!==e}},b=320,w=1680,E=[{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"}],x=(e,t,n)=>{const o=parseFloat(document.body.dataset.zoom||"1"),r=((e,t)=>{const n=e+Math.round(t);return Math.max(b,Math.min(w,n))})(n,(e.clientX-t)/o);return r},L=(e,t)=>{e.style.setProperty("--container-width",`${t}px`),((e,t)=>{e.querySelectorAll(".resize-preset-button").forEach((e,n)=>{n<E.length&&(E[n].rawValue===t?e.classList.add("is-active"):e.classList.remove("is-active"))})})(e,t)};e.createCanvasObserver=function(){const e=document.querySelector(".transform-layer");if(!e)return{disconnect:()=>{}};const o=t(()=>{(()=>{const e=n(["zoom","current"]);document.body.style.setProperty("--zoom",e.toFixed(5)),document.body.style.setProperty("--stroke-width",(2/e).toFixed(3)),document.body.dataset.zoom=e.toFixed(5),document.body.dataset.strokeWidth=(2/e).toFixed(3)})()}),r=new MutationObserver(()=>{o()});return r.observe(e,{attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0}),{disconnect:function(){o.cleanup(),r.disconnect()}}},e.createNodeTools=e=>{const n=e;let o=null,r=null,a=null;const i=g(),l=t(v),d=e=>{if(a!==e){if(a=e,i.isEditing()){const t=i.getEditableNode();t&&t!==e&&i.blurEditMode()}var t,s;o?.disconnect(),r?.disconnect(),e&&n&&(i.enableEditMode(e,n),o=((e,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n})(n,()=>{l(e,n)}),r=new MutationObserver(()=>{l(e,n),h(e,n)}),r.observe(e,{attributes:!0,attributeFilter:["class"]})),t="selectedNodeChanged",s=e?.getAttribute("data-node-id")??null,window.parent.postMessage({source:"node-edit-utils",action:t,data:s,timestamp:Date.now()},"*"),p(e,n),e&&n&&h(e,n)}},u=c(n,d,()=>{i.isEditing()&&i.blurEditMode(),a&&n&&(s(n),a=null,o?.disconnect(),r?.disconnect())},i.getEditableNode),m={selectNode:d,getSelectedNode:()=>a,refreshHighlightFrame:()=>{l(a,n)},clearSelectedNode:()=>{s(n),a=null,o?.disconnect(),r?.disconnect()},getEditableNode:()=>i.getEditableNode(),cleanup:()=>{u(),o?.disconnect(),r?.disconnect(),i.blurEditMode(),l.cleanup()}};var f,y;return f="nodeTools",y=m,"undefined"!=typeof window&&(window[f]=y),m},e.createViewport=e=>{const n=document.querySelector(".canvas-container"),o=e.querySelector(".resize-handle");o&&o.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",E.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,L);let s=!1,a=0,i=0;const l=t(t=>{if(!s)return;n&&(n.style.cursor="ew-resize");const o=x(t,a,i);L(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(),s=!0,a=t.clientX,i=e.offsetWidth},l,e=>{e.preventDefault(),e.stopPropagation(),n&&(n.style.cursor="default"),s=!1},()=>{s=!1});return{setWidth:t=>{L(e,t)},cleanup:()=>{s=!1,l?.cleanup(),d(),r.remove()}}}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-edit-utils/core",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Utilities for editing nodes in a dom tree.",
5
5
  "type": "module",
6
6
  "main": "dist/node-edit-utils.cjs.js",
@@ -41,6 +41,8 @@ export const createNodeTools = (element: HTMLElement | null): NodeTools => {
41
41
  return;
42
42
  }
43
43
 
44
+ selectedNode = node;
45
+
44
46
  if (text.isEditing()) {
45
47
  const currentEditable = text.getEditableNode();
46
48
  if (currentEditable && currentEditable !== node) {
@@ -69,7 +71,6 @@ export const createNodeTools = (element: HTMLElement | null): NodeTools => {
69
71
  });
70
72
  }
71
73
 
72
- selectedNode = node;
73
74
  sendPostMessage("selectedNodeChanged", node?.getAttribute("data-node-id") ?? null);
74
75
  highlightNode(node, nodeProvider as HTMLElement) ?? null;
75
76
 
@@ -19,6 +19,9 @@ export const setupEventListener = (
19
19
  console.log("Esacpe Handler", event);
20
20
 
21
21
  if (event.key === "Escape") {
22
+ event.preventDefault();
23
+ event.stopPropagation();
24
+
22
25
  onEscapePressed?.();
23
26
  }
24
27
  };
@@ -0,0 +1,4 @@
1
+ export const isLocked = (node: HTMLElement | null): boolean => {
2
+ return node?.classList.contains("select-none") ?? false;
3
+ };
4
+
@@ -1,5 +1,6 @@
1
1
  import { IGNORED_DOM_ELEMENTS } from "./constants";
2
2
  import { getElementsFromPoint } from "./helpers/getElementsFromPoint";
3
+ import { isLocked } from "./helpers/isLocked";
3
4
  import { targetSameCandidates } from "./helpers/targetSameCandidates";
4
5
 
5
6
  let candidateCache: Element[] = [];
@@ -14,10 +15,13 @@ export const selectNode = (event: MouseEvent, editableNode: HTMLElement | null):
14
15
  const clickThrough = event.metaKey || event.ctrlKey;
15
16
 
16
17
  const candidates = getElementsFromPoint(clickX, clickY).filter(
17
- (element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase()) && !element.classList.contains("select-none")
18
+ (element) => !IGNORED_DOM_ELEMENTS.includes(element.tagName.toLowerCase())
18
19
  );
19
20
 
20
21
  if (editableNode && candidates.includes(editableNode)) {
22
+ if (isLocked(editableNode)) {
23
+ return null;
24
+ }
21
25
  return editableNode;
22
26
  }
23
27
 
@@ -25,6 +29,9 @@ export const selectNode = (event: MouseEvent, editableNode: HTMLElement | null):
25
29
  candidateCache = [];
26
30
 
27
31
  selectedNode = candidates[0] as HTMLElement;
32
+ if (isLocked(selectedNode)) {
33
+ return null;
34
+ }
28
35
  return selectedNode;
29
36
  }
30
37
 
@@ -40,5 +47,9 @@ export const selectNode = (event: MouseEvent, editableNode: HTMLElement | null):
40
47
 
41
48
  candidateCache = candidates;
42
49
 
50
+ if (isLocked(selectedNode)) {
51
+ return null;
52
+ }
53
+
43
54
  return selectedNode;
44
55
  };
@@ -1,17 +1,24 @@
1
+ import { isLocked } from "../node-tools/select/helpers/isLocked";
2
+
1
3
  export const processPostMessage = (event: MessageEvent, onNodeSelected?: (node: HTMLElement | null) => void) => {
2
- if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
3
- if (event.data.action === "zoom") {
4
- const zoom = event.data.data;
5
- }
6
- }
4
+ // if (event.data.source === "markup-canvas" && event.data.canvasName === "canvas") {
5
+ // if (event.data.action === "zoom") {
6
+ // // Zoom handling can be implemented here if needed
7
+ // }
8
+ // }
7
9
 
8
10
  if (event.data.source === "application") {
9
11
  if (event.data.action === "selectedNodeChanged") {
10
12
  const nodeId = event.data.data;
11
- const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`);
13
+ const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`) as HTMLElement | null;
14
+
15
+ if (isLocked(selectedNode)) {
16
+ onNodeSelected?.(null);
17
+ return;
18
+ }
12
19
 
13
20
  if (selectedNode) {
14
- onNodeSelected?.(selectedNode as HTMLElement);
21
+ onNodeSelected?.(selectedNode);
15
22
  }
16
23
  }
17
24
  }