5 changed files with 120 additions and 62 deletions
@ -1,33 +1,59 @@ |
|||||||
import clsx from "clsx"; |
import clsx from "clsx"; |
||||||
|
|
||||||
// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
|
// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
|
||||||
export const ButtonIconSelect = <T extends Object>({ |
export const ButtonIconSelect = <T extends Object>( |
||||||
options, |
props: { |
||||||
value, |
options: { |
||||||
onChange, |
value: T; |
||||||
group, |
text: string; |
||||||
}: { |
icon: JSX.Element; |
||||||
options: { value: T; text: string; icon: JSX.Element; testId?: string }[]; |
testId?: string; |
||||||
value: T | null; |
/** if not supplied, defaults to value identity check */ |
||||||
onChange: (value: T) => void; |
active?: boolean; |
||||||
group: string; |
}[]; |
||||||
}) => ( |
value: T | null; |
||||||
|
type?: "radio" | "button"; |
||||||
|
} & ( |
||||||
|
| { type?: "radio"; group: string; onChange: (value: T) => void } |
||||||
|
| { |
||||||
|
type: "button"; |
||||||
|
onClick: ( |
||||||
|
value: T, |
||||||
|
event: React.MouseEvent<HTMLButtonElement, MouseEvent>, |
||||||
|
) => void; |
||||||
|
} |
||||||
|
), |
||||||
|
) => ( |
||||||
<div className="buttonList buttonListIcon"> |
<div className="buttonList buttonListIcon"> |
||||||
{options.map((option) => ( |
{props.options.map((option) => |
||||||
<label |
props.type === "button" ? ( |
||||||
key={option.text} |
<button |
||||||
className={clsx({ active: value === option.value })} |
key={option.text} |
||||||
title={option.text} |
onClick={(event) => props.onClick(option.value, event)} |
||||||
> |
className={clsx({ |
||||||
<input |
active: option.active ?? props.value === option.value, |
||||||
type="radio" |
})} |
||||||
name={group} |
|
||||||
onChange={() => onChange(option.value)} |
|
||||||
checked={value === option.value} |
|
||||||
data-testid={option.testId} |
data-testid={option.testId} |
||||||
/> |
title={option.text} |
||||||
{option.icon} |
> |
||||||
</label> |
{option.icon} |
||||||
))} |
</button> |
||||||
|
) : ( |
||||||
|
<label |
||||||
|
key={option.text} |
||||||
|
className={clsx({ active: props.value === option.value })} |
||||||
|
title={option.text} |
||||||
|
> |
||||||
|
<input |
||||||
|
type="radio" |
||||||
|
name={props.group} |
||||||
|
onChange={() => props.onChange(option.value)} |
||||||
|
checked={props.value === option.value} |
||||||
|
data-testid={option.testId} |
||||||
|
/> |
||||||
|
{option.icon} |
||||||
|
</label> |
||||||
|
), |
||||||
|
)} |
||||||
</div> |
</div> |
||||||
); |
); |
||||||
|
|||||||
Loading…
Reference in new issue