UNPKG

@talend/react-forms

Version:

React forms library based on json schema form.

184 lines (181 loc) 5.98 kB
/* eslint-disable jsx-a11y/no-autofocus */ import { useState } from 'react'; import { withTranslation } from 'react-i18next'; import PropTypes from 'prop-types'; import { Form, SkeletonInput } from '@talend/design-system'; import { I18N_DOMAIN_FORMS } from '../../../constants'; import { getLabelProps } from '../../utils/labels'; import { extractDataAttributes } from '../../utils/properties'; import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; export const 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] = 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__*/_jsx(_Fragment, { children: loading ? /*#__PURE__*/_jsx(SkeletonInput, {}) : /*#__PURE__*/_jsx(Form.File, { label: 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, ...extractDataAttributes(schema) }) }); }; if (process.env.NODE_ENV !== 'production') { FileWidget.propTypes = { id: PropTypes.string, isValid: PropTypes.bool, errorMessage: PropTypes.string, onChange: PropTypes.func.isRequired, onFinish: PropTypes.func.isRequired, onTrigger: PropTypes.func, required: PropTypes.bool, schema: PropTypes.shape({ accept: PropTypes.string, autoFocus: PropTypes.bool, description: PropTypes.string, disabled: PropTypes.bool, placeholder: PropTypes.string, readOnly: PropTypes.bool, required: PropTypes.bool, title: PropTypes.string, labelProps: PropTypes.object, type: PropTypes.string, triggers: PropTypes.arrayOf(PropTypes.object), hint: PropTypes.shape({ icon: PropTypes.string, className: PropTypes.string, overlayComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.string]).isRequired, overlayPlacement: PropTypes.string }) }), value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), valueIsUpdating: PropTypes.bool }; } FileWidget.defaultProps = { isValid: true, schema: {} }; export { FileWidget, base64Decode, getFileName }; export default withTranslation(I18N_DOMAIN_FORMS)(FileWidget); //# sourceMappingURL=File.component.js.map