antd-img-crop 4.11.1 → 4.12.1

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.
package/README.md CHANGED
@@ -37,30 +37,29 @@ const Demo = () => (
37
37
 
38
38
  ## Props
39
39
 
40
- | Prop | Type | Default | Description |
41
- | -------------- | ---------- | -------------- | ----------------------------------------------------------------- |
42
- | quality | `number` | `0.4` | Cropped image quality, `0` to `1` |
43
- | fillColor | `string` | `'white'` | Fill color when cropped image smaller than canvas |
44
- | zoomSlider | `boolean` | `true` | Enable zoom adjustment for image |
45
- | rotationSlider | `boolean` | `false` | Enable rotation adjustment for image |
46
- | aspectSlider | `boolean` | `false` | Enable aspect adjustment for crop area |
47
- | showReset | `boolean` | `false` | show a reset button to reset zoom, rotation, aspect |
48
- | aspect | `number` | `1 / 1` | Aspect of crop area , `width / height` |
49
- | minZoom | `number` | `1` | Minimum zoom factor |
50
- | maxZoom | `number` | `3` | Maximum zoom factor |
51
- | cropShape | `string` | `'rect'` | Shape of crop area, `'rect'` or `'round'` |
52
- | showGrid | `boolean` | `false` | Show grid of crop area (third-lines) |
53
- | cropperProps | `object` | - | [react-easy-crop] props (\* existing props cannot be overridden) |
54
- | modalClassName | `string` | `''` | Provide your own classname for the Modal container |
55
- | modalTitle | `string` | `'Edit image'` | Title of modal |
56
- | modalWidth | `number` | `string` | Width of modal in pixels number or percentages |
57
- | modalOk | `string` | | Text of modal confirm button |
58
- | modalCancel | `string` | | Text of modal cancel button |
59
- | onModalOk | `function` | - | Call when click modal confirm button |
60
- | onModalCancel | `function` | - | Call when click modal mask, top right "x", or cancel button |
61
- | modalProps | `object` | | [Ant Design Modal] props (\* existing props cannot be overridden) |
62
- | beforeCrop | `function` | - | Call before modal open, if return `false`, it'll not open |
63
- | onUploadFail | `function` | - | Call when upload failed |
40
+ | Prop | Type | Default | Description |
41
+ | -------------- | ---------- | -------------- | ------------------------------------------------------------------- |
42
+ | quality | `number` | `0.4` | Cropped image quality, `0` to `1` |
43
+ | fillColor | `string` | `'white'` | Fill color when cropped image smaller than canvas |
44
+ | zoomSlider | `boolean` | `true` | Enable zoom adjustment for image |
45
+ | rotationSlider | `boolean` | `false` | Enable rotation adjustment for image |
46
+ | aspectSlider | `boolean` | `false` | Enable aspect adjustment for crop area |
47
+ | showReset | `boolean` | `false` | show a reset button to reset zoom, rotation, aspect |
48
+ | aspect | `number` | `1 / 1` | Aspect of crop area , `width / height` |
49
+ | minZoom | `number` | `1` | Minimum zoom factor |
50
+ | maxZoom | `number` | `3` | Maximum zoom factor |
51
+ | cropShape | `string` | `'rect'` | Shape of crop area, `'rect'` or `'round'` |
52
+ | showGrid | `boolean` | `false` | Show grid of crop area (third-lines) |
53
+ | cropperProps | `object` | - | [react-easy-crop] props (\* existing props cannot be overridden) |
54
+ | modalClassName | `string` | `''` | Provide your own classname for the Modal container |
55
+ | modalTitle | `string` | `'Edit image'` | Title of modal |
56
+ | modalWidth | `number` | `string` | Width of modal in pixels number or percentages |
57
+ | modalOk | `string` | | Text of modal confirm button |
58
+ | modalCancel | `string` | | Text of modal cancel button |
59
+ | onModalOk | `function` | - | Call when click modal confirm button |
60
+ | onModalCancel | `function` | - | Call when click modal mask, top right "x", or cancel button |
61
+ | modalProps | `object` | | [Ant Design Modal] props (\* existing props cannot be overridden) |
62
+ | beforeCrop | `function` | - | Call before modal open, if return `false` or reject, it'll not open |
64
63
 
65
64
  ## FAQ
66
65
 
package/README.zh-CN.md CHANGED
@@ -37,30 +37,29 @@ const Demo = () => (
37
37
 
38
38
  ## Props
39
39
 
40
- | 属性 | 类型 | 默认 | 说明 |
41
- | -------------- | -------------------- | ------------ | ----------------------------------------------------- |
42
- | quality | `number` | `0.4` | 裁切图片质量,`0` 到 `1` 之间 |
43
- | fillColor | `string` | `'white'` | 裁切图像小于画布时的填充颜色 |
44
- | zoomSlider | `boolean` | `true` | 启用图片缩放调整 |
45
- | rotationSlider | `boolean` | `false` | 启用图片旋转调整 |
46
- | aspectSlider | `boolean` | `false` | 启用裁切比率调整 |
47
- | showReset | `boolean` | `false` | 显示重置按钮,用以重置缩放、旋转、比率 |
48
- | aspect | `number` | `1 / 1` | 裁切区域宽高比,`width / height` |
49
- | minZoom | `number` | `1` | 最小缩放倍数 |
50
- | maxZoom | `number` | `3` | 最大缩放倍数 |
51
- | cropShape | `string` | `'rect'` | 裁切区域形状,`'rect'` 或 `'round'` |
52
- | showGrid | `boolean` | `false` | 显示裁切区域网格(九宫格) |
53
- | cropperProps | `object` | - | [react-easy-crop] 的 props(\* 已有 props 无法重写) |
54
- | modalClassName | `string` | `''` | 为 Modal 容器提供您自己的类名 |
55
- | modalTitle | `string` | `'编辑图片'` | 弹窗标题 |
56
- | modalWidth | `number` \| `string` | | 弹窗宽度,`px` 的数值或百分比 |
57
- | modalOk | `string` | | 弹窗确定按钮文字 |
58
- | modalCancel | `string` | | 弹窗取消按钮文字 |
59
- | onModalOK | `function` | - | 点击弹窗确定回调 |
60
- | onModalCancel | `function` | - | 点击弹窗遮罩层、右上角叉、取消的回调 |
61
- | modalProps | `object` | | [Ant Design Modal] 的 props(\* 已有 props 无法重写) |
62
- | beforeCrop | `function` | - | 弹窗打开前调用,若返回 `false`,弹框将不会打开 |
63
- | onUploadFail | `function` | - | 上传失败时的回调 |
40
+ | 属性 | 类型 | 默认 | 说明 |
41
+ | -------------- | -------------------- | ------------ | -------------------------------------------------------- |
42
+ | quality | `number` | `0.4` | 裁切图片质量,`0` 到 `1` 之间 |
43
+ | fillColor | `string` | `'white'` | 裁切图像小于画布时的填充颜色 |
44
+ | zoomSlider | `boolean` | `true` | 启用图片缩放调整 |
45
+ | rotationSlider | `boolean` | `false` | 启用图片旋转调整 |
46
+ | aspectSlider | `boolean` | `false` | 启用裁切比率调整 |
47
+ | showReset | `boolean` | `false` | 显示重置按钮,用以重置缩放、旋转、比率 |
48
+ | aspect | `number` | `1 / 1` | 裁切区域宽高比,`width / height` |
49
+ | minZoom | `number` | `1` | 最小缩放倍数 |
50
+ | maxZoom | `number` | `3` | 最大缩放倍数 |
51
+ | cropShape | `string` | `'rect'` | 裁切区域形状,`'rect'` 或 `'round'` |
52
+ | showGrid | `boolean` | `false` | 显示裁切区域网格(九宫格) |
53
+ | cropperProps | `object` | - | [react-easy-crop] 的 props(\* 已有 props 无法重写) |
54
+ | modalClassName | `string` | `''` | 为 Modal 容器提供您自己的类名 |
55
+ | modalTitle | `string` | `'编辑图片'` | 弹窗标题 |
56
+ | modalWidth | `number` \| `string` | | 弹窗宽度,`px` 的数值或百分比 |
57
+ | modalOk | `string` | | 弹窗确定按钮文字 |
58
+ | modalCancel | `string` | | 弹窗取消按钮文字 |
59
+ | onModalOK | `function` | - | 点击弹窗确定回调 |
60
+ | onModalCancel | `function` | - | 点击弹窗遮罩层、右上角叉、取消的回调 |
61
+ | modalProps | `object` | | [Ant Design Modal] 的 props(\* 已有 props 无法重写) |
62
+ | beforeCrop | `function` | - | 弹窗打开前调用,若返回 `false` 或 reject,弹框将不会打开 |
64
63
 
65
64
  ## FAQ
66
65
 
@@ -5,6 +5,7 @@ var jsxRuntime = require('react/jsx-runtime');
5
5
  var react = require('react');
6
6
  var antd = require('antd');
7
7
  var AntModal = require('antd/lib/modal');
8
+ var AntUpload = require('antd/lib/upload');
8
9
  var compareVersions = require('compare-versions');
9
10
  var Cropper = require('react-easy-crop');
10
11
  var AntButton = require('antd/lib/button');
@@ -22,7 +23,7 @@ const ASPECT_MAX = 2;
22
23
  const ASPECT_STEP = 0.01;
23
24
 
24
25
  const EasyCrop = react.forwardRef((props, ref) => {
25
- const { cropperRef, zoomSlider, rotationSlider, aspectSlider, showReset, image, aspect: ASPECT_INITIAL, minZoom, maxZoom, cropShape, showGrid, cropperProps, isCN, } = props;
26
+ const { cropperRef, zoomSlider, rotationSlider, aspectSlider, showReset, modalImage, aspect: ASPECT_INITIAL, minZoom, maxZoom, cropShape, showGrid, cropperProps, isCN, } = props;
26
27
  const [zoom, setZoom] = react.useState(ZOOM_INITIAL);
27
28
  const [rotation, setRotation] = react.useState(ROTATION_INITIAL);
28
29
  const [aspect, setAspect] = react.useState(ASPECT_INITIAL);
@@ -40,22 +41,21 @@ const EasyCrop = react.forwardRef((props, ref) => {
40
41
  cropPixelsRef.current = croppedAreaPixels;
41
42
  }, []);
42
43
  react.useImperativeHandle(ref, () => ({
43
- setZoom,
44
44
  rotation,
45
- setRotation,
46
45
  cropPixelsRef,
46
+ onReset,
47
47
  }));
48
- const wrapperClass = 'flex items-center w-3/5 mx-auto';
49
- const buttonClass = 'flex items-center justify-center w-8 h-8 bg-transparent border-0 font-[inherit] text-[18px] cursor-pointer disabled:opacity-20 disabled:cursor-default';
50
- const sliderClass = 'flex-1 mx-2';
51
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image: image, crop: crop,
48
+ const wrapperClass = '[display:flex] [align-items:center] [width:60%] [margin-inline:auto]';
49
+ const buttonClass = '[display:flex] [align-items:center] [justify-content:center] [height:32px] [width:32px] [background:transparent] [border:0] [font-family:inherit] [font-size:18px] [cursor:pointer] disabled:[opacity:20%] disabled:[cursor:default]';
50
+ const sliderClass = '[flex:1]';
51
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image: modalImage, crop: crop,
52
52
  //
53
53
  zoom: zoom, rotation: rotation, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, zoomWithScroll: zoomSlider,
54
54
  //
55
55
  cropShape: cropShape, showGrid: showGrid, onCropChange: onCropChange, onZoomChange: setZoom, onRotationChange: setRotation, onCropComplete: onCropComplete, classes: {
56
- containerClassName: `${PREFIX}-container !relative w-full h-[40vh] [&~section:first-of-type]:mt-4 [&~section:last-of-type]:mb-4`,
56
+ containerClassName: `${PREFIX}-container ![position:relative] [width:100%] [height:40vh] [&~section:first-of-type]:[margin-top:16px] [&~section:last-of-type]:[margin-bottom:16px]`,
57
57
  mediaClassName: `${PREFIX}-media`,
58
- } })), zoomSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-zoom ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom - ZOOM_STEP), disabled: zoom - ZOOM_STEP < minZoom }, { children: "\uFF0D" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: minZoom, max: maxZoom, step: ZOOM_STEP, value: zoom, onChange: setZoom }), jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom + ZOOM_STEP), disabled: zoom + ZOOM_STEP > maxZoom }, { children: "\uFF0B" }))] }))), rotationSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-rotation ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: `${buttonClass} !text-[16px]`, onClick: () => setRotation(rotation - ROTATION_STEP), disabled: rotation === ROTATION_MIN }, { children: "\u21BA" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: ROTATION_MIN, max: ROTATION_MAX, step: ROTATION_STEP, value: rotation, onChange: setRotation }), jsxRuntime.jsx("button", Object.assign({ className: `${buttonClass} !text-[16px]`, onClick: () => setRotation(rotation + ROTATION_STEP), disabled: rotation === ROTATION_MAX }, { children: "\u21BB" }))] }))), aspectSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-aspect ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect - ASPECT_STEP), disabled: aspect - ASPECT_STEP < ASPECT_MIN }, { children: "\u2195\uFE0F" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: ASPECT_MIN, max: ASPECT_MAX, step: ASPECT_STEP, value: aspect, onChange: setAspect }), jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect + ASPECT_STEP), disabled: aspect + ASPECT_STEP > ASPECT_MAX }, { children: "\u2194\uFE0F" }))] }))), showReset && (zoomSlider || rotationSlider || aspectSlider) && (jsxRuntime.jsx(AntButton, Object.assign({ className: "absolute bottom-[20px]", style: isResetActive ? {} : { opacity: 0.3, pointerEvents: 'none' }, onClick: onReset }, { children: isCN ? '重置' : 'Reset' })))] }));
58
+ } })), zoomSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-zoom ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom - ZOOM_STEP), disabled: zoom - ZOOM_STEP < minZoom }, { children: "\uFF0D" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: minZoom, max: maxZoom, step: ZOOM_STEP, value: zoom, onChange: setZoom }), jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom + ZOOM_STEP), disabled: zoom + ZOOM_STEP > maxZoom }, { children: "\uFF0B" }))] }))), rotationSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-rotation ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: `${buttonClass} [font-size:16px]`, onClick: () => setRotation(rotation - ROTATION_STEP), disabled: rotation === ROTATION_MIN }, { children: "\u21BA" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: ROTATION_MIN, max: ROTATION_MAX, step: ROTATION_STEP, value: rotation, onChange: setRotation }), jsxRuntime.jsx("button", Object.assign({ className: `${buttonClass} [font-size:16px]`, onClick: () => setRotation(rotation + ROTATION_STEP), disabled: rotation === ROTATION_MAX }, { children: "\u21BB" }))] }))), aspectSlider && (jsxRuntime.jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-aspect ${wrapperClass}` }, { children: [jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect - ASPECT_STEP), disabled: aspect - ASPECT_STEP < ASPECT_MIN }, { children: "\u2195\uFE0F" })), jsxRuntime.jsx(AntSlider, { className: sliderClass, min: ASPECT_MIN, max: ASPECT_MAX, step: ASPECT_STEP, value: aspect, onChange: setAspect }), jsxRuntime.jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect + ASPECT_STEP), disabled: aspect + ASPECT_STEP > ASPECT_MAX }, { children: "\u2194\uFE0F" }))] }))), showReset && (zoomSlider || rotationSlider || aspectSlider) && (jsxRuntime.jsx(AntButton, Object.assign({ className: "[position:absolute] [bottom:20px]", style: isResetActive ? {} : { opacity: 0.3, pointerEvents: 'none' }, onClick: onReset }, { children: isCN ? '重置' : 'Reset' })))] }));
59
59
  });
60
60
  var EasyCrop$1 = react.memo(EasyCrop);
61
61
 
@@ -86,7 +86,7 @@ function styleInject(css, ref) {
86
86
  }
87
87
  }
88
88
 
89
- var css_248z = ".container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.absolute{position:absolute}.\\!relative{position:relative!important}.bottom-\\[20px\\]{bottom:20px}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.flex{display:flex}.grid{display:grid}.h-8{height:2rem}.h-\\[40vh\\]{height:40vh}.w-3\\/5{width:60%}.w-8{width:2rem}.w-full{width:100%}.flex-1{flex:1 1 0%}.cursor-pointer{cursor:pointer}.items-center{align-items:center}.justify-center{justify-content:center}.border-0{border-width:0}.bg-transparent{background-color:transparent}.font-\\[inherit\\]{font-family:inherit}.\\!text-\\[16px\\]{font-size:16px!important}.text-\\[18px\\]{font-size:18px}.disabled\\:cursor-default:disabled{cursor:default}.disabled\\:opacity-20:disabled{opacity:.2}.\\[\\&\\~section\\:first-of-type\\]\\:mt-4~section:first-of-type{margin-top:1rem}.\\[\\&\\~section\\:last-of-type\\]\\:mb-4~section:last-of-type{margin-bottom:1rem}";
89
+ var css_248z = ".container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.grid{display:grid}.\\!\\[position\\:relative\\]{position:relative!important}.\\[align-items\\:center\\]{align-items:center}.\\[background\\:transparent\\]{background:transparent}.\\[border\\:0\\]{border:0}.\\[bottom\\:20px\\]{bottom:20px}.\\[cursor\\:pointer\\]{cursor:pointer}.\\[display\\:flex\\]{display:flex}.\\[flex\\:1\\]{flex:1}.\\[font-family\\:inherit\\]{font-family:inherit}.\\[font-size\\:16px\\]{font-size:16px}.\\[font-size\\:18px\\]{font-size:18px}.\\[height\\:32px\\]{height:32px}.\\[height\\:40vh\\]{height:40vh}.\\[justify-content\\:center\\]{justify-content:center}.\\[margin-inline\\:auto\\]{margin-inline:auto}.\\[position\\:absolute\\]{position:absolute}.\\[width\\:100\\%\\]{width:100%}.\\[width\\:32px\\]{width:32px}.\\[width\\:60\\%\\]{width:60%}.disabled\\:\\[cursor\\:default\\]:disabled{cursor:default}.disabled\\:\\[opacity\\:20\\%\\]:disabled{opacity:20%}.\\[\\&\\~section\\:first-of-type\\]\\:\\[margin-top\\:16px\\]~section:first-of-type{margin-top:16px}.\\[\\&\\~section\\:last-of-type\\]\\:\\[margin-bottom\\:16px\\]~section:last-of-type{margin-bottom:16px}";
90
90
  styleInject(css_248z);
91
91
 
92
92
  const openKey = compareVersions.compareVersions(antd.version, '4.23.0') === -1 ? 'visible' : 'open';
@@ -106,96 +106,36 @@ const ImgCrop = react.forwardRef((props, cropperRef) => {
106
106
  // @ts-ignore
107
107
  cropShape: CROP_SHAPE = 'rect',
108
108
  // @ts-ignore
109
- showGrid: SHOW_GRID = false, cropperProps, modalClassName, modalTitle, modalWidth, modalOk, modalCancel, showReset = false, onModalOk, onModalCancel, modalProps, beforeCrop, onUploadFail, children, } = props;
109
+ showGrid: SHOW_GRID = false, cropperProps, modalClassName, modalTitle, modalWidth, modalOk, modalCancel, showReset = false, onModalOk, onModalCancel, modalProps, beforeCrop, children, } = props;
110
+ /**
111
+ * init
112
+ */
110
113
  const zoomSlider = deprecate(props, 'zoom', 'zoomSlider') || true;
111
114
  const rotationSlider = deprecate(props, 'rotate', 'rotationSlider') || false;
112
115
  const cropShape = deprecate(props, 'shape', 'cropShape') || 'rect';
113
116
  const showGrid = deprecate(props, 'grid', 'showGrid') || false;
117
+ if ('onUploadFail' in props) {
118
+ console.error(`\`onUploadFail\` is removed, because the only way it is called, is when the file is rejected by beforeUpload`);
119
+ }
114
120
  deprecate(props, 'modalMaskTransitionName', 'modalProps.maskTransitionName');
