Skip to content
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

Cover Block: Normalize the block toolbar #29247

Merged
merged 12 commits into from
Mar 15, 2021
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Alignment Matrix Control

The alignment matrix control allows users to quickly adjust inner block alignment; this is in contrast to the alignment toolbar that aligns the frame block.

![Button components](https://i.imgur.com/PxYkgL5.png)

## Table of contents

- [Alignment Matrix Control](#alignment-matrix-control)
- [Table of contents](#table-of-contents)
- [Design guidelines](#design-guidelines)
- [Usage](#usage)
- [Development guidelines](#development-guidelines)
- [Usage](#usage-1)
- [Props](#props)

## Design guidelines

### Usage

The alignment matrix is a specialized tool, and it's used in the cover block.

![Cover](https://i.imgur.com/nJjqen8.png)

As an example, here's the matrix alignment tool in action.

![center](https://i.imgur.com/0Ce1fZm.png)

![rop_right](https://i.imgur.com/yGGf6IP.png)

## Development guidelines

### Usage

```jsx
// This is a paraphrased example from the cover block
import {
BlockControls,
__experimentalBlockAlignmentMatrixControl as BlockAlignmentMatrixControl
} from "@wordpress/block-editor";

const controls = (
<>
<BlockControls>
<BlockAlignmentMatrixControl
label={ __( 'Change content position' ) }
value={ contentPosition }
onChange={ ( nextPosition ) =>
setAttributes( { contentPosition: nextPosition } )
}
/>
</BlockControls>
</>
}
```

### Props

| Name | Type | Default | Description |
| ---------- | ---------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `label` | `string` | `Change matrix alignment` | concise description of tool's functionality. |
| `onChange` | `function` | `noop` | the function to execute upon a user's change of the matrix state |
| `value` | `string` | `center` | describes the content alignment location and can be `top`, `right`, `bottom`, `left`, `topRight`, `bottomRight`, `bottomLeft`, `topLeft` |
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import { DOWN } from '@wordpress/keycodes';
import {
ToolbarButton,
Dropdown,
ToolbarGroup,
__experimentalAlignmentMatrixControl as AlignmentMatrixControl,
} from '@wordpress/components';

export function BlockAlignmentMatrixToolbar( props ) {
function BlockAlignmentMatrixControl( props ) {
const {
label = __( 'Change matrix alignment' ),
onChange = noop,
Expand All @@ -23,7 +22,7 @@ export function BlockAlignmentMatrixToolbar( props ) {
} = props;

const icon = <AlignmentMatrixControl.Icon value={ value } />;
const className = 'block-editor-block-alignment-matrix-toolbar';
const className = 'block-editor-block-alignment-matrix-control';
const popoverClassName = `${ className }__popover`;
const isAlternate = true;

Expand All @@ -42,18 +41,16 @@ export function BlockAlignmentMatrixToolbar( props ) {
};

return (
<ToolbarGroup>
<ToolbarButton
onClick={ onToggle }
aria-haspopup="true"
aria-expanded={ isOpen }
onKeyDown={ openOnArrowDown }
label={ label }
icon={ icon }
showTooltip
disabled={ isDisabled }
/>
</ToolbarGroup>
<ToolbarButton
onClick={ onToggle }
aria-haspopup="true"
aria-expanded={ isOpen }
onKeyDown={ openOnArrowDown }
label={ label }
icon={ icon }
showTooltip
disabled={ isDisabled }
/>
);
} }
renderContent={ () => (
Expand All @@ -67,4 +64,4 @@ export function BlockAlignmentMatrixToolbar( props ) {
);
}

export default BlockAlignmentMatrixToolbar;
export default BlockAlignmentMatrixControl;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.block-editor-block-alignment-matrix-toolbar__popover {
.block-editor-block-alignment-matrix-control__popover {
.components-popover__content {
min-width: 0;
width: auto;
Expand All @@ -7,5 +7,4 @@
padding: $grid-unit;
}
}

}

This file was deleted.

48 changes: 48 additions & 0 deletions packages/block-editor/src/components/block-controls/fill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* External dependencies
*/
import { isEmpty } from 'lodash';

/**
* WordPress dependencies
*/
import {
__experimentalToolbarContext as ToolbarContext,
ToolbarGroup,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import useDisplayBlockControls from '../use-display-block-controls';
import groups from './groups';

export default function BlockControlsFill( {
group = 'default',
controls,
children,
} ) {
if ( ! useDisplayBlockControls() ) {
return null;
}
const Fill = groups[ group ].Fill;

return (
<Fill>
{ ( fillProps ) => {
// Children passed to BlockControlsFill will not have access to any
// React Context whose Provider is part of the BlockControlsSlot tree.
// So we re-create the Provider in this subtree.
const value = ! isEmpty( fillProps ) ? fillProps : null;
return (
<ToolbarContext.Provider value={ value }>
{ group === 'default' && (
<ToolbarGroup controls={ controls } />
) }
{ children }
</ToolbarContext.Provider>
);
} }
</Fill>
);
}
18 changes: 18 additions & 0 deletions packages/block-editor/src/components/block-controls/groups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* WordPress dependencies
*/
import { createSlotFill } from '@wordpress/components';

const BlockControlsDefault = createSlotFill( 'BlockControls' );
const BlockControlsBlock = createSlotFill( 'BlockControlsBlock' );
const BlockControlsInline = createSlotFill( 'BlockFormatControls' );
const BlockControlsOther = createSlotFill( 'BlockControlsOther' );

const groups = {
default: BlockControlsDefault,
block: BlockControlsBlock,
inline: BlockControlsInline,
other: BlockControlsOther,
};

export default groups;
56 changes: 10 additions & 46 deletions packages/block-editor/src/components/block-controls/index.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,19 @@
/**
* External dependencies
*/
import { isEmpty } from 'lodash';

/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
import {
__experimentalToolbarContext as ToolbarContext,
createSlotFill,
ToolbarGroup,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import useDisplayBlockControls from '../use-display-block-controls';

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

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

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

return (
<Fill>
{ ( fillProps ) => {
// Children passed to BlockControlsFill will not have access to any
// React Context whose Provider is part of the BlockControlsSlot tree.
// So we re-create the Provider in this subtree.
const value = ! isEmpty( fillProps ) ? fillProps : null;
return (
<ToolbarContext.Provider value={ value }>
<ToolbarGroup controls={ controls } />
{ children }
</ToolbarContext.Provider>
);
} }
</Fill>
);
}
import BlockControlsFill from './fill';
import BlockControlsSlot from './slot';

const BlockControls = BlockControlsFill;

BlockControls.Slot = BlockControlsSlot;

// This is just here for backward compatibility
export const BlockFormatControls = ( props ) => {
return <BlockControlsFill group="inline" { ...props } />;
};
BlockFormatControls.Slot = ( props ) => {
return <BlockControlsSlot group="inline" { ...props } />;
};

export default BlockControls;
45 changes: 45 additions & 0 deletions packages/block-editor/src/components/block-controls/slot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
import {
__experimentalToolbarContext as ToolbarContext,
ToolbarGroup,
__experimentalUseSlot as useSlot,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import groups from './groups';

export default function BlockControlsSlot( { group = 'default', ...props } ) {
const accessibleToolbarState = useContext( ToolbarContext );
const Slot = groups[ group ].Slot;
const slot = useSlot( Slot.__unstableName );
const hasFills = Boolean( slot.fills && slot.fills.length );

if ( ! hasFills ) {
return null;
}

if ( group === 'default' ) {
return (
<Slot
{ ...props }
bubblesVirtually
fillProps={ accessibleToolbarState }
/>
);
}

return (
<ToolbarGroup>
<Slot
{ ...props }
bubblesVirtually
fillProps={ accessibleToolbarState }
/>
</ToolbarGroup>
);
}
Loading