# FileField

Das FileField stellt eine kompakte Lösung dar, um Uploads von Dateien zu ermöglichen.

## Overview

# Playground

Verwende `<FileField />`, um ein FileField darzustellen. Innerhalb des
FileFields kommen die Components [Label](/04-components/content/label/overview)
und [Button](/04-components/actions/button/overview) zum Einsatz.

```tsx
import {
  Button,
  FileField,
  Label,
} from "@mittwald/flow-react-components";

<FileField>
  <Label>Zertifikat</Label>
  <Button variant="outline" color="secondary">
    Auswählen
  </Button>
</FileField>
```

---

# Disabled

Ist das FileField **disabled**, ist keine Interaktion möglich. Sobald die
Ursache behoben ist, kann es wieder wie gewohnt verwendet werden.

```tsx
import {
  Button,
  FileField,
  Label,
} from "@mittwald/flow-react-components";

<FileField isDisabled>
  <Label>Zertifikat</Label>
  <Button variant="outline" color="secondary">
    Auswählen
  </Button>
</FileField>
```

---

# Mit FieldDescription

Um wichtige Hinweise zum FileField bereitzustellen, kann unterhalb eine
`<FieldDescription />` eingebaut werden. In vielen Fällen empfiehlt es sich, die
erlaubten Dateitypen dort anzugeben.

```tsx
import {
  Button,
  FieldDescription,
  FileField,
  Label,
} from "@mittwald/flow-react-components";

<FileField accept={"image/png, image/jpeg"}>
  <Label>Zertifikat</Label>
  <Button variant="outline" color="secondary">
    Auswählen
  </Button>
  <FieldDescription>
    Erlaubte Dateitypen sind .jpeg und .png
  </FieldDescription>
</FileField>
```

---

# Invalid

Bei ungültiger Eingabe wird das FileField invalidiert. Über `<FieldError />`
kann eine entsprechende
[Fehlermeldung](/02-foundations/03-content-guidelines/03-fehlermeldungen)
ausgegeben werden.

```tsx
import {
  Button,
  FieldError,
  FileField,
  Label,
} from "@mittwald/flow-react-components";

<FileField isInvalid>
  <Label>Zertifikat</Label>
  <Button variant="outline" color="secondary">
    Auswählen
  </Button>
  <FieldError>
    Wir konnten das Zertifikat nicht hochladen. Bitte
    verwende eine .txt-Datei.
  </FieldError>
</FileField>
```

---

# Mehere Dateien

Über die Property `multiple` wird das gleichzeitige Hochladen mehrerer Dateien
ermöglicht. Beim erneutem Hochladen werden bestehende Dateien ersetzt. Ein
Beispiel für das Hochladen und Verwalten mehrerer Dateien findest du im
Codesnippet [Multi Upload](/03-patterns/02-codesnippets/multi-upload).

```tsx
import {
  Button,
  FileField,
  Label,
  Section,
  LabeledValue,
  Text,
} from "@mittwald/flow-react-components";
import { useState } from "react";

export default () => {
  const [files, setFiles] = useState<FileList | null>(null);

  return (
    <Section>
      <FileField multiple onChange={setFiles}>
        <Label>Dateien</Label>
        <Button variant="outline" color="secondary">
          Auswählen
        </Button>
      </FileField>

      <LabeledValue>
        <Label>Ausgewählte Dateien</Label>
        <Text>
          {files
            ? [...files].map((file) => file.name).join(", ")
            : "-"}
        </Text>
      </LabeledValue>
    </Section>
  );
}
```

---

# Kombiniere mit ...

## ContextualHelp

Verwende [ContextualHelp](/04-components/overlays/contextual-help/overview), um
zusätzliche Informationen bereitzustellen.

```tsx
import {
  Button,
  ContextualHelp,
  ContextualHelpTrigger,
  FileField,
  Heading,
  Label,
  Text,
} from "@mittwald/flow-react-components";

<FileField>
  <Label>
    Zertifikat
    <ContextualHelpTrigger>
      <Button />
      <ContextualHelp>
        <Heading>Weitere Informationen</Heading>
        <Text>
          Hier gibt es weitere Informationen, die zu lang
          für die FieldDescription sind.
        </Text>
      </ContextualHelp>
    </ContextualHelpTrigger>
  </Label>
  <Button variant="outline" color="secondary">
    Auswählen
  </Button>
</FileField>
```

