Skip to content

Commit

Permalink
SlotFill: unify registry and fill implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnajdr committed Dec 17, 2024
1 parent 7dd3127 commit 4a6addb
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 354 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import {
fireEvent,
render,
render as baseRender,
screen,
waitFor,
within,
Expand All @@ -13,6 +13,7 @@ import userEvent from '@testing-library/user-event';
/**
* WordPress dependencies
*/
import { SlotFillProvider } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';

Expand Down Expand Up @@ -67,6 +68,10 @@ afterEach( () => {
mockFetchRichUrlData?.mockReset(); // Conditionally reset as it may NOT be a mock.
} );

function render( ui, options ) {
return baseRender( ui, { wrapper: SlotFillProvider, ...options } );
}

/**
* Workaround to trigger an arrow up keypress event.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import userEvent from '@testing-library/user-event';
* WordPress dependencies
*/
import { useState } from '@wordpress/element';

import { SlotFillProvider } from '@wordpress/components';
/**
* Internal dependencies
*/
Expand All @@ -19,16 +19,18 @@ const noop = () => {};
function TestWrapper() {
const [ mediaURL, setMediaURL ] = useState( 'https://example.media' );
return (
<MediaReplaceFlow
mediaId={ 1 }
mediaURL={ mediaURL }
allowedTypes={ [ 'png' ] }
accept="image/*"
onSelect={ noop }
onSelectURL={ setMediaURL }
onError={ noop }
onCloseModal={ noop }
/>
<SlotFillProvider>
<MediaReplaceFlow
mediaId={ 1 }
mediaURL={ mediaURL }
allowedTypes={ [ 'png' ] }
accept="image/*"
onSelect={ noop }
onSelectURL={ setMediaURL }
onError={ noop }
onCloseModal={ noop }
/>
</SlotFillProvider>
);
}

Expand Down
50 changes: 0 additions & 50 deletions packages/components/src/slot-fill/bubbles-virtually/fill.tsx

This file was deleted.

This file was deleted.

This file was deleted.

25 changes: 16 additions & 9 deletions packages/components/src/slot-fill/bubbles-virtually/slot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useMergeRefs } from '@wordpress/compose';
* Internal dependencies
*/
import { View } from '../../view';
import SlotFillContext from './slot-fill-context';
import SlotFillContext from '../context';
import type { WordPressComponentProps } from '../../context';
import type { SlotComponentProps } from '../types';

Expand All @@ -40,25 +40,32 @@ function Slot(
} = props;

const registry = useContext( SlotFillContext );

const instanceRef = useRef( {} );
const ref = useRef< HTMLElement >( null );

// We don't want to unregister and register the slot whenever
// `fillProps` change, which would cause the fill to be re-mounted. Instead,
// we can just update the slot (see hook below).
// For more context, see https://github.com/WordPress/gutenberg/pull/44403#discussion_r994415973
const fillPropsRef = useRef( fillProps );
useLayoutEffect( () => {
fillPropsRef.current = fillProps;
}, [ fillProps ] );

useLayoutEffect( () => {
registry.registerSlot( name, ref, fillPropsRef.current );
return () => registry.unregisterSlot( name, ref );
const instance = instanceRef.current;
registry.registerSlot( name, {
type: 'portal',
instance,
ref,
fillProps: fillPropsRef.current,
} );
return () => registry.unregisterSlot( name, instance );
}, [ registry, name ] );

useLayoutEffect( () => {
registry.updateSlot( name, ref, fillPropsRef.current );
registry.updateSlot( name, {
type: 'portal',
instance: instanceRef.current,
ref,
fillProps: fillPropsRef.current,
} );
} );

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useObservableValue } from '@wordpress/compose';
/**
* Internal dependencies
*/
import SlotFillContext from './slot-fill-context';
import SlotFillContext from '../context';
import type { SlotKey } from '../types';

export default function useSlotFills( name: SlotKey ) {
Expand Down
10 changes: 7 additions & 3 deletions packages/components/src/slot-fill/bubbles-virtually/use-slot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import { useObservableValue } from '@wordpress/compose';
/**
* Internal dependencies
*/
import SlotFillContext from './slot-fill-context';
import type { SlotKey } from '../types';
import SlotFillContext from '../context';
import type { SlotKey, SlotRef } from '../types';

export default function useSlot( name: SlotKey ) {
const registry = useContext( SlotFillContext );
const slot = useObservableValue( registry.slots, name );
return { ...slot };
let ref: SlotRef | undefined;
if ( slot && slot.type === 'portal' ) {
ref = slot.ref;
}
return { ref };
}
19 changes: 14 additions & 5 deletions packages/components/src/slot-fill/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@
*/
import { observableMap } from '@wordpress/compose';
import { createContext } from '@wordpress/element';
import warning from '@wordpress/warning';

/**
* Internal dependencies
*/
import type { BaseSlotFillContext } from './types';
import type { SlotFillRegistry } from './types';

const initialValue: BaseSlotFillContext = {
const initialValue: SlotFillRegistry = {
slots: observableMap(),
fills: observableMap(),
registerSlot: () => {},
registerSlot: () => {
warning(
'Components must be wrapped within `SlotFillProvider`. ' +
'See https://developer.wordpress.org/block-editor/components/slot-fill/'
);
},
unregisterSlot: () => {},
updateSlot: () => {},
registerFill: () => {},
unregisterFill: () => {},
updateFill: () => {},

// This helps the provider know if it's using the default context value or not.
isDefault: true,
};
export const SlotFillContext = createContext( initialValue );

export default SlotFillContext;
export default createContext( initialValue );
Loading

0 comments on commit 4a6addb

Please sign in to comment.