Skip to content

Commit

Permalink
Core Columns Block - adds ability to vertically align all the columns (
Browse files Browse the repository at this point in the history
…#13899)

* Adds ability to valign all the columns via parent

Proof of concept demonstrating ability to change the valignment of columns with a parent column Block

* Adds ability to v-align individual Columns

* Adds ability to select individual Column Blocks to access Block Toolbar

Previously the ability to select an individual Column Block was disabled via CSS. This was because the Column itself was just a passthrough element with no UI or Tools of its own. Now we’ve introduced the v-align toolbar on the Column the Block needs to be selectable.

* Adds Material UI icons

@thomasguillot recommended using Material UI icons. Added dedicated icons file and implemented.

* Updates to add i18n to text strings

Ensure all text strings are translatable. Also reuse icon defs in parent Columns Block alignment settings

* Extracts reusable VAlignToolbar to DRY up implementation

* Fixes alignment attribute not updating

* Updates Toolbar API to observe Single Responsibility

Previously Toolbar was too aware of its context and assumed responsibility for updating parent Block’s attributes via setAttributes prop. Revised to utilise callback prop to propagate change events up to the parent. Now upto the consuming component to observe the change and handle it as required. This makes the VAlignToolbar easy to reuse in other locations.

Refactor Blocks to utilise new pattern.

* Extract deprecations for readability

This prepares deprecations for adding a new deprecation to handle the addition of the `verticalAlignment` attribute.

* Updates valignment default to no alignment specified

Previously we enforced a “top” valign on all columns. This seemed heavy handed given that Themes might wish to control this. Now we default to no valignment and allow user to optionally choose to specifiy a valignment.

* Adds ability to toggle alignment settings on and off

Previously once alignment had been set there was no way to disable it. Added ability to toggle each setting on and off.

* Adds editor preview of vertical alignment

* Adds reusable valign toolbar to editor package components

* Updates Columns Block to utilise new editor package toolbar component

Previously we utilised a bespoke toolbar for the Block. As this toolbar is also required in other components determined best to extract to a resuable component within the @wordpress/editor package.

Updates Block to utilise this new component. Removes old bespoke component.

See Slack convo: https://wordpress.slack.com/archives/C02QB2JS7/p1550657882430900

* Adds documentation to the BlockVerticalAlignmentToolbar

* Updates to use simplified arrow function syntax

* Fixes deprecation save definition back to original version

Previously the save definition of the deprecation was accidentally altered during testing. Restoring to the current state of `master` to ensure that we haven’t broken the existing deprecation when moving this block to a seperate file.

* Updates known classes to use simplified classnames util style

Resolves

* #13899 (comment)
* #13899 (comment)
* #13899 (comment)

* remove extraneous file with icons

* Fixes icon vars to use standard coding style

Resolves #13899 (comment)

* Updates test to use `it` instead of `test`

Resolves #13899 (comment)

* Fix spelling and grammatical errors

Resolves

* #13899 (comment)
* #13899 (comment)

* Removes duplicate dependencies comment

Resolves #13899 (comment)

* Updates code readability and self documentation

Previously the tenary to determine which icon to show when in “collapsed” mode wasn’t easy to comprehend.

Update to add clear variable names to make it more explicit about what happens when there is/isn’t a active alignment value set.

This address the concern raised in #13899 (comment) but looks to prefer code readability over absolutely succinct code.

* Consolidates selectors for improve readability/comprehension

Prevously nested of selectors was getting a little confusing. Pulled onto a single line to this unit of code in a single location.

Resolves #13899 (comment)

* Updates to consolidate similar CSS rules

Resolves #13899 (comment)

* Fixes spelling error

Resolves #13899 (comment)

* Removes unecessary type checking in favour of coercion rules

Previously we were explicitly checking the type of the `verticalAlignment` attr with `isNil()`. However this only checks for `undefined` or `null`. Other falsey values would have passed here which is undesirable. As `undefined` and `null` are both coerced to falsey we can remove the dep on `isNil` and simplify.

Resolves #13899 (comment)

* update icon sizes to match others in Toolbar

* Fixes bottom alignment on front end

Specificity overide to ensure margin is applied and preserved on last child to ensure that when columns are aligned to bottom they are are flush with each other

Resolves #13899 (comment)

* Fix failing e2e testing due to additional of toolbar

e2e tests were failing due to introduction of valign toolbar meaning that number of tab stops needed to be increased by 3 (the number of items in the new toolbar).

Also uncovered a bug with Pupeteer not handling Cmd + A to “Select All” on a Mac. This is a known issue (puppeteer/puppeteer#1313
) and it is now worked around using arrows and backspace.

* Fixes toolbar snapshot unit test

* Adds force update of child columns when parent setting changes

Previously it was possible to have a setting on the parent and individual settings on the individual columns. However the parent would still show an alignment setting even though not all of the child columns had that alignment.

Now if the parent has an alignment setting it will be auto applied to the state of the child columns directly. If a child column changes it’s individual alignment to something which does not match the parent’s alignment setting then the parent’s alignment setting is removed. However the individual column alignments still stay “as is” because each individual column has the valign setting directly rather than pseudo inheried from the parent via CSS.

Addresses: #13899 (comment)

* Updates changelog with `BlockVerticalAlignmentToolbar` feature

* Adds valign feature to changelog for Block Library

* Creates dedicated files for large code blocks

Previously all code blocks were in a single large index file. This was becoming unwieldy and difficult to manage/edit. Extract each large block into it’s own file for readability and maintainability.

* Updates to avoid tests depending on erroneous _id prop

Previously the `_id` prop was included purely to make testing easier (more resilient). On reflection introducing code just for tests was a bad idea. Now depends on string comparison which is an acceptable compromise.

Resolves #13899 (comment)

* Removes usage of unused attribute introduced as experiment

This attribute was introduced as part of experimenting in e759315 and never removed. It’s unused and has been removed.

* Updates example to run without erroring due to missing var

Resolves #13899 (comment)

* Fixes comment to match coding style guidelines

Resolves #13899 (comment)

* Fixes to avoid mutation in render method

Previously in order to reset the Parent’s alignment when one of the child Columns set it’s own alignment, the render method of the Parent Columns mutated the attributes causing a re-render. To avoid this we now reset the Parent from the Child Column whose alignment changed.

Addresses #13899 (comment)

* Fixes single Column Block breadcrumb to RHS of boundary

Resolves point raised in #13899 (comment)

* Restores pass through click behaviour on single Column Block

As discussed [here](#13899 (comment)) selection of parent/child Blocks is currently being worked on elsewhere. Therefore to get the vertical-alignment shipped, this commit reverts the change that made Columns individually selectable. Now reverts to original behaviour of only being selectable via the Block Inspector (or keyboard). This assumes that future PRs will land better Parent/Child selection behaviour. Also removes unwanted space within the Columns themselves.

* Updates to tidy CSS selectors for improved readability

* Updates to move VAlign Toolbar into Block Editor package

Previously the editor package container the toolbar. Now the new Block Editor should be the new home for the toolbar

* Automated README update

* Updates changlogs to reflect release status
  • Loading branch information
getdave committed Mar 19, 2019
1 parent 7e5f1d8 commit c34d6b7
Show file tree
Hide file tree
Showing 16 changed files with 783 additions and 196 deletions.
6 changes: 6 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ Undocumented declaration.

Undocumented declaration.

### BlockVerticalAlignmentToolbar

[src/index.js#L15-L15](src/index.js#L15-L15)

Undocumented declaration.

### ColorPalette

[src/index.js#L15-L15](src/index.js#L15-L15)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
BlockVerticalAlignmentToolbar
=============================

`BlockVerticalAlignmentToolbar` is a simple `Toolbar` component designed to provide _vertical_ alignment UI controls for use within the editor `BlockControls` toolbar.

This builds upon similar patterns to the [`BlockAlignmentToolbar`](https://github.com/WordPress/gutenberg/tree/master/packages/editor/src/components/block-alignment-toolbar) but is focused on vertical alignment only.

## Usage

In a block's `edit` implementation, render a `<BlockControls />` component. Then inside of this add the `<BlockVerticalAlignmentToolbar />` where required.


```jsx
import { registerBlockType } from '@wordpress/blocks';
import { Fragment } from '@wordpress/element';
import {
BlockControls,
BlockVerticalAlignmentToolbar,
} from '@wordpress/block-editor';

registerBlockType( 'my-plugin/my-block', {
// ...

attributes: {
// other attributes here
// ...

verticalAlignment: {
type: 'string',
},
},

edit( { attributes, setAttributes } ) {

const { verticalAlignment } = attributes;

// Change handler to set Block `attributes`
const onChange = ( alignment ) => setAttributes( { verticalAlignment: alignment } );

return (
<Fragment>
<BlockControls>
<BlockVerticalAlignmentToolbar
onChange={ onChange }
value={ verticalAlignment }
/>
</BlockControls>
<div>
// your Block here
</div>
</Fragment>
);
}
} );
```

_Note:_ by default if you do not provide an initial `value` prop for the current alignment value, then no value will be selected (ie: there is no default alignment set).

_Note:_ the user can repeatedly click on the toolbar buttons to toggle the alignment values on/off. This is handled within the component.

## Props

### `value`
* **Type:** `String`
* **Default:** `undefined`
* **Options:**: `top`, `center`, `bottom`

The current value of the alignment setting. You may only choose from the `Options` listed above.


### `onChange`
* **Type:** `Function`

A callback function invoked when the toolbar's alignment value is changed via an interaction with any of the toolbar's buttons. Called with the new alignment value (ie: `top`, `center`, `bottom`, `undefined`) as the only argument.

Note: the value may be `undefined` if the user has toggled the component "off".

```js
const onChange = ( alignment ) => setAttributes( { verticalAlignment: alignment } );
```

## Examples

The [Core Columns](https://github.com/WordPress/gutenberg/tree/master/packages/block-library/src/columns) Block utilises the `BlockVerticalAlignmentToolbar`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* WordPress dependencies
*/
import { Path, SVG } from '@wordpress/components';

export const alignBottom = (
<SVG xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
<Path fill="none" d="M0 0h24v24H0V0z" />
<Path d="M16 13h-3V3h-2v10H8l4 4 4-4zM4 19v2h16v-2H4z" />
</SVG>
);

export const alignCenter = (
<SVG xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
<Path fill="none" d="M0 0h24v24H0V0z" />
<Path d="M8 19h3v4h2v-4h3l-4-4-4 4zm8-14h-3V1h-2v4H8l4 4 4-4zM4 11v2h16v-2H4z"
/>
</SVG>
);

export const alignTop = (
<SVG xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
<Path fill="none" d="M0 0h24v24H0V0z" />
<Path d="M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z" />
</SVG>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* WordPress dependencies
*/
import { _x } from '@wordpress/i18n';
import { Toolbar } from '@wordpress/components';
import { withViewportMatch } from '@wordpress/viewport';
import { withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { withBlockEditContext } from '../block-edit/context';
import { alignTop, alignCenter, alignBottom } from './icons';

const BLOCK_ALIGNMENTS_CONTROLS = {
top: {
icon: alignTop,
title: _x( 'Vertically Align Top', 'Block vertical alignment setting' ),
},
center: {
icon: alignCenter,
title: _x( 'Vertically Align Middle', 'Block vertical alignment setting' ),
},
bottom: {
icon: alignBottom,
title: _x( 'Vertically Align Bottom', 'Block vertical alignment setting' ),
},
};

const DEFAULT_CONTROLS = [ 'top', 'center', 'bottom' ];
const DEFAULT_CONTROL = 'top';

export function BlockVerticalAlignmentToolbar( { isCollapsed, value, onChange, controls = DEFAULT_CONTROLS } ) {
function applyOrUnset( align ) {
return () => onChange( value === align ? undefined : align );
}

const activeAlignment = BLOCK_ALIGNMENTS_CONTROLS[ value ];
const defaultAlignmentControl = BLOCK_ALIGNMENTS_CONTROLS[ DEFAULT_CONTROL ];

return (
<Toolbar
isCollapsed={ isCollapsed }
icon={ activeAlignment ? activeAlignment.icon : defaultAlignmentControl.icon }
label={ _x( 'Change Alignment', 'Block vertical alignment setting label' ) }
controls={
controls.map( ( control ) => {
return {
...BLOCK_ALIGNMENTS_CONTROLS[ control ],
isActive: value === control,
onClick: applyOrUnset( control ),
};
} )
}
/>
);
}

export default compose(
withBlockEditContext( ( { clientId } ) => {
return {
clientId,
};
} ),
withViewportMatch( { isLargeViewport: 'medium' } ),
withSelect( ( select, { clientId, isLargeViewport, isCollapsed } ) => {
const { getBlockRootClientId, getEditorSettings } = select( 'core/editor' );
return {
isCollapsed: isCollapsed || ! isLargeViewport || (
! getEditorSettings().hasFixedToolbar &&
getBlockRootClientId( clientId )
),
};
} ),
)( BlockVerticalAlignmentToolbar );
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BlockVerticalAlignmentToolbar should match snapshot 1`] = `
<Toolbar
controls={
Array [
Object {
"icon": <SVG
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<Path
d="M0 0h24v24H0V0z"
fill="none"
/>
<Path
d="M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z"
/>
</SVG>,
"isActive": true,
"onClick": [Function],
"title": "Vertically Align Top",
},
Object {
"icon": <SVG
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<Path
d="M0 0h24v24H0V0z"
fill="none"
/>
<Path
d="M8 19h3v4h2v-4h3l-4-4-4 4zm8-14h-3V1h-2v4H8l4 4 4-4zM4 11v2h16v-2H4z"
/>
</SVG>,
"isActive": false,
"onClick": [Function],
"title": "Vertically Align Middle",
},
Object {
"icon": <SVG
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<Path
d="M0 0h24v24H0V0z"
fill="none"
/>
<Path
d="M16 13h-3V3h-2v10H8l4 4 4-4zM4 19v2h16v-2H4z"
/>
</SVG>,
"isActive": false,
"onClick": [Function],
"title": "Vertically Align Bottom",
},
]
}
icon={
<SVG
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<Path
d="M0 0h24v24H0V0z"
fill="none"
/>
<Path
d="M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z"
/>
</SVG>
}
label="Change Alignment"
/>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* Internal dependencies
*/
import { BlockVerticalAlignmentToolbar } from '../';

describe( 'BlockVerticalAlignmentToolbar', () => {
const alignment = 'top';
const onChange = jest.fn();

const wrapper = shallow( <BlockVerticalAlignmentToolbar value={ alignment } onChange={ onChange } /> );

const controls = wrapper.props().controls;

afterEach( () => {
onChange.mockClear();
} );

it( 'should match snapshot', () => {
expect( wrapper ).toMatchSnapshot();
} );

it( 'should call onChange with undefined, when the control is already active', () => {
const activeControl = controls.find( ( { title } ) => title.toLowerCase().includes( alignment ) );
activeControl.onClick();

expect( activeControl.isActive ).toBe( true );
expect( onChange ).toHaveBeenCalledTimes( 1 );
expect( onChange ).toHaveBeenCalledWith( undefined );
} );

it( 'should call onChange with alignment value when the control is inactive', () => {
// note "middle" alias for "center"
const inactiveCenterControl = controls.find( ( { title } ) => title.toLowerCase().includes( 'middle' ) );

inactiveCenterControl.onClick();

expect( inactiveCenterControl.isActive ).toBe( false );
expect( onChange ).toHaveBeenCalledTimes( 1 );
expect( onChange ).toHaveBeenCalledWith( 'center' );
} );
} );
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as BlockEdit } from './block-edit';
export { default as BlockFormatControls } from './block-format-controls';
export { default as BlockNavigationDropdown } from './block-navigation/dropdown';
export { default as BlockIcon } from './block-icon';
export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar';
export { default as ColorPalette } from './color-palette';
export { default as withColorContext } from './color-palette/with-color-context';
export * from './colors';
Expand Down
4 changes: 4 additions & 0 deletions packages/block-library/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.4.0 (Unreleased)

- Add vertical alignment controls to `columns` Block ([#13899](https://github.com/WordPress/gutenberg/pull/13899/)).

## 2.3.0 (2019-03-06)

### New Feature
Expand Down

0 comments on commit c34d6b7

Please sign in to comment.