feat(frontend): add polling job queue ui
This commit is contained in:
62
frontend/src/components/SelectField.tsx
Normal file
62
frontend/src/components/SelectField.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import type { FocusEvent } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
export type SelectOption = {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
type SelectFieldProps = {
|
||||
label?: string;
|
||||
value: string;
|
||||
options: SelectOption[];
|
||||
placeholder?: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export function SelectField({ label, value, options, placeholder = "Select", onChange }: SelectFieldProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const selectedOption = useMemo(() => options.find((option) => option.value === value), [options, value]);
|
||||
const closeOnOutsideBlur = (event: FocusEvent<HTMLDivElement>) => {
|
||||
const nextTarget = event.relatedTarget;
|
||||
if (!(nextTarget instanceof Node) || !event.currentTarget.contains(nextTarget)) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
const control = (
|
||||
<div className="select-field" onBlur={closeOnOutsideBlur}>
|
||||
<button className={`select-trigger ${open ? "open" : ""}`} type="button" aria-haspopup="listbox" aria-expanded={open} onClick={() => setOpen(!open)}>
|
||||
<span>{selectedOption?.label ?? placeholder}</span>
|
||||
<ChevronDown size={16} />
|
||||
</button>
|
||||
{open && (
|
||||
<div className="select-menu" role="listbox">
|
||||
{options.map((option) => (
|
||||
<button
|
||||
className={option.value === value ? "select-option active" : "select-option"}
|
||||
key={option.value}
|
||||
role="option"
|
||||
type="button"
|
||||
aria-selected={option.value === value}
|
||||
onClick={() => {
|
||||
onChange(option.value);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (!label) return control;
|
||||
return (
|
||||
<label>
|
||||
{label}
|
||||
{control}
|
||||
</label>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user