UNPKG

antd-mobile

Version:
260 lines (259 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ImageUploader = void 0; var _tslib = require("tslib"); var _react = _interopRequireWildcard(require("react")); var _antdMobileIcons = require("antd-mobile-icons"); var _withDefaultProps = require("../../utils/with-default-props"); var _imageViewer = _interopRequireDefault(require("../image-viewer")); var _previewItem = _interopRequireDefault(require("./preview-item")); var _usePropsValue = require("../../utils/use-props-value"); var _ahooks = require("ahooks"); var _space = _interopRequireDefault(require("../space")); var _nativeProps = require("../../utils/native-props"); var _measureCssLength = require("../../utils/measure-css-length"); var _configProvider = require("../config-provider"); var _grid = _interopRequireDefault(require("../grid")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const classPrefix = `adm-image-uploader`; const defaultProps = { disableUpload: false, deletable: true, deleteIcon: _react.default.createElement(_antdMobileIcons.CloseOutline, { className: `${classPrefix}-cell-delete-icon` }), showUpload: true, multiple: false, maxCount: 0, defaultValue: [], accept: 'image/*', preview: true, showFailed: true, imageFit: 'cover' }; const ImageUploader = (0, _react.forwardRef)((p, ref) => { const { locale } = (0, _configProvider.useConfig)(); const props = (0, _withDefaultProps.mergeProps)(defaultProps, p); const { columns } = props; const [value, setValue] = (0, _usePropsValue.usePropsValue)(props); const [tasks, setTasks] = (0, _react.useState)([]); const containerRef = (0, _react.useRef)(null); const containerSize = (0, _ahooks.useSize)(containerRef); const gapMeasureRef = (0, _react.useRef)(null); const [cellSize, setCellSize] = (0, _react.useState)(80); const inputRef = (0, _react.useRef)(null); (0, _ahooks.useIsomorphicLayoutEffect)(() => { const gapMeasure = gapMeasureRef.current; if (columns && containerSize && gapMeasure) { const width = containerSize.width; const gap = (0, _measureCssLength.measureCSSLength)(window.getComputedStyle(gapMeasure).getPropertyValue('height')); setCellSize((width - gap * (columns - 1)) / columns); } }, [containerSize === null || containerSize === void 0 ? void 0 : containerSize.width]); const style = { '--cell-size': cellSize + 'px' }; (0, _ahooks.useIsomorphicLayoutEffect)(() => { setTasks(prev => prev.filter(task => { if (task.url === undefined) return true; return !value.some(fileItem => fileItem.url === task.url); })); }, [value]); (0, _ahooks.useIsomorphicLayoutEffect)(() => { var _a; (_a = props.onUploadQueueChange) === null || _a === void 0 ? void 0 : _a.call(props, tasks.map(item => ({ id: item.id, status: item.status }))); }, [tasks]); const idCountRef = (0, _react.useRef)(0); const { maxCount, onPreview, renderItem } = props; function processFile(file, fileList) { return (0, _tslib.__awaiter)(this, void 0, void 0, function* () { const { beforeUpload } = props; let transformedFile = file; transformedFile = yield beforeUpload === null || beforeUpload === void 0 ? void 0 : beforeUpload(file, fileList); return transformedFile; }); } function getFinalTasks(tasks) { return props.showFailed ? tasks : tasks.filter(task => task.status !== 'fail'); } function onChange(e) { var _a; return (0, _tslib.__awaiter)(this, void 0, void 0, function* () { e.persist(); const { files: rawFiles } = e.target; if (!rawFiles) return; let files = [].slice.call(rawFiles); e.target.value = ''; // HACK: fix the same file doesn't trigger onChange if (props.beforeUpload) { const postFiles = files.map(file => processFile(file, files)); yield Promise.all(postFiles).then(filesList => { files = filesList.filter(Boolean); }); } if (files.length === 0) { return; } if (maxCount > 0) { const exceed = value.length + files.length - maxCount; if (exceed > 0) { files = files.slice(0, files.length - exceed); (_a = props.onCountExceed) === null || _a === void 0 ? void 0 : _a.call(props, exceed); } } const newTasks = files.map(file => ({ id: idCountRef.current++, status: 'pending', file })); setTasks(prev => [...getFinalTasks(prev), ...newTasks]); const newVal = []; yield Promise.all(newTasks.map((currentTask, index) => (0, _tslib.__awaiter)(this, void 0, void 0, function* () { try { const result = yield props.upload(currentTask.file); newVal[index] = result; setTasks(prev => { return prev.map(task => { if (task.id === currentTask.id) { return Object.assign(Object.assign({}, task), { status: 'success', url: result.url }); } return task; }); }); } catch (e) { setTasks(prev => { return prev.map(task => { if (task.id === currentTask.id) { return Object.assign(Object.assign({}, task), { status: 'fail' }); } return task; }); }); throw e; } }))).catch(error => console.error(error)); setValue(prev => prev.concat(newVal)); }); } const imageViewerHandlerRef = (0, _react.useRef)(null); function previewImage(index) { imageViewerHandlerRef.current = _imageViewer.default.Multi.show({ images: value.map(fileItem => fileItem.url), defaultIndex: index, onClose: () => { imageViewerHandlerRef.current = null; } }); } (0, _ahooks.useUnmount)(() => { var _a; (_a = imageViewerHandlerRef.current) === null || _a === void 0 ? void 0 : _a.close(); }); const finalTasks = getFinalTasks(tasks); const showUpload = props.showUpload && (maxCount === 0 || value.length + finalTasks.length < maxCount); const renderImages = () => { return value.map((fileItem, index) => { var _a, _b; const originNode = _react.default.createElement(_previewItem.default, { key: (_a = fileItem.key) !== null && _a !== void 0 ? _a : index, url: (_b = fileItem.thumbnailUrl) !== null && _b !== void 0 ? _b : fileItem.url, deletable: props.deletable, deleteIcon: props.deleteIcon, imageFit: props.imageFit, onClick: () => { if (props.preview) { previewImage(index); } onPreview && onPreview(index, fileItem); }, onDelete: () => (0, _tslib.__awaiter)(void 0, void 0, void 0, function* () { var _c; const canDelete = yield (_c = props.onDelete) === null || _c === void 0 ? void 0 : _c.call(props, fileItem); if (canDelete === false) return; setValue(value.filter((x, i) => i !== index)); }) }); return renderItem ? renderItem(originNode, fileItem, value) : originNode; }); }; const contentNode = _react.default.createElement(_react.default.Fragment, null, renderImages(), tasks.map(task => { if (!props.showFailed && task.status === 'fail') { return null; } return _react.default.createElement(_previewItem.default, { key: task.id, file: task.file, deletable: task.status !== 'pending', deleteIcon: props.deleteIcon, status: task.status, imageFit: props.imageFit, onDelete: () => { setTasks(tasks.filter(x => x.id !== task.id)); } }); }), _react.default.createElement("div", { className: `${classPrefix}-upload-button-wrap`, style: showUpload ? undefined : { display: 'none' } }, props.children || _react.default.createElement("span", { className: `${classPrefix}-cell ${classPrefix}-upload-button`, role: 'button', "aria-label": locale.ImageUploader.upload }, _react.default.createElement("span", { className: `${classPrefix}-upload-button-icon` }, _react.default.createElement(_antdMobileIcons.AddOutline, null))), !props.disableUpload && _react.default.createElement("input", { ref: inputRef, capture: props.capture, accept: props.accept, multiple: props.multiple, type: 'file', className: `${classPrefix}-input`, onChange: onChange, "aria-hidden": true }))); (0, _react.useImperativeHandle)(ref, () => ({ get nativeElement() { return inputRef.current; } })); return (0, _nativeProps.withNativeProps)(props, _react.default.createElement("div", { className: classPrefix, ref: containerRef }, columns ? _react.default.createElement(_grid.default, { className: `${classPrefix}-grid`, columns: columns, style: style }, _react.default.createElement("div", { className: `${classPrefix}-gap-measure`, ref: gapMeasureRef }), contentNode.props.children) : _react.default.createElement(_space.default, { className: `${classPrefix}-space`, wrap: true, block: true }, contentNode.props.children))); }); exports.ImageUploader = ImageUploader;