@zemd/react-slottable
Version:
A lightweight concept to customize subcomponents in React
53 lines (49 loc) • 1.78 kB
text/typescript
import { ElementType, ComponentProps } from 'react';
type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
/**
* A helper type that allows to define proper slot props.
*
* Usage:
* ```ts
* type ButtonProps = PropsWithSlots<
* React.PropsWithChildren<{ name: string }>,
* ["startDecorator", "endDecorator"]
* >;
* const Button: React.FC<ButtonProps> = (props) => {
* const SlotStartDecorator = useSlot("startDecorator", props);
* const SlotEndDecorator = useSlot("endDecorator", props);
*
* return (
* <button>
* <SlotStartDecorator />
* {props.children}
* <SlotEndDecorator />
* </button>
* );
* };
* ```
*/
type PropsWithSlots<ArgProps = {}, ArgSlots extends string[] = []> = ArgProps & (ArgSlots["length"] extends 0 ? {} : {
slots?: {
[K in ArgSlots[number]]?: ElementType;
};
slotProps?: {
[K in ArgSlots[number]]?: ComponentProps<ElementType>;
};
});
type SlotOptions<T extends ElementType> = {
slot?: T;
};
type SlotsProps<T extends Record<string, ElementType>> = {
slots?: T;
};
type SlotPropsProps<T extends Record<string, any>> = {
slotProps?: Partial<T>;
};
/**
* A hook that returns a component for a given slot.
*/
declare function useSlot<ArgSlotType extends ElementType, ArgExtraProps extends Partial<ComponentProps<ArgSlotType>>, ArgSlotOptions extends SlotOptions<ArgSlotType> & ArgExtraProps, ReturnComponent extends ArgSlotOptions extends SlotOptions<infer T> ? T : ElementType, ArgSlotsKeys extends Record<string, ElementType>>(name: keyof ArgSlotsKeys, props: Prettify<SlotsProps<ArgSlotsKeys> & SlotPropsProps<Record<keyof ArgSlotsKeys, any>>>, { slot, ...extraProps }?: ArgSlotOptions): ReturnComponent;
export { type PropsWithSlots, useSlot };