diff --git a/src/toolbar/OpenFileButton.tsx b/src/toolbar/OpenFileButton.tsx index 58e1cf51..fa7dffbf 100644 --- a/src/toolbar/OpenFileButton.tsx +++ b/src/toolbar/OpenFileButton.tsx @@ -2,9 +2,9 @@ // Copyright (c) 2020-2021 The Pybricks Authors import { Button, Intent, Position, Spinner, Tooltip } from '@blueprintjs/core'; -import { WithI18nProps, withI18n } from '@shopify/react-i18n'; +import { useI18n } from '@shopify/react-i18n'; import React from 'react'; -import Dropzone, { FileRejection } from 'react-dropzone'; +import Dropzone from 'react-dropzone'; import { tooltipDelay } from '../app/constants'; import { TooltipId } from './i18n'; import en from './i18n.en.json'; @@ -32,114 +32,102 @@ export interface OpenFileButtonProps { readonly onClick?: () => void; } -type Props = OpenFileButtonProps & WithI18nProps; - /** * Button that opens a file chooser dialog or accepts files dropped on it. */ -class OpenFileButton extends React.Component { - constructor(props: Props) { - super(props); - this.onDropAccepted = this.onDropAccepted.bind(this); - this.onDropRejected = this.onDropRejected.bind(this); - } +const OpenFileButton: React.FC = (props) => { + const [i18n] = useI18n({ + id: 'openFileButton', + translations: { en }, + fallback: en, + }); - private onDropAccepted(acceptedFiles: File[]): void { - // should only be one file since multiple={false} - acceptedFiles.forEach((f) => { - const reader = new FileReader(); + return ( + { + // should only be one file since multiple={false} + acceptedFiles.forEach((f) => { + const reader = new FileReader(); - reader.onabort = (): void => console.error('file reading was aborted'); - reader.onerror = (): void => console.error('file reading has failed'); - reader.onload = (): void => { - const binaryStr = reader.result; - if (binaryStr === null) { - throw Error('Unexpected null binaryStr'); - } - if (typeof binaryStr === 'string') { - throw Error('Unexpected string binaryStr'); - } - this.props.onFile(binaryStr); - }; - reader.readAsArrayBuffer(f); - }); - } - - private onDropRejected(fileRejections: FileRejection[]): void { - // should only be one file since multiple={false} - fileRejections.forEach((r) => { - this.props.onReject(r.file); - }); - } - - render(): JSX.Element { - return ( - - {({ getRootProps, getInputProps }): JSX.Element => ( - + console.error('file reading was aborted'); + reader.onerror = (): void => + console.error('file reading has failed'); + reader.onload = (): void => { + const binaryStr = reader.result; + if (binaryStr === null) { + throw Error('Unexpected null binaryStr'); + } + if (typeof binaryStr === 'string') { + throw Error('Unexpected string binaryStr'); + } + props.onFile(binaryStr); + }; + reader.readAsArrayBuffer(f); + }); + }} + onDropRejected={(fileRejections) => { + // should only be one file since multiple={false} + fileRejections.forEach((r) => { + props.onReject(r.file); + }); + }} + > + {({ getRootProps, getInputProps }): JSX.Element => ( + +
-
e.preventDefault()} // prevent focus + // onClick={this.props.onClick} + // breaks Dropzone when this.props.onClick is undefined + // so we have to do it the long way + {...(props.onClick ? { onClick: props.onClick } : {})} > - -
- - )} - - ); - } -} + + {props.showProgress ? ( + + ) : ( + {props.id} + )} + +
+
+ )} +
+ ); +}; -export default withI18n({ id: 'openFileButton', fallback: en, translations: { en } })( - OpenFileButton, -); +export default OpenFileButton;