115
121
  deprecate(props, 'modalTransitionName', 'modalProps.transitionName');
116
122
  const cb = react.useRef({});
117
123
  cb.current.onModalOk = onModalOk;
118
124
  cb.current.onModalCancel = onModalCancel;
119
125
  cb.current.beforeCrop = beforeCrop;
120
- cb.current.onUploadFail = onUploadFail;
121
- /**
122
- * upload
123
- */
124
- const [image, setImage] = react.useState('');
125
- const fileRef = react.useRef({});
126
- const beforeUploadRef = react.useRef();
127
- const resolveRef = react.useRef(() => { });
128
- const rejectRef = react.useRef(() => { });
129
- const uploadComponent = react.useMemo(() => {
130
- const upload = Array.isArray(children) ? children[0] : children;
131
- const _a = upload.props, { beforeUpload, accept } = _a, restUploadProps = tslib.__rest(_a, ["beforeUpload", "accept"]);
132
- beforeUploadRef.current = beforeUpload;
133
- return Object.assign(Object.assign({}, upload), { props: Object.assign(Object.assign({}, restUploadProps), { accept: accept || 'image/*', beforeUpload: (file, fileList) => {
134
- return new Promise((resolve, reject) => tslib.__awaiter(void 0, void 0, void 0, function* () {
135
- if (typeof cb.current.beforeCrop === 'function') {
136
- const shouldCrop = yield cb.current.beforeCrop(file, fileList);
137
- if (!shouldCrop) {
138
- return reject();
139
- }
140
- }
141
- fileRef.current = file;
142
- resolveRef.current = (newFile) => {
143
- var _a, _b;
144
- (_b = (_a = cb.current).onModalOk) === null || _b === void 0 ? void 0 : _b.call(_a, newFile);
145
- resolve(newFile);
146
- };
147
- rejectRef.current = (uploadErr) => {
148
- var _a, _b;
149
- (_b = (_a = cb.current).onUploadFail) === null || _b === void 0 ? void 0 : _b.call(_a, uploadErr);
150
- reject();
151
- };
152
- const reader = new FileReader();
153
- reader.addEventListener('load', () => {
154
- if (typeof reader.result === 'string') {
155
- setImage(reader.result);
156
- }
157
- });
158
- reader.readAsDataURL(file);
159
- }));
160
- } }) });
161
- }, [children]);
162
126
  /**
163
127
  * crop
164
128
  */