## React Hook Form

Weitere Details zur Formularlogik und -validierung ist in der Component
[Form (React Hook Form)](/04-components/react-hook-form/form/overview) zu
finden.

```tsx
import {
  Button,
  FileCard,
  FileCardList,
  FileField,
  Label,
  Section,
} from "@mittwald/flow-react-components";
import { useForm } from "react-hook-form";
import {
  Form,
  SubmitButton,
  typedField,
} from "@mittwald/flow-react-components/react-hook-form";
import { sleep } from "@/content/04-components/actions/action/examples/lib";

export default () => {
  const form = useForm<{
    files: FileList | File[] | [];
  }>({ defaultValues: { files: [] } });
  const Field = typedField(form);

  const watchedFiles = [...form.watch("files")];

  return (
    <Section>
      <Form form={form} onSubmit={sleep}>
        <Field
          name="files"
          rules={{
            required:
              "Bitte wähle mindestens eine Datei aus",
          }}
        >
          <FileField multiple>
            <Label>Dateien</Label>
            <Button variant="outline" color="secondary">
              Auswählen
            </Button>
          </FileField>
        </Field>
        <FileCardList>
          {watchedFiles.map((file) => (
            <FileCard
              name={file.name}
              type={file.type}
              key={file.name}
              sizeInBytes={file.size}
              onDelete={() =>
                form.setValue(
                  "files",
                  watchedFiles.filter(
                    (watched) => watched !== file,
                  ),
                )
              }
            />
          ))}
        </FileCardList>
        <SubmitButton>Hochladen</SubmitButton>
      </Form>
    </Section>
  );
}
```


## Develop

# Properties

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `isReadOnly` | `boolean` | - | Whether the component is read only. |
| `children` | `ReactNode` | - | - |
| `wrapWith` | `ReactElement<unknown, string \| JSXElementConstructor<any>>` | - | - |
| `ref` | `Ref<HTMLSpanElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see [React Docs](https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom) |
| `key` | `Key` | - | - |
| `name` | `string` | - | - |
| `accept` | `string` | - | - |
| `multiple` | `boolean` | - | - |
| `validationBehavior` | `"native" \| "aria"` | `'native'` | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. |
| `isDisabled` | `boolean` | - | Whether the input is disabled. |
| `isRequired` | `boolean` | - | Whether user input is required on the input before form submission. |
| `isInvalid` | `boolean` | - | Whether the value is invalid. |

### Events

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `onChange` | `FileInputOnChangeHandler` | - | Handler that is called when the file input changes. |


## Guidelines

# Grundlagen

Das FileField ermöglicht den manuellen Upload einer Datei über eine kompakte
[Button](/04-components/actions/button/overview)-Darstellung. Wenn genügend
Platz vorhanden ist und Drag-and-Drop gewünscht wird, sollte stattdessen die
[FileDropZone](/04-components/upload/file-drop-zone/overview) eingesetzt werden.

## Best practices

Achte bei der Verwendung eines FileFields darauf, dass ...

- ein aussagekräftiges [Label](/04-components/content/label/overview) vorhanden
  ist, falls das FileField sonst nicht eindeutig verständlich wäre.
- die zulässigen Dateitypen und ggf. Größenbeschränkungen deutlich kommuniziert
  werden.
- hochgeladene Dateien übersichtlich dargestellt werden – z. B. als
  [FileCard](/04-components/upload/file-card/overview) oder
  [FileCardList](/04-components/upload/file-card-list/overview).
- [Fehlermeldungen](/02-foundations/03-content-guidelines/03-fehlermeldungen)
  klar und hilfreich formuliert sind.

## Verwendung

Verwende ein FileField, um einen kompakten
Upload-[Button](/04-components/actions/button/overview) in der
Benutzeroberfläche bereitzustellen.

