81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
import * as React from "react";
|
|
import type { AriaSelectProps } from "@react-types/select";
|
|
import { useSelectState } from "react-stately";
|
|
import {
|
|
useSelect,
|
|
HiddenSelect,
|
|
useButton,
|
|
mergeProps,
|
|
useFocusRing,
|
|
} from "react-aria";
|
|
import ChevronDown from "@spectrum-icons/workflow/ChevronDown";
|
|
|
|
import { ListBox } from "./ListBox";
|
|
import { Popover } from "./Popover";
|
|
|
|
export { Item } from "react-stately";
|
|
|
|
export function Select<T extends object>(props: AriaSelectProps<T>) {
|
|
// Create state based on the incoming props
|
|
let state = useSelectState(props);
|
|
|
|
// Get props for child elements from useSelect
|
|
let ref = React.useRef(null);
|
|
let { labelProps, triggerProps, valueProps, menuProps } = useSelect(
|
|
props,
|
|
state,
|
|
ref
|
|
);
|
|
|
|
// Get props for the button based on the trigger props from useSelect
|
|
let { buttonProps } = useButton(triggerProps, ref);
|
|
|
|
let { focusProps, isFocusVisible } = useFocusRing();
|
|
|
|
return (
|
|
<div className="inline-flex flex-col relative">
|
|
<div
|
|
{...labelProps}
|
|
className="block text-xs text-left cursor-default mb-1"
|
|
>
|
|
{props.label}
|
|
</div>
|
|
<HiddenSelect
|
|
label={props.label}
|
|
name={props.name}
|
|
state={state}
|
|
triggerRef={ref}
|
|
/>
|
|
<button
|
|
{...mergeProps(buttonProps, focusProps)}
|
|
className={`py-[5px] px-3 w-[150px] flex flex-row items-center justify-between overflow-hidden cursor-default rounded border hover:bg-transparentblack ${
|
|
isFocusVisible ? "border-green-700" : "border-black"
|
|
} ${state.isOpen ? "bg-gray-100" : "bg-white"}`}
|
|
ref={ref}
|
|
>
|
|
<span {...valueProps} className="text-sm">
|
|
{state.selectedItem
|
|
? state.selectedItem.rendered
|
|
: "Select an option"}
|
|
</span>
|
|
<ChevronDown
|
|
UNSAFE_className="mx-1"
|
|
UNSAFE_style={{
|
|
width: "15px",
|
|
}}
|
|
/>
|
|
</button>
|
|
{state.isOpen && (
|
|
<Popover
|
|
className="w-[150px]"
|
|
placement="bottom start"
|
|
state={state}
|
|
triggerRef={ref}
|
|
>
|
|
<ListBox {...menuProps} state={state} />
|
|
</Popover>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|