UNPKG

chayns-components

Version:

A set of beautiful React components for developing chayns® applications.

294 lines (291 loc) 12.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _clsx = _interopRequireDefault(require("clsx")); var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireWildcard(require("react")); var _Icon = _interopRequireDefault(require("../../react-chayns-icon/component/Icon")); var _SmallWaitCursor = _interopRequireDefault(require("../../react-chayns-smallwaitcursor/component/SmallWaitCursor")); var _is = require("../../utils/is"); var _fileInputCall = _interopRequireDefault(require("../utils/fileInputCall")); var _supportsFileInput = _interopRequireDefault(require("../utils/supportsFileInput")); 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; } /** * @component */ /** * Accepts specified file types via dialog or drag and drop. */ class FileInput extends _react.PureComponent { constructor(props) { super(props); this.onDragEnter = (event, item, index) => { if (this.checkFileType(event.dataTransfer.items[0].type, item.types)) { this.itemRefs[index].classList.add('cc__file-input--hover'); } }; this.onDragLeave = index => { this.itemRefs[index].classList.remove('cc__file-input--hover'); }; this.onError = (item, errorMessage) => { if ((0, _is.isFunction)(item.onError)) { return item.onError(errorMessage); } return chayns.dialog.alert('', errorMessage); }; this.onChange = async (event, item, index) => { const { errorMessages } = this.props; const { files } = event.target; this.onDragLeave(index); if (files && files.length > 0) { this.setState({ isLoading: true }); const invalidFiles = []; const validFiles = []; for (let i = 0, l = files.length; i < l; i++) { const file = files[i]; if (!this.checkFileType(file.type, item.types)) { invalidFiles.push(file); this.onError(item, errorMessages.wrongFileType); } else if (item.maxNumberOfFiles > 0 && validFiles.length >= item.maxNumberOfFiles) { invalidFiles.push(file); this.onError(item, errorMessages.tooMuchFiles.replace('##NUMBER##', item.maxNumberOfFiles)); } else if (item.maxFileSize > 0 && file.size > item.maxFileSize) { this.onError(item, errorMessages.fileTooBig.replace('##SIZE##', `${Math.ceil(item.maxFileSize / (1024 * 1024))} MB`)); invalidFiles.push(file); } else { validFiles.push(file); } } item.onChange(validFiles, invalidFiles); this.setState({ isLoading: false }); } if (this.fileInputRefs[index]) { this.fileInputRefs[index].value = null; } }; this.onClick = async (event, item, index) => { const { hasMemoryAccess } = this.state; const { stopPropagation, errorMessages } = this.props; if (stopPropagation) event.stopPropagation(); if ((0, _is.isFunction)(item.onClick)) item.onClick(event); if (item.onChange) { if (this.needAppCall) { const compatibilityEvent = await (0, _fileInputCall.default)(); // TODO remove in future version this.onChange(compatibilityEvent, item, index); } else if (!hasMemoryAccess) { const result = await chayns.invokeCall({ action: 239 }, true); if (result.status === 1) { this.setState({ hasMemoryAccess: true }); if (event.isTrusted) { // trigger another click on file input after permission is granted, // but only when event was generated by user action to prevent multiple file select dialogs this.fileInputRefs[index].click(); } } else if (result.status === 2 && errorMessages.temporaryNoPermission) { this.onError(item, errorMessages.temporaryNoPermission); } else if (result.status === 3 && errorMessages.permanentNoPermission) { await this.onError(item, errorMessages.permanentNoPermission); chayns.invokeCall({ action: 239, value: { showAppInfo: true } }); } } } }; this.checkFileType = (fileType, supportedTypes) => { if (fileType === '') { return true; } for (let i = 0; i < supportedTypes.length; i += 1) { const type = supportedTypes[i]; if (type === FileInput.types.ALL) { return true; } if (type === fileType) { return true; } const fileTypeMatch = fileType.match(/(.)+\//g); const typeMatch = type.match(/(.)+\//g); if (type.match(/\/\*/g) && fileTypeMatch && typeMatch && fileTypeMatch[0] === typeMatch[0]) { return true; } } return false; }; this.itemRefs = []; this.fileInputRefs = []; this.needAppCall = !(0, _supportsFileInput.default)(); this.state = { hasMemoryAccess: !(chayns.env.isAndroid && (chayns.env.isApp || chayns.env.isMyChaynsApp) && (chayns.env.myChaynsAppVersion || chayns.env.appVersion) >= 6244), isLoading: false }; } render() { const { items, className, style, disabled } = this.props; const { hasMemoryAccess, isLoading } = this.state; return /*#__PURE__*/_react.default.createElement("div", { className: (0, _clsx.default)("cc__file-input cc__file-input--custom", className, disabled && 'cc__file-input--disabled'), style: style }, items.map((item, index) => /*#__PURE__*/_react.default.createElement("div", { className: (0, _clsx.default)('cc__file-input__split', item.className, (item.disabled || isLoading) && 'cc__file-input__split--disabled'), style: item.style // eslint-disable-next-line react/no-array-index-key , key: `item${index}` }, item.content && item.content.children ? item.content.children : /*#__PURE__*/_react.default.createElement("div", { className: "cc__file-input--placeholder", ref: ref => { this.itemRefs[index] = ref; }, onClick: event => this.onClick(event, item, index) }, item.onChange && !this.needAppCall ? /*#__PURE__*/_react.default.createElement("input", { style: !hasMemoryAccess ? { display: 'none' } : null, title: "", multiple: item.maxNumberOfFiles !== 1, directory: item.directory ? '' : null, webkitdirectory: item.directory ? '' : null, className: "cc__file-input__input", type: "file", onChange: event => this.onChange(event, item, index), accept: item.types, onDragEnter: event => this.onDragEnter(event, item, index), onDragLeave: () => this.onDragLeave(index), ref: ref => { this.fileInputRefs[index] = ref; } }) : null, !isLoading ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", { className: "cc__file-input__icon" }, /*#__PURE__*/_react.default.createElement(_Icon.default, { icon: item.content && item.content.icon ? item.content.icon : 'fa fa-upload' })), /*#__PURE__*/_react.default.createElement("div", { className: "cc__file-input__message" }, item.content && item.content.text ? item.content.text : 'Datei hochladen')) : /*#__PURE__*/_react.default.createElement(_SmallWaitCursor.default, { show: true, showBackground: false, className: "cc__file-input__wait-cursor" }))))); } } exports.default = FileInput; FileInput.types = { IMAGE: 'image/*', VIDEO: 'video/*', AUDIO: 'audio/*', ALL: '*' }; FileInput.typePresets = { TSIMG_CLOUD: ['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml', 'image/avif'], STREAMINGSERVICE: ['video/mp4', 'video/webm', 'video/avi', 'video/flv', 'video/wmv', 'video/mpg', 'video/quicktime'] }; FileInput.propTypes = { /** * A classname string that is applied to the root element. */ className: _propTypes.default.string, /** * A React style object that is applied to the root element. */ style: _propTypes.default.objectOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])), /** * Wether to stop propagation of click events to parent elements. */ stopPropagation: _propTypes.default.bool, /** * Disables any interaction with the component and renders it in a disabled * style. */ disabled: _propTypes.default.bool, /** * Custom error messages for the component. */ errorMessages: _propTypes.default.shape({ tooMuchFiles: _propTypes.default.string, fileTooBig: _propTypes.default.string, wrongFileType: _propTypes.default.string, permanentNoPermission: _propTypes.default.string, temporaryNoPermission: _propTypes.default.string }), /** * The different fields that will be shown in the file input. */ items: _propTypes.default.arrayOf(_propTypes.default.shape({ types: _propTypes.default.arrayOf(_propTypes.default.string), maxFileSize: _propTypes.default.number, maxNumberOfFiles: _propTypes.default.number, directory: _propTypes.default.bool, onClick: _propTypes.default.func, onChange: _propTypes.default.func, onError: _propTypes.default.func, className: _propTypes.default.string, style: _propTypes.default.objectOf(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])), disabled: _propTypes.default.bool, content: _propTypes.default.oneOfType([_propTypes.default.shape({ text: _propTypes.default.string, icon: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]) }), _propTypes.default.shape({ children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.arrayOf(_propTypes.default.node)]) })]) })) }; FileInput.defaultProps = { className: null, style: null, stopPropagation: false, disabled: false, errorMessages: { tooMuchFiles: 'Du kannst nur ##NUMBER## Dateien hochladen.', fileTooBig: 'Es sind nur Dateien bis ##SIZE## erlaubt.', wrongFileType: 'Mindestens eine Datei hat das falsche Dateiformat.', permanentNoPermission: 'Bitte überprüfe die Einstellungen Deiner App und erlaube den Dateizugriff auf Deinem Gerät.', temporaryNoPermission: null }, items: [{ types: [FileInput.types.ALL], maxFileSize: 4 * 1024 * 1024, // 4 MB maxNumberOfFiles: 0, // 0=infinity directory: false, onClick: null, onChange: null, onError: null, className: null, style: null, disabled: false, content: null }] }; FileInput.displayName = 'FileInput'; //# sourceMappingURL=FileInput.js.map