165
- const easyCropRef = react.useRef({});
166
- /**
167
- * modal
168
- */
169
- const modalBaseProps = react.useMemo(() => {
170
- const obj = {};
171
- if (modalWidth !== undefined)
172
- obj.width = modalWidth;
173
- if (modalOk !== undefined)
174
- obj.okText = modalOk;
175
- if (modalCancel !== undefined)
176
- obj.cancelText = modalCancel;
177
- return obj;
178
- }, [modalCancel, modalOk, modalWidth]);
179
- const onClose = () => {
180
- setImage('');
181
- easyCropRef.current.setZoom(ZOOM_INITIAL);
182
- easyCropRef.current.setRotation(ROTATION_INITIAL);
183
- };
184
- const onCancel = react.useCallback(() => {
185
- var _a, _b;
186
- (_b = (_a = cb.current).onModalCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
187
- onClose();
188
- }, []);
189
- const onOk = react.useCallback((event) => tslib.__awaiter(void 0, void 0, void 0, function* () {
129
+ const easyCropRef = react.useRef(null);
130
+ const getCropCanvas = react.useCallback((target) => {
190
131
  var _a;
191
- onClose();
192
132
  const canvas = document.createElement('canvas');
193
133
  const ctx = canvas.getContext('2d');
194
- const target = event.target;
195
134
  const context = ((_a = target === null || target === void 0 ? void 0 : target.getRootNode) === null || _a === void 0 ? void 0 : _a.call(target)) || document;
196
135
  const imgSource = context.querySelector(`.${PREFIX}-media`);
197
136
  const { width: cropWidth, height: cropHeight, x: cropX, y: cropY, } = easyCropRef.current.cropPixelsRef.current;
198
- if (rotationSlider && easyCropRef.current.rotation !== ROTATION_INITIAL) {
137
+ if (rotationSlider &&
138
+ easyCropRef.current.rotation !== ROTATION_INITIAL) {
199
139
  const { naturalWidth: imgWidth, naturalHeight: imgHeight } = imgSource;
200
140
  const angle = easyCropRef.current.rotation * (Math.PI / 180);
201
141
  // get container for rotated image
@@ -230,40 +170,97 @@ const ImgCrop = react.forwardRef((props, cropperRef) => {
230
170
  ctx.fillRect(0, 0, cropWidth, cropHeight);
231
171
  ctx.drawImage(imgSource, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
232
172
  }
233
- // get the new image
234
- const { type, name, uid } = fileRef.current;
235
- canvas.toBlob((blob) => tslib.__awaiter(void 0, void 0, void 0, function* () {
236
- const newFile = new File([blob], name, { type });
237
- Object.assign(newFile, { uid });
238
- if (typeof beforeUploadRef.current !== 'function') {
239
- resolveRef.current(newFile);
240
- return;
241
- }
242
- // https://github.com/ant-design/ant-design/blob/master/components/upload/Upload.tsx
243
- // https://ant.design/components/upload-cn#api
244
- try {
245
- const rcFile = newFile;
246
- const result = yield beforeUploadRef.current(rcFile, [rcFile]);
247
- if (result === true) {
248
- resolveRef.current(newFile); // true
249
- }
250
- else if (result === false) {
251
- rejectRef.current(new Error('beforeUpload → false')); // false
252
- }
253
- else {
254
- resolveRef.current(result); // File, Upload.LIST_IGNORE
173
+ return canvas;
174
+ }, [fillColor, rotationSlider]);
175
+ /**
176
+ * upload
177
+ */
178
+ const [modalImage, setModalImage] = react.useState('');
179
+ const onCancel = react.useRef();
180
+ const onOk = react.useRef();
181
+ const uploadComponent = react.useMemo(() => {
182
+ const upload = Array.isArray(children) ? children[0] : children;
183
+ const _a = upload.props, { beforeUpload, accept } = _a, restUploadProps = tslib.__rest(_a, ["beforeUpload", "accept"]);
184
+ const innerBeforeUpload = (file, fileList) => {
185
+ return new Promise((resolve) => tslib.__awaiter(void 0, void 0, void 0, function* () {
186
+ if (typeof cb.current.beforeCrop === 'function') {
187
+ try {
188
+ const result = yield cb.current.beforeCrop(file, fileList);
189
+ if (result !== true) {
190
+ return resolve(result);
191
+ }
192
+ }
193
+ catch (err) {
194
+ return resolve(err);
195
+ }
255
196
  }
256
- }
257
- catch (err) {
258
- rejectRef.current(new Error('beforeUpload → reject')); // reject
259
- }
260
- }), type, quality);
261
- }), [fillColor, quality, rotationSlider]);
197
+ // get file result
198
+ const reader = new FileReader();
199
+ reader.addEventListener('load', () => {
200
+ if (typeof reader.result === 'string') {
201
+ setModalImage(reader.result); // open modal
202
+ }
203
+ });
204
+ reader.readAsDataURL(file);
205
+ // on modal cancel
206
+ onCancel.current = () => {
207
+ var _a, _b;
208
+ setModalImage('');
209
+ easyCropRef.current.onReset();
210
+ resolve(AntUpload.LIST_IGNORE);
211
+ (_b = (_a = cb.current).onModalCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
212
+ };
213
+ // on modal confirm
214
+ onOk.current = (event) => tslib.__awaiter(void 0, void 0, void 0, function* () {
215
+ setModalImage('');
216
+ easyCropRef.current.onReset();
217
+ const canvas = getCropCanvas(event.target);
218
+ const { type, name, uid } = file;
219
+ canvas.toBlob((blob) => tslib.__awaiter(void 0, void 0, void 0, function* () {
220
+ var _a, _b, _c, _d, _e, _f;
221
+ const newFile = new File([blob], name, { type });
222
+ Object.assign(newFile, { uid });
223
+ if (typeof beforeUpload !== 'function') {
224
+ resolve(newFile);
225
+ (_b = (_a = cb.current).onModalOk) === null || _b === void 0 ? void 0 : _b.call(_a, newFile);
226
+ return;
227
+ }
228
+ try {
229
+ // https://github.com/ant-design/ant-design/blob/master/components/upload/Upload.tsx#L128-L148
230
+ // https://ant.design/components/upload-cn#api
231
+ const result = yield beforeUpload(newFile, [newFile]);
232
+ const value = result === true ? newFile : result;
233
+ resolve(value);
234
+ (_d = (_c = cb.current).onModalOk) === null || _d === void 0 ? void 0 : _d.call(_c, value);
235
+ }
236
+ catch (err) {
237
+ resolve(err);
238
+ (_f = (_e = cb.current).onModalOk) === null || _f === void 0 ? void 0 : _f.call(_e, err);
239
+ }
240
+ }), type, quality);
241
+ });
242
+ }));
243
+ };
244
+ return Object.assign(Object.assign({}, upload), { props: Object.assign(Object.assign({}, restUploadProps), { accept: accept || 'image/*', beforeUpload: innerBeforeUpload }) });
245
+ }, [children, getCropCanvas, quality]);
246
+ /**
247
+ * modal
248
+ */
249
+ const modalBaseProps = react.useMemo(() => {
250
+ const obj = {};
251
+ if (modalWidth !== undefined)
252
+ obj.width = modalWidth;
253
+ if (modalOk !== undefined)
254
+ obj.okText = modalOk;
255
+ if (modalCancel !== undefined)
256
+ obj.cancelText = modalCancel;
257
+ return obj;
258
+ }, [modalCancel, modalOk, modalWidth]);
262
259
  const wrapClassName = `${PREFIX}-modal${modalClassName ? ` ${modalClassName}` : ''}`;
263
260
  const lang = typeof window === 'undefined' ? '' : window.navigator.language;
264
261
  const isCN = lang === 'zh-CN';
265
262
  const title = modalTitle || (isCN ? '编辑图片' : 'Edit image');
266
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [uploadComponent, image && (jsxRuntime.jsx(AntModal, Object.assign({}, modalProps, modalBaseProps, { [openKey]: true }, { title: title, onOk: onOk, onCancel: onCancel, wrapClassName: wrapClassName, maskClosable: false, destroyOnClose: true }, { children: jsxRuntime.jsx(EasyCrop$1, { ref: easyCropRef, cropperRef: cropperRef, zoomSlider: zoomSlider, rotationSlider: rotationSlider, aspectSlider: aspectSlider, showReset: showReset, image: image, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, cropShape: cropShape, showGrid: showGrid, cropperProps: cropperProps, isCN: isCN }) })))] }));
263
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [uploadComponent, modalImage && (jsxRuntime.jsx(AntModal, Object.assign({}, modalProps, modalBaseProps, { [openKey]: true }, { title: title, onCancel: onCancel.current, onOk: onOk.current, wrapClassName: wrapClassName, maskClosable: false, destroyOnClose: true }, { children: jsxRuntime.jsx(EasyCrop$1, { ref: easyCropRef, cropperRef: cropperRef, zoomSlider: zoomSlider, rotationSlider: rotationSlider, aspectSlider: aspectSlider, showReset: showReset, modalImage: modalImage, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, cropShape: cropShape, showGrid: showGrid, cropperProps: cropperProps, isCN: isCN }) })))] }));
267
264
  });
