import { type Accessor, createContext, useContext } from "solid-js"; import type { BaseUIChangeEventDetails, BaseUIEventReasons, } from "../internals/change-event-details"; import type { UseCheckboxGroupParentReturnValue } from "./use-checkbox-group-parent.ts"; /** * Change-event details handed to `setValue` by child checkboxes / the * parent-indicator helper. Mirrors * `CheckboxGroup.ChangeEventDetails` from the React port. */ export type CheckboxGroupChangeEventDetails = BaseUIChangeEventDetails< BaseUIEventReasons["none"] >; /** * The value handed down by `` to its descendant * `` elements. * * Solid 2 adaptations from Base UI React's `CheckboxGroupContext`: * * - Every reactive slot is an `Accessor` so child checkboxes pull on * demand without tripping the top-level-reactive-read rule (RFC 01). * - `setValue` is wrapped in `createStableCallback` by the group root so * children can capture it into closures / refs without re-wiring. * - `parent` carries the `useCheckboxGroupParent` return value. Its own * callbacks are stable too (wrapped inside the helper). * - `present` is true when a real `` is an ancestor; child * checkboxes branch on it to decide whether to override their internal * `checked`/`onClick` behaviour. */ export interface CheckboxGroupContextValue { /** Current group value. */ value: Accessor; /** * The group's `defaultValue` while the group is uncontrolled, * `undefined` while controlled (mirrors React Base UI's * `CheckboxGroupContext.defaultValue`). Child checkboxes use it to seed * their own uncontrolled state (`defaultGroupValue.includes(value)`). */ defaultValue: Accessor; /** Names of all checkboxes in the group — used by the parent-indicator helper. */ allValues: Accessor; /** Write to the group value. Fires `onValueChange` and respects `details.cancel()`. */ setValue: (next: string[], details: CheckboxGroupChangeEventDetails) => void; /** Parent-indicator bundle (checked / indeterminate / child+parent props factories). */ parent: UseCheckboxGroupParentReturnValue; /** Whether the group is disabled — propagates to every child. */ disabled: Accessor; /** Marker — `true` when provided by a real ``. */ readonly present: boolean; } /** * Sentinel used as the context's default so `useContext` returns a real * value instead of throwing a `ContextNotFoundError` (Solid 2 beta throws * when the default is literal `undefined`). Callers branch on `.present` * rather than the identity of this value. */ const NOOP_CHECKBOX_GROUP_CONTEXT = Object.freeze({ present: false, }) as CheckboxGroupContextValue; /** * Checkbox-group context. The default is a frozen sentinel whose `.present` * is false, so `useCheckboxGroupContext` can always return a safe value and * children branch on `present` to decide whether to override their internal * behaviour. */ export const CheckboxGroupContext = createContext( NOOP_CHECKBOX_GROUP_CONTEXT, ); /** * Read the surrounding `` context. Returns a noop (with * `present: false`) when no group is an ancestor — the child checkbox-root * branches on `.present` rather than nullishness. */ export function useCheckboxGroupContext(): CheckboxGroupContextValue { return useContext(CheckboxGroupContext); }