@archireport/react-native-drawing 0.2.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 (323) hide show
  1. package/README.md +181 -0
  2. package/lib/commonjs/DrawingEditor.js +815 -0
  3. package/lib/commonjs/DrawingEditor.js.map +1 -0
  4. package/lib/commonjs/assets/toolbar-icons/arrow-disabled.png +0 -0
  5. package/lib/commonjs/assets/toolbar-icons/arrow-enabled.png +0 -0
  6. package/lib/commonjs/assets/toolbar-icons/arrow.png +0 -0
  7. package/lib/commonjs/assets/toolbar-icons/circle-disabled.png +0 -0
  8. package/lib/commonjs/assets/toolbar-icons/circle-enabled.png +0 -0
  9. package/lib/commonjs/assets/toolbar-icons/circle.png +0 -0
  10. package/lib/commonjs/assets/toolbar-icons/freehand-disabled.png +0 -0
  11. package/lib/commonjs/assets/toolbar-icons/freehand-enabled.png +0 -0
  12. package/lib/commonjs/assets/toolbar-icons/freehand.png +0 -0
  13. package/lib/commonjs/assets/toolbar-icons/line-disabled.png +0 -0
  14. package/lib/commonjs/assets/toolbar-icons/line-enabled.png +0 -0
  15. package/lib/commonjs/assets/toolbar-icons/line.png +0 -0
  16. package/lib/commonjs/assets/toolbar-icons/measure-disabled.png +0 -0
  17. package/lib/commonjs/assets/toolbar-icons/measure-enabled.png +0 -0
  18. package/lib/commonjs/assets/toolbar-icons/measure.png +0 -0
  19. package/lib/commonjs/assets/toolbar-icons/move-disabled.png +0 -0
  20. package/lib/commonjs/assets/toolbar-icons/move-enabled.png +0 -0
  21. package/lib/commonjs/assets/toolbar-icons/move.png +0 -0
  22. package/lib/commonjs/assets/toolbar-icons/polygon-disabled.png +0 -0
  23. package/lib/commonjs/assets/toolbar-icons/polygon-enabled.png +0 -0
  24. package/lib/commonjs/assets/toolbar-icons/polygon.png +0 -0
  25. package/lib/commonjs/assets/toolbar-icons/rectangle-disabled.png +0 -0
  26. package/lib/commonjs/assets/toolbar-icons/rectangle-enabled.png +0 -0
  27. package/lib/commonjs/assets/toolbar-icons/rectangle.png +0 -0
  28. package/lib/commonjs/assets/toolbar-icons/text-disabled.png +0 -0
  29. package/lib/commonjs/assets/toolbar-icons/text-enabled.png +0 -0
  30. package/lib/commonjs/assets/toolbar-icons/text.png +0 -0
  31. package/lib/commonjs/components/ColorPalette.js +379 -0
  32. package/lib/commonjs/components/ColorPalette.js.map +1 -0
  33. package/lib/commonjs/components/LineWidthSlider.js +70 -0
  34. package/lib/commonjs/components/LineWidthSlider.js.map +1 -0
  35. package/lib/commonjs/components/MeasurementEditModal.js +153 -0
  36. package/lib/commonjs/components/MeasurementEditModal.js.map +1 -0
  37. package/lib/commonjs/components/MiniMap.js +244 -0
  38. package/lib/commonjs/components/MiniMap.js.map +1 -0
  39. package/lib/commonjs/components/TextAnnotation.js +162 -0
  40. package/lib/commonjs/components/TextAnnotation.js.map +1 -0
  41. package/lib/commonjs/components/TextEditModal.js +133 -0
  42. package/lib/commonjs/components/TextEditModal.js.map +1 -0
  43. package/lib/commonjs/components/Toolbar.js +198 -0
  44. package/lib/commonjs/components/Toolbar.js.map +1 -0
  45. package/lib/commonjs/components/ZoomBadge.js +161 -0
  46. package/lib/commonjs/components/ZoomBadge.js.map +1 -0
  47. package/lib/commonjs/hooks/useFreehandGesture.js +173 -0
  48. package/lib/commonjs/hooks/useFreehandGesture.js.map +1 -0
  49. package/lib/commonjs/hooks/usePolygonGesture.js +109 -0
  50. package/lib/commonjs/hooks/usePolygonGesture.js.map +1 -0
  51. package/lib/commonjs/hooks/useSelectionGesture.js +236 -0
  52. package/lib/commonjs/hooks/useSelectionGesture.js.map +1 -0
  53. package/lib/commonjs/hooks/useShapeGesture.js +181 -0
  54. package/lib/commonjs/hooks/useShapeGesture.js.map +1 -0
  55. package/lib/commonjs/hooks/useViewportGesture.js +238 -0
  56. package/lib/commonjs/hooks/useViewportGesture.js.map +1 -0
  57. package/lib/commonjs/index.js +104 -0
  58. package/lib/commonjs/index.js.map +1 -0
  59. package/lib/commonjs/package.json +1 -0
  60. package/lib/commonjs/renderers/ArrowRenderer.js +118 -0
  61. package/lib/commonjs/renderers/ArrowRenderer.js.map +1 -0
  62. package/lib/commonjs/renderers/CircleRenderer.js +51 -0
  63. package/lib/commonjs/renderers/CircleRenderer.js.map +1 -0
  64. package/lib/commonjs/renderers/FreehandRenderer.js +31 -0
  65. package/lib/commonjs/renderers/FreehandRenderer.js.map +1 -0
  66. package/lib/commonjs/renderers/InProgressRenderer.js +174 -0
  67. package/lib/commonjs/renderers/InProgressRenderer.js.map +1 -0
  68. package/lib/commonjs/renderers/LineRenderer.js +27 -0
  69. package/lib/commonjs/renderers/LineRenderer.js.map +1 -0
  70. package/lib/commonjs/renderers/MeasurementRenderer.js +134 -0
  71. package/lib/commonjs/renderers/MeasurementRenderer.js.map +1 -0
  72. package/lib/commonjs/renderers/ObjectRenderer.js +65 -0
  73. package/lib/commonjs/renderers/ObjectRenderer.js.map +1 -0
  74. package/lib/commonjs/renderers/PolygonRenderer.js +46 -0
  75. package/lib/commonjs/renderers/PolygonRenderer.js.map +1 -0
  76. package/lib/commonjs/renderers/RectRenderer.js +51 -0
  77. package/lib/commonjs/renderers/RectRenderer.js.map +1 -0
  78. package/lib/commonjs/renderers/SelectedObjectRenderer.js +592 -0
  79. package/lib/commonjs/renderers/SelectedObjectRenderer.js.map +1 -0
  80. package/lib/commonjs/renderers/SelectionOverlay.js +120 -0
  81. package/lib/commonjs/renderers/SelectionOverlay.js.map +1 -0
  82. package/lib/commonjs/store/useDrawingStore.js +354 -0
  83. package/lib/commonjs/store/useDrawingStore.js.map +1 -0
  84. package/lib/commonjs/types.js +6 -0
  85. package/lib/commonjs/types.js.map +1 -0
  86. package/lib/commonjs/utils/colors.js +44 -0
  87. package/lib/commonjs/utils/colors.js.map +1 -0
  88. package/lib/commonjs/utils/coordinates.js +81 -0
  89. package/lib/commonjs/utils/coordinates.js.map +1 -0
  90. package/lib/commonjs/utils/hitTesting.js +181 -0
  91. package/lib/commonjs/utils/hitTesting.js.map +1 -0
  92. package/lib/commonjs/utils/serialization.js +42 -0
  93. package/lib/commonjs/utils/serialization.js.map +1 -0
  94. package/lib/commonjs/utils/shapeDetection.js +151 -0
  95. package/lib/commonjs/utils/shapeDetection.js.map +1 -0
  96. package/lib/commonjs/utils/smoothing.js +85 -0
  97. package/lib/commonjs/utils/smoothing.js.map +1 -0
  98. package/lib/module/DrawingEditor.js +811 -0
  99. package/lib/module/DrawingEditor.js.map +1 -0
  100. package/lib/module/assets/toolbar-icons/arrow-disabled.png +0 -0
  101. package/lib/module/assets/toolbar-icons/arrow-enabled.png +0 -0
  102. package/lib/module/assets/toolbar-icons/arrow.png +0 -0
  103. package/lib/module/assets/toolbar-icons/circle-disabled.png +0 -0
  104. package/lib/module/assets/toolbar-icons/circle-enabled.png +0 -0
  105. package/lib/module/assets/toolbar-icons/circle.png +0 -0
  106. package/lib/module/assets/toolbar-icons/freehand-disabled.png +0 -0
  107. package/lib/module/assets/toolbar-icons/freehand-enabled.png +0 -0
  108. package/lib/module/assets/toolbar-icons/freehand.png +0 -0
  109. package/lib/module/assets/toolbar-icons/line-disabled.png +0 -0
  110. package/lib/module/assets/toolbar-icons/line-enabled.png +0 -0
  111. package/lib/module/assets/toolbar-icons/line.png +0 -0
  112. package/lib/module/assets/toolbar-icons/measure-disabled.png +0 -0
  113. package/lib/module/assets/toolbar-icons/measure-enabled.png +0 -0
  114. package/lib/module/assets/toolbar-icons/measure.png +0 -0
  115. package/lib/module/assets/toolbar-icons/move-disabled.png +0 -0
  116. package/lib/module/assets/toolbar-icons/move-enabled.png +0 -0
  117. package/lib/module/assets/toolbar-icons/move.png +0 -0
  118. package/lib/module/assets/toolbar-icons/polygon-disabled.png +0 -0
  119. package/lib/module/assets/toolbar-icons/polygon-enabled.png +0 -0
  120. package/lib/module/assets/toolbar-icons/polygon.png +0 -0
  121. package/lib/module/assets/toolbar-icons/rectangle-disabled.png +0 -0
  122. package/lib/module/assets/toolbar-icons/rectangle-enabled.png +0 -0
  123. package/lib/module/assets/toolbar-icons/rectangle.png +0 -0
  124. package/lib/module/assets/toolbar-icons/text-disabled.png +0 -0
  125. package/lib/module/assets/toolbar-icons/text-enabled.png +0 -0
  126. package/lib/module/assets/toolbar-icons/text.png +0 -0
  127. package/lib/module/components/ColorPalette.js +374 -0
  128. package/lib/module/components/ColorPalette.js.map +1 -0
  129. package/lib/module/components/LineWidthSlider.js +64 -0
  130. package/lib/module/components/LineWidthSlider.js.map +1 -0
  131. package/lib/module/components/MeasurementEditModal.js +148 -0
  132. package/lib/module/components/MeasurementEditModal.js.map +1 -0
  133. package/lib/module/components/MiniMap.js +239 -0
  134. package/lib/module/components/MiniMap.js.map +1 -0
  135. package/lib/module/components/TextAnnotation.js +157 -0
  136. package/lib/module/components/TextAnnotation.js.map +1 -0
  137. package/lib/module/components/TextEditModal.js +128 -0
  138. package/lib/module/components/TextEditModal.js.map +1 -0
  139. package/lib/module/components/Toolbar.js +193 -0
  140. package/lib/module/components/Toolbar.js.map +1 -0
  141. package/lib/module/components/ZoomBadge.js +155 -0
  142. package/lib/module/components/ZoomBadge.js.map +1 -0
  143. package/lib/module/hooks/useFreehandGesture.js +169 -0
  144. package/lib/module/hooks/useFreehandGesture.js.map +1 -0
  145. package/lib/module/hooks/usePolygonGesture.js +106 -0
  146. package/lib/module/hooks/usePolygonGesture.js.map +1 -0
  147. package/lib/module/hooks/useSelectionGesture.js +232 -0
  148. package/lib/module/hooks/useSelectionGesture.js.map +1 -0
  149. package/lib/module/hooks/useShapeGesture.js +177 -0
  150. package/lib/module/hooks/useShapeGesture.js.map +1 -0
  151. package/lib/module/hooks/useViewportGesture.js +234 -0
  152. package/lib/module/hooks/useViewportGesture.js.map +1 -0
  153. package/lib/module/index.js +20 -0
  154. package/lib/module/index.js.map +1 -0
  155. package/lib/module/package.json +1 -0
  156. package/lib/module/renderers/ArrowRenderer.js +113 -0
  157. package/lib/module/renderers/ArrowRenderer.js.map +1 -0
  158. package/lib/module/renderers/CircleRenderer.js +46 -0
  159. package/lib/module/renderers/CircleRenderer.js.map +1 -0
  160. package/lib/module/renderers/FreehandRenderer.js +26 -0
  161. package/lib/module/renderers/FreehandRenderer.js.map +1 -0
  162. package/lib/module/renderers/InProgressRenderer.js +169 -0
  163. package/lib/module/renderers/InProgressRenderer.js.map +1 -0
  164. package/lib/module/renderers/LineRenderer.js +22 -0
  165. package/lib/module/renderers/LineRenderer.js.map +1 -0
  166. package/lib/module/renderers/MeasurementRenderer.js +129 -0
  167. package/lib/module/renderers/MeasurementRenderer.js.map +1 -0
  168. package/lib/module/renderers/ObjectRenderer.js +60 -0
  169. package/lib/module/renderers/ObjectRenderer.js.map +1 -0
  170. package/lib/module/renderers/PolygonRenderer.js +41 -0
  171. package/lib/module/renderers/PolygonRenderer.js.map +1 -0
  172. package/lib/module/renderers/RectRenderer.js +46 -0
  173. package/lib/module/renderers/RectRenderer.js.map +1 -0
  174. package/lib/module/renderers/SelectedObjectRenderer.js +587 -0
  175. package/lib/module/renderers/SelectedObjectRenderer.js.map +1 -0
  176. package/lib/module/renderers/SelectionOverlay.js +116 -0
  177. package/lib/module/renderers/SelectionOverlay.js.map +1 -0
  178. package/lib/module/store/useDrawingStore.js +350 -0
  179. package/lib/module/store/useDrawingStore.js.map +1 -0
  180. package/lib/module/types.js +4 -0
  181. package/lib/module/types.js.map +1 -0
  182. package/lib/module/utils/colors.js +40 -0
  183. package/lib/module/utils/colors.js.map +1 -0
  184. package/lib/module/utils/coordinates.js +71 -0
  185. package/lib/module/utils/coordinates.js.map +1 -0
  186. package/lib/module/utils/hitTesting.js +171 -0
  187. package/lib/module/utils/hitTesting.js.map +1 -0
  188. package/lib/module/utils/serialization.js +36 -0
  189. package/lib/module/utils/serialization.js.map +1 -0
  190. package/lib/module/utils/shapeDetection.js +147 -0
  191. package/lib/module/utils/shapeDetection.js.map +1 -0
  192. package/lib/module/utils/smoothing.js +80 -0
  193. package/lib/module/utils/smoothing.js.map +1 -0
  194. package/lib/typescript/DrawingEditor.d.ts +3 -0
  195. package/lib/typescript/DrawingEditor.d.ts.map +1 -0
  196. package/lib/typescript/components/ColorPalette.d.ts +9 -0
  197. package/lib/typescript/components/ColorPalette.d.ts.map +1 -0
  198. package/lib/typescript/components/LineWidthSlider.d.ts +11 -0
  199. package/lib/typescript/components/LineWidthSlider.d.ts.map +1 -0
  200. package/lib/typescript/components/MeasurementEditModal.d.ts +11 -0
  201. package/lib/typescript/components/MeasurementEditModal.d.ts.map +1 -0
  202. package/lib/typescript/components/MiniMap.d.ts +23 -0
  203. package/lib/typescript/components/MiniMap.d.ts.map +1 -0
  204. package/lib/typescript/components/TextAnnotation.d.ts +22 -0
  205. package/lib/typescript/components/TextAnnotation.d.ts.map +1 -0
  206. package/lib/typescript/components/TextEditModal.d.ts +10 -0
  207. package/lib/typescript/components/TextEditModal.d.ts.map +1 -0
  208. package/lib/typescript/components/Toolbar.d.ts +13 -0
  209. package/lib/typescript/components/Toolbar.d.ts.map +1 -0
  210. package/lib/typescript/components/ZoomBadge.d.ts +9 -0
  211. package/lib/typescript/components/ZoomBadge.d.ts.map +1 -0
  212. package/lib/typescript/hooks/useFreehandGesture.d.ts +47 -0
  213. package/lib/typescript/hooks/useFreehandGesture.d.ts.map +1 -0
  214. package/lib/typescript/hooks/usePolygonGesture.d.ts +47 -0
  215. package/lib/typescript/hooks/usePolygonGesture.d.ts.map +1 -0
  216. package/lib/typescript/hooks/useSelectionGesture.d.ts +32 -0
  217. package/lib/typescript/hooks/useSelectionGesture.d.ts.map +1 -0
  218. package/lib/typescript/hooks/useShapeGesture.d.ts +54 -0
  219. package/lib/typescript/hooks/useShapeGesture.d.ts.map +1 -0
  220. package/lib/typescript/hooks/useViewportGesture.d.ts +37 -0
  221. package/lib/typescript/hooks/useViewportGesture.d.ts.map +1 -0
  222. package/lib/typescript/index.d.ts +11 -0
  223. package/lib/typescript/index.d.ts.map +1 -0
  224. package/lib/typescript/renderers/ArrowRenderer.d.ts +9 -0
  225. package/lib/typescript/renderers/ArrowRenderer.d.ts.map +1 -0
  226. package/lib/typescript/renderers/CircleRenderer.d.ts +9 -0
  227. package/lib/typescript/renderers/CircleRenderer.d.ts.map +1 -0
  228. package/lib/typescript/renderers/FreehandRenderer.d.ts +9 -0
  229. package/lib/typescript/renderers/FreehandRenderer.d.ts.map +1 -0
  230. package/lib/typescript/renderers/InProgressRenderer.d.ts +32 -0
  231. package/lib/typescript/renderers/InProgressRenderer.d.ts.map +1 -0
  232. package/lib/typescript/renderers/LineRenderer.d.ts +9 -0
  233. package/lib/typescript/renderers/LineRenderer.d.ts.map +1 -0
  234. package/lib/typescript/renderers/MeasurementRenderer.d.ts +9 -0
  235. package/lib/typescript/renderers/MeasurementRenderer.d.ts.map +1 -0
  236. package/lib/typescript/renderers/ObjectRenderer.d.ts +12 -0
  237. package/lib/typescript/renderers/ObjectRenderer.d.ts.map +1 -0
  238. package/lib/typescript/renderers/PolygonRenderer.d.ts +13 -0
  239. package/lib/typescript/renderers/PolygonRenderer.d.ts.map +1 -0
  240. package/lib/typescript/renderers/RectRenderer.d.ts +9 -0
  241. package/lib/typescript/renderers/RectRenderer.d.ts.map +1 -0
  242. package/lib/typescript/renderers/SelectedObjectRenderer.d.ts +18 -0
  243. package/lib/typescript/renderers/SelectedObjectRenderer.d.ts.map +1 -0
  244. package/lib/typescript/renderers/SelectionOverlay.d.ts +21 -0
  245. package/lib/typescript/renderers/SelectionOverlay.d.ts.map +1 -0
  246. package/lib/typescript/store/useDrawingStore.d.ts +30 -0
  247. package/lib/typescript/store/useDrawingStore.d.ts.map +1 -0
  248. package/lib/typescript/types.d.ts +130 -0
  249. package/lib/typescript/types.d.ts.map +1 -0
  250. package/lib/typescript/utils/colors.d.ts +11 -0
  251. package/lib/typescript/utils/colors.d.ts.map +1 -0
  252. package/lib/typescript/utils/coordinates.d.ts +34 -0
  253. package/lib/typescript/utils/coordinates.d.ts.map +1 -0
  254. package/lib/typescript/utils/hitTesting.d.ts +18 -0
  255. package/lib/typescript/utils/hitTesting.d.ts.map +1 -0
  256. package/lib/typescript/utils/serialization.d.ts +17 -0
  257. package/lib/typescript/utils/serialization.d.ts.map +1 -0
  258. package/lib/typescript/utils/shapeDetection.d.ts +22 -0
  259. package/lib/typescript/utils/shapeDetection.d.ts.map +1 -0
  260. package/lib/typescript/utils/smoothing.d.ts +16 -0
  261. package/lib/typescript/utils/smoothing.d.ts.map +1 -0
  262. package/package.json +108 -0
  263. package/src/DrawingEditor.tsx +1071 -0
  264. package/src/assets/toolbar-icons/arrow-disabled.png +0 -0
  265. package/src/assets/toolbar-icons/arrow-enabled.png +0 -0
  266. package/src/assets/toolbar-icons/arrow.png +0 -0
  267. package/src/assets/toolbar-icons/circle-disabled.png +0 -0
  268. package/src/assets/toolbar-icons/circle-enabled.png +0 -0
  269. package/src/assets/toolbar-icons/circle.png +0 -0
  270. package/src/assets/toolbar-icons/freehand-disabled.png +0 -0
  271. package/src/assets/toolbar-icons/freehand-enabled.png +0 -0
  272. package/src/assets/toolbar-icons/freehand.png +0 -0
  273. package/src/assets/toolbar-icons/line-disabled.png +0 -0
  274. package/src/assets/toolbar-icons/line-enabled.png +0 -0
  275. package/src/assets/toolbar-icons/line.png +0 -0
  276. package/src/assets/toolbar-icons/measure-disabled.png +0 -0
  277. package/src/assets/toolbar-icons/measure-enabled.png +0 -0
  278. package/src/assets/toolbar-icons/measure.png +0 -0
  279. package/src/assets/toolbar-icons/move-disabled.png +0 -0
  280. package/src/assets/toolbar-icons/move-enabled.png +0 -0
  281. package/src/assets/toolbar-icons/move.png +0 -0
  282. package/src/assets/toolbar-icons/polygon-disabled.png +0 -0
  283. package/src/assets/toolbar-icons/polygon-enabled.png +0 -0
  284. package/src/assets/toolbar-icons/polygon.png +0 -0
  285. package/src/assets/toolbar-icons/rectangle-disabled.png +0 -0
  286. package/src/assets/toolbar-icons/rectangle-enabled.png +0 -0
  287. package/src/assets/toolbar-icons/rectangle.png +0 -0
  288. package/src/assets/toolbar-icons/text-disabled.png +0 -0
  289. package/src/assets/toolbar-icons/text-enabled.png +0 -0
  290. package/src/assets/toolbar-icons/text.png +0 -0
  291. package/src/components/ColorPalette.tsx +497 -0
  292. package/src/components/LineWidthSlider.tsx +87 -0
  293. package/src/components/MeasurementEditModal.tsx +163 -0
  294. package/src/components/MiniMap.tsx +275 -0
  295. package/src/components/TextAnnotation.tsx +198 -0
  296. package/src/components/TextEditModal.tsx +139 -0
  297. package/src/components/Toolbar.tsx +254 -0
  298. package/src/components/ZoomBadge.tsx +166 -0
  299. package/src/hooks/useFreehandGesture.ts +249 -0
  300. package/src/hooks/usePolygonGesture.ts +162 -0
  301. package/src/hooks/useSelectionGesture.ts +293 -0
  302. package/src/hooks/useShapeGesture.ts +256 -0
  303. package/src/hooks/useViewportGesture.ts +337 -0
  304. package/src/index.tsx +51 -0
  305. package/src/renderers/ArrowRenderer.tsx +123 -0
  306. package/src/renderers/CircleRenderer.tsx +60 -0
  307. package/src/renderers/FreehandRenderer.tsx +33 -0
  308. package/src/renderers/InProgressRenderer.tsx +217 -0
  309. package/src/renderers/LineRenderer.tsx +34 -0
  310. package/src/renderers/MeasurementRenderer.tsx +179 -0
  311. package/src/renderers/ObjectRenderer.tsx +42 -0
  312. package/src/renderers/PolygonRenderer.tsx +66 -0
  313. package/src/renderers/RectRenderer.tsx +60 -0
  314. package/src/renderers/SelectedObjectRenderer.tsx +738 -0
  315. package/src/renderers/SelectionOverlay.tsx +170 -0
  316. package/src/store/useDrawingStore.ts +357 -0
  317. package/src/types.ts +186 -0
  318. package/src/utils/colors.ts +98 -0
  319. package/src/utils/coordinates.ts +75 -0
  320. package/src/utils/hitTesting.ts +242 -0
  321. package/src/utils/serialization.ts +45 -0
  322. package/src/utils/shapeDetection.ts +160 -0
  323. package/src/utils/smoothing.ts +84 -0
