import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from "react"; import { createContext, useContext, useState } from "react"; import { cx } from "../../utils/cx.utils"; import "./segmented.component.css"; interface SegmentedContextValue { value: string | null; select: (itemId: string) => void; } const SegmentedContext = createContext(null); /** Props accepted by {@link Segmented}. */ export interface SegmentedProps extends Omit, "onChange"> { /** `id` of the {@link Segmented.Item} highlighted when the control first renders. */ defaultId?: string; /** Stretches the control to 100% width, with segments evenly distributed. Defaults to `false`. */ fullWidth?: boolean; /** Called with the `id` of the segment that was clicked. */ onChange?: (id: string) => void; } /** Props accepted by {@link Segmented.Item}. */ export interface SegmentedItemProps extends Omit, "id"> { /** Identifies this segment; passed to `onChange` and matched against `defaultId`. */ id: string; /** Segment label. */ children: ReactNode; } /** * Single option of a {@link Segmented} control. Can only be used inside * {@link Segmented}, which it reads its selected/click behavior from via * context. * * @example * ```tsx * Week * ``` */ function SegmentedItem({ className, id, children, ...rest }: SegmentedItemProps) { const context = useContext(SegmentedContext); const isSelected = context?.value === id; return (
  • ); } /** * Row of mutually-exclusive {@link Segmented.Item}s, highlighting the * selected one and reporting clicks via `onChange`. * * @example * ```tsx * setRange(id)}> * Day * Week * Month * Year * * ``` */ export function Segmented({ className, children, defaultId, fullWidth = false, onChange, ...rest }: SegmentedProps) { const [value, setValue] = useState(defaultId ?? null); const select = (itemId: string) => { setValue(itemId); onChange?.(itemId); }; return ( ); } Segmented.Item = SegmentedItem;