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 +23 -24
- package/README.zh-CN.md +23 -24
- package/dist/antd-img-crop.cjs.js +107 -110
- package/dist/antd-img-crop.d.ts +5 -5
- package/dist/antd-img-crop.esm.js +107 -110
- package/package.json +11 -11
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
|
|
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,
|
|
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
|
|
49
|
-
const buttonClass = 'flex items
|
|
50
|
-
const sliderClass = 'flex
|
|
51
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image:
|
|
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
|
|
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}
|
|
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}.
|
|
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,
|
|
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 &&
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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,
|
|
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;
|
package/dist/antd-img-crop.d.ts
CHANGED
|
@@ -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?: (
|
|
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?:
|
|
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,
|
|
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
|
|
47
|
-
const buttonClass = 'flex items
|
|
48
|
-
const sliderClass = 'flex
|
|
49
|
-
return (jsxs(Fragment, { children: [jsx(Cropper, Object.assign({}, cropperProps, { ref: cropperRef, image:
|
|
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
|
|
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}
|
|
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}.
|
|
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,
|
|
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 &&
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
57
|
-
"typescript": "^5.0.
|
|
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
|
+
}
|