Skip to content

Commit

Permalink
Block editor: improve root portal
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Mar 6, 2023
1 parent 95d52c4 commit e8f0a0d
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 102 deletions.
68 changes: 58 additions & 10 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ import {
} from '@wordpress/compose';
import {
createContext,
useState,
useMemo,
useCallback,
useLayoutEffect,
useContext,
useRef,
Fragment,
createElement,
useReducer,
} from '@wordpress/element';

/**
Expand All @@ -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 );
};
} );
}

function Components( { subscriber, components } ) {
const [ , forceRender ] = useReducer( () => ( {} ) );
subscriber.current = forceRender;
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();
},
} ),
[]
) }
>
<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 ) => {
Expand Down Expand Up @@ -105,7 +152,6 @@ function Root( { className, ...settings } ) {
ref: useMergeRefs( [
useBlockSelectionClearer(),
useInBetweenInserter(),
setElement,
] ),
className: classnames( 'is-root-container', className, {
'is-outline-mode': isOutlineMode,
Expand All @@ -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>
);
}

Expand All @@ -135,7 +183,7 @@ export default function BlockList( settings ) {
);
}

BlockList.__unstableElementContext = elementContext;
BlockList.useRootPortal = useRootPortal;

function Items( {
placeholder,
Expand Down
15 changes: 3 additions & 12 deletions packages/block-editor/src/hooks/duotone.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import namesPlugin from 'colord/plugins/names';
import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
import { addFilter } from '@wordpress/hooks';
import { useMemo, useContext, createPortal } from '@wordpress/element';
import { useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';

/**
Expand Down Expand Up @@ -255,14 +255,6 @@ function BlockDuotoneStyles( { name, duotoneStyle, id } ) {
defaultSetting: 'color.defaultDuotone',
} );

const element = useContext( BlockList.__unstableElementContext );

// Portals cannot exist without a container.
// Guard against empty Duotone styles.
if ( ! element || ! duotoneStyle ) {
return null;
}

let colors = duotoneStyle;

if ( ! Array.isArray( colors ) && colors !== 'unset' ) {
Expand All @@ -282,13 +274,12 @@ function BlockDuotoneStyles( { name, duotoneStyle, id } ) {
duotoneSupportSelectors
);

return createPortal(
BlockList.useRootPortal(
<InlineDuotone
selector={ selectorsGroup }
id={ id }
colors={ colors }
/>,
element
/>
);
}

Expand Down
50 changes: 20 additions & 30 deletions packages/block-editor/src/hooks/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
PanelBody,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useContext, createPortal } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -364,7 +363,6 @@ export const withLayoutStyles = createHigherOrderComponent(
hasLayoutBlockSupport && ! disableLayoutStyles;
const id = useInstanceId( BlockListBlock );
const defaultThemeLayout = useSetting( 'layout' ) || {};
const element = useContext( BlockList.__unstableElementContext );
const { layout } = attributes;
const { default: defaultBlockLayout } =
getBlockSupport( name, layoutBlockSupportKey ) || {};
Expand Down Expand Up @@ -405,26 +403,23 @@ export const withLayoutStyles = createHigherOrderComponent(
layoutClasses
);

return (
<>
{ shouldRenderLayoutStyles &&
element &&
!! css &&
createPortal(
<LayoutStyle
blockName={ name }
selector={ selector }
css={ css }
layout={ usedLayout }
style={ attributes?.style }
/>,
element
) }
<BlockListBlock
{ ...props }
__unstableLayoutClassNames={ layoutClassNames }
BlockList.useRootPortal(
shouldRenderLayoutStyles && !! css && (
<LayoutStyle
blockName={ name }
selector={ selector }
css={ css }
layout={ usedLayout }
style={ attributes?.style }
/>
</>
)
);

return (
<BlockListBlock
{ ...props }
__unstableLayoutClassNames={ layoutClassNames }
/>
);
}
);
Expand All @@ -449,7 +444,6 @@ export const withChildLayoutStyles = createHigherOrderComponent(
const shouldRenderChildLayoutStyles =
hasChildLayout && ! disableLayoutStyles;

const element = useContext( BlockList.__unstableElementContext );
const id = useInstanceId( BlockListBlock );
const selector = `.wp-container-content-${ id }`;

Expand All @@ -472,15 +466,11 @@ export const withChildLayoutStyles = createHigherOrderComponent(
shouldRenderChildLayoutStyles && !! css, // Only attach a container class if there is generated CSS to be attached.
} );

return (
<>
{ shouldRenderChildLayoutStyles &&
element &&
!! css &&
createPortal( <style>{ css }</style>, element ) }
<BlockListBlock { ...props } className={ className } />
</>
BlockList.useRootPortal(
shouldRenderChildLayoutStyles && !! css && <style>{ css }</style>
);

return <BlockListBlock { ...props } className={ className } />;
}
);

Expand Down
20 changes: 5 additions & 15 deletions packages/block-editor/src/hooks/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ import {
} from '@wordpress/components';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import {
useContext,
useMemo,
createPortal,
Platform,
} from '@wordpress/element';
import { useMemo, Platform } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';

/**
Expand Down Expand Up @@ -353,7 +348,6 @@ export const withPositionStyles = createHigherOrderComponent(
hasPositionBlockSupport && ! useIsPositionDisabled( props );

const id = useInstanceId( BlockListBlock );
const element = useContext( BlockList.__unstableElementContext );

// Higher specificity to override defaults in editor UI.
const positionSelector = `.wp-container-${ id }.wp-container-${ id }`;
Expand All @@ -377,15 +371,11 @@ export const withPositionStyles = createHigherOrderComponent(
!! attributes?.style?.position?.type,
} );

return (
<>
{ allowPositionStyles &&
element &&
!! css &&
createPortal( <style>{ css }</style>, element ) }
<BlockListBlock { ...props } className={ className } />
</>
BlockList.useRootPortal(
allowPositionStyles && !! css && <style>{ css }</style>
);

return <BlockListBlock { ...props } className={ className } />;
}
);

Expand Down
47 changes: 21 additions & 26 deletions packages/block-editor/src/hooks/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useContext, useMemo, createPortal } from '@wordpress/element';
import { useMemo } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import {
getBlockSupport,
Expand Down Expand Up @@ -418,33 +418,28 @@ const withElementsStyles = createHigherOrderComponent(
return elementCssRules.length > 0 ? elementCssRules : undefined;
}, [ props.attributes.style?.elements ] );

const element = useContext( BlockList.__unstableElementContext );
BlockList.useRootPortal(
styles && (
<style
dangerouslySetInnerHTML={ {
__html: styles,
} }
/>
)
);

return (
<>
{ styles &&
element &&
createPortal(
<style
dangerouslySetInnerHTML={ {
__html: styles,
} }
/>,
element
) }

<BlockListBlock
{ ...props }
className={
props.attributes.style?.elements
? classnames(
props.className,
blockElementsContainerIdentifier
)
: props.className
}
/>
</>
<BlockListBlock
{ ...props }
className={
props.attributes.style?.elements
? classnames(
props.className,
blockElementsContainerIdentifier
)
: props.className
}
/>
);
}
);
Expand Down
10 changes: 1 addition & 9 deletions packages/block-library/src/gallery/gap-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import {
BlockList,
__experimentalGetGapCSSValue as getGapCSSValue,
} from '@wordpress/block-editor';
import { useContext, createPortal } from '@wordpress/element';

export default function GapStyles( { blockGap, clientId } ) {
const styleElement = useContext( BlockList.__unstableElementContext );
// --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default
// gap on the gallery.
const fallbackValue = `var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )`;
Expand All @@ -35,11 +33,5 @@ export default function GapStyles( { blockGap, clientId } ) {
gap: ${ gapValue }
}`;

const GapStyle = () => {
return <style>{ gap }</style>;
};

return gap && styleElement
? createPortal( <GapStyle />, styleElement )
: null;
BlockList.useRootPortal( gap ? <style>{ gap }</style> : null );
}

0 comments on commit e8f0a0d

Please sign in to comment.