UNPKG

react-konva-utils

Version:

Useful components and hooks for react-konva

122 lines (121 loc) 5.09 kB
"use strict"; 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Html = void 0; exports.useEvent = useEvent; const react_1 = __importDefault(require("react")); const client_1 = __importDefault(require("react-dom/client")); const react_konva_1 = require("react-konva"); const its_fine_1 = require("its-fine"); const react_dom_1 = require("react-dom"); const needForceStyle = (el) => { const pos = window.getComputedStyle(el).position; const ok = pos === 'absolute' || pos === 'relative'; return !ok; }; function useEvent(fn = () => { }) { const ref = react_1.default.useRef(fn); ref.current = fn; return react_1.default.useCallback((...args) => { return ref.current.apply(null, args); }, []); } const Html = ({ children, groupProps, divProps, transform, transformFunc, parentNodeFunc, }) => { const Bridge = (0, its_fine_1.useContextBridge)(); const groupRef = react_1.default.useRef(null); const [div] = react_1.default.useState(() => document.createElement('div')); const root = react_1.default.useMemo(() => client_1.default.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"]); // apply deep nesting, because direct assign of "divProps" will overwrite styles above Object.assign(div.style, style); Object.assign(div, restProps); }); react_1.default.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_1.default.useLayoutEffect(() => { handleTransform(); }, [divProps, transformFunc]); react_1.default.useLayoutEffect(() => { // Run *after* React’s commit but *before* the next paint // ideally we should just call root.render here with a sync mode // TODO: does React 19 support sync mode? // but react doing re-render in async mode // in some scenarios we want to see result instantly, // so it is in sync with Konva stage queueMicrotask(() => { (0, react_dom_1.flushSync)(() => { root.render(react_1.default.createElement(Bridge, null, children)); }); }); }); react_1.default.useLayoutEffect(() => { return () => { // I am not really sure why do we need timeout here // but it resolve warnings from react // ref: https://github.com/konvajs/react-konva-utils/issues/26 setTimeout(() => { root.unmount(); }); }; }, []); return react_1.default.createElement(react_konva_1.Group, Object.assign({ ref: groupRef }, groupProps)); }; exports.Html = Html;