react-native-expo-cropper 1.2.50 → 1.2.52

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.
@@ -29,7 +29,9 @@ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
29
29
  var CAMERA_PREVIEW_MAX_WIDTH = 500;
30
30
  function CustomCamera(_ref) {
31
31
  var onPhotoCaptured = _ref.onPhotoCaptured,
32
- onFrameCalculated = _ref.onFrameCalculated;
32
+ onFrameCalculated = _ref.onFrameCalculated,
33
+ _ref$instructionText = _ref.instructionText,
34
+ instructionText = _ref$instructionText === void 0 ? 'Place the tray inside the green box' : _ref$instructionText;
33
35
  var _useWindowDimensions = (0, _reactNative.useWindowDimensions)(),
34
36
  windowWidth = _useWindowDimensions.width;
35
37
  var cameraPreviewWidth = Math.min(windowWidth, CAMERA_PREVIEW_MAX_WIDTH);
@@ -318,7 +320,9 @@ function CustomCamera(_ref) {
318
320
  });
319
321
  console.log("Camera wrapper layout updated:", layout);
320
322
  }
321
- }, /*#__PURE__*/_react["default"].createElement(_expoCamera.CameraView, {
323
+ }, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
324
+ style: styles.cameraInstruction
325
+ }, instructionText), /*#__PURE__*/_react["default"].createElement(_expoCamera.CameraView, {
322
326
  style: styles.camera,
323
327
  facing: "back",
324
328
  ref: cameraRef,
@@ -397,6 +401,25 @@ var styles = _reactNative.StyleSheet.create({
397
401
  justifyContent: 'center',
398
402
  position: 'relative'
399
403
  },
404
+ cameraInstruction: {
405
+ position: 'absolute',
406
+ top: 8,
407
+ left: 12,
408
+ right: 12,
409
+ textAlign: 'center',
410
+ color: GLOW_WHITE,
411
+ fontSize: 14,
412
+ fontWeight: '600',
413
+ zIndex: 10,
414
+ textShadowColor: 'rgba(0, 0, 0, 0.7)',
415
+ textShadowOffset: {
416
+ width: 0,
417
+ height: 1
418
+ },
419
+ textShadowRadius: 2,
420
+ // Allow camera/scan frame to still receive touches
421
+ pointerEvents: 'none'
422
+ },
400
423
  camera: _objectSpread({}, _reactNative.StyleSheet.absoluteFillObject),
401
424
  scanFrame: {
402
425
  position: 'absolute',
@@ -45,7 +45,14 @@ var ImageCropper = function ImageCropper(_ref) {
45
45
  openCameraFirst = _ref.openCameraFirst,
46
46
  initialImage = _ref.initialImage,
47
47
  addheight = _ref.addheight,
48
- rotationLabel = _ref.rotationLabel;
48
+ rotationLabel = _ref.rotationLabel,
49
+ onCancel = _ref.onCancel,
50
+ _ref$confirmText = _ref.confirmText,
51
+ confirmText = _ref$confirmText === void 0 ? 'Confirm' : _ref$confirmText,
52
+ _ref$resetText = _ref.resetText,
53
+ resetText = _ref$resetText === void 0 ? 'Reset' : _ref$resetText,
54
+ _ref$cameraInstructio = _ref.cameraInstructionText,
55
+ cameraInstructionText = _ref$cameraInstructio === void 0 ? 'Place the tray inside the green box' : _ref$cameraInstructio;
49
56
  var _useWindowDimensions = (0, _reactNative.useWindowDimensions)(),
50
57
  windowWidth = _useWindowDimensions.width,
51
58
  windowHeight = _useWindowDimensions.height;
@@ -1223,6 +1230,7 @@ var ImageCropper = function ImageCropper(_ref) {
1223
1230
  return /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
1224
1231
  style: _ImageCropperStyles["default"].container
1225
1232
  }, showCustomCamera ? /*#__PURE__*/_react["default"].createElement(_CustomCamera["default"], {
1233
+ instructionText: cameraInstructionText,
1226
1234
  onPhotoCaptured: function onPhotoCaptured(uri, frameData) {
1227
1235
  // ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
1228
1236
  if (frameData && frameData.greenFrame) {
@@ -1388,7 +1396,26 @@ var ImageCropper = function ImageCropper(_ref) {
1388
1396
  paddingHorizontal: Math.round(12 * responsiveScale),
1389
1397
  gap: Math.round(8 * responsiveScale)
1390
1398
  }]
1391
- }, _reactNative.Platform.OS === 'android' && /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
1399
+ }, /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
1400
+ style: [_ImageCropperStyles["default"].rotationButton, {
1401
+ backgroundColor: 'transparent',
1402
+ borderWidth: 1,
1403
+ borderColor: 'white',
1404
+ width: Math.round(40 * responsiveScale),
1405
+ height: Math.round(40 * responsiveScale),
1406
+ borderRadius: Math.round(20 * responsiveScale),
1407
+ marginRight: Math.round(6 * responsiveScale)
1408
+ }],
1409
+ onPress: function onPress() {
1410
+ if (onCancel) {
1411
+ onCancel();
1412
+ }
1413
+ }
1414
+ }, /*#__PURE__*/_react["default"].createElement(_vectorIcons.Ionicons, {
1415
+ name: "close",
1416
+ size: Math.round(20 * responsiveScale),
1417
+ color: "white"
1418
+ })), _reactNative.Platform.OS === 'android' && /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
1392
1419
  style: [_ImageCropperStyles["default"].rotationButton, {
1393
1420
  width: Math.round(56 * responsiveScale),
1394
1421
  height: Math.round(48 * responsiveScale),
@@ -1418,7 +1445,7 @@ var ImageCropper = function ImageCropper(_ref) {
1418
1445
  style: [_ImageCropperStyles["default"].buttonText, {
1419
1446
  fontSize: Math.max(14, Math.round(18 * responsiveScale))
1420
1447
  }]
1421
- }, "Reset")), /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
1448
+ }, resetText)), /*#__PURE__*/_react["default"].createElement(_reactNative.TouchableOpacity, {
1422
1449
  onPress: /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
1423
1450
  var _cameraFrameData$curr4, actualImageWidth, actualImageHeight, isCoverMode, captured, layout, contentRect, displayedWidth, displayedHeight, scale, coverOffsetX, coverOffsetY, scaledWidth, scaledHeight, originalUri, cropMeta, imagePoints, minX, minY, maxX, maxY, cropX, cropY, cropEndX, cropEndY, cropWidth, cropHeight, bbox, polygon, ext, safeExt, name, _t2;
1424
1451
  return _regenerator().w(function (_context2) {
@@ -1594,7 +1621,7 @@ var ImageCropper = function ImageCropper(_ref) {
1594
1621
  style: [_ImageCropperStyles["default"].buttonText, {
1595
1622
  fontSize: Math.max(14, Math.round(18 * responsiveScale))
1596
1623
  }]
1597
- }, "Confirm"))), !showResult && !image && /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
1624
+ }, confirmText))), !showResult && !image && /*#__PURE__*/_react["default"].createElement(_reactNative.View, {
1598
1625
  style: _ImageCropperStyles["default"].centerButtonsContainer
1599
1626
  }, /*#__PURE__*/_react["default"].createElement(_reactNative.Text, {
1600
1627
  style: _ImageCropperStyles["default"].welcomeText
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-expo-cropper",
3
- "version": "1.2.50",
3
+ "version": "1.2.52",
4
4
  "description": "Recadrage polygonal d'images.",
5
5
  "main": "index.js",
6
6
  "author": "PCS AGRI",
@@ -16,7 +16,11 @@ import { Camera, CameraView } from 'expo-camera';
16
16
  // Max width for camera preview on large screens (tablets) so it doesn't stretch full width
17
17
  const CAMERA_PREVIEW_MAX_WIDTH = 500;
18
18
 
19
- export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
19
+ export default function CustomCamera({
20
+ onPhotoCaptured,
21
+ onFrameCalculated,
22
+ instructionText = 'Place the tray inside the green box',
23
+ }) {
20
24
  const { width: windowWidth } = useWindowDimensions();
21
25
  const cameraPreviewWidth = Math.min(windowWidth, CAMERA_PREVIEW_MAX_WIDTH);
22
26
  const [isReady, setIsReady] = useState(false);
@@ -250,6 +254,9 @@ export default function CustomCamera({ onPhotoCaptured, onFrameCalculated }) {
250
254
  console.log("Camera wrapper layout updated:", layout);
251
255
  }}
252
256
  >
257
+ <Text style={styles.cameraInstruction}>
258
+ {instructionText}
259
+ </Text>
253
260
  <CameraView
254
261
  style={styles.camera}
255
262
  facing="back"
@@ -345,6 +352,22 @@ const styles = StyleSheet.create({
345
352
  justifyContent: 'center',
346
353
  position: 'relative',
347
354
  },
355
+ cameraInstruction: {
356
+ position: 'absolute',
357
+ top: 8,
358
+ left: 12,
359
+ right: 12,
360
+ textAlign: 'center',
361
+ color: GLOW_WHITE,
362
+ fontSize: 14,
363
+ fontWeight: '600',
364
+ zIndex: 10,
365
+ textShadowColor: 'rgba(0, 0, 0, 0.7)',
366
+ textShadowOffset: { width: 0, height: 1 },
367
+ textShadowRadius: 2,
368
+ // Allow camera/scan frame to still receive touches
369
+ pointerEvents: 'none',
370
+ },
348
371
  camera: {
349
372
  ...StyleSheet.absoluteFillObject,
350
373
  },
@@ -13,7 +13,17 @@ const PRIMARY_GREEN = '#198754';
13
13
  // Base dimension for responsive scaling (e.g. ~375pt design width)
14
14
  const RESPONSIVE_BASE = 375;
15
15
 
16
- const ImageCropper = ({ onConfirm, openCameraFirst, initialImage, addheight, rotationLabel }) => {
16
+ const ImageCropper = ({
17
+ onConfirm,
18
+ openCameraFirst,
19
+ initialImage,
20
+ addheight,
21
+ rotationLabel,
22
+ onCancel,
23
+ confirmText = 'Confirm',
24
+ resetText = 'Reset',
25
+ cameraInstructionText = 'Place the tray inside the green box',
26
+ }) => {
17
27
  const { width: windowWidth, height: windowHeight } = useWindowDimensions();
18
28
 
19
29
  // Responsive scale: image and UI adapt to small (phone) and large (tablet) screens
@@ -1044,6 +1054,7 @@ const rotatePreviewImage = async (degrees) => {
1044
1054
 
1045
1055
  {showCustomCamera ? (
1046
1056
  <CustomCamera
1057
+ instructionText={cameraInstructionText}
1047
1058
  onPhotoCaptured={(uri, frameData) => {
1048
1059
  // ✅ CRITICAL FIX: Store green frame coordinates for coordinate conversion
1049
1060
  if (frameData && frameData.greenFrame) {
@@ -1192,15 +1203,40 @@ const rotatePreviewImage = async (degrees) => {
1192
1203
 
1193
1204
  {/* ✅ Buttons positioned as a responsive bottom bar (scale with screen size) */}
1194
1205
  {!showResult && image && (
1195
- <View style={[
1196
- styles.buttonContainerBelow,
1197
- {
1198
- paddingBottom: Math.max(insets.bottom, Math.round(16 * responsiveScale)),
1199
- paddingTop: Math.round(12 * responsiveScale),
1200
- paddingHorizontal: Math.round(12 * responsiveScale),
1201
- gap: Math.round(8 * responsiveScale),
1202
- },
1203
- ]}>
1206
+ <View
1207
+ style={[
1208
+ styles.buttonContainerBelow,
1209
+ {
1210
+ paddingBottom: Math.max(insets.bottom, Math.round(16 * responsiveScale)),
1211
+ paddingTop: Math.round(12 * responsiveScale),
1212
+ paddingHorizontal: Math.round(12 * responsiveScale),
1213
+ gap: Math.round(8 * responsiveScale),
1214
+ },
1215
+ ]}
1216
+ >
1217
+ {/* Close button: always visible, closes cropper */}
1218
+ <TouchableOpacity
1219
+ style={[
1220
+ styles.rotationButton,
1221
+ {
1222
+ backgroundColor: 'transparent',
1223
+ borderWidth: 1,
1224
+ borderColor: 'white',
1225
+ width: Math.round(40 * responsiveScale),
1226
+ height: Math.round(40 * responsiveScale),
1227
+ borderRadius: Math.round(20 * responsiveScale),
1228
+ marginRight: Math.round(6 * responsiveScale),
1229
+ },
1230
+ ]}
1231
+ onPress={() => {
1232
+ if (onCancel) {
1233
+ onCancel();
1234
+ }
1235
+ }}
1236
+ >
1237
+ <Ionicons name="close" size={Math.round(20 * responsiveScale)} color="white" />
1238
+ </TouchableOpacity>
1239
+
1204
1240
  {Platform.OS === 'android' && (
1205
1241
  <TouchableOpacity
1206
1242
  style={[
@@ -1234,7 +1270,14 @@ const rotatePreviewImage = async (degrees) => {
1234
1270
  ]}
1235
1271
  onPress={handleReset}
1236
1272
  >
1237
- <Text style={[styles.buttonText, { fontSize: Math.max(14, Math.round(18 * responsiveScale)) }]}>Reset</Text>
1273
+ <Text
1274
+ style={[
1275
+ styles.buttonText,
1276
+ { fontSize: Math.max(14, Math.round(18 * responsiveScale)) },
1277
+ ]}
1278
+ >
1279
+ {resetText}
1280
+ </Text>
1238
1281
  </TouchableOpacity>
1239
1282
 
1240
1283
  <TouchableOpacity
@@ -1377,7 +1420,14 @@ const rotatePreviewImage = async (degrees) => {
1377
1420
  },
1378
1421
  ]}
1379
1422
  >
1380
- <Text style={[styles.buttonText, { fontSize: Math.max(14, Math.round(18 * responsiveScale)) }]}>Confirm</Text>
1423
+ <Text
1424
+ style={[
1425
+ styles.buttonText,
1426
+ { fontSize: Math.max(14, Math.round(18 * responsiveScale)) },
1427
+ ]}
1428
+ >
1429
+ {confirmText}
1430
+ </Text>
1381
1431
  </TouchableOpacity>
1382
1432
  </View>
1383
1433
  )}