Files
web/packages/design-system/lib/components/DeprecatedSelect/index.tsx
Rasmus Langvad d0546926a9 Merged in fix/3697-prettier-configs (pull request #3396)
fix(SW-3691): Setup one prettier config for whole repo

* Setup prettierrc in root and remove other configs


Approved-by: Joakim Jäderberg
Approved-by: Linus Flood
2026-01-07 12:45:50 +00:00

176 lines
4.8 KiB
TypeScript

"use client"
import { ReactElement, useState } from "react"
import {
Button,
type Key,
ListBox,
ListBoxItem,
Popover,
Select as ReactAriaSelect,
SelectValue,
} from "react-aria-components"
import SelectChevron from "./SelectChevron"
import styles from "./select.module.css"
import { InputLabel } from "../InputLabel"
import { Typography } from "../Typography"
interface SelectProps extends Omit<
React.SelectHTMLAttributes<HTMLSelectElement>,
"onSelect"
> {
defaultSelectedKey?: Key
items: { label: string; value: Key }[]
label: string
name: string
onSelect: (key: Key) => void
value?: string | number
maxHeight?: number
showRadioButton?: boolean
discreet?: boolean
isNestedInModal?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
optionsIcon?: ReactElement<any>
}
type SelectPortalContainer = HTMLDivElement | undefined
type SelectPortalContainerArgs = HTMLDivElement | null
const DELIMITER = ":"
/**
* @deprecated Do not use.
*/
export default function Select({
className = "",
"aria-label": ariaLabel,
defaultSelectedKey,
items,
label,
name,
onSelect,
disabled,
required = false,
tabIndex,
value,
maxHeight,
showRadioButton = false,
discreet = false,
isNestedInModal = false,
optionsIcon,
}: SelectProps) {
const [rootDiv, setRootDiv] = useState<SelectPortalContainer>(undefined)
const setOverflowVisible = useSetOverflowVisibleOnRA(isNestedInModal)
function setRef(node: SelectPortalContainerArgs) {
if (node) {
setRootDiv(node)
}
}
function handleOnSelect(key: Key | null) {
if (key !== null) {
onSelect(key)
}
}
let chevronProps = {}
if (discreet) {
chevronProps = { color: "baseButtonTextOnFillNormal" }
} else if (disabled) {
chevronProps = { color: "disabled" }
}
return (
<div className={`${styles.container} ${className}`} ref={setRef}>
<ReactAriaSelect
aria-label={ariaLabel}
className={`${styles.select} ${discreet ? styles.discreet : ""} select-container`}
defaultSelectedKey={defaultSelectedKey}
name={name}
onSelectionChange={handleOnSelect}
selectedKey={value as Key}
onOpenChange={setOverflowVisible}
isDisabled={disabled}
>
<Typography variant="Body/Paragraph/mdRegular">
<Button
className={`${styles.input} select-button`}
data-testid={name}
>
<SelectValue tabIndex={tabIndex}>
{({ selectedText }) => (
<>
<InputLabel
required={required}
size={discreet ? "discreet" : "regular"}
>
{label}
{discreet && DELIMITER}
</InputLabel>
{selectedText && (
<Typography
variant="Body/Paragraph/mdRegular"
className={optionsIcon ? styles.iconLabel : ""}
>
<p>
{optionsIcon ? optionsIcon : null}
{selectedText}
</p>
</Typography>
)}
</>
)}
</SelectValue>
<SelectChevron {...chevronProps} />
</Button>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<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={item.label}
className={`${styles.listBoxItem} ${showRadioButton && styles.showRadioButton} ${optionsIcon && styles.iconLabel}`}
id={item.value}
key={`${item.value}_${item.label}`}
data-testid={item.label}
>
{optionsIcon}
{item.label}
</ListBoxItem>
))}
</ListBox>
</Popover>
</Typography>
</ReactAriaSelect>
</div>
)
}
function useSetOverflowVisibleOnRA(isNestedInModal?: boolean) {
function setOverflowVisible(isOpen: boolean) {
if (isOpen) {
document.body.style.overflow = "visible"
} else if (!isNestedInModal) {
document.body.style.overflow = ""
}
}
return setOverflowVisible
}