268
265
 
269
266
  module.exports = ImgCrop;
@@ -1,8 +1,9 @@
1
1
  import * as react from 'react';
2
2
  import Cropper, { CropperProps } from 'react-easy-crop';
3
- import { ModalProps } from 'antd';
4
- import { RcFile } from 'antd/es/upload/interface';
3
+ import { ModalProps, UploadProps } from 'antd';
5
4
 
5
+ type BeforeUpload = Exclude<UploadProps['beforeUpload'], undefined>;
6
+ type BeforeUploadReturnType = ReturnType<BeforeUpload>;
6
7
  type ImgCropProps = {
7
8
  quality?: number;
8
9
  fillColor?: string;
@@ -21,11 +22,10 @@ type ImgCropProps = {
21
22
  modalWidth?: number | string;
22
23
  modalOk?: string;
23
24
  modalCancel?: string;
24
- onModalOk?: (file: void | boolean | string | Blob | File) => void;
25
+ onModalOk?: (value: BeforeUploadReturnType) => void;
25
26
  onModalCancel?: () => void;
26
27
  modalProps?: Omit<ModalProps, 'className' | 'title' | 'width' | 'okText' | 'cancelText' | 'onOk' | 'onCancel' | 'open' | 'visible' | 'wrapClassName' | 'maskClosable' | 'destroyOnClose'>;
27
- beforeCrop?: (file: RcFile, fileList: RcFile[]) => boolean | Promise<boolean>;
28
- onUploadFail?: (err: Error) => void;
28
+ beforeCrop?: BeforeUpload;
29
29
  children: JSX.Element;
30
30
  };
31
31
 
@@ -3,6 +3,7 @@ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
  import { forwardRef, useState, useRef, useCallback, useImperativeHandle, memo, useMemo } from 'react';
4
4
  import { version } from 'antd';
5
5
  import AntModal from 'antd/es/modal';
6
+ import AntUpload from 'antd/es/upload';
6
7
  import { compareVersions } from 'compare-versions';
7
8
  import Cropper from 'react-easy-crop';
8
9
  import AntButton from 'antd/es/button';
@@ -20,7 +21,7 @@ const ASPECT_MAX = 2;
20
21
  const ASPECT_STEP = 0.01;
21
22
 
22
23
  const EasyCrop = forwardRef((props, ref) => {
23
- const { cropperRef, zoomSlider, rotationSlider, aspectSlider, showReset, image, aspect: ASPECT_INITIAL, minZoom, maxZoom, cropShape, showGrid, cropperProps, isCN, } = props;
24
+ const { cropperRef, zoomSlider, rotationSlider, aspectSlider, showReset, modalImage, aspect: ASPECT_INITIAL, minZoom, maxZoom, cropShape, showGrid, cropperProps, isCN, } = props;
24
25
  const [zoom, setZoom] = useState(ZOOM_INITIAL);
25
26
  const [rotation, setRotation] = useState(ROTATION_INITIAL);
26
27
  const [aspect, setAspect] = useState(ASPECT_INITIAL);
@@ -38,22 +39,21 @@ const EasyCrop = forwardRef((props, ref) => {
38
39
  cropPixelsRef.current = croppedAreaPixels;
39
40
  }, []);
40
41
  useImperativeHandle(ref, () => ({
41
- setZoom,
42
42
  rotation,
43
- setRotation,
44
43
  cropPixelsRef,
44
+ onReset,
45
45
  }));
46
- const wrapperClass = 'flex items-center w-3/5 mx-auto';
47
- const buttonClass = 'flex items-center justify-center w-8 h-8 bg-transparent border-0 font-[inherit] text-[18px] cursor-pointer disabled:opacity-20 disabled:cursor-default';
48
- const sliderClass = 'flex-1 mx-2';
49
- return (jsxs(Fragment, { children: [jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image: image, crop: crop,
46
+ const wrapperClass = '[display:flex] [align-items:center] [width:60%] [margin-inline:auto]';
47
+ const buttonClass = '[display:flex] [align-items:center] [justify-content:center] [height:32px] [width:32px] [background:transparent] [border:0] [font-family:inherit] [font-size:18px] [cursor:pointer] disabled:[opacity:20%] disabled:[cursor:default]';
48
+ const sliderClass = '[flex:1]';
49
+ return (jsxs(Fragment, { children: [jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image: modalImage, crop: crop,
50
50
  //
51
51
  zoom: zoom, rotation: rotation, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, zoomWithScroll: zoomSlider,
52
52
  //
53
53
  cropShape: cropShape, showGrid: showGrid, onCropChange: onCropChange, onZoomChange: setZoom, onRotationChange: setRotation, onCropComplete: onCropComplete, classes: {
54
- containerClassName: `${PREFIX}-container !relative w-full h-[40vh] [&~section:first-of-type]:mt-4 [&~section:last-of-type]:mb-4`,
54
+ containerClassName: `${PREFIX}-container ![position:relative] [width:100%] [height:40vh] [&~section:first-of-type]:[margin-top:16px] [&~section:last-of-type]:[margin-bottom:16px]`,
55
55
  mediaClassName: `${PREFIX}-media`,
56
- } })), zoomSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-zoom ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom - ZOOM_STEP), disabled: zoom - ZOOM_STEP < minZoom }, { children: "\uFF0D" })), jsx(AntSlider, { className: sliderClass, min: minZoom, max: maxZoom, step: ZOOM_STEP, value: zoom, onChange: setZoom }), jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom + ZOOM_STEP), disabled: zoom + ZOOM_STEP > maxZoom }, { children: "\uFF0B" }))] }))), rotationSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-rotation ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: `${buttonClass} !text-[16px]`, onClick: () => setRotation(rotation - ROTATION_STEP), disabled: rotation === ROTATION_MIN }, { children: "\u21BA" })), jsx(AntSlider, { className: sliderClass, min: ROTATION_MIN, max: ROTATION_MAX, step: ROTATION_STEP, value: rotation, onChange: setRotation }), jsx("button", Object.assign({ className: `${buttonClass} !text-[16px]`, onClick: () => setRotation(rotation + ROTATION_STEP), disabled: rotation === ROTATION_MAX }, { children: "\u21BB" }))] }))), aspectSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-aspect ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect - ASPECT_STEP), disabled: aspect - ASPECT_STEP < ASPECT_MIN }, { children: "\u2195\uFE0F" })), jsx(AntSlider, { className: sliderClass, min: ASPECT_MIN, max: ASPECT_MAX, step: ASPECT_STEP, value: aspect, onChange: setAspect }), jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect + ASPECT_STEP), disabled: aspect + ASPECT_STEP > ASPECT_MAX }, { children: "\u2194\uFE0F" }))] }))), showReset && (zoomSlider || rotationSlider || aspectSlider) && (jsx(AntButton, Object.assign({ className: "absolute bottom-[20px]", style: isResetActive ? {} : { opacity: 0.3, pointerEvents: 'none' }, onClick: onReset }, { children: isCN ? '重置' : 'Reset' })))] }));
56
+ } })), zoomSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-zoom ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom - ZOOM_STEP), disabled: zoom - ZOOM_STEP < minZoom }, { children: "\uFF0D" })), jsx(AntSlider, { className: sliderClass, min: minZoom, max: maxZoom, step: ZOOM_STEP, value: zoom, onChange: setZoom }), jsx("button", Object.assign({ className: buttonClass, onClick: () => setZoom(zoom + ZOOM_STEP), disabled: zoom + ZOOM_STEP > maxZoom }, { children: "\uFF0B" }))] }))), rotationSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-rotation ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: `${buttonClass} [font-size:16px]`, onClick: () => setRotation(rotation - ROTATION_STEP), disabled: rotation === ROTATION_MIN }, { children: "\u21BA" })), jsx(AntSlider, { className: sliderClass, min: ROTATION_MIN, max: ROTATION_MAX, step: ROTATION_STEP, value: rotation, onChange: setRotation }), jsx("button", Object.assign({ className: `${buttonClass} [font-size:16px]`, onClick: () => setRotation(rotation + ROTATION_STEP), disabled: rotation === ROTATION_MAX }, { children: "\u21BB" }))] }))), aspectSlider && (jsxs("section", Object.assign({ className: `${PREFIX}-control ${PREFIX}-control-aspect ${wrapperClass}` }, { children: [jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect - ASPECT_STEP), disabled: aspect - ASPECT_STEP < ASPECT_MIN }, { children: "\u2195\uFE0F" })), jsx(AntSlider, { className: sliderClass, min: ASPECT_MIN, max: ASPECT_MAX, step: ASPECT_STEP, value: aspect, onChange: setAspect }), jsx("button", Object.assign({ className: buttonClass, onClick: () => setAspect(aspect + ASPECT_STEP), disabled: aspect + ASPECT_STEP > ASPECT_MAX }, { children: "\u2194\uFE0F" }))] }))), showReset && (zoomSlider || rotationSlider || aspectSlider) && (jsx(AntButton, Object.assign({ className: "[position:absolute] [bottom:20px]", style: isResetActive ? {} : { opacity: 0.3, pointerEvents: 'none' }, onClick: onReset }, { children: isCN ? '重置' : 'Reset' })))] }));
57
57
  });
