# useForm
Package: @dataliva/livalib
Description: @dataliva/livalib form durumu yönetimi hook'u.

Form durumunu yöneten genel amaçlı hook: alan değerleri, kirli (dirty)
takibi, doğrulama kuralları, hata mesajları ve yükleme durumlu kaydetme
akışını tek yerden sağlar. `LivaForm`'un `form` prop'una doğrudan
bağlanabilir ya da bu sayfadaki örnekte olduğu gibi tekil editörlerle
`setFormItem` üzerinden kullanılabilir.

```tsx
import { useForm } from "@dataliva/livalib";

const form = useForm<Profil>({
  initialValues: { ad: "", eposta: "", yas: 30 },
  validationRules: {
    ad: [{ type: "required", message: "Ad alanı zorunludur." }],
    eposta: [
      { type: "required", message: "E-posta alanı zorunludur." },
      { type: "email", message: "Geçerli bir e-posta adresi girin." },
    ],
    yas: [{ type: "range", min: 18, max: 99, message: "Yaş 18 ile 99 arasında olmalıdır." }],
  },
  validateOnChange: true,
  onSave: async (data) => {
    await new Promise((res) => setTimeout(res, 800)); // sahte API çağrısı
  },
});
```

## Canlı örnek

Alanlara yazdıkça `formData` güncellenir, `isDirty` işaretlenir ve
`validateOnChange: true` olduğu için `errors` anında dolar. Sağdaki panel
hook'un döndürdüğü durumu canlı gösterir. Kaydet butonu `onSave`'i çağırır:
önce doğrulama yapılır, geçerse sahte kayıt 800 ms sürer ve `isSaving`
bu süre boyunca `true` kalır; başarılı kayıtta form yeniden temiz sayılır.

**Örnek — Canlı form durumu:**

```tsx
<div key={resetSayisi} style={{ display: "flex", flexDirection: "column", gap: 12, flex: "1 1 260px" }}>
  <LivaTextBox
    label="Ad"
    defaultValue={form.formData.ad}
    errorMessage={form.errors.ad}
    onType={(v: string) => form.setFormItem("ad", v)}
  />
  <LivaTextBox
    label="E-posta"
    defaultValue={form.formData.eposta}
    errorMessage={form.errors.eposta}
    onType={(v: string) => form.setFormItem("eposta", v)}
  />
  <LivaNumberBox
    label="Yaş"
    defaultValue={form.formData.yas}
    showSpinButtons
    errorMessage={form.errors.yas}
    onValueChanged={(e) => form.setFormItem("yas", e.value ?? 0)}
  />
  <div style={{ display: "flex", gap: 8 }}>
    <LivaButton
      text="Kaydet"
      loading={form.isSaving}
      onClick={async () => {
        const basarili = await form.onSave();
        setSonuc(basarili ? "Kayıt başarıyla tamamlandı." : "Doğrulama hataları düzeltilmeli.");
      }}
    />
    <LivaButton text="Doğrula" variant="outlined" onClick={() => form.validate()} />
    <LivaButton
      text="Sıfırla"
      type="normal"
      onClick={() => {
        form.resetForm();
        setSonuc("");
        setResetSayisi((n) => n + 1);
      }}
    />
  </div>
  {sonuc && <p style={{ margin: 0 }}>{sonuc}</p>}
</div>
<pre style={{ flex: "1 1 260px", margin: 0, padding: 12, borderRadius: 8, background: "#18181b", color: "#e4e4e7", fontSize: 12, overflowX: "auto" }}>
  {JSON.stringify(
    {
      formData: form.formData,
      isDirty: form.isDirty,
      isSaving: form.isSaving,
      errors: form.errors,
    },
    null,
    2
  )}
</pre>
```

## Parametreler

| Alan | Tip | Açıklama |
|------|------|---------|
| `initialValues` | `T` | Formun başlangıç değerleri (zorunlu). |
| `validationRules` | `Partial<Record<keyof T, ValidationRule[]>>` | Alan bazında kural dizileri. |
| `onSave` | `(data: T) => Promise<void> \| void` | `onSave()` doğrulamayı geçince çağrılan kaydetme fonksiyonu. |
| `validateOnChange` | `boolean` | `true` ise her alan güncellemesinde ilgili alan doğrulanır. Varsayılan: `false`. |

## Dönen Değerler

| Alan | Tip | Açıklama |
|------|------|---------|
| `formData` | `T` | Güncel form verisi. |
| `setFormData` | `(data: T \| ((prev: T) => T)) => void` | Tüm form verisini değiştirir. |
| `setFormItem` | `(field: K, value: T[K]) => void` | Tek bir alanı günceller. |
| `resetForm` | `() => void` | Formu başlangıç değerlerine döndürür, hataları temizler. |
| `isDirty` | `boolean` | Form başlangıç değerlerinden saptı mı. |
| `onSave` | `() => Promise<boolean>` | Doğrular ve kaydeder; başarı durumunu döner. |
| `isSaving` | `boolean` | Kaydetme işlemi sürüyor mu. |
| `markAsClean` | `() => void` | Formu elle temiz (dirty değil) olarak işaretler. |
| `errors` | `Partial<Record<keyof T, string>>` | Alan bazında hata mesajları. |
| `validate` | `() => boolean` | Tüm formu doğrular. |
| `validateField` | `(field: K) => boolean` | Tek bir alanı doğrular. |
| `clearErrors` | `() => void` | Tüm hataları temizler. |
| `clearFieldError` | `(field: K) => void` | Tek bir alanın hatasını temizler. |

## Doğrulama kuralı tipleri

`ValidationRule.type` şu değerleri alır:

| Tip | Açıklama |
|------|---------|
| `required` | Boş, `null`, `undefined` veya boş dizi olamaz; `trim` ile boşluklar kırpılır. |
| `email` | Geçerli e-posta biçimi. |
| `numeric` | Sayıya çevrilebilir olmalı. |
| `range` | `min`/`max` aralığında sayısal değer. |
| `stringLength` | Metin uzunluğu `min`/`max` sınırları içinde. |
| `pattern` | `pattern` (string veya `RegExp`) ile eşleşme. |
| `compare` | `comparisonTarget` (alan adı veya fonksiyon) ile eşitlik. |

Her kural `message` alanıyla özel hata metni taşıyabilir.
