@talend/react-forms
Version:
React forms library based on json schema form.
195 lines (190 loc) • 6.75 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PRESIGNED_URL_TRIGGER_ACTION = exports.FileWidget = void 0;
exports.base64Decode = base64Decode;
exports.default = void 0;
exports.getFileName = getFileName;
var _react = require("react");
var _reactI18next = require("react-i18next");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _designSystem = require("@talend/design-system");
var _constants = require("../../../constants");
var _labels = require("../../utils/labels");
var _properties = require("../../utils/properties");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/* eslint-disable jsx-a11y/no-autofocus */
const PRESIGNED_URL_TRIGGER_ACTION = exports.PRESIGNED_URL_TRIGGER_ACTION = 'generatePresignedURL';
const BASE64_NAME = ';name=';
const BASE64_PREFIX = ';base64,';
/**
* Decode the base64 file name with multi-byte character support
* @param {string} filename The base64 value of the file name
* @returns {string} The decoded file name
*/
function base64Decode(filename) {
return decodeURIComponent(atob(filename).split('').map(c => {
return `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`;
}).join(''));
}
/**
* Extract the file name from the value
* @param {string} value The base64 value of the file.
* Looks like `data:text/xml;name=test.xml;base64,PD94bWwgdmVyc2l...`
* @param {Object} schema The widget schema to get triggers.
* @returns {string} The file name, for example: `test.xml`.
*/
function getFileName(value, schema) {
if (value && value.indexOf(BASE64_NAME) !== -1) {
return value.slice(value.indexOf(BASE64_NAME) + BASE64_NAME.length, value.indexOf(BASE64_PREFIX));
}
if (value && schema && schema.triggers) {
const uploadTrigger = schema.triggers.find(trigger => trigger.action === PRESIGNED_URL_TRIGGER_ACTION);
if (uploadTrigger) {
return base64Decode(value.split('.')[1]);
}
}
return value;
}
/**
* Add the file name to the data url.
* @param {string} value The base64 value of the file.
* Looks like `data:text/xml;base64,PD94bWwgdmVyc2l...`
* @param {string} fileName The file name, for exemple `test.xml`.
* @returns {(string|undefined)} the base 64 encoding of the file with the file name within.
* Looks like `data:text/xml;name=test.xml;base64,PD94bWwgdmVyc2l...`
* Or undefined if value is undefined.
*/
function getBase64(value, fileName) {
if (value && value.indexOf(BASE64_NAME) === -1) {
const fileNamePos = value.indexOf(BASE64_PREFIX);
if (fileNamePos !== -1) {
return [value.slice(0, fileNamePos), BASE64_NAME, fileName, value.slice(fileNamePos)].join('');
}
}
return value;
}
const FileWidget = props => {
const {
id,
isValid,
errorMessage,
onFinish,
onChange,
onTrigger,
schema,
valueIsUpdating,
value
} = props;
const {
accept,
autoFocus,
description,
disabled = false,
placeholder,
readOnly = false,
title,
labelProps,
required
} = schema;
const [loading, setLoading] = (0, _react.useState)(false);
const handleOnChange = event => {
event.persist();
const fileList = event.target.files;
if (fileList.length > 0) {
const file = fileList[0];
if (schema.triggers && schema.triggers.some(trigger => trigger.action === PRESIGNED_URL_TRIGGER_ACTION)) {
setLoading(true);
Promise.all(schema.triggers.map(trigger => {
if (trigger.action === PRESIGNED_URL_TRIGGER_ACTION && trigger.onEvent === 'change') {
return onTrigger(event, {
trigger,
schema
});
}
return Promise.resolve();
})).finally(() => setLoading(false));
} else {
const reader = new FileReader();
reader.onload = () => {
const data = getBase64(reader.result, file.name);
onChange(event, {
schema,
value: data
});
};
reader.readAsDataURL(file);
}
} else {
onChange(event, {
schema,
value: ''
});
}
};
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
children: loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_designSystem.SkeletonInput, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_designSystem.Form.File, {
label: (0, _labels.getLabelProps)(title, labelProps, schema.hint, required),
required: required,
accept: accept,
autoFocus: autoFocus,
name: `input-filename-${id}`,
id: `input-${id}`,
disabled: disabled || valueIsUpdating,
onBlur: event => onFinish(event, {
schema
}),
onChange: handleOnChange,
onDrop: handleOnChange,
placeholder: placeholder,
readOnly: readOnly,
files: value && [getFileName(value, schema)],
description: errorMessage || description,
hasError: !isValid,
"aria-invalid": !isValid,
"aria-required": schema.required,
...(0, _properties.extractDataAttributes)(schema)
})
});
};
exports.FileWidget = FileWidget;
if (process.env.NODE_ENV !== 'production') {
FileWidget.propTypes = {
id: _propTypes.default.string,
isValid: _propTypes.default.bool,
errorMessage: _propTypes.default.string,
onChange: _propTypes.default.func.isRequired,
onFinish: _propTypes.default.func.isRequired,
onTrigger: _propTypes.default.func,
required: _propTypes.default.bool,
schema: _propTypes.default.shape({
accept: _propTypes.default.string,
autoFocus: _propTypes.default.bool,
description: _propTypes.default.string,
disabled: _propTypes.default.bool,
placeholder: _propTypes.default.string,
readOnly: _propTypes.default.bool,
required: _propTypes.default.bool,
title: _propTypes.default.string,
labelProps: _propTypes.default.object,
type: _propTypes.default.string,
triggers: _propTypes.default.arrayOf(_propTypes.default.object),
hint: _propTypes.default.shape({
icon: _propTypes.default.string,
className: _propTypes.default.string,
overlayComponent: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.string]).isRequired,
overlayPlacement: _propTypes.default.string
})
}),
value: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
valueIsUpdating: _propTypes.default.bool
};
}
FileWidget.defaultProps = {
isValid: true,
schema: {}
};
var _default = exports.default = (0, _reactI18next.withTranslation)(_constants.I18N_DOMAIN_FORMS)(FileWidget);
//# sourceMappingURL=File.component.js.map