npm package: @isi-ui7/lookup-input
Description: LookupInput component for banking forms — opens a popup table to browse and select records.
Latest version: 0.1.2

# @isi-ui7/lookup-input

Input field dengan popup data table untuk pemilihan data dari master (nasabah, rekening, produk, dll).

## Fitur

- Input text dengan tombol search — klik atau ketik untuk membuka popup tabel
- Data source fleksibel: `"direct"` (static array) atau `"api"` (POST endpoint server-side)
- Multi-field display: tampilkan kombinasi beberapa field sebagai nilai yang terlihat
- Tipe kolom: String, Int, Number, Float, BoolStr, BoolInt, DateTime
- Read-only mode: tampilkan nilai tanpa bisa membuka popup
- Popup width configurable

## Instalasi

```bash
pnpm add @isi-ui7/lookup-input @isi-ui7/data-table @carbon/react @carbon/icons-react react react-dom
```

## Penggunaan

### Static data (`dataSource="direct"`)

```tsx
"use client";
import { LookupInput } from "@isi-ui7/lookup-input";
import { useState } from "react";

const PRODUK = [
  { kode: "TAB001", nama: "Tabungan Regular", jenis: "Tabungan" },
  { kode: "DEP001", nama: "Deposito 3 Bulan", jenis: "Deposito" },
];

export function ProdukForm() {
  const [kode, setKode] = useState("");

  return (
    <LookupInput
      id="produk"
      labelText="Produk"
      value={kode}
      onChange={setKode}
      onDataSelected={(row) => console.log("dipilih:", row)}
      dataSource="direct"
      lookupData={PRODUK}
      lookupDataStructure={{ kode: "String", nama: "String", jenis: "String" }}
      displayFieldNames={["nama"]}
    />
  );
}
```

### API data (`dataSource="api"`)

```tsx
<LookupInput
  id="nasabah"
  labelText="Nasabah"
  value={noNasabah}
  onChange={setNoNasabah}
  onDataSelected={(row) => {
    setNoNasabah(row.noNasabah as string);
    setNama(row.nama as string);
  }}
  dataSource="api"
  lookupAPI="/api/lookup/nasabah"
  lookupDataStructure={{ noNasabah: "String", nama: "String", tglLahir: "DateTime" }}
  lookupFieldTitles={{ noNasabah: "No. Nasabah", tglLahir: "Tgl Lahir" }}
  displayFieldNames={["noNasabah", "nama"]}
  displaySeparator=" - "
  popupWidthPx={600}
/>
```

## Props

| Nama | Tipe | Wajib | Deskripsi |
| --- | --- | --- | --- |
| `id` | `string` | ya | HTML id untuk input |
| `value` | `string` | ya | Nilai terkontrol (primary key field) |
| `onChange` | `(v: string) => void` | tidak | Dipanggil dengan nilai field display pertama saat pilih |
| `onDataSelected` | `(row) => void` | ya | Dipanggil dengan data baris penuh saat pilih |
| `dataSource` | `"direct" \| "api"` | ya | Sumber data popup |
| `lookupDataStructure` | `Record<string, T_LookupTblStruct>` | ya | Tipe tiap kolom |
| `lookupData` | `Record<string, unknown>[]` | jika `direct` | Data statis |
| `lookupAPI` | `string` | jika `api` | POST endpoint (`I_DataTblRequest` → `I_DataTblResponse`) |
| `lookupFieldTitles` | `Record<string, string>` | tidak | Override judul kolom di popup |
| `displayFieldNames` | `string[]` | tidak | Field yang ditampilkan di input. Default: field pertama |
| `displaySeparator` | `string` | tidak | Separator antar field display. Default: `" "` |
| `labelText` | `string` | tidak | Label input |
| `placeholder` | `string` | tidak | Placeholder input |
| `disabled` | `boolean` | tidak | Disable input dan tombol |
| `readOnly` | `boolean` | tidak | Tampilkan nilai tapi tidak bisa membuka popup |
| `popupWidthPx` | `number` | tidak | Lebar popup dalam px. Default: mengikuti lebar input |
| `className` | `string` | tidak | CSS class tambahan |

### `T_LookupTblStruct`

`"String" | "Int" | "Number" | "Float" | "BoolStr" | "BoolInt" | "DateTime"`

- `BoolStr`: boolean sebagai string (`"Y"`/`"N"`, `"true"`/`"false"`)
- `BoolInt`: boolean sebagai integer (`0`/`1`)

## A11y

- Input memiliki `aria-label` dan `role="combobox"` (dari Carbon TextInput)
- Tombol search memiliki `aria-label="Cari"`
- Popup menutup dengan Escape

## Scripts

```bash
pnpm build      # Build ke dist/
pnpm lint       # ESLint
pnpm test       # Vitest
pnpm typecheck  # TypeScript check
```

## Catatan

- Peer deps: React/ReactDOM `>=18`, `@carbon/react >=1.97`, `@carbon/icons-react >=11.0`, `@isi-ui7/data-table`
- Komponen menggunakan `"use client"` — hanya untuk Next.js App Router
- `dataSource="api"` menggunakan protokol yang sama dengan `ServerDataTable` (`I_DataTblRequest`/`I_DataTblResponse`)