# BottomSheet

> Organism — orn-ui

> ⚠️ Requiere <UIProvider>: Este componente (como todos los de orn-ui) debe renderizarse dentro de un ancestro <UIProvider>, o lanza un error en runtime. See https://orn-ui-docs.vercel.app/getting-started.md

> Corre en Expo SDK 54, 55, 56 y 57, y en React Native puro >=0.81 con react >=19.1. Sin módulos nativos — funciona en Expo Go, sin prebuild.

## Instalación

Instala solo este componente (copia el código fuente a tu proyecto, sin dependencia npm)
```bash
npx orn-ui add bottom-sheet
```

O instala el paquete completo e impórtalo
```tsx
pnpm add orn-ui
import { BottomSheet } from 'orn-ui/bottom-sheet';
```

Depende de: core (theme + icons), title, icon-button, pressable-scale, transition

## Variantes

### bare — handle only

```tsx
<>
  <Button title="Open sheet" onPress={() => setBare(true)} />
  <BottomSheet visible={bare} onClose={() => setBare(false)}>
    <Title style={{ marginBottom: 8 }}>Bottom sheet</Title>
    <Body>Drag the handle down, or tap outside, to dismiss.</Body>
  </BottomSheet>
</>
```

### title + footer — a form in a sheet

```tsx
<>
  <Button title="Open form" onPress={() => setForm(true)} />
  <BottomSheet
    visible={form}
    onClose={() => setForm(false)}
    title="Add a note"
    footer={
      <FormActions
        primaryLabel="Save"
        onPrimaryPress={() => setForm(false)}
        secondaryLabel="Cancel"
        onSecondaryPress={() => setForm(false)}
      />
    }
  >
    <Input label="Note" placeholder="Anything worth remembering" value={note} onChangeText={setNote} />
  </BottomSheet>
</>
```

### long content — scrolls up to maxHeight

```tsx
<>
  <Button title="Open long sheet" onPress={() => setLong(true)} />
  <BottomSheet visible={long} onClose={() => setLong(false)} title="Twelve rows">
    <View style={{ gap: 12 }}>
      {LONG.map((row) => (
        <Body key={row}>{row}</Body>
      ))}
    </View>
  </BottomSheet>
</>
```

### footerPlacement="hide-with-keyboard" — the form keeps that row

```tsx
<>
  <Button title="Open long form" onPress={() => setHiding(true)} />
  <BottomSheet
    visible={hiding}
    onClose={() => setHiding(false)}
    title="Long form"
    footerPlacement="hide-with-keyboard"
    footer={
      <FormActions
        primaryLabel="Save"
        onPrimaryPress={() => setHiding(false)}
        secondaryLabel="Cancel"
        onSecondaryPress={() => setHiding(false)}
      />
    }
  >
    <View style={{ gap: 12 }}>
      {['Name', 'Company', 'Email', 'Phone', 'Address'].map((label) => (
        <Input key={label} label={label} value={note} onChangeText={setNote} />
      ))}
    </View>
  </BottomSheet>
</>
```

### draggable={false} + maxHeight={0.4}

```tsx
<>
  <Button title="Open fixed sheet" onPress={() => setFixed(true)} />
  <BottomSheet
    visible={fixed}
    onClose={() => setFixed(false)}
    title="No dragging"
    draggable={false}
    maxHeight={0.4}
  >
    <Body>Dismiss with the close button or by tapping outside.</Body>
  </BottomSheet>
</>
```

## Código completo del demo

```tsx
const variants: VariantDef[] = [
  {
    label: 'bare — handle only',
    content: (
      <>
        <Button title="Open sheet" onPress={() => setBare(true)} />
        <BottomSheet visible={bare} onClose={() => setBare(false)}>
          <Title style={{ marginBottom: 8 }}>Bottom sheet</Title>
          <Body>Drag the handle down, or tap outside, to dismiss.</Body>
        </BottomSheet>
      </>
    ),
  },
  {
    label: 'title + footer — a form in a sheet',
    content: (
      <>
        <Button title="Open form" onPress={() => setForm(true)} />
        <BottomSheet
          visible={form}
          onClose={() => setForm(false)}
          title="Add a note"
          footer={
            <FormActions
              primaryLabel="Save"
              onPrimaryPress={() => setForm(false)}
              secondaryLabel="Cancel"
              onSecondaryPress={() => setForm(false)}
            />
          }
        >
          <Input label="Note" placeholder="Anything worth remembering" value={note} onChangeText={setNote} />
        </BottomSheet>
      </>
    ),
  },
  {
    label: 'long content — scrolls up to maxHeight',
    content: (
      <>
        <Button title="Open long sheet" onPress={() => setLong(true)} />
        <BottomSheet visible={long} onClose={() => setLong(false)} title="Twelve rows">
          <View style={{ gap: 12 }}>
            {LONG.map((row) => (
              <Body key={row}>{row}</Body>
            ))}
          </View>
        </BottomSheet>
      </>
    ),
  },
  {
    label: 'footerPlacement="hide-with-keyboard" — the form keeps that row',
    content: (
      <>
        <Button title="Open long form" onPress={() => setHiding(true)} />
        <BottomSheet
          visible={hiding}
          onClose={() => setHiding(false)}
          title="Long form"
          footerPlacement="hide-with-keyboard"
          footer={
            <FormActions
              primaryLabel="Save"
              onPrimaryPress={() => setHiding(false)}
              secondaryLabel="Cancel"
              onSecondaryPress={() => setHiding(false)}
            />
          }
        >
          <View style={{ gap: 12 }}>
            {['Name', 'Company', 'Email', 'Phone', 'Address'].map((label) => (
              <Input key={label} label={label} value={note} onChangeText={setNote} />
            ))}
          </View>
        </BottomSheet>
      </>
    ),
  },
  {
    label: 'draggable={false} + maxHeight={0.4}',
    content: (
      <>
        <Button title="Open fixed sheet" onPress={() => setFixed(true)} />
        <BottomSheet
          visible={fixed}
          onClose={() => setFixed(false)}
          title="No dragging"
          draggable={false}
          maxHeight={0.4}
        >
          <Body>Dismiss with the close button or by tapping outside.</Body>
        </BottomSheet>
      </>
    ),
  },
];
return <VariantList variants={variants} />;
```

## Props

| Nombre | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `visible` | `boolean` | — | — |
| `onClose` | `() => void` | — | — |
| `title?` | `string` | — | Con título aparece el header, con su botón de cerrar. |
| `footer?` | `ReactNode` | — | Acciones de la hoja. Dónde viven lo decide `footerPlacement`. |
| `footerPlacement?` | `'fixed' \| 'scroll' \| 'hide-with-keyboard'` | fixed | 'fixed' lo ancla al fondo de la hoja; 'scroll' lo deja al final del contenido; 'hide-with-keyboard' lo esconde mientras se tipea, que en un formulario largo le devuelve esa franja al campo enfocado. |
| `scrollable?` | `boolean` | true | El contenido scrollea cuando no entra. |
| `draggable?` | `boolean` | true | Arrastrar la hoja hacia abajo la cierra. |
| `maxHeight?` | `number` | 0.9 | Fracción de la pantalla (0-1) o píxeles. |
| `closeAccessibilityLabel?` | `string` | Close | — |
| `containerStyle?` | `ViewStyle` | — | — |
| `contentStyle?` | `ViewStyle` | — | — |