58
58
  var EasyCrop$1 = memo(EasyCrop);
59
59
 
@@ -84,7 +84,7 @@ function styleInject(css, ref) {
84
84
  }
85
85
  }
86
86
 
87
- var css_248z = ".container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.absolute{position:absolute}.\\!relative{position:relative!important}.bottom-\\[20px\\]{bottom:20px}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.flex{display:flex}.grid{display:grid}.h-8{height:2rem}.h-\\[40vh\\]{height:40vh}.w-3\\/5{width:60%}.w-8{width:2rem}.w-full{width:100%}.flex-1{flex:1 1 0%}.cursor-pointer{cursor:pointer}.items-center{align-items:center}.justify-center{justify-content:center}.border-0{border-width:0}.bg-transparent{background-color:transparent}.font-\\[inherit\\]{font-family:inherit}.\\!text-\\[16px\\]{font-size:16px!important}.text-\\[18px\\]{font-size:18px}.disabled\\:cursor-default:disabled{cursor:default}.disabled\\:opacity-20:disabled{opacity:.2}.\\[\\&\\~section\\:first-of-type\\]\\:mt-4~section:first-of-type{margin-top:1rem}.\\[\\&\\~section\\:last-of-type\\]\\:mb-4~section:last-of-type{margin-bottom:1rem}";
87
+ var css_248z = ".container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.grid{display:grid}.\\!\\[position\\:relative\\]{position:relative!important}.\\[align-items\\:center\\]{align-items:center}.\\[background\\:transparent\\]{background:transparent}.\\[border\\:0\\]{border:0}.\\[bottom\\:20px\\]{bottom:20px}.\\[cursor\\:pointer\\]{cursor:pointer}.\\[display\\:flex\\]{display:flex}.\\[flex\\:1\\]{flex:1}.\\[font-family\\:inherit\\]{font-family:inherit}.\\[font-size\\:16px\\]{font-size:16px}.\\[font-size\\:18px\\]{font-size:18px}.\\[height\\:32px\\]{height:32px}.\\[height\\:40vh\\]{height:40vh}.\\[justify-content\\:center\\]{justify-content:center}.\\[margin-inline\\:auto\\]{margin-inline:auto}.\\[position\\:absolute\\]{position:absolute}.\\[width\\:100\\%\\]{width:100%}.\\[width\\:32px\\]{width:32px}.\\[width\\:60\\%\\]{width:60%}.disabled\\:\\[cursor\\:default\\]:disabled{cursor:default}.disabled\\:\\[opacity\\:20\\%\\]:disabled{opacity:20%}.\\[\\&\\~section\\:first-of-type\\]\\:\\[margin-top\\:16px\\]~section:first-of-type{margin-top:16px}.\\[\\&\\~section\\:last-of-type\\]\\:\\[margin-bottom\\:16px\\]~section:last-of-type{margin-bottom:16px}";
88
88
  styleInject(css_248z);
