@primer/react
Version:
An implementation of GitHub's Primer Design System using React
64 lines • 2.91 kB
TypeScript
import React from 'react';
/**
* useSlots - Extract slot components from children for SSR-compatible slot APIs.
*
* Given a list of children and a config mapping slot names to component types,
* separates children into two groups: matched slots and the rest.
*
* Config: { leadingVisual: LeadingVisual, description: Description }
*
* Children: Matching: Output:
* +----------------+ slots = {
* | LeadingVisual | -> matches slot 0 --> leadingVisual: <LeadingVisual />
* | "Project name" | -> no match --> description: <Description />
* | Description | -> matches slot 1 --> }
* | TrailingVisual | -> no match --> rest = ["Project name", <TrailingVisual />]
* +----------------+
*
* Performance-sensitive: called per item in lists (e.g. 100-item ActionList
* calls this 101 times per render).
*
* Once all slots are filled, remaining children skip matching entirely in
* production (single integer comparison). In dev, we still scan for duplicates
* to emit a warning.
*
* Flow per child:
*
* child ──> isValidElement? ──no──> rest[]
* |
* yes
* |
* v
* all slots filled? ──yes──> rest[] (prod)
* | |
* no [dev: check for
* | duplicate warning]
* v
* match against unfilled slots
* |
* found match? ──no──> rest[]
* |
* yes
* |
* v
* slots[key] = child, slotsFound++
*
* Slot config supports two matcher styles:
* 1. Component reference: { visual: LeadingVisual }
* 2. Component + test fn: { block: [Description, props => props.variant === 'block'] }
*/
type Props = any;
type ComponentMatcher = React.ElementType<Props>;
type ComponentAndPropsMatcher = [ComponentMatcher, (props: Props) => boolean];
export type SlotConfig = Record<string, ComponentMatcher | ComponentAndPropsMatcher>;
type SlotElements<Config extends SlotConfig> = {
[Property in keyof Config]: SlotValue<Config, Property>;
};
type SlotValue<Config, Property extends keyof Config> = Config[Property] extends React.ElementType ? React.ReactElement<React.ComponentPropsWithoutRef<Config[Property]>, Config[Property]> : Config[Property] extends readonly [
infer ElementType extends React.ElementType,
infer _testFn
] ? React.ReactElement<React.ComponentPropsWithoutRef<ElementType>, ElementType> : never;
/** Extract slot components from children. See file header for details. */
export declare function useSlots<Config extends SlotConfig>(children: React.ReactNode, config: Config): [Partial<SlotElements<Config>>, React.ReactNode[]];
export {};
//# sourceMappingURL=useSlots.d.ts.map