Files
web/components/TempDesignSystem/Select/index.tsx
Niclas Edenvin 18d40120b9 Merged in feat/SW-338-filter-sort-ui (pull request #896)
Feat/SW-338 design filters and sorting on select hotel

* feat(SW-338): design hotel sort dropdown

* Translations

* feat(SW-338): style filters

* Bold

* Import type

* Translations

* Rename and add translation

* Rename translation


Approved-by: Bianca Widstam
2024-11-15 07:18:30 +00:00

111 lines
3.0 KiB
TypeScript

"use client"
import { useState } from "react"
import {
Button,
type Key,
ListBox,
ListBoxItem,
Popover,
Select as ReactAriaSelect,
SelectValue,
} from "react-aria-components"
import Label from "@/components/TempDesignSystem/Form/Label"
import Body from "@/components/TempDesignSystem/Text/Body"
import SelectChevron from "../Form/SelectChevron"
import styles from "./select.module.css"
import type {
SelectPortalContainer,
SelectPortalContainerArgs,
SelectProps,
} from "./select"
export default function Select({
"aria-label": ariaLabel,
defaultSelectedKey,
items,
label,
name,
onSelect,
placeholder,
required = false,
tabIndex,
value,
maxHeight,
showRadioButton = false,
discreet = false,
}: SelectProps) {
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(undefined)
function setRef(node: SelectPortalContainerArgs) {
if (node) {
setRootDiv(node)
}
}
function handleOnSelect(key: Key) {
onSelect(key)
}
return (
<div className={styles.container} ref={setRef}>
<ReactAriaSelect
aria-label={ariaLabel}
className={`${styles.select} ${discreet && styles.discreet}`}
defaultSelectedKey={defaultSelectedKey}
name={name}
onSelectionChange={handleOnSelect}
placeholder={placeholder}
selectedKey={value as Key}
>
<Body asChild fontOnly>
<Button className={styles.input} data-testid={name}>
<span className={styles.inputContentWrapper} tabIndex={tabIndex}>
<Label required={required} size={discreet ? "discreet" : "small"}>
{label}
{discreet && `:`}
</Label>
<SelectValue />
</span>
<SelectChevron
{...(discreet ? { color: "baseButtonTextOnFillNormal" } : {})}
/>
</Button>
</Body>
<Body asChild fontOnly>
<Popover
className={styles.popover}
placement="bottom"
shouldFlip={false}
/**
* react-aria uses portals to render Popover in body
* unless otherwise specified. We need it to be contained
* by this component to both access css variables assigned
* on the container as well as to not overflow it at any time.
*/
UNSTABLE_portalContainer={rootDiv}
maxHeight={maxHeight}
>
<ListBox className={styles.listBox}>
{items.map((item) => (
<ListBoxItem
aria-label={String(item)}
className={`${styles.listBoxItem} ${showRadioButton && styles.showRadioButton}`}
id={item.value}
key={item.label}
data-testid={item.label}
>
{item.label}
</ListBoxItem>
))}
</ListBox>
</Popover>
</Body>
</ReactAriaSelect>
</div>
)
}