89
89
 
90
90
  const openKey = compareVersions(version, '4.23.0') === -1 ? 'visible' : 'open';
@@ -104,96 +104,36 @@ const ImgCrop = forwardRef((props, cropperRef) => {
104
104
  // @ts-ignore
105
105
  cropShape: CROP_SHAPE = 'rect',
106
106
  // @ts-ignore
107
- showGrid: SHOW_GRID = false, cropperProps, modalClassName, modalTitle, modalWidth, modalOk, modalCancel, showReset = false, onModalOk, onModalCancel, modalProps, beforeCrop, onUploadFail, children, } = props;
107
+ showGrid: SHOW_GRID = false, cropperProps, modalClassName, modalTitle, modalWidth, modalOk, modalCancel, showReset = false, onModalOk, onModalCancel, modalProps, beforeCrop, children, } = props;
108
+ /**
109
+ * init
110
+ */
108
111
  const zoomSlider = deprecate(props, 'zoom', 'zoomSlider') || true;
109
112
  const rotationSlider = deprecate(props, 'rotate', 'rotationSlider') || false;
110
113
  const cropShape = deprecate(props, 'shape', 'cropShape') || 'rect';
111
114
  const showGrid = deprecate(props, 'grid', 'showGrid') || false;
115
+ if ('onUploadFail' in props) {
116
+ console.error(`\`onUploadFail\` is removed, because the only way it is called, is when the file is rejected by beforeUpload`);
117
+ }
112
118
  deprecate(props, 'modalMaskTransitionName', 'modalProps.maskTransitionName');
