Start time grid #62
89
frontend/src/components/Choicebox/Choicebox.tsx
Normal file
89
frontend/src/components/Choicebox/Choicebox.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import type { InputHTMLAttributes } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
export interface ChoiceboxProps
|
||||
extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
|
||||
primaryText: string;
|
||||
secondaryText?: string;
|
||||
unavailable?: boolean;
|
||||
fitContent?: boolean;
|
||||
}
|
||||
|
||||
const baseClasses = clsx(
|
||||
"flex items-center gap-(--spacing-md)",
|
||||
"border-[length:var(--border-width-sm)]",
|
||||
"rounded-(--border-radius-md)",
|
||||
"p-(--padding-md)",
|
||||
);
|
||||
|
||||
const availableClasses = clsx(
|
||||
"bg-sky-20 border-sky-100",
|
||||
"cursor-pointer",
|
||||
// Hover
|
||||
"hover:bg-sky-35",
|
||||
// Focus
|
||||
"focus-within:bg-sky-20 focus-within:border-primary",
|
||||
"focus-within:outline focus-within:outline-sky-100 focus-within:outline-[length:var(--border-width-lg)]",
|
||||
// Selected
|
||||
"has-[:checked]:bg-sky-70 has-[:checked]:border-secondary",
|
||||
// Selected + Focus
|
||||
"has-[:checked]:focus-within:bg-sky-35",
|
||||
);
|
||||
|
||||
const unavailableClasses = clsx(
|
||||
"bg-base-canvas border-base-ink-soft",
|
||||
"cursor-not-allowed",
|
||||
);
|
||||
|
||||
const radioClasses = clsx(
|
||||
"appearance-none shrink-0",
|
||||
"w-[var(--font-size-body-md)] h-[var(--font-size-body-md)]",
|
||||
"rounded-full",
|
||||
"border-[length:var(--border-width-sm)] border-base-ink-medium",
|
||||
"bg-base-canvas",
|
||||
"outline-none",
|
||||
// Selected
|
||||
"checked:border-primary",
|
||||
"checked:bg-[radial-gradient(circle,var(--color-primary)_50%,var(--color-base-canvas)_50%)]",
|
||||
);
|
||||
|
||||
export default function Choicebox({
|
||||
primaryText,
|
||||
secondaryText,
|
||||
unavailable = false,
|
||||
fitContent = false,
|
||||
className = "",
|
||||
disabled,
|
||||
...props
|
||||
}: ChoiceboxProps) {
|
||||
const isDisabled = unavailable || disabled;
|
||||
const textColorClass = unavailable ? "text-base-ink-placeholder" : "text-primary";
|
||||
|
||||
return (
|
||||
<label
|
||||
className={clsx(
|
||||
baseClasses,
|
||||
unavailable ? unavailableClasses : availableClasses,
|
||||
fitContent ? "w-fit" : "w-full",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
<span className={clsx("body-bold-lg break-words", textColorClass)}>
|
||||
{primaryText}
|
||||
</span>
|
||||
{secondaryText && (
|
||||
<span className={clsx("body-light-sm break-words", textColorClass)}>
|
||||
{secondaryText}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
type="radio"
|
||||
className={radioClasses}
|
||||
disabled={isDisabled}
|
||||
{...props}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user