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

86 lines 5.25 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useEffect, useRef, useState } from 'react'; import clsx from 'clsx'; import { useMergeRefs, useUniqueId, warnOnce } from '@awsui/component-toolkit/internal'; import { useSingleTabStopNavigation } from '@awsui/component-toolkit/internal'; import { getAnalyticsMetadataAttribute, } from '@awsui/component-toolkit/internal/analytics-metadata'; import InternalButton from '../button/internal'; import { useFormFieldContext } from '../contexts/form-field'; import { getBaseProps } from '../internal/base-component/index.js'; import ScreenreaderOnly from '../internal/components/screenreader-only'; import { fireNonCancelableEvent } from '../internal/events'; import checkControlled from '../internal/hooks/check-controlled'; import useForwardFocus from '../internal/hooks/forward-focus'; import { joinStrings } from '../internal/utils/strings'; import styles from './styles.css.js'; const InternalFileInput = React.forwardRef(({ accept, ariaRequired, ariaLabel, multiple = false, value, onChange, variant = 'button', children, __internalRootRef, __inputClassName, __inputNativeAttributes, __injectAnalyticsComponentMetadata, ...restProps }, ref) => { var _a; const baseProps = getBaseProps(restProps); const uploadInputRef = useRef(null); const containerRef = useRef(null); const mergedRef = useMergeRefs(__internalRootRef, containerRef); const uploadButtonLabelId = useUniqueId('upload-button-label'); const formFieldContext = useFormFieldContext(restProps); const selfControlId = useUniqueId('upload-input'); const controlId = (_a = formFieldContext.controlId) !== null && _a !== void 0 ? _a : selfControlId; useForwardFocus(ref, uploadInputRef); const [isFocused, setIsFocused] = useState(false); const onUploadButtonClick = () => { var _a; return (_a = uploadInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }; const onUploadInputFocus = () => { setIsFocused(true); }; const onUploadInputBlur = () => setIsFocused(false); const onUploadInputChange = ({ target }) => { fireNonCancelableEvent(onChange, { value: target.files ? Array.from(target.files) : [] }); }; checkControlled('FileInput', 'value', value, 'onChange', onChange); const nativeAttributes = { 'aria-label': ariaLabel || children, 'aria-labelledby': joinStrings(formFieldContext.ariaLabelledby, uploadButtonLabelId), 'aria-describedby': formFieldContext.ariaDescribedby, ...__inputNativeAttributes, }; if (formFieldContext.invalid) { nativeAttributes['aria-invalid'] = true; } if (ariaRequired) { nativeAttributes['aria-required'] = true; } if (variant === 'icon' && !ariaLabel) { warnOnce('FileInput', 'Aria label is required with icon variant.'); } // Synchronizing component's value with the native file input state. useEffect(() => { /* istanbul ignore next: The DataTransfer is not available in jsdom. */ if (window.DataTransfer) { const dataTransfer = new DataTransfer(); for (const file of value) { dataTransfer.items.add(file); } uploadInputRef.current.files = dataTransfer.files; } if (uploadInputRef.current) { uploadInputRef.current.value = ''; // reset value to allow calling onChange when the same file is uploaded again } }, [value]); const { tabIndex } = useSingleTabStopNavigation(uploadInputRef); const analyticsLabel = variant === 'button' && children ? 'button' : 'input'; const componentAnalyticsMetadata = { name: 'awsui.FileInput', label: analyticsLabel, }; const analyticsMetadata = { detail: { label: analyticsLabel } }; if (__injectAnalyticsComponentMetadata) { analyticsMetadata.component = componentAnalyticsMetadata; } return (React.createElement("div", { ...baseProps, ref: mergedRef, className: clsx(baseProps.className, styles.root), ...getAnalyticsMetadataAttribute(analyticsMetadata) }, React.createElement("input", { id: controlId, ref: uploadInputRef, type: "file", hidden: false, multiple: multiple, accept: accept, onChange: onUploadInputChange, onFocus: onUploadInputFocus, onBlur: onUploadInputBlur, className: clsx(styles['file-input'], styles.hidden, __inputClassName), tabIndex: tabIndex, ...nativeAttributes }), React.createElement(InternalButton, { iconName: "upload", variant: variant === 'icon' ? 'icon' : undefined, formAction: "none", onClick: onUploadButtonClick, className: clsx(styles['file-input-button'], { [styles['force-focus-outline-button']]: isFocused && variant === 'button', [styles['force-focus-outline-icon']]: isFocused && variant === 'icon', }), nativeButtonAttributes: { tabIndex: -1, 'aria-hidden': true }, __skipNativeAttributesWarnings: true }, variant === 'button' && children), React.createElement(ScreenreaderOnly, { id: uploadButtonLabelId }, ariaLabel || children))); }); export default InternalFileInput; //# sourceMappingURL=internal.js.map