113
119
  deprecate(props, 'modalTransitionName', 'modalProps.transitionName');
114
120
  const cb = useRef({});
115
121
  cb.current.onModalOk = onModalOk;
116
122
  cb.current.onModalCancel = onModalCancel;
117
123
  cb.current.beforeCrop = beforeCrop;
118
- cb.current.onUploadFail = onUploadFail;
119
- /**
120
- * upload
121
- */
122
- const [image, setImage] = useState('');
123
- const fileRef = useRef({});
124
- const beforeUploadRef = useRef();
125
- const resolveRef = useRef(() => { });
126
- const rejectRef = useRef(() => { });
127
- const uploadComponent = useMemo(() => {
128
- const upload = Array.isArray(children) ? children[0] : children;
129
- const _a = upload.props, { beforeUpload, accept } = _a, restUploadProps = __rest(_a, ["beforeUpload", "accept"]);
130
- beforeUploadRef.current = beforeUpload;
131
- return Object.assign(Object.assign({}, upload), { props: Object.assign(Object.assign({}, restUploadProps), { accept: accept || 'image/*', beforeUpload: (file, fileList) => {
132
- return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
133
- if (typeof cb.current.beforeCrop === 'function') {
134
- const shouldCrop = yield cb.current.beforeCrop(file, fileList);
135
- if (!shouldCrop) {
136
- return reject();
137
- }
138
- }
139
- fileRef.current = file;
140
- resolveRef.current = (newFile) => {
141
- var _a, _b;
142
- (_b = (_a = cb.current).onModalOk) === null || _b === void 0 ? void 0 : _b.call(_a, newFile);
143
- resolve(newFile);
144
- };
145
- rejectRef.current = (uploadErr) => {
146
- var _a, _b;
147
- (_b = (_a = cb.current).onUploadFail) === null || _b === void 0 ? void 0 : _b.call(_a, uploadErr);
148
- reject();
149
- };
150
- const reader = new FileReader();
151
- reader.addEventListener('load', () => {
152
- if (typeof reader.result === 'string') {
153
- setImage(reader.result);
154
- }
155
- });
156
- reader.readAsDataURL(file);
157
- }));
158
- } }) });
159
- }, [children]);
160
124
  /**
161
125
  * crop
162
126
  */