@@ -0,0 +1,163 @@
1
+ import React, { useState, useCallback } from "react";
2
+ import {
3
+ Modal,
4
+ View,
5
+ TextInput,
6
+ TouchableOpacity,
7
+ Text,
8
+ StyleSheet,
9
+ KeyboardAvoidingView,
10
+ Platform,
11
+ } from "react-native";
12
+
13
+ interface MeasurementEditModalProps {
14
+ visible: boolean;
15
+ initialValue: string;
16
+ initialUnit: string;
17
+ onSubmit: (value: string, unit: string) => void;
18
+ onCancel: () => void;
19
+ }
20
+
21
+ export const MeasurementEditModal = React.memo(function MeasurementEditModal({
22
+ visible,
23
+ initialValue,
24
+ initialUnit,
25
+ onSubmit,
26
+ onCancel,
27
+ }: MeasurementEditModalProps) {
28
+ const [value, setValue] = useState(initialValue);
29
+ const [unit, setUnit] = useState(initialUnit);
30
+
31
+ React.useEffect(() => {
32
+ if (visible) {
33
+ setValue(initialValue);
34
+ setUnit(initialUnit);
35
+ }
36
+ }, [visible, initialValue, initialUnit]);
37
+
38
+ const handleSubmit = useCallback(() => {
39
+ onSubmit(value || "0", unit || "cm");
40
+ }, [value, unit, onSubmit]);
41
+
42
+ return (
43
+ <Modal
44
+ visible={visible}
45
+ transparent
46
+ animationType="fade"
47
+ onRequestClose={onCancel}
48
+ >
49
+ <KeyboardAvoidingView
50
+ style={styles.overlay}
51
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
52
+ >
53
+ <View style={styles.dialog}>
54
+ <Text style={styles.title}>Measurement</Text>
55
+
56
+ <View style={styles.inputRow}>
57
+ <TextInput
58
+ style={[styles.input, styles.valueInput]}
59
+ value={value}
60
+ onChangeText={setValue}
61
+ placeholder="Value"
62
+ placeholderTextColor="#999"
63
+ keyboardType="decimal-pad"
64
+ autoFocus
65
+ />
66
+ <TextInput
67
+ style={[styles.input, styles.unitInput]}
68
+ value={unit}
69
+ onChangeText={setUnit}
70
+ placeholder="Unit"
71
+ placeholderTextColor="#999"
72
+ autoCapitalize="none"
73
+ autoCorrect={false}
74
+ />
75
+ </View>
76
+
77
+ <View style={styles.buttons}>
78
+ <TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
79
+ <Text style={styles.cancelText}>Cancel</Text>
80
+ </TouchableOpacity>
81
+ <TouchableOpacity
82
+ style={styles.submitButton}
83
+ onPress={handleSubmit}
84
+ >
85
+ <Text style={styles.submitText}>OK</Text>
86
+ </TouchableOpacity>
87
+ </View>
88
+ </View>
89
+ </KeyboardAvoidingView>
90
+ </Modal>
91
+ );
92
+ });
93
+
94
+ const styles = StyleSheet.create({
95
+ overlay: {
96
+ flex: 1,
97
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
98
+ justifyContent: "center",
99
+ alignItems: "center",
100
+ padding: 24,
101
+ },
102
+ dialog: {
103
+ backgroundColor: "#2C2C2E",
104
+ borderRadius: 14,
105
+ padding: 20,
106
+ width: "100%",
107
+ maxWidth: 320,
108
+ },
109
+ title: {
110
+ color: "#FFFFFF",
111
+ fontSize: 17,
112
+ fontWeight: "600",
113
+ marginBottom: 16,
114
+ textAlign: "center",
115
+ },
116
+ inputRow: {
117
+ flexDirection: "row",
118
+ gap: 10,
119
+ marginBottom: 16,
120
+ },
121
+ input: {
122
+ backgroundColor: "#1C1C1E",
123
+ borderRadius: 10,
124
+ padding: 12,
125
+ color: "#FFFFFF",
126
+ fontSize: 17,
127
+ },
128
+ valueInput: {
129
+ flex: 2,
130
+ textAlign: "center",
131
+ },
132
+ unitInput: {
133
+ flex: 1,
134
+ textAlign: "center",
135
+ },
136
+ buttons: {
137
+ flexDirection: "row",
138
+ gap: 12,
139
+ },
140
+ cancelButton: {
141
+ flex: 1,
142
+ paddingVertical: 12,
143
+ borderRadius: 10,
144
+ backgroundColor: "#3A3A3C",
145
+ alignItems: "center",
146
+ },
147
+ cancelText: {
148
+ color: "#FFFFFF",
149
+ fontSize: 16,
150
+ },
151
+ submitButton: {
152
+ flex: 1,
153
+ paddingVertical: 12,
154
+ borderRadius: 10,
155
+ backgroundColor: "#007AFF",
156
+ alignItems: "center",
157
+ },
158
+ submitText: {
159
+ color: "#FFFFFF",
160
+ fontSize: 16,
161
+ fontWeight: "600",
162
+ },
163
+ });
@@ -0,0 +1,275 @@
1
+ import React, { useRef } from "react";
2
+ import { StyleSheet, type GestureResponderEvent } from "react-native";
3
+ import {
4
+ Canvas,
5
+ Image,
6
+ Rect,
7
+ type SkImage,
8
+ } from "@shopify/react-native-skia";
9
+ import Animated, {
10
+ useAnimatedStyle,
11
+ withTiming,
12
+ type SharedValue,
13
+ } from "react-native-reanimated";
14
+
15
+ const MINIMAP_WIDTH = 100;
16
+ const MINIMAP_BORDER_RADIUS = 6;
17
+
18
+ interface MiniMapProps {
19
+ image: SkImage | null;
20
+ /** Image rect within the layout (fitted) */
21
+ imageRect: { x: number; y: number; width: number; height: number };
22
+ /** Viewport shared values */
23
+ scale: SharedValue<number>;
24
+ translateX: SharedValue<number>;
25
+ translateY: SharedValue<number>;
26
+ visible: boolean;
27
+ /** Clamp translate callback — keeps viewport in bounds */
28
+ onPanViewport?: (dtx: number, dty: number) => void;
29
+ }
30
+
31
+ export const MiniMap = React.memo(function MiniMap({
32
+ image,
33
+ imageRect,
34
+ scale: scaleSV,
35
+ translateX: txSV,
36
+ translateY: tySV,
37
+ visible,
38
+ onPanViewport,
39
+ }: MiniMapProps) {
40
+ const animatedStyle = useAnimatedStyle(() => ({
41
+ opacity: withTiming(visible && image && imageRect.width > 0 ? 1 : 0, {
42
+ duration: 250,
43
+ }),
44
+ }));
45
+
46
+ // Track last touch position for drag-to-pan
47
+ const lastTouchRef = useRef<{ x: number; y: number } | null>(null);
48
+
49
+ if (!image || imageRect.width === 0) return null;
50
+
51
+ const imgAspect = imageRect.width / imageRect.height;
52
+ const miniW = MINIMAP_WIDTH;
53
+ const miniH = miniW / imgAspect;
54
+
55
+ const handleTouchStart = (e: GestureResponderEvent) => {
56
+ const touch = e.nativeEvent;
57
+ lastTouchRef.current = { x: touch.locationX, y: touch.locationY };
58
+ };
59
+
60
+ const handleTouchMove = (e: GestureResponderEvent) => {
61
+ if (!lastTouchRef.current || !onPanViewport) return;
62
+ const touch = e.nativeEvent;
63
+ const dx = touch.locationX - lastTouchRef.current.x;
64
+ const dy = touch.locationY - lastTouchRef.current.y;
65
+ lastTouchRef.current = { x: touch.locationX, y: touch.locationY };
66
+
67
+ // Convert minimap drag to viewport translate delta
68
+ // Dragging right on minimap = viewing more right = translateX decreases
69
+ const s = scaleSV.value;
70
+ const dtx = -(dx * imageRect.width / miniW) * s;
71
+ const dty = -(dy * imageRect.height / miniH) * s;
72
+ onPanViewport(dtx, dty);
73
+ };
74
+
75
+ const handleTouchEnd = () => {
76
+ lastTouchRef.current = null;
77
+ };
78
+
79
+ return (
80
+ <Animated.View
81
+ style={[styles.container, { width: miniW + 4, height: miniH + 4 }, animatedStyle]}
82
+ pointerEvents={visible ? "auto" : "none"}
83
+ onStartShouldSetResponder={() => true}
84
+ onMoveShouldSetResponder={() => true}
85
+ onResponderGrant={handleTouchStart}
86
+ onResponderMove={handleTouchMove}
87
+ onResponderRelease={handleTouchEnd}
88
+ onResponderTerminate={handleTouchEnd}
89
+ >
90
+ <Canvas style={{ width: miniW, height: miniH }}>
91
+ {/* Thumbnail of the image */}
92
+ <Image
93
+ image={image}
94
+ x={0}
95
+ y={0}
96
+ width={miniW}
97
+ height={miniH}
98
+ fit="contain"
99
+ />
100
+
101
+ {/* Visible region rect */}
102
+ <ViewportRect
103
+ miniW={miniW}
104
+ miniH={miniH}
105
+ imageRect={imageRect}
106
+ scale={scaleSV}
107
+ translateX={txSV}
108
+ translateY={tySV}
109
+ />
110
+ </Canvas>
111
+ </Animated.View>
112
+ );
113
+ });
114
+
115
+ /**
116
+ * Renders a translucent rectangle showing the currently visible area.
117
+ *
118
+ * The viewport transform is: screen = canvas * scale + translate
119
+ * So the visible canvas region in image-relative coords is:
120
+ * visibleLeft = (imgOffX - tx/s ... but let's think in terms of the image area.
121
+ *
122
+ * Screen position of image top-left = imgOffX * scale + tx
123
+ * Screen position of image bottom-right = (imgOffX + imgW) * scale + tx
124
+ *
125
+ * The layout viewport is [0, 0, layoutW, layoutH].
126
+ * The image occupies [imgOffX, imgOffY, imgW, imgH] on screen at scale=1.
127
+ *
128
+ * Visible portion of image in normalized [0,1]:
129
+ * left = (imgOffX - (imgOffX * scale + tx)) / (imgW * scale)
130
+ * = (imgOffX * (1 - scale) - tx) / (imgW * scale)
131
+ * right = left + imgW / (imgW * scale) = left + 1/scale
132
+ *
133
+ * Actually simpler: the visible region on screen is the image area [imgOffX..imgOffX+imgW].
134
+ * A screen point sx maps to canvas point (sx - tx) / scale.
135
+ * So visible canvas x-range = [(imgOffX - tx)/scale, (imgOffX + imgW - tx)/scale].
136
+ * In image-relative coords (subtract imgOffX):
137
+ * left = (imgOffX - tx) / scale - imgOffX
138
+ * right = (imgOffX + imgW - tx) / scale - imgOffX
139
+ * Normalized [0..1]:
140
+ * nLeft = left / imgW
141
+ * nRight = right / imgW
142
+ */
143
+ function ViewportRect({
144
+ miniW,
145
+ miniH,
146
+ imageRect,
147
+ scale,
148
+ translateX,
149
+ translateY,
150
+ }: {
151
+ miniW: number;
152
+ miniH: number;
153
+ imageRect: { x: number; y: number; width: number; height: number };
154
+ scale: SharedValue<number>;
155
+ translateX: SharedValue<number>;
156
+ translateY: SharedValue<number>;
157
+ }) {
158
+ const [rectState, setRectState] = React.useState({
159
+ x: 0,
160
+ y: 0,
161
+ w: miniW,
162
+ h: miniH,
163
+ });
164
+
165
+ React.useEffect(() => {
166
+ const id = setInterval(() => {
167
+ const s = scale.value;
168
+ const tx = translateX.value;
169
+ const ty = translateY.value;
170
+ const { x: imgX, y: imgY, width: imgW, height: imgH } = imageRect;
171
+
172
+ // Canvas coords of visible region edges (the image display area on screen
173
+ // goes from imgX to imgX+imgW; map those screen coords to canvas coords)
174
+ const canvasLeft = (imgX - tx) / s;
175
+ const canvasTop = (imgY - ty) / s;
176
+ const canvasRight = (imgX + imgW - tx) / s;
177
+ const canvasBottom = (imgY + imgH - ty) / s;
178
+
179
+ // Image-relative
180
+ const relLeft = canvasLeft - imgX;
181
+ const relTop = canvasTop - imgY;
182
+ const relRight = canvasRight - imgX;
183
+ const relBottom = canvasBottom - imgY;
184
+
185
+ // Normalized [0..1]
186
+ const nLeft = Math.max(0, relLeft / imgW);
187
+ const nTop = Math.max(0, relTop / imgH);
188
+ const nRight = Math.min(1, relRight / imgW);
189
+ const nBottom = Math.min(1, relBottom / imgH);
190
+
191
+ const x = nLeft * miniW;
192
+ const y = nTop * miniH;
193
+ const w = (nRight - nLeft) * miniW;
194
+ const h = (nBottom - nTop) * miniH;
195
+
196
+ setRectState((prev) => {
197
+ if (
198
+ Math.abs(prev.x - x) < 0.5 &&
199
+ Math.abs(prev.y - y) < 0.5 &&
200
+ Math.abs(prev.w - w) < 0.5 &&
201
+ Math.abs(prev.h - h) < 0.5
202
+ ) {
203
+ return prev;
204
+ }
205
+ return { x, y, w, h };
206
+ });
207
+ }, 50);
208
+ return () => clearInterval(id);
209
+ }, [scale, translateX, translateY, imageRect, miniW, miniH]);
210
+
211
+ return (
212
+ <>
213
+ {/* Semi-transparent overlay outside visible rect */}
214
+ {/* Top band */}
215
+ <Rect
216
+ x={0}
217
+ y={0}
218
+ width={miniW}
219
+ height={Math.max(0, rectState.y)}
220
+ color="rgba(0, 0, 0, 0.55)"
221
+ />
222
+ {/* Bottom band */}
223
+ <Rect
224
+ x={0}
225
+ y={rectState.y + rectState.h}
226
+ width={miniW}
227
+ height={Math.max(0, miniH - rectState.y - rectState.h)}
228
+ color="rgba(0, 0, 0, 0.55)"
229
+ />
230
+ {/* Left band */}
231
+ <Rect
232
+ x={0}
233
+ y={rectState.y}
234
+ width={Math.max(0, rectState.x)}
235
+ height={rectState.h}
236
+ color="rgba(0, 0, 0, 0.55)"
237
+ />
238
+ {/* Right band */}
239
+ <Rect
240
+ x={rectState.x + rectState.w}
241
+ y={rectState.y}
242
+ width={Math.max(0, miniW - rectState.x - rectState.w)}
243
+ height={rectState.h}
244
+ color="rgba(0, 0, 0, 0.55)"
245
+ />
246
+ {/* Visible area border */}
247
+ <Rect
248
+ x={rectState.x + 0.5}
249
+ y={rectState.y + 0.5}
250
+ width={Math.max(0, rectState.w - 1)}
251
+ height={Math.max(0, rectState.h - 1)}
252
+ color="rgba(255, 255, 255, 0.6)"
253
+ style="stroke"
254
+ strokeWidth={1}
255
+ />
256
+ </>
257
+ );
258
+ }
259
+
260
+ const styles = StyleSheet.create({
261
+ container: {
262
+ position: "absolute",
263
+ bottom: 12,
264
+ right: 12,
265
+ borderRadius: MINIMAP_BORDER_RADIUS,
266
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
267
+ overflow: "hidden",
268
+ // Subtle shadow instead of a hard border
269
+ shadowColor: "#000",
270
+ shadowOffset: { width: 0, height: 2 },
271
+ shadowOpacity: 0.5,
272
+ shadowRadius: 6,
273
+ elevation: 8,
274
+ },
275
+ });
@@ -0,0 +1,198 @@
1
+ import React, { useCallback, useMemo } from "react";
2
+ import {
3
+ Text,
4
+ StyleSheet,
5
+ TouchableOpacity,
6
+ Platform,
7
+ type ViewStyle,
8
+ } from "react-native";
9
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
10
+ import Animated, {
11
+ useSharedValue,
12
+ useAnimatedStyle,
13
+ runOnJS,
14
+ } from "react-native-reanimated";
15
+ import type { SharedValue } from "react-native-reanimated";
16
+ import type { TextObject, Size } from "../types";
17
+ import { denormalize } from "../utils/coordinates";
18
+
19
+ interface TextAnnotationProps {
20
+ object: TextObject;
21
+ canvasSize: Size;
22
+ imageOffset: { x: number; y: number };
23
+ isSelected: boolean;
24
+ onSelect: (id: string) => void;
25
+ onMove: (id: string, dx: number, dy: number) => void;
26
+ onDoubleTap: (id: string) => void;
27
+ onDelete: (id: string) => void;
28
+ viewScale: SharedValue<number>;
29
+ viewTranslateX: SharedValue<number>;
30
+ viewTranslateY: SharedValue<number>;
31
+ }
32
+
33
+ const textCursorStyle = { cursor: "grab" } as unknown as ViewStyle;
34
+
35
+ export const TextAnnotation = React.memo(function TextAnnotation({
36
+ object,
37
+ canvasSize,
38
+ imageOffset,
39
+ isSelected,
40
+ onSelect,
41
+ onMove,
42
+ onDoubleTap,
43
+ onDelete,
44
+ viewScale,
45
+ viewTranslateX,
46
+ viewTranslateY,
47
+ }: TextAnnotationProps) {
48
+ const pos = useMemo(() => {
49
+ const p = denormalize(object.position, canvasSize);
50
+ return { x: p.x + imageOffset.x, y: p.y + imageOffset.y };
51
+ }, [object.position, canvasSize, imageOffset]);
52
+ const width = object.width * canvasSize.width;
53
+ const height = object.height * canvasSize.height;
54
+
55
+ const translateX = useSharedValue(0);
56
+ const translateY = useSharedValue(0);
57
+
58
+ const handleDragEnd = useCallback(
59
+ (dx: number, dy: number) => {
60
+ // dx/dy are already in canvas space (divided by scale in gesture)
61
+ const normalizedDx = canvasSize.width > 0 ? dx / canvasSize.width : 0;
62
+ const normalizedDy = canvasSize.height > 0 ? dy / canvasSize.height : 0;
63
+ onMove(object.id, normalizedDx, normalizedDy);
64
+ translateX.value = 0;
65
+ translateY.value = 0;
66
+ },
67
+ [object.id, canvasSize, onMove, translateX, translateY],
68
+ );
69
+
70
+ const panGesture = Gesture.Pan()
71
+ .onBegin(() => {
72
+ "worklet";
73
+ runOnJS(onSelect)(object.id);
74
+ })
75
+ .onUpdate((e) => {
76
+ "worklet";
77
+ // Translate in screen space but represent in canvas space
78
+ translateX.value = e.translationX / viewScale.value;
79
+ translateY.value = e.translationY / viewScale.value;
80
+ })
81
+ .onEnd(() => {
82
+ "worklet";
83
+ const dx = translateX.value;
84
+ const dy = translateY.value;
85
+ runOnJS(handleDragEnd)(dx, dy);
86
+ });
87
+
88
+ const tapGesture = Gesture.Tap().onEnd(() => {
89
+ "worklet";
90
+ runOnJS(onSelect)(object.id);
91
+ });
92
+
93
+ const doubleTapGesture = Gesture.Tap()
94
+ .numberOfTaps(2)
95
+ .onEnd(() => {
96
+ "worklet";
97
+ runOnJS(onDoubleTap)(object.id);
98
+ });
99
+
100
+ const composedGesture = Gesture.Exclusive(
101
+ doubleTapGesture,
102
+ tapGesture,
103
+ panGesture,
104
+ );
105
+
106
+ const animatedStyle = useAnimatedStyle(() => {
107
+ const s = viewScale.value;
108
+ const vtx = viewTranslateX.value;
109
+ const vty = viewTranslateY.value;
110
+ return {
111
+ transform: [
112
+ // Apply drag offset in canvas space, then scale to screen space
113
+ { translateX: (pos.x + translateX.value) * s + vtx - pos.x },
114
+ { translateY: (pos.y + translateY.value) * s + vty - pos.y },
115
+ { scale: s },
116
+ ],
117
+ };
118
+ });
119
+
120
+ const bgColor = object.backgroundColor
121
+ ? object.backgroundColor.replace(
122
+ /[\d.]+\)$/,
123
+ `${object.backgroundAlpha ?? 0.5})`,
124
+ )
125
+ : "transparent";
126
+
127
+ return (
128
+ <GestureDetector gesture={composedGesture}>
129
+ <Animated.View
130
+ style={[
131
+ styles.container,
132
+ Platform.OS === "web" ? textCursorStyle : undefined,
133
+ {
134
+ left: pos.x,
135
+ top: pos.y,
136
+ width,
137
+ height,
138
+ backgroundColor: bgColor,
139
+ borderColor: isSelected ? "rgba(0, 122, 255, 0.8)" : "transparent",
140
+ borderWidth: isSelected ? 1 : 0,
141
+ borderStyle: isSelected ? "dashed" : "solid",
142
+ },
143
+ animatedStyle,
144
+ ]}
145
+ >
146
+ <Text
147
+ style={[styles.text, { color: object.color }]}
148
+ numberOfLines={0}
149
+ adjustsFontSizeToFit
150
+ minimumFontScale={0.035}
151
+ >
152
+ {object.value}
153
+ </Text>
154
+
155
+ {isSelected && (
156
+ <TouchableOpacity
157
+ style={styles.deleteButton}
158
+ onPress={() => onDelete(object.id)}
159
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
160
+ >
161
+ <Text style={styles.deleteIcon}>✕</Text>
162
+ </TouchableOpacity>
163
+ )}
164
+ </Animated.View>
165
+ </GestureDetector>
166
+ );
167
+ });
168
+
169
+ const styles = StyleSheet.create({
170
+ container: {
171
+ position: "absolute",
172
+ justifyContent: "center",
173
+ alignItems: "center",
174
+ padding: 4,
175
+ minWidth: 40,
176
+ minHeight: 24,
177
+ },
178
+ text: {
179
+ fontSize: 18,
180
+ textAlign: "center",
181
+ },
182
+ deleteButton: {
183
+ position: "absolute",
184
+ top: -12,
185
+ left: -12,
186
+ width: 24,
187
+ height: 24,
188
+ borderRadius: 12,
189
+ backgroundColor: "rgba(255, 59, 48, 0.9)",
190
+ justifyContent: "center",
191
+ alignItems: "center",
192
+ },
193
+ deleteIcon: {
194
+ color: "#FFFFFF",
195
+ fontSize: 12,
196
+ fontWeight: "bold",
197
+ },
198
+ });