UNPKG

choerodon-ui

Version:

An enterprise-class UI design language and React-based implementation

576 lines (500 loc) 19.3 kB
import _extends from "@babel/runtime/helpers/extends"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _objectSpread from "@babel/runtime/helpers/objectSpread2"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; var _excluded = ["beforeUpload", "accept"]; import _regeneratorRuntime from "@babel/runtime/regenerator"; import React, { forwardRef, useCallback, useContext, useRef, useState } from 'react'; import Cropper from 'react-easy-crop'; import isFunction from 'lodash/isFunction'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import Modal from '../modal'; import defaultLocale from '../locale-provider/default'; import Button from '../button'; import ButtonGroup from '../button/ButtonGroup'; import Upload from '../upload'; import AvatarUploader from './avatarUpload'; import { ShapeCroper } from './enum'; import ConfigContext from '../config-provider/ConfigContext'; // ssr if (typeof window !== 'undefined') { // 兼容ie11 remove 方法 (function (arr) { arr.forEach(function (item) { // eslint-disable-next-line no-prototype-builtins if (item.hasOwnProperty('remove')) { return; } Object.defineProperty(item, 'remove', { configurable: true, enumerable: true, writable: true, value: function remove() { if (this.parentNode === null) { return; } this.parentNode.removeChild(this); } }); }); // 兼容IE if (!HTMLCanvasElement.prototype.toBlob) { Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { value: function value(callback, type, quality) { var _this = this; setTimeout(function () { var binStr = atob(_this.toDataURL(type, quality).split(',')[1]); var len = binStr.length; var arrArray = new Uint8Array(len); for (var i = 0; i < len; i++) { arrArray[i] = binStr.charCodeAt(i); } callback(new Blob([arrArray], { type: type || 'image/png' })); }); } }); } })([Element.prototype, CharacterData.prototype, DocumentType.prototype]); } var MIN_ZOOM = 1; var MAX_ZOOM = 3; var ZOOM_STEP = 0.1; export { ShapeCroper }; var EasyCrop = /*#__PURE__*/forwardRef(function (props, ref) { var src = props.src, aspect = props.aspect, shape = props.shape, grid = props.grid, hasZoom = props.hasZoom, zoomVal = props.zoomVal, rotateVal = props.rotateVal, setZoomVal = props.setZoomVal, setRotateVal = props.setRotateVal, onComplete = props.onComplete, prefixCls = props.prefixCls; var _useState = useState({ x: 0, y: 0 }), _useState2 = _slicedToArray(_useState, 2), crop = _useState2[0], setCrop = _useState2[1]; var onCropComplete = useCallback(function (_croppedArea, croppedAreaPixels) { croppedAreaPixels.zoom = zoomVal || 0; croppedAreaPixels.rotate = rotateVal || 0; onComplete(croppedAreaPixels); }, [onComplete, zoomVal, rotateVal]); return /*#__PURE__*/React.createElement(Cropper, { ref: ref, image: src, aspect: aspect, cropShape: shape, showGrid: grid, zoomWithScroll: hasZoom, crop: crop, zoom: zoomVal, rotation: rotateVal, onCropChange: setCrop, onZoomChange: setZoomVal, onRotationChange: setRotateVal, onCropComplete: onCropComplete, classes: { containerClassName: "".concat(prefixCls, "-container"), mediaClassName: "".concat(prefixCls, "-media") } }); }); // 图片转化为canvas var imageToCanvas = function imageToCanvas(image) { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; if (ctx) { ctx.drawImage(image, 0, 0); return canvas; } return undefined; }; var ImgCrop = /*#__PURE__*/forwardRef(function ImgCrop(props, ref) { var aspect = props.aspect, shape = props.shape, grid = props.grid, zoom = props.zoom, rotate = props.rotate, _props$rotateStep = props.rotateStep, rotateStep = _props$rotateStep === void 0 ? 90 : _props$rotateStep, beforeCrop = props.beforeCrop, modalTitle = props.modalTitle, modalWidth = props.modalWidth, modalOk = props.modalOk, modalCancel = props.modalCancel, modalVisible = props.modalVisible, children = props.children, onModalCancel = props.onCancel, onModalOk = props.onOk, imageSrc = props.src, serverCrop = props.serverCrop, modalProps = props.modalProps, cropContent = props.cropContent, onCropComplete = props.onCropComplete, customizePrefixCls = props.prefixCls; var _useContext = useContext(ConfigContext), getPrefixCls = _useContext.getPrefixCls; var prefixCls = getPrefixCls('image-crop', customizePrefixCls); var prefixClsMedia = "".concat(prefixCls, "-media"); var hasZoom = zoom === true; var hasRotate = rotate === true; var _useState3 = useState(''), _useState4 = _slicedToArray(_useState3, 2), src = _useState4[0], setSrc = _useState4[1]; var _useState5 = useState(1), _useState6 = _slicedToArray(_useState5, 2), zoomVal = _useState6[0], setZoomVal = _useState6[1]; var _useState7 = useState(0), _useState8 = _slicedToArray(_useState7, 2), rotateVal = _useState8[0], setRotateVal = _useState8[1]; var beforeUploadRef = React.useRef(); // 返回上传组件的上传之前的钩子函数 var fileRef = React.useRef(); // 记录文件的参数 var resolveRef = useRef(); // 返回文件上传的成功数据的方法 var rejectRef = useRef(); // 返回失败数据的方法 var cropPixelsRef = React.useRef(); var imageCropCanvas = function imageCropCanvas(naturalModalImg) { var naturalWidth = naturalModalImg.naturalWidth, naturalHeight = naturalModalImg.naturalHeight; var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); if (ctx) { // create a max canvas to cover the source image after rotated var maxLen = Math.sqrt(Math.pow(naturalWidth, 2) + Math.pow(naturalHeight, 2)); canvas.width = maxLen; canvas.height = maxLen; // rotate the image if (hasRotate && rotateVal > 0 && rotateVal < 360) { var halfMax = maxLen / 2; ctx.translate(halfMax, halfMax); ctx.rotate(rotateVal * Math.PI / 180); ctx.translate(-halfMax, -halfMax); } // draw the source image in the center of the max canvas var left = (maxLen - naturalWidth) / 2; var top = (maxLen - naturalHeight) / 2; ctx.drawImage(naturalModalImg, left, top); // shrink the max canvas to the crop area size, then align two center points var maxImgData = ctx.getImageData(0, 0, maxLen, maxLen); if (cropPixelsRef && cropPixelsRef.current) { var _cropPixelsRef$curren = cropPixelsRef.current, width = _cropPixelsRef$curren.width, height = _cropPixelsRef$curren.height, x = _cropPixelsRef$curren.x, y = _cropPixelsRef$curren.y; canvas.width = width; canvas.height = height; // get the new image ctx.putImageData(maxImgData, -left - x, -top - y); return canvas; } } }; /** * Upload */ var renderUpload = useCallback(function () { var upload = Array.isArray(children) ? children[0] : children; if (upload && upload.props && upload.type === Upload) { var _upload$props = upload.props, beforeUpload = _upload$props.beforeUpload, accept = _upload$props.accept, restUploadProps = _objectWithoutProperties(_upload$props, _excluded); beforeUploadRef.current = beforeUpload; return _objectSpread(_objectSpread({}, upload), {}, { props: _objectSpread(_objectSpread({}, restUploadProps), {}, { accept: accept || 'image/*', beforeUpload: function beforeUpload(file, fileList) { return new Promise(function (resolve, reject) { if (beforeCrop && !beforeCrop(file, fileList)) { reject(); return; } fileRef.current = file; resolveRef.current = resolve; rejectRef.current = reject; var reader = new FileReader(); if (reader) { reader.addEventListener('load', function () { if (reader.result && typeof reader.result === 'string') { setSrc(reader.result); } }); if (file instanceof Blob) { reader.readAsDataURL(file); } } }); } }) }); } if (imageSrc && typeof window !== 'undefined') { var newimage = new Image(); newimage.src = imageSrc; newimage.crossOrigin = 'anonymous'; newimage.onload = function () { var canvas = imageToCanvas(newimage); if (canvas) { if (isFunction(onModalOk) && canvas) { setSrc(canvas.toDataURL()); } } }; } }, [beforeCrop, children]); /** * EasyCrop */ var onComplete = useCallback(function (croppedAreaPixels) { cropPixelsRef.current = croppedAreaPixels; if (isFunction(onCropComplete)) { var naturalModalImg = document.querySelector(".".concat(prefixClsMedia)); var canvas = serverCrop ? imageToCanvas(naturalModalImg) : imageCropCanvas(naturalModalImg); if (canvas) { canvas.toBlob(function (blob) { var area = {}; if (cropPixelsRef.current) { area = cropPixelsRef.current; } onCropComplete({ url: canvas.toDataURL(), blob: blob, area: area }); }); } } }, [rotateVal, hasRotate]); /** * Controls */ var MIN_ROTATE = 0; var MAX_ROTATE = 360; var isMinZoom = zoomVal <= MIN_ZOOM; var isMaxZoom = zoomVal >= MAX_ZOOM; var isMinRotate = rotateVal === MIN_ROTATE; var isMaxRotate = rotateVal >= MAX_ROTATE; var subZoomVal = useCallback(function () { if (!isMinZoom) setZoomVal(zoomVal - ZOOM_STEP); }, [isMinZoom, zoomVal]); var addZoomVal = useCallback(function () { if (!isMaxZoom) setZoomVal(zoomVal + ZOOM_STEP); }, [isMaxZoom, zoomVal]); var addRotateVal = useCallback(function () { if (!isMaxRotate) { setRotateVal(rotateVal + rotateStep); } else { setRotateVal(MIN_ROTATE + rotateStep); } }, [isMaxRotate, rotateVal]); var initVal = useCallback(function () { if (!isMinZoom || !isMinRotate) { setZoomVal(MIN_ZOOM); setRotateVal(MIN_ROTATE); } }, [zoomVal, rotateVal]); /** * Modal */ var closeModal = useCallback(function () { setSrc(''); setZoomVal(1); setRotateVal(0); }, []); var onClose = useCallback(function () { closeModal(); if (isFunction(onModalCancel)) { onModalCancel(); } }, []); var onOk = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var naturalModalImg, canvas, _fileRef$current, type, name, uid; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: onClose(); naturalModalImg = document.querySelector(".".concat(prefixClsMedia)); if (naturalModalImg) { if (naturalModalImg && naturalModalImg instanceof HTMLImageElement) { canvas = serverCrop ? imageToCanvas(naturalModalImg) : imageCropCanvas(naturalModalImg); if (fileRef.current && canvas) { _fileRef$current = fileRef.current, type = _fileRef$current.type, name = _fileRef$current.name, uid = _fileRef$current.uid; canvas.toBlob( /*#__PURE__*/function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(blob) { var newFile, res, passedFile, passedFileType; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: newFile = blob; if (!newFile) { _context.next = 30; break; } newFile.lastModifiedDate = Date.now(); newFile.name = name; newFile.uid = uid; newFile.imageCropArea = cropPixelsRef.current; if (!(resolveRef && rejectRef && resolveRef.current && rejectRef.current)) { _context.next = 30; break; } if (!(typeof beforeUploadRef.current !== 'function')) { _context.next = 9; break; } return _context.abrupt("return", resolveRef.current(newFile)); case 9: res = beforeUploadRef.current(newFile, [newFile]); if (!(typeof res !== 'boolean' && !res)) { _context.next = 13; break; } console.error('beforeUpload must return a boolean or Promise'); return _context.abrupt("return"); case 13: if (!(res === true)) { _context.next = 15; break; } return _context.abrupt("return", resolveRef.current(newFile)); case 15: if (!(res === false)) { _context.next = 17; break; } return _context.abrupt("return", rejectRef.current('not upload')); case 17: if (!(res && typeof res.then === 'function')) { _context.next = 30; break; } _context.prev = 18; _context.next = 21; return res; case 21: passedFile = _context.sent; passedFileType = Object.prototype.toString.call(passedFile); if (passedFileType === '[object File]' || passedFileType === '[object Blob]') newFile = passedFile; resolveRef.current(newFile); _context.next = 30; break; case 27: _context.prev = 27; _context.t0 = _context["catch"](18); rejectRef.current(_context.t0); case 30: case "end": return _context.stop(); } } }, _callee, null, [[18, 27]]); })); return function (_x) { return _ref2.apply(this, arguments); }; }(), type, 0.4); } if (isFunction(onModalOk) && canvas) { canvas.toBlob(function (blob) { var area = {}; if (cropPixelsRef.current) { area = cropPixelsRef.current; } onModalOk({ url: canvas.toDataURL(), blob: blob, area: area }); }); } } } case 3: case "end": return _context2.stop(); } } }, _callee2); })), [hasRotate, onClose, rotateVal]); var RenderCrop = /*#__PURE__*/React.createElement(EasyCrop, { ref: ref, src: src, aspect: aspect, shape: shape, grid: grid, hasZoom: hasZoom, zoomVal: zoomVal, rotateVal: rotateVal, setZoomVal: setZoomVal, setRotateVal: setRotateVal, onComplete: onComplete, prefixCls: prefixCls }); var title = modalProps && modalProps.title || modalTitle; var cancelButtonProps = { funcType: 'raised' }; var okButtonProps = { funcType: 'raised', type: 'primary' }; return /*#__PURE__*/React.createElement(LocaleReceiver, { componentName: "imageCrop", defaultLocale: defaultLocale.imageCrop }, function (locale) { return /*#__PURE__*/React.createElement(React.Fragment, null, renderUpload(), src && modalVisible && /*#__PURE__*/React.createElement(Modal, _extends({ visible: modalVisible, wrapClassName: "".concat(prefixCls, "-modal"), title: title || (locale && locale.editImage ? locale.editImage : 'Edit image'), width: modalWidth, destroyOnClose: true, maskClosable: false, onCancel: onClose, onOk: onOk, cancelButtonProps: cancelButtonProps, okButtonProps: okButtonProps, okText: modalOk, cancelText: modalCancel }, modalProps), cropContent ? cropContent(RenderCrop) : RenderCrop, /*#__PURE__*/React.createElement("div", { className: "".concat(prefixCls, "-control") }, hasZoom && /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(Button, { funcType: "raised", icon: "zoom_in", onClick: addZoomVal, disabled: isMaxZoom }), /*#__PURE__*/React.createElement(Button, { funcType: "raised", icon: "zoom_out", onClick: subZoomVal, disabled: isMinZoom })), hasRotate && /*#__PURE__*/React.createElement(Button, { funcType: "raised", icon: rotateStep === 90 ? 'play_90' : 'rotate_right', onClick: addRotateVal }), hasZoom && /*#__PURE__*/React.createElement(Button, { funcType: "raised", onClick: initVal }, "1:1")))); }); }); ImgCrop.displayName = 'ImgCrop'; ImgCrop.defaultProps = { shape: ShapeCroper.rect, grid: false, zoom: true, rotate: false, modalWidth: 600, modalVisible: true, serverCrop: false }; ImgCrop.AvatarUploader = AvatarUploader; export default ImgCrop; //# sourceMappingURL=index.js.map