163
- const easyCropRef = useRef({});
164
- /**
165
- * modal
166
- */
167
- const modalBaseProps = useMemo(() => {
168
- const obj = {};
169
- if (modalWidth !== undefined)
170
- obj.width = modalWidth;
171
- if (modalOk !== undefined)
172
- obj.okText = modalOk;
173
- if (modalCancel !== undefined)
174
- obj.cancelText = modalCancel;
175
- return obj;
176
- }, [modalCancel, modalOk, modalWidth]);
177
- const onClose = () => {
178
- setImage('');
179
- easyCropRef.current.setZoom(ZOOM_INITIAL);
180
- easyCropRef.current.setRotation(ROTATION_INITIAL);
181
- };
182
- const onCancel = useCallback(() => {
183
- var _a, _b;
184
- (_b = (_a = cb.current).onModalCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
185
- onClose();
186
- }, []);
187
- const onOk = useCallback((event) => __awaiter(void 0, void 0, void 0, function* () {
127
+ const easyCropRef = useRef(null);
128
+ const getCropCanvas = useCallback((target) => {
188
129
  var _a;
189
- onClose();
190
130
  const canvas = document.createElement('canvas');
191
131
  const ctx = canvas.getContext('2d');
192
- const target = event.target;
193
132
  const context = ((_a = target === null || target === void 0 ? void 0 : target.getRootNode) === null || _a === void 0 ? void 0 : _a.call(target)) || document;
194
133
  const imgSource = context.querySelector(`.${PREFIX}-media`);
195
134
  const { width: cropWidth, height: cropHeight, x: cropX, y: cropY, } = easyCropRef.current.cropPixelsRef.current;
196
- if (rotationSlider && easyCropRef.current.rotation !== ROTATION_INITIAL) {
135
+ if (rotationSlider &&
136
+ easyCropRef.current.rotation !== ROTATION_INITIAL) {
197
137
  const { naturalWidth: imgWidth, naturalHeight: imgHeight } = imgSource;
198
138
  const angle = easyCropRef.current.rotation * (Math.PI / 180);
199
139
  // get container for rotated image
@@ -228,40 +168,97 @@ const ImgCrop = forwardRef((props, cropperRef) => {
228
168
  ctx.fillRect(0, 0, cropWidth, cropHeight);
229
169
  ctx.drawImage(imgSource, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
230
170
  }
231
- // get the new image
232
- const { type, name, uid } = fileRef.current;
233
- canvas.toBlob((blob) => __awaiter(void 0, void 0, void 0, function* () {
234
- const newFile = new File([blob], name, { type });
235
- Object.assign(newFile, { uid });
236
- if (typeof beforeUploadRef.current !== 'function') {
237
- resolveRef.current(newFile);
238
- return;
239
- }
240
- // https://github.com/ant-design/ant-design/blob/master/components/upload/Upload.tsx
241
- // https://ant.design/components/upload-cn#api
242
- try {
243
- const rcFile = newFile;
244
- const result = yield beforeUploadRef.current(rcFile, [rcFile]);
245
- if (result === true) {
246
- resolveRef.current(newFile); // true
247
- }
248
- else if (result === false) {
249
- rejectRef.current(new Error('beforeUpload → false')); // false
250
- }
251
- else {
252
- resolveRef.current(result); // File, Upload.LIST_IGNORE
171
+ return canvas;
172
+ }, [fillColor, rotationSlider]);
173
+ /**
174
+ * upload
175
+ */
176
+ const [modalImage, setModalImage] = useState('');
177
+ const onCancel = useRef();
178
+ const onOk = useRef();
179
+ const uploadComponent = useMemo(() => {
180
+ const upload = Array.isArray(children) ? children[0] : children;
181
+ const _a = upload.props, { beforeUpload, accept } = _a, restUploadProps = __rest(_a, ["beforeUpload", "accept"]);
182
+ const innerBeforeUpload = (file, fileList) => {
183
+ return new Promise((resolve) => __awaiter(void 0, void 0, void 0, function* () {
184
+ if (typeof cb.current.beforeCrop === 'function') {
185
+ try {
186
+ const result = yield cb.current.beforeCrop(file, fileList);
187
+ if (result !== true) {
188
+ return resolve(result);
189
+ }
190
+ }
191
+ catch (err) {
192
+ return resolve(err);
193
+ }
253
194
  }
254
- }
255
- catch (err) {
256
- rejectRef.current(new Error('beforeUpload → reject')); // reject
257
- }
258
- }), type, quality);
259
- }), [fillColor, quality, rotationSlider]);
195
+ // get file result
196
+ const reader = new FileReader();
197
+ reader.addEventListener('load', () => {
198
+ if (typeof reader.result === 'string') {
199
+ setModalImage(reader.result); // open modal
200
+ }
201
+ });
202
+ reader.readAsDataURL(file);
203
+ // on modal cancel
204
+ onCancel.current = () => {
205
+ var _a, _b;
206
+ setModalImage('');
207
+ easyCropRef.current.onReset();
208
+ resolve(AntUpload.LIST_IGNORE);
209
+ (_b = (_a = cb.current).onModalCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
210
+ };
211
+ // on modal confirm
212
+ onOk.current = (event) => __awaiter(void 0, void 0, void 0, function* () {
213
+ setModalImage('');
214
+ easyCropRef.current.onReset();
215
+ const canvas = getCropCanvas(event.target);
216
+ const { type, name, uid } = file;
217
+ canvas.toBlob((blob) => __awaiter(void 0, void 0, void 0, function* () {
218
+ var _a, _b, _c, _d, _e, _f;
219
+ const newFile = new File([blob], name, { type });
220
+ Object.assign(newFile, { uid });
221
+ if (typeof beforeUpload !== 'function') {
222
+ resolve(newFile);
223
+ (_b = (_a = cb.current).onModalOk) === null || _b === void 0 ? void 0 : _b.call(_a, newFile);
224
+ return;
225
+ }
226
+ try {
227
+ // https://github.com/ant-design/ant-design/blob/master/components/upload/Upload.tsx#L128-L148
228
+ // https://ant.design/components/upload-cn#api
229
+ const result = yield beforeUpload(newFile, [newFile]);
230
+ const value = result === true ? newFile : result;
231
+ resolve(value);
232
+ (_d = (_c = cb.current).onModalOk) === null || _d === void 0 ? void 0 : _d.call(_c, value);
233
+ }
234
+ catch (err) {
235
+ resolve(err);
236
+ (_f = (_e = cb.current).onModalOk) === null || _f === void 0 ? void 0 : _f.call(_e, err);
237
+ }
238
+ }), type, quality);
239
+ });
240
+ }));
241
+ };
242
+ return Object.assign(Object.assign({}, upload), { props: Object.assign(Object.assign({}, restUploadProps), { accept: accept || 'image/*', beforeUpload: innerBeforeUpload }) });
243
+ }, [children, getCropCanvas, quality]);
244
+ /**
245
+ * modal
246
+ */
247
+ const modalBaseProps = useMemo(() => {
248
+ const obj = {};
249
+ if (modalWidth !== undefined)
250
+ obj.width = modalWidth;
251
+ if (modalOk !== undefined)
252
+ obj.okText = modalOk;
253
+ if (modalCancel !== undefined)
254
+ obj.cancelText = modalCancel;
255
+ return obj;
256
+ }, [modalCancel, modalOk, modalWidth]);
260
257
  const wrapClassName = `${PREFIX}-modal${modalClassName ? ` ${modalClassName}` : ''}`;
261
258
  const lang = typeof window === 'undefined' ? '' : window.navigator.language;
262
259
  const isCN = lang === 'zh-CN';
263
260
  const title = modalTitle || (isCN ? '编辑图片' : 'Edit image');
264
- return (jsxs(Fragment, { children: [uploadComponent, image && (jsx(AntModal, Object.assign({}, modalProps, modalBaseProps, { [openKey]: true }, { title: title, onOk: onOk, onCancel: onCancel, wrapClassName: wrapClassName, maskClosable: false, destroyOnClose: true }, { children: jsx(EasyCrop$1, { ref: easyCropRef, cropperRef: cropperRef, zoomSlider: zoomSlider, rotationSlider: rotationSlider, aspectSlider: aspectSlider, showReset: showReset, image: image, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, cropShape: cropShape, showGrid: showGrid, cropperProps: cropperProps, isCN: isCN }) })))] }));
261
+ return (jsxs(Fragment, { children: [uploadComponent, modalImage && (jsx(AntModal, Object.assign({}, modalProps, modalBaseProps, { [openKey]: true }, { title: title, onCancel: onCancel.current, onOk: onOk.current, wrapClassName: wrapClassName, maskClosable: false, destroyOnClose: true }, { children: jsx(EasyCrop$1, { ref: easyCropRef, cropperRef: cropperRef, zoomSlider: zoomSlider, rotationSlider: rotationSlider, aspectSlider: aspectSlider, showReset: showReset, modalImage: modalImage, aspect: aspect, minZoom: minZoom, maxZoom: maxZoom, cropShape: cropShape, showGrid: showGrid, cropperProps: cropperProps, isCN: isCN }) })))] }));
265
262
  });
266
263
 
267
264
  export { ImgCrop as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antd-img-crop",
3
- "version": "4.11.1",
3
+ "version": "4.12.1",
4
4
  "description": "An image cropper for Ant Design Upload",
5
5
  "keywords": [
6
6
  "react",
@@ -22,6 +22,9 @@
22
22
  "files": [
23
23
  "dist"
24
24
  ],
25
+ "scripts": {
26
+ "build": "rm -rf dist && rollup -c --configPlugin @rollup/plugin-typescript"
27
+ },
25
28
  "peerDependencies": {
26
29
  "antd": ">=4.0.0",
27
30
  "react": ">=16.8.0",
@@ -34,30 +37,27 @@
34
37
  },
35
38
  "devDependencies": {
36
39
  "@rollup/plugin-replace": "^5.0.2",
37
- "@rollup/plugin-typescript": "^11.0.0",
40
+ "@rollup/plugin-typescript": "^11.1.0",
38
41
  "@trivago/prettier-plugin-sort-imports": "^4.1.1",
39
42
  "@types/node": "^18.15.11",
40
- "@types/react": "^18.0.31",
43
+ "@types/react": "^18.0.33",
41
44
  "@types/react-dom": "^18.0.11",
42
45
  "@vitejs/plugin-react": "^3.1.0",
43
- "antd": "^5.3.3",
46
+ "antd": "^5.4.0",
44
47
  "autoprefixer": "^10.4.14",
45
48
  "eslint": "^8.37.0",
46
49
  "eslint-config-prettier": "^8.8.0",
47
50
  "eslint-config-react-app": "^7.0.1",
48
51
  "postcss": "^8.4.21",
49
52
  "prettier": "^2.8.7",
50
- "prettier-plugin-tailwindcss": "^0.2.5",
53
+ "prettier-plugin-tailwindcss": "^0.2.7",
51
54
  "react": "^18.2.0",
52
55
  "react-dom": "^18.2.0",
53
56
  "rollup": "3.20.2",
54
57
  "rollup-plugin-dts": "^5.3.0",
55
58
  "rollup-plugin-postcss": "^4.0.2",
56
- "tailwindcss": "^3.3.0",
57
- "typescript": "^5.0.2",
59
+ "tailwindcss": "^3.3.1",
60
+ "typescript": "^5.0.3",
58
61
  "vite": "^4.2.1"
59
- },
60
- "scripts": {
61
- "build": "rm -rf dist && rollup -c --configPlugin @rollup/plugin-typescript"
62
62
  }
63
- }
63
+ }