/* Copyright (c) 2018-2020 Uber Technologies, Inc. This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. */ // @flow import * as React from 'react'; import Dropzone from 'react-dropzone'; import {LocaleContext} from '../locale/index.js'; import {Block} from '../block/index.js'; import {Button, KIND, SHAPE, SIZE as BUTTON_SIZE} from '../button/index.js'; import {getOverrides} from '../helpers/overrides.js'; import {ProgressBar} from '../progress-bar/index.js'; import {StyledSpinnerNext, SIZE as SPINNER_SIZE} from '../spinner/index.js'; import { StyledRoot, StyledFileDragAndDrop, StyledContentMessage, StyledContentSeparator, StyledErrorMessage, StyledHiddenInput, } from './styled-components.js'; import type {PropsT} from './types.js'; function prependStyleProps(styleProps) { return Object.keys(styleProps).reduce((nextStyleProps, currentKey) => { nextStyleProps[`$${currentKey}`] = styleProps[currentKey]; return nextStyleProps; }, {}); } function FileUploader(props: PropsT) { const {overrides = {}} = props; const [Root, rootProps] = getOverrides(overrides.Root, StyledRoot); const [FileDragAndDrop, fileDragAndDropProps] = getOverrides( overrides.FileDragAndDrop, StyledFileDragAndDrop, ); const [ContentMessage, contentMessageProps] = getOverrides( overrides.ContentMessage, StyledContentMessage, ); const [ContentSeparator, contentSeparatorProps] = getOverrides( overrides.ContentSeparator, StyledContentSeparator, ); const [ErrorMessage, errorMessageProps] = getOverrides( overrides.ErrorMessage, StyledErrorMessage, ); const [HiddenInput, hiddenInputProps] = getOverrides( overrides.HiddenInput, StyledHiddenInput, ); const [ButtonComponent, buttonProps] = getOverrides( overrides.ButtonComponent, Button, ); const [SpinnerComponent, spinnerProps] = getOverrides( overrides.Spinner, StyledSpinnerNext, ); const afterFileDrop = !!( props.progressAmount || props.progressMessage || props.errorMessage ); return ( {renderProps => { const {getRootProps, getInputProps, open, ...styleProps} = renderProps; const prefixedStyledProps = prependStyleProps({ ...styleProps, isDisabled: props.disabled, afterFileDrop, }); const getRootPropsArgs: { onClick?: (SyntheticEvent) => void, tabIndex: string, } = { ...(props.disableClick ? {onClick: evt => evt.preventDefault()} : {}), tabIndex: '-1', }; return ( {locale => ( {!afterFileDrop && ( {locale.fileuploader.dropFilesToUpload} {/* TODO(v11): ContentSeparator potentially can be removed in the next major version */} {locale.fileuploader.or} ({ marginTop: $theme.sizing.scale500, }), }, }} {...prefixedStyledProps} {...buttonProps} > {locale.fileuploader.browseFiles} )} {afterFileDrop && ( {/** * Below checks typeof value to ensure if progressAmount = 0 we will * render the progress bar rather than the spinner. Providing a number * value implies that we expect to have some progress percent in the * future. We do not want to flash the spinner in this case. */} {typeof props.progressAmount === 'number' ? ( ({ backgroundColor: props.errorMessage ? $theme.colors.negative : $theme.colors.accent, }), }, }} /> ) : props.errorMessage ? null : ( )} {(props.errorMessage || props.progressMessage) && props.errorMessage ? ( {props.errorMessage} ) : ( {props.progressMessage} )} {props.errorMessage ? ( { props.onRetry && props.onRetry(); }} aria-invalid={Boolean(props.errorMessage)} aria-describedby={props['aria-describedby']} aria-errormessage={props.errorMessage} > {locale.fileuploader.retry} ) : ( { props.onCancel && props.onCancel(); }} aria-describedby={props['aria-describedby']} overrides={{ BaseButton: { style: ({$theme}) => ({ color: $theme.colors.contentNegative, }), }, }} > {locale.fileuploader.cancel} )} )} )} ); }} ); } FileUploader.defaultProps = { disableClick: true, overrides: {}, }; export default FileUploader; declare var __DEV__: boolean; declare var __NODE__: boolean; declare var __BROWSER__: boolean;