@node-edit-utils/core 2.1.7 → 2.1.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/helpers/index.d.ts +1 -1
- package/dist/lib/helpers/withRAF.d.ts +3 -0
- package/dist/node-edit-utils.cjs.js +38 -2
- package/dist/node-edit-utils.esm.js +38 -2
- package/dist/node-edit-utils.umd.js +38 -2
- package/dist/node-edit-utils.umd.min.js +1 -1
- package/package.json +1 -1
- package/src/lib/helpers/index.ts +1 -1
- package/src/lib/helpers/withRAF.ts +41 -0
- package/src/lib/node-tools/createNodeTools.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
export { withRAF, withRAFThrottle } from "./withRAF";
|
|
1
|
+
export { withRAF, withRAFThrottle, withDoubleRAF } from "./withRAF";
|
|
@@ -2,3 +2,6 @@ export declare function withRAF(operation: () => void): () => void;
|
|
|
2
2
|
export declare function withRAFThrottle<T extends (...args: any[]) => void>(func: T): T & {
|
|
3
3
|
cleanup: () => void;
|
|
4
4
|
};
|
|
5
|
+
export declare function withDoubleRAF<T extends (...args: any[]) => void>(func: T): T & {
|
|
6
|
+
cleanup: () => void;
|
|
7
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 2.1.
|
|
4
|
+
* @version 2.1.8
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -30,6 +30,42 @@ function withRAFThrottle(func) {
|
|
|
30
30
|
};
|
|
31
31
|
return throttled;
|
|
32
32
|
}
|
|
33
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
34
|
+
function withDoubleRAF(func) {
|
|
35
|
+
let rafId1 = null;
|
|
36
|
+
let rafId2 = null;
|
|
37
|
+
let lastArgs = null;
|
|
38
|
+
const throttled = (...args) => {
|
|
39
|
+
lastArgs = args;
|
|
40
|
+
if (rafId1 === null) {
|
|
41
|
+
rafId1 = requestAnimationFrame(() => {
|
|
42
|
+
// First RAF: let browser complete layout
|
|
43
|
+
rafId2 = requestAnimationFrame(() => {
|
|
44
|
+
// Second RAF: read bounds after layout is complete
|
|
45
|
+
if (lastArgs) {
|
|
46
|
+
const currentArgs = lastArgs;
|
|
47
|
+
rafId1 = null;
|
|
48
|
+
rafId2 = null;
|
|
49
|
+
lastArgs = null;
|
|
50
|
+
func(...currentArgs);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
throttled.cleanup = () => {
|
|
57
|
+
if (rafId1 !== null) {
|
|
58
|
+
cancelAnimationFrame(rafId1);
|
|
59
|
+
rafId1 = null;
|
|
60
|
+
}
|
|
61
|
+
if (rafId2 !== null) {
|
|
62
|
+
cancelAnimationFrame(rafId2);
|
|
63
|
+
rafId2 = null;
|
|
64
|
+
}
|
|
65
|
+
lastArgs = null;
|
|
66
|
+
};
|
|
67
|
+
return throttled;
|
|
68
|
+
}
|
|
33
69
|
|
|
34
70
|
const getCanvasWindowValue = (path) => {
|
|
35
71
|
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
@@ -462,7 +498,7 @@ const createNodeTools = (element) => {
|
|
|
462
498
|
let mutationObserver = null;
|
|
463
499
|
let selectedNode = null;
|
|
464
500
|
const text = nodeText();
|
|
465
|
-
const throttledFrameRefresh =
|
|
501
|
+
const throttledFrameRefresh = withDoubleRAF(refreshHighlightFrame);
|
|
466
502
|
const handleEscape = () => {
|
|
467
503
|
if (text.isEditing()) {
|
|
468
504
|
text.blurEditMode();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 2.1.
|
|
4
|
+
* @version 2.1.8
|
|
5
5
|
*/
|
|
6
6
|
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
7
7
|
function withRAFThrottle(func) {
|
|
@@ -28,6 +28,42 @@ function withRAFThrottle(func) {
|
|
|
28
28
|
};
|
|
29
29
|
return throttled;
|
|
30
30
|
}
|
|
31
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
32
|
+
function withDoubleRAF(func) {
|
|
33
|
+
let rafId1 = null;
|
|
34
|
+
let rafId2 = null;
|
|
35
|
+
let lastArgs = null;
|
|
36
|
+
const throttled = (...args) => {
|
|
37
|
+
lastArgs = args;
|
|
38
|
+
if (rafId1 === null) {
|
|
39
|
+
rafId1 = requestAnimationFrame(() => {
|
|
40
|
+
// First RAF: let browser complete layout
|
|
41
|
+
rafId2 = requestAnimationFrame(() => {
|
|
42
|
+
// Second RAF: read bounds after layout is complete
|
|
43
|
+
if (lastArgs) {
|
|
44
|
+
const currentArgs = lastArgs;
|
|
45
|
+
rafId1 = null;
|
|
46
|
+
rafId2 = null;
|
|
47
|
+
lastArgs = null;
|
|
48
|
+
func(...currentArgs);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
throttled.cleanup = () => {
|
|
55
|
+
if (rafId1 !== null) {
|
|
56
|
+
cancelAnimationFrame(rafId1);
|
|
57
|
+
rafId1 = null;
|
|
58
|
+
}
|
|
59
|
+
if (rafId2 !== null) {
|
|
60
|
+
cancelAnimationFrame(rafId2);
|
|
61
|
+
rafId2 = null;
|
|
62
|
+
}
|
|
63
|
+
lastArgs = null;
|
|
64
|
+
};
|
|
65
|
+
return throttled;
|
|
66
|
+
}
|
|
31
67
|
|
|
32
68
|
const getCanvasWindowValue = (path) => {
|
|
33
69
|
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
@@ -460,7 +496,7 @@ const createNodeTools = (element) => {
|
|
|
460
496
|
let mutationObserver = null;
|
|
461
497
|
let selectedNode = null;
|
|
462
498
|
const text = nodeText();
|
|
463
|
-
const throttledFrameRefresh =
|
|
499
|
+
const throttledFrameRefresh = withDoubleRAF(refreshHighlightFrame);
|
|
464
500
|
const handleEscape = () => {
|
|
465
501
|
if (text.isEditing()) {
|
|
466
502
|
text.blurEditMode();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 2.1.
|
|
4
|
+
* @version 2.1.8
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
@@ -34,6 +34,42 @@
|
|
|
34
34
|
};
|
|
35
35
|
return throttled;
|
|
36
36
|
}
|
|
37
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
38
|
+
function withDoubleRAF(func) {
|
|
39
|
+
let rafId1 = null;
|
|
40
|
+
let rafId2 = null;
|
|
41
|
+
let lastArgs = null;
|
|
42
|
+
const throttled = (...args) => {
|
|
43
|
+
lastArgs = args;
|
|
44
|
+
if (rafId1 === null) {
|
|
45
|
+
rafId1 = requestAnimationFrame(() => {
|
|
46
|
+
// First RAF: let browser complete layout
|
|
47
|
+
rafId2 = requestAnimationFrame(() => {
|
|
48
|
+
// Second RAF: read bounds after layout is complete
|
|
49
|
+
if (lastArgs) {
|
|
50
|
+
const currentArgs = lastArgs;
|
|
51
|
+
rafId1 = null;
|
|
52
|
+
rafId2 = null;
|
|
53
|
+
lastArgs = null;
|
|
54
|
+
func(...currentArgs);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
throttled.cleanup = () => {
|
|
61
|
+
if (rafId1 !== null) {
|
|
62
|
+
cancelAnimationFrame(rafId1);
|
|
63
|
+
rafId1 = null;
|
|
64
|
+
}
|
|
65
|
+
if (rafId2 !== null) {
|
|
66
|
+
cancelAnimationFrame(rafId2);
|
|
67
|
+
rafId2 = null;
|
|
68
|
+
}
|
|
69
|
+
lastArgs = null;
|
|
70
|
+
};
|
|
71
|
+
return throttled;
|
|
72
|
+
}
|
|
37
73
|
|
|
38
74
|
const getCanvasWindowValue = (path) => {
|
|
39
75
|
// biome-ignore lint/suspicious/noExplicitAny: global window extension
|
|
@@ -466,7 +502,7 @@
|
|
|
466
502
|
let mutationObserver = null;
|
|
467
503
|
let selectedNode = null;
|
|
468
504
|
const text = nodeText();
|
|
469
|
-
const throttledFrameRefresh =
|
|
505
|
+
const throttledFrameRefresh = withDoubleRAF(refreshHighlightFrame);
|
|
470
506
|
const handleEscape = () => {
|
|
471
507
|
if (text.isEditing()) {
|
|
472
508
|
text.blurEditMode();
|
|
@@ -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)};const o=(e,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n};function r(e){return e.querySelector(".highlight-frame")}const s=e=>{if(!e)return;const t=r(e);t&&t.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,t)=>{const n=new ResizeObserver(e=>{t(e)});return n.observe(e),n};function r(e){return e.querySelector(".highlight-frame")}const s=e=>{if(!e)return;const t=r(e);t&&t.remove()},l=["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,s=e.metaKey||e.ctrlKey,d=((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=>!l.includes(e.tagName.toLowerCase())&&!e.classList.contains("select-none"));if(t&&d.includes(t))return t;if(s)return a=[],n=d[0],n;var c,u;u=d,(c=a).length===u.length&&c.every((e,t)=>e===u[t])?i<=d.length&&i++:i=0;return n=d[d.length-1-i],a=d,n},c=(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)},l=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,o(),t)},a=e=>{"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),n?.())};return window.addEventListener("message",r),document.addEventListener("click",l),document.addEventListener("keydown",a),()=>{window.removeEventListener("message",r),document.removeEventListener("click",l),document.removeEventListener("keydown",a)}};function u(e,t){const o=e.getBoundingClientRect(),r=t.getBoundingClientRect(),s=o.top-r.top,l=o.left-r.left,a=n(["zoom","current"])??1;return{top:parseFloat((s/a).toFixed(5)),left:parseFloat((l/a).toFixed(5)),width:Math.max(4,parseFloat((o.width/a).toFixed(5))),height:parseFloat((o.height/a).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:l}=u(e,t),a=n(["zoom","current"])??1;document.body.style.setProperty("--zoom",a.toString()),document.body.style.setProperty("--stroke-width",(2/a).toFixed(3));const i=document.createElement("div");i.classList.add("highlight-frame"),i.style.setProperty("--frame-top",`${o}px`),i.style.setProperty("--frame-left",`${r}px`),i.style.setProperty("--frame-width",`${s}px`),i.style.setProperty("--frame-height",`${l}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),i.appendChild(d),i})(e,t);"true"===e.contentEditable&&s.classList.add("is-editable"),m(e,s),t.appendChild(s)},h=(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:l,left:a,width:i,height:d}=u(e,t);o.style.setProperty("--frame-top",`${l}px`),o.style.setProperty("--frame-left",`${a}px`),o.style.setProperty("--frame-width",`${i}px`),o.style.setProperty("--frame-height",`${d}px`)},v=(e,t)=>{const n=r(t);if(!n)return;const o=e.classList.contains("hidden")||e.classList.contains("select-none")?"none":"";n.style.display=o;const s=n.querySelector(".tag-label");s&&(s.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)}},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,()=>{h(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 l=(e=>Array.from(e.childNodes).some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim()))(t);l&&(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 t=e;let n=null,r=null,l=null,a=null;const i=g(),d=function(e){let t=null,n=null,o=null;const r=(...r)=>{o=r,null===t&&(t=requestAnimationFrame(()=>{n=requestAnimationFrame(()=>{if(o){const r=o;t=null,n=null,o=null,e(...r)}})}))};return r.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null),null!==n&&(cancelAnimationFrame(n),n=null),o=null},r}(h),u=e=>{if(a!==e){if(i.isEditing()){const t=i.getEditableNode();t&&t!==e&&i.blurEditMode()}var s,c;n?.disconnect(),r?.disconnect(),l?.disconnect(),e&&t&&(i.enableEditMode(e,t),n=o(t,()=>{d(e,t)}),l=new MutationObserver(()=>{d(e,t),v(e,t)}),l.observe(e,{attributes:!0,subtree:!0,childList:!0,characterData:!0}),r=o(e,()=>{d(e,t),v(e,t)})),a=e,s="selectedNodeChanged",c=e?.getAttribute("data-node-id")??null,window.parent.postMessage({source:"node-edit-utils",action:s,data:c,timestamp:Date.now()},"*"),p(e,t),e&&t&&v(e,t)}},m=c(t,u,()=>{i.isEditing()&&i.blurEditMode(),a&&t&&(s(t),a=null,n?.disconnect(),r?.disconnect(),l?.disconnect())},i.getEditableNode),f={selectNode:u,getSelectedNode:()=>a,refreshHighlightFrame:()=>{d(a,t)},clearSelectedNode:()=>{s(t),a=null,n?.disconnect(),r?.disconnect(),l?.disconnect()},getEditableNode:()=>i.getEditableNode(),cleanup:()=>{m(),n?.disconnect(),r?.disconnect(),l?.disconnect(),i.blurEditMode(),d.cleanup()}};var y,b;return y="nodeTools",b=f,"undefined"!=typeof window&&(window[y]=b),f},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,l=0,a=0;const i=t(t=>{if(!s)return;n&&(n.style.cursor="ew-resize");const o=x(t,l,a);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,l=t.clientX,a=e.offsetWidth},i,e=>{e.preventDefault(),e.stopPropagation(),n&&(n.style.cursor="default"),s=!1},()=>{s=!1});return{setWidth:t=>{L(e,t)},cleanup:()=>{s=!1,i?.cleanup(),d(),r.remove()}}}});
|
package/package.json
CHANGED
package/src/lib/helpers/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { withRAF, withRAFThrottle } from "./withRAF";
|
|
1
|
+
export { withRAF, withRAFThrottle, withDoubleRAF } from "./withRAF";
|
|
@@ -37,3 +37,44 @@ export function withRAFThrottle<T extends (...args: any[]) => void>(func: T): T
|
|
|
37
37
|
|
|
38
38
|
return throttled as T & { cleanup: () => void };
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
// biome-ignore lint/suspicious/noExplicitAny: generic constraint requires flexibility
|
|
42
|
+
export function withDoubleRAF<T extends (...args: any[]) => void>(func: T): T & { cleanup: () => void } {
|
|
43
|
+
let rafId1: number | null = null;
|
|
44
|
+
let rafId2: number | null = null;
|
|
45
|
+
let lastArgs: Parameters<T> | null = null;
|
|
46
|
+
|
|
47
|
+
const throttled = (...args: Parameters<T>) => {
|
|
48
|
+
lastArgs = args;
|
|
49
|
+
|
|
50
|
+
if (rafId1 === null) {
|
|
51
|
+
rafId1 = requestAnimationFrame(() => {
|
|
52
|
+
// First RAF: let browser complete layout
|
|
53
|
+
rafId2 = requestAnimationFrame(() => {
|
|
54
|
+
// Second RAF: read bounds after layout is complete
|
|
55
|
+
if (lastArgs) {
|
|
56
|
+
const currentArgs = lastArgs;
|
|
57
|
+
rafId1 = null;
|
|
58
|
+
rafId2 = null;
|
|
59
|
+
lastArgs = null;
|
|
60
|
+
func(...currentArgs);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
throttled.cleanup = () => {
|
|
68
|
+
if (rafId1 !== null) {
|
|
69
|
+
cancelAnimationFrame(rafId1);
|
|
70
|
+
rafId1 = null;
|
|
71
|
+
}
|
|
72
|
+
if (rafId2 !== null) {
|
|
73
|
+
cancelAnimationFrame(rafId2);
|
|
74
|
+
rafId2 = null;
|
|
75
|
+
}
|
|
76
|
+
lastArgs = null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return throttled as T & { cleanup: () => void };
|
|
80
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { withDoubleRAF } from "../helpers";
|
|
2
2
|
import { connectResizeObserver } from "../helpers/observer/connectResizeObserver";
|
|
3
3
|
import { sendPostMessage } from "../post-message/sendPostMessage";
|
|
4
4
|
import { bindToWindow } from "../window/bindToWindow";
|
|
@@ -19,7 +19,7 @@ export const createNodeTools = (element: HTMLElement | null): NodeTools => {
|
|
|
19
19
|
let selectedNode: HTMLElement | null = null;
|
|
20
20
|
|
|
21
21
|
const text = nodeText();
|
|
22
|
-
const throttledFrameRefresh =
|
|
22
|
+
const throttledFrameRefresh = withDoubleRAF(refreshHighlightFrame);
|
|
23
23
|
|
|
24
24
|
const handleEscape = (): void => {
|
|
25
25
|
if (text.isEditing()) {
|