react-konva-utils
Version:
Useful components and hooks for react-konva
104 lines (103 loc) • 3.96 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Group } from 'react-konva';
import { useContextBridge } from 'its-fine';
import { flushSync } from 'react-dom';
const needForceStyle = (el) => {
const pos = window.getComputedStyle(el).position;
const ok = pos === 'absolute' || pos === 'relative';
return !ok;
};
export function useEvent(fn = () => { }) {
const ref = React.useRef(fn);
ref.current = fn;
return React.useCallback((...args) => {
return ref.current.apply(null, args);
}, []);
}
export const Html = ({ children, groupProps, divProps, transform, transformFunc, parentNodeFunc, }) => {
const Bridge = useContextBridge();
const groupRef = React.useRef(null);
const [div] = React.useState(() => document.createElement('div'));
const root = React.useMemo(() => ReactDOM.createRoot(div), [div]);
const shouldTransform = transform !== null && transform !== void 0 ? transform : true;
const handleTransform = useEvent(() => {
if (shouldTransform && groupRef.current) {
const tr = groupRef.current.getAbsoluteTransform();
let attrs = tr.decompose();
if (transformFunc) {
attrs = transformFunc(attrs);
}
div.style.position = 'absolute';
div.style.zIndex = '10';
div.style.top = '0px';
div.style.left = '0px';
div.style.transform = `translate(${attrs.x}px, ${attrs.y}px) rotate(${attrs.rotation}deg) scaleX(${attrs.scaleX}) scaleY(${attrs.scaleY})`;
div.style.transformOrigin = 'top left';
}
else {
div.style.position = '';
div.style.zIndex = '';
div.style.top = '';
div.style.left = '';
div.style.transform = ``;
div.style.transformOrigin = '';
}
const _a = divProps || {}, { style } = _a, restProps = __rest(_a, ["style"]);
Object.assign(div.style, style);
Object.assign(div, restProps);
});
React.useLayoutEffect(() => {
var _a;
const group = groupRef.current;
if (!group) {
return;
}
const parent = parentNodeFunc
? parentNodeFunc({ stage: group.getStage() })
: (_a = group.getStage()) === null || _a === void 0 ? void 0 : _a.container();
if (!parent) {
return;
}
parent.appendChild(div);
if (shouldTransform && needForceStyle(parent)) {
parent.style.position = 'relative';
}
group.on('absoluteTransformChange', handleTransform);
handleTransform();
return () => {
var _a;
group.off('absoluteTransformChange', handleTransform);
(_a = div.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(div);
};
}, [shouldTransform, parentNodeFunc]);
React.useLayoutEffect(() => {
handleTransform();
}, [divProps, transformFunc]);
React.useLayoutEffect(() => {
queueMicrotask(() => {
flushSync(() => {
root.render(React.createElement(Bridge, null, children));
});
});
});
React.useLayoutEffect(() => {
return () => {
setTimeout(() => {
root.unmount();
});
};
}, []);
return React.createElement(Group, Object.assign({ ref: groupRef }, groupProps));
};