feat(design): glass surfaces by role, the static Badge, LinkButton, user pickers on the Combobox (E28 S3d1)
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import Combobox from "./ui/Combobox";
|
||||
|
||||
// Pick one registered user by name or email: the download quota's "any user" picker and the share
|
||||
// dialog's recipient. Both used to hand-roll an input over an absolute list that only a mouse could
|
||||
// reach (no arrow keys, no listbox for a screen reader, closed by a blur timer); this is the shared
|
||||
// Combobox in single-select, which brings all of that. A pick is an ACTION here, not a value to show,
|
||||
// so nothing stays selected: the field clears for the next one.
|
||||
export interface PickableUser {
|
||||
id: number;
|
||||
email: string;
|
||||
display_name?: string | null;
|
||||
}
|
||||
|
||||
export default function UserPicker<U extends PickableUser>({
|
||||
users,
|
||||
onPick,
|
||||
label,
|
||||
placeholder,
|
||||
loading,
|
||||
}: {
|
||||
users: readonly U[];
|
||||
onPick: (u: U) => void;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
loading?: boolean;
|
||||
}) {
|
||||
const byId = new Map(users.map((u) => [String(u.id), u]));
|
||||
return (
|
||||
<Combobox
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
multiple={false}
|
||||
loading={loading}
|
||||
selected={[]}
|
||||
// The label carries both, so the client filter matches a name OR an email.
|
||||
options={users.map((u) => ({
|
||||
value: String(u.id),
|
||||
label: u.display_name ? `${u.display_name} · ${u.email}` : u.email,
|
||||
}))}
|
||||
onChange={(next) => {
|
||||
const u = next[0] != null ? byId.get(next[0]) : undefined;
|
||||
if (u) onPick(u);
|
||||
}}
|
||||
renderOption={(o) => {
|
||||
const u = byId.get(o.value);
|
||||
return (
|
||||
<span className="flex min-w-0 flex-col">
|
||||
<span className="truncate">{u?.display_name || u?.email}</span>
|
||||
{u?.display_name && <span className="truncate text-xs text-muted">{u.email}</span>}
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user