chayns-components
Version:
A set of beautiful React components for developing chayns® applications.
294 lines (291 loc) • 12.1 kB
JavaScript
"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