UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

52 lines (51 loc) 2.7 kB
import { type ComponentType, type FunctionComponent, type JSX } from "react"; import type { Elements } from "../../util/element.js"; import type { ChildProps } from "../util/props.js"; /** * Dispatch table from a `JSX.IntrinsicElements` key to a renderer component. * - Each entry is optional — unmapped elements fall through and render as themselves (e.g. an unmapped `<tree-foo>` appears as a raw `<tree-foo>` HTML element). * - Per-entry component receives `JSX.IntrinsicElements[K] & E` — the declared props for that element type, plus any extra props `E` the mapper is configured to thread through. */ export type Mapping<E = unknown> = { [K in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[K] & E>; }; /** Props for the `Mapping` component returned by `createMapper()`. */ export interface MappingProps<E = unknown> extends ChildProps { /** Mapping entries that extend or override the inherited mapping inside this subtree. */ readonly mapping: Mapping<E>; } /** * Props for the `Mapper` component returned by `createMapper()`. * - `children` holds the pre-walked elements to dispatch. * - All other props are spread onto every mapped child as additional props (`E`). */ export type MapperProps<E = unknown> = E & { readonly children?: Elements; }; /** * Create a `[Mapping, Mapper]` pair of components backed by their own private React context. * * - `Mapping` extends or overrides the mapping inside a subtree (useful for swapping in custom renderers for specific element types). * - `Mapper` accepts a pre-walked iterable of elements as `children` and dispatches each to the registered component for its `type`. Any other props passed to `Mapper` are spread onto every dispatched child. * * Each call creates its own context — independent mappers don't interfere with each other. * * @typeParam E The shape of any extra props the mapper threads through to every dispatched child. Defaults to `unknown` (no extras). * * @example * // No extras: * const [TreeCardMapping, TreeCardMapper] = createMapper({ * "tree-directory": DirectoryCard, * "tree-file": FileCard, * }); * <TreeCardMapper>{walkElements(children)}</TreeCardMapper> * * @example * // With extras (`path` threaded into every dispatched child): * const [TreeMenuMapping, TreeMenuMapper] = createMapper<{ path?: AbsolutePath }>({ * "tree-directory": TreeMenuItem, * "tree-file": TreeMenuItem, * }); * <TreeMenuMapper path="/foo">{queryElements(children, query)}</TreeMenuMapper> */ export declare function createMapper<E = unknown>(defaults?: Mapping<E>): [Mapping: FunctionComponent<MappingProps<E>>, Mapper: FunctionComponent<MapperProps<E>>];