/**
* Contexts used by the composite primitives.
*
* There are two distinct contexts:
*
* - `CompositeListContext` — exposes registration helpers + the shared
* `elementsRef` / `labelsRef` plain arrays. `useCompositeListItem` reads
* from this context; `CompositeList` provides it.
* - `CompositeRootContext` — exposes `highlightedIndex()` + its setter so
* child items can read/update the focused-item state. This mirrors Base
* UI React's `CompositeRootContext`.
*
* Solid 2 context providers are "context-as-provider" (RFC 02), so a
* `{...}` is used at
* the call sites — there is no `.Provider`.
*/
import { type Accessor } from "solid-js";
/**
* Per-item metadata carried alongside the `Element → metadata` map. `index`
* is managed by `CompositeList` — consumers supply their own custom fields.
*/
export type CompositeMetadata = {
index?: number | null | undefined;
} & CustomMetadata;
/**
* A disposer returned by subscription helpers.
*/
export type Disposer = () => void;
/**
* The notification payload shared through `CompositeListContext.subscribe`.
* Consumers receive the sorted map on every change.
*/
export type CompositeMapListener = (map: Map | null>) => void;
export interface CompositeListContextValue {
/** Register a node + its metadata with the list. `source` is a unique,
* per-item token that lets the list detect stale entries when a consumer
* re-registers with a different node. Token shape is deliberately
* `symbol` so consumers can create one per `useCompositeListItem` call. */
register: (source: symbol, node: Element, metadata: Metadata) => void;
/** Unregister by `source` token (node may already be detached). */
unregister: (source: symbol) => void;
/** Subscribe to sorted-map changes. */
subscribeMapChange: (fn: CompositeMapListener) => Disposer;
/**
* Plain array of elements ordered by DOM position. This is a plain
* JavaScript array — NOT a reactive signal — because the root's keyboard
* handler reads it at call time and libraries like floating-ui expect a
* mutable `.current`-shaped list. Subscribe to `subscribeMapChange` for
* ordering updates.
*/
elementsRef: Array;
/** Parallel labels array, when the caller opted in by passing `labelsRef`
* on ``. */
labelsRef?: Array | undefined;
}
/**
* Phantom brand carried by the erased context value. The brand exists only
* in the type system — at runtime the field is absent — so there's no cost
* beyond TypeScript's assignability check. It prevents arbitrary
* `CompositeListContextValue` objects from being mistaken for the erased
* shape: only values produced by `eraseCompositeListContext` (or the frozen
* no-op default) carry the brand.
*/
declare const erasedMetadataBrand: unique symbol;
/**
* Erased storage shape for `CompositeListContext`. `Metadata` is fixed to
* `unknown` so the shape is concrete and the context can hold a single
* monomorphic type. Providers erase via `eraseCompositeListContext`;
* consumers reify via `useCompositeListContext()`. Both ends
* preserve the brand so the erasure can't be bypassed with a plain cast.
*/
export type ErasedCompositeListContextValue = CompositeListContextValue & {
readonly [erasedMetadataBrand]: true;
};
/**
* Erase the `Metadata` type parameter so a concrete
* `CompositeListContextValue` can be stored on the shared context.
* The cast is confined here — the context's `register`/`subscribeMapChange`
* handlers never actually observe values typed against the wrong `Metadata`
* because the corresponding `useCompositeListContext()` reader on
* the other side re-projects them to the same concrete type before the
* caller sees them.
*/
export declare function eraseCompositeListContext(value: CompositeListContextValue): ErasedCompositeListContextValue;
/**
* The context stores the erased shape. `` passes its concrete
* `CompositeListContextValue` through `eraseCompositeListContext`;
* consumers pull the branded value back out through
* `useCompositeListContext()` which reifies `Metadata` at the call
* site.
*/
export declare const CompositeListContext: import("solid-js").Context;
/**
* Read the nearest `CompositeListContext`. Returns the no-op default when
* there is no provider, so callers don't have to handle `undefined`. The
* single cast here is the only place `Metadata` is re-reified from the
* erased storage shape.
*/
export declare function useCompositeListContext(): CompositeListContextValue;
export interface CompositeRootContextValue {
/** Current highlighted index. */
highlightedIndex: Accessor;
/** Setter matching React Base UI's signature exactly. */
onHighlightedIndexChange: (index: number, shouldScrollIntoView?: boolean) => void;
/** If `true`, hovering an item moves focus to it. */
highlightItemOnHover: Accessor;
/**
* Forwards an external keyboard event into the composite's `onKeyDown`
* handler. Useful when the triggering element is rendered outside the
* composite tree (e.g. menubar with detached triggers).
*/
relayKeyboardEvent: (event: KeyboardEvent) => void;
/** `true` only when provided by a real ``. */
readonly present: boolean;
}
export declare const CompositeRootContext: import("solid-js").Context;
/**
* Read the composite root context. Returns `undefined` in the `optional: true`
* form when no real `` is an ancestor; otherwise throws.
*/
export declare function useCompositeRootContext(optional: true): CompositeRootContextValue | undefined;
export declare function useCompositeRootContext(optional?: false): CompositeRootContextValue;
export {};
//# sourceMappingURL=composite-context.d.ts.map