@depup/react-konva 19.2.3-depup.0
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/LICENSE +21 -0
- package/README.md +25 -0
- package/ReactKonvaCore.d.ts +117 -0
- package/changes.json +5 -0
- package/es/ReactKonva.js +10 -0
- package/es/ReactKonvaCore.d.ts +117 -0
- package/es/ReactKonvaCore.js +185 -0
- package/es/ReactKonvaHostConfig.js +220 -0
- package/es/makeUpdates.js +117 -0
- package/lib/ReactKonva.js +25 -0
- package/lib/ReactKonvaCore.d.ts +117 -0
- package/lib/ReactKonvaCore.js +221 -0
- package/lib/ReactKonvaHostConfig.js +277 -0
- package/lib/makeUpdates.js +123 -0
- package/package.json +93 -0
- package/react-konva.d.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Anton Lavrenov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @depup/react-konva
|
|
2
|
+
|
|
3
|
+
> Dependency-bumped version of [react-konva](https://www.npmjs.com/package/react-konva)
|
|
4
|
+
|
|
5
|
+
Generated by [DepUp](https://github.com/depup/npm) -- all production
|
|
6
|
+
dependencies bumped to latest versions.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @depup/react-konva
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Field | Value |
|
|
15
|
+
|-------|-------|
|
|
16
|
+
| Original | [react-konva](https://www.npmjs.com/package/react-konva) @ 19.2.3 |
|
|
17
|
+
| Processed | 2026-03-18 |
|
|
18
|
+
| Smoke test | failed |
|
|
19
|
+
| Deps updated | 0 |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/react-konva
|
|
24
|
+
|
|
25
|
+
License inherited from the original package.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// special file for minimal import
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as ReactReconciler from 'react-reconciler';
|
|
4
|
+
import Konva from 'konva';
|
|
5
|
+
import { useContextBridge } from 'its-fine';
|
|
6
|
+
|
|
7
|
+
export interface KonvaNodeEvents {
|
|
8
|
+
onMouseOver?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
9
|
+
onMouseMove?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
10
|
+
onMouseOut?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
11
|
+
onMouseEnter?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
12
|
+
onMouseLeave?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
13
|
+
onMouseDown?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
14
|
+
onMouseUp?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
15
|
+
onWheel?(evt: Konva.KonvaEventObject<WheelEvent>): void;
|
|
16
|
+
onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
17
|
+
onDblClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
18
|
+
onTouchStart?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
19
|
+
onTouchMove?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
20
|
+
onTouchEnd?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
21
|
+
onTap?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
22
|
+
onDblTap?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
23
|
+
onDragStart?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
24
|
+
onDragMove?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
25
|
+
onDragEnd?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
26
|
+
onTransform?(evt: Konva.KonvaEventObject<Event>): void;
|
|
27
|
+
onTransformStart?(evt: Konva.KonvaEventObject<Event>): void;
|
|
28
|
+
onTransformEnd?(evt: Konva.KonvaEventObject<Event>): void;
|
|
29
|
+
onContextMenu?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
30
|
+
onPointerDown?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
31
|
+
onPointerMove?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
32
|
+
onPointerUp?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
33
|
+
onPointerCancel?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
34
|
+
onPointerEnter?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
35
|
+
onPointerLeave?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
36
|
+
onPointerOver?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
37
|
+
onPointerOut?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
38
|
+
onPointerClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
39
|
+
onPointerDblClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
40
|
+
onGotPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
41
|
+
onLostPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface KonvaNodeComponent<
|
|
45
|
+
Node extends Konva.Node,
|
|
46
|
+
Props = Konva.NodeConfig
|
|
47
|
+
// We use React.ClassAttributes to fake the 'ref' attribute. This will ensure
|
|
48
|
+
// consumers get the proper 'Node' type in 'ref' instead of the wrapper
|
|
49
|
+
// component type.
|
|
50
|
+
> extends React.FC<Props & KonvaNodeEvents & React.ClassAttributes<Node>> {
|
|
51
|
+
getPublicInstance(): Node;
|
|
52
|
+
getNativeNode(): Node;
|
|
53
|
+
// putEventListener(type: string, listener: Function): void;
|
|
54
|
+
// handleEvent(event: Event): void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface StageProps
|
|
58
|
+
extends Konva.NodeConfig,
|
|
59
|
+
KonvaNodeEvents,
|
|
60
|
+
Pick<
|
|
61
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
62
|
+
'className' | 'role' | 'style' | 'tabIndex' | 'title'
|
|
63
|
+
> {}
|
|
64
|
+
|
|
65
|
+
// Stage is the only real class because the others are stubs that only know how
|
|
66
|
+
// to be rendered when they are under stage. Since there is no real backing
|
|
67
|
+
// class and are in reality are a string literal we don't want users to actually
|
|
68
|
+
// try and use them as a type. By defining them as a variable with an interface
|
|
69
|
+
// consumers will not be able to use the values as a type or constructor.
|
|
70
|
+
// The down side to this approach, is that typescript thinks the type is a
|
|
71
|
+
// function, but if the user tries to call it a runtime exception will occur.
|
|
72
|
+
|
|
73
|
+
export var Stage: KonvaNodeComponent<Konva.Stage, StageProps>;
|
|
74
|
+
export var Layer: KonvaNodeComponent<Konva.Layer, Konva.LayerConfig>;
|
|
75
|
+
export var FastLayer: KonvaNodeComponent<Konva.FastLayer, Konva.LayerConfig>;
|
|
76
|
+
export var Group: KonvaNodeComponent<Konva.Group, Konva.GroupConfig>;
|
|
77
|
+
export var Label: KonvaNodeComponent<Konva.Label, Konva.LabelConfig>;
|
|
78
|
+
|
|
79
|
+
/** Shapes */
|
|
80
|
+
export var Rect: KonvaNodeComponent<Konva.Rect, Konva.RectConfig>;
|
|
81
|
+
export var Circle: KonvaNodeComponent<Konva.Circle, Konva.CircleConfig>;
|
|
82
|
+
export var Ellipse: KonvaNodeComponent<Konva.Ellipse, Konva.EllipseConfig>;
|
|
83
|
+
export var Wedge: KonvaNodeComponent<Konva.Wedge, Konva.WedgeConfig>;
|
|
84
|
+
export var Transformer: KonvaNodeComponent<
|
|
85
|
+
Konva.Transformer,
|
|
86
|
+
Konva.TransformerConfig
|
|
87
|
+
>;
|
|
88
|
+
export var Line: KonvaNodeComponent<Konva.Line, Konva.LineConfig>;
|
|
89
|
+
export var Sprite: KonvaNodeComponent<Konva.Sprite, Konva.SpriteConfig>;
|
|
90
|
+
export var Image: KonvaNodeComponent<Konva.Image, Konva.ImageConfig>;
|
|
91
|
+
export var Text: KonvaNodeComponent<Konva.Text, Konva.TextConfig>;
|
|
92
|
+
export var TextPath: KonvaNodeComponent<Konva.TextPath, Konva.TextPathConfig>;
|
|
93
|
+
export var Star: KonvaNodeComponent<Konva.Star, Konva.StarConfig>;
|
|
94
|
+
export var Ring: KonvaNodeComponent<Konva.Ring, Konva.RingConfig>;
|
|
95
|
+
export var Arc: KonvaNodeComponent<Konva.Arc, Konva.ArcConfig>;
|
|
96
|
+
export var Tag: KonvaNodeComponent<Konva.Tag, Konva.TagConfig>;
|
|
97
|
+
export var Path: KonvaNodeComponent<Konva.Path, Konva.PathConfig>;
|
|
98
|
+
export var RegularPolygon: KonvaNodeComponent<
|
|
99
|
+
Konva.RegularPolygon,
|
|
100
|
+
Konva.RegularPolygonConfig
|
|
101
|
+
>;
|
|
102
|
+
export var Arrow: KonvaNodeComponent<Konva.Arrow, Konva.ArrowConfig>;
|
|
103
|
+
export var Shape: KonvaNodeComponent<Konva.Shape, Konva.ShapeConfig>;
|
|
104
|
+
|
|
105
|
+
export var useStrictMode: (useStrictMode: boolean) => void;
|
|
106
|
+
export var KonvaRenderer: ReactReconciler.Reconciler<
|
|
107
|
+
any,
|
|
108
|
+
any,
|
|
109
|
+
any,
|
|
110
|
+
any,
|
|
111
|
+
any,
|
|
112
|
+
any
|
|
113
|
+
>;
|
|
114
|
+
|
|
115
|
+
export var version: string;
|
|
116
|
+
|
|
117
|
+
export { useContextBridge };
|
package/changes.json
ADDED
package/es/ReactKonva.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// special file for minimal import
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as ReactReconciler from 'react-reconciler';
|
|
4
|
+
import Konva from 'konva';
|
|
5
|
+
import { useContextBridge } from 'its-fine';
|
|
6
|
+
|
|
7
|
+
export interface KonvaNodeEvents {
|
|
8
|
+
onMouseOver?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
9
|
+
onMouseMove?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
10
|
+
onMouseOut?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
11
|
+
onMouseEnter?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
12
|
+
onMouseLeave?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
13
|
+
onMouseDown?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
14
|
+
onMouseUp?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
15
|
+
onWheel?(evt: Konva.KonvaEventObject<WheelEvent>): void;
|
|
16
|
+
onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
17
|
+
onDblClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
|
|
18
|
+
onTouchStart?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
19
|
+
onTouchMove?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
20
|
+
onTouchEnd?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
21
|
+
onTap?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
22
|
+
onDblTap?(evt: Konva.KonvaEventObject<TouchEvent>): void;
|
|
23
|
+
onDragStart?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
24
|
+
onDragMove?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
25
|
+
onDragEnd?(evt: Konva.KonvaEventObject<DragEvent>): void;
|
|
26
|
+
onTransform?(evt: Konva.KonvaEventObject<Event>): void;
|
|
27
|
+
onTransformStart?(evt: Konva.KonvaEventObject<Event>): void;
|
|
28
|
+
onTransformEnd?(evt: Konva.KonvaEventObject<Event>): void;
|
|
29
|
+
onContextMenu?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
30
|
+
onPointerDown?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
31
|
+
onPointerMove?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
32
|
+
onPointerUp?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
33
|
+
onPointerCancel?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
34
|
+
onPointerEnter?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
35
|
+
onPointerLeave?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
36
|
+
onPointerOver?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
37
|
+
onPointerOut?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
38
|
+
onPointerClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
39
|
+
onPointerDblClick?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
40
|
+
onGotPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
41
|
+
onLostPointerCapture?(evt: Konva.KonvaEventObject<PointerEvent>): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface KonvaNodeComponent<
|
|
45
|
+
Node extends Konva.Node,
|
|
46
|
+
Props = Konva.NodeConfig
|
|
47
|
+
// We use React.ClassAttributes to fake the 'ref' attribute. This will ensure
|
|
48
|
+
// consumers get the proper 'Node' type in 'ref' instead of the wrapper
|
|
49
|
+
// component type.
|
|
50
|
+
> extends React.FC<Props & KonvaNodeEvents & React.ClassAttributes<Node>> {
|
|
51
|
+
getPublicInstance(): Node;
|
|
52
|
+
getNativeNode(): Node;
|
|
53
|
+
// putEventListener(type: string, listener: Function): void;
|
|
54
|
+
// handleEvent(event: Event): void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface StageProps
|
|
58
|
+
extends Konva.NodeConfig,
|
|
59
|
+
KonvaNodeEvents,
|
|
60
|
+
Pick<
|
|
61
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
62
|
+
'className' | 'role' | 'style' | 'tabIndex' | 'title'
|
|
63
|
+
> {}
|
|
64
|
+
|
|
65
|
+
// Stage is the only real class because the others are stubs that only know how
|
|
66
|
+
// to be rendered when they are under stage. Since there is no real backing
|
|
67
|
+
// class and are in reality are a string literal we don't want users to actually
|
|
68
|
+
// try and use them as a type. By defining them as a variable with an interface
|
|
69
|
+
// consumers will not be able to use the values as a type or constructor.
|
|
70
|
+
// The down side to this approach, is that typescript thinks the type is a
|
|
71
|
+
// function, but if the user tries to call it a runtime exception will occur.
|
|
72
|
+
|
|
73
|
+
export var Stage: KonvaNodeComponent<Konva.Stage, StageProps>;
|
|
74
|
+
export var Layer: KonvaNodeComponent<Konva.Layer, Konva.LayerConfig>;
|
|
75
|
+
export var FastLayer: KonvaNodeComponent<Konva.FastLayer, Konva.LayerConfig>;
|
|
76
|
+
export var Group: KonvaNodeComponent<Konva.Group, Konva.GroupConfig>;
|
|
77
|
+
export var Label: KonvaNodeComponent<Konva.Label, Konva.LabelConfig>;
|
|
78
|
+
|
|
79
|
+
/** Shapes */
|
|
80
|
+
export var Rect: KonvaNodeComponent<Konva.Rect, Konva.RectConfig>;
|
|
81
|
+
export var Circle: KonvaNodeComponent<Konva.Circle, Konva.CircleConfig>;
|
|
82
|
+
export var Ellipse: KonvaNodeComponent<Konva.Ellipse, Konva.EllipseConfig>;
|
|
83
|
+
export var Wedge: KonvaNodeComponent<Konva.Wedge, Konva.WedgeConfig>;
|
|
84
|
+
export var Transformer: KonvaNodeComponent<
|
|
85
|
+
Konva.Transformer,
|
|
86
|
+
Konva.TransformerConfig
|
|
87
|
+
>;
|
|
88
|
+
export var Line: KonvaNodeComponent<Konva.Line, Konva.LineConfig>;
|
|
89
|
+
export var Sprite: KonvaNodeComponent<Konva.Sprite, Konva.SpriteConfig>;
|
|
90
|
+
export var Image: KonvaNodeComponent<Konva.Image, Konva.ImageConfig>;
|
|
91
|
+
export var Text: KonvaNodeComponent<Konva.Text, Konva.TextConfig>;
|
|
92
|
+
export var TextPath: KonvaNodeComponent<Konva.TextPath, Konva.TextPathConfig>;
|
|
93
|
+
export var Star: KonvaNodeComponent<Konva.Star, Konva.StarConfig>;
|
|
94
|
+
export var Ring: KonvaNodeComponent<Konva.Ring, Konva.RingConfig>;
|
|
95
|
+
export var Arc: KonvaNodeComponent<Konva.Arc, Konva.ArcConfig>;
|
|
96
|
+
export var Tag: KonvaNodeComponent<Konva.Tag, Konva.TagConfig>;
|
|
97
|
+
export var Path: KonvaNodeComponent<Konva.Path, Konva.PathConfig>;
|
|
98
|
+
export var RegularPolygon: KonvaNodeComponent<
|
|
99
|
+
Konva.RegularPolygon,
|
|
100
|
+
Konva.RegularPolygonConfig
|
|
101
|
+
>;
|
|
102
|
+
export var Arrow: KonvaNodeComponent<Konva.Arrow, Konva.ArrowConfig>;
|
|
103
|
+
export var Shape: KonvaNodeComponent<Konva.Shape, Konva.ShapeConfig>;
|
|
104
|
+
|
|
105
|
+
export var useStrictMode: (useStrictMode: boolean) => void;
|
|
106
|
+
export var KonvaRenderer: ReactReconciler.Reconciler<
|
|
107
|
+
any,
|
|
108
|
+
any,
|
|
109
|
+
any,
|
|
110
|
+
any,
|
|
111
|
+
any,
|
|
112
|
+
any
|
|
113
|
+
>;
|
|
114
|
+
|
|
115
|
+
export var version: string;
|
|
116
|
+
|
|
117
|
+
export { useContextBridge };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Based on ReactArt.js
|
|
3
|
+
* Copyright (c) 2017-present Lavrenov Anton.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* MIT
|
|
7
|
+
*/
|
|
8
|
+
'use strict';
|
|
9
|
+
import React from 'react';
|
|
10
|
+
if (React.version.indexOf('19') === -1) {
|
|
11
|
+
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.');
|
|
12
|
+
}
|
|
13
|
+
import Konva from 'konva/lib/Core.js';
|
|
14
|
+
import ReactFiberReconciler from 'react-reconciler';
|
|
15
|
+
import { ConcurrentRoot } from 'react-reconciler/constants.js';
|
|
16
|
+
import * as HostConfig from './ReactKonvaHostConfig.js';
|
|
17
|
+
import { applyNodeProps, toggleStrictMode } from './makeUpdates.js';
|
|
18
|
+
import { useContextBridge, FiberProvider } from 'its-fine';
|
|
19
|
+
function usePrevious(value) {
|
|
20
|
+
const ref = React.useRef({});
|
|
21
|
+
React.useLayoutEffect(() => {
|
|
22
|
+
ref.current = value;
|
|
23
|
+
});
|
|
24
|
+
React.useLayoutEffect(() => {
|
|
25
|
+
return () => {
|
|
26
|
+
// when using suspense it is possible that stage is unmounted
|
|
27
|
+
// but React still keep component ref
|
|
28
|
+
// in that case we need to manually flush props
|
|
29
|
+
// we have a special test for that
|
|
30
|
+
ref.current = {};
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
return ref.current;
|
|
34
|
+
}
|
|
35
|
+
const useIsReactStrictMode = () => {
|
|
36
|
+
const memoCount = React.useRef(0);
|
|
37
|
+
// in strict mode, memo will be called twice
|
|
38
|
+
React.useMemo(() => {
|
|
39
|
+
memoCount.current++;
|
|
40
|
+
}, []);
|
|
41
|
+
return memoCount.current > 1;
|
|
42
|
+
};
|
|
43
|
+
const StageWrap = (props) => {
|
|
44
|
+
const container = React.useRef(null);
|
|
45
|
+
const stage = React.useRef(null);
|
|
46
|
+
const fiberRef = React.useRef(null);
|
|
47
|
+
const oldProps = usePrevious(props);
|
|
48
|
+
const Bridge = useContextBridge();
|
|
49
|
+
const pendingDestroy = React.useRef(null);
|
|
50
|
+
const _setRef = (stage) => {
|
|
51
|
+
const { forwardedRef } = props;
|
|
52
|
+
if (!forwardedRef) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (typeof forwardedRef === 'function') {
|
|
56
|
+
forwardedRef(stage);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
forwardedRef.current = stage;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const isStrictMode = useIsReactStrictMode();
|
|
63
|
+
const destroyStage = () => {
|
|
64
|
+
_setRef(null);
|
|
65
|
+
// CRITICAL: flushSyncFromReconciler is required here to ensure pending work
|
|
66
|
+
// (e.g. stale MobX updates on child components) is flushed synchronously
|
|
67
|
+
// before the tree is torn down. Without it, unmounting a Stage can leave
|
|
68
|
+
// pending Konva work that runs after the stage is already destroyed.
|
|
69
|
+
KonvaRenderer.flushSyncFromReconciler(() => {
|
|
70
|
+
KonvaRenderer.updateContainer(null, fiberRef.current, null);
|
|
71
|
+
});
|
|
72
|
+
stage.current?.destroy();
|
|
73
|
+
stage.current = null;
|
|
74
|
+
};
|
|
75
|
+
React.useLayoutEffect(() => {
|
|
76
|
+
// Cancel any pending destruction (happens during re-ordering in strict mode)
|
|
77
|
+
if (pendingDestroy.current) {
|
|
78
|
+
clearTimeout(pendingDestroy.current);
|
|
79
|
+
pendingDestroy.current = null;
|
|
80
|
+
}
|
|
81
|
+
// If stage already exists (re-ordering scenario), reuse it
|
|
82
|
+
if (stage.current) {
|
|
83
|
+
_setRef(stage.current);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
stage.current = new Konva.Stage({
|
|
87
|
+
width: props.width,
|
|
88
|
+
height: props.height,
|
|
89
|
+
container: container.current,
|
|
90
|
+
});
|
|
91
|
+
_setRef(stage.current);
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
fiberRef.current = KonvaRenderer.createContainer(stage.current, ConcurrentRoot, null, false, null, '', console.error, console.error, console.error, null);
|
|
94
|
+
KonvaRenderer.updateContainer(React.createElement(Bridge, {}, props.children), fiberRef.current, null, () => { });
|
|
95
|
+
}
|
|
96
|
+
return () => {
|
|
97
|
+
if (isStrictMode) {
|
|
98
|
+
// Delay destruction to allow cancellation on remount
|
|
99
|
+
pendingDestroy.current = setTimeout(destroyStage, 0);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
destroyStage();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}, []);
|
|
106
|
+
React.useLayoutEffect(() => {
|
|
107
|
+
_setRef(stage.current);
|
|
108
|
+
applyNodeProps(stage.current, props, oldProps);
|
|
109
|
+
// =============================================================================
|
|
110
|
+
// CRITICAL FIX - DO NOT REMOVE
|
|
111
|
+
// =============================================================================
|
|
112
|
+
// This flushSyncFromReconciler wrapper is CRITICAL for React 19 compatibility.
|
|
113
|
+
//
|
|
114
|
+
// THE BUG:
|
|
115
|
+
// When using useSyncExternalStore (MobX, Zustand, etc.) with react-konva,
|
|
116
|
+
// parent component's useLayoutEffect couldn't find newly added Konva nodes.
|
|
117
|
+
// The nodes were added to the store, but not yet rendered to the canvas.
|
|
118
|
+
//
|
|
119
|
+
// ROOT CAUSE:
|
|
120
|
+
// React 19's updateContainer can defer Konva reconciler work to a later
|
|
121
|
+
// microtask. Combined with Bridge component (from its-fine) and Html components
|
|
122
|
+
// that create secondary React roots, this caused child components to render
|
|
123
|
+
// AFTER parent's useLayoutEffect completed.
|
|
124
|
+
//
|
|
125
|
+
// THE FIX:
|
|
126
|
+
// flushSyncFromReconciler forces ALL scheduled Konva reconciler work to
|
|
127
|
+
// complete synchronously within this useLayoutEffect, ensuring child
|
|
128
|
+
// components render before any parent effects run.
|
|
129
|
+
//
|
|
130
|
+
// WARNING - NOT COVERED BY TESTS:
|
|
131
|
+
// This bug CANNOT be reproduced in local test environments (Vitest/Playwright).
|
|
132
|
+
// It only manifests in production builds with specific conditions:
|
|
133
|
+
// - MobX/useSyncExternalStore for state management
|
|
134
|
+
// - Html components with secondary React roots using Bridge
|
|
135
|
+
// - Complex component hierarchies (multiple pages/stages)
|
|
136
|
+
// The fix was verified in Polotno production app.
|
|
137
|
+
// =============================================================================
|
|
138
|
+
KonvaRenderer.flushSyncFromReconciler(() => {
|
|
139
|
+
KonvaRenderer.updateContainer(React.createElement(Bridge, {}, props.children), fiberRef.current, null);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
return React.createElement('div', {
|
|
143
|
+
ref: container,
|
|
144
|
+
id: props.id,
|
|
145
|
+
accessKey: props.accessKey,
|
|
146
|
+
className: props.className,
|
|
147
|
+
role: props.role,
|
|
148
|
+
style: props.style,
|
|
149
|
+
tabIndex: props.tabIndex,
|
|
150
|
+
title: props.title,
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
export const Layer = 'Layer';
|
|
154
|
+
export const FastLayer = 'FastLayer';
|
|
155
|
+
export const Group = 'Group';
|
|
156
|
+
export const Label = 'Label';
|
|
157
|
+
export const Rect = 'Rect';
|
|
158
|
+
export const Circle = 'Circle';
|
|
159
|
+
export const Ellipse = 'Ellipse';
|
|
160
|
+
export const Wedge = 'Wedge';
|
|
161
|
+
export const Line = 'Line';
|
|
162
|
+
export const Sprite = 'Sprite';
|
|
163
|
+
export const Image = 'Image';
|
|
164
|
+
export const Text = 'Text';
|
|
165
|
+
export const TextPath = 'TextPath';
|
|
166
|
+
export const Star = 'Star';
|
|
167
|
+
export const Ring = 'Ring';
|
|
168
|
+
export const Arc = 'Arc';
|
|
169
|
+
export const Tag = 'Tag';
|
|
170
|
+
export const Path = 'Path';
|
|
171
|
+
export const RegularPolygon = 'RegularPolygon';
|
|
172
|
+
export const Arrow = 'Arrow';
|
|
173
|
+
export const Shape = 'Shape';
|
|
174
|
+
export const Transformer = 'Transformer';
|
|
175
|
+
export const version = '19.2.3';
|
|
176
|
+
// @ts-ignore
|
|
177
|
+
export const KonvaRenderer = ReactFiberReconciler(HostConfig);
|
|
178
|
+
// Update Stage component declaration
|
|
179
|
+
export const Stage = React.forwardRef((props, ref) => {
|
|
180
|
+
return React.createElement(FiberProvider, {}, React.createElement(StageWrap, { ...props, forwardedRef: ref }));
|
|
181
|
+
});
|
|
182
|
+
export const useStrictMode = toggleStrictMode;
|
|
183
|
+
// export useContextBridge from its-fine for reuse in react-konva-utils
|
|
184
|
+
// so react-konva-utils don't use its own version of its-fine (it is possible on pnpm)
|
|
185
|
+
export { useContextBridge };
|