@cratis/components 4.21.0 → 4.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/MIGRATION.md +3 -3
  2. package/compat-manifest.json +16 -16
  3. package/dist/esm/Canvas/Canvas.d.ts +12 -81
  4. package/dist/esm/Canvas/Canvas.d.ts.map +1 -1
  5. package/dist/esm/Canvas/Canvas.js +83 -676
  6. package/dist/esm/Canvas/Canvas.js.map +1 -1
  7. package/dist/esm/Canvas/CanvasCaptureAttributes.d.ts +10 -0
  8. package/dist/esm/Canvas/CanvasCaptureAttributes.d.ts.map +1 -0
  9. package/dist/esm/Canvas/CanvasCaptureAttributes.js +4 -0
  10. package/dist/esm/Canvas/CanvasCaptureAttributes.js.map +1 -0
  11. package/dist/esm/Canvas/CanvasContext.d.ts +9 -0
  12. package/dist/esm/Canvas/CanvasContext.d.ts.map +1 -0
  13. package/dist/esm/Canvas/CanvasContext.js +4 -0
  14. package/dist/esm/Canvas/CanvasContext.js.map +1 -0
  15. package/dist/esm/Canvas/CanvasHandle.d.ts +13 -0
  16. package/dist/esm/Canvas/CanvasHandle.d.ts.map +1 -0
  17. package/dist/esm/Canvas/CanvasHandle.js +4 -0
  18. package/dist/esm/Canvas/CanvasHandle.js.map +1 -0
  19. package/dist/esm/Canvas/CanvasItem.js +4 -1
  20. package/dist/esm/Canvas/CanvasItem.js.map +1 -1
  21. package/dist/esm/Canvas/CanvasItemData.d.ts +10 -0
  22. package/dist/esm/Canvas/CanvasItemData.d.ts.map +1 -0
  23. package/dist/esm/Canvas/CanvasItemData.js +4 -0
  24. package/dist/esm/Canvas/CanvasItemData.js.map +1 -0
  25. package/dist/esm/Canvas/CanvasItemRegistryContext.d.ts +5 -0
  26. package/dist/esm/Canvas/CanvasItemRegistryContext.d.ts.map +1 -0
  27. package/dist/esm/Canvas/CanvasItemRegistryContext.js +6 -0
  28. package/dist/esm/Canvas/CanvasItemRegistryContext.js.map +1 -0
  29. package/dist/esm/Canvas/CanvasItemRegistryContextValue.d.ts +26 -0
  30. package/dist/esm/Canvas/CanvasItemRegistryContextValue.d.ts.map +1 -0
  31. package/dist/esm/Canvas/CanvasItemRegistryContextValue.js +4 -0
  32. package/dist/esm/Canvas/CanvasItemRegistryContextValue.js.map +1 -0
  33. package/dist/esm/Canvas/CanvasItemRegistryEntry.d.ts +19 -0
  34. package/dist/esm/Canvas/CanvasItemRegistryEntry.d.ts.map +1 -0
  35. package/dist/esm/Canvas/CanvasItemRegistryEntry.js +4 -0
  36. package/dist/esm/Canvas/CanvasItemRegistryEntry.js.map +1 -0
  37. package/dist/esm/Canvas/WebKitGestureEvent.d.ts +13 -0
  38. package/dist/esm/Canvas/WebKitGestureEvent.d.ts.map +1 -0
  39. package/dist/esm/Canvas/WebKitGestureEvent.js +4 -0
  40. package/dist/esm/Canvas/WebKitGestureEvent.js.map +1 -0
  41. package/dist/esm/Canvas/canvasEasing.d.ts +8 -0
  42. package/dist/esm/Canvas/canvasEasing.d.ts.map +1 -0
  43. package/dist/esm/Canvas/canvasEasing.js +8 -0
  44. package/dist/esm/Canvas/canvasEasing.js.map +1 -0
  45. package/dist/esm/Canvas/canvasGestureTuning.d.ts +6 -0
  46. package/dist/esm/Canvas/canvasGestureTuning.d.ts.map +1 -0
  47. package/dist/esm/Canvas/canvasGestureTuning.js +7 -0
  48. package/dist/esm/Canvas/canvasGestureTuning.js.map +1 -0
  49. package/dist/esm/Canvas/index.js +2 -1
  50. package/dist/esm/Canvas/index.js.map +1 -1
  51. package/dist/esm/Canvas/shapes/Region/Region.js +4 -1
  52. package/dist/esm/Canvas/shapes/Region/Region.js.map +1 -1
  53. package/dist/esm/Canvas/useCanvasCamera.d.ts +37 -0
  54. package/dist/esm/Canvas/useCanvasCamera.d.ts.map +1 -0
  55. package/dist/esm/Canvas/useCanvasCamera.js +79 -0
  56. package/dist/esm/Canvas/useCanvasCamera.js.map +1 -0
  57. package/dist/esm/Canvas/useCanvasItemRegistry.d.ts +14 -0
  58. package/dist/esm/Canvas/useCanvasItemRegistry.d.ts.map +1 -0
  59. package/dist/esm/Canvas/useCanvasItemRegistry.js +59 -0
  60. package/dist/esm/Canvas/useCanvasItemRegistry.js.map +1 -0
  61. package/dist/esm/Canvas/useCanvasNavigation.d.ts +36 -0
  62. package/dist/esm/Canvas/useCanvasNavigation.d.ts.map +1 -0
  63. package/dist/esm/Canvas/useCanvasNavigation.js +186 -0
  64. package/dist/esm/Canvas/useCanvasNavigation.js.map +1 -0
  65. package/dist/esm/Canvas/useCanvasPointerGestures.d.ts +34 -0
  66. package/dist/esm/Canvas/useCanvasPointerGestures.d.ts.map +1 -0
  67. package/dist/esm/Canvas/useCanvasPointerGestures.js +178 -0
  68. package/dist/esm/Canvas/useCanvasPointerGestures.js.map +1 -0
  69. package/dist/esm/Canvas/useCanvasWheelZoom.d.ts +23 -0
  70. package/dist/esm/Canvas/useCanvasWheelZoom.d.ts.map +1 -0
  71. package/dist/esm/Canvas/useCanvasWheelZoom.js +146 -0
  72. package/dist/esm/Canvas/useCanvasWheelZoom.js.map +1 -0
  73. package/dist/esm/Canvas/useLatestRef.d.ts +8 -0
  74. package/dist/esm/Canvas/useLatestRef.d.ts.map +1 -0
  75. package/dist/esm/Canvas/useLatestRef.js +12 -0
  76. package/dist/esm/Canvas/useLatestRef.js.map +1 -0
  77. package/dist/esm/Canvas/usePixiApplication.d.ts +32 -0
  78. package/dist/esm/Canvas/usePixiApplication.d.ts.map +1 -0
  79. package/dist/esm/Canvas/usePixiApplication.js +92 -0
  80. package/dist/esm/Canvas/usePixiApplication.js.map +1 -0
  81. package/dist/esm/Canvas/usePixiItems.d.ts +19 -0
  82. package/dist/esm/Canvas/usePixiItems.d.ts.map +1 -0
  83. package/dist/esm/Canvas/usePixiItems.js +49 -0
  84. package/dist/esm/Canvas/usePixiItems.js.map +1 -0
  85. package/dist/esm/Chat/ChatSidebar.d.ts.map +1 -1
  86. package/dist/esm/Chat/ChatSidebar.js +1 -1
  87. package/dist/esm/Chat/ChatSidebar.js.map +1 -1
  88. package/dist/esm/ClassNames/classNames.d.ts +7 -0
  89. package/dist/esm/ClassNames/classNames.d.ts.map +1 -0
  90. package/dist/esm/ClassNames/classNames.js +4 -0
  91. package/dist/esm/ClassNames/classNames.js.map +1 -0
  92. package/dist/esm/Common/Breadcrumbs.d.ts.map +1 -1
  93. package/dist/esm/Common/Breadcrumbs.js +1 -1
  94. package/dist/esm/Common/Breadcrumbs.js.map +1 -1
  95. package/dist/esm/Common/ComboBox.d.ts.map +1 -1
  96. package/dist/esm/Common/ComboBox.js +1 -1
  97. package/dist/esm/Common/ComboBox.js.map +1 -1
  98. package/dist/esm/Common/DatePickerInputImplementation.d.ts.map +1 -1
  99. package/dist/esm/Common/DatePickerInputImplementation.js +1 -1
  100. package/dist/esm/Common/DatePickerInputImplementation.js.map +1 -1
  101. package/dist/esm/Common/NumberInput.d.ts.map +1 -1
  102. package/dist/esm/Common/NumberInput.js +1 -1
  103. package/dist/esm/Common/NumberInput.js.map +1 -1
  104. package/dist/esm/Common/Tabs.d.ts.map +1 -1
  105. package/dist/esm/Common/Tabs.js +1 -1
  106. package/dist/esm/Common/Tabs.js.map +1 -1
  107. package/dist/esm/Common/TagGroup.d.ts.map +1 -1
  108. package/dist/esm/Common/TagGroup.js +1 -1
  109. package/dist/esm/Common/TagGroup.js.map +1 -1
  110. package/dist/esm/Common/ToggleGroup.d.ts.map +1 -1
  111. package/dist/esm/Common/ToggleGroup.js +1 -1
  112. package/dist/esm/Common/ToggleGroup.js.map +1 -1
  113. package/dist/esm/DataTables/ColumnFilterMenu.d.ts.map +1 -1
  114. package/dist/esm/DataTables/ColumnFilterMenu.js +1 -1
  115. package/dist/esm/DataTables/ColumnFilterMenu.js.map +1 -1
  116. package/dist/esm/DataTables/DataTableBody.d.ts +22 -0
  117. package/dist/esm/DataTables/DataTableBody.d.ts.map +1 -0
  118. package/dist/esm/DataTables/DataTableBody.js +10 -0
  119. package/dist/esm/DataTables/DataTableBody.js.map +1 -0
  120. package/dist/esm/DataTables/DataTableCore.d.ts +8 -48
  121. package/dist/esm/DataTables/DataTableCore.d.ts.map +1 -1
  122. package/dist/esm/DataTables/DataTableCore.js +50 -278
  123. package/dist/esm/DataTables/DataTableCore.js.map +1 -1
  124. package/dist/esm/DataTables/DataTableHeaderCell.d.ts +25 -0
  125. package/dist/esm/DataTables/DataTableHeaderCell.d.ts.map +1 -0
  126. package/dist/esm/DataTables/DataTableHeaderCell.js +26 -0
  127. package/dist/esm/DataTables/DataTableHeaderCell.js.map +1 -0
  128. package/dist/esm/DataTables/DataTableMessageOverrides.d.ts +12 -0
  129. package/dist/esm/DataTables/DataTableMessageOverrides.d.ts.map +1 -0
  130. package/dist/esm/DataTables/DataTableMessageOverrides.js +4 -0
  131. package/dist/esm/DataTables/DataTableMessageOverrides.js.map +1 -0
  132. package/dist/esm/DataTables/DataTableMessages.d.ts +12 -0
  133. package/dist/esm/DataTables/DataTableMessages.d.ts.map +1 -0
  134. package/dist/esm/DataTables/DataTableMessages.js +4 -0
  135. package/dist/esm/DataTables/DataTableMessages.js.map +1 -0
  136. package/dist/esm/DataTables/DataTableParts.d.ts +40 -0
  137. package/dist/esm/DataTables/DataTableParts.d.ts.map +1 -0
  138. package/dist/esm/DataTables/DataTableParts.js +4 -0
  139. package/dist/esm/DataTables/DataTableParts.js.map +1 -0
  140. package/dist/esm/DataTables/DataTableRow.d.ts +22 -0
  141. package/dist/esm/DataTables/DataTableRow.d.ts.map +1 -0
  142. package/dist/esm/DataTables/DataTableRow.js +25 -0
  143. package/dist/esm/DataTables/DataTableRow.js.map +1 -0
  144. package/dist/esm/DataTables/DataTableRowClickEvent.d.ts +8 -0
  145. package/dist/esm/DataTables/DataTableRowClickEvent.d.ts.map +1 -0
  146. package/dist/esm/DataTables/DataTableRowClickEvent.js +4 -0
  147. package/dist/esm/DataTables/DataTableRowClickEvent.js.map +1 -0
  148. package/dist/esm/DataTables/DataTableSearch.d.ts +13 -0
  149. package/dist/esm/DataTables/DataTableSearch.d.ts.map +1 -0
  150. package/dist/esm/DataTables/DataTableSearch.js +7 -0
  151. package/dist/esm/DataTables/DataTableSearch.js.map +1 -0
  152. package/dist/esm/DataTables/DataTableState.d.ts +18 -0
  153. package/dist/esm/DataTables/DataTableState.d.ts.map +1 -0
  154. package/dist/esm/DataTables/DataTableState.js +4 -0
  155. package/dist/esm/DataTables/DataTableState.js.map +1 -0
  156. package/dist/esm/DataTables/DataTableStateProps.d.ts +20 -0
  157. package/dist/esm/DataTables/DataTableStateProps.d.ts.map +1 -0
  158. package/dist/esm/DataTables/DataTableStateProps.js +4 -0
  159. package/dist/esm/DataTables/DataTableStateProps.js.map +1 -0
  160. package/dist/esm/DataTables/ProcessedRow.d.ts +8 -0
  161. package/dist/esm/DataTables/ProcessedRow.d.ts.map +1 -0
  162. package/dist/esm/DataTables/ProcessedRow.js +4 -0
  163. package/dist/esm/DataTables/ProcessedRow.js.map +1 -0
  164. package/dist/esm/DataTables/RowProcessingState.d.ts +17 -0
  165. package/dist/esm/DataTables/RowProcessingState.d.ts.map +1 -0
  166. package/dist/esm/DataTables/RowProcessingState.js +4 -0
  167. package/dist/esm/DataTables/RowProcessingState.js.map +1 -0
  168. package/dist/esm/DataTables/RowSelection.d.ts +19 -0
  169. package/dist/esm/DataTables/RowSelection.d.ts.map +1 -0
  170. package/dist/esm/DataTables/RowSelection.js +4 -0
  171. package/dist/esm/DataTables/RowSelection.js.map +1 -0
  172. package/dist/esm/DataTables/RowSelectionSource.d.ts +16 -0
  173. package/dist/esm/DataTables/RowSelectionSource.d.ts.map +1 -0
  174. package/dist/esm/DataTables/RowSelectionSource.js +4 -0
  175. package/dist/esm/DataTables/RowSelectionSource.js.map +1 -0
  176. package/dist/esm/DataTables/matchesFilterEntry.d.ts +15 -0
  177. package/dist/esm/DataTables/matchesFilterEntry.d.ts.map +1 -0
  178. package/dist/esm/DataTables/matchesFilterEntry.js +70 -0
  179. package/dist/esm/DataTables/matchesFilterEntry.js.map +1 -0
  180. package/dist/esm/DataTables/processRows.d.ts +10 -0
  181. package/dist/esm/DataTables/processRows.d.ts.map +1 -0
  182. package/dist/esm/DataTables/processRows.js +42 -0
  183. package/dist/esm/DataTables/processRows.js.map +1 -0
  184. package/dist/esm/DataTables/useDataTableMessages.d.ts +9 -0
  185. package/dist/esm/DataTables/useDataTableMessages.d.ts.map +1 -0
  186. package/dist/esm/DataTables/useDataTableMessages.js +33 -0
  187. package/dist/esm/DataTables/useDataTableMessages.js.map +1 -0
  188. package/dist/esm/DataTables/useDataTableState.d.ts +10 -0
  189. package/dist/esm/DataTables/useDataTableState.d.ts.map +1 -0
  190. package/dist/esm/DataTables/useDataTableState.js +19 -0
  191. package/dist/esm/DataTables/useDataTableState.js.map +1 -0
  192. package/dist/esm/DataTables/useRowSelection.d.ts +9 -0
  193. package/dist/esm/DataTables/useRowSelection.d.ts.map +1 -0
  194. package/dist/esm/DataTables/useRowSelection.js +87 -0
  195. package/dist/esm/DataTables/useRowSelection.js.map +1 -0
  196. package/dist/esm/DataTables/valueAtPath.d.ts +10 -0
  197. package/dist/esm/DataTables/valueAtPath.d.ts.map +1 -0
  198. package/dist/esm/DataTables/valueAtPath.js +18 -0
  199. package/dist/esm/DataTables/valueAtPath.js.map +1 -0
  200. package/dist/esm/Dialogs/DialogImplementation.d.ts.map +1 -1
  201. package/dist/esm/Dialogs/DialogImplementation.js +1 -1
  202. package/dist/esm/Dialogs/DialogImplementation.js.map +1 -1
  203. package/dist/esm/Display/Message.d.ts +8 -1
  204. package/dist/esm/Display/Message.d.ts.map +1 -1
  205. package/dist/esm/Display/Message.js +1 -1
  206. package/dist/esm/Display/Message.js.map +1 -1
  207. package/dist/esm/Dropdown/DropdownImplementation.d.ts.map +1 -1
  208. package/dist/esm/Dropdown/DropdownImplementation.js +1 -1
  209. package/dist/esm/Dropdown/DropdownImplementation.js.map +1 -1
  210. package/dist/esm/Notifications/Toaster.d.ts.map +1 -1
  211. package/dist/esm/Notifications/Toaster.js +1 -1
  212. package/dist/esm/Notifications/Toaster.js.map +1 -1
  213. package/dist/esm/PivotViewer/components/PivotCanvas.d.ts +7 -50
  214. package/dist/esm/PivotViewer/components/PivotCanvas.d.ts.map +1 -1
  215. package/dist/esm/PivotViewer/components/PivotCanvas.js +34 -433
  216. package/dist/esm/PivotViewer/components/PivotCanvas.js.map +1 -1
  217. package/dist/esm/PivotViewer/components/PivotCanvasProps.d.ts +51 -0
  218. package/dist/esm/PivotViewer/components/PivotCanvasProps.d.ts.map +1 -0
  219. package/dist/esm/PivotViewer/components/PivotCanvasProps.js +4 -0
  220. package/dist/esm/PivotViewer/components/PivotCanvasProps.js.map +1 -0
  221. package/dist/esm/PivotViewer/components/pivot/PivotRenderContext.d.ts +16 -0
  222. package/dist/esm/PivotViewer/components/pivot/PivotRenderContext.d.ts.map +1 -0
  223. package/dist/esm/PivotViewer/components/pivot/PivotRenderContext.js +4 -0
  224. package/dist/esm/PivotViewer/components/pivot/PivotRenderContext.js.map +1 -0
  225. package/dist/esm/PivotViewer/components/pivot/PivotStage.d.ts +19 -0
  226. package/dist/esm/PivotViewer/components/pivot/PivotStage.d.ts.map +1 -0
  227. package/dist/esm/PivotViewer/components/pivot/PivotStage.js +4 -0
  228. package/dist/esm/PivotViewer/components/pivot/PivotStage.js.map +1 -0
  229. package/dist/esm/PivotViewer/components/pivot/PivotTransitionState.d.ts +21 -0
  230. package/dist/esm/PivotViewer/components/pivot/PivotTransitionState.d.ts.map +1 -0
  231. package/dist/esm/PivotViewer/components/pivot/PivotTransitionState.js +4 -0
  232. package/dist/esm/PivotViewer/components/pivot/PivotTransitionState.js.map +1 -0
  233. package/dist/esm/PivotViewer/components/pivot/asReactMouseEvent.d.ts +8 -0
  234. package/dist/esm/PivotViewer/components/pivot/asReactMouseEvent.d.ts.map +1 -0
  235. package/dist/esm/PivotViewer/components/pivot/asReactMouseEvent.js +6 -0
  236. package/dist/esm/PivotViewer/components/pivot/asReactMouseEvent.js.map +1 -0
  237. package/dist/esm/PivotViewer/components/pivot/sprites.js +1 -1
  238. package/dist/esm/PivotViewer/components/pivot/usePivotCardColors.d.ts +22 -0
  239. package/dist/esm/PivotViewer/components/pivot/usePivotCardColors.d.ts.map +1 -0
  240. package/dist/esm/PivotViewer/components/pivot/usePivotCardColors.js +25 -0
  241. package/dist/esm/PivotViewer/components/pivot/usePivotCardColors.js.map +1 -0
  242. package/dist/esm/PivotViewer/components/pivot/usePivotGroupBackgrounds.d.ts +8 -0
  243. package/dist/esm/PivotViewer/components/pivot/usePivotGroupBackgrounds.d.ts.map +1 -0
  244. package/dist/esm/PivotViewer/components/pivot/usePivotGroupBackgrounds.js +53 -0
  245. package/dist/esm/PivotViewer/components/pivot/usePivotGroupBackgrounds.js.map +1 -0
  246. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.d.ts +8 -0
  247. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.d.ts.map +1 -0
  248. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js +100 -0
  249. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js.map +1 -0
  250. package/dist/esm/PivotViewer/components/pivot/usePivotSelectionHighlight.d.ts +7 -0
  251. package/dist/esm/PivotViewer/components/pivot/usePivotSelectionHighlight.d.ts.map +1 -0
  252. package/dist/esm/PivotViewer/components/pivot/usePivotSelectionHighlight.js +35 -0
  253. package/dist/esm/PivotViewer/components/pivot/usePivotSelectionHighlight.js.map +1 -0
  254. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.d.ts +8 -0
  255. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.d.ts.map +1 -0
  256. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js +123 -0
  257. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js.map +1 -0
  258. package/dist/esm/PivotViewer/components/pivot/usePivotStage.d.ts +21 -0
  259. package/dist/esm/PivotViewer/components/pivot/usePivotStage.d.ts.map +1 -0
  260. package/dist/esm/PivotViewer/components/pivot/usePivotStage.js +171 -0
  261. package/dist/esm/PivotViewer/components/pivot/usePivotStage.js.map +1 -0
  262. package/dist/esm/PivotViewer/components/pivot/usePivotTransitionState.d.ts +13 -0
  263. package/dist/esm/PivotViewer/components/pivot/usePivotTransitionState.d.ts.map +1 -0
  264. package/dist/esm/PivotViewer/components/pivot/usePivotTransitionState.js +31 -0
  265. package/dist/esm/PivotViewer/components/pivot/usePivotTransitionState.js.map +1 -0
  266. package/dist/esm/TimeMachine/EventsView.d.ts.map +1 -1
  267. package/dist/esm/TimeMachine/EventsView.js +1 -1
  268. package/dist/esm/TimeMachine/EventsView.js.map +1 -1
  269. package/package.json +1 -1
