-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathslot-fill-provider.tsx
107 lines (94 loc) · 2.35 KB
/
slot-fill-provider.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';
import isShallowEqual from '@wordpress/is-shallow-equal';
/**
* Internal dependencies
*/
import SlotFillContext from './slot-fill-context';
import type {
SlotFillProviderProps,
SlotFillBubblesVirtuallyContext,
} from '../types';
import { observableMap } from './observable-map';
function createSlotRegistry(): SlotFillBubblesVirtuallyContext {
const slots: SlotFillBubblesVirtuallyContext[ 'slots' ] = observableMap();
const fills: SlotFillBubblesVirtuallyContext[ 'fills' ] = observableMap();
const registerSlot: SlotFillBubblesVirtuallyContext[ 'registerSlot' ] = (
name,
ref,
fillProps
) => {
const slot = slots.get( name );
slots.set( name, {
...slot,
ref: ref || slot?.ref,
fillProps: fillProps || slot?.fillProps || {},
} );
};
const unregisterSlot: SlotFillBubblesVirtuallyContext[ 'unregisterSlot' ] =
( name, ref ) => {
// Make sure we're not unregistering a slot registered by another element
// See https://github.com/WordPress/gutenberg/pull/19242#issuecomment-590295412
if ( slots.get( name )?.ref === ref ) {
slots.delete( name );
}
};
const updateSlot: SlotFillBubblesVirtuallyContext[ 'updateSlot' ] = (
name,
fillProps
) => {
const slot = slots.get( name );
if ( ! slot ) {
return;
}
if ( isShallowEqual( slot.fillProps, fillProps ) ) {
return;
}
slot.fillProps = fillProps;
const slotFills = fills.get( name );
if ( slotFills ) {
// Force update fills.
slotFills.forEach( ( fill ) => fill.current.rerender() );
}
};
const registerFill: SlotFillBubblesVirtuallyContext[ 'registerFill' ] = (
name,
ref
) => {
fills.set( name, [ ...( fills.get( name ) || [] ), ref ] );
};
const unregisterFill: SlotFillBubblesVirtuallyContext[ 'registerFill' ] = (
name,
ref
) => {
const fillsForName = fills.get( name );
if ( ! fillsForName ) {
return;
}
fills.set(
name,
fillsForName.filter( ( fillRef ) => fillRef !== ref )
);
};
return {
slots,
fills,
registerSlot,
updateSlot,
unregisterSlot,
registerFill,
unregisterFill,
};
}
export default function SlotFillProvider( {
children,
}: SlotFillProviderProps ) {
const registry = useMemo( createSlotRegistry, [] );
return (
<SlotFillContext.Provider value={ registry }>
{ children }
</SlotFillContext.Provider>
);
}