import type { ReactNode } from "react"; import { PlusIcon, XMarkIcon } from "@heroicons/react/16/solid"; import { INPUT_CLASS } from "./ui"; export interface KeyValueEntry { key: string; value: string; } export function entriesFromMap(map: { [key: string]: string }): KeyValueEntry[] { return Object.entries(map).map(([key, value]) => ({ key, value })); } export function mapFromEntries(entries: KeyValueEntry[]): { [key: string]: string } { return Object.fromEntries( entries .map((entry): [string, string] => [entry.key.trim(), entry.value]) .filter((entry) => entry[0] !== ""), ); } export function KeyValueEditor({ entries, onChange, keyPlaceholder, valuePlaceholder, addLabel, renderEntryHint, }: { entries: KeyValueEntry[]; onChange: (entries: KeyValueEntry[]) => void; keyPlaceholder: string; valuePlaceholder: string; addLabel: string; renderEntryHint?: (entry: KeyValueEntry, index: number) => ReactNode; }) { function update(index: number, partial: Partial) { onChange(entries.map((entry, i) => (i === index ? { ...entry, ...partial } : entry))); } return (
{entries.map((entry, index) => (
update(index, { key: e.target.value })} placeholder={keyPlaceholder} autoComplete="off" spellCheck={false} className={`${INPUT_CLASS} font-mono`} /> update(index, { value: e.target.value })} placeholder={valuePlaceholder} autoComplete="off" spellCheck={false} className={`${INPUT_CLASS} font-mono`} /> onChange(entries.filter((_, i) => i !== index))} />
{renderEntryHint ? renderEntryHint(entry, index) : null}
))} onChange([...entries, { key: "", value: "" }])} />
); } function AddButton({ label, onClick }: { label: string; onClick: () => void }) { return ( ); } function RemoveButton({ onClick }: { onClick: () => void }) { return ( ); }