UNPKG

react-konva

Version:

React binding to canvas element via Konva framework

121 lines (120 loc) 4.26 kB
/** * Based on ReactArt.js * Copyright (c) 2017-present Lavrenov Anton. * All rights reserved. * * MIT */ 'use strict'; import React from 'react'; if (React.version.indexOf('19') === -1) { throw new Error('react-konva version 19 is only compatible with React 19. Make sure to have the last version of react-konva and react or downgrade react-konva to version 18.'); } import Konva from 'konva/lib/Core.js'; import ReactFiberReconciler from 'react-reconciler'; import { ConcurrentRoot } from 'react-reconciler/constants.js'; import * as HostConfig from './ReactKonvaHostConfig.js'; import { applyNodeProps, toggleStrictMode } from './makeUpdates.js'; import { useContextBridge, FiberProvider } from 'its-fine'; function usePrevious(value) { const ref = React.useRef({}); React.useLayoutEffect(() => { ref.current = value; }); React.useLayoutEffect(() => { return () => { // when using suspense it is possible that stage is unmounted // but React still keep component ref // in that case we need to manually flush props // we have a special test for that ref.current = {}; }; }, []); return ref.current; } const StageWrap = (props) => { const container = React.useRef(null); const stage = React.useRef(null); const fiberRef = React.useRef(null); const oldProps = usePrevious(props); const Bridge = useContextBridge(); const _setRef = (stage) => { const { forwardedRef } = props; if (!forwardedRef) { return; } if (typeof forwardedRef === 'function') { forwardedRef(stage); } else { forwardedRef.current = stage; } }; React.useLayoutEffect(() => { stage.current = new Konva.Stage({ width: props.width, height: props.height, container: container.current, }); _setRef(stage.current); // @ts-ignore fiberRef.current = KonvaRenderer.createContainer(stage.current, ConcurrentRoot, null, false, null, '', console.error, console.error, console.error, null); KonvaRenderer.updateContainer(React.createElement(Bridge, {}, props.children), fiberRef.current, null, () => { }); return () => { _setRef(null); KonvaRenderer.updateContainer(null, fiberRef.current, null); stage.current.destroy(); }; }, []); React.useLayoutEffect(() => { _setRef(stage.current); applyNodeProps(stage.current, props, oldProps); KonvaRenderer.updateContainer(React.createElement(Bridge, {}, props.children), fiberRef.current, null); }); return React.createElement('div', { ref: container, id: props.id, accessKey: props.accessKey, className: props.className, role: props.role, style: props.style, tabIndex: props.tabIndex, title: props.title, }); }; export const Layer = 'Layer'; export const FastLayer = 'FastLayer'; export const Group = 'Group'; export const Label = 'Label'; export const Rect = 'Rect'; export const Circle = 'Circle'; export const Ellipse = 'Ellipse'; export const Wedge = 'Wedge'; export const Line = 'Line'; export const Sprite = 'Sprite'; export const Image = 'Image'; export const Text = 'Text'; export const TextPath = 'TextPath'; export const Star = 'Star'; export const Ring = 'Ring'; export const Arc = 'Arc'; export const Tag = 'Tag'; export const Path = 'Path'; export const RegularPolygon = 'RegularPolygon'; export const Arrow = 'Arrow'; export const Shape = 'Shape'; export const Transformer = 'Transformer'; // @ts-ignore export const KonvaRenderer = ReactFiberReconciler(HostConfig); KonvaRenderer.injectIntoDevTools({ // @ts-ignore findHostInstanceByFiber: () => null, bundleType: process.env.NODE_ENV !== 'production' ? 1 : 0, version: React.version, rendererPackageName: 'react-konva', }); // Update Stage component declaration export const Stage = React.forwardRef((props, ref) => { return React.createElement(FiberProvider, {}, React.createElement(StageWrap, { ...props, forwardedRef: ref })); }); export const useStrictMode = toggleStrictMode;