MCPcopy Index your code
hub / github.com/primer/react / createSlots

Function createSlots

packages/react/src/deprecated/utils/create-slots.tsx:13–99  ·  view source on GitHub ↗
(slotNames: SlotNames[])

Source from the content-addressed store, hash-verified

11 * + Slot component that is used by LeadingVisual, Description
12 */
13const createSlots = <SlotNames extends string>(slotNames: SlotNames[]) => {
14 type Slots = {
15 [key in SlotNames]?: React.ReactNode
16 }
17
18 type ContextProps = {
19 registerSlot: (name: SlotNames, contents: React.ReactNode) => void
20 unregisterSlot: (name: SlotNames) => void
21 context: Record<string, unknown>
22 }
23 const SlotsContext = React.createContext<ContextProps>({
24 registerSlot: () => null,
25 unregisterSlot: () => null,
26 context: {},
27 })
28
29 // maintain a static reference to avoid infinite render loop
30 const defaultContext = Object.freeze({})
31
32 /** Slots uses a Double render strategy inspired by [reach-ui/descendants](https://github.com/reach/reach-ui/tree/develop/packages/descendants)
33 * Slot registers themself with the Slots parent.
34 * When all the children have mounted = registered themselves in slot,
35 * we re-render the parent component to render with slots
36 */
37 const Slots: React.FC<{
38 context?: ContextProps['context']
39 children: (slots: Slots) => React.ReactNode
40 }> = ({context = defaultContext, children}) => {
41 // initialise slots
42 const slotsDefinition: Slots = {}
43 slotNames.map(name => (slotsDefinition[name] = null))
44 const slotsRef = React.useRef<Slots>(slotsDefinition)
45
46 const rerenderWithSlots = useForceUpdate()
47 const [isMounted, setIsMounted] = React.useState(false)
48
49 // fires after all the effects in children
50 useLayoutEffect(() => {
51 rerenderWithSlots()
52 setIsMounted(true)
53 }, [rerenderWithSlots])
54
55 const registerSlot = React.useCallback(
56 (name: SlotNames, contents: React.ReactNode) => {
57 slotsRef.current[name] = contents
58
59 // don't render until the component mounts = all slots are registered
60 if (isMounted) rerenderWithSlots()
61 },
62 [isMounted, rerenderWithSlots],
63 )
64
65 // Slot can be removed from the tree as well,
66 // we need to unregister them from the slot
67 const unregisterSlot = React.useCallback(
68 (name: SlotNames) => {
69 slotsRef.current[name] = null
70 rerenderWithSlots()

Callers 1

Calls

no outgoing calls

Tested by

no test coverage detected