# ReorderableList

> 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 reorderable-list
```

O instala el paquete completo e impórtalo
```tsx
pnpm add orn-ui
import { ReorderableList } from 'orn-ui/reorderable-list';
```

Depende de: core (theme + icons)

## Variantes

### Long-press a row and drag — the rows in between shift out of the way

```tsx
<ReorderableList
  data={data}
  keyExtractor={(item) => item.id}
  itemHeight={ITEM_HEIGHT}
  onReorder={setData}
  renderItem={(item, _index, dragging) => <Row name={item.name} dragging={dragging} />}
/>
```

### disabled — rows render but can’t be dragged

```tsx
<ReorderableList
  data={INITIAL}
  keyExtractor={(item) => item.id}
  itemHeight={ITEM_HEIGHT}
  disabled
  onReorder={() => {}}
  renderItem={(item, _index, dragging) => <Row name={item.name} dragging={dragging} />}
/>
```

## Código completo del demo

```tsx
const variants: VariantDef[] = [
  {
    label: 'Long-press a row and drag — the rows in between shift out of the way',
    content: (
      <ReorderableList
        data={data}
        keyExtractor={(item) => item.id}
        itemHeight={ITEM_HEIGHT}
        onReorder={setData}
        renderItem={(item, _index, dragging) => <Row name={item.name} dragging={dragging} />}
      />
    ),
  },
  {
    label: 'disabled — rows render but can’t be dragged',
    content: (
      <ReorderableList
        data={INITIAL}
        keyExtractor={(item) => item.id}
        itemHeight={ITEM_HEIGHT}
        disabled
        onReorder={() => {}}
        renderItem={(item, _index, dragging) => <Row name={item.name} dragging={dragging} />}
      />
    ),
  },
];
return (
  <>
    <Caption style={{ marginBottom: 8 }}>Web preview doesn’t simulate touch drag — see the gif on this page.</Caption>
    <VariantList variants={variants} />
  </>
);
```

## Props

| Nombre | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `data` | `T[]` | — | — |
| `keyExtractor` | `(item: T, index: number) => string` | — | — |
| `itemHeight` | `number` | — | Alto fijo de cada fila: necesario para calcular el índice destino sin medir layout async. |
| `renderItem` | `(item: T, index: number, dragging: boolean) => ReactElement<unknown, string \| JSXElementConstructor<any>>` | — | — |
| `onReorder` | `(data: T[]) => void` | — | Se llama al soltar, con el array ya reordenado. No muta `data`. |
| `onDragStart?` | `(index: number) => void` | — | Empieza a arrastrar la fila `index`. Usalo para apagar el scroll del contenedor (`scrollEnabled={false}`) mientras dure: en iOS el `UIScrollView` padre cancela los toques sobre el contenido apenas arranca su gesto vertical, y sin esto el drag muere a los pocos píxeles. |
| `onDragEnd?` | `() => void` | — | Termina el drag — al soltar o cancelar. Siempre corre si `onDragStart` corrió. |
| `disabled?` | `boolean` | false | — |
| `style?` | `StyleProp<ViewStyle>` | — | — |
