@aws-northstar/ui
Version:
NorthStar Design System v2
75 lines (71 loc) • 4.76 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/** *******************************************************************************************************************
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. *
******************************************************************************************************************** */
import FormField from '@cloudscape-design/components/form-field';
import Button from '@cloudscape-design/components/button';
import TokenGroup from '@cloudscape-design/components/token-group';
import StatusIndicator from '@cloudscape-design/components/status-indicator';
import { useCallback, useRef, useMemo, useState } from 'react';
import useUniqueId from '../../hooks/useUniqueId';
import FileTokenLabel from './components/FileTokenLabel';
import SpaceBetween from '@cloudscape-design/components/space-between';
import getDisplaySize from './utils/getDisplaySize';
import getDisplayLastModified from './utils/getDisplayLastModified';
/**
* File upload is a form element that enables users to select one or multiple local files to upload.
* The file(s) can then be uploaded upon form submission or processed further in the browser.
*/
const FileUpload = ({ controlId, multi, label, description, constraintText, secondaryControl, errorText, info, buttonText, name, accept, onChange, files, ...props }) => {
const [selectedFiles, setSelectedFiles] = useState(files || []);
const id = useUniqueId(controlId);
const inputElement = useRef(null);
const displayedButtonText = useMemo(() => {
return buttonText || `Choose ${multi ? 'files' : 'file'}`;
}, [buttonText, multi]);
const testId = props['data-testid'] || 'file-upload';
const handleFileSelectionDismiss = useCallback(({ detail: { itemIndex } }) => {
const newFiles = selectedFiles.filter((_, index) => index !== itemIndex);
setSelectedFiles(newFiles);
onChange?.(newFiles);
}, [selectedFiles, setSelectedFiles, onChange]);
const footer = useMemo(() => {
if (!selectedFiles || selectedFiles.length === 0) {
return null;
}
if (!multi) {
return (_jsx(FileTokenLabel, { name: selectedFiles[0].name, size: selectedFiles[0].size, lastModified: selectedFiles[0].lastModified }));
}
const items = selectedFiles.map((file) => ({
label: file.name,
description: getDisplaySize(file.size),
tags: file.lastModified ? [getDisplayLastModified(file.lastModified)] : [],
iconSvg: _jsx(StatusIndicator, { type: "success" }),
}));
return (_jsx("div", { style: {
display: 'flex',
}, children: _jsx(TokenGroup, { items: items, onDismiss: handleFileSelectionDismiss, alignment: "vertical" }) }));
}, [selectedFiles, multi, handleFileSelectionDismiss]);
const handleFileSelectionButtonClick = useCallback(() => {
inputElement.current?.click();
}, []);
const handleFileSelectionChange = useCallback((event) => {
const { files } = event.target;
const newSelectedFiles = files ? Array.from(files).filter((file) => file) : [];
const newFiles = multi ? [...selectedFiles, ...newSelectedFiles] : newSelectedFiles;
setSelectedFiles(newFiles);
onChange?.(newFiles);
}, [selectedFiles, setSelectedFiles, onChange, multi]);
return (_jsxs(SpaceBetween, { direction: "vertical", size: "m", children: [_jsxs(FormField, { ...props, controlId: id, label: label, info: info, description: description, constraintText: constraintText, secondaryControl: secondaryControl, errorText: errorText, "data-testid": testId, children: [_jsx("input", { ref: inputElement, id: id, name: name, style: { display: 'none' }, type: "file", multiple: multi, accept: accept, onChange: handleFileSelectionChange, "data-testid": `${testId}-input` }), _jsx(Button, { "data-testid": `${testId}-button`, iconName: "upload", onClick: handleFileSelectionButtonClick, children: displayedButtonText })] }), footer] }));
};
export default FileUpload;
export * from './types';