px-react-ui-components 1.0.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 (75) hide show
  1. package/.babelrc +3 -0
  2. package/README.md +126 -0
  3. package/dist/components/MyAlert/MyAlert.css +113 -0
  4. package/dist/components/MyAlert/MyAlert.js +109 -0
  5. package/dist/components/MyContainer/MyContainer.js +59 -0
  6. package/dist/components/MyContainer/MyContainer.module.css +110 -0
  7. package/dist/components/MyContainer/MyContainerBody.js +9 -0
  8. package/dist/components/MyContainer/MyContainerFooter.js +9 -0
  9. package/dist/components/MyContainer/MyContainerRight.js +10 -0
  10. package/dist/components/MyEditor/MyEditor.js +292 -0
  11. package/dist/components/MyEditor/MyEditor.scss +277 -0
  12. package/dist/components/MyFileUpload/MyFileUpload.js +288 -0
  13. package/dist/components/MyFileUpload/MyFileUpload.module.css +86 -0
  14. package/dist/components/MyImageCropper/MyImageCropper.js +95 -0
  15. package/dist/components/MyInput/MyInput.js +768 -0
  16. package/dist/components/MyInput/MyInput.module.css +420 -0
  17. package/dist/components/MyMaps/YandexMaps.js +162 -0
  18. package/dist/components/MyMenu/MenuItem.js +55 -0
  19. package/dist/components/MyMenu/MyMenu.module.css +102 -0
  20. package/dist/components/MyModal/MyModal.css +83 -0
  21. package/dist/components/MyModal/MyModal.js +71 -0
  22. package/dist/components/MyModal/MyModalBody.js +9 -0
  23. package/dist/components/MyModal/MyModalFooter.js +9 -0
  24. package/dist/components/MyNotFound/MyNotFound.css +22 -0
  25. package/dist/components/MyNotFound/MyNotFound.js +20 -0
  26. package/dist/components/MyScrollableCard/MyScrollableCard.js +74 -0
  27. package/dist/components/MyTable/MyTable.js +310 -0
  28. package/dist/components/MyTable/MyTable.module.css +350 -0
  29. package/dist/components/MyTable/MyTableBody.js +9 -0
  30. package/dist/components/MyTable/MyTableHead.js +9 -0
  31. package/dist/components/MyTabs/MyTabPane.js +17 -0
  32. package/dist/components/MyTabs/MyTabs.css +105 -0
  33. package/dist/components/MyTabs/MyTabs.js +66 -0
  34. package/dist/components/MyWaiting/MyWaiting.css +28 -0
  35. package/dist/components/MyWaiting/MyWaiting.js +27 -0
  36. package/dist/components/MyZoomImage/MyZoomImage.css +0 -0
  37. package/dist/components/MyZoomImage/MyZoomImage.js +108 -0
  38. package/dist/index.js +15 -0
  39. package/package.json +44 -0
  40. package/src/components/MyAlert/MyAlert.css +113 -0
  41. package/src/components/MyAlert/MyAlert.jsx +96 -0
  42. package/src/components/MyContainer/MyContainer.jsx +90 -0
  43. package/src/components/MyContainer/MyContainer.module.css +110 -0
  44. package/src/components/MyContainer/MyContainerBody.jsx +8 -0
  45. package/src/components/MyContainer/MyContainerFooter.jsx +8 -0
  46. package/src/components/MyContainer/MyContainerRight.jsx +11 -0
  47. package/src/components/MyEditor/MyEditor.jsx +252 -0
  48. package/src/components/MyEditor/MyEditor.scss +277 -0
  49. package/src/components/MyFileUpload/MyFileUpload.jsx +373 -0
  50. package/src/components/MyFileUpload/MyFileUpload.module.css +86 -0
  51. package/src/components/MyImageCropper/MyImageCropper.jsx +108 -0
  52. package/src/components/MyInput/MyInput.jsx +896 -0
  53. package/src/components/MyInput/MyInput.module.css +420 -0
  54. package/src/components/MyMaps/YandexMaps.jsx +186 -0
  55. package/src/components/MyMenu/MenuItem.jsx +62 -0
  56. package/src/components/MyMenu/MyMenu.module.css +102 -0
  57. package/src/components/MyModal/MyModal.css +83 -0
  58. package/src/components/MyModal/MyModal.jsx +78 -0
  59. package/src/components/MyModal/MyModalBody.jsx +8 -0
  60. package/src/components/MyModal/MyModalFooter.jsx +8 -0
  61. package/src/components/MyNotFound/MyNotFound.css +22 -0
  62. package/src/components/MyNotFound/MyNotFound.jsx +11 -0
  63. package/src/components/MyScrollableCard/MyScrollableCard.jsx +86 -0
  64. package/src/components/MyTable/MyTable.jsx +458 -0
  65. package/src/components/MyTable/MyTable.module.css +350 -0
  66. package/src/components/MyTable/MyTableBody.jsx +8 -0
  67. package/src/components/MyTable/MyTableHead.jsx +10 -0
  68. package/src/components/MyTabs/MyTabPane.jsx +9 -0
  69. package/src/components/MyTabs/MyTabs.css +105 -0
  70. package/src/components/MyTabs/MyTabs.jsx +63 -0
  71. package/src/components/MyWaiting/MyWaiting.css +28 -0
  72. package/src/components/MyWaiting/MyWaiting.jsx +27 -0
  73. package/src/components/MyZoomImage/MyZoomImage.css +0 -0
  74. package/src/components/MyZoomImage/MyZoomImage.jsx +139 -0
  75. package/src/index.js +15 -0
