@cs-open/react-fabric 0.0.6 → 0.0.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.
Files changed (213) hide show
  1. package/README.md +132 -0
  2. package/dist/cjs/components/BackgroundImage/index.cjs +1 -1
  3. package/dist/cjs/components/BackgroundImage/index.cjs.map +1 -1
  4. package/dist/cjs/components/Canvas/index.cjs +1 -1
  5. package/dist/cjs/components/Canvas/index.cjs.map +1 -1
  6. package/dist/cjs/components/Control/index.cjs +1 -1
  7. package/dist/cjs/components/Control/index.cjs.map +1 -1
  8. package/dist/cjs/components/Control2/index.cjs +2 -0
  9. package/dist/cjs/components/Control2/index.cjs.map +1 -0
  10. package/dist/cjs/components/Ellipse/index.cjs +1 -1
  11. package/dist/cjs/components/Ellipse/index.cjs.map +1 -1
  12. package/dist/cjs/components/Group/index.cjs +1 -1
  13. package/dist/cjs/components/Group/index.cjs.map +1 -1
  14. package/dist/cjs/components/IText/index.cjs +2 -0
  15. package/dist/cjs/components/IText/index.cjs.map +1 -0
  16. package/dist/cjs/components/Image/index.cjs +1 -1
  17. package/dist/cjs/components/Image/index.cjs.map +1 -1
  18. package/dist/cjs/components/Line/index.cjs +1 -1
  19. package/dist/cjs/components/Line/index.cjs.map +1 -1
  20. package/dist/cjs/components/Loading/index.cjs +11 -0
  21. package/dist/cjs/components/Loading/index.cjs.map +1 -0
  22. package/dist/cjs/components/NodeToolbarPortal/index.cjs +1 -1
  23. package/dist/cjs/components/NodeToolbarPortal/index.cjs.map +1 -1
  24. package/dist/cjs/components/Objects/index.cjs +1 -1
  25. package/dist/cjs/components/Objects/index.cjs.map +1 -1
  26. package/dist/cjs/components/Path/index.cjs +1 -1
  27. package/dist/cjs/components/Path/index.cjs.map +1 -1
  28. package/dist/cjs/components/Polyline/index.cjs +2 -0
  29. package/dist/cjs/components/Polyline/index.cjs.map +1 -0
  30. package/dist/cjs/components/ReactFabricProvider.cjs +1 -1
  31. package/dist/cjs/components/Rect/index.cjs +1 -1
  32. package/dist/cjs/components/Rect/index.cjs.map +1 -1
  33. package/dist/cjs/components/StoreUpdater/index.cjs +1 -1
  34. package/dist/cjs/components/StoreUpdater/index.cjs.map +1 -1
  35. package/dist/cjs/components/Text/index.cjs +1 -1
  36. package/dist/cjs/components/Text/index.cjs.map +1 -1
  37. package/dist/cjs/components/Textbox/index.cjs +2 -0
  38. package/dist/cjs/components/Textbox/index.cjs.map +1 -0
  39. package/dist/cjs/components/WavyLine/index.cjs +2 -0
  40. package/dist/cjs/components/WavyLine/index.cjs.map +1 -0
  41. package/dist/cjs/container/ReactFabric/index.cjs +1 -1
  42. package/dist/cjs/container/ReactFabric/index.cjs.map +1 -1
  43. package/dist/cjs/hooks/useCreateObject.cjs +1 -1
  44. package/dist/cjs/hooks/useCreateObject.cjs.map +1 -1
  45. package/dist/cjs/hooks/useDidUpdate.cjs +1 -1
  46. package/dist/cjs/hooks/useDraggable.cjs +1 -1
  47. package/dist/cjs/hooks/useInstancePosition.cjs +2 -0
  48. package/dist/cjs/hooks/useInstancePosition.cjs.map +1 -0
  49. package/dist/cjs/hooks/useReactFabric.cjs +1 -1
  50. package/dist/cjs/hooks/useReactFabric.cjs.map +1 -1
  51. package/dist/cjs/hooks/useResizeHandler.cjs +1 -1
  52. package/dist/cjs/hooks/useResizeHandler.cjs.map +1 -1
  53. package/dist/cjs/hooks/useSplitProps.cjs +1 -1
  54. package/dist/cjs/hooks/useStore.cjs +1 -1
  55. package/dist/cjs/hooks/useStore.cjs.map +1 -1
  56. package/dist/cjs/index.cjs +1 -1
  57. package/dist/cjs/plugins/FreeDraw.cjs +2 -0
  58. package/dist/cjs/plugins/FreeDraw.cjs.map +1 -0
  59. package/dist/cjs/plugins/FreeRect.cjs +1 -1
  60. package/dist/cjs/plugins/FreeText.cjs +2 -0
  61. package/dist/cjs/plugins/FreeText.cjs.map +1 -0
  62. package/dist/cjs/plugins/Mask.cjs +2 -0
  63. package/dist/cjs/plugins/Mask.cjs.map +1 -0
  64. package/dist/cjs/plugins/Pinch.cjs +1 -1
  65. package/dist/cjs/plugins/Pinch.cjs.map +1 -1
  66. package/dist/cjs/plugins/index.cjs +2 -0
  67. package/dist/cjs/plugins/index.cjs.map +1 -0
  68. package/dist/cjs/store/index.cjs +1 -1
  69. package/dist/cjs/store/index.cjs.map +1 -1
  70. package/dist/cjs/store/initialState.cjs +1 -1
  71. package/dist/cjs/store/initialState.cjs.map +1 -1
  72. package/dist/cjs/utils/business.cjs +2 -0
  73. package/dist/cjs/utils/business.cjs.map +1 -0
  74. package/dist/cjs/utils/childrenWithPosition.cjs +2 -0
  75. package/dist/cjs/utils/childrenWithPosition.cjs.map +1 -0
  76. package/dist/esm/components/BackgroundImage/index.mjs +1 -1
  77. package/dist/esm/components/BackgroundImage/index.mjs.map +1 -1
  78. package/dist/esm/components/Canvas/index.mjs +1 -1
  79. package/dist/esm/components/Canvas/index.mjs.map +1 -1
  80. package/dist/esm/components/Control/index.mjs +1 -1
  81. package/dist/esm/components/Control/index.mjs.map +1 -1
  82. package/dist/esm/components/Control2/index.mjs +2 -0
  83. package/dist/esm/components/Control2/index.mjs.map +1 -0
  84. package/dist/esm/components/Ellipse/index.mjs +1 -1
  85. package/dist/esm/components/Ellipse/index.mjs.map +1 -1
  86. package/dist/esm/components/Group/index.mjs.map +1 -1
  87. package/dist/esm/components/IText/index.mjs +2 -0
  88. package/dist/esm/components/IText/index.mjs.map +1 -0
  89. package/dist/esm/components/Image/index.mjs +2 -0
  90. package/dist/esm/components/Image/index.mjs.map +1 -0
  91. package/dist/esm/components/Line/index.mjs +1 -1
  92. package/dist/esm/components/Line/index.mjs.map +1 -1
  93. package/dist/esm/components/Loading/index.mjs +11 -0
  94. package/dist/esm/components/Loading/index.mjs.map +1 -0
  95. package/dist/esm/components/NodeToolbarPortal/index.mjs +1 -1
  96. package/dist/esm/components/NodeToolbarPortal/index.mjs.map +1 -1
  97. package/dist/esm/components/Objects/index.mjs +1 -1
  98. package/dist/esm/components/Objects/index.mjs.map +1 -1
  99. package/dist/esm/components/Path/index.mjs +1 -1
  100. package/dist/esm/components/Path/index.mjs.map +1 -1
  101. package/dist/esm/components/Rect/index.mjs +1 -1
  102. package/dist/esm/components/Rect/index.mjs.map +1 -1
  103. package/dist/esm/components/StoreUpdater/index.mjs +1 -1
  104. package/dist/esm/components/StoreUpdater/index.mjs.map +1 -1
  105. package/dist/esm/components/Text/index.mjs +1 -1
  106. package/dist/esm/components/Text/index.mjs.map +1 -1
  107. package/dist/esm/components/Textbox/index.mjs +2 -0
  108. package/dist/esm/components/Textbox/index.mjs.map +1 -0
  109. package/dist/esm/components/WavyLine/index.mjs +2 -0
  110. package/dist/esm/components/WavyLine/index.mjs.map +1 -0
  111. package/dist/esm/container/ReactFabric/index.mjs +1 -1
  112. package/dist/esm/container/ReactFabric/index.mjs.map +1 -1
  113. package/dist/esm/hooks/useCreateObject.mjs.map +1 -1
  114. package/dist/esm/hooks/useInstancePosition.mjs +2 -0
  115. package/dist/esm/hooks/useInstancePosition.mjs.map +1 -0
  116. package/dist/esm/hooks/useReactFabric.mjs +1 -1
  117. package/dist/esm/hooks/useReactFabric.mjs.map +1 -1
  118. package/dist/esm/hooks/useResizeHandler.mjs +1 -1
  119. package/dist/esm/hooks/useResizeHandler.mjs.map +1 -1
  120. package/dist/esm/hooks/useStore.mjs +1 -1
  121. package/dist/esm/hooks/useStore.mjs.map +1 -1
  122. package/dist/esm/index.mjs +1 -1
  123. package/dist/esm/plugins/FreeDraw.mjs +2 -0
  124. package/dist/esm/plugins/FreeDraw.mjs.map +1 -0
  125. package/dist/esm/plugins/FreeText.mjs +2 -0
  126. package/dist/esm/plugins/FreeText.mjs.map +1 -0
  127. package/dist/esm/plugins/Pinch.mjs +1 -1
  128. package/dist/esm/plugins/Pinch.mjs.map +1 -1
  129. package/dist/esm/store/index.mjs +1 -1
  130. package/dist/esm/store/index.mjs.map +1 -1
  131. package/dist/esm/store/initialState.mjs +1 -1
  132. package/dist/esm/store/initialState.mjs.map +1 -1
  133. package/dist/esm/utils/business.mjs +2 -0
  134. package/dist/esm/utils/business.mjs.map +1 -0
  135. package/dist/esm/utils/childrenWithPosition.mjs +2 -0
  136. package/dist/esm/utils/childrenWithPosition.mjs.map +1 -0
  137. package/dist/esm/utils/constants.mjs +1 -1
  138. package/dist/esm/utils/constants.mjs.map +1 -1
  139. package/dist/esm/utils/dom.mjs +2 -0
  140. package/dist/esm/utils/dom.mjs.map +1 -0
  141. package/dist/esm/utils/position.mjs +2 -0
  142. package/dist/esm/utils/position.mjs.map +1 -0
  143. package/dist/esm/utils/props.mjs +1 -1
  144. package/dist/esm/utils/props.mjs.map +1 -1
  145. package/dist/types/components/BackgroundImage/index.d.ts.map +1 -1
  146. package/dist/types/components/Canvas/index.d.ts.map +1 -1
  147. package/dist/types/components/Control/index.d.ts.map +1 -1
  148. package/dist/types/components/Control2/index.d.ts +28 -0
  149. package/dist/types/components/Control2/index.d.ts.map +1 -0
  150. package/dist/types/components/Ellipse/index.d.ts +3 -0
  151. package/dist/types/components/Ellipse/index.d.ts.map +1 -1
  152. package/dist/types/components/Group/index.d.ts.map +1 -1
  153. package/dist/types/components/IText/index.d.ts +12 -0
  154. package/dist/types/components/IText/index.d.ts.map +1 -0
  155. package/dist/types/components/Image/index.d.ts +4 -4
  156. package/dist/types/components/Image/index.d.ts.map +1 -1
  157. package/dist/types/components/Line/index.d.ts +2 -0
  158. package/dist/types/components/Line/index.d.ts.map +1 -1
  159. package/dist/types/components/Loading/index.d.ts +3 -0
  160. package/dist/types/components/Loading/index.d.ts.map +1 -0
  161. package/dist/types/components/NodeToolbarPortal/index.d.ts.map +1 -1
  162. package/dist/types/components/Objects/index.d.ts.map +1 -1
  163. package/dist/types/components/Path/index.d.ts +2 -0
  164. package/dist/types/components/Path/index.d.ts.map +1 -1
  165. package/dist/types/components/Polyline/index.d.ts +12 -0
  166. package/dist/types/components/Polyline/index.d.ts.map +1 -0
  167. package/dist/types/components/Rect/index.d.ts +4 -2
  168. package/dist/types/components/Rect/index.d.ts.map +1 -1
  169. package/dist/types/components/StoreUpdater/index.d.ts +1 -1
  170. package/dist/types/components/StoreUpdater/index.d.ts.map +1 -1
  171. package/dist/types/components/Text/index.d.ts +2 -0
  172. package/dist/types/components/Text/index.d.ts.map +1 -1
  173. package/dist/types/components/Textbox/index.d.ts +12 -0
  174. package/dist/types/components/Textbox/index.d.ts.map +1 -0
  175. package/dist/types/components/WavyLine/index.d.ts +12 -0
  176. package/dist/types/components/WavyLine/index.d.ts.map +1 -0
  177. package/dist/types/container/ReactFabric/index.d.ts +4 -0
  178. package/dist/types/container/ReactFabric/index.d.ts.map +1 -1
  179. package/dist/types/hooks/useCreateObject.d.ts.map +1 -1
  180. package/dist/types/hooks/useInstancePosition.d.ts +12 -0
  181. package/dist/types/hooks/useInstancePosition.d.ts.map +1 -0
  182. package/dist/types/hooks/useReactFabric.d.ts +1 -1
  183. package/dist/types/hooks/useReactFabric.d.ts.map +1 -1
  184. package/dist/types/hooks/useResizeHandler.d.ts.map +1 -1
  185. package/dist/types/index.d.ts +13 -6
  186. package/dist/types/index.d.ts.map +1 -1
  187. package/dist/types/plugins/FreeDraw.d.ts +9 -0
  188. package/dist/types/plugins/FreeDraw.d.ts.map +1 -0
  189. package/dist/types/plugins/FreeText.d.ts +11 -0
  190. package/dist/types/plugins/FreeText.d.ts.map +1 -0
  191. package/dist/types/plugins/Mask.d.ts +8 -0
  192. package/dist/types/plugins/Mask.d.ts.map +1 -0
  193. package/dist/types/plugins/Pinch.d.ts +15 -3
  194. package/dist/types/plugins/Pinch.d.ts.map +1 -1
  195. package/dist/types/plugins/index.d.ts +7 -0
  196. package/dist/types/plugins/index.d.ts.map +1 -0
  197. package/dist/types/store/index.d.ts.map +1 -1
  198. package/dist/types/store/initialState.d.ts.map +1 -1
  199. package/dist/types/types/component-props.d.ts +0 -35
  200. package/dist/types/types/component-props.d.ts.map +1 -1
  201. package/dist/types/types/store.d.ts +13 -0
  202. package/dist/types/types/store.d.ts.map +1 -1
  203. package/dist/types/utils/business.d.ts +83 -0
  204. package/dist/types/utils/business.d.ts.map +1 -0
  205. package/dist/types/utils/childrenWithPosition.d.ts +6 -0
  206. package/dist/types/utils/childrenWithPosition.d.ts.map +1 -0
  207. package/package.json +22 -18
  208. package/dist/cjs/toolbar/Vertical/index.cjs +0 -2
  209. package/dist/cjs/toolbar/Vertical/index.cjs.map +0 -1
  210. package/dist/esm/toolbar/Vertical/index.mjs +0 -2
  211. package/dist/esm/toolbar/Vertical/index.mjs.map +0 -1
  212. package/dist/types/toolbar/Vertical/index.d.ts +0 -10
  213. package/dist/types/toolbar/Vertical/index.d.ts.map +0 -1
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @cs-open/react-fabric
2
+
3
+ React 组件库,基于 Fabric.js 构建,提供强大的 Canvas 绘图功能。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @cs-open/react-fabric
9
+ # 或者
10
+ yarn add @cs-open/react-fabric
11
+ # 或者
12
+ pnpm add @cs-open/react-fabric
13
+ ```
14
+
15
+ ## 依赖要求
16
+
17
+ ### 必需依赖
18
+
19
+ 以下依赖会自动安装:
20
+
21
+ - `fabric` - Fabric.js 核心库
22
+ - `react` - React 框架
23
+ - `react-dom` - React DOM 渲染器
24
+ - `zustand` - 状态管理
25
+ - `@floating-ui/core` - 浮动 UI 组件
26
+ - `use-sync-external-store` - 同步外部存储
27
+
28
+ ### 可选依赖
29
+
30
+ 某些插件需要额外的依赖才能正常工作:
31
+
32
+ #### Pinch 插件(触摸手势支持)
33
+
34
+ ```bash
35
+ npm install hammerjs
36
+ # 如果使用 TypeScript,还需要安装类型定义
37
+ npm install @types/hammerjs
38
+ ```
39
+
40
+ **注意**:如果没有安装 `hammerjs`,Pinch 插件会自动禁用,不会影响其他功能。
41
+
42
+ ## 使用示例
43
+
44
+ ```tsx
45
+ import React from 'react'
46
+ import { Canvas, Rect, Text } from '@cs-open/react-fabric'
47
+
48
+ function App() {
49
+ return (
50
+ <Canvas width={800} height={600}>
51
+ <Rect left={100} top={100} width={200} height={100} fill="red" />
52
+ <Text left={150} top={150} text="Hello Fabric!" fontSize={20} fill="white" />
53
+ </Canvas>
54
+ )
55
+ }
56
+
57
+ export default App
58
+ ```
59
+
60
+ ## 插件系统
61
+
62
+ ### 内置插件
63
+
64
+ - **Pinch**: 触摸设备双指缩放支持
65
+ - **FreeDraw**: 自由绘制工具
66
+ - **FreeRect**: 自由矩形绘制工具
67
+ - **FreeText**: 自由文本工具
68
+ - **GridLine**: 网格线辅助工具
69
+ - **Mask**: 遮罩效果
70
+ - **Pinch**: 触摸手势支持
71
+
72
+ ### 使用插件
73
+
74
+ ```tsx
75
+ import { Canvas } from '@cs-open/react-fabric'
76
+ import { Pinch, FreeDraw } from '@cs-open/react-fabric/plugins'
77
+
78
+ function App() {
79
+ return (
80
+ <Canvas width={800} height={600}>
81
+ {/* 你的画布内容 */}
82
+ <Pinch />
83
+ <FreeDraw />
84
+ </Canvas>
85
+ )
86
+ }
87
+ ```
88
+
89
+ ## 故障排除
90
+
91
+ ### Pinch 插件不工作
92
+
93
+ 如果触摸手势功能不工作,请确保:
94
+
95
+ 1. 已安装 `hammerjs`:
96
+
97
+ ```bash
98
+ npm install hammerjs
99
+ ```
100
+
101
+ 2. 检查控制台是否有相关警告信息
102
+
103
+ 3. 确保在触摸设备上测试
104
+
105
+ ### 其他问题
106
+
107
+ 如果遇到其他问题,请检查:
108
+
109
+ 1. 所有必需依赖是否正确安装
110
+ 2. 浏览器控制台是否有错误信息
111
+ 3. 确保使用兼容的浏览器版本
112
+
113
+ DOM control
114
+
115
+ ```jsx
116
+ <Rect>
117
+ <div className="w-full h-full bg-red-500">
118
+ <EvaluatesHtml
119
+ type="right"
120
+ pageSize={pageSize}
121
+ allSentences={allSentences}
122
+ isPaperFront={isPaperFront}
123
+ fontSizeMemo={fontSizeMemo / 1.2}
124
+ singleColumnLeft={singleColumnLeft}
125
+ />
126
+ </div>
127
+ </Rect>
128
+ ```
129
+
130
+ ## 许可证
131
+
132
+ MIT
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var f=require("fabric"),i=require("react"),F=require("../../hooks/useDidUpdate.cjs"),w=require("../../hooks/useStore.cjs");const q=n=>({width:n.width,height:n.height}),R=i.forwardRef(({src:n,onLoad:b,onScaling:V,scaleToFit:l,scaleToCover:d,...g},S)=>{const r=i.useRef(null),a=w.useStoreApi(),{width:T,height:p}=w.useStore(q),m=i.useCallback(c=>{const{canvas:e,manualZoom:t=1,defaultCentered:o}=a.getState();if(!r.current)return;if(!e){console.warn("updateViewport: !canvas");return}if(!e.backgroundImage){console.warn("updateViewport: !canvas.backgroundImage");return}const u=c.scaleToFit?f.util.findScaleToFit(r.current,e):c.scaleToCover?f.util.findScaleToCover(r.current,e):1,s=u*t;e.setViewportTransform([s,0,0,s,0,0]);let h=0,v=0;if(o&&e.backgroundImage){const k=e.backgroundImage.width||0,C=e.backgroundImage.height||0;h=(e.width-k*s)/2,v=(e.height-C*s)/2}const I=[s,0,0,s,h,v];e.setViewportTransform(I),e.requestRenderAll(),a.setState({fitZoom:u,manualZoom:t,zoom:s})},[a]);return i.useEffect(()=>{m({scaleToFit:l,scaleToCover:d})},[T,p,l,d,m,a]),i.useEffect(()=>{if(!n){console.warn("ReactFabricBackgroundImage: !src");return}const{domNode:c,setLoading:e}=a.getState();return e(!0),f.FabricImage.fromURL(n,{crossOrigin:"anonymous"}).then(t=>{const{canvas:o}=a.getState();if(o){const u={...g,angle:0};if(t.set({...u,objectCaching:!1}),o.getContext().imageSmoothingEnabled=!0,o.getContext().imageSmoothingQuality="high",o.backgroundImage=t,r.current=t,requestAnimationFrame(()=>{m({scaleToFit:l,scaleToCover:d})}),!o.viewportTransform){console.warn("!viewport");return}b?.(t)}else console.warn("ReactFabric:BackgroundImage: !canvas",o)}).catch(console.error).finally(()=>{c&&(c.dataset.src=n),e(!1)}),()=>{const{canvas:t}=a.getState();t?.backgroundImage&&(t.backgroundImage=void 0,t.remove(r.current),r.current=null,t.renderAll())}},[n]),F.useDidUpdate(()=>{const{canvas:c}=a.getState();r.current&&(Object.entries(g).forEach(([e,t])=>{e==="angle"?r.current?.rotate(t):r.current?.set(e,t)}),c?.requestRenderAll())},[g,a]),i.useImperativeHandle(S,()=>({instance:r.current})),null});var A=i.memo(R);exports.default=A;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var h=require("fabric"),s=require("react"),F=require("../../hooks/useDidUpdate.cjs"),w=require("../../hooks/useStore.cjs");const q=o=>({width:o.width,height:o.height}),R=s.forwardRef(({src:o,onLoad:b,onScaling:V,scaleToFit:l,scaleToCover:g,...d},S)=>{const a=s.useRef(null),n=w.useStoreApi(),{width:T,height:p}=w.useStore(q),m=s.useCallback(c=>{const{canvas:e,manualZoom:r=1,defaultCentered:f}=n.getState();if(!a.current)return;if(!e){console.warn("updateViewport: !canvas");return}if(!e.backgroundImage){console.warn("updateViewport: !canvas.backgroundImage");return}const i=c.scaleToFit?h.util.findScaleToFit(a.current,e):c.scaleToCover?h.util.findScaleToCover(a.current,e):1,t=i*r;e.setViewportTransform([t,0,0,t,0,0]);let u=0,v=0;if(f&&e.backgroundImage){const k=e.backgroundImage.width||0,C=e.backgroundImage.height||0;u=(e.width-k*t)/2,v=(e.height-C*t)/2}const I=[t,0,0,t,u,v];e.setViewportTransform(I),e.requestRenderAll(),n.setState({fitZoom:i,manualZoom:r,zoom:t})},[n]);return s.useEffect(()=>{m({scaleToFit:l,scaleToCover:g})},[T,p,l,g,m,n]),s.useEffect(()=>{if(!o){console.warn("ReactFabricBackgroundImage: !src");return}const{domNode:c,setLoading:e}=n.getState();return e(!0),h.FabricImage.fromURL(o,{crossOrigin:"anonymous"}).then(r=>{const f=r.getSrc(),i=a.current?.getSrc();if(i&&f!==i)return;const{canvas:t}=n.getState();if(t){const u={...d,angle:0};if(r.set({...u,objectCaching:!1}),t.getContext().imageSmoothingEnabled=!0,t.getContext().imageSmoothingQuality="high",t.backgroundImage=r,a.current=r,requestAnimationFrame(()=>{m({scaleToFit:l,scaleToCover:g})}),!t.viewportTransform){console.warn("!viewport");return}b?.(r)}else console.warn("ReactFabric:BackgroundImage: !canvas",t)}).catch(console.error).finally(()=>{c&&(c.dataset.src=o),e(!1)}),()=>{const{canvas:r}=n.getState();r?.backgroundImage&&(r.backgroundImage=void 0,r.remove(a.current),a.current=null,r.renderAll())}},[o]),F.useDidUpdate(()=>{const{canvas:c}=n.getState();a.current&&(Object.entries(d).forEach(([e,r])=>{e==="angle"?a.current?.rotate(r):a.current?.set(e,r)}),c?.requestRenderAll())},[d,n]),s.useImperativeHandle(S,()=>({instance:a.current})),null});var A=s.memo(R);exports.default=A;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/BackgroundImage/index.tsx"],"sourcesContent":["import type {\n BasicTransformEvent,\n ImageProps,\n ObjectEvents,\n SerializedImageProps,\n TDegree,\n TPointerEvent,\n} from 'fabric'\nimport { FabricImage, util } from 'fabric'\nimport { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef } from 'react'\nimport { useDidUpdate } from '../../hooks/useDidUpdate'\nimport { useStore, useStoreApi } from '../../hooks/useStore'\nimport type { ReactFabricState } from '../../types/store'\n\nexport type Handle = {}\n\ntype ScaleMode = {\n scaleToFit?: boolean\n scaleToCover?: boolean\n}\nexport type BackgroundImageProps = Partial<ImageProps> & {\n src: string\n onLoad?: (imageSource: FabricImage<Partial<ImageProps>, SerializedImageProps, ObjectEvents>) => void\n onScaling?: (scale: BasicTransformEvent<TPointerEvent>) => void\n\n /** 自动缩放至容器宽高 */\n} & ScaleMode\n\nconst selector = (s: ReactFabricState) => ({\n width: s.width,\n height: s.height,\n})\n\nconst BackgroundImage = forwardRef<Handle, BackgroundImageProps>(\n ({ src, onLoad, onScaling, scaleToFit, scaleToCover, ...options }, ref) => {\n const backgroundImageRef = useRef<FabricImage | null>(null)\n\n const store = useStoreApi()\n\n const { width, height } = useStore(selector)\n\n const updateViewport = useCallback(\n (params: { scaleToFit?: boolean; scaleToCover?: boolean }) => {\n const { canvas, manualZoom = 1, defaultCentered } = store.getState()\n if (!backgroundImageRef.current) {\n return\n }\n if (!canvas) {\n console.warn('updateViewport: !canvas')\n return\n }\n if (!canvas.backgroundImage) {\n console.warn('updateViewport: !canvas.backgroundImage')\n return\n }\n\n // 1. 计算缩放\n const fitZoom = params.scaleToFit\n ? util.findScaleToFit(backgroundImageRef.current, canvas)\n : params.scaleToCover\n ? util.findScaleToCover(backgroundImageRef.current, canvas)\n : 1\n\n const combinedZoom = fitZoom * manualZoom\n\n // 2. 先应用基础缩放\n canvas.setViewportTransform([combinedZoom, 0, 0, combinedZoom, 0, 0])\n\n // 3. 如果需要居中,计算偏移量\n let deltaX = 0\n let deltaY = 0\n\n if (defaultCentered && canvas.backgroundImage) {\n const bgWidth = canvas.backgroundImage.width || 0\n const bgHeight = canvas.backgroundImage.height || 0\n deltaX = (canvas.width! - bgWidth * combinedZoom) / 2\n deltaY = (canvas.height! - bgHeight * combinedZoom) / 2\n // const canvasCenter = {\n // x: canvas.width! / 2,\n // y: canvas.height! / 2,\n // }\n // const bgCenter = {\n // x:\n // (canvas.backgroundImage.left! + (canvas.backgroundImage.width! * canvas.backgroundImage.scaleX!) / 2) *\n // combinedZoom,\n // y:\n // (canvas.backgroundImage.top! + (canvas.backgroundImage.height! * canvas.backgroundImage.scaleY!) / 2) *\n // combinedZoom,\n // }\n // deltaX = canvasCenter.x - bgCenter.x\n // deltaY = canvasCenter.y - bgCenter.y\n }\n\n // 4. 应用最终变换\n const finalTransform: [number, number, number, number, number, number] = [\n combinedZoom,\n 0,\n 0,\n combinedZoom,\n deltaX,\n deltaY,\n ]\n\n canvas.setViewportTransform(finalTransform)\n canvas.requestRenderAll()\n\n // 5. 更新 store\n store.setState({\n fitZoom,\n manualZoom,\n zoom: combinedZoom,\n })\n },\n [store],\n )\n\n // 监听 width, height 的变化\n useEffect(() => {\n updateViewport({\n scaleToFit,\n scaleToCover,\n })\n }, [width, height, scaleToFit, scaleToCover, updateViewport, store])\n\n useEffect(() => {\n if (!src) {\n console.warn('ReactFabricBackgroundImage: !src')\n return\n }\n const { domNode, setLoading } = store.getState()\n setLoading(true)\n FabricImage.fromURL(src, { crossOrigin: 'anonymous' })\n .then(imageSource => {\n const { canvas } = store.getState()\n if (canvas) {\n // 初始化时角度的旋转,一定要放到 updateViewport 之后;先画正图片,再进行旋转\n const removeAngleOptions = { ...options, angle: 0 }\n imageSource.set({\n ...removeAngleOptions,\n objectCaching: false,\n })\n canvas.getContext().imageSmoothingEnabled = true\n canvas.getContext().imageSmoothingQuality = 'high'\n canvas.backgroundImage = imageSource\n backgroundImageRef.current = imageSource\n\n requestAnimationFrame(() => {\n updateViewport({\n scaleToFit,\n scaleToCover,\n })\n })\n\n const viewport = canvas.viewportTransform\n if (!viewport) {\n console.warn('!viewport')\n return\n }\n\n // imageSource.angle = options.angle || 0\n onLoad?.(imageSource)\n } else {\n console.warn('ReactFabric:BackgroundImage: !canvas', canvas)\n }\n })\n .catch(console.error)\n .finally(() => {\n if (domNode) domNode.dataset.src = src\n setLoading(false)\n })\n\n return () => {\n const { canvas } = store.getState()\n if (canvas?.backgroundImage) {\n canvas.backgroundImage = undefined\n canvas.remove(backgroundImageRef.current!)\n backgroundImageRef.current = null\n canvas.renderAll()\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [src])\n\n useDidUpdate(() => {\n const { canvas } = store.getState()\n\n if (backgroundImageRef.current) {\n Object.entries(options).forEach(([key, value]) => {\n if (key === 'angle') {\n backgroundImageRef.current?.rotate(value as TDegree)\n } else {\n backgroundImageRef.current?.set(key, value)\n }\n })\n canvas?.requestRenderAll()\n }\n }, [options, store])\n\n useImperativeHandle(ref, () => ({\n // 是最新的?\n instance: backgroundImageRef.current,\n }))\n\n return null\n },\n)\n\nexport default memo(BackgroundImage)\n"],"names":["selector","s","BackgroundImage","forwardRef","src","onLoad","onScaling","scaleToFit","scaleToCover","options","ref","backgroundImageRef","useRef","store","useStoreApi","width","height","useStore","updateViewport","useCallback","params","canvas","manualZoom","defaultCentered","fitZoom","util","combinedZoom","deltaX","deltaY","bgWidth","bgHeight","finalTransform","useEffect","domNode","setLoading","FabricImage","imageSource","removeAngleOptions","useDidUpdate","key","value","useImperativeHandle","memo"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/BackgroundImage/index.tsx"],"sourcesContent":["import type {\n BasicTransformEvent,\n ImageProps,\n ObjectEvents,\n SerializedImageProps,\n TDegree,\n TPointerEvent,\n} from 'fabric'\nimport { FabricImage, util } from 'fabric'\nimport { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef } from 'react'\nimport { useDidUpdate } from '../../hooks/useDidUpdate'\nimport { useStore, useStoreApi } from '../../hooks/useStore'\nimport type { ReactFabricState } from '../../types/store'\n\nexport type Handle = {}\n\ntype ScaleMode = {\n scaleToFit?: boolean\n scaleToCover?: boolean\n}\nexport type BackgroundImageProps = Partial<ImageProps> & {\n src: string\n onLoad?: (imageSource: FabricImage<Partial<ImageProps>, SerializedImageProps, ObjectEvents>) => void\n onScaling?: (scale: BasicTransformEvent<TPointerEvent>) => void\n\n /** 自动缩放至容器宽高 */\n} & ScaleMode\n\nconst selector = (s: ReactFabricState) => ({\n width: s.width,\n height: s.height,\n})\n\nconst BackgroundImage = forwardRef<Handle, BackgroundImageProps>(\n ({ src, onLoad, onScaling, scaleToFit, scaleToCover, ...options }, ref) => {\n const backgroundImageRef = useRef<FabricImage | null>(null)\n\n const store = useStoreApi()\n\n const { width, height } = useStore(selector)\n\n const updateViewport = useCallback(\n (params: { scaleToFit?: boolean; scaleToCover?: boolean }) => {\n const { canvas, manualZoom = 1, defaultCentered } = store.getState()\n if (!backgroundImageRef.current) {\n return\n }\n if (!canvas) {\n console.warn('updateViewport: !canvas')\n return\n }\n if (!canvas.backgroundImage) {\n console.warn('updateViewport: !canvas.backgroundImage')\n return\n }\n\n // 1. 计算缩放\n const fitZoom = params.scaleToFit\n ? util.findScaleToFit(backgroundImageRef.current, canvas)\n : params.scaleToCover\n ? util.findScaleToCover(backgroundImageRef.current, canvas)\n : 1\n\n const combinedZoom = fitZoom * manualZoom\n\n // 2. 先应用基础缩放\n canvas.setViewportTransform([combinedZoom, 0, 0, combinedZoom, 0, 0])\n\n // 3. 如果需要居中,计算偏移量\n let deltaX = 0\n let deltaY = 0\n\n if (defaultCentered && canvas.backgroundImage) {\n const bgWidth = canvas.backgroundImage.width || 0\n const bgHeight = canvas.backgroundImage.height || 0\n deltaX = (canvas.width! - bgWidth * combinedZoom) / 2\n deltaY = (canvas.height! - bgHeight * combinedZoom) / 2\n // const canvasCenter = {\n // x: canvas.width! / 2,\n // y: canvas.height! / 2,\n // }\n // const bgCenter = {\n // x:\n // (canvas.backgroundImage.left! + (canvas.backgroundImage.width! * canvas.backgroundImage.scaleX!) / 2) *\n // combinedZoom,\n // y:\n // (canvas.backgroundImage.top! + (canvas.backgroundImage.height! * canvas.backgroundImage.scaleY!) / 2) *\n // combinedZoom,\n // }\n // deltaX = canvasCenter.x - bgCenter.x\n // deltaY = canvasCenter.y - bgCenter.y\n }\n\n // 4. 应用最终变换\n const finalTransform: [number, number, number, number, number, number] = [\n combinedZoom,\n 0,\n 0,\n combinedZoom,\n deltaX,\n deltaY,\n ]\n\n canvas.setViewportTransform(finalTransform)\n canvas.requestRenderAll()\n\n // 5. 更新 store\n store.setState({\n fitZoom,\n manualZoom,\n zoom: combinedZoom,\n })\n },\n [store],\n )\n\n // 监听 width, height 的变化\n useEffect(() => {\n updateViewport({\n scaleToFit,\n scaleToCover,\n })\n }, [width, height, scaleToFit, scaleToCover, updateViewport, store])\n\n useEffect(() => {\n if (!src) {\n console.warn('ReactFabricBackgroundImage: !src')\n return\n }\n const { domNode, setLoading } = store.getState()\n setLoading(true)\n FabricImage.fromURL(src, { crossOrigin: 'anonymous' })\n .then(imageSource => {\n const currentSrc = imageSource.getSrc()\n const latestSrc = backgroundImageRef.current?.getSrc()\n\n if (latestSrc && currentSrc !== latestSrc) {\n return\n }\n\n const { canvas } = store.getState()\n if (canvas) {\n // 初始化时角度的旋转,一定要放到 updateViewport 之后;先画正图片,再进行旋转\n const removeAngleOptions = { ...options, angle: 0 }\n imageSource.set({\n ...removeAngleOptions,\n objectCaching: false,\n })\n canvas.getContext().imageSmoothingEnabled = true\n canvas.getContext().imageSmoothingQuality = 'high'\n canvas.backgroundImage = imageSource\n backgroundImageRef.current = imageSource\n\n requestAnimationFrame(() => {\n updateViewport({\n scaleToFit,\n scaleToCover,\n })\n })\n\n const viewport = canvas.viewportTransform\n if (!viewport) {\n console.warn('!viewport')\n return\n }\n\n // imageSource.angle = options.angle || 0\n onLoad?.(imageSource)\n } else {\n console.warn('ReactFabric:BackgroundImage: !canvas', canvas)\n }\n })\n .catch(console.error)\n .finally(() => {\n if (domNode) domNode.dataset.src = src\n setLoading(false)\n })\n\n return () => {\n const { canvas } = store.getState()\n if (canvas?.backgroundImage) {\n canvas.backgroundImage = undefined\n canvas.remove(backgroundImageRef.current!)\n backgroundImageRef.current = null\n canvas.renderAll()\n }\n }\n }, [src])\n\n useDidUpdate(() => {\n const { canvas } = store.getState()\n\n if (backgroundImageRef.current) {\n Object.entries(options).forEach(([key, value]) => {\n if (key === 'angle') {\n backgroundImageRef.current?.rotate(value as TDegree)\n } else {\n backgroundImageRef.current?.set(key, value)\n }\n })\n canvas?.requestRenderAll()\n }\n }, [options, store])\n\n useImperativeHandle(ref, () => ({\n // 是最新的?\n instance: backgroundImageRef.current,\n }))\n\n return null\n },\n)\n\nexport default memo(BackgroundImage)\n"],"names":["selector","s","BackgroundImage","forwardRef","src","onLoad","onScaling","scaleToFit","scaleToCover","options","ref","backgroundImageRef","useRef","store","useStoreApi","width","height","useStore","updateViewport","useCallback","params","canvas","manualZoom","defaultCentered","fitZoom","util","combinedZoom","deltaX","deltaY","bgWidth","bgHeight","finalTransform","useEffect","domNode","setLoading","FabricImage","imageSource","currentSrc","latestSrc","removeAngleOptions","useDidUpdate","key","value","useImperativeHandle","memo"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var h=require("react/jsx-runtime"),c=require("fabric"),n=require("react"),E=require("../../hooks/useDraggable.cjs"),R=require("../../hooks/useResizeHandler.cjs"),g=require("../../hooks/useSplitProps.cjs"),z=require("../../hooks/useStore.cjs"),Y=require("../../utils/events.cjs");const j={position:"absolute",width:"100%",height:"100%",top:0,left:0},x=({children:w,onMouseWheel:l,...q})=>{const e=n.useRef(),t=z.useStoreApi(),i=n.useRef(null);E.default();const f=n.useRef(null),[S,u]=g.useSplitProps(q);return n.useLayoutEffect(()=>{const o=i.current;e.current=new c.Canvas(o||void 0,{...u});const r=Y.bindEvents(e.current,S);return t.setState({canvas:e.current}),window.canvas=e.current,()=>{r(),e.current?.dispose(),o?.remove(),e.current=void 0,t.setState({canvas:null})}},[]),R.default(),n.useEffect(()=>{const o=r=>{const{zoomable:b,maxManualZoom:v,minManualZoom:d,fitZoom:m=1,zoom:P}=t.getState();if(r.e.preventDefault(),r.e.stopPropagation(),r.e.wheelDeltaY!==0){if(r.e.ctrlKey||r.e.wheelDeltaY===void 0){if(!b)return;const a=r.e.deltaY>0?.95:1.05;let s=P/m*a;s>v&&(s=v),s<d&&(s=d);const p=s*m;e.current?.zoomToPoint(new c.Point(r.e.offsetX,r.e.offsetY),p),t.setState({manualZoom:s,zoom:p})}else{const a=new c.Point(-r.e.deltaX*1.5,-r.e.deltaY*1.5);e.current?.relativePan(a)}l?.(r)}};return e.current?.on("mouse:wheel",o),()=>{e.current?.off("mouse:wheel",o)}},[l,t]),n.useEffect(()=>{t.setState({domNode:f.current?.closest(".react-fabric")})},[t]),n.useEffect(()=>{e.current&&(e.current.set(u),e.current.requestRenderAll())},[u]),h.jsxs("div",{className:"react-fabric__canvas",ref:f,style:j,children:[h.jsx("canvas",{ref:i}),w]})};exports.default=x;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var c=require("react/jsx-runtime"),i=require("fabric"),a=require("react"),j=require("../../hooks/useDraggable.cjs"),x=require("../../hooks/useResizeHandler.cjs"),y=require("../../hooks/useSplitProps.cjs"),b=require("../../hooks/useStore.cjs"),z=require("../../utils/events.cjs");const E={position:"absolute",width:"100%",height:"100%",top:0,left:0},M=({children:w,onMouseWheel:l,...S})=>{const e=a.useRef(),o=b.useStoreApi(),f=a.useRef(null);j.default();const d=a.useRef(null),q=b.useStore(r=>r.controls),[P,n]=y.useSplitProps(S);return a.useLayoutEffect(()=>{const r=f.current;e.current=new i.Canvas(r||void 0,{...n});const t=z.bindEvents(e.current,P);return o.setState({canvas:e.current}),window.canvas=e.current,()=>{t(),e.current?.dispose(),r?.remove(),e.current=void 0,o.setState({canvas:null})}},[]),x.default(),a.useEffect(()=>{const r=t=>{const{zoomable:R,panAble:_,maxManualZoom:v,minManualZoom:m,fitZoom:p=1,zoom:g}=o.getState();if(t.e.preventDefault(),t.e.stopPropagation(),t.e.wheelDeltaY!==0){if(t.e.ctrlKey||t.e.wheelDeltaY===void 0){if(!R)return;const u=t.e.deltaY>0?.95:1.05;let s=g/p*u;s>v&&(s=v),s<m&&(s=m);const h=s*p;e.current?.zoomToPoint(new i.Point(t.e.offsetX,t.e.offsetY),h),o.setState({manualZoom:s,zoom:h})}else{if(!_)return;const u=1.5,s=new i.Point(-t.e.deltaX*u,-t.e.deltaY*u);e.current?.relativePan(s)}l?.(t)}};return e.current?.on("mouse:wheel",r),()=>{e.current?.off("mouse:wheel",r)}},[l,o]),a.useEffect(()=>{o.setState({domNode:d.current?.closest(".react-fabric")})},[o]),a.useEffect(()=>{e.current&&(e.current.set(n),e.current.requestRenderAll())},[n]),c.jsxs("div",{className:"react-fabric__canvas",ref:d,style:E,children:[c.jsx("canvas",{ref:f}),w,q.map(r=>c.jsx("div",{id:r.id,style:{position:"absolute"},className:`react-fabric__control ${r.className}`,ref:r.ref,children:r.children},r.id))]})};exports.default=M;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Canvas/index.tsx"],"sourcesContent":["import type { CanvasEvents, CanvasOptions, TPointerEventInfo } from 'fabric'\nimport { Canvas as BaseCanvas, Point } from 'fabric'\nimport type { CSSProperties, PropsWithChildren } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\nimport useDraggable from '../../hooks/useDraggable'\nimport useResizeHandler from '../../hooks/useResizeHandler'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport { useStoreApi } from '../../hooks/useStore'\nimport type { AllCanvasEvents } from '../../types/canvas'\nimport { bindEvents } from '../../utils/events'\n\nconst style: CSSProperties = {\n position: 'absolute',\n width: '100%',\n height: '100%',\n top: 0,\n left: 0,\n}\n\n// 首先定义事件类型\ntype CanvasEventProps = {\n [K in keyof AllCanvasEvents]: AllCanvasEvents[K]\n}\n\n// 分离配置属性类型\ntype CanvasConfigProps = Omit<CanvasOptions, keyof CanvasEventProps>\n\n// 重新定义 CanvasProps\nexport type CanvasProps = PropsWithChildren<Partial<CanvasConfigProps> & Partial<CanvasEventProps>>\n\nconst Canvas = ({ children, onMouseWheel, ...props }: CanvasProps) => {\n const canvasRef = useRef<BaseCanvas>()\n const store = useStoreApi()\n const canvasDomRef = useRef<HTMLCanvasElement | null>(null)\n useDraggable()\n const domRef = useRef<HTMLDivElement>(null)\n\n const [listeners, attributes] = useSplitProps(props)\n\n useLayoutEffect(() => {\n const canvas = canvasDomRef.current\n\n canvasRef.current = new BaseCanvas(canvas || undefined, {\n ...attributes,\n })\n\n // 绑定事件并获取清理函数\n const unbindEvents = bindEvents<CanvasEvents>(canvasRef.current, listeners)\n\n store.setState({\n canvas: canvasRef.current,\n })\n //@ts-expect-error\n window.canvas = canvasRef.current\n\n return () => {\n unbindEvents() // 调用清理函数\n canvasRef.current?.dispose()\n canvas?.remove()\n canvasRef.current = undefined // 清除引用\n store.setState({\n canvas: null,\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n useResizeHandler()\n\n useEffect(() => {\n const onMouseWheelHandler = (opt: TPointerEventInfo<WheelEvent>) => {\n const { zoomable, maxManualZoom, minManualZoom, fitZoom = 1, zoom } = store.getState()\n\n // 阻止默认行为\n opt.e.preventDefault()\n opt.e.stopPropagation()\n\n // 如果是惯性滚动,直接返回\n if ((opt.e as any).wheelDeltaY === 0) return\n\n // 检查是否为缩放手势(Mac 上的双指捏合/张开)\n if (opt.e.ctrlKey || (opt.e as any).wheelDeltaY === undefined) {\n // 缩放逻辑\n if (!zoomable) return\n\n const delta = opt.e.deltaY\n const zoomFactor = delta > 0 ? 0.95 : 1.05\n let currentManualZoom = zoom / fitZoom\n let newManualZoom = currentManualZoom * zoomFactor\n\n if (newManualZoom > maxManualZoom) newManualZoom = maxManualZoom\n if (newManualZoom < minManualZoom) newManualZoom = minManualZoom\n\n const combinedZoom = newManualZoom * fitZoom\n\n canvasRef.current?.zoomToPoint(new Point(opt.e.offsetX, opt.e.offsetY), combinedZoom)\n\n store.setState({\n manualZoom: newManualZoom,\n zoom: combinedZoom,\n })\n } else {\n // 平移逻辑\n // 如果觉得太灵敏了,可以调小这个值,比如改为 1.2 或更小\n const sensitivityFactor = 1.5\n const delta = new Point(-opt.e.deltaX * sensitivityFactor, -opt.e.deltaY * sensitivityFactor)\n canvasRef.current?.relativePan(delta)\n }\n\n onMouseWheel?.(opt)\n }\n\n canvasRef.current?.on('mouse:wheel', onMouseWheelHandler)\n\n return () => {\n canvasRef.current?.off('mouse:wheel', onMouseWheelHandler)\n }\n }, [onMouseWheel, store])\n\n useEffect(() => {\n store.setState({\n domNode: domRef.current?.closest('.react-fabric') as HTMLDivElement,\n })\n }, [store])\n\n useEffect(() => {\n if (canvasRef.current) {\n canvasRef.current.set(attributes)\n canvasRef.current.requestRenderAll()\n }\n }, [attributes])\n\n return (\n <div className=\"react-fabric__canvas\" ref={domRef} style={style}>\n <canvas ref={canvasDomRef}></canvas>\n {children}\n </div>\n )\n}\n\nexport default Canvas\n"],"names":["style","Canvas","children","onMouseWheel","props","canvasRef","useRef","store","useStoreApi","canvasDomRef","useDraggable","domRef","listeners","attributes","useSplitProps","useLayoutEffect","canvas","BaseCanvas","unbindEvents","bindEvents","useResizeHandler","useEffect","onMouseWheelHandler","opt","zoomable","maxManualZoom","minManualZoom","fitZoom","zoom","zoomFactor","newManualZoom","combinedZoom","Point","delta","jsxs","jsx"],"mappings":"iWAWMA,EAAuB,CAC3B,SAAU,WACV,MAAO,OACP,OAAQ,OACR,IAAK,EACL,KAAM,CACR,EAaMC,EAAS,CAAC,CAAE,SAAAC,EAAU,aAAAC,EAAc,GAAGC,CAAM,IAAmB,CACpE,MAAMC,EAAYC,EAAAA,SACZC,EAAQC,EAAAA,YACRC,EAAAA,EAAeH,SAAiC,IAAI,EAC1DI,EAAAA,QACA,EAAA,MAAMC,EAASL,EAAuB,OAAA,IAAI,EAEpC,CAACM,EAAWC,CAAU,EAAIC,EAAAA,cAAcV,CAAK,EAEnD,OAAAW,EAAAA,gBAAgB,IAAM,CACpB,MAAMC,EAASP,EAAa,QAE5BJ,EAAU,QAAU,IAAIY,EAAAA,OAAWD,GAAU,OAAW,CACtD,GAAGH,CACL,CAAC,EAGD,MAAMK,EAAeC,EAAAA,WAAyBd,EAAU,QAASO,CAAS,EAE1E,OAAAL,EAAM,SAAS,CACb,OAAQF,EAAU,OACpB,CAAC,EAED,OAAO,OAASA,EAAU,QAEnB,IAAM,CACXa,EAAa,EACbb,EAAU,SAAS,QAAA,EACnBW,GAAQ,OACRX,EAAAA,EAAU,QAAU,OACpBE,EAAM,SAAS,CACb,OAAQ,IACV,CAAC,CACH,CAEF,EAAG,CAAE,CAAA,EAELa,EAAAA,QAEAC,EAAAA,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAuBC,GAAuC,CAClE,KAAM,CAAE,SAAAC,EAAU,cAAAC,EAAe,cAAAC,EAAe,QAAAC,EAAU,EAAG,KAAAC,CAAK,EAAIrB,EAAM,SAAS,EAOrF,GAJAgB,EAAI,EAAE,eAAe,EACrBA,EAAI,EAAE,gBAAA,EAGDA,EAAI,EAAU,cAAgB,EAGnC,IAAIA,EAAI,EAAE,SAAYA,EAAI,EAAU,cAAgB,OAAW,CAE7D,GAAI,CAACC,EAAU,OAGf,MAAMK,EADQN,EAAI,EAAE,OACO,EAAI,IAAO,KAEtC,IAAIO,EADoBF,EAAOD,EACSE,EAEpCC,EAAgBL,IAAeK,EAAgBL,GAC/CK,EAAgBJ,IAAeI,EAAgBJ,GAEnD,MAAMK,EAAeD,EAAgBH,EAErCtB,EAAU,SAAS,YAAY,IAAI2B,QAAMT,EAAI,EAAE,QAASA,EAAI,EAAE,OAAO,EAAGQ,CAAY,EAEpFxB,EAAM,SAAS,CACb,WAAYuB,EACZ,KAAMC,CACR,CAAC,CACH,KAAO,CAIL,MAAME,EAAQ,IAAID,EAAAA,MAAM,CAACT,EAAI,EAAE,OAAS,IAAmB,CAACA,EAAI,EAAE,OAAS,GAAiB,EAC5FlB,EAAU,SAAS,YAAY4B,CAAK,CACtC,CAEA9B,IAAeoB,CAAG,CACpB,CAAA,EAEA,OAAAlB,EAAU,SAAS,GAAG,cAAeiB,CAAmB,EAEjD,IAAM,CACXjB,EAAU,SAAS,IAAI,cAAeiB,CAAmB,CAC3D,CACF,EAAG,CAACnB,EAAcI,CAAK,CAAC,EAExBc,EAAAA,UAAU,IAAM,CACdd,EAAM,SAAS,CACb,QAASI,EAAO,SAAS,QAAQ,eAAe,CAClD,CAAC,CACH,EAAG,CAACJ,CAAK,CAAC,EAEVc,EAAAA,UAAU,IAAM,CACVhB,EAAU,UACZA,EAAU,QAAQ,IAAIQ,CAAU,EAChCR,EAAU,QAAQ,iBAEtB,EAAA,EAAG,CAACQ,CAAU,CAAC,EAGbqB,EAAAA,KAAC,OAAI,UAAU,uBAAuB,IAAKvB,EAAQ,MAAOX,EACxD,SAAAmC,CAAAA,EAAAA,IAAC,UAAO,IAAK1B,CAAAA,CAAc,EAC1BP,CACH,CAAA,CAAA,CAEJ"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Canvas/index.tsx"],"sourcesContent":["import type { CanvasEvents, CanvasOptions, TPointerEventInfo } from 'fabric'\nimport { Canvas as BaseCanvas, Point } from 'fabric'\nimport type { CSSProperties, PropsWithChildren } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\nimport useDraggable from '../../hooks/useDraggable'\nimport useResizeHandler from '../../hooks/useResizeHandler'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport { useStore, useStoreApi } from '../../hooks/useStore'\nimport type { AllCanvasEvents } from '../../types/canvas'\nimport { bindEvents } from '../../utils/events'\n\nconst style: CSSProperties = {\n position: 'absolute',\n width: '100%',\n height: '100%',\n top: 0,\n left: 0,\n}\n\n// 首先定义事件类型\ntype CanvasEventProps = {\n [K in keyof AllCanvasEvents]: AllCanvasEvents[K]\n}\n\n// 分离配置属性类型\ntype CanvasConfigProps = Omit<CanvasOptions, keyof CanvasEventProps>\n\n// 重新定义 CanvasProps\nexport type CanvasProps = PropsWithChildren<Partial<CanvasConfigProps> & Partial<CanvasEventProps>>\n\nconst Canvas = ({ children, onMouseWheel, ...props }: CanvasProps) => {\n const canvasRef = useRef<BaseCanvas>()\n const store = useStoreApi()\n const canvasDomRef = useRef<HTMLCanvasElement | null>(null)\n useDraggable()\n const domRef = useRef<HTMLDivElement>(null)\n const controls = useStore(state => state.controls)\n\n const [listeners, attributes] = useSplitProps(props)\n\n useLayoutEffect(() => {\n const canvas = canvasDomRef.current\n\n canvasRef.current = new BaseCanvas(canvas || undefined, {\n ...attributes,\n })\n\n // 绑定事件并获取清理函数\n const unbindEvents = bindEvents<CanvasEvents>(canvasRef.current, listeners)\n\n store.setState({\n canvas: canvasRef.current,\n })\n //@ts-expect-error 报错撒撒\n window.canvas = canvasRef.current\n\n return () => {\n unbindEvents() // 调用清理函数\n canvasRef.current?.dispose()\n canvas?.remove()\n canvasRef.current = undefined // 清除引用\n store.setState({\n canvas: null,\n })\n }\n }, [])\n\n useResizeHandler()\n\n useEffect(() => {\n const onMouseWheelHandler = (opt: TPointerEventInfo<WheelEvent>) => {\n const { zoomable, panAble, maxManualZoom, minManualZoom, fitZoom = 1, zoom } = store.getState()\n\n // 阻止默认行为\n opt.e.preventDefault()\n opt.e.stopPropagation()\n\n // 如果是惯性滚动,直接返回\n if ((opt.e as any).wheelDeltaY === 0) return\n\n // 检查是否为缩放手势(Mac 上的双指捏合/张开)\n if (opt.e.ctrlKey || (opt.e as any).wheelDeltaY === undefined) {\n // 缩放逻辑\n if (!zoomable) return\n\n const delta = opt.e.deltaY\n const zoomFactor = delta > 0 ? 0.95 : 1.05\n const currentManualZoom = zoom / fitZoom\n let newManualZoom = currentManualZoom * zoomFactor\n\n if (newManualZoom > maxManualZoom) newManualZoom = maxManualZoom\n if (newManualZoom < minManualZoom) newManualZoom = minManualZoom\n\n const combinedZoom = newManualZoom * fitZoom\n\n canvasRef.current?.zoomToPoint(new Point(opt.e.offsetX, opt.e.offsetY), combinedZoom)\n\n store.setState({\n manualZoom: newManualZoom,\n zoom: combinedZoom,\n })\n } else {\n if (!panAble) return\n // 平移逻辑\n // 如果觉得太灵敏了,可以调小这个值,比如改为 1.2 或更小\n const sensitivityFactor = 1.5\n const delta = new Point(-opt.e.deltaX * sensitivityFactor, -opt.e.deltaY * sensitivityFactor)\n canvasRef.current?.relativePan(delta)\n }\n\n onMouseWheel?.(opt)\n }\n\n canvasRef.current?.on('mouse:wheel', onMouseWheelHandler)\n\n return () => {\n canvasRef.current?.off('mouse:wheel', onMouseWheelHandler)\n }\n }, [onMouseWheel, store])\n\n useEffect(() => {\n store.setState({\n domNode: domRef.current?.closest('.react-fabric') as HTMLDivElement,\n })\n }, [store])\n\n useEffect(() => {\n if (canvasRef.current) {\n canvasRef.current.set(attributes)\n canvasRef.current.requestRenderAll()\n }\n }, [attributes])\n\n return (\n <div className=\"react-fabric__canvas\" ref={domRef} style={style}>\n <canvas ref={canvasDomRef}></canvas>\n {children}\n {controls.map(control => (\n <div\n key={control.id}\n id={control.id}\n style={{\n position: 'absolute',\n }}\n className={`react-fabric__control ${control.className}`}\n ref={control.ref}\n >\n {control.children}\n </div>\n ))}\n </div>\n )\n}\n\nexport default Canvas\n"],"names":["style","Canvas","children","onMouseWheel","props","canvasRef","useRef","store","useStoreApi","canvasDomRef","useDraggable","domRef","controls","useStore","state","listeners","attributes","useSplitProps","useLayoutEffect","canvas","BaseCanvas","unbindEvents","bindEvents","useResizeHandler","useEffect","onMouseWheelHandler","opt","zoomable","panAble","maxManualZoom","minManualZoom","fitZoom","zoom","zoomFactor","newManualZoom","combinedZoom","Point","sensitivityFactor","delta","jsxs","jsx","control"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var p=require("react/jsx-runtime"),m=require("@floating-ui/core"),E=require("fabric"),b=require("tailwind-merge"),t=require("react"),R=require("../../hooks/useStore.cjs"),P=require("../NodeToolbarPortal/index.cjs");const j=t.forwardRef(({children:s,className:w,placement:g="bottom",open:o=!0,onOpenChange:f,closeOnOutsideClick:h=!0,Content:x},l)=>{const d=t.useRef(void 0),r=R.useStore(e=>e.canvas),i=t.useRef(null),v=t.useCallback(e=>{e!==d.current&&(d.current=e,typeof l=="function"?l(e):l&&(l.current=e))},[l]),C=t.useMemo(()=>t.Children.only(s)&&t.isValidElement(s)?t.cloneElement(s,{ref:v,...s.props}):s,[s,v]),c=t.useCallback(()=>{if(!d.current||!i.current||!r)return;const e=i.current.getBoundingClientRect();if(e.width===0||e.height===0){requestAnimationFrame(c);return}const n=d.current.getCoords().map(a=>E.util.sendPointToPlane(a,r.viewportTransform,void 0)),u={getElementRects:a=>a,getDimensions:a=>a,getClippingRect:()=>({x:0,y:0,width:r.width,height:r.height})},y={x:n[0].x,y:n[0].y,width:n[2].x-n[0].x,height:n[2].y-n[0].y};m.computePosition(y,i.current.getBoundingClientRect(),{platform:u,placement:g,middleware:[m.offset(5),m.flip(),m.shift({padding:5})]}).then(({x:a,y:q})=>{i.current&&Object.assign(i.current.style,{left:`${a}px`,top:`${q}px`})})},[r,g]);return t.useEffect(()=>{o&&requestAnimationFrame(c)},[o,c]),t.useEffect(()=>(r?.on("after:render",c),()=>{r?.off("after:render",c)}),[r,c]),t.useEffect(()=>{const e=u=>{u.e.stopPropagation(),u.e.preventDefault(),u.target===d.current?f?.(!o):o&&f?.(!1)},n=u=>{i.current?.contains(u.target)||h&&o&&f?.(!1)};return r?.on("mouse:down",e),document.addEventListener("mousedown",n,!1),()=>{r?.off("mouse:down",e),document.removeEventListener("mousedown",n,!1)}},[r,h,f,o]),p.jsxs(p.Fragment,{children:[C,o&&p.jsx(P.default,{className:b.twMerge("absolute",w),ref:i,onClick:e=>{e.stopPropagation(),e.preventDefault()},children:x})]})});exports.default=j;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var p=require("react/jsx-runtime"),m=require("@floating-ui/core"),q=require("fabric"),t=require("react"),R=require("../../hooks/useStore.cjs"),b=require("../NodeToolbarPortal/index.cjs");const P=t.forwardRef(({children:s,className:w,placement:g="bottom",open:o=!0,onOpenChange:f,closeOnOutsideClick:h=!0,Content:x},l)=>{const d=t.useRef(void 0),r=R.useStore(e=>e.canvas),i=t.useRef(null),v=t.useCallback(e=>{e!==d.current&&(d.current=e,typeof l=="function"?l(e):l&&(l.current=e))},[l]),C=t.useMemo(()=>t.Children.only(s)&&t.isValidElement(s)?t.cloneElement(s,{ref:v,...s.props}):s,[s,v]),c=t.useCallback(()=>{if(!d.current||!i.current||!r)return;const e=i.current.getBoundingClientRect();if(e.width===0||e.height===0){requestAnimationFrame(c);return}const n=d.current.getCoords().map(a=>q.util.sendPointToPlane(a,r.viewportTransform,void 0)),u={getElementRects:a=>a,getDimensions:a=>a,getClippingRect:()=>({x:0,y:0,width:r.width,height:r.height})},y={x:n[0].x,y:n[0].y,width:n[2].x-n[0].x,height:n[2].y-n[0].y};m.computePosition(y,i.current.getBoundingClientRect(),{platform:u,placement:g,middleware:[m.offset(5),m.flip(),m.shift({padding:5})]}).then(({x:a,y:E})=>{i.current&&Object.assign(i.current.style,{left:`${a}px`,top:`${E}px`})})},[r,g]);return t.useEffect(()=>{o&&requestAnimationFrame(c)},[o,c]),t.useEffect(()=>(r?.on("after:render",c),()=>{r?.off("after:render",c)}),[r,c]),t.useEffect(()=>{const e=u=>{u.e.stopPropagation(),u.e.preventDefault(),u.target===d.current?f?.(!o):o&&f?.(!1)},n=u=>{i.current?.contains(u.target)||h&&o&&f?.(!1)};return r?.on("mouse:down",e),document.addEventListener("mousedown",n,!1),()=>{r?.off("mouse:down",e),document.removeEventListener("mousedown",n,!1)}},[r,h,f,o]),p.jsxs(p.Fragment,{children:[C,o&&p.jsx(b.default,{className:`absolute ${w}`,ref:i,onClick:e=>{e.stopPropagation(),e.preventDefault()},children:x})]})});exports.default=P;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Control/index.tsx"],"sourcesContent":["import { computePosition, flip, offset, shift,ComputePositionConfig } from '@floating-ui/core'\nimport type { FabricObject, FabricObjectProps, TPointerEvent, TPointerEventInfo } from 'fabric'\nimport { util } from 'fabric'\nimport { twMerge } from 'tailwind-merge'\nimport type { ReactNode } from 'react'\nimport { useMemo } from 'react'\nimport { useCallback } from 'react'\nimport { useRef } from 'react'\nimport { useEffect } from 'react'\nimport React from 'react'\nimport { useStore } from '../../hooks/useStore'\nimport type { AllObjectEvents } from '../../types/object'\nimport NodeToolbarPortal from '../NodeToolbarPortal'\n\n/**\n * @desc 不能内置支持 selected , 因为需要 rect 开启 lockMovementX lockMovementY, 这样支持的场景就受限了\n */\nexport type ControlProps = Partial<AllObjectEvents & FabricObjectProps> & {\n Content: ReactNode\n children: ReactNode\n placement?: ComputePositionConfig['placement']\n className?: string\n open?: boolean\n onOpenChange?: (open: boolean) => void\n closeOnOutsideClick?: boolean\n}\n\nconst Control = React.forwardRef(\n (\n {\n children,\n className,\n placement = 'bottom',\n open = true,\n onOpenChange,\n closeOnOutsideClick = true,\n Content,\n }: ControlProps,\n forwardRef,\n ) => {\n const instanceRef = useRef<FabricObject | undefined>(undefined)\n const canvas = useStore(state => state.canvas)\n const floatingElRef = useRef<HTMLDivElement>(null)\n\n // 使用 useCallback 创建稳定的 ref 回调\n const refCallback = useCallback(\n (node: any) => {\n // 只在节点真正改变时更新 ref\n if (node !== instanceRef.current) {\n instanceRef.current = node\n\n // 处理 forwardRef\n if (typeof forwardRef === 'function') {\n forwardRef(node)\n } else if (forwardRef) {\n forwardRef.current = node\n }\n }\n },\n [forwardRef],\n )\n\n // 使用 useMemo 缓存克隆的子元素\n const newChildren = useMemo(() => {\n if (React.Children.only(children) && React.isValidElement(children)) {\n return React.cloneElement(children, {\n ref: refCallback,\n ...children.props,\n })\n }\n return children\n }, [children, refCallback]) // 只在 children 或 refCallback 改变时重新克隆\n\n const updatePosition = useCallback(() => {\n if (!instanceRef.current || !floatingElRef.current || !canvas) {\n return\n }\n\n // 确保元素已经渲染并且有尺寸\n const floatingRect = floatingElRef.current.getBoundingClientRect()\n if (floatingRect.width === 0 || floatingRect.height === 0) {\n // 如果元素还没有尺寸,等待下一帧再试\n requestAnimationFrame(updatePosition)\n return\n }\n\n const sceneCoords = instanceRef.current.getCoords()\n const viewportCoords = sceneCoords.map(point => util.sendPointToPlane(point, canvas.viewportTransform, undefined))\n\n const platform = {\n getElementRects: (data:any) => data,\n getDimensions: (element:any) => element,\n getClippingRect: () => ({\n x: 0,\n y: 0,\n width: canvas.width,\n height: canvas.height,\n }),\n }\n\n const virtualEl = {\n x: viewportCoords[0].x,\n y: viewportCoords[0].y,\n width: viewportCoords[2].x - viewportCoords[0].x,\n height: viewportCoords[2].y - viewportCoords[0].y,\n }\n\n computePosition(virtualEl, floatingElRef.current.getBoundingClientRect(), {\n platform,\n placement,\n middleware: [offset(5), flip(), shift({ padding: 5 })],\n }).then(({ x, y }) => {\n if (!floatingElRef.current) return\n\n Object.assign(floatingElRef.current.style, {\n left: `${x}px`,\n top: `${y}px`,\n })\n })\n }, [canvas, placement])\n\n // 确保在元素挂载后更新位置\n useEffect(() => {\n if (open) {\n requestAnimationFrame(updatePosition)\n }\n }, [open, updatePosition])\n\n useEffect(() => {\n canvas?.on('after:render', updatePosition)\n\n return () => {\n canvas?.off('after:render', updatePosition)\n }\n }, [canvas, updatePosition])\n\n useEffect(() => {\n const handleCanvasClick = (e: TPointerEventInfo<TPointerEvent>) => {\n // 阻止事件冒泡到 document\n e.e.stopPropagation()\n e.e.preventDefault() // 也阻止默认行为\n\n // 使用 id 比较来确保正确匹配\n if (e.target === instanceRef.current) {\n onOpenChange?.(!open)\n }\n // 点击其他区域时关闭\n else if (open) {\n onOpenChange?.(false)\n }\n }\n\n const handleDocumentClick = (e: MouseEvent) => {\n // 如果点击在浮动内容内,不处理\n if (floatingElRef.current?.contains(e.target as Node)) {\n return\n }\n\n if (closeOnOutsideClick && open) {\n onOpenChange?.(false)\n }\n }\n\n canvas?.on('mouse:down', handleCanvasClick)\n // 改为冒泡阶段处理 document 事件\n document.addEventListener('mousedown', handleDocumentClick, false)\n\n return () => {\n canvas?.off('mouse:down', handleCanvasClick)\n document.removeEventListener('mousedown', handleDocumentClick, false)\n }\n }, [canvas, closeOnOutsideClick, onOpenChange, open])\n\n return (\n <>\n {newChildren}\n {open && (\n <NodeToolbarPortal\n className={twMerge('absolute', className)}\n ref={floatingElRef}\n onClick={e => {\n e.stopPropagation()\n e.preventDefault()\n }}\n >\n {Content}\n </NodeToolbarPortal>\n )}\n </>\n )\n },\n)\n\nexport default Control\n"],"names":["Control","React","children","className","placement","open","onOpenChange","closeOnOutsideClick","Content","forwardRef","instanceRef","useRef","canvas","useStore","state","floatingElRef","refCallback","useCallback","node","newChildren","useMemo","updatePosition","floatingRect","viewportCoords","point","util","platform","data","element","virtualEl","computePosition","offset","flip","shift","x","y","useEffect","handleCanvasClick","e","handleDocumentClick","jsxs","Fragment","jsx","NodeToolbarPortal","twMerge"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Control/index.tsx"],"sourcesContent":["import { computePosition, flip, offset, shift, ComputePositionConfig } from '@floating-ui/core'\nimport type { FabricObject, FabricObjectProps, TPointerEvent, TPointerEventInfo } from 'fabric'\nimport { util } from 'fabric'\nimport type { ReactNode } from 'react'\nimport { useMemo } from 'react'\nimport { useCallback } from 'react'\nimport { useRef } from 'react'\nimport { useEffect } from 'react'\nimport React from 'react'\nimport { useStore } from '../../hooks/useStore'\nimport type { AllObjectEvents } from '../../types/object'\nimport NodeToolbarPortal from '../NodeToolbarPortal'\n\n/**\n * @desc 不能内置支持 selected , 因为需要 rect 开启 lockMovementX lockMovementY, 这样支持的场景就受限了\n */\nexport type ControlProps = Partial<AllObjectEvents & FabricObjectProps> & {\n Content: ReactNode\n children: ReactNode\n placement?: ComputePositionConfig['placement']\n className?: string\n open?: boolean\n onOpenChange?: (open: boolean) => void\n closeOnOutsideClick?: boolean\n}\n\nconst Control = React.forwardRef(\n (\n {\n children,\n className,\n placement = 'bottom',\n open = true,\n onOpenChange,\n closeOnOutsideClick = true,\n Content,\n }: ControlProps,\n forwardRef,\n ) => {\n const instanceRef = useRef<FabricObject | undefined>(undefined)\n const canvas = useStore(state => state.canvas)\n const floatingElRef = useRef<HTMLDivElement>(null)\n\n // 使用 useCallback 创建稳定的 ref 回调\n const refCallback = useCallback(\n (node: any) => {\n // 只在节点真正改变时更新 ref\n if (node !== instanceRef.current) {\n instanceRef.current = node\n\n // 处理 forwardRef\n if (typeof forwardRef === 'function') {\n forwardRef(node)\n } else if (forwardRef) {\n forwardRef.current = node\n }\n }\n },\n [forwardRef],\n )\n\n // 使用 useMemo 缓存克隆的子元素\n const newChildren = useMemo(() => {\n if (React.Children.only(children) && React.isValidElement(children)) {\n return React.cloneElement(children, {\n ref: refCallback,\n ...children.props,\n })\n }\n return children\n }, [children, refCallback]) // 只在 children 或 refCallback 改变时重新克隆\n\n const updatePosition = useCallback(() => {\n if (!instanceRef.current || !floatingElRef.current || !canvas) {\n return\n }\n\n // 确保元素已经渲染并且有尺寸\n const floatingRect = floatingElRef.current.getBoundingClientRect()\n if (floatingRect.width === 0 || floatingRect.height === 0) {\n // 如果元素还没有尺寸,等待下一帧再试\n requestAnimationFrame(updatePosition)\n return\n }\n\n const sceneCoords = instanceRef.current.getCoords()\n const viewportCoords = sceneCoords.map(point => util.sendPointToPlane(point, canvas.viewportTransform, undefined))\n\n const platform = {\n getElementRects: (data: any) => data,\n getDimensions: (element: any) => element,\n getClippingRect: () => ({\n x: 0,\n y: 0,\n width: canvas.width,\n height: canvas.height,\n }),\n }\n\n const virtualEl = {\n x: viewportCoords[0].x,\n y: viewportCoords[0].y,\n width: viewportCoords[2].x - viewportCoords[0].x,\n height: viewportCoords[2].y - viewportCoords[0].y,\n }\n\n computePosition(virtualEl, floatingElRef.current.getBoundingClientRect(), {\n platform,\n placement,\n middleware: [offset(5), flip(), shift({ padding: 5 })],\n }).then(({ x, y }) => {\n if (!floatingElRef.current) return\n\n Object.assign(floatingElRef.current.style, {\n left: `${x}px`,\n top: `${y}px`,\n })\n })\n }, [canvas, placement])\n\n // 确保在元素挂载后更新位置\n useEffect(() => {\n if (open) {\n requestAnimationFrame(updatePosition)\n }\n }, [open, updatePosition])\n\n useEffect(() => {\n canvas?.on('after:render', updatePosition)\n\n return () => {\n canvas?.off('after:render', updatePosition)\n }\n }, [canvas, updatePosition])\n\n useEffect(() => {\n const handleCanvasClick = (e: TPointerEventInfo<TPointerEvent>) => {\n // 阻止事件冒泡到 document\n e.e.stopPropagation()\n e.e.preventDefault() // 也阻止默认行为\n\n // 使用 id 比较来确保正确匹配\n if (e.target === instanceRef.current) {\n onOpenChange?.(!open)\n }\n // 点击其他区域时关闭\n else if (open) {\n onOpenChange?.(false)\n }\n }\n\n const handleDocumentClick = (e: MouseEvent) => {\n // 如果点击在浮动内容内,不处理\n if (floatingElRef.current?.contains(e.target as Node)) {\n return\n }\n\n if (closeOnOutsideClick && open) {\n onOpenChange?.(false)\n }\n }\n\n canvas?.on('mouse:down', handleCanvasClick)\n // 改为冒泡阶段处理 document 事件\n document.addEventListener('mousedown', handleDocumentClick, false)\n\n return () => {\n canvas?.off('mouse:down', handleCanvasClick)\n document.removeEventListener('mousedown', handleDocumentClick, false)\n }\n }, [canvas, closeOnOutsideClick, onOpenChange, open])\n\n return (\n <>\n {newChildren}\n {open && (\n <NodeToolbarPortal\n className={`absolute ${className}`}\n ref={floatingElRef}\n onClick={e => {\n e.stopPropagation()\n e.preventDefault()\n }}\n >\n {Content}\n </NodeToolbarPortal>\n )}\n </>\n )\n },\n)\n\nexport default Control\n"],"names":["Control","React","children","className","placement","open","onOpenChange","closeOnOutsideClick","Content","forwardRef","instanceRef","useRef","canvas","useStore","state","floatingElRef","refCallback","useCallback","node","newChildren","useMemo","updatePosition","floatingRect","viewportCoords","point","util","platform","data","element","virtualEl","computePosition","offset","flip","shift","x","y","useEffect","handleCanvasClick","e","handleDocumentClick","jsxs","Fragment","jsx","NodeToolbarPortal"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var x=require("react/jsx-runtime"),p=require("@floating-ui/core"),b=require("fabric"),n=require("react"),E=require("../../hooks/useStore.cjs");const O=()=>Math.random().toString(36).substring(2)+Date.now().toString(36),P=n.forwardRef(({children:u,className:g,placement:v="bottom",open:a=!0,onOpenChange:w,closeOnOutsideClick:S=!0,Content:h},l)=>{const m=n.useRef(void 0),r=E.useStore(e=>e.canvas),o=n.useRef(null),[c,j]=n.useState(O()),i=E.useStoreApi(),y=n.useCallback(e=>{e!==m.current&&(m.current=e,typeof l=="function"?l(e):l&&(l.current=e))},[l]),C=n.useMemo(()=>n.Children.only(u)&&n.isValidElement(u)?n.cloneElement(u,{ref:y,...u.props}):u,[u,y]),d=n.useCallback(()=>{if(!m.current||!o.current||!r)return;const e=o.current.getBoundingClientRect();if(e.width===0||e.height===0){requestAnimationFrame(d);return}const t=m.current.getCoords().map(s=>b.util.sendPointToPlane(s,r.viewportTransform,void 0)),f={getElementRects:s=>s,getDimensions:s=>s,getClippingRect:()=>({x:0,y:0,width:r.width,height:r.height})},R={x:t[0].x,y:t[0].y,width:t[2].x-t[0].x,height:t[2].y-t[0].y};p.computePosition(R,o.current.getBoundingClientRect(),{platform:f,placement:v,middleware:[p.offset(5),p.flip(),p.shift({padding:5})]}).then(({x:s,y:q})=>{o.current&&Object.assign(o.current.style,{left:`${s}px`,top:`${q}px`})})},[r,v]);return n.useEffect(()=>{a&&requestAnimationFrame(d)},[a,d]),n.useEffect(()=>(r?.on("after:render",d),()=>{r?.off("after:render",d)}),[r,d]),n.useEffect(()=>{const e=f=>{f.e.stopPropagation(),f.e.preventDefault()},t=f=>{o.current?.contains(f.target)||S&&a&&w?.(!1)};return r?.on("mouse:down",e),document.addEventListener("mousedown",t,!1),()=>{r?.off("mouse:down",e),document.removeEventListener("mousedown",t,!1)}},[r,S,w,a]),n.useEffect(()=>{const{controls:e}=i.getState();if(!e.find(t=>t.id===c))return i.setState({controls:[...e,{id:c,className:g,children:h,ref:o}]}),()=>{i.setState({controls:e.filter(t=>t.id!==c)})}},[i]),n.useEffect(()=>{const{controls:e}=i.getState();e.find(t=>t.id===c)&&i.setState({controls:e.map(t=>t.id===c?{...t,children:a?h:null,className:g}:t)})},[h,g,c,i,a]),x.jsx(x.Fragment,{children:C})});exports.default=P;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Control2/index.tsx"],"sourcesContent":["import { computePosition, flip, offset, shift } from '@floating-ui/core'\nimport type { ComputePositionConfig } from '@floating-ui/react'\nimport type { FabricObject, FabricObjectProps, TPointerEvent, TPointerEventInfo } from 'fabric'\nimport { util } from 'fabric'\nimport type { ReactNode } from 'react'\nimport { useState } from 'react'\nimport { useMemo } from 'react'\nimport { useCallback } from 'react'\nimport { useRef } from 'react'\nimport { useEffect } from 'react'\nimport React from 'react'\nimport { useStore, useStoreApi } from '../../hooks/useStore'\nimport type { AllObjectEvents } from '../../types/object'\n\n// 生成随机ID的函数\nconst generateRandomId = (): string => {\n return Math.random().toString(36).substring(2) + Date.now().toString(36)\n}\n\n/**\n * @desc 不能内置支持 selected , 因为需要 rect 开启 lockMovementX lockMovementY, 这样支持的场景就受限了\n */\nexport type Control2Props = Partial<AllObjectEvents & FabricObjectProps> & {\n Content: ReactNode\n children: ReactNode\n placement?: ComputePositionConfig['placement']\n className?: string\n open?: boolean\n onOpenChange?: (open: boolean) => void\n closeOnOutsideClick?: boolean\n}\n\nconst Control = React.forwardRef(\n (\n {\n children,\n className,\n placement = 'bottom',\n open = true,\n onOpenChange,\n closeOnOutsideClick = true,\n Content,\n }: Control2Props,\n forwardRef,\n ) => {\n const instanceRef = useRef<FabricObject | undefined>(undefined)\n const canvas = useStore(state => state.canvas)\n const floatingElRef = useRef<HTMLDivElement>(null)\n const [id, _setId] = useState(generateRandomId())\n\n const store = useStoreApi()\n // 使用 useCallback 创建稳定的 ref 回调\n const refCallback = useCallback(\n (node: any) => {\n // 只在节点真正改变时更新 ref\n if (node !== instanceRef.current) {\n instanceRef.current = node\n\n // 处理 forwardRef\n if (typeof forwardRef === 'function') {\n forwardRef(node)\n } else if (forwardRef) {\n forwardRef.current = node\n }\n }\n },\n [forwardRef],\n )\n\n // 使用 useMemo 缓存克隆的子元素\n const newChildren = useMemo(() => {\n if (React.Children.only(children) && React.isValidElement(children)) {\n return React.cloneElement(children, {\n ref: refCallback,\n ...children.props,\n })\n }\n return children\n }, [children, refCallback]) // 只在 children 或 refCallback 改变时重新克隆\n\n const updatePosition = useCallback(() => {\n // 这里测试下来是多余的,可删除;after:render 后都有值\n if (!instanceRef.current || !floatingElRef.current || !canvas) {\n return\n }\n\n // 确保元素已经渲染并且有尺寸\n const floatingRect = floatingElRef.current.getBoundingClientRect()\n if (floatingRect.width === 0 || floatingRect.height === 0) {\n // 如果元素还没有尺寸,等待下一帧再试\n requestAnimationFrame(updatePosition)\n return\n }\n\n const sceneCoords = instanceRef.current.getCoords()\n const viewportCoords = sceneCoords.map(point => util.sendPointToPlane(point, canvas.viewportTransform, undefined))\n\n const platform = {\n getElementRects: (data: any) => data,\n getDimensions: (element: any) => element,\n getClippingRect: () => ({\n x: 0,\n y: 0,\n width: canvas.width,\n height: canvas.height,\n }),\n }\n\n const virtualEl = {\n x: viewportCoords[0].x,\n y: viewportCoords[0].y,\n width: viewportCoords[2].x - viewportCoords[0].x,\n height: viewportCoords[2].y - viewportCoords[0].y,\n }\n\n computePosition(virtualEl, floatingElRef.current.getBoundingClientRect(), {\n platform,\n placement,\n middleware: [offset(5), flip(), shift({ padding: 5 })],\n }).then(({ x, y }) => {\n if (!floatingElRef.current) return\n\n Object.assign(floatingElRef.current.style, {\n left: `${x}px`,\n top: `${y}px`,\n })\n })\n }, [canvas, placement])\n\n // 确保在元素挂载后更新位置\n // 这里测试下来是多余的,可删除;\n useEffect(() => {\n if (open) {\n requestAnimationFrame(updatePosition)\n }\n }, [open, updatePosition])\n\n useEffect(() => {\n canvas?.on('after:render', updatePosition)\n\n return () => {\n canvas?.off('after:render', updatePosition)\n }\n }, [canvas, updatePosition])\n\n useEffect(() => {\n const handleCanvasClick = (e: TPointerEventInfo<TPointerEvent>) => {\n // 阻止事件冒泡到 document\n e.e.stopPropagation()\n e.e.preventDefault() // 也阻止默认行为\n\n // 使用 id 比较来确保正确匹配\n // if (e.target === instanceRef.current) {\n // onOpenChange?.(!open)\n // }\n // // 点击其他区域时关闭\n // else if (open) {\n // onOpenChange?.(false)\n // }\n }\n\n const handleDocumentClick = (e: MouseEvent) => {\n // 如果点击在浮动内容内,不处理\n if (floatingElRef.current?.contains(e.target as Node)) {\n return\n }\n\n if (closeOnOutsideClick && open) {\n onOpenChange?.(false)\n }\n }\n\n canvas?.on('mouse:down', handleCanvasClick)\n // 改为冒泡阶段处理 document 事件\n document.addEventListener('mousedown', handleDocumentClick, false)\n\n return () => {\n canvas?.off('mouse:down', handleCanvasClick)\n document.removeEventListener('mousedown', handleDocumentClick, false)\n }\n }, [canvas, closeOnOutsideClick, onOpenChange, open])\n\n useEffect(() => {\n const { controls } = store.getState()\n\n const control = controls.find(control => control.id === id)\n\n if (control) {\n return\n }\n\n store.setState({\n controls: [\n ...controls,\n {\n id,\n className,\n children: Content,\n ref: floatingElRef,\n },\n ],\n })\n return () => {\n store.setState({\n controls: controls.filter(control => control.id !== id),\n })\n }\n }, [store])\n\n useEffect(() => {\n const { controls } = store.getState()\n const control = controls.find(control => control.id === id)\n\n if (control) {\n store.setState({\n controls: controls.map(control =>\n control.id === id ? { ...control, children: open ? Content : null, className } : control,\n ),\n })\n }\n }, [Content, className, id, store, open])\n\n return <>{newChildren}</>\n },\n)\n\nexport default Control\n"],"names":["generateRandomId","Control","React","children","className","placement","open","onOpenChange","closeOnOutsideClick","Content","forwardRef","instanceRef","useRef","canvas","useStore","state","floatingElRef","id","_setId","useState","store","useStoreApi","refCallback","useCallback","node","newChildren","useMemo","updatePosition","floatingRect","viewportCoords","point","util","platform","data","element","virtualEl","computePosition","offset","flip","shift","x","y","useEffect","handleCanvasClick","e","handleDocumentClick","controls","control","jsx","Fragment"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var o=require("fabric"),e=require("react"),p=require("../../hooks/useCreateObject.cjs"),n=require("../../hooks/useSplitProps.cjs");const c=e.forwardRef(({group:t,...u},s)=>{const[a,i,l]=n.useSplitProps(u),r=p.useCreateObject({Constructor:o.Ellipse,defaultValues:l,attributes:i,group:t,listeners:a});return e.useImperativeHandle(s,()=>r,[r]),null});var d=e.memo(c);exports.default=d;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var l=require("fabric"),r=require("react"),c=require("../../hooks/useCreateObject.cjs"),p=require("../../hooks/useSplitProps.cjs"),d=require("../../hooks/useInstancePosition.cjs");const v=r.forwardRef(({group:t,children:u,...s},i)=>{const[a,o,n]=p.useSplitProps(s),e=c.useCreateObject({Constructor:l.Ellipse,defaultValues:n,attributes:o,group:t,listeners:a});return r.useImperativeHandle(i,()=>e,[e]),d.useInstancePosition(e,u)});var b=r.memo(v);exports.default=b;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Ellipse/index.tsx"],"sourcesContent":["import type { Group as BaseGroup } from 'fabric'\nimport { Ellipse as BaseEllipse } from 'fabric'\nimport { forwardRef, memo, useImperativeHandle } from 'react'\nimport { useCreateObject } from '../../hooks/useCreateObject'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport type { AllObjectEvents } from '../../types/object'\n\nexport type EllipseProps<T = unknown> = Partial<BaseEllipse & AllObjectEvents> & {\n group?: BaseGroup\n defaultLeft?: number\n defaultTop?: number\n defaultWidth?: number\n defaultHeight?: number\n} & T\n\nconst Ellipse = forwardRef<BaseEllipse | undefined, EllipseProps>(({ group, ...props }, ref) => {\n const [listeners, attributes, defaultValues] = useSplitProps(props)\n\n const instance = useCreateObject({\n Constructor: BaseEllipse,\n defaultValues,\n attributes,\n group,\n listeners,\n })\n\n useImperativeHandle(ref, () => instance, [instance])\n\n return null\n})\n\nexport default memo(Ellipse)\n"],"names":["Ellipse","forwardRef","group","props","ref","listeners","attributes","defaultValues","useSplitProps","instance","useCreateObject","BaseEllipse","useImperativeHandle","memo"],"mappings":"uMAeA,MAAMA,EAAUC,EAAAA,WAAkD,CAAC,CAAE,MAAAC,EAAO,GAAGC,CAAM,EAAGC,IAAQ,CAC9F,KAAM,CAACC,EAAWC,EAAYC,CAAa,EAAIC,EAAAA,cAAcL,CAAK,EAE5DM,EAAWC,kBAAgB,CAC/B,YAAaC,EAAAA,QACb,cAAAJ,EACA,WAAAD,EACA,MAAAJ,EACA,UAAAG,CACF,CAAC,EAED,OAAAO,EAAAA,oBAAoBR,EAAK,IAAMK,EAAU,CAACA,CAAQ,CAAC,EAE5C,IACT,CAAC,EAED,MAAeI,OAAKb,CAAO"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Ellipse/index.tsx"],"sourcesContent":["import type { Group as BaseGroup } from 'fabric'\nimport { Ellipse as BaseEllipse } from 'fabric'\nimport { forwardRef, memo, useImperativeHandle, type ReactNode } from 'react'\nimport { useCreateObject } from '../../hooks/useCreateObject'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport type { AllObjectEvents } from '../../types/object'\nimport { useInstancePosition } from '../../hooks/useInstancePosition'\n\nexport type EllipseProps<T = unknown> = Partial<BaseEllipse & AllObjectEvents> & {\n group?: BaseGroup\n defaultLeft?: number\n defaultTop?: number\n defaultWidth?: number\n defaultHeight?: number\n children?: ReactNode\n} & T\n\nconst Ellipse = forwardRef<BaseEllipse | undefined, EllipseProps>(({ group, children, ...props }, ref) => {\n const [listeners, attributes, defaultValues] = useSplitProps(props)\n\n const instance = useCreateObject({\n Constructor: BaseEllipse,\n defaultValues,\n attributes,\n group,\n listeners,\n })\n useImperativeHandle(ref, () => instance, [instance])\n\n return useInstancePosition(instance, children)\n})\n\nexport default memo(Ellipse)\n"],"names":["Ellipse","forwardRef","group","children","props","ref","listeners","attributes","defaultValues","useSplitProps","instance","useCreateObject","BaseEllipse","useImperativeHandle","useInstancePosition","memo"],"mappings":"wPAiBA,MAAMA,EAAUC,EAAAA,WAAkD,CAAC,CAAE,MAAAC,EAAO,SAAAC,EAAU,GAAGC,CAAM,EAAGC,IAAQ,CACxG,KAAM,CAACC,EAAWC,EAAYC,CAAa,EAAIC,EAAAA,cAAcL,CAAK,EAE5DM,EAAWC,EAAAA,gBAAgB,CAC/B,YAAaC,EAAAA,QACb,cAAAJ,EACA,WAAAD,EACA,MAAAL,EACA,UAAAI,CACF,CAAC,EACD,OAAAO,EAAAA,oBAAoBR,EAAK,IAAMK,EAAU,CAACA,CAAQ,CAAC,EAE5CI,sBAAoBJ,EAAUP,CAAQ,CAC/C,CAAC,EAED,MAAeY,OAAKf,CAAO"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var l=require("react/jsx-runtime"),v=require("fabric"),r=require("react"),p=require("../../hooks/useDidUpdate.cjs"),f=require("../../hooks/useSplitProps.cjs"),m=require("../../hooks/useStore.cjs"),S=require("../../utils/events.cjs");const q=r.memo(({children:c,controlsVisibility:u,...d})=>{const s=m.useStoreApi(),[e,n]=r.useState(null),[a,i]=f.useSplitProps(d);return r.useLayoutEffect(()=>{const t=new v.Group([],{...i});return n(t),()=>{const{canvas:o}=s.getState();t&&o&&o.remove(t),n(null)}},[s]),r.useEffect(()=>{const{canvas:t}=s.getState();!e||!t||t.add(e)},[s,e]),r.useEffect(()=>e?S.bindEvents(e,a):void 0,[e,a]),r.useEffect(()=>{!e||!u||e.setControlsVisibility(u)},[e,u]),p.useDidUpdate(()=>{const{canvas:t}=s.getState();!e||!t||(e.set(i),e.setCoords(),t.requestRenderAll())},[i]),l.jsx(l.Fragment,{children:e&&r.Children.map(c,t=>r.isValidElement(t)?r.cloneElement(t,{group:e}):null)})});exports.default=q;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var l=require("react/jsx-runtime"),v=require("fabric"),r=require("react"),p=require("../../hooks/useDidUpdate.cjs"),f=require("../../hooks/useSplitProps.cjs"),S=require("../../hooks/useStore.cjs"),m=require("../../utils/events.cjs");const q=r.memo(({children:c,controlsVisibility:u,...d})=>{const s=S.useStoreApi(),[e,n]=r.useState(null),[a,i]=f.useSplitProps(d);return r.useLayoutEffect(()=>{const t=new v.Group([],{...i});return n(t),()=>{const{canvas:o}=s.getState();t&&o&&o.remove(t),n(null)}},[s]),r.useEffect(()=>{const{canvas:t}=s.getState();!e||!t||t.add(e)},[s,e]),r.useEffect(()=>e?m.bindEvents(e,a):void 0,[e,a]),r.useEffect(()=>{!e||!u||e.setControlsVisibility(u)},[e,u]),p.useDidUpdate(()=>{const{canvas:t}=s.getState();!e||!t||(e.set(i),e.setCoords(),t.requestRenderAll())},[i]),l.jsx(l.Fragment,{children:e&&r.Children.map(c,t=>r.isValidElement(t)?r.cloneElement(t,{group:e}):null)})});exports.default=q;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Group/index.tsx"],"sourcesContent":["import type { GroupEvents, GroupProps } from 'fabric'\nimport { Group as BaseGroup } from 'fabric'\nimport { Children, cloneElement, isValidElement, memo, useEffect, useLayoutEffect, useState } from 'react'\nimport { useDidUpdate } from '../../hooks/useDidUpdate'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport { useStoreApi } from '../../hooks/useStore'\nimport type { AllEvents } from '../../types/canvas'\nimport { bindEvents } from '../../utils/events'\n\nexport type MyGroupProps = Partial<GroupProps & AllEvents<GroupEvents>> & {\n children: React.ReactElement<{ group?: BaseGroup }>[] | React.ReactElement<{ group?: BaseGroup }>\n controlsVisibility?: {\n ml?: boolean\n mt?: boolean\n mr?: boolean\n mb?: boolean\n mtr?: boolean\n tl?: boolean\n tr?: boolean\n bl?: boolean\n br?: boolean\n }\n}\n\nconst Group = memo(({ children, controlsVisibility, ...props }: MyGroupProps) => {\n const store = useStoreApi()\n const [instance, setInstance] = useState<BaseGroup | null>(null)\n\n const [listeners, attributes] = useSplitProps(props)\n\n // 创建 Group 实例,但不立即添加到 canvas\n useLayoutEffect(() => {\n const newInstance = new BaseGroup([], {\n ...attributes,\n })\n setInstance(newInstance)\n\n return () => {\n const { canvas } = store.getState()\n if (newInstance && canvas) {\n canvas.remove(newInstance)\n }\n setInstance(null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store])\n\n // 等待子元素添加完成后,再将 group 添加到 canvas\n useEffect(() => {\n const { canvas } = store.getState()\n if (!instance || !canvas) return\n\n canvas.add(instance)\n }, [store, instance])\n\n // 单独处理事件绑定\n useEffect(() => {\n if (!instance) return\n\n const cleanup = bindEvents(instance, listeners)\n return cleanup\n }, [instance, listeners])\n\n // 专门处理 setControlsVisibility\n useEffect(() => {\n if (!instance || !controlsVisibility) return\n instance.setControlsVisibility(controlsVisibility)\n }, [instance, controlsVisibility])\n\n // 处理属性更新\n useDidUpdate(() => {\n const { canvas } = store.getState()\n if (!instance || !canvas) return\n\n instance.set(attributes)\n instance.setCoords()\n canvas.requestRenderAll()\n }, [attributes])\n\n return (\n <>\n {instance &&\n Children.map(children, child => {\n if (isValidElement(child)) {\n return cloneElement(child, {\n group: instance,\n })\n }\n return null\n })}\n </>\n )\n})\n\nexport default Group\n"],"names":["Group","memo","children","controlsVisibility","props","store","useStoreApi","instance","setInstance","useState","listeners","attributes","useSplitProps","useLayoutEffect","newInstance","BaseGroup","canvas","useEffect","bindEvents","useDidUpdate","jsx","Fragment","Children","child","isValidElement","cloneElement"],"mappings":"mTAwBMA,EAAQC,EAAAA,KAAK,CAAC,CAAE,SAAAC,EAAU,mBAAAC,EAAoB,GAAGC,CAAM,IAAoB,CAC/E,MAAMC,EAAQC,gBACR,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAA2B,IAAI,EAEzD,CAACC,EAAWC,CAAU,EAAIC,EAAAA,cAAcR,CAAK,EAGnD,OAAAS,EAAgB,gBAAA,IAAM,CACpB,MAAMC,EAAc,IAAIC,QAAU,CAAA,EAAI,CACpC,GAAGJ,CACL,CAAC,EACD,OAAAH,EAAYM,CAAW,EAEhB,IAAM,CACX,KAAM,CAAE,OAAAE,CAAO,EAAIX,EAAM,SAAS,EAC9BS,GAAeE,GACjBA,EAAO,OAAOF,CAAW,EAE3BN,EAAY,IAAI,CAClB,CAEF,EAAG,CAACH,CAAK,CAAC,EAGVY,EAAU,UAAA,IAAM,CACd,KAAM,CAAE,OAAAD,CAAO,EAAIX,EAAM,SAAS,EAC9B,CAACE,GAAY,CAACS,GAElBA,EAAO,IAAIT,CAAQ,CACrB,EAAG,CAACF,EAAOE,CAAQ,CAAC,EAGpBU,YAAU,IACHV,EAEWW,EAAAA,WAAWX,EAAUG,CAAS,EAF/B,OAId,CAACH,EAAUG,CAAS,CAAC,EAGxBO,EAAAA,UAAU,IAAM,CACV,CAACV,GAAY,CAACJ,GAClBI,EAAS,sBAAsBJ,CAAkB,CACnD,EAAG,CAACI,EAAUJ,CAAkB,CAAC,EAGjCgB,EAAAA,aAAa,IAAM,CACjB,KAAM,CAAE,OAAAH,CAAO,EAAIX,EAAM,SAAS,EAC9B,CAACE,GAAY,CAACS,IAElBT,EAAS,IAAII,CAAU,EACvBJ,EAAS,UACTS,EAAAA,EAAO,iBAAiB,EAC1B,EAAG,CAACL,CAAU,CAAC,EAGbS,EAAAA,IAAAC,EAAAA,SAAA,CACG,SAAAd,GACCe,EAAAA,SAAS,IAAIpB,EAAUqB,GACjBC,EAAAA,eAAeD,CAAK,EACfE,EAAAA,aAAaF,EAAO,CACzB,MAAOhB,CACT,CAAC,EAEI,IACR,CACL,CAAA,CAEJ,CAAC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Group/index.tsx"],"sourcesContent":["import type { GroupEvents, GroupProps } from 'fabric'\nimport { Group as BaseGroup } from 'fabric'\nimport { Children, cloneElement, isValidElement, memo, useEffect, useLayoutEffect, useState } from 'react'\nimport { useDidUpdate } from '../../hooks/useDidUpdate'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport { useStoreApi } from '../../hooks/useStore'\nimport type { AllEvents } from '../../types/canvas'\nimport { bindEvents } from '../../utils/events'\n\nexport type MyGroupProps = Partial<GroupProps & AllEvents<GroupEvents>> & {\n children: React.ReactElement<{ group?: BaseGroup }>[] | React.ReactElement<{ group?: BaseGroup }>\n controlsVisibility?: {\n ml?: boolean\n mt?: boolean\n mr?: boolean\n mb?: boolean\n mtr?: boolean\n tl?: boolean\n tr?: boolean\n bl?: boolean\n br?: boolean\n }\n}\n\nconst Group = memo(({ children, controlsVisibility, ...props }: MyGroupProps) => {\n const store = useStoreApi()\n const [instance, setInstance] = useState<BaseGroup | null>(null)\n\n const [listeners, attributes] = useSplitProps(props)\n\n // 创建 Group 实例,但不立即添加到 canvas\n useLayoutEffect(() => {\n const newInstance = new BaseGroup([], {\n ...attributes,\n })\n setInstance(newInstance)\n\n return () => {\n const { canvas } = store.getState()\n if (newInstance && canvas) {\n canvas.remove(newInstance)\n }\n setInstance(null)\n }\n }, [store])\n\n // 等待子元素添加完成后,再将 group 添加到 canvas\n useEffect(() => {\n const { canvas } = store.getState()\n if (!instance || !canvas) return\n\n canvas.add(instance)\n }, [store, instance])\n\n // 单独处理事件绑定\n useEffect(() => {\n if (!instance) return\n\n const cleanup = bindEvents(instance, listeners)\n return cleanup\n }, [instance, listeners])\n\n // 专门处理 setControlsVisibility\n useEffect(() => {\n if (!instance || !controlsVisibility) return\n instance.setControlsVisibility(controlsVisibility)\n }, [instance, controlsVisibility])\n\n // 处理属性更新\n useDidUpdate(() => {\n const { canvas } = store.getState()\n if (!instance || !canvas) return\n\n instance.set(attributes)\n instance.setCoords()\n canvas.requestRenderAll()\n }, [attributes])\n\n return (\n <>\n {instance &&\n Children.map(children, child => {\n if (isValidElement(child)) {\n return cloneElement(child, {\n group: instance,\n })\n }\n return null\n })}\n </>\n )\n})\n\nexport default Group\n"],"names":["Group","memo","children","controlsVisibility","props","store","useStoreApi","instance","setInstance","useState","listeners","attributes","useSplitProps","useLayoutEffect","newInstance","BaseGroup","canvas","useEffect","bindEvents","useDidUpdate","jsx","Fragment","Children","child","isValidElement","cloneElement"],"mappings":"mTAwBMA,EAAQC,EAAAA,KAAK,CAAC,CAAE,SAAAC,EAAU,mBAAAC,EAAoB,GAAGC,CAAM,IAAoB,CAC/E,MAAMC,EAAQC,gBACR,CAACC,EAAUC,CAAW,EAAIC,EAAAA,SAA2B,IAAI,EAEzD,CAACC,EAAWC,CAAU,EAAIC,EAAAA,cAAcR,CAAK,EAGnD,OAAAS,EAAgB,gBAAA,IAAM,CACpB,MAAMC,EAAc,IAAIC,QAAU,CAAA,EAAI,CACpC,GAAGJ,CACL,CAAC,EACD,OAAAH,EAAYM,CAAW,EAEhB,IAAM,CACX,KAAM,CAAE,OAAAE,CAAO,EAAIX,EAAM,SAAS,EAC9BS,GAAeE,GACjBA,EAAO,OAAOF,CAAW,EAE3BN,EAAY,IAAI,CAClB,CACF,EAAG,CAACH,CAAK,CAAC,EAGVY,EAAU,UAAA,IAAM,CACd,KAAM,CAAE,OAAAD,CAAO,EAAIX,EAAM,SAAS,EAC9B,CAACE,GAAY,CAACS,GAElBA,EAAO,IAAIT,CAAQ,CACrB,EAAG,CAACF,EAAOE,CAAQ,CAAC,EAGpBU,YAAU,IACHV,EAEWW,EAAAA,WAAWX,EAAUG,CAAS,EAF/B,OAId,CAACH,EAAUG,CAAS,CAAC,EAGxBO,EAAAA,UAAU,IAAM,CACV,CAACV,GAAY,CAACJ,GAClBI,EAAS,sBAAsBJ,CAAkB,CACnD,EAAG,CAACI,EAAUJ,CAAkB,CAAC,EAGjCgB,EAAAA,aAAa,IAAM,CACjB,KAAM,CAAE,OAAAH,CAAO,EAAIX,EAAM,SAAS,EAC9B,CAACE,GAAY,CAACS,IAElBT,EAAS,IAAII,CAAU,EACvBJ,EAAS,UACTS,EAAAA,EAAO,iBAAiB,EAC1B,EAAG,CAACL,CAAU,CAAC,EAGbS,EAAAA,IAAAC,EAAAA,SAAA,CACG,SAAAd,GACCe,EAAAA,SAAS,IAAIpB,EAAUqB,GACjBC,EAAAA,eAAeD,CAAK,EACfE,EAAAA,aAAaF,EAAO,CACzB,MAAOhB,CACT,CAAC,EAEI,IACR,CACL,CAAA,CAEJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("fabric"),t=require("react"),p=require("../../hooks/useCreateObject.cjs"),d=require("../../hooks/useSplitProps.cjs"),l=require("../../hooks/useInstancePosition.cjs");e.IText.prototype.set({_getNonTransformedDimensions(){return new e.Point(this.width,this.height).scalarAdd(this.padding)},_calculateCurrentDimensions(){return e.util.transformPoint(this._getTransformedDimensions(),this.getViewportTransform(),!0)}});const m=t.forwardRef(({group:s,text:i,children:n,...a},o)=>{const[u,c]=d.useSplitProps(a),r=p.useCreateObject({Constructor:e.IText,param:i,attributes:c,group:s,listeners:u});return t.useImperativeHandle(o,()=>r,[r]),l.useInstancePosition(r,n)});var h=t.memo(m);exports.default=h;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/IText/index.tsx"],"sourcesContent":["import type { Group as BaseGroup } from 'fabric'\nimport { IText, util, Point } from 'fabric'\nimport { forwardRef, memo, useImperativeHandle, type ReactNode } from 'react'\nimport { useCreateObject } from '../../hooks/useCreateObject'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport type { AllObjectEvents } from '../../types/object'\nimport { useInstancePosition } from '../../hooks/useInstancePosition'\n\nexport type ITextProps<T = unknown> = Partial<ConstructorParameters<typeof IText>[1] & AllObjectEvents> & {\n group?: BaseGroup\n text: string\n children?: ReactNode\n} & T\n\nIText.prototype.set({\n _getNonTransformedDimensions() {\n // Object dimensions\n return new Point(this.width, this.height).scalarAdd(this.padding)\n },\n _calculateCurrentDimensions() {\n // Controls dimensions\n return util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true)\n },\n})\n\nconst ITextBox = forwardRef<IText | undefined, ITextProps>(({ group, text, children, ...props }, ref) => {\n const [listeners, attributes] = useSplitProps(props)\n\n const instance = useCreateObject({\n Constructor: IText,\n param: text,\n attributes,\n group,\n listeners,\n })\n\n useImperativeHandle(ref, () => instance, [instance])\n\n return useInstancePosition(instance, children)\n})\n\nexport default memo(ITextBox)\n"],"names":["IText","Point","util","ITextBox","forwardRef","group","text","children","props","ref","listeners","attributes","useSplitProps","instance","useCreateObject","useImperativeHandle","useInstancePosition","x","memo"],"mappings":"wPAcAA,EAAAA,MAAM,UAAU,IAAI,CAClB,8BAA+B,CAE7B,OAAO,IAAIC,EAAM,MAAA,KAAK,MAAO,KAAK,MAAM,EAAE,UAAU,KAAK,OAAO,CAClE,EACA,6BAA8B,CAE5B,OAAOC,EAAAA,KAAK,eAAe,KAAK,4BAA6B,KAAK,uBAAwB,EAAI,CAChG,CACF,CAAC,EAED,MAAMC,EAAWC,EAA0C,WAAA,CAAC,CAAE,MAAAC,EAAO,KAAAC,EAAM,SAAAC,EAAU,GAAGC,CAAM,EAAGC,IAAQ,CACvG,KAAM,CAACC,EAAWC,CAAU,EAAIC,gBAAcJ,CAAK,EAE7CK,EAAWC,EAAgB,gBAAA,CAC/B,YAAad,EACb,MAAA,MAAOM,EACP,WAAAK,EACA,MAAAN,EACA,UAAAK,CACF,CAAC,EAED,OAAAK,sBAAoBN,EAAK,IAAMI,EAAU,CAACA,CAAQ,CAAC,EAE5CG,EAAoBH,oBAAAA,EAAUN,CAAQ,CAC/C,CAAC,EAED,IAAAU,EAAeC,EAAAA,KAAKf,CAAQ"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var v=require("fabric"),e=require("react"),l=require("../../hooks/useDidUpdate.cjs"),p=require("../../hooks/useStore.cjs");const R=e.forwardRef(({group:a,src:c,onLoad:o,...t},m)=>{const r=e.useRef(),i=e.useRef(o),u=p.useStoreApi(),d=e.useRef(t);return e.useEffect(()=>{i.current=o,d.current=t}),e.useEffect(()=>{const{canvas:n}=u.getState();if(!n?.getElement())return;const f=a??n;return v.FabricImage.fromURL(c,{crossOrigin:"anonymous"}).then(s=>{r.current=s,s.set(d.current),i.current?.(s),f.add(s)}),()=>{r.current&&f?.remove(r.current)}},[c,u,a]),l.useDidUpdate(()=>{const{canvas:n}=u.getState();r.current&&(r.current.set(t),r.current.setCoords(),n?.requestRenderAll())},[t,u]),e.useImperativeHandle(m,()=>({instance:r.current})),null});var g=e.memo(R);exports.default=g;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var l=require("fabric"),e=require("react"),g=require("../../hooks/useStore.cjs"),p=require("../../hooks/useInstancePosition.cjs");const R=e.forwardRef(({group:u,src:n,onLoad:c,children:m,...s},v)=>{const r=e.useRef(),o=e.useRef(c),a=g.useStoreApi(),i=e.useRef(s);return e.useEffect(()=>{o.current=c,i.current=s}),e.useEffect(()=>{const{canvas:f}=a.getState();if(!f?.getElement())return;const d=u??f;return l.FabricImage.fromURL(n,{crossOrigin:"anonymous"}).then(t=>{r.current=t,t.set(i.current),o.current?.(t),d.add(t)}),()=>{r.current&&d?.remove(r.current)}},[n,a,u]),e.useImperativeHandle(v,()=>r.current),p.useInstancePosition(r.current,m)});var q=e.memo(R);exports.default=q;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Image/index.tsx"],"sourcesContent":["import type { ImageProps as FabricImageProps, ObjectEvents, SerializedImageProps, Canvas } from 'fabric'\nimport { FabricImage } from 'fabric'\nimport type { Group as BaseGroup } from 'fabric'\nimport { forwardRef, memo, useEffect, useImperativeHandle, useRef } from 'react'\nimport { useDidUpdate } from '../../hooks/useDidUpdate'\nimport { useStoreApi } from '../../hooks/useStore'\n\nexport type Handle = {\n instance: FabricImage | undefined\n}\n\nexport type ImageProps = Partial<FabricImageProps> & {\n src: string\n group?: BaseGroup\n onLoad?: (imageSource: FabricImage<Partial<ImageProps>, SerializedImageProps, ObjectEvents>) => void\n}\n\nconst Image = forwardRef<Handle, ImageProps>(({ group, src, onLoad, ...options }, ref) => {\n const instanceRef = useRef<FabricImage>()\n const onLoadRef = useRef(onLoad)\n const store = useStoreApi()\n const optionsRef = useRef(options)\n\n // 更新 onLoadRef\n useEffect(() => {\n onLoadRef.current = onLoad\n optionsRef.current = options\n })\n\n // 只在 src 改变时初始化 image\n useEffect(() => {\n const { canvas } = store.getState()\n if (!canvas?.getElement()) return\n\n const parent = group ?? canvas\n\n FabricImage.fromURL(src, { crossOrigin: 'anonymous' }).then(imageSource => {\n instanceRef.current = imageSource\n imageSource.set(optionsRef.current)\n onLoadRef.current?.(imageSource)\n parent.add(imageSource)\n })\n\n return () => {\n if (instanceRef.current) {\n parent?.remove(instanceRef.current)\n }\n }\n }, [src, store, group]) // 只包含初始化需要的依赖\n\n // 只在 options 更新时执行\n useDidUpdate(() => {\n const { canvas } = store.getState()\n\n if (instanceRef.current) {\n instanceRef.current.set(options)\n instanceRef.current.setCoords()\n canvas?.requestRenderAll()\n }\n }, [options, store])\n\n useImperativeHandle(ref, () => ({\n instance: instanceRef.current,\n }))\n\n return null\n})\n\nexport default memo(Image)\n"],"names":["Image","forwardRef","group","src","onLoad","options","ref","instanceRef","useRef","onLoadRef","store","useStoreApi","optionsRef","useEffect","canvas","parent","FabricImage","imageSource","useDidUpdate","useImperativeHandle","memo"],"mappings":"+LAiBA,MAAMA,EAAQC,EAAAA,WAA+B,CAAC,CAAE,MAAAC,EAAO,IAAAC,EAAK,OAAAC,EAAQ,GAAGC,CAAQ,EAAGC,IAAQ,CACxF,MAAMC,EAAcC,EAAAA,OAAoB,EAClCC,EAAYD,EAAAA,OAAOJ,CAAM,EACzBM,EAAQC,EAAAA,YACRC,EAAAA,EAAaJ,SAAOH,CAAO,EAGjC,OAAAQ,EAAU,UAAA,IAAM,CACdJ,EAAU,QAAUL,EACpBQ,EAAW,QAAUP,CACvB,CAAC,EAGDQ,EAAAA,UAAU,IAAM,CACd,KAAM,CAAE,OAAAC,CAAO,EAAIJ,EAAM,SAAS,EAClC,GAAI,CAACI,GAAQ,WAAc,EAAA,OAE3B,MAAMC,EAASb,GAASY,EAExB,OAAAE,EAAAA,YAAY,QAAQb,EAAK,CAAE,YAAa,WAAY,CAAC,EAAE,KAAKc,GAAe,CACzEV,EAAY,QAAUU,EACtBA,EAAY,IAAIL,EAAW,OAAO,EAClCH,EAAU,UAAUQ,CAAW,EAC/BF,EAAO,IAAIE,CAAW,CACxB,CAAC,EAEM,IAAM,CACPV,EAAY,SACdQ,GAAQ,OAAOR,EAAY,OAAO,CAEtC,CACF,EAAG,CAACJ,EAAKO,EAAOR,CAAK,CAAC,EAGtBgB,EAAAA,aAAa,IAAM,CACjB,KAAM,CAAE,OAAAJ,CAAO,EAAIJ,EAAM,WAErBH,EAAY,UACdA,EAAY,QAAQ,IAAIF,CAAO,EAC/BE,EAAY,QAAQ,UAAA,EACpBO,GAAQ,iBAEZ,EAAA,EAAG,CAACT,EAASK,CAAK,CAAC,EAEnBS,EAAAA,oBAAoBb,EAAK,KAAO,CAC9B,SAAUC,EAAY,OACxB,EAAE,EAEK,IACT,CAAC,EAED,IAAea,EAAAA,EAAAA,KAAKpB,CAAK"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Image/index.tsx"],"sourcesContent":["import type { ImageProps as FabricImageProps, ObjectEvents, SerializedImageProps } from 'fabric'\nimport { FabricImage } from 'fabric'\nimport type { Group as BaseGroup } from 'fabric'\nimport { forwardRef, memo, useEffect, useImperativeHandle, useRef, type ReactNode } from 'react'\nimport { useStoreApi } from '../../hooks/useStore'\nimport { useInstancePosition } from '../../hooks/useInstancePosition'\n\nexport type ImageProps = Partial<FabricImageProps> & {\n src: string\n group?: BaseGroup\n onLoad?: (imageSource: FabricImage<Partial<ImageProps>, SerializedImageProps, ObjectEvents>) => void\n children?: ReactNode\n}\n\nconst Image = forwardRef<FabricImage | undefined, ImageProps>(({ group, src, onLoad, children, ...options }, ref) => {\n const instanceRef = useRef<FabricImage>()\n const onLoadRef = useRef(onLoad)\n const store = useStoreApi()\n const optionsRef = useRef(options)\n\n // 更新 onLoadRef\n useEffect(() => {\n onLoadRef.current = onLoad\n optionsRef.current = options\n })\n\n // 只在 src 改变时初始化 image\n useEffect(() => {\n const { canvas } = store.getState()\n if (!canvas?.getElement()) return\n\n const parent = group ?? canvas\n\n FabricImage.fromURL(src, { crossOrigin: 'anonymous' }).then(imageSource => {\n instanceRef.current = imageSource\n imageSource.set(optionsRef.current)\n onLoadRef.current?.(imageSource)\n parent.add(imageSource)\n })\n\n return () => {\n if (instanceRef.current) {\n parent?.remove(instanceRef.current)\n }\n }\n }, [src, store, group]) // 只包含初始化需要的依赖\n\n useImperativeHandle(ref, () => instanceRef.current)\n\n return useInstancePosition(instanceRef.current, children)\n})\n\nexport default memo(Image)\n"],"names":["Image","forwardRef","group","src","onLoad","children","options","ref","instanceRef","useRef","onLoadRef","store","useStoreApi","optionsRef","useEffect","canvas","parent","FabricImage","imageSource","useImperativeHandle","useInstancePosition","memo"],"mappings":"sMAcA,MAAMA,EAAQC,EAAAA,WAAgD,CAAC,CAAE,MAAAC,EAAO,IAAAC,EAAK,OAAAC,EAAQ,SAAAC,EAAU,GAAGC,CAAQ,EAAGC,IAAQ,CACnH,MAAMC,EAAcC,EAAAA,OAAoB,EAClCC,EAAYD,SAAOL,CAAM,EACzBO,EAAQC,EAAY,YAAA,EACpBC,EAAaJ,EAAAA,OAAOH,CAAO,EAGjC,OAAAQ,EAAAA,UAAU,IAAM,CACdJ,EAAU,QAAUN,EACpBS,EAAW,QAAUP,CACvB,CAAC,EAGDQ,EAAAA,UAAU,IAAM,CACd,KAAM,CAAE,OAAAC,CAAO,EAAIJ,EAAM,SAAS,EAClC,GAAI,CAACI,GAAQ,WAAW,EAAG,OAE3B,MAAMC,EAASd,GAASa,EAExB,OAAAE,cAAY,QAAQd,EAAK,CAAE,YAAa,WAAY,CAAC,EAAE,KAAKe,GAAe,CACzEV,EAAY,QAAUU,EACtBA,EAAY,IAAIL,EAAW,OAAO,EAClCH,EAAU,UAAUQ,CAAW,EAC/BF,EAAO,IAAIE,CAAW,CACxB,CAAC,EAEM,IAAM,CACPV,EAAY,SACdQ,GAAQ,OAAOR,EAAY,OAAO,CAEtC,CACF,EAAG,CAACL,EAAKQ,EAAOT,CAAK,CAAC,EAEtBiB,sBAAoBZ,EAAK,IAAMC,EAAY,OAAO,EAE3CY,EAAAA,oBAAoBZ,EAAY,QAASH,CAAQ,CAC1D,CAAC,EAED,IAAegB,EAAAA,EAAAA,KAAKrB,CAAK"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var c=require("fabric"),e=require("react"),v=require("../../hooks/useCreateObject.cjs"),b=require("../../hooks/useSplitProps.cjs");const f=e.forwardRef(({group:t,x1:u,y1:a,x2:s,y2:i,...o},l)=>{const[n,p]=b.useSplitProps(o),r=v.useCreateObject({Constructor:c.Line,param:[u,a,s,i],attributes:p,group:t,listeners:n});return e.useImperativeHandle(l,()=>r,[r]),null});var m=e.memo(f);exports.default=m;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var v=require("fabric"),r=require("react"),d=require("../../hooks/useCreateObject.cjs"),P=require("../../hooks/useSplitProps.cjs"),b=require("../../hooks/useInstancePosition.cjs");const f=r.forwardRef(({group:t,x1:u,y1:s,x2:a,y2:i,children:o,...n},c)=>{const[p,l]=P.useSplitProps(n),e=d.useCreateObject({Constructor:v.Line,param:[u,s,a,i],attributes:l,group:t,listeners:p});return r.useImperativeHandle(c,()=>e,[e]),b.useInstancePosition(e,o)});var m=r.memo(f);exports.default=m;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Line/index.tsx"],"sourcesContent":["import type { Group as BaseGroup } from 'fabric'\nimport { Line as BaseLine } from 'fabric'\nimport { forwardRef, memo, useImperativeHandle } from 'react'\nimport { useCreateObject } from '../../hooks/useCreateObject'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport type { AllObjectEvents } from '../../types/object'\n\nexport type Handle = BaseLine | undefined\n\nexport type LineProps<T = unknown> = Partial<ConstructorParameters<typeof BaseLine>[1] & AllObjectEvents> & {\n group?: BaseGroup\n path?: string\n} & T\n\nconst Line = forwardRef<Handle, LineProps>(({ group, x1, y1, x2, y2, ...props }, ref) => {\n const [listeners, attributes] = useSplitProps(props)\n\n const instance = useCreateObject({\n Constructor: BaseLine,\n param: [x1, y1, x2, y2],\n attributes,\n group,\n listeners,\n })\n\n useImperativeHandle(ref, () => instance, [instance])\n\n return null\n})\n\nexport default memo(Line)\n"],"names":["Line","forwardRef","group","x1","y1","x2","y2","props","ref","listeners","attributes","useSplitProps","instance","useCreateObject","BaseLine","useImperativeHandle","memo"],"mappings":"uMAcA,MAAMA,EAAOC,aAA8B,CAAC,CAAE,MAAAC,EAAO,GAAAC,EAAI,GAAAC,EAAI,GAAAC,EAAI,GAAAC,EAAI,GAAGC,CAAM,EAAGC,IAAQ,CACvF,KAAM,CAACC,EAAWC,CAAU,EAAIC,gBAAcJ,CAAK,EAE7CK,EAAWC,EAAAA,gBAAgB,CAC/B,YAAaC,EAAAA,KACb,MAAO,CAACX,EAAIC,EAAIC,EAAIC,CAAE,EACtB,WAAAI,EACA,MAAAR,EACA,UAAAO,CACF,CAAC,EAED,OAAAM,EAAAA,oBAAoBP,EAAK,IAAMI,EAAU,CAACA,CAAQ,CAAC,EAE5C,IACT,CAAC,EAED,IAAeI,EAAAA,EAAAA,KAAKhB,CAAI"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Line/index.tsx"],"sourcesContent":["import type { Group as BaseGroup } from 'fabric'\nimport { Line as BaseLine } from 'fabric'\nimport { forwardRef, memo, useImperativeHandle, type ReactNode } from 'react'\nimport { useCreateObject } from '../../hooks/useCreateObject'\nimport { useSplitProps } from '../../hooks/useSplitProps'\nimport type { AllObjectEvents } from '../../types/object'\nimport { useInstancePosition } from '../../hooks/useInstancePosition'\n\nexport type Handle = BaseLine | undefined\n\nexport type LineProps<T = unknown> = Partial<ConstructorParameters<typeof BaseLine>[1] & AllObjectEvents> & {\n group?: BaseGroup\n path?: string\n children?: ReactNode\n} & T\n\nconst Line = forwardRef<Handle, LineProps>(({ group, x1, y1, x2, y2, children, ...props }, ref) => {\n const [listeners, attributes] = useSplitProps(props)\n\n const instance = useCreateObject({\n Constructor: BaseLine,\n param: [x1, y1, x2, y2],\n attributes,\n group,\n listeners,\n })\n\n useImperativeHandle(ref, () => instance, [instance])\n\n return useInstancePosition(instance, children)\n})\n\nexport default memo(Line)\n"],"names":["Line","forwardRef","group","x1","y1","x2","y2","children","props","ref","listeners","attributes","useSplitProps","instance","useCreateObject","BaseLine","useImperativeHandle","useInstancePosition","memo"],"mappings":"wPAgBA,MAAMA,EAAOC,EAAAA,WAA8B,CAAC,CAAE,MAAAC,EAAO,GAAAC,EAAI,GAAAC,EAAI,GAAAC,EAAI,GAAAC,EAAI,SAAAC,EAAU,GAAGC,CAAM,EAAGC,IAAQ,CACjG,KAAM,CAACC,EAAWC,CAAU,EAAIC,EAAAA,cAAcJ,CAAK,EAE7CK,EAAWC,EAAgB,gBAAA,CAC/B,YAAaC,EACb,KAAA,MAAO,CAACZ,EAAIC,EAAIC,EAAIC,CAAE,EACtB,WAAAK,EACA,MAAAT,EACA,UAAAQ,CACF,CAAC,EAED,OAAAM,EAAAA,oBAAoBP,EAAK,IAAMI,EAAU,CAACA,CAAQ,CAAC,EAE5CI,sBAAoBJ,EAAUN,CAAQ,CAC/C,CAAC,EAED,IAAeW,EAAAA,EAAAA,KAAKlB,CAAI"}
@@ -0,0 +1,11 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),r=require("../../hooks/useStore.cjs");const o=()=>r.useStore(t=>t.loading)?e.jsxs("div",{style:{position:"absolute",bottom:0,left:0,right:0,top:0,zIndex:40,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",overflow:"hidden"},children:[e.jsx("span",{style:{width:"48px",height:"48px",border:"5px solid #04aa65",borderBottomColor:"transparent",borderRadius:"50%",display:"inline-block",boxSizing:"border-box",animation:"rotation 1s linear infinite"}}),e.jsx("style",{children:`
2
+ @keyframes rotation {
3
+ 0% {
4
+ transform: rotate(0deg);
5
+ }
6
+ 100% {
7
+ transform: rotate(360deg);
8
+ }
9
+ }
10
+ `})]}):null;exports.default=o;
11
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Loading/index.tsx"],"sourcesContent":["import { useStore } from '../../hooks/useStore'\n\n// bg-[hsla(221,14%,4%,0.6)\nconst Loading = () => {\n const loading = useStore(state => state.loading)\n\n return loading ? (\n <div\n style={{\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n top: 0,\n zIndex: 40,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n overflow: 'hidden',\n }}\n >\n <span\n style={{\n width: '48px',\n height: '48px',\n border: '5px solid #04aa65',\n borderBottomColor: 'transparent',\n borderRadius: '50%',\n display: 'inline-block',\n boxSizing: 'border-box',\n animation: 'rotation 1s linear infinite',\n }}\n ></span>\n <style>\n {`\n @keyframes rotation {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n `}\n </style>\n </div>\n ) : null\n}\n\nexport default Loading\n"],"names":["Loading","useStore","state","jsxs","jsx"],"mappings":"6IAGMA,MAAAA,EAAU,IACEC,EAAAA,SAASC,GAASA,EAAM,OAAO,EAG7CC,EAAAA,KAAC,MACC,CAAA,MAAO,CACL,SAAU,WACV,OAAQ,EACR,KAAM,EACN,MAAO,EACP,IAAK,EACL,OAAQ,GACR,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,SAAU,QACZ,EAEA,SAAA,CAAAC,EAAAA,IAAC,OAAA,CACC,MAAO,CACL,MAAO,OACP,OAAQ,OACR,OAAQ,oBACR,kBAAmB,cACnB,aAAc,MACd,QAAS,eACT,UAAW,aACX,UAAW,6BACb,CACD,CAAA,EACDA,MAAC,QACE,CAAA,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAUH,CAAA,CAAA,CAAA,CACF,EACE"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var i=require("react-dom"),d=require("tailwind-merge"),u=require("react"),f=require("../../hooks/useStore.cjs");const v=a=>a.domNode?.querySelector(".react-fabric__canvas"),m=u.forwardRef(({children:a,className:l,onClick:n},t)=>{const o=f.useStore(v),e=u.useRef(),s=u.useCallback(r=>{r!==e.current&&(e.current=r||void 0,typeof t=="function"?t(r):t&&(t.current=r))},[t]);if(u.useEffect(()=>()=>{e.current&&(e.current.remove(),e.current=void 0)},[]),!o||e.current)return e.current?i.createPortal(a,e.current):null;const c=document.createElement("div");return c.className=d.twMerge("react-fabric__portal",l),n&&c.addEventListener("click",r=>{r.stopPropagation(),n(r)}),o.appendChild(c),s(c),i.createPortal(a,c)});exports.default=m;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var i=require("react-dom"),a=require("react"),d=require("../../hooks/useStore.cjs");const f=u=>u.domNode?.querySelector(".react-fabric__canvas"),v=a.forwardRef(({children:u,className:l,onClick:n},t)=>{const o=d.useStore(f),e=a.useRef(),s=a.useCallback(r=>{r!==e.current&&(e.current=r||void 0,typeof t=="function"?t(r):t&&(t.current=r))},[t]);if(a.useEffect(()=>()=>{e.current&&(e.current.remove(),e.current=void 0)},[]),!o||e.current)return e.current?i.createPortal(u,e.current):null;const c=document.createElement("div");return c.className=`react-fabric__portal ${l}`,n&&c.addEventListener("click",r=>{r.stopPropagation(),n(r)}),o.appendChild(c),s(c),i.createPortal(u,c)});exports.default=v;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/NodeToolbarPortal/index.tsx"],"sourcesContent":["import { createPortal } from 'react-dom'\nimport { twMerge } from 'tailwind-merge'\nimport type { ReactNode } from 'react'\nimport { forwardRef, useCallback, useEffect, useRef } from 'react'\nimport { useStore } from '../../hooks/useStore'\nimport type { ReactFabricState } from '../../types/store'\n\nconst selector = (state: ReactFabricState) => state.domNode?.querySelector('.react-fabric__canvas')\n\ninterface Props {\n children: ReactNode\n className?: string\n onClick?: (e: React.MouseEvent) => void\n}\n\nconst NodeToolbarPortal = forwardRef<HTMLDivElement, Props>(({ children, className, onClick }, forwardRef) => {\n const wrapperRef = useStore(selector)\n const containerRef = useRef<HTMLDivElement>()\n\n // 使用 useCallback 创建稳定的 ref 回调\n const refCallback = useCallback(\n (node: HTMLDivElement | null) => {\n if (node !== containerRef.current) {\n containerRef.current = node || undefined\n\n if (typeof forwardRef === 'function') {\n forwardRef(node)\n } else if (forwardRef) {\n forwardRef.current = node\n }\n }\n },\n [forwardRef],\n )\n\n // 组件卸载时清理\n useEffect(() => {\n return () => {\n if (containerRef.current) {\n containerRef.current.remove()\n containerRef.current = undefined\n }\n }\n }, [])\n\n // 如果已经有 container 或没有 wrapper,直接返回\n if (!wrapperRef || containerRef.current) {\n return containerRef.current ? createPortal(children, containerRef.current) : null\n }\n\n // 创建 DOM 元素\n const div = document.createElement('div')\n div.className = twMerge('react-fabric__portal', className)\n if (onClick) {\n div.addEventListener('click', e => {\n e.stopPropagation()\n onClick(e as any)\n })\n }\n wrapperRef.appendChild(div)\n refCallback(div)\n\n return createPortal(children, div)\n})\n\nexport default NodeToolbarPortal\n"],"names":["selector","state","NodeToolbarPortal","forwardRef","children","className","onClick","wrapperRef","useStore","containerRef","useRef","refCallback","useCallback","node","useEffect","createPortal","div","twMerge","e"],"mappings":"oLAOA,MAAMA,EAAYC,GAA4BA,EAAM,SAAS,cAAc,uBAAuB,EAQ5FC,EAAoBC,EAAkC,WAAA,CAAC,CAAE,SAAAC,EAAU,UAAAC,EAAW,QAAAC,CAAQ,EAAGH,IAAe,CAC5G,MAAMI,EAAaC,EAASR,SAAAA,CAAQ,EAC9BS,EAAeC,EAAAA,OAAAA,EAGfC,EAAcC,EAAAA,YACjBC,GAAgC,CAC3BA,IAASJ,EAAa,UACxBA,EAAa,QAAUI,GAAQ,OAE3B,OAAOV,GAAe,WACxBA,EAAWU,CAAI,EACNV,IACTA,EAAW,QAAUU,GAG3B,EACA,CAACV,CAAU,CACb,EAaA,GAVAW,EAAAA,UAAU,IACD,IAAM,CACPL,EAAa,UACfA,EAAa,QAAQ,SACrBA,EAAa,QAAU,OAE3B,EACC,CAAA,CAAE,EAGD,CAACF,GAAcE,EAAa,QAC9B,OAAOA,EAAa,QAAUM,EAAAA,aAAaX,EAAUK,EAAa,OAAO,EAAI,KAI/E,MAAMO,EAAM,SAAS,cAAc,KAAK,EACxC,OAAAA,EAAI,UAAYC,EAAAA,QAAQ,uBAAwBZ,CAAS,EACrDC,GACFU,EAAI,iBAAiB,QAASE,GAAK,CACjCA,EAAE,gBACFZ,EAAAA,EAAQY,CAAQ,CAClB,CAAC,EAEHX,EAAW,YAAYS,CAAG,EAC1BL,EAAYK,CAAG,EAERD,EAAAA,aAAaX,EAAUY,CAAG,CACnC,CAAC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/NodeToolbarPortal/index.tsx"],"sourcesContent":["import { createPortal } from 'react-dom'\nimport type { ReactNode } from 'react'\nimport { forwardRef, useCallback, useEffect, useRef } from 'react'\nimport { useStore } from '../../hooks/useStore'\nimport type { ReactFabricState } from '../../types/store'\n\nconst selector = (state: ReactFabricState) => state.domNode?.querySelector('.react-fabric__canvas')\n\ninterface Props {\n children: ReactNode\n className?: string\n onClick?: (e: React.MouseEvent) => void\n}\n\nconst NodeToolbarPortal = forwardRef<HTMLDivElement, Props>(({ children, className, onClick }, forwardRef) => {\n const wrapperRef = useStore(selector)\n const containerRef = useRef<HTMLDivElement>()\n\n // 使用 useCallback 创建稳定的 ref 回调\n const refCallback = useCallback(\n (node: HTMLDivElement | null) => {\n if (node !== containerRef.current) {\n containerRef.current = node || undefined\n\n if (typeof forwardRef === 'function') {\n forwardRef(node)\n } else if (forwardRef) {\n forwardRef.current = node\n }\n }\n },\n [forwardRef],\n )\n\n // 组件卸载时清理\n useEffect(() => {\n return () => {\n if (containerRef.current) {\n containerRef.current.remove()\n containerRef.current = undefined\n }\n }\n }, [])\n\n // 如果已经有 container 或没有 wrapper,直接返回\n if (!wrapperRef || containerRef.current) {\n return containerRef.current ? createPortal(children, containerRef.current) : null\n }\n\n // 创建 DOM 元素\n const div = document.createElement('div')\n div.className = `react-fabric__portal ${className}`\n if (onClick) {\n div.addEventListener('click', e => {\n e.stopPropagation()\n onClick(e as any)\n })\n }\n wrapperRef.appendChild(div)\n refCallback(div)\n\n return createPortal(children, div)\n})\n\nexport default NodeToolbarPortal\n"],"names":["selector","state","NodeToolbarPortal","forwardRef","children","className","onClick","wrapperRef","useStore","containerRef","useRef","refCallback","useCallback","node","useEffect","createPortal","div","e"],"mappings":"wJAMA,MAAMA,EAAYC,GAA4BA,EAAM,SAAS,cAAc,uBAAuB,EAQ5FC,EAAoBC,EAAAA,WAAkC,CAAC,CAAE,SAAAC,EAAU,UAAAC,EAAW,QAAAC,CAAQ,EAAGH,IAAe,CAC5G,MAAMI,EAAaC,WAASR,CAAQ,EAC9BS,EAAeC,EAAAA,OAAAA,EAGfC,EAAcC,EAAAA,YACjBC,GAAgC,CAC3BA,IAASJ,EAAa,UACxBA,EAAa,QAAUI,GAAQ,OAE3B,OAAOV,GAAe,WACxBA,EAAWU,CAAI,EACNV,IACTA,EAAW,QAAUU,GAG3B,EACA,CAACV,CAAU,CACb,EAaA,GAVAW,EAAAA,UAAU,IACD,IAAM,CACPL,EAAa,UACfA,EAAa,QAAQ,SACrBA,EAAa,QAAU,OAE3B,EACC,CAAA,CAAE,EAGD,CAACF,GAAcE,EAAa,QAC9B,OAAOA,EAAa,QAAUM,EAAAA,aAAaX,EAAUK,EAAa,OAAO,EAAI,KAI/E,MAAMO,EAAM,SAAS,cAAc,KAAK,EACxC,OAAAA,EAAI,UAAY,wBAAwBX,CAAS,GAC7CC,GACFU,EAAI,iBAAiB,QAASC,GAAK,CACjCA,EAAE,gBACFX,EAAAA,EAAQW,CAAQ,CAClB,CAAC,EAEHV,EAAW,YAAYS,CAAG,EAC1BL,EAAYK,CAAG,EAERD,EAAAA,aAAaX,EAAUY,CAAG,CACnC,CAAC"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),l=require("react"),d=require("../Path/index.cjs"),u=require("../Text/index.cjs"),s=require("../Rect/index.cjs"),o=require("../Line/index.cjs");const x=({objects:r})=>{const a={rect:s.default,path:d.default,text:u.default,line:o.default,"i-text":u.default};return r?e.jsx(e.Fragment,{children:r?.map(({type:n,...i})=>{const t=a[n.toLowerCase()];return t?e.jsx(t,{...i}):null})}):null};var c=l.memo(x);exports.default=c;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),d=require("react"),l=require("../Path/index.cjs"),u=require("../Text/index.cjs"),x=require("../Rect/index.cjs"),s=require("../Line/index.cjs"),o=require("../IText/index.cjs");const v=({objects:r})=>{const a={rect:x.default,path:l.default,text:u.default,line:s.default,"i-text":u.default,itext:o.default};return r?e.jsx(e.Fragment,{children:r?.map(({type:i,...n})=>{const t=a[i.toLowerCase()];return t?e.jsx(t,{...n}):null})}):null};var c=d.memo(v);exports.default=c;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/Objects/index.tsx"],"sourcesContent":["import { memo } from 'react'\nimport Path from '../Path'\nimport Text from '../Text'\nimport Rect from '../Rect'\nimport Line from '../Line'\n\nexport type ObjectsProps = {\n objects: { type: string; [index: string]: any }[]\n}\n\nconst Objects = ({ objects }: ObjectsProps) => {\n const components = {\n rect: Rect,\n path: Path,\n text: Text,\n line: Line,\n 'i-text': Text,\n }\n\n if (!objects) return null\n return (\n <>\n {objects?.map(({ type, ...options }) => {\n // @ts-expect-error\n const Component = components[type.toLowerCase()]\n if (!Component) {\n \n return null\n }\n return <Component {...options} />\n })}\n </>\n )\n}\n\nexport default memo(Objects)\n"],"names":["Objects","objects","components","Rect","Path","Text","Line","jsx","Fragment","type","options","Component","memo"],"mappings":"sPAUA,MAAMA,EAAU,CAAC,CAAE,QAAAC,CAAQ,IAAoB,CAC7C,MAAMC,EAAa,CACjB,KAAMC,UACN,KAAMC,EAAAA,QACN,KAAMC,EAAAA,QACN,KAAMC,EAAAA,QACN,SAAUD,SACZ,EAEA,OAAKJ,EAEHM,MAAAC,EAAAA,SAAA,CACG,SAAAP,GAAS,IAAI,CAAC,CAAE,KAAAQ,EAAM,GAAGC,CAAQ,IAAM,CAEtC,MAAMC,EAAYT,EAAWO,EAAK,YAAA,CAAa,EAC/C,OAAKE,EAIEJ,EAACI,IAAAA,EAAA,CAAW,GAAGD,CAAAA,CAAS,EAFtB,IAGX,CAAC,CACH,CAAA,EAZmB,IAcvB,EAEA,IAAeE,EAAAA,EAAAA,KAAKZ,CAAO"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/Objects/index.tsx"],"sourcesContent":["import { memo } from 'react'\nimport Path from '../Path'\nimport Text from '../Text'\nimport Rect from '../Rect'\nimport Line from '../Line'\nimport IText from '../IText'\n\nexport type ObjectsProps = {\n objects: { type: string;[index: string]: any }[]\n}\n\nconst Objects = ({ objects }: ObjectsProps) => {\n const components = {\n rect: Rect,\n path: Path,\n text: Text,\n line: Line,\n 'i-text': Text,\n itext: IText,\n }\n\n if (!objects) return null\n return (\n <>\n {objects?.map(({ type, ...options }) => {\n const Component = components[type.toLowerCase() as keyof typeof components]\n if (!Component) {\n return null\n }\n return <Component {...options} />\n })}\n </>\n )\n}\n\nexport default memo(Objects)\n"],"names":["Objects","objects","components","Rect","Path","Text","Line","IText","jsx","Fragment","type","options","Component","memo"],"mappings":"sRAWA,MAAMA,EAAU,CAAC,CAAE,QAAAC,CAAQ,IAAoB,CAC7C,MAAMC,EAAa,CACjB,KAAMC,EAAAA,QACN,KAAMC,UACN,KAAMC,UACN,KAAMC,EACN,QAAA,SAAUD,EAAAA,QACV,MAAOE,EAAAA,OACT,EAEA,OAAKN,EAEHO,EAAAA,IAAAC,EAAAA,SAAA,CACG,SAAAR,GAAS,IAAI,CAAC,CAAE,KAAAS,EAAM,GAAGC,CAAQ,IAAM,CACtC,MAAMC,EAAYV,EAAWQ,EAAK,YAAwC,CAAA,EAC1E,OAAKE,EAGEJ,EAAAA,IAACI,EAAA,CAAW,GAAGD,EAAS,EAFtB,IAGX,CAAC,CACH,CAAA,EAVmB,IAYvB,EAEA,IAAeE,EAAAA,EAAAA,KAAKb,CAAO"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var p=require("fabric"),e=require("react"),l=require("../../hooks/useCreateObject.cjs"),c=require("../../hooks/useSplitProps.cjs");const n=e.forwardRef(({group:t,path:u="M 0 0",...a},s)=>{const[i,o]=c.useSplitProps(a),r=l.useCreateObject({Constructor:p.Path,param:u,attributes:o,group:t,listeners:i});return e.useImperativeHandle(s,()=>r,[r]),null});var v=e.memo(n);exports.default=v;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var c=require("fabric"),r=require("react"),p=require("../../hooks/useCreateObject.cjs"),l=require("../../hooks/useSplitProps.cjs"),v=require("../../hooks/useInstancePosition.cjs");const d=r.forwardRef(({group:t,path:s="M 0 0",children:u,...a},i)=>{const[o,n]=l.useSplitProps(a),e=p.useCreateObject({Constructor:c.Path,param:s,attributes:n,group:t,listeners:o});return r.useImperativeHandle(i,()=>e,[e]),v.useInstancePosition(e,u)});var P=r.memo(d);exports.default=P;
2
2
  //# sourceMappingURL=index.cjs.map