UNPKG

@awsui/components-react

Version:

On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en

88 lines 7.88 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useRef, useState } from 'react'; import clsx from 'clsx'; import { useMergeRefs, useUniqueId, warnOnce } from '@awsui/component-toolkit/internal'; import InternalBox from '../box/internal'; import { useFormFieldContext } from '../contexts/form-field'; import InternalFileDropzone from '../file-dropzone/internal'; import { useFilesDragging } from '../file-dropzone/use-files-dragging'; import InternalFileInput from '../file-input/internal'; import InternalFileTokenGroup from '../file-token-group/internal'; import { ConstraintText, FormFieldError, FormFieldWarning } from '../form-field/internal'; import { useInternalI18n } from '../i18n/context'; import { getBaseProps } from '../internal/base-component'; import { fireNonCancelableEvent } from '../internal/events'; import checkControlled from '../internal/hooks/check-controlled'; import { useListFocusController } from '../internal/hooks/use-list-focus-controller'; import { joinStrings } from '../internal/utils/strings'; import InternalSpaceBetween from '../space-between/internal'; import fileInputStyles from '../file-input/styles.css.js'; import tokenListStyles from '../internal/components/token-list/styles.css.js'; import styles from './styles.css.js'; export default React.forwardRef(InternalFileUpload); function InternalFileUpload({ accept, ariaRequired, multiple = false, onChange, value, tokenLimit, showFileSize, showFileLastModified, showFileThumbnail, i18nStrings, __internalRootRef, constraintText, errorText, warningText, fileErrors, fileWarnings, fileTokenAlignment = 'vertical', ...restProps }, externalRef) { var _a, _b, _c; const [nextFocusIndex, setNextFocusIndex] = useState(null); const tokenListRef = useListFocusController({ nextFocusIndex, onFocusMoved: target => { target.focus(); setNextFocusIndex(null); }, listItemSelector: `.${tokenListStyles['list-item']}`, showMoreSelector: `.${tokenListStyles.toggle}`, fallbackSelector: `.${fileInputStyles['file-input']}`, }); const i18n = useInternalI18n('file-upload'); const baseProps = getBaseProps(restProps); const metadata = { showFileSize, showFileLastModified, showFileThumbnail }; const errorId = useUniqueId('error-'); const warningId = useUniqueId('warning-'); const constraintTextId = useUniqueId('constraint-text-'); const fileInputRef = useRef(null); const ref = useMergeRefs(fileInputRef, externalRef); checkControlled('FileUpload', 'value', value, 'onChange', onChange); if (!multiple && value.length > 1) { warnOnce('FileUpload', 'Value must be an array of size 0 or 1 when `multiple=false`.'); } const handleFilesChange = (newFiles) => { const newValue = multiple ? [...value, ...newFiles] : newFiles[0] ? newFiles.slice(0, 1) : [...value]; fireNonCancelableEvent(onChange, { value: newValue }); }; const onFileRemove = (removeFileIndex) => { const newValue = value.filter((_, fileIndex) => fileIndex !== removeFileIndex); fireNonCancelableEvent(onChange, { value: newValue }); setNextFocusIndex(removeFileIndex); }; const { areFilesDragging } = useFilesDragging(); const showWarning = warningText && !errorText; if (warningText && errorText) { warnOnce('FileUpload', 'Both `errorText` and `warningText` exist. `warningText` will not be shown.'); } const formFieldContext = useFormFieldContext(restProps); const ariaDescribedBy = joinStrings((_a = restProps.ariaDescribedby) !== null && _a !== void 0 ? _a : formFieldContext.ariaDescribedby, errorText ? errorId : undefined, showWarning ? warningId : undefined, constraintText ? constraintTextId : undefined); const hasError = Boolean(errorText || (fileErrors === null || fileErrors === void 0 ? void 0 : fileErrors.filter(Boolean).length)); const invalid = restProps.invalid || formFieldContext.invalid || hasError; return (React.createElement(InternalSpaceBetween, { ...baseProps, size: "xs", className: clsx(baseProps.className, styles.root), __internalRootRef: __internalRootRef, ref: tokenListRef }, React.createElement(InternalBox, null, areFilesDragging ? (React.createElement(InternalFileDropzone, { onChange: event => handleFilesChange(event.detail.value) }, i18n('i18nStrings.dropzoneText', (_b = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.dropzoneText) === null || _b === void 0 ? void 0 : _b.call(i18nStrings, multiple), format => format({ multiple: `${multiple}` })))) : (React.createElement(InternalFileInput, { ref: ref, accept: accept, ariaRequired: ariaRequired, multiple: multiple, onChange: event => handleFilesChange(event.detail.value), value: value, ariaLabelledby: restProps.ariaLabelledby, controlId: restProps.controlId, ariaDescribedby: ariaDescribedBy, invalid: invalid }, i18n('i18nStrings.uploadButtonText', (_c = i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.uploadButtonText) === null || _c === void 0 ? void 0 : _c.call(i18nStrings, multiple), format => format({ multiple: `${multiple}` })))), (constraintText || errorText || warningText) && (React.createElement("div", { className: styles.hints }, errorText && (React.createElement(FormFieldError, { id: errorId, errorIconAriaLabel: i18n('i18nStrings.errorIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.errorIconAriaLabel) }, errorText)), showWarning && (React.createElement(FormFieldWarning, { id: warningId, warningIconAriaLabel: i18n('i18nStrings.warningIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.warningIconAriaLabel) }, warningText)), constraintText && (React.createElement(ConstraintText, { id: constraintTextId, hasValidationText: !!errorText || !!warningText }, constraintText))))), value.length > 0 ? (React.createElement(InternalFileTokenGroup, { limit: tokenLimit, alignment: fileTokenAlignment, items: value.map((file, fileIndex) => ({ file, errorText: fileErrors === null || fileErrors === void 0 ? void 0 : fileErrors[fileIndex], warningText: fileWarnings === null || fileWarnings === void 0 ? void 0 : fileWarnings[fileIndex], })), showFileLastModified: metadata.showFileLastModified, showFileSize: metadata.showFileSize, showFileThumbnail: metadata.showFileThumbnail, i18nStrings: { removeFileAriaLabel: i18n('i18nStrings.removeFileAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.removeFileAriaLabel, format => fileIndex => format({ fileIndex: fileIndex + 1 })), limitShowFewer: i18n('i18nStrings.limitShowFewer', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.limitShowFewer), limitShowMore: i18n('i18nStrings.limitShowMore', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.limitShowMore), formatFileSize: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.formatFileSize, formatFileLastModified: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.formatFileLastModified, errorIconAriaLabel: i18n('i18nStrings.errorIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.errorIconAriaLabel), warningIconAriaLabel: i18n('i18nStrings.warningIconAriaLabel', i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.warningIconAriaLabel), }, onDismiss: event => onFileRemove(event.detail.fileIndex) })) : null)); } //# sourceMappingURL=internal.js.map