# LivaDNDTree
Package: @dataliva/livalib
Description: @dataliva/livalib sürükle-bırak destekli ağaç bileşeni.

DevExtreme TreeList üzerine kurulu, sürükle-bırak ile yeniden
düzenlenebilen ağaç bileşeni. Düz liste (`id` / `parentId`) yapısındaki
veriyi hiyerarşik gösterir; bir düğüm başka bir düğümün üzerine
bırakıldığında onun altına taşınır, araya bırakıldığında kardeş olarak
sıralanır. Her değişiklikte `onChange` güncel listeyi döndürür ve kardeş
düğümlerin `order` alanlarını yeniden numaralandırır.

```tsx
import { LivaDNDTree, type DNDTreeItem } from "@dataliva/livalib";
```

## Sürükle-bırak hiyerarşi

Departman/kişi hiyerarşisini sürükleyerek değiştirin: bir kişiyi başka bir
departmanın üzerine bırakın ya da satırlar arasına bırakarak sırasını
değiştirin. Satıra tıklamak seçimi günceller ve `onSelect` tetiklenir.

**Örnek — Sürükle-bırak hiyerarşi:**

```tsx
const [ogeler, setOgeler] = useState<DNDTreeItem[]>(organizasyon);
const [secili, setSecili] = useState<DNDTreeItem | null>(null);

<LivaDNDTree
  items={ogeler}
  height={380}
  onChange={setOgeler}
  onSelect={setSecili}
/>
<p>Seçili öğe: {secili ? secili.name : "yok"}</p>
```

## Satır aksiyonları

`onAdd`, `onRename` veya `onDelete` geri çağrılarından en az biri
verildiğinde satır sonunda bir aksiyon menüsü düğmesi görünür
(`showRowActions` ile bu davranış elle de kontrol edilebilir). Menü;
yeniden adlandırma, alt öğe ekleme ve silme komutlarını sunar — veri
güncellemesi tamamen size aittir.

**Örnek — Satır aksiyonları:**

```tsx
const [ekip, setEkip] = useState<DNDTreeItem[]>(organizasyon);

<LivaDNDTree
  items={ekip}
  height={380}
  onChange={setEkip}
  onAdd={(ust) =>
    setEkip((onceki) => {
      const yeniId = Math.max(...onceki.map((o) => Number(o.id))) + 1;
      return [...onceki, { id: yeniId, parentId: ust ? ust.id : null, name: "Yeni Üye", order: 99 }];
    })
  }
  onRename={(oge, mevcutAd) => {
    const yeniAd = window.prompt("Yeni ad:", mevcutAd);
    if (yeniAd) {
      setEkip((onceki) => onceki.map((o) => (o.id === oge.id ? { ...o, name: yeniAd } : o)));
    }
  }}
  onDelete={(oge) =>
    setEkip((onceki) => onceki.filter((o) => o.id !== oge.id && o.parentId !== oge.id))
  }
/>
```

`onRename` geri çağrısına öğeyle birlikte mevcut ad iletilir; yeni adın
nasıl alınacağı (satır içi düzenleme, popup vb.) uygulamaya bırakılmıştır.
Özel `columns` verildiğinde varsayılan ad kolonu ve aksiyon kolonu yerine
tamamen sizin kolonlarınız kullanılır.

## Veri tipi

```ts
type DNDTreeItem = Record<string, any> & {
  id: string | number;
  parentId?: string | number | null;
  name?: string;
  order?: number; // kardeşler arası sıra; taşımalarda yeniden numaralandırılır
};
```

## Prop'lar

| Prop | Tip | Varsayılan |
|------|------|---------|
| `items` | `DNDTreeItem[]` | — |
| `keyExpr` | `string` | `'id'` |
| `parentIdExpr` | `string` | `'parentId'` |
| `displayExpr` | `string` | `'name'` |
| `allowDropInsideItem` | `boolean` | `true` |
| `allowReordering` | `boolean` | `true` |
| `onChange` | `(items: DNDTreeItem[]) => void` | — |
| `columns` | `Array<Partial<TreeListTypes.Column>>` | — |
| `selectedKey` | `string \| number` | — |
| `defaultSelectedKey` | `string \| number` | — |
| `onSelect` | `(item: DNDTreeItem \| null) => void` | — |
| `onRename` | `(item, newName) => void` | — |
| `onAdd` | `(parent: DNDTreeItem \| null) => void` | — |
| `onDelete` | `(item: DNDTreeItem) => void` | — |
| `showRowActions` | `boolean` | otomatik |

Ayrıca DevExtreme `TreeListTypes.Properties`'ten gelen tüm prop'lar
(ör. `height`, `width`, `autoExpandAll`) olduğu gibi aktarılır.
