Skip to content

Commit

Permalink
[Try] Customizable toolbar contents (#23613)
Browse files Browse the repository at this point in the history
* Customizable toolbar contents

* Export BlockToolbarContents as __experimentalBlockToolbarContents

* Update package-lock.json

* Update package-lock.json

* Use BlockControlsSlot instead of a custom BlockToolbarContents slot

* Update package-lock.json

* rename resize to resizeToolbar

* Renamed symbols for increased readability

* Rename CSS class for increased readability
  • Loading branch information
adamziel authored Jul 7, 2020
1 parent e2da15e commit 5078c43
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 12 deletions.
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@wordpress/token-list": "file:../token-list",
"@wordpress/url": "file:../url",
"@wordpress/viewport": "file:../viewport",
"@wordpress/warning": "file:../warning",
"@wordpress/wordcount": "file:../wordcount",
"classnames": "^2.2.5",
"css-mediaquery": "^0.1.2",
Expand All @@ -60,6 +61,7 @@
"memize": "^1.1.0",
"react-autosize-textarea": "^3.0.2",
"react-spring": "^8.0.19",
"react-transition-group": "^2.9.0",
"redux-multi": "^0.1.12",
"refx": "^3.0.0",
"rememo": "^3.0.0",
Expand Down
17 changes: 13 additions & 4 deletions packages/block-editor/src/components/block-controls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@ import useDisplayBlockControls from '../use-display-block-controls';

const { Fill, Slot } = createSlotFill( 'BlockControls' );

function BlockControlsSlot( props ) {
function BlockControlsSlot( { __experimentalIsExpanded = false, ...props } ) {
const accessibleToolbarState = useContext( ToolbarContext );
return <Slot { ...props } fillProps={ accessibleToolbarState } />;
return (
<Slot
name={ buildSlotName( __experimentalIsExpanded ) }
{ ...props }
fillProps={ accessibleToolbarState }
/>
);
}

function BlockControlsFill( { controls, children } ) {
function BlockControlsFill( { controls, __experimentalIsExpanded, children } ) {
if ( ! useDisplayBlockControls() ) {
return null;
}

return (
<Fill>
<Fill name={ buildSlotName( __experimentalIsExpanded ) }>
{ ( fillProps ) => {
// Children passed to BlockControlsFill will not have access to any
// React Context whose Provider is part of the BlockControlsSlot tree.
Expand All @@ -48,6 +54,9 @@ function BlockControlsFill( { controls, children } ) {
);
}

const buildSlotName = ( isExpanded ) =>
`BlockControls${ isExpanded ? '-expanded' : '' }`;

const BlockControls = BlockControlsFill;

BlockControls.Slot = BlockControlsSlot;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* External dependencies
*/
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { throttle } from 'lodash';

/**
* WordPress dependencies
*/
import { useRef, useState, useEffect, useCallback } from '@wordpress/element';
import warning from '@wordpress/warning';

/**
* Internal dependencies
*/
import BlockControls from '../block-controls';

export default function ExpandedBlockControlsContainer( {
children,
className,
} ) {
return (
<BlockControls.Slot __experimentalIsExpanded>
{ ( fills ) => {
return (
<ExpandedBlockControlsHandler
className={ className }
fills={ fills }
>
{ children }
</ExpandedBlockControlsHandler>
);
} }
</BlockControls.Slot>
);
}

function ExpandedBlockControlsHandler( { fills, className = '', children } ) {
const containerRef = useRef();
const fillsRef = useRef();
const toolbarRef = useRef();
const [ dimensions, setDimensions ] = useState( {} );

const fillsPropRef = useRef();
fillsPropRef.current = fills;
const resizeToolbar = useCallback(
throttle( () => {
const toolbarContentElement = fillsPropRef.current.length
? fillsRef.current
: toolbarRef.current;
if ( ! toolbarContentElement ) {
return;
}
toolbarContentElement.style.position = 'absolute';
toolbarContentElement.style.width = 'auto';
const contentCSS = window.getComputedStyle(
toolbarContentElement,
null
);
setDimensions( {
width: contentCSS.getPropertyValue( 'width' ),
height: contentCSS.getPropertyValue( 'height' ),
} );
toolbarContentElement.style.position = '';
toolbarContentElement.style.width = '';
}, 100 ),
[]
);

useEffect( () => {
const observer = new window.MutationObserver( function (
mutationsList
) {
const hasChildList = mutationsList.find(
( { type } ) => type === 'childList'
);
if ( hasChildList ) {
resizeToolbar();
}
} );

observer.observe( containerRef.current, {
childList: true,
subtree: true,
} );

return () => observer.disconnect();
}, [] );

useEffect( () => {
if ( fills.length > 1 ) {
warning(
`${ fills.length } <BlockControls isExpanded> slots were registered but only one may be displayed.`
);
}
}, [ fills.length ] );

const displayFill = fills[ 0 ];
return (
<div
className="block-editor-block-toolbar-animated-width-container"
ref={ containerRef }
style={ dimensions }
>
<TransitionGroup>
{ displayFill ? (
<CSSTransition
key="fills"
timeout={ 300 }
classNames="block-editor-block-toolbar-content"
>
<div className={ className } ref={ fillsRef }>
{ displayFill }
</div>
</CSSTransition>
) : (
<CSSTransition
key="default"
timeout={ 300 }
classNames="block-editor-block-toolbar-content"
>
<div className={ className } ref={ toolbarRef }>
{ children }
</div>
</CSSTransition>
) }
</TransitionGroup>
</div>
);
}
14 changes: 11 additions & 3 deletions packages/block-editor/src/components/block-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ import BlockFormatControls from '../block-format-controls';
import BlockSettingsMenu from '../block-settings-menu';
import BlockDraggable from '../block-draggable';
import { useShowMoversGestures, useToggleBlockHighlight } from './utils';
import ExpandedBlockControlsContainer from './expanded-block-controls-container';

export default function BlockToolbar( { hideDragHandle } ) {
export default function BlockToolbar( {
hideDragHandle,
__experimentalExpandedControl = false,
} ) {
const {
blockClientIds,
blockClientId,
Expand Down Expand Up @@ -94,8 +98,12 @@ export default function BlockToolbar( { hideDragHandle } ) {
shouldShowMovers && 'is-showing-movers'
);

const Wrapper = __experimentalExpandedControl
? ExpandedBlockControlsContainer
: 'div';

return (
<div className={ classes }>
<Wrapper className={ classes }>
<div
className="block-editor-block-toolbar__mover-switcher-container"
ref={ nodeRef }
Expand Down Expand Up @@ -143,6 +151,6 @@ export default function BlockToolbar( { hideDragHandle } ) {
</>
) }
<BlockSettingsMenu clientIds={ blockClientIds } />
</div>
</Wrapper>
);
}
28 changes: 28 additions & 0 deletions packages/block-editor/src/components/block-toolbar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,31 @@
display: block;
}
}

.block-editor-block-toolbar-animated-width-container {
position: relative;
overflow: hidden;
transition: width 300ms;
}

.block-editor-block-toolbar-content-enter {
position: absolute;
top: 0;
left: 0;
width: auto;
opacity: 0;
}
.block-editor-block-toolbar-content-enter-active {
position: absolute;
opacity: 1;
transition: opacity 300ms;
}
.block-editor-block-toolbar-content-exit {
width: auto;
opacity: 1;
pointer-events: none;
}
.block-editor-block-toolbar-content-exit-active {
opacity: 0;
transition: opacity 300ms;
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ export default function BlockEditorArea( {
aria-label={ __( 'Block tools' ) }
>
{ hasSelectedBlock && ! isRootBlockSelected && (
<BlockToolbar hideDragHandle />
<BlockToolbar
hideDragHandle
__experimentalExpandedControl
/>
) }
</NavigableToolbar>
<Popover.Slot name="block-toolbar" />
Expand Down

0 comments on commit 5078c43

Please sign in to comment.