Repository: h2oai/wave
File: ui/src/file_upload.tsx (TypeScript)

Code before:
      margin: '20px 0'
    },
    uploadRemove: {
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    },
    compact: {
      position: 'relative'
    }
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple, required } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      { semanticColors: { errorText: errorTextColor } } = Fluent.useTheme(),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      rejectXhr = React.useRef<(reason?: any) => void>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            rejectXhr.current = () => {
              reject()
              xhr.abort()
              setPercentComplete(0)
            }
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              xhr.status >= 200 && xhr.status < 300 ? resolve(xhr) : reject(xhr)
            }
          })
          const { files } = JSON.parse(responseText)

Review comment (suggestion):
We could maybe make this a CSS var (`--errorText`) and set it on theme change. Would make also future code simpler.

Code after:
      position: 'absolute',
      top: 2,
      right: 2,
      height: 28
    },
    uploadMessageBar: {
      margin: '20px 0'
    },
    uploadRemove: {
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    },
    compact: {
      position: 'relative'
    }
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple, required } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      rejectXhr = React.useRef<(reason?: any) => void>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            rejectXhr.current = () => {
              reject()
              xhr.abort()
              setPercentComplete(0)
            }
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {