@itwin/itwinui-react
Version:
A react component library for iTwinUI
201 lines (200 loc) • 6.36 kB
JavaScript
import * as React from 'react';
import {
getWindow,
SvgDocument,
useMergedRefs,
useSafeContext,
useId,
mergeEventHandlers,
polymorphic,
Box,
} from '../../utils/index.js';
import cx from 'classnames';
import { FileEmptyCard } from './FileEmptyCard.js';
import { Anchor } from '../Typography/Anchor.js';
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
let toBytes = (bytes) => {
let units = [' bytes', 'KB', 'MB', 'GB', 'TB'];
let i = 0;
while (bytes >= 1024 && ++i) bytes /= 1024;
return bytes.toFixed(bytes < 10 && i > 0 ? 2 : 0) + units[i];
};
let toDate = (dateNumber) => {
let date = new Date(dateNumber);
return date.toDateString() + ' ' + date.toLocaleTimeString();
};
let FileUploadCardIcon = polymorphic.span('iui-file-card-icon', {
children: React.createElement(SvgDocument, null),
});
if ('development' === process.env.NODE_ENV)
FileUploadCardIcon.displayName = 'FileUploadCard.Icon';
let FileUploadCardInfo = polymorphic.span('iui-file-card-text');
if ('development' === process.env.NODE_ENV)
FileUploadCardInfo.displayName = 'FileUploadCard.Info';
let FileUploadCardTitle = React.forwardRef((props, ref) => {
let { children, className, ...rest } = props;
let { files } = useSafeContext(FileUploadCardContext);
let title =
files.length > 1 ? files.length + ' files selected' : files[0].name;
return React.createElement(
Box,
{
as: 'span',
className: cx('iui-file-card-title', className),
ref: ref,
...rest,
},
children ?? title,
);
});
if ('development' === process.env.NODE_ENV)
FileUploadCardTitle.displayName = 'FileUploadCard.Title';
let FileUploadCardDescription = React.forwardRef((props, ref) => {
let { children, className, ...rest } = props;
let { files } = useSafeContext(FileUploadCardContext);
let description =
files.length > 1
? files[0].name + ', ' + files[1].name
: toBytes(files[0].size) + ' ' + toDate(files[0].lastModified);
if (files.length > 2)
description += ', and ' + (files.length - 2) + ' others';
return React.createElement(
Box,
{
as: 'span',
className: cx('iui-file-card-description', className),
ref: ref,
...rest,
},
children ?? description,
);
});
if ('development' === process.env.NODE_ENV)
FileUploadCardDescription.displayName = 'FileUploadCard.Description';
let FileUploadCardAction = polymorphic.div('iui-file-card-action');
if ('development' === process.env.NODE_ENV)
FileUploadCardAction.displayName = 'FileUploadCard.Action';
let FileUploadCardInputLabel = React.forwardRef((props, ref) => {
let { children, ...rest } = props;
let { inputId } = useSafeContext(FileUploadCardContext);
return React.createElement(
Anchor,
{
as: 'label',
ref: ref,
htmlFor: inputId,
...rest,
},
children,
);
});
if ('development' === process.env.NODE_ENV)
FileUploadCardInputLabel.displayName = 'FileUploadCard.InputLabel';
let FileUploadCardInput = React.forwardRef((props, ref) => {
let { children, onChange, id, ...rest } = props;
let { files, onFilesChange, setInternalFiles, inputId, setInputId } =
useSafeContext(FileUploadCardContext);
let setNativeFilesRef = React.useCallback(
(node) => {
if (!node || !getWindow()?.DataTransfer) return;
let dataTransfer = new DataTransfer();
dataTransfer.items.clear();
Array.from(files).forEach((file) => dataTransfer.items.add(file));
node.files = dataTransfer.files;
},
[files],
);
let refs = useMergedRefs(ref, setNativeFilesRef);
React.useEffect(() => {
if (id && id !== inputId) setInputId(id);
}, [id, inputId, setInputId]);
return React.createElement(
React.Fragment,
null,
React.createElement(VisuallyHidden, {
as: 'input',
type: 'file',
unhideOnFocus: false,
onChange: mergeEventHandlers(onChange, (e) => {
let _files = Array.from(e.currentTarget.files || []);
onFilesChange?.(_files);
setInternalFiles(_files);
}),
ref: refs,
id: id ?? inputId,
...rest,
}),
children,
);
});
if ('development' === process.env.NODE_ENV)
FileUploadCardInput.displayName = 'FileUploadCard.Input';
let FileUploadCardComponent = React.forwardRef((props, ref) => {
let {
className,
children,
files: filesProp,
onFilesChange,
emptyCard = React.createElement(FileEmptyCard, null),
input,
...rest
} = props;
let [internalFiles, setInternalFiles] = React.useState();
let uid = useId();
let [inputId, setInputId] = React.useState(uid);
let files = filesProp ?? internalFiles ?? [];
return React.createElement(
FileUploadCardContext.Provider,
{
value: {
files,
onFilesChange,
setInternalFiles,
inputId,
setInputId,
},
},
files?.length
? React.createElement(
Box,
{
className: cx('iui-file-card', className),
ref: ref,
...rest,
},
children ??
React.createElement(
React.Fragment,
null,
React.createElement(FileUploadCard.Icon, null),
React.createElement(
FileUploadCard.Info,
null,
React.createElement(FileUploadCard.Title, null),
React.createElement(FileUploadCard.Description, null),
),
React.createElement(
FileUploadCard.Action,
null,
React.createElement(FileUploadCard.InputLabel, null, 'Replace'),
),
),
)
: emptyCard,
input ?? React.createElement(FileUploadCard.Input, null),
);
});
export const FileUploadCard = Object.assign(FileUploadCardComponent, {
Icon: FileUploadCardIcon,
Info: FileUploadCardInfo,
Title: FileUploadCardTitle,
Description: FileUploadCardDescription,
Action: FileUploadCardAction,
InputLabel: FileUploadCardInputLabel,
Input: FileUploadCardInput,
});
if ('development' === process.env.NODE_ENV)
FileUploadCard.displayName = 'FileUploadCard';
export const FileUploadCardContext = React.createContext(void 0);
if ('development' === process.env.NODE_ENV)
FileUploadCardContext.displayName = 'FileUploadCardContext';