Komponen / Lapisan & umpan balik
Popover
Panel melayang non-modal untuk detail ringkas atau filter tanpa meninggalkan layar: filter daftar PO, detail singkat customer, ringkasan termin.
Filter daftar
Checkbox status dengan Atur ulang dan Terapkan di footer. Pilihan baru berlaku setelah Terapkan; tombol Terapkan dibungkus Popover.Close.
Daftar PO customer · status: Menunggu persetujuan
import { useState } from 'react';
import { Button, Checkbox, Popover } from '@divistant/circca-react';
import { Funnel } from '@phosphor-icons/react';
const STATUS = ['Draf', 'Menunggu persetujuan', 'Terbit', 'Dibatalkan'] as const;
// Filter daftar PO customer: pilihan disimpan sementara, baru berlaku setelah "Terapkan".
export default function Example() {
const [aktif, setAktif] = useState<string[]>(['Menunggu persetujuan']);
const [draf, setDraf] = useState<string[]>(aktif);
const ubah = (s: string, on: boolean) => setDraf(d => (on ? [...d, s] : d.filter(x => x !== s)));
return (
<div className="grid justify-items-start gap-3">
<Popover
title="Filter status PO"
onOpenChange={o => o && setDraf(aktif)}
trigger={<Button leadingVisual={Funnel}>Status{aktif.length ? ` (${aktif.length})` : ''}</Button>}
footer={
<>
<Button size="sm" onClick={() => setDraf([])}>
Atur ulang
</Button>
<Popover.Close asChild>
<Button size="sm" variant="primary" onClick={() => setAktif(draf)}>
Terapkan
</Button>
</Popover.Close>
</>
}
>
<div className="grid gap-2">
{STATUS.map(s => (
<Checkbox key={s} checked={draf.includes(s)} onCheckedChange={on => ubah(s, on)}>
{s}
</Checkbox>
))}
</div>
</Popover>
<p className="type-callout-default text-muted">
Daftar PO customer · status: {aktif.length ? aktif.join(', ') : 'semua'}
</p>
</div>
);
}Detail singkat
Ringkasan customer tanpa membuka halaman detail. Tanpa footer bila tidak ada aksi.
import { Button, Popover, StateLabel } from '@divistant/circca-react';
import { Info } from '@phosphor-icons/react';
// Detail singkat customer tanpa meninggalkan daftar PO. Tanpa footer: hanya informasi + satu tautan lanjut.
export default function Example() {
return (
<Popover
title="PT Pelanggan Contoh A"
trigger={
<Button variant="ghost" leadingVisual={Info}>
PT Pelanggan Contoh A
</Button>
}
>
<dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1.5 type-callout-default">
<dt className="text-muted">Status</dt>
<dd>
<StateLabel tone="success" size="sm">
Aktif
</StateLabel>
</dd>
<dt className="text-muted">PIC sales</dt>
<dd>Anisa Nugraha</dd>
<dt className="text-muted">PO berjalan</dt>
<dd>3 PO · Rp 482.500.000</dd>
<dt className="text-muted">Termin jatuh tempo</dt>
<dd>PO-2026-0142 · 14 Okt 2026</dd>
</dl>
</Popover>
);
}Dengan & tanpa caret
Caret=Top (default) menunjuk pemicu; Caret=None untuk panel yang jelas menempel pada pemicunya.
import { Button, Popover } from '@divistant/circca-react';
// Caret=Top (default) menunjuk pemicu — pakai saat pemicu kecil atau berdekatan dengan pemicu lain.
// Caret=None untuk panel yang menempel jelas pada pemicunya (mis. tombol filter di toolbar).
export default function Example() {
const isi = (
<div className="grid gap-1 type-callout-default">
<p>60% saat PO terbit · Rp 90.000.000</p>
<p>40% setelah BAST · Rp 60.000.000</p>
<p className="text-muted">Disetujui Rina Kartika (Finance)</p>
</div>
);
return (
<div className="flex flex-wrap gap-3">
<Popover title="Termin PO-2026-0142" trigger={<Button>Dengan caret</Button>}>
{isi}
</Popover>
<Popover title="Termin PO-2026-0142" caret={false} trigger={<Button>Tanpa caret</Button>}>
{isi}
</Popover>
</div>
);
}