@@ -1,696 +1,103 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React, { useRef, useState, useCallback, useEffect, useMemo } from 'react';
3
- import * as PIXI from 'pixi.js';
2
+ import { useRef } from 'react';
4
3
  import { CanvasControls } from './CanvasControls.js';
5
- import { canvasGesture } from './canvasGesture.js';
6
- import { canvasTransformActivity } from './canvasTransformActivity.js';
7
- import { isBackgroundPointerTarget } from './isBackgroundPointerTarget.js';
8
- import { isWithinScrollableContent } from './isWithinScrollableContent.js';
9
- import { velocityFromSamples, trimSamples, decayVelocity } from './panMomentum.js';
10
- import { pinchSnapshotOf, pinchChangeBetween } from './pinchGesture.js';
4
+ import { CanvasItemRegistryContext } from './CanvasItemRegistryContext.js';
5
+ import { useCanvasCamera } from './useCanvasCamera.js';
6
+ import { useCanvasItemRegistry } from './useCanvasItemRegistry.js';
7
+ import { useCanvasNavigation } from './useCanvasNavigation.js';
8
+ import { useCanvasPointerGestures } from './useCanvasPointerGestures.js';
9
+ import { useCanvasWheelZoom } from './useCanvasWheelZoom.js';
11
10
  import { useDragSelectionGuard } from './useDragSelectionGuard.js';