@@ -0,0 +1,373 @@
1
+ import React, { useEffect, useState, useRef } from "react";
2
+ import { PiCamera, PiFileArrowUpLight } from "react-icons/pi";
3
+ import Resizer from "react-image-file-resizer";
4
+ import Camera, { FACING_MODES, IMAGE_TYPES } from "react-html5-camera-photo";
5
+ import "react-html5-camera-photo/build/css/index.css";
6
+ import { useTranslation } from "../../context/TranslationContext";
7
+ import MyWaiting from "../MyWaiting/MyWaiting";
8
+ import { MyAlert, MyAlertType } from "../MyAlert/MyAlert";
9
+ import styles from "./MyFileUpload.module.css"
10
+ import MyModal from "../MyModal/MyModal";
11
+
12
+ export const AcceptType = {
13
+ ALL: "all",
14
+ FILE: "file",
15
+ IMAGE: "image",
16
+ MEDIA: "media",
17
+ PDF: "pdf",
18
+ IMAGEPDF: "imagepdf",
19
+ };
20
+
21
+ Object.freeze(MyAlertType);
22
+
23
+ export default function MyFileUpload({
24
+ multiple = false,
25
+ accept = AcceptType.ALL,
26
+ className = null,
27
+ camera = true,
28
+ maxSizeMB = 50,
29
+ onData,
30
+ }) {
31
+ const { t } = useTranslation();
32
+
33
+ const [loading, setLoading] = useState(false);
34
+ const [accepttypes, setAccepttypes] = useState(AcceptType.ALL);
35
+ const [acceptlabel, setAcceptlabel] = useState(AcceptType.ALL);
36
+ const [cameraopen, setCameraopen] = useState(false);
37
+ const [cameraopened, setCameraopened] = useState(false);
38
+ const [devices, setDevices] = useState([]);
39
+ const [selectedDeviceId, setSelectedDeviceId] = useState("");
40
+
41
+ const fileInputRef = useRef(null);
42
+
43
+ let type_files = ".pdf,.rar,.zip,.doc,.docx,.xls,.xlsx,.ppt,.pptx,msword,msexcel,vnd.ms-excel,vnd.openxmlformats-officedocument.spreadsheetml.sheet,vnd.openxmlformats-officedocument.wordprocessingml.document";
44
+ let type_image = ".jpg,.jpeg,.png";
45
+ let type_media = ".mp3,.mp4,.avi,.wav";
46
+
47
+ useEffect(() => {
48
+ switch (accept) {
49
+ case AcceptType.ALL:
50
+ setAccepttypes(
51
+ type_files + "," + type_image + "," + type_media
52
+ );
53
+ setAcceptlabel(
54
+ "PNG, JPG, PDF, RAR, ZIP, MP3, MP4, AVI, WAV veya Word-Excel Dosyaları"
55
+ );
56
+ break;
57
+ case AcceptType.IMAGE:
58
+ setAccepttypes(type_image);
59
+ setAcceptlabel(t("PNG veya JPG Dosyaları"));
60
+ break;
61
+ case AcceptType.MEDIA:
62
+ setAccepttypes(type_media);
63
+ setAcceptlabel(t("MP3, MP4, AVI veya WAV Dosyaları"));
64
+ break;
65
+ case AcceptType.FILE:
66
+ setAccepttypes(type_files + "," + type_image);
67
+ setAcceptlabel(
68
+ t("PDF, RAR, ZIP, PNG, JPG veya Word-Excel Dosyaları")
69
+ );
70
+ break;
71
+ case AcceptType.PDF:
72
+ setAccepttypes(".pdf");
73
+ setAcceptlabel(t("PDF Dosyaları"));
74
+ break;
75
+ case AcceptType.IMAGEPDF:
76
+ setAccepttypes(type_image + ",.pdf");
77
+ setAcceptlabel(t("PNG, JPG veya PDF Dosyaları"));
78
+ break;
79
+ }
80
+
81
+ navigator.mediaDevices.enumerateDevices().then((deviceInfos) => {
82
+ const videoDevices = deviceInfos.filter(
83
+ (device) => device.kind === "videoinput"
84
+ );
85
+ setDevices(videoDevices);
86
+ if (videoDevices.length > 0) {
87
+ setSelectedDeviceId(videoDevices[0].deviceId); // İlk kamerayı varsayılan olarak seç
88
+ }
89
+ });
90
+ }, []);
91
+
92
+ const responseData = (resdata, _error) => {
93
+ if (_error.length > 0) {
94
+ let message = _error.map((e, i) => {
95
+ return (
96
+ i +
97
+ 1 +
98
+ ".) <b><i>" +
99
+ e.filename +
100
+ "</i></b><br/>---- " +
101
+ e.message +
102
+ "<br/>"
103
+ );
104
+ });
105
+
106
+ MyAlert(
107
+ t("Aşağıdaki dosyalar eklenemedi!") +
108
+ "<br/><br/><div style='display: block;font-size:13px;width: 100%;text-align: left;'>" +
109
+ message +
110
+ "</div>",
111
+ MyAlertType.WARNING
112
+ );
113
+ }
114
+
115
+ if (onData && (
116
+ (Array.isArray(resdata) && resdata.length > 0) ||
117
+ (!Array.isArray(resdata) && resdata)
118
+ )
119
+ )
120
+ onData(resdata);
121
+
122
+ setLoading(false);
123
+ };
124
+
125
+ const getBase64 = (files, callback = null) => {
126
+ let response_files = [];
127
+ let _error = [];
128
+ let fileReaderCalc = 0;
129
+
130
+ setLoading(true);
131
+
132
+ for (let i = 0; i < files.length; i++) {
133
+ const file = files[i];
134
+ let filesize = parseInt(file.size) / 1024 / 1024; //MB
135
+
136
+ let file_ext = file.type.split("/");
137
+ file_ext = file_ext[file_ext.length - 1];
138
+
139
+ if (filesize > maxSizeMB || accepttypes.indexOf(file_ext) == -1) {
140
+ if (filesize > maxSizeMB) {
141
+ _error.push({
142
+ filename: file.name,
143
+ message: t("Boyutu Max. Dosya Boyutundan büyük olamaz!") + ` <b>${maxSizeMB}MB</b>`,
144
+ });
145
+ } else {
146
+ _error.push({
147
+ filename: file.name,
148
+ message: t("Dosya türü desteklenmiyor!") + ` <b>${file_ext}</b>`,
149
+ });
150
+ }
151
+
152
+ if (files.length == i + 1 && response_files.length == 0) {
153
+ responseData(response_files, _error);
154
+
155
+ if (callback) {
156
+ callback();
157
+ }
158
+ }
159
+
160
+ continue;
161
+ }
162
+
163
+ let extension_type = type_image.indexOf(file_ext) > -1 ? "image" : "file";
164
+
165
+ if (extension_type == "file") {
166
+ const reader = new FileReader();
167
+ reader.onload = function() {
168
+ let fileitem = {
169
+ base64: reader.result,
170
+ extension: file_ext,
171
+ extension_type: type_image.indexOf(file_ext) > -1 ? "image" : "file",
172
+ file: file,
173
+ };
174
+
175
+ if (!multiple) {
176
+ response_files = fileitem;
177
+ } else {
178
+ response_files.push(fileitem);
179
+ }
180
+
181
+ fileReaderCalc++;
182
+ if (files.length == fileReaderCalc) {
183
+ responseData(response_files, _error);
184
+
185
+ if (callback) {
186
+ callback();
187
+ }
188
+ }
189
+ };
190
+ reader.readAsDataURL(file);
191
+ } else {
192
+ let reader_param = {
193
+ file: file,
194
+ index: i,
195
+ ext: file_ext,
196
+ type_image: type_image,
197
+ };
198
+
199
+ Resizer.imageFileResizer(
200
+ file,
201
+ 2600,
202
+ 2600,
203
+ "JPEG",
204
+ 100,
205
+ 0,
206
+ (uri) => {
207
+ fileReaderCalc++;
208
+
209
+ let fileitem = {
210
+ base64: uri,
211
+ extension: reader_param.ext,
212
+ extension_type:
213
+ reader_param.type_image.indexOf(reader_param.ext) >
214
+ -1
215
+ ? "image"
216
+ : "file",
217
+ file: reader_param.file,
218
+ };
219
+
220
+ if (!multiple) {
221
+ response_files = fileitem;
222
+ } else {
223
+ response_files.push(fileitem);
224
+ }
225
+
226
+ if (files.length == fileReaderCalc) {
227
+ responseData(response_files, _error);
228
+
229
+ if (callback) {
230
+ callback();
231
+ }
232
+ }
233
+ },
234
+ "base64"
235
+ );
236
+ }
237
+ }
238
+
239
+ // responseData(response_files, _error);
240
+ };
241
+
242
+ useEffect(() => {
243
+ if (!cameraopen) {
244
+ setCameraopened(false);
245
+ }
246
+ }, [cameraopen]);
247
+
248
+ const handleFileInputChange = (e) => {
249
+ getBase64(e.target.files, () => {
250
+ if (fileInputRef.current) {
251
+ fileInputRef.current.value = '';
252
+ fileInputRef.current.files = null;
253
+ }
254
+ });
255
+ };
256
+
257
+ const handleDeviceChange = (event) => {
258
+ setSelectedDeviceId(event.target.value);
259
+ };
260
+ const handleTakePhoto = (dataUri) => {
261
+ let fileitem = {
262
+ base64: dataUri,
263
+ extension: "jpg",
264
+ extension_type: "image",
265
+ file: "",
266
+ };
267
+
268
+ responseData([fileitem], []);
269
+
270
+ setCameraopened(false);
271
+ setCameraopen(false);
272
+ };
273
+
274
+ const handleCameraError = () => {
275
+ // setCameraopened(false);
276
+ // setCameraopen(false);
277
+ };
278
+
279
+ const handleCameraStart = (stream) => {
280
+ setCameraopened(true);
281
+ };
282
+
283
+ const handleCameraStop = () => {
284
+ // setCameraopened(false);
285
+ };
286
+
287
+ return (
288
+ <>
289
+ <MyWaiting show={loading} message="" />
290
+ <div className={className}>
291
+ <div className={styles.myFileUploadContainer}>
292
+ <div className={styles.myFileUploadContainerItem}>
293
+ <div className={styles.myFileUploadContainerItemIcon}>
294
+ <PiFileArrowUpLight className={styles.Icon} />
295
+ <h2 className={styles.myFileUploadContainerItemIconText}>
296
+ {acceptlabel}
297
+ <br /> {t("En fazla")} {maxSizeMB} MB
298
+ </h2>
299
+ </div>
300
+ <div className={styles.myFileUploadContainerItemFile}>
301
+ <input
302
+ type="file"
303
+ hidden
304
+ ref={fileInputRef}
305
+ onChange={handleFileInputChange}
306
+ multiple={multiple}
307
+ accept={accepttypes}
308
+ />
309
+ <div
310
+ className={styles.myFileUploadButton}
311
+ onClick={() => fileInputRef.current.click()}
312
+ >
313
+ {t("Dosya Seç")}
314
+ </div>
315
+ </div>
316
+ </div>
317
+ {camera && (
318
+ <div className={styles.myFileUploadContainerItem}>
319
+ <div className={styles.myFileUploadContainerItemIcon}>
320
+ <PiCamera className={styles.Icon} />
321
+ <div className={styles.myFileUploadContainerItemIconText}>
322
+ <span>
323
+ {t("Kameradan fotoğraf çekebilirsin.")}
324
+ </span>
325
+ </div>
326
+ </div>
327
+ <div className={styles.myFileUploadContainerItemFile}>
328
+ <button
329
+ type="button"
330
+ className={styles.myFileUploadButton}
331
+ onClick={() => setCameraopen(true)}
332
+ >
333
+ {t("Fotoğraf Çek")}
334
+ </button>
335
+ </div>
336
+ </div>
337
+ )}
338
+ </div>
339
+ </div>
340
+ <MyModal show={cameraopen} onClose={() => setCameraopen(false)} title={t("Fotoğraf Çek")} closeOnEsc={false} closeOnBackdropClick={false} >
341
+ <div>
342
+ <Camera
343
+ videoConstraints={{
344
+ deviceId: selectedDeviceId
345
+ ? { exact: selectedDeviceId }
346
+ : undefined,
347
+ }}
348
+ onTakePhoto={(dataUri) => {
349
+ console.log(dataUri);
350
+ handleTakePhoto(dataUri);
351
+ }}
352
+ onCameraError={handleCameraError}
353
+ onCameraStart={(stream) => {
354
+ handleCameraStart(stream);
355
+ }}
356
+ onCameraStop={() => {
357
+ handleCameraStop();
358
+ }}
359
+ idealFacingMode={FACING_MODES.ENVIRONMENT}
360
+ idealResolution={{ width: 1024, height: 1024 }}
361
+ imageType={IMAGE_TYPES.JPG}
362
+ isMaxResolution={true}
363
+ isImageMirror={false}
364
+ isSilentMode={false}
365
+ isDisplayStartCameraError={true}
366
+ isFullscreen={false}
367
+ sizeFactor={1}
368
+ />
369
+ </div>
370
+ </MyModal>
371
+ </>
372
+ );
373
+ }
@@ -0,0 +1,86 @@
1
+ .myFileUploadContainer {
2
+ display: flex;
3
+ width: 100%;
4
+ flex-direction: row;
5
+ gap: 5px;
6
+ }
7
+
8
+ .myFileUploadContainer .myFileUploadContainerItem {
9
+ width: 100%;
10
+ padding: 5px;
11
+ background-color: #f0f0f0;
12
+ border-radius: 5px;
13
+ border: 1px dashed #ccc;
14
+ display: flex;
15
+ flex-direction: row;
16
+ justify-content: center;
17
+ align-items: center;
18
+ gap: 3px;
19
+ }
20
+
21
+ .myFileUploadContainer
22
+ .myFileUploadContainerItem
23
+ .myFileUploadContainerItemIcon {
24
+ display: flex;
25
+ width: 100%;
26
+
27
+ flex-direction: row;
28
+ justify-content: center;
29
+ align-items: center;
30
+ gap: 1px;
31
+ }
32
+
33
+ .myFileUploadContainer
34
+ .myFileUploadContainerItem
35
+ .myFileUploadContainerItemIcon
36
+ .Icon {
37
+ font-size: 35px;
38
+ color: #17305b;
39
+ }
40
+
41
+ .myFileUploadContainer
42
+ .myFileUploadContainerItem
43
+ .myFileUploadContainerItemIcon
44
+ .myFileUploadContainerItemIconText {
45
+ width: 100%;
46
+
47
+ text-align: center;
48
+ font-weight: normal;
49
+ color: #636363;
50
+ font-size: 12px;
51
+ line-height: 1.3;
52
+ }
53
+
54
+ .myFileUploadContainer
55
+ .myFileUploadContainerItem
56
+ .myFileUploadContainerItemFile {
57
+ display: flex;
58
+ flex-direction: row;
59
+ justify-content: center;
60
+ align-items: center;
61
+ }
62
+
63
+ .myFileUploadContainer
64
+ .myFileUploadContainerItem
65
+ .myFileUploadContainerItemFile
66
+ .myFileUploadButton {
67
+ display: flex;
68
+ width: 200px;
69
+ height: 35px;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ justify-content: center;
73
+ gap: 10px;
74
+ flex-shrink: 0;
75
+ background-color: #334f7f;
76
+ color: #fff;
77
+ border-radius: 15px;
78
+ cursor: pointer;
79
+ font-size: 13px;
80
+ }
81
+ .myFileUploadContainer
82
+ .myFileUploadContainerItem
83
+ .myFileUploadContainerItemFile
84
+ .myFileUploadButton:hover {
85
+ background-color: #2a436a;
86
+ }
@@ -0,0 +1,108 @@
1
+ import React, { useState } from "react";
2
+ import ReactCrop from "react-image-crop";
3
+ import "react-image-crop/dist/ReactCrop.css";
4
+ import MyImageZoom from "../MyZoomImage/MyZoomImage";
5
+
6
+ const MyImageCropper = ({ image, style = null, onChange = null }) => {
7
+ const [crop, setCrop] = useState({
8
+ x: 0,
9
+ y: 0,
10
+ width: 0,
11
+ height: 0,
12
+ aspect: 1,
13
+ });
14
+ // const [croppedImageUrl, setCroppedImageUrl] = useState(null);
15
+ const [imageRef, setImageRef] = useState(null);
16
+ const [zoom, setZoom] = useState({ scale: 1, positionX: 0, positionY: 0 }); // Zoom seviyesini saklamak için state
17
+ const [scaleFactor, setScaleFactor] = useState(1.5);
18
+
19
+ // Görüntü yüklendiğinde çağrılır
20
+ const handleImageLoad = (e) => {
21
+ setImageRef(e.currentTarget); // HTMLImageElement olarak kaydediyoruz
22
+ };
23
+
24
+ // Zoom değiştiğinde çağrılır
25
+ const handleZoomChange = (newZoom) => {
26
+ setZoom(newZoom);
27
+ setScaleFactor(newZoom.scale * 3);
28
+ };
29
+
30
+ // Kırpma tamamlandığında çağrılır
31
+ const onCropComplete = (newCrop) => {
32
+ if (imageRef && newCrop.width && newCrop.height) {
33
+ // Zoom oranını kullanarak yeni koordinatlar hesapla
34
+ const adjustedCrop = {
35
+ ...newCrop,
36
+ x: (newCrop.x - zoom.positionX) / zoom.scale,
37
+ y: (newCrop.y - zoom.positionY) / zoom.scale,
38
+ width: newCrop.width / zoom.scale,
39
+ height: newCrop.height / zoom.scale,
40
+ };
41
+
42
+ generateCroppedImage(imageRef, adjustedCrop);
43
+ }
44
+ };
45
+
46
+ // Kırpılmış görseli base64 formatında almak için
47
+ const generateCroppedImage = (image, crop) => {
48
+ if (!crop || !crop.width || !crop.height || crop.width === 0) {
49
+ console.warn("Geçersiz kırpma ölçüleri");
50
+ return;
51
+ }
52
+
53
+ const canvas = document.createElement("canvas");
54
+ const scaleX = image.naturalWidth / image.width;
55
+ const scaleY = image.naturalHeight / image.height;
56
+
57
+ // Kesim boyutlarını scaleFactor ile çarp
58
+ const outputWidth = crop.width * scaleFactor;
59
+ const outputHeight = crop.height * scaleFactor;
60
+
61
+ canvas.width = outputWidth;
62
+ canvas.height = outputHeight;
63
+ const ctx = canvas.getContext("2d");
64
+
65
+ ctx.drawImage(
66
+ image,
67
+ crop.x * scaleX,
68
+ crop.y * scaleY,
69
+ crop.width * scaleX,
70
+ crop.height * scaleY,
71
+ 0,
72
+ 0,
73
+ outputWidth,
74
+ outputHeight // Büyütülmüş boyutlar
75
+ );
76
+
77
+ const base64Image = canvas.toDataURL("image/jpeg");
78
+ // setCroppedImageUrl(base64Image);
79
+
80
+ if (onChange) {
81
+ onChange({ value: base64Image });
82
+ }
83
+ };
84
+
85
+ return (
86
+ <div style={style}>
87
+ {image && (
88
+ <ReactCrop
89
+ crop={crop}
90
+ onComplete={onCropComplete}
91
+ onChange={(newCrop) => setCrop(newCrop)}
92
+ style={style}
93
+ >
94
+ <MyImageZoom onZoomChange={handleZoomChange}>
95
+ <img
96
+ src={image}
97
+ alt="Crop preview"
98
+ onLoad={handleImageLoad}
99
+ className="rounded-e-md"
100
+ />
101
+ </MyImageZoom>
102
+ </ReactCrop>
103
+ )}
104
+ </div>
105
+ );
106
+ };
107
+
108
+ export default MyImageCropper;