メインコンテンツまでスキップ

FileInput

選ばれたファイルを File として渡すコンポーネント。

読み込むのは呼び出し側の仕事です。音声ファイルなら decodeAudioData、プリセットなら JSON.parse へ。このコンポーネントは、ブラウザがバイト列を渡してきたところで止まります。

Source Style
Loading...
function App() {
  const [files, setFiles] = useState<File[]>([])
  const [rejected, setRejected] = useState<File[]>([])

  return (
    <div>
      <FileInput.Root
        className={fileInputTheme.root}
        accept="audio/*"
        multiple
        onChange={(files) => {
          setRejected([])
          setFiles(files)
        }}
        onReject={(files) => setRejected(files)}
      >
        <FileInput.Trigger className={fileInputTheme.trigger}>
          Choose audio
        </FileInput.Trigger>
        <span>{files.length > 0 ? `${files.length} selected` : 'No file'}</span>
      </FileInput.Root>
      <ul>
        {files.map((file) => (
          <li key={file.name}>
            {file.name} ({file.type || 'unknown type'})
          </li>
        ))}
      </ul>
      {rejected.length > 0 && (
        <p>Not audio: {rejected.map((file) => file.name).join(', ')}</p>
      )}
    </div>
  )
}

インポート​

import { FileInput } from '@tremolo-ui/react'

このコンポーネントが引き受けること​

accept は受け取るときにもう一度照合します。 ブラウザはこの属性をピッカーへのヒントとして扱うので、「すべてのファイル」に切り替えれば何でも選べます。一致しなかったものは onChange ではなく onReject に届くので、黙って何も起きない代わりに理由を表示できます。

同じファイルを 2 回選べます。 ファイル入力は選択が変わらないと change イベントを発火しないので、直前に選んだファイルをもう一度選んでも何も起きないはずでした。読み取った時点で value を空にしています。

コントロールは今もネイティブの input です。 ツリーの中に、見えないけれどタブ順には残る形で置いてあります。フォーカスを取り、Enter でピッカーを開き、アクセシブルな名前を持つのはこの要素です。FileInput.Trigger はその <label> なので、独自の JavaScript 無しにクリックがピッカーへ届きます。

フォーカスが当たるのは見えない要素なので、フォーカスリングは親から描いてください。デモのテーマは .root の :focus-within でそうしています。

input の ARIA 属性は、Root が描くラッパーに残さず Root が受け取ってコントロールへ渡します。「WAV / AIFF、10 MB まで」のような補足は aria-describedby で指し、FileInput.Trigger を使わず名前を取れない場合は aria-label で付けられます。

ドロップも受け取る​

FileInput が答えるのはクリックです。ページにドロップされたファイルを受け取るには DropZone を見てください。同じ File[] を報告します。

API リファレンス​

各パートには、そのパート固有の props があります。描画する要素の属性(className や style など)も受け取ります。

Svelte / Vue でも props は同じで、書き方だけがそれぞれの流儀になります(className ではなく class、bind:value や v-model、中身は snippet やスロットなど)。Svelte と Vue を参照してください。

状態は data 属性として要素に付くので、セレクタひとつで届きます(スタイリング)。属性は、その状態が on のときだけ存在します。

Root​

設定と、隠された <input type="file"> を持ち、選ばれたものを報告します。

Prop型既定値
acceptstring—
multiplebooleanfalse
disabledbooleanfalse
onChange(files: File[]) => void—
onReject(files: File[]) => void—
children*ReactNode—

すべての説明: FileInputProps

Data attributeValues
[data-disabled]disabled が設定されているときに存在します

Trigger​

ピッカーを開き、スクリーンリーダー向けに input へ名前を付けます。<label> として描画されます。

Prop型既定値
children*ReactNode—

すべての説明: FileInputTriggerProps

Data attributeValues
[data-disabled]Root に disabled が設定されているときに存在します