12
- import { applyZoomLayer, shouldUseCssZoom, isMultiTouchCapableDevice } from './zoomMechanism.js';
11
+ import { useLatestRef } from './useLatestRef.js';
12
+ import { usePixiApplication } from './usePixiApplication.js';
13
+ import { usePixiItems } from './usePixiItems.js';
14
+ import { shouldUseCssZoom, isMultiTouchCapableDevice } from './zoomMechanism.js';
13
15
 
14
- function easeInOutCubic(progress) {
15
- return progress < 0.5
16
- ? 4 * progress * progress * progress
17
- : 1 - (-2 * progress + 2) ** 3 / 2;
18
- }
19
- const CanvasItemRegistryContext = React.createContext(null);
20
- const ZOOM_INTENSITY = 0.008;
21
- const GESTURE_SETTLE_MS = 150;
22
- const MOMENTUM_SAMPLE_WINDOW_MS = 100;
23
- const MOMENTUM_MIN_VELOCITY = 0.02;
24
16
  function Canvas({ children, items = [], renderItem, onItemPointerDown, onReady, onTransformChange, onHandleReady, initialZoom = 1, initialPan = { x: 0, y: 0 }, minZoom = 0.1, maxZoom = 5, showControls = true, showMinimap = false, minimapWorldWidth, minimapWorldHeight, minimapItems, controlsPlacement = 'bottom-left', className, style, onHelp, helpTitle, controlsLabels, controlsIcons, controlsFollowViewportInsets = true, controlsGlassSurface, disableControlsGlass = false, captureAttributes, readOnly = false, backgroundDragPans = true, }) {
25
17
  const containerRef = useRef(null);
26
18
  useDragSelectionGuard(containerRef);
27
- const appRef = useRef(null);
28
- const worldRef = useRef(null);
29
19
  const minimapRef = useRef(null);
30
20
  const overlayRef = useRef(null);
31
21
  const zoomLayerRef = useRef(null);
32
- const spritesRef = useRef(new Map());
33
22
  const animationFrameRef = useRef(null);
34
- const [pixiReady, setPixiReady] = useState(false);
35
23
  const panRef = useRef({ x: initialPan.x, y: initialPan.y });
36
24
  const zoomRef = useRef(initialZoom);
37
25
  const initialTransformRef = useRef({ pan: initialPan, zoom: initialZoom });
38
- const gestureActiveRef = useRef(false);
39
- const gestureSettleTimerRef = useRef(undefined);
40
- const transformFramePendingRef = useRef(false);
41
- const isPanningRef = useRef(false);
42
- const lastPointerRef = useRef({ x: 0, y: 0 });
43
- const setPanCursor = useCallback((panning) => {
44
- if (containerRef.current)
45
- containerRef.current.style.cursor = panning ? 'grabbing' : 'default';
46
- }, []);
47
26
  const touchPointersRef = useRef(new Map());
48
- const pinchRef = useRef(null);
49
- const touchPanSamplesRef = useRef([]);
50
- const onReadyRef = useRef(onReady);
51
- const onItemPointerDownRef = useRef(onItemPointerDown);
52
- const onTransformChangeRef = useRef(onTransformChange);
53
- const onHandleReadyRef = useRef(onHandleReady);
54
- const itemsRef = useRef(items);
55
- useEffect(() => {
56
- onReadyRef.current = onReady;
57
- }, [onReady]);
58
- useEffect(() => {
59
- onItemPointerDownRef.current = onItemPointerDown;
60
- }, [onItemPointerDown]);
61
- useEffect(() => {
62
- onTransformChangeRef.current = onTransformChange;
63
- }, [onTransformChange]);
64
- useEffect(() => {
65
- onHandleReadyRef.current = onHandleReady;
66
- }, [onHandleReady]);
67
- useEffect(() => {
68
- itemsRef.current = items;
69
- }, [items]);
70
- const itemRegistryRef = useRef(new Map());
71
- const [itemRegistryVersion, setItemRegistryVersion] = useState(0);
72
- const registrySnapshotRef = useRef(new Map());
73
- const registryListenersRef = useRef(new Set());
74
- const notifyRegistryChanged = useCallback(() => {
75
- registrySnapshotRef.current = new Map(itemRegistryRef.current);
76
- setItemRegistryVersion((version) => version + 1);
77
- registryListenersRef.current.forEach((listener) => listener());
78
- }, []);
79
- const registerItem = useCallback((id, entry) => {
80
- const existing = itemRegistryRef.current.get(id);
81
- if (existing &&
82
- existing.x === entry.x &&
83
- existing.y === entry.y &&
84
- existing.width === entry.width &&
85
- existing.height === entry.height &&
86
- existing.anonymous === entry.anonymous)
87
- return;
88
- itemRegistryRef.current.set(id, entry);
89
- notifyRegistryChanged();
90
- }, [notifyRegistryChanged]);
91
- const unregisterItem = useCallback((id) => {
92
- if (!itemRegistryRef.current.delete(id))
93
- return;
94
- notifyRegistryChanged();
95
- }, [notifyRegistryChanged]);
96
- const getRegistrySnapshot = useCallback(() => registrySnapshotRef.current, []);
97
- const subscribeToRegistry = useCallback((listener) => {
98
- registryListenersRef.current.add(listener);
99
- return () => {
100
- registryListenersRef.current.delete(listener);
101
- };
102
- }, []);
103
- const registryContextValue = useMemo(() => ({
104
- register: registerItem,
105
- unregister: unregisterItem,
106
- getSnapshot: getRegistrySnapshot,
107
- subscribe: subscribeToRegistry,
108
- }), [registerItem, unregisterItem, getRegistrySnapshot, subscribeToRegistry]);
109
- const autoMinimapItems = useMemo(() => {
110
- const result = [];
111
- itemRegistryRef.current.forEach((entry) => {
112
- result.push({
113
- x: entry.x,
114
- y: entry.y,
115
- width: entry.width,
116
- height: entry.height,
117
- });
118
- });
119
- return result;
120
- }, [itemRegistryVersion]);
27
+ const onReadyRef = useLatestRef(onReady);
28
+ const onItemPointerDownRef = useLatestRef(onItemPointerDown);
29
+ const onTransformChangeRef = useLatestRef(onTransformChange);
30
+ const onHandleReadyRef = useLatestRef(onHandleReady);
31
+ const { itemRegistryRef, registryContextValue, autoMinimapItems } = useCanvasItemRegistry();
121
32
  const effectiveMinimapItems = minimapItems ?? autoMinimapItems;
122
- const refreshMinimap = useCallback(() => {
123
- const app = appRef.current;
124
- if (!app || !minimapRef.current)
125
- return;
126
- minimapRef.current.update(panRef.current, zoomRef.current, app.renderer.width, app.renderer.height);
127
- }, []);
128
- const applyWorldTransform = useCallback(() => {
129
- const world = worldRef.current;
130
- if (!world)
131
- return;
132
- world.position.set(panRef.current.x, panRef.current.y);
133
- world.scale.set(zoomRef.current);
134
- if (overlayRef.current) {
135
- overlayRef.current.style.transform = `translate(${panRef.current.x}px, ${panRef.current.y}px)`;
136
- }
137
- if (zoomLayerRef.current) {
138
- applyZoomLayer(zoomLayerRef.current, zoomRef.current, gestureActiveRef.current);
139
- }
140
- onTransformChangeRef.current?.(zoomRef.current, panRef.current);
141
- canvasTransformActivity.notify();
142
- }, []);
143
- const render = useCallback(() => {
144
- const app = appRef.current;
145
- if (!app)
146
- return;
147
- if ((worldRef.current?.children.length ?? 0) === 0)
148
- return;
149
- PIXI.Ticker.system.update();
150
- app.renderer.render(app.stage);
151
- }, []);
152
- useEffect(() => {
153
- const container = containerRef.current;
154
- if (!container || appRef.current)
155
- return;
156
- let mounted = true;
157
- (async () => {
158
- const rect = container.getBoundingClientRect();
159
- const width = rect.width > 0 ? rect.width : container.clientWidth || 800;
160
- const height = rect.height > 0 ? rect.height : container.clientHeight || 600;
161
- const app = new PIXI.Application();
162
- await app.init({
163
- backgroundAlpha: 0,
164
- antialias: true,
165
- autoDensity: true,
166
- resolution: window.devicePixelRatio || 1,
167
- width,
168
- height,
169
- autoStart: false,
170
- });
171
- if (!mounted || !containerRef.current) {
172
- app.destroy(true, { children: true });
173
- return;
174
- }
175
- appRef.current = app;
176
- const world = new PIXI.Container();
177
- world.position.set(panRef.current.x, panRef.current.y);
178
- world.scale.set(zoomRef.current);
179
- app.stage.addChild(world);
180
- worldRef.current = world;
181
- const canvas = app.canvas;
182
- canvas.style.display = 'block';
183
- canvas.style.touchAction = 'none';
184
- containerRef.current.appendChild(canvas);
185
- setPixiReady(true);
186
- app.renderer.render(app.stage);
187
- PIXI.Ticker.system.stop();
188
- onReadyRef.current?.({ app, world });
189
- })();
190
- return () => {
191
- mounted = false;
192
- if (appRef.current) {
193
- appRef.current.destroy(true, { children: true });
194
- appRef.current = null;
195
- worldRef.current = null;
196
- }
197
- spritesRef.current.clear();
198
- };
199
- }, []);
200
- useEffect(() => {
201
- const canvas = appRef.current?.canvas;
202
- const attribute = captureAttributes?.layer;
203
- if (!canvas || !attribute)
204
- return;
205
- canvas.setAttribute(attribute, 'true');
206
- return () => canvas.removeAttribute(attribute);
207
- }, [pixiReady, captureAttributes?.layer]);
208
- useEffect(() => {
209
- const container = containerRef.current;
210
- if (!container)
211
- return;
212
- const observer = new ResizeObserver(() => {
213
- const app = appRef.current;
214
- if (!app)
215
- return;
216
- app.renderer.resize(container.clientWidth, container.clientHeight);
217
- render();
218
- });
219
- observer.observe(container);
220
- return () => observer.disconnect();
221
- }, [render]);
222
- const scheduleTransformApply = useCallback(() => {
223
- if (transformFramePendingRef.current)
224
- return;
225
- transformFramePendingRef.current = true;
226
- requestAnimationFrame(() => {
227
- transformFramePendingRef.current = false;
228
- applyWorldTransform();
229
- refreshMinimap();
230
- render();
231
- });
232
- }, [applyWorldTransform, refreshMinimap, render]);
233
- const noteGestureActivity = useCallback(() => {
234
- gestureActiveRef.current = true;
235
- canvasGesture.set(true);
236
- clearTimeout(gestureSettleTimerRef.current);
237
- gestureSettleTimerRef.current = setTimeout(() => {
238
- gestureActiveRef.current = false;
239
- applyWorldTransform();
240
- canvasGesture.set(false);
241
- }, GESTURE_SETTLE_MS);
242
- }, [applyWorldTransform]);
243
- useEffect(() => () => {
244
- clearTimeout(gestureSettleTimerRef.current);
245
- canvasGesture.set(false);
246
- }, []);
247
- const zoomTowards = useCallback((focusX, focusY, factor) => {
248
- const newZoom = Math.max(minZoom, Math.min(maxZoom, zoomRef.current * factor));
249
- const worldX = (focusX - panRef.current.x) / zoomRef.current;
250
- const worldY = (focusY - panRef.current.y) / zoomRef.current;
251
- panRef.current = {
252
- x: focusX - worldX * newZoom,
253
- y: focusY - worldY * newZoom,
254
- };
255
- zoomRef.current = newZoom;
256
- noteGestureActivity();
257
- scheduleTransformApply();
258
- }, [minZoom, maxZoom, noteGestureActivity, scheduleTransformApply]);
259
- const handleWheel = useCallback((e) => {
260
- const container = containerRef.current;
261
- if (!container)
262
- return;
263
- if (!(e.ctrlKey || e.metaKey) &&
264
- isWithinScrollableContent(e.target, container))
265
- return;
266
- e.preventDefault();
267
- if (animationFrameRef.current !== null) {
268
- cancelAnimationFrame(animationFrameRef.current);
269
- animationFrameRef.current = null;
270
- }
271
- const rect = container.getBoundingClientRect();
272
- const mouseX = e.clientX - rect.left;
273
- const mouseY = e.clientY - rect.top;
274
- if (e.ctrlKey || e.metaKey) {
275
- zoomTowards(mouseX, mouseY, Math.exp(-e.deltaY * ZOOM_INTENSITY));
276
- }
277
- else {
278
- panRef.current = {
279
- x: panRef.current.x - e.deltaX,
280
- y: panRef.current.y - e.deltaY,
281
- };
282
- noteGestureActivity();
283
- scheduleTransformApply();
284
- }
285
- }, [zoomTowards, noteGestureActivity, scheduleTransformApply]);
286
- useEffect(() => {
287
- const container = containerRef.current;
288
- if (!container)
289
- return;
290
- container.addEventListener('wheel', handleWheel, { passive: false });
291
- return () => container.removeEventListener('wheel', handleWheel);
292
- }, [handleWheel]);
293
- useEffect(() => {
294
- const container = containerRef.current;
295
- if (!container)
296
- return;
297
- let lastScale = 1;
298
- const handleGestureStart = (event) => {
299
- event.preventDefault();
300
- lastScale = event.scale || 1;
301
- };
302
- const handleGestureChange = (event) => {
303
- event.preventDefault();
304
- if (touchPointersRef.current.size > 0)
305
- return;
306
- const gesture = event;
307
- if (!gesture.scale || !lastScale)
308
- return;
309
- const rect = container.getBoundingClientRect();
310
- zoomTowards(gesture.clientX - rect.left, gesture.clientY - rect.top, gesture.scale / lastScale);
311
- lastScale = gesture.scale;
312
- };
313
- const handleGestureEnd = (event) => event.preventDefault();
314
- container.addEventListener('gesturestart', handleGestureStart, {
315
- passive: false,
316
- });
317
- container.addEventListener('gesturechange', handleGestureChange, {
318
- passive: false,
319
- });
320
- container.addEventListener('gestureend', handleGestureEnd, { passive: false });
321
- return () => {
322
- container.removeEventListener('gesturestart', handleGestureStart);
323
- container.removeEventListener('gesturechange', handleGestureChange);
324
- container.removeEventListener('gestureend', handleGestureEnd);
325
- };
326
- }, [zoomTowards]);
327
- useEffect(() => {
328
- const isWithinCanvas = (x, y) => {
329
- const rect = containerRef.current?.getBoundingClientRect();
330
- return (!!rect &&
331
- x >= rect.left &&
332
- x <= rect.right &&
333
- y >= rect.top &&
334
- y <= rect.bottom);
335
- };
336
- const reachesContainerListeners = (event) => event.target instanceof Node &&
337
- !!containerRef.current?.contains(event.target);
338
- const handleWindowWheel = (event) => {
339
- if ((event.ctrlKey || event.metaKey) &&
340
- isWithinCanvas(event.clientX, event.clientY)) {
341
- event.preventDefault();
342
- }
343
- };
344
- let lastScale = 1;
345
- const handleWindowGestureStart = (event) => {
346
- const gesture = event;
347
- if (!isWithinCanvas(gesture.clientX, gesture.clientY))
348
- return;
349
- event.preventDefault();
350
- lastScale = gesture.scale || 1;
351
- };
352
- const handleWindowGestureChange = (event) => {
353
- const gesture = event;
354
- if (!isWithinCanvas(gesture.clientX, gesture.clientY))
355
- return;
356
- event.preventDefault();
357
- if (reachesContainerListeners(event))
358
- return;
359
- if (touchPointersRef.current.size > 0)
360
- return;
361
- if (!gesture.scale || !lastScale)
362
- return;
363
- const rect = containerRef.current?.getBoundingClientRect();
364
- if (!rect)
365
- return;
366
- zoomTowards(gesture.clientX - rect.left, gesture.clientY - rect.top, gesture.scale / lastScale);
367
- lastScale = gesture.scale;
368
- };
369
- const handleWindowGestureEnd = (event) => {
370
- const gesture = event;
371
- if (isWithinCanvas(gesture.clientX, gesture.clientY))
372
- event.preventDefault();
373
- };
374
- window.addEventListener('wheel', handleWindowWheel, { passive: false });
375
- window.addEventListener('gesturestart', handleWindowGestureStart, {
376
- passive: false,
377
- });
378
- window.addEventListener('gesturechange', handleWindowGestureChange, {
379
- passive: false,
380
- });
381
- window.addEventListener('gestureend', handleWindowGestureEnd, { passive: false });
382
- return () => {
383
- window.removeEventListener('wheel', handleWindowWheel);
384
- window.removeEventListener('gesturestart', handleWindowGestureStart);
385
- window.removeEventListener('gesturechange', handleWindowGestureChange);
386
- window.removeEventListener('gestureend', handleWindowGestureEnd);
387
- };
388
- }, [zoomTowards]);
389
- const applyPinch = useCallback(() => {
390
- const container = containerRef.current;
391
- const snapshot = pinchSnapshotOf(touchPointersRef.current.values());
392
- if (!container || !snapshot)
393
- return;
394
- const previous = pinchRef.current;
395
- pinchRef.current = snapshot;
396
- if (!previous)
397
- return;
398
- const change = pinchChangeBetween(previous, snapshot);
399
- const rect = container.getBoundingClientRect();
400
- const focusX = snapshot.center.x - rect.left;
401
- const focusY = snapshot.center.y - rect.top;
402
- const newZoom = Math.max(minZoom, Math.min(maxZoom, zoomRef.current * change.scale));
403
- const worldX = (focusX - change.panX - panRef.current.x) / zoomRef.current;
404
- const worldY = (focusY - change.panY - panRef.current.y) / zoomRef.current;
405
- panRef.current = { x: focusX - worldX * newZoom, y: focusY - worldY * newZoom };
406
- zoomRef.current = newZoom;
407
- noteGestureActivity();
408
- scheduleTransformApply();
409
- }, [minZoom, maxZoom, noteGestureActivity, scheduleTransformApply]);
410
- const startTouchMomentum = useCallback(() => {
411
- const initialVelocity = velocityFromSamples(touchPanSamplesRef.current, MOMENTUM_MIN_VELOCITY);
412
- if (!initialVelocity)
413
- return;
414
- if (animationFrameRef.current !== null) {
415
- cancelAnimationFrame(animationFrameRef.current);
416
- animationFrameRef.current = null;
417
- }
418
- let velocity = initialVelocity;
419
- let lastFrameTime = performance.now();
420
- const animate = (currentTime) => {
421
- const frameElapsedMs = currentTime - lastFrameTime;
422
- lastFrameTime = currentTime;
423
- panRef.current = {
424
- x: panRef.current.x + velocity.x * frameElapsedMs,
425
- y: panRef.current.y + velocity.y * frameElapsedMs,
426
- };
427
- velocity = decayVelocity(velocity, frameElapsedMs);
428
- applyWorldTransform();
429
- refreshMinimap();
430
- render();
431
- noteGestureActivity();
432
- if (Math.hypot(velocity.x, velocity.y) > MOMENTUM_MIN_VELOCITY) {
433
- animationFrameRef.current = requestAnimationFrame(animate);
434
- }
435
- else {
436
- animationFrameRef.current = null;
437
- }
438
- };
439
- animationFrameRef.current = requestAnimationFrame(animate);
440
- }, [applyWorldTransform, refreshMinimap, render, noteGestureActivity]);
441
- const handlePointerDown = useCallback((e) => {
442
- if (animationFrameRef.current !== null) {
443
- cancelAnimationFrame(animationFrameRef.current);
444
- animationFrameRef.current = null;
445
- }
446
- if (e.pointerType === 'touch') {
447
- touchPointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
448
- if (touchPointersRef.current.size > 1) {
449
- isPanningRef.current = false;
450
- setPanCursor(false);
451
- pinchRef.current = pinchSnapshotOf(touchPointersRef.current.values());
452
- return;
453
- }
454
- }
455
- const isBackground = isBackgroundPointerTarget(e.pointerType, readOnly, e.target, containerRef.current);
456
- const mayDragPan = backgroundDragPans || e.pointerType === 'touch';
457
- if (e.button === 1 || (e.button === 0 && isBackground && mayDragPan)) {
458
- if (e.button === 1)
459
- e.preventDefault();
460
- isPanningRef.current = true;
461
- setPanCursor(true);
462
- lastPointerRef.current = { x: e.clientX, y: e.clientY };
463
- if (e.pointerType === 'touch') {
464
- touchPanSamplesRef.current = [
465
- { x: e.clientX, y: e.clientY, time: performance.now() },
466
- ];
467
- }
468
- e.currentTarget.setPointerCapture(e.pointerId);
469
- }
470
- }, [readOnly, backgroundDragPans, setPanCursor]);
471
- const handlePointerMove = useCallback((e) => {
472
- if (e.pointerType === 'touch' && touchPointersRef.current.has(e.pointerId)) {
473
- touchPointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
474
- if (touchPointersRef.current.size > 1) {
475
- applyPinch();
476
- return;
477
- }
478
- }
479
- if (!isPanningRef.current)
480
- return;
481
- const deltaX = e.clientX - lastPointerRef.current.x;
482
- const deltaY = e.clientY - lastPointerRef.current.y;
483
- lastPointerRef.current = { x: e.clientX, y: e.clientY };
484
- panRef.current = {
485
- x: panRef.current.x + deltaX,
486
- y: panRef.current.y + deltaY,
487
- };
488
- if (e.pointerType === 'touch') {
489
- const samples = [
490
- ...touchPanSamplesRef.current,
491
- { x: e.clientX, y: e.clientY, time: performance.now() },
492
- ];
493
- touchPanSamplesRef.current = trimSamples(samples, MOMENTUM_SAMPLE_WINDOW_MS);
494
- }
495
- noteGestureActivity();
496
- scheduleTransformApply();
497
- }, [applyPinch, noteGestureActivity, scheduleTransformApply]);
498
- const handlePointerUp = useCallback((e) => {
499
- if (touchPointersRef.current.delete(e.pointerId)) {
500
- pinchRef.current = pinchSnapshotOf(touchPointersRef.current.values());
501
- const [remaining] = [...touchPointersRef.current.values()];
502
- if (remaining) {
503
- isPanningRef.current = true;
504
- setPanCursor(true);
505
- lastPointerRef.current = { x: remaining.x, y: remaining.y };
506
- touchPanSamplesRef.current = [
507
- { x: remaining.x, y: remaining.y, time: performance.now() },
508
- ];
509
- return;
510
- }
511
- }
512
- const wasPanningTouch = e.pointerType === 'touch' && isPanningRef.current;
513
- isPanningRef.current = false;
514
- setPanCursor(false);
515
- if (wasPanningTouch)
516
- startTouchMomentum();
517
- }, [startTouchMomentum, setPanCursor]);
518
- useEffect(() => {
519
- const world = worldRef.current;
520
- if (!pixiReady || !world || !renderItem)
521
- return;
522
- const incoming = new Map(items.map((item) => [item.id, item]));
523
- spritesRef.current.forEach((container, id) => {
524
- if (!incoming.has(id)) {
525
- world.removeChild(container);
526
- container.destroy({ children: true });
527
- spritesRef.current.delete(id);
528
- }
529
- });
530
- items.forEach((item) => {
531
- const existing = spritesRef.current.get(item.id);
532
- if (existing) {
533
- existing.position.set(item.x, item.y);
534
- existing.removeAllListeners('pointerdown');
535
- existing.on('pointerdown', (event) => {
536
- onItemPointerDownRef.current?.(item, event);
537
- });
538
- }
539
- else {
540
- const container = renderItem(item);
541
- container.position.set(item.x, item.y);
542
- container.eventMode = 'static';
543
- container.on('pointerdown', (event) => {
544
- onItemPointerDownRef.current?.(item, event);
545
- });
546
- world.addChild(container);
547
- spritesRef.current.set(item.id, container);
548
- }
549
- });
550
- appRef.current?.renderer.render(appRef.current.stage);
551
- }, [pixiReady, items, renderItem]);
552
- const handleZoomIn = useCallback(() => {
553
- const container = containerRef.current;
554
- if (!container)
555
- return;
556
- const cx = container.clientWidth / 2;
557
- const cy = container.clientHeight / 2;
558
- const factor = 1.2;
559
- const newZoom = Math.min(maxZoom, zoomRef.current * factor);
560
- const worldX = (cx - panRef.current.x) / zoomRef.current;
561
- const worldY = (cy - panRef.current.y) / zoomRef.current;
562
- panRef.current = { x: cx - worldX * newZoom, y: cy - worldY * newZoom };
563
- zoomRef.current = newZoom;
564
- applyWorldTransform();
565
- refreshMinimap();
566
- render();
567
- }, [maxZoom, applyWorldTransform, refreshMinimap, render]);
568
- const handleZoomOut = useCallback(() => {
569
- const container = containerRef.current;
570
- if (!container)
571
- return;
572
- const cx = container.clientWidth / 2;
573
- const cy = container.clientHeight / 2;
574
- const factor = 1.2;
575
- const newZoom = Math.max(minZoom, zoomRef.current / factor);
576
- const worldX = (cx - panRef.current.x) / zoomRef.current;
577
- const worldY = (cy - panRef.current.y) / zoomRef.current;
578
- panRef.current = { x: cx - worldX * newZoom, y: cy - worldY * newZoom };
579
- zoomRef.current = newZoom;
580
- applyWorldTransform();
581
- refreshMinimap();
582
- render();
583
- }, [minZoom, applyWorldTransform, refreshMinimap, render]);
584
- const handleZoomReset = useCallback(() => {
585
- zoomRef.current = 1;
586
- applyWorldTransform();
587
- refreshMinimap();
588
- render();
589
- }, [applyWorldTransform, refreshMinimap, render]);
590
- const handleMinimapPan = useCallback((pan) => {
591
- panRef.current = pan;
592
- applyWorldTransform();
593
- refreshMinimap();
594
- render();
595
- }, [applyWorldTransform, refreshMinimap, render]);
596
- const smoothPanToWorld = useCallback((worldX, worldY, durationMs = 600) => {
597
- const container = containerRef.current;
598
- if (!container)
599
- return;
600
- if (animationFrameRef.current !== null) {
601
- cancelAnimationFrame(animationFrameRef.current);
602
- animationFrameRef.current = null;
603
- }
604
- const viewportWidth = container.clientWidth;
605
- const viewportHeight = container.clientHeight;
606
- const targetPanX = viewportWidth / 2 - worldX * zoomRef.current;
607
- const targetPanY = viewportHeight / 2 - worldY * zoomRef.current;
608
- const startPanX = panRef.current.x;
609
- const startPanY = panRef.current.y;
610
- const startTime = performance.now();
611
- const animate = (currentTime) => {
612
- const elapsed = currentTime - startTime;
613
- const progress = Math.min(elapsed / durationMs, 1);
614
- const eased = easeInOutCubic(progress);
615
- panRef.current = {
616
- x: startPanX + (targetPanX - startPanX) * eased,
617
- y: startPanY + (targetPanY - startPanY) * eased,
618
- };
619
- applyWorldTransform();
620
- refreshMinimap();
621
- render();
622
- if (progress < 1) {
623
- animationFrameRef.current = requestAnimationFrame(animate);
624
- }
625
- else {
626
- animationFrameRef.current = null;
627
- }
628
- };
629
- animationFrameRef.current = requestAnimationFrame(animate);
630
- }, [applyWorldTransform, refreshMinimap, render]);
631
- const smoothPanZoomToWorld = useCallback((worldX, worldY, targetZoom = 1, durationMs = 600) => {
632
- const container = containerRef.current;
633
- if (!container)
634
- return;
635
- if (animationFrameRef.current !== null) {
636
- cancelAnimationFrame(animationFrameRef.current);
637
- animationFrameRef.current = null;
638
- }
639
- const viewportWidth = container.clientWidth;
640
- const viewportHeight = container.clientHeight;
641
- const startZoom = zoomRef.current;
642
- const endZoom = Math.min(maxZoom, Math.max(minZoom, targetZoom));
643
- const startPanX = panRef.current.x;
644
- const startPanY = panRef.current.y;
645
- const endPanX = viewportWidth / 2 - worldX * endZoom;
646
- const endPanY = viewportHeight / 2 - worldY * endZoom;
647
- const startTime = performance.now();
648
- const animate = (currentTime) => {
649
- const elapsed = currentTime - startTime;
650
- const progress = Math.min(elapsed / durationMs, 1);
651
- const eased = easeInOutCubic(progress);
652
- zoomRef.current = startZoom + (endZoom - startZoom) * eased;
653
- panRef.current = {
654
- x: startPanX + (endPanX - startPanX) * eased,
655
- y: startPanY + (endPanY - startPanY) * eased,
656
- };
657
- applyWorldTransform();
658
- refreshMinimap();
659
- render();
660
- if (progress < 1) {
661
- animationFrameRef.current = requestAnimationFrame(animate);
662
- }
663
- else {
664
- animationFrameRef.current = null;
665
- }
666
- };
667
- animationFrameRef.current = requestAnimationFrame(animate);
668
- }, [maxZoom, minZoom, applyWorldTransform, refreshMinimap, render]);
669
- const getContainerRect = useCallback(() => {
670
- return containerRef.current?.getBoundingClientRect() ?? null;
671
- }, []);
672
- const getItemBounds = useCallback(() => Array.from(itemRegistryRef.current.values(), (entry) => ({
673
- x: entry.x,
674
- y: entry.y,
675
- width: entry.width,
676
- height: entry.height,
677
- })), []);
678
- useEffect(() => {
679
- if (!pixiReady)
680
- return;
681
- onHandleReadyRef.current?.({
682
- smoothPanToWorld,
683
- smoothPanZoomToWorld,
684
- getContainerRect,
685
- getItemBounds,
686
- });
687
- }, [
33
+ const { appRef, worldRef, spritesRef, pixiReady, render } = usePixiApplication({
34
+ containerRef,
35
+ panRef,
36
+ zoomRef,
37
+ onReadyRef,
38
+ captureLayer: captureAttributes?.layer,
39
+ });
40
+ const { applyWorldTransform, refreshMinimap, scheduleTransformApply, noteGestureActivity, zoomTowards, } = useCanvasCamera({
41
+ appRef,
42
+ worldRef,
43
+ minimapRef,
44
+ overlayRef,
45
+ zoomLayerRef,
46
+ panRef,
47
+ zoomRef,
48
+ onTransformChangeRef,
49
+ render,
50
+ minZoom,
51
+ maxZoom,
52
+ });
53
+ useCanvasWheelZoom({
54
+ containerRef,
55
+ animationFrameRef,
56
+ panRef,
57
+ touchPointersRef,
58
+ zoomTowards,
59
+ noteGestureActivity,
60
+ scheduleTransformApply,
61
+ });
62
+ const { handlePointerDown, handlePointerMove, handlePointerUp } = useCanvasPointerGestures({
63
+ containerRef,
64
+ animationFrameRef,
65
+ panRef,
66
+ zoomRef,
67
+ touchPointersRef,
68
+ minZoom,
69
+ maxZoom,
70
+ readOnly,
71
+ backgroundDragPans,
72
+ applyWorldTransform,
73
+ refreshMinimap,
74
+ render,
75
+ noteGestureActivity,
76
+ scheduleTransformApply,
77
+ });
78
+ usePixiItems({
79
+ pixiReady,
80
+ appRef,
81
+ worldRef,
82
+ spritesRef,
83
+ items,
84
+ renderItem,
85
+ onItemPointerDownRef,
86
+ });
87
+ const { handleZoomIn, handleZoomOut, handleZoomReset, handleMinimapPan } = useCanvasNavigation({
88
+ containerRef,
89
+ animationFrameRef,
90
+ panRef,
91
+ zoomRef,
92
+ itemRegistryRef,
93
+ minZoom,
94
+ maxZoom,
688
95
  pixiReady,
689
- smoothPanToWorld,
690
- smoothPanZoomToWorld,
691
- getContainerRect,
692
- getItemBounds,
693
- ]);
96
+ onHandleReadyRef,
97
+ applyWorldTransform,
98
+ refreshMinimap,
99
+ render,
100
+ });
694
101
  return (jsxs("div", { ref: containerRef, className: `canvas-surface cratis:relative cratis:overflow-hidden${className ? ` ${className}` : ''}`, style: { cursor: 'default', ...style }, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, onPointerCancel: handlePointerUp, children: [jsx(CanvasItemRegistryContext.Provider, { value: registryContextValue, children: jsx("div", { ref: overlayRef, ...(captureAttributes?.transformHost
695
102
  ? { [captureAttributes.transformHost]: 'true' }
696
103
  : {}), style: {