-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Block editor: improve root portal #48803
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,9 +19,14 @@ import { | |
} from '@wordpress/compose'; | ||
import { | ||
createContext, | ||
useState, | ||
useMemo, | ||
useCallback, | ||
useLayoutEffect, | ||
useContext, | ||
useRef, | ||
Fragment, | ||
createElement, | ||
useReducer, | ||
} from '@wordpress/element'; | ||
|
||
/** | ||
|
@@ -41,13 +46,55 @@ import { | |
DEFAULT_BLOCK_EDIT_CONTEXT, | ||
} from '../block-edit/context'; | ||
|
||
const elementContext = createContext(); | ||
const componentsContext = createContext(); | ||
|
||
export const IntersectionObserver = createContext(); | ||
const pendingBlockVisibilityUpdatesPerRegistry = new WeakMap(); | ||
|
||
function useRootPortal( component ) { | ||
const components = useContext( componentsContext ); | ||
|
||
useLayoutEffect( () => { | ||
if ( ! components ) return; | ||
components.add( component ); | ||
return () => { | ||
components.delete( component ); | ||
}; | ||
} ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems fragile. Every time it renders it deletes the component and adds a new one. And when it does that it changes the order of the components. Because of the lack of keys, it will just re-render everything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can add keys 👍 |
||
} | ||
|
||
function Components( { subscriber, components } ) { | ||
const [ , forceRender ] = useReducer( () => ( {} ) ); | ||
subscriber.current = forceRender; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Writing refs during rendering is not recommended in concurrent mode. It seems to be only acceptable when it's for lazily evaluating for once. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What does that mean? |
||
return createElement( Fragment, null, ...components.current ); | ||
} | ||
|
||
function ComponentRenderer( { children } ) { | ||
const subscriber = useRef( () => {} ); | ||
const components = useRef( new Set() ); | ||
return ( | ||
<componentsContext.Provider | ||
value={ useMemo( | ||
() => ( { | ||
add( component ) { | ||
components.current.add( component ); | ||
subscriber.current(); | ||
}, | ||
delete( component ) { | ||
components.current.delete( component ); | ||
subscriber.current(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whenever a component that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll fix this. |
||
}, | ||
} ), | ||
[] | ||
) } | ||
> | ||
<Components subscriber={ subscriber } components={ components } /> | ||
{ children } | ||
</componentsContext.Provider> | ||
); | ||
} | ||
|
||
function Root( { className, ...settings } ) { | ||
const [ element, setElement ] = useState(); | ||
const isLargeViewport = useViewportMatch( 'medium' ); | ||
const { isOutlineMode, isFocusMode, editorMode } = useSelect( | ||
( select ) => { | ||
|
@@ -105,7 +152,6 @@ function Root( { className, ...settings } ) { | |
ref: useMergeRefs( [ | ||
useBlockSelectionClearer(), | ||
useInBetweenInserter(), | ||
setElement, | ||
] ), | ||
className: classnames( 'is-root-container', className, { | ||
'is-outline-mode': isOutlineMode, | ||
|
@@ -116,11 +162,13 @@ function Root( { className, ...settings } ) { | |
settings | ||
); | ||
return ( | ||
<elementContext.Provider value={ element }> | ||
<IntersectionObserver.Provider value={ intersectionObserver }> | ||
<div { ...innerBlocksProps } /> | ||
</IntersectionObserver.Provider> | ||
</elementContext.Provider> | ||
<IntersectionObserver.Provider value={ intersectionObserver }> | ||
<div { ...innerBlocksProps }> | ||
<ComponentRenderer> | ||
{ innerBlocksProps.children } | ||
</ComponentRenderer> | ||
</div> | ||
</IntersectionObserver.Provider> | ||
); | ||
} | ||
|
||
|
@@ -135,7 +183,7 @@ export default function BlockList( settings ) { | |
); | ||
} | ||
|
||
BlockList.__unstableElementContext = elementContext; | ||
BlockList.useRootPortal = useRootPortal; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to also make this unstable for now, but eventually this should be exported in the block editor package as an official API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we can start private. |
||
|
||
function Items( { | ||
placeholder, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be
ComponentsContext
?This also confused me when I first noticed
elementsContext
, all the other contexts in the codebase have an uppercase first character.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a component? :)