import type { JSX } from "@solidjs/web"; import { type Accessor } from "solid-js"; import { type MaybeAccessor } from "../internals/maybe-accessor.js"; /** * Options for {@link createCollapsible}. * * All reactive inputs accept `MaybeAccessor` so a consumer can flip * `open` / `disabled` / `keepMounted` post-construction without * re-creating the primitive. * * **Solid-native shape (2026-04-30).** No internal state. `open` is * required and the consumer always owns the signal. The primitive is * a pure function from `(open, onOpenChange) → api`. Migration from * pre-2026-04-30: `createCollapsible({ defaultOpen: false })` becomes * `const [open, setOpen] = createSignal(false); createCollapsible({ open, onOpenChange: setOpen })`. * See `solidify.md` §6 for rationale. */ export interface CreateCollapsibleOptions { /** * Open state. Consumer-owned signal — the primitive reads through * the accessor and does NOT keep an internal copy. Writes happen * via `onOpenChange` (the consumer's responsibility to update their * signal in response). */ open: MaybeAccessor; /** * Whether interaction is suppressed. * @default false */ disabled?: MaybeAccessor; /** * Pre-change callback. Called synchronously before any internal state * write with `(next, event, reason)`. The consumer can call * `event.preventDefault()` to veto the transition. * * **Pre/post asymmetry — important.** This callback is pre-change ONLY. * Reading `c.open()` inside this handler returns the OLD value (the * setter's microtask write hasn't flushed yet). Don't drive post-change * side effects from here. For post-change observation, use: * ```ts * createEffect(c.open, (next) => { ... }); * ``` * * **Event contract.** The `event` argument is one of two shapes: * * | Trigger | `event` shape | * |---|---| * | DOM (click via `c.trigger()`/directive, keydown via `useButton`) | The live `MouseEvent` / `KeyboardEvent`. | * | Programmatic `c.setOpen(next)` / `c.toggle()` with no event arg | A synthesized `new Event("openchange", { cancelable: true })`. | * | Programmatic `c.setOpen(next, event)` with explicit event | The supplied event, used as-is. | * * Cancellation flows by reference: any layer in the chain that calls * `event.preventDefault()` is observed by every later layer. */ onOpenChange?: (open: boolean, event: Event, reason: CollapsibleChangeReason) => void; /** * Keep the panel in the DOM even while closed. Read by inline-headless * consumers via `c.panel()` (currently dormant under the structural * `` wrapper, which composes its own * `createMountTransition`). * @default false */ keepMounted?: MaybeAccessor; /** * Use `hidden="until-found"` so the browser's built-in page search can * find and expand the panel. Forces {@link keepMounted}. Same dormancy * note as `keepMounted` for the structural wrapper path. * @default false */ hiddenUntilFound?: MaybeAccessor; } /** * Why the open state changed. Emitted on the third arg of * `onOpenChange(next, event, reason)` and accepted by * `c.setOpen(next, event?, reason?)` / `c.toggle(event?, reason?)`. * * - `"trigger-press"` — click or keyboard-activated (Enter/Space) trigger. * - `"beforematch"` — browser find-in-page expanded the panel (when * `hiddenUntilFound` is enabled, via the wrapper's `createMountTransition`). * - `"imperative"` — programmatic change with no originating DOM event, * or caller-supplied reason not covered by the above. * * Outer compounds that embed Collapsible (Accordion, etc.) receive this * as-is. */ export type CollapsibleChangeReason = "trigger-press" | "beforematch" | "imperative"; /** * Public API returned by {@link createCollapsible}. Flat accessors and * setters at the root; no `state` snapshot blob (axis D). * * Stage-01c cleanup-chain (post AccordionPanel migration): `mounted`, * `transitionStatus`, `shouldRenderPanel`, and `_setMounted` are no longer * on this api — animation lifecycle lives in `createMountTransition`, * composed by each structural panel wrapper. */ export interface CollapsibleApi { /** Reactive accessor for the current open state. */ open: Accessor; /** Whether interaction is suppressed. */ disabled: Accessor; /** * Stable id for the panel element. Generated at primitive setup * (`createUniqueId()` is stable for the owner's lifetime). Inline- * headless consumers reading the panel slot get this on * `c.panel().id`; outer compounds that embed this primitive * (Accordion, etc.) read it directly to wire `aria-labelledby` / * `aria-controls` cross-component without going through the slot bag. */ panelId: Accessor; /** * Override the panel id. Called by `` / * `` when the consumer provides an explicit `id` * prop, so the trigger's `aria-controls` binding reflects the * consumer-supplied value. */ setPanelId: (id: string) => void; /** * Flip `open` (no-op if `disabled`). Same `event?` / `reason?` contract * as {@link setOpen}. */ toggle: (event?: Event, reason?: CollapsibleChangeReason) => void; /** * Imperative open setter. Fires `onOpenChange(next, event, reason)` first; * if the consumer calls `event.preventDefault()` the internal write is * skipped. */ setOpen: (next: boolean, event?: Event, reason?: CollapsibleChangeReason) => void; /** * Trigger slot — returns a getter-bag of HTML attributes ready for * spreading onto a ` * ``` */ triggerRef: () => (el: HTMLButtonElement | null) => void; /** Directive form of {@link panel}. */ panelRef: () => (el: HTMLElement | null) => void; /** * Context provider. Wrap a subtree to make the API discoverable via * `useCollapsible()` without prop-drilling. */ Provider: (props: { children: JSX.Element; }) => JSX.Element; } /** * Shape of attributes emitted by `c.trigger()`. */ export interface CollapsibleTriggerSlotProps { type: "button"; "aria-expanded": "true" | "false"; "aria-controls": string | undefined; "data-panel-open": "" | undefined; "data-disabled": "" | undefined; onClick: (event: MouseEvent) => void; } export interface CollapsiblePanelSlotProps { id: string | undefined; "data-state": "open" | "closed"; "data-open": "" | undefined; "data-closed": "" | undefined; } /** * Read the nearest {@link CollapsibleApi} provided by `c.Provider`. * Throws if used outside a Provider. */ export declare function useCollapsible(): CollapsibleApi; /** * Solid 2.0-native compound primitive for collapsible disclosure. One call * owns logical state (open/disabled, panel id, change callbacks). Animation * lifecycle (mount, exit, measurement, beforematch) is NOT in this primitive * — wrappers compose `createMountTransition` over `c.open`. */ export declare function createCollapsible(options: CreateCollapsibleOptions): CollapsibleApi; /** * Shared directive-factory pattern used by both `c.triggerRef()` / * `c.panelRef()` (above) and the top-level `collapsibleTrigger(c)` / * `collapsiblePanel(c)` exports. */ //# sourceMappingURL=create-collapsible.d.ts.map