UNPKG

@isilin/react-slot

Version:

Simple and powerful typed slots for React components

1 lines 5.47 kB
{"version":3,"sources":["../src/index.ts","../src/lib/utils.ts","../src/lib/defineSlotComponent.ts","../src/lib/getSlots.ts"],"sourcesContent":["export * from './lib';\n","export function getDisplayName(component: unknown): string {\n if (typeof component === 'function') {\n return component.name || 'Component';\n }\n if (\n typeof component === 'object' &&\n component !== null &&\n 'displayName' in component\n ) {\n return (component as any).displayName || 'Component';\n }\n return 'Component';\n}\n","import { ReactElement, ReactNode } from 'react';\nimport { ExtraMap, SlotMap, SlotRules } from './types';\nimport { getDisplayName } from './utils';\nimport { pascalCase } from 'change-case';\n\ninterface DefineSlotComponentOptions<\n TSlots extends SlotMap,\n TExtras extends ExtraMap,\n> {\n slots: TSlots;\n extras?: TExtras;\n rules?: Partial<SlotRules<TSlots>>;\n}\n\ntype NamedComponent<TProps = any> =\n | ((props: TProps) => ReactElement)\n | React.MemoExoticComponent<any>\n | React.ForwardRefExoticComponent<any>;\n\nexport function defineSlotComponent<\n TProps extends {} = { children: ReactNode },\n TSlots extends SlotMap = {},\n TExtras extends ExtraMap = {},\n>(\n render: NamedComponent<TProps>,\n options: DefineSlotComponentOptions<TSlots, TExtras>,\n): typeof render & {\n [K in keyof TSlots as Capitalize<string & K>]: TSlots[K];\n} & { slots: TSlots; rules?: Partial<SlotRules<TSlots>> } & TExtras {\n const { slots, extras, rules } = options;\n const componentName = getDisplayName(render);\n\n const Comp = ((props: TProps) => render(props)) as any;\n Comp.slots = slots;\n\n if (rules) {\n Comp.rules = options.rules;\n }\n\n for (const [key, comp] of Object.entries(slots)) {\n const pascal = pascalCase(key);\n comp.displayName ||= `${componentName}.${pascal}`;\n Comp[pascal] = comp;\n }\n\n if (extras) {\n Object.assign(Comp, extras);\n }\n\n return Comp;\n}\n","import React, { ReactElement, ReactNode } from 'react';\nimport { SlotComponent, SlotMap, SlotResult, SlotRules } from './types';\n\nexport function getSlots<\n T extends { slots: SlotMap; rules?: Partial<SlotRules<T['slots']>> },\n>(children: ReactNode, slotHost: T): SlotResult<T['slots']> {\n const slotComponents = slotHost.slots;\n const rules: Partial<SlotRules<T['slots']>> = slotHost.rules ?? {};\n const slots: Partial<\n Record<keyof T['slots'], ReactElement | ReactElement[]>\n > = {};\n const others: ReactNode[] = [];\n\n for (const key in slotComponents) {\n if (rules?.[key as keyof T['slots']] === 'multiple') {\n slots[key as keyof T['slots']] = [];\n }\n }\n\n React.Children.forEach(children, (child) => {\n if (!React.isValidElement(child)) {\n others.push(child);\n return;\n }\n\n const childType = child.type as SlotComponent;\n\n const matchKey = Object.entries(slotComponents).find(\n ([, slotComponent]) =>\n childType === slotComponent ||\n childType.displayName === slotComponent.displayName,\n )?.[0] as keyof T['slots'] | undefined;\n\n if (matchKey) {\n const rule = rules?.[matchKey] ?? 'single';\n if (rule === 'multiple') {\n (slots[matchKey] as ReactElement[]).push(child);\n } else {\n if (slots[matchKey] && process.env.NODE_ENV !== 'production') {\n console.warn(\n `Slot \"${String(matchKey)}\" was provided multiple times but is declared as single. Only the last one will be used.`,\n );\n }\n slots[matchKey] = child;\n }\n } else {\n others.push(child);\n }\n });\n\n return { ...(slots as Record<keyof T['slots'], any>), others };\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,EAAA,mBAAAC,EAAA,aAAAC,IAAA,eAAAC,EAAAL,GCAO,SAASM,EAAeC,EAA4B,CACzD,OAAI,OAAOA,GAAc,WAChBA,EAAU,MAAQ,YAGzB,OAAOA,GAAc,UACrBA,IAAc,MACd,gBAAiBA,GAETA,EAAkB,aAAe,WAG7C,CCTA,IAAAC,EAA2B,uBAgBpB,SAASC,EAKdC,EACAC,EAGkE,CAClE,GAAM,CAAE,MAAAC,EAAO,OAAAC,EAAQ,MAAAC,CAAM,EAAIH,EAC3BI,EAAgBC,EAAeN,CAAM,EAErCO,EAASC,GAAkBR,EAAOQ,CAAK,EAC7CD,EAAK,MAAQL,EAETE,IACFG,EAAK,MAAQN,EAAQ,OAGvB,OAAW,CAACQ,EAAKC,CAAI,IAAK,OAAO,QAAQR,CAAK,EAAG,CAC/C,IAAMS,KAAS,cAAWF,CAAG,EAC7BC,EAAK,cAAgB,GAAGL,CAAa,IAAIM,CAAM,GAC/CJ,EAAKI,CAAM,EAAID,CACjB,CAEA,OAAIP,GACF,OAAO,OAAOI,EAAMJ,CAAM,EAGrBI,CACT,CClDA,IAAAK,EAA+C,sBAGxC,SAASC,EAEdC,EAAqBC,EAAqC,CAC1D,IAAMC,EAAiBD,EAAS,MAC1BE,EAAwCF,EAAS,OAAS,CAAC,EAC3DG,EAEF,CAAC,EACCC,EAAsB,CAAC,EAE7B,QAAWC,KAAOJ,EACZC,IAAQG,CAAuB,IAAM,aACvCF,EAAME,CAAuB,EAAI,CAAC,GAItC,SAAAC,QAAM,SAAS,QAAQP,EAAWQ,GAAU,CAC1C,GAAI,CAAC,EAAAD,QAAM,eAAeC,CAAK,EAAG,CAChCH,EAAO,KAAKG,CAAK,EACjB,MACF,CAEA,IAAMC,EAAYD,EAAM,KAElBE,EAAW,OAAO,QAAQR,CAAc,EAAE,KAC9C,CAAC,CAAC,CAAES,CAAa,IACfF,IAAcE,GACdF,EAAU,cAAgBE,EAAc,WAC5C,IAAI,CAAC,EAEDD,GACWP,IAAQO,CAAQ,GAAK,YACrB,WACVN,EAAMM,CAAQ,EAAqB,KAAKF,CAAK,GAE1CJ,EAAMM,CAAQ,GAAK,QAAQ,IAAI,WAAa,cAC9C,QAAQ,KACN,SAAS,OAAOA,CAAQ,CAAC,0FAC3B,EAEFN,EAAMM,CAAQ,EAAIF,GAGpBH,EAAO,KAAKG,CAAK,CAErB,CAAC,EAEM,CAAE,GAAIJ,EAAyC,OAAAC,CAAO,CAC/D","names":["index_exports","__export","defineSlotComponent","getDisplayName","getSlots","__toCommonJS","getDisplayName","component","import_change_case","defineSlotComponent","render","options","slots","extras","rules","componentName","getDisplayName","Comp","props","key","comp","pascal","import_react","getSlots","children","slotHost","slotComponents","rules","slots","others","key","React","child","childType","matchKey","slotComponent"]}