{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "author": "Lopifi (https://lopifi.com)",
  "categories": [
    "payments",
    "finance",
    "accounting"
  ],
  "dependencies": [
    "@base-ui-components/react"
  ],
  "description": "Recipient picker with fuzzy search and last-paid.",
  "files": [
    {
      "content": "\"use client\";\n\nimport { Popover } from \"@base-ui-components/react/popover\";\nimport * as React from \"react\";\nimport { cn } from \"@/lib/ledger/cn\";\nimport { formatDate } from \"@/lib/ledger/fiscal-period\";\nimport type { MoneyValue } from \"@/lib/ledger/money.types\";\nimport { EntityMark } from \"@/components/ledger/entity-mark\";\nimport { ChevronDownIcon, MagnifyingGlassIcon, PlusIcon } from \"@/components/ledger/icons\";\nimport { Money } from \"@/components/ledger/money\";\nimport { MaskedAccount } from \"@/components/ledger/reference\";\n\nexport type Payee = {\n  id: string;\n  name: string;\n  last4: string;\n  reference?: string;\n  lastPaid?: { amount: MoneyValue; date: Date };\n};\n\nexport interface PayeeSelectProps {\n  className?: string;\n  onCreate?: (name: string) => void;\n  onValueChange: (id: string) => void;\n  payees: Payee[];\n  value: string | null;\n}\n\n/**\n * Last-paid amount and date inline — the single most useful piece of context\n * when choosing a recipient. The new-payee flow is inline, not a route.\n */\nexport function PayeeSelect({ payees, value, onValueChange, onCreate, className }: PayeeSelectProps) {\n  const [open, setOpen] = React.useState(false);\n  const [query, setQuery] = React.useState(\"\");\n  const selected = payees.find((p) => p.id === value);\n\n  const filtered = React.useMemo(() => {\n    const q = query.trim().toLowerCase();\n    if (!q) return payees;\n    return payees.filter((p) =>\n      [p.name, p.last4, p.reference ?? \"\"].some((f) => f.toLowerCase().includes(q)),\n    );\n  }, [payees, query]);\n\n  return (\n    <Popover.Root onOpenChange={setOpen} open={open}>\n      <Popover.Trigger\n        aria-label={selected ? `Recipient: ${selected.name}` : \"Choose a recipient\"}\n        className={cn(\n          \"flex h-12 w-full items-center gap-3 rounded-md border border-border bg-surface px-3\",\n          \"text-left transition-colors duration-1 ease-standard hover:border-border-strong\",\n          className,\n        )}\n      >\n        {selected ? (\n          <>\n            <EntityMark category=\"company\" name={selected.name} size={24} />\n            <span className=\"min-w-0 flex-1\">\n              <span className=\"block truncate text-body\">{selected.name}</span>\n            </span>\n            <MaskedAccount last4={selected.last4} />\n          </>\n        ) : (\n          <span className=\"flex-1 text-body text-text-tertiary\">Choose a recipient</span>\n        )}\n        <ChevronDownIcon aria-hidden=\"true\" className=\"size-4 text-text-tertiary\" />\n      </Popover.Trigger>\n      <Popover.Portal>\n        <Popover.Positioner align=\"start\" className=\"z-dropdown\" sideOffset={8}>\n          <Popover.Popup\n            className=\"w-[var(--anchor-width)] min-w-[320px] overflow-hidden rounded-md border border-border bg-surface-raised shadow-elevation-3\"\n            style={{ transformOrigin: \"var(--transform-origin)\" }}\n          >\n            <div className=\"flex items-center gap-2 border-b border-border-subtle px-3\">\n              <MagnifyingGlassIcon aria-hidden=\"true\" className=\"size-4 text-text-tertiary\" />\n              <input\n                aria-label=\"Search recipients\"\n                autoFocus\n                className=\"h-10 flex-1 bg-transparent text-body outline-none placeholder:text-text-disabled\"\n                onChange={(e) => setQuery(e.target.value)}\n                placeholder=\"Search name, account or reference\"\n                value={query}\n              />\n            </div>\n            <div className=\"max-h-[320px] overflow-y-auto py-1 scrollbar-thin\">\n              {filtered.map((p) => (\n                <button\n                  className={cn(\n                    \"flex w-full items-center gap-3 px-3 py-2 text-left\",\n                    \"transition-colors duration-1 ease-standard hover:bg-surface-hover\",\n                    p.id === value && \"bg-surface-selected\",\n                  )}\n                  key={p.id}\n                  onClick={() => {\n                    onValueChange(p.id);\n                    setOpen(false);\n                  }}\n                  type=\"button\"\n                >\n                  <EntityMark category=\"company\" name={p.name} size={32} />\n                  <span className=\"min-w-0 flex-1\">\n                    <span className=\"block truncate text-body\">{p.name}</span>\n                    <MaskedAccount last4={p.last4} />\n                  </span>\n                  {p.lastPaid ? (\n                    <span className=\"text-right\">\n                      <Money size=\"xs\" tone=\"secondary\" value={p.lastPaid.amount} />\n                      <span className=\"block text-caption text-text-tertiary\">\n                        {formatDate(p.lastPaid.date)}\n                      </span>\n                    </span>\n                  ) : null}\n                </button>\n              ))}\n              {filtered.length === 0 && onCreate ? (\n                <button\n                  className=\"flex w-full items-center gap-2 px-3 py-3 text-left text-body text-accent hover:bg-surface-hover\"\n                  onClick={() => {\n                    onCreate(query);\n                    setOpen(false);\n                  }}\n                  type=\"button\"\n                >\n                  <PlusIcon aria-hidden=\"true\" className=\"size-4\" />\n                  Add “{query}” as a new recipient\n                </button>\n              ) : null}\n            </div>\n          </Popover.Popup>\n        </Popover.Positioner>\n      </Popover.Portal>\n    </Popover.Root>\n  );\n}\n",
      "path": "components/ledger/payee-select.tsx",
      "target": "components/ledger/payee-select.tsx",
      "type": "registry:component"
    }
  ],
  "name": "payee-select",
  "registryDependencies": [
    "@lopifi/theme",
    "@lopifi/cn",
    "@lopifi/entity-mark",
    "@lopifi/fiscal-period",
    "@lopifi/icons",
    "@lopifi/money",
    "@lopifi/money.types",
    "@lopifi/reference"
  ],
  "title": "PayeeSelect",
  "type": "registry:component"
}
