Skip to content

Commit 106f41d

Browse files
committed
Blocks: Extract and factorize block alignment controls
1 parent 9635125 commit 106f41d

File tree

5 files changed

+128
-193
lines changed

5 files changed

+128
-193
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from 'i18n';
5+
import { Toolbar } from 'components';
6+
7+
const BLOCK_ALIGNMENTS_CONTROLS = {
8+
left: {
9+
icon: 'align-left',
10+
title: __( 'Align left' ),
11+
},
12+
center: {
13+
icon: 'align-center',
14+
title: __( 'Align center' ),
15+
},
16+
right: {
17+
icon: 'align-right',
18+
title: __( 'Align right' ),
19+
},
20+
wide: {
21+
icon: 'align-wide',
22+
title: __( 'Wide width' ),
23+
},
24+
full: {
25+
icon: 'align-full-width',
26+
title: __( 'Full width' ),
27+
},
28+
};
29+
30+
const DEFAULT_CONTROLS = [ 'left', 'center', 'right' ];
31+
32+
export default function BlockAlignmentToolbar( { value, onChange, controls = DEFAULT_CONTROLS } ) {
33+
function applyOrUnset( align ) {
34+
return () => onChange( value === align ? undefined : align );
35+
}
36+
37+
return (
38+
<Toolbar
39+
controls={
40+
controls.map( control => {
41+
return {
42+
...BLOCK_ALIGNMENTS_CONTROLS[ control ],
43+
isActive: value === control,
44+
onClick: applyOrUnset( control ),
45+
};
46+
} )
47+
}
48+
/>
49+
);
50+
}

blocks/library/button/index.js

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,11 @@ import { IconButton } from 'components';
99
import './style.scss';
1010
import { registerBlockType, query } from '../../api';
1111
import Editable from '../../editable';
12+
import BlockControls from '../../block-controls';
13+
import BlockAlignmentToolbar from '../../block-alignment-toolbar';
1214

1315
const { attr, children } = query;
1416

15-
/**
16-
* Returns an attribute setter with behavior that if the target value is
17-
* already the assigned attribute value, it will be set to undefined.
18-
*
19-
* @param {string} align Alignment value
20-
* @return {Function} Attribute setter
21-
*/
22-
function applyOrUnset( align ) {
23-
return ( attributes, setAttributes ) => {
24-
const nextAlign = attributes.align === align ? undefined : align;
25-
setAttributes( { align: nextAlign } );
26-
};
27-
}
28-
2917
registerBlockType( 'core/button', {
3018
title: wp.i18n.__( 'Button' ),
3119

@@ -39,27 +27,6 @@ registerBlockType( 'core/button', {
3927
text: children( 'a' ),
4028
},
4129

42-
controls: [
43-
{
44-
icon: 'align-left',
45-
title: wp.i18n.__( 'Align left' ),
46-
isActive: ( { align } ) => 'left' === align,
47-
onClick: applyOrUnset( 'left' ),
48-
},
49-
{
50-
icon: 'align-center',
51-
title: wp.i18n.__( 'Align center' ),
52-
isActive: ( { align } ) => 'center' === align,
53-
onClick: applyOrUnset( 'center' ),
54-
},
55-
{
56-
icon: 'align-right',
57-
title: wp.i18n.__( 'Align right' ),
58-
isActive: ( { align } ) => 'right' === align,
59-
onClick: applyOrUnset( 'right' ),
60-
},
61-
],
62-
6330
getEditWrapperProps( attributes ) {
6431
const { align } = attributes;
6532
if ( 'left' === align || 'right' === align || 'center' === align ) {
@@ -68,10 +35,16 @@ registerBlockType( 'core/button', {
6835
},
6936

7037
edit( { attributes, setAttributes, focus, setFocus } ) {
71-
const { text, url, title } = attributes;
38+
const { text, url, title, align } = attributes;
39+
const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } );
7240

73-
return (
74-
<span className="blocks-button" title={ title }>
41+
return [
42+
focus && (
43+
<BlockControls key="controls">
44+
<BlockAlignmentToolbar value={ align } onChange={ updateAlignment } />
45+
</BlockControls>
46+
),
47+
<span key="button" className="blocks-button" title={ title }>
7548
<Editable
7649
tagName="span"
7750
placeholder={ wp.i18n.__( 'Write label…' ) }
@@ -98,8 +71,8 @@ registerBlockType( 'core/button', {
9871
<IconButton icon="editor-break" type="submit" />
9972
</form>
10073
}
101-
</span>
102-
);
74+
</span>,
75+
];
10376
},
10477

10578
save( { attributes } ) {

blocks/library/embed/index.js

Lines changed: 31 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,13 @@ import { Button, Placeholder, HtmlEmbed, Spinner } from 'components';
1515
import './style.scss';
1616
import { registerBlockType, query } from '../../api';
1717
import Editable from '../../editable';
18+
import BlockControls from '../../block-controls';
19+
import BlockAlignmentToolbar from '../../block-alignment-toolbar';
1820

1921
const { attr, children } = query;
2022

2123
const HOSTS_NO_PREVIEWS = [ 'facebook.com' ];
2224

23-
/**
24-
* Returns an attribute setter with behavior that if the target value is
25-
* already the assigned attribute value, it will be set to undefined.
26-
*
27-
* @param {string} align Alignment value
28-
* @return {Function} Attribute setter
29-
*/
30-
function toggleAlignment( align ) {
31-
return ( attributes, setAttributes ) => {
32-
const nextAlign = attributes.align === align ? undefined : align;
33-
setAttributes( { align: nextAlign } );
34-
};
35-
}
36-
3725
function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
3826
return {
3927
title: wp.i18n.__( title ),
@@ -47,39 +35,6 @@ function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
4735
caption: children( 'figcaption' ),
4836
},
4937

50-
controls: [
51-
{
52-
icon: 'align-left',
53-
title: wp.i18n.__( 'Align left' ),
54-
isActive: ( { align } ) => 'left' === align,
55-
onClick: toggleAlignment( 'left' ),
56-
},
57-
{
58-
icon: 'align-center',
59-
title: wp.i18n.__( 'Align center' ),
60-
isActive: ( { align } ) => ! align || 'center' === align,
61-
onClick: toggleAlignment( 'center' ),
62-
},
63-
{
64-
icon: 'align-right',
65-
title: wp.i18n.__( 'Align right' ),
66-
isActive: ( { align } ) => 'right' === align,
67-
onClick: toggleAlignment( 'right' ),
68-
},
69-
{
70-
icon: 'align-full-width',
71-
title: wp.i18n.__( 'Wide width' ),
72-
isActive: ( { align } ) => 'wide' === align,
73-
onClick: toggleAlignment( 'wide' ),
74-
},
75-
{
76-
icon: 'align-full-width',
77-
title: wp.i18n.__( 'Full width' ),
78-
isActive: ( { align } ) => 'full' === align,
79-
onClick: toggleAlignment( 'full' ),
80-
},
81-
],
82-
8338
getEditWrapperProps( attributes ) {
8439
const { align } = attributes;
8540
if ( 'left' === align || 'right' === align || 'wide' === align || 'full' === align ) {
@@ -144,21 +99,36 @@ function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
14499

145100
render() {
146101
const { html, type, error, fetching } = this.state;
147-
const { url, caption } = this.props.attributes;
102+
const { align, url, caption } = this.props.attributes;
148103
const { setAttributes, focus, setFocus } = this.props;
104+
const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } );
105+
106+
const controls = (
107+
focus && (
108+
<BlockControls key="controls">
109+
<BlockAlignmentToolbar
110+
value={ align }
111+
onChange={ updateAlignment }
112+
controls={ [ 'left', 'center', 'right', 'wide', 'full' ] }
113+
/>
114+
</BlockControls>
115+
)
116+
);
149117

150118
if ( fetching ) {
151-
return (
152-
<div className="blocks-embed is-loading">
119+
return [
120+
controls,
121+
<div key="loading" className="blocks-embed is-loading">
153122
<Spinner />
154123
<p>{ wp.i18n.__( 'Embedding…' ) }</p>
155-
</div>
156-
);
124+
</div>,
125+
];
157126
}
158127

159128
if ( ! html ) {
160-
return (
161-
<Placeholder icon={ icon } label={ wp.i18n.sprintf( wp.i18n.__( '%s URL' ), title ) } className="blocks-embed">
129+
return [
130+
controls,
131+
<Placeholder key="placeholder" icon={ icon } label={ wp.i18n.sprintf( wp.i18n.__( '%s URL' ), title ) } className="blocks-embed">
162132
<form onSubmit={ this.doServerSideRender }>
163133
<input
164134
type="url"
@@ -173,8 +143,8 @@ function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
173143
</Button>
174144
{ error && <p className="components-placeholder__error">{ wp.i18n.__( 'Sorry, we could not embed that content.' ) }</p> }
175145
</form>
176-
</Placeholder>
177-
);
146+
</Placeholder>,
147+
];
178148
}
179149

180150
const parsedUrl = parse( url );
@@ -185,8 +155,9 @@ function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
185155
typeClassName = 'blocks-embed-video';
186156
}
187157

188-
return (
189-
<figure className={ typeClassName }>
158+
return [
159+
controls,
160+
<figure key="embed" className={ typeClassName }>
190161
{ ( cannotPreview ) ? (
191162
<Placeholder icon={ icon } label={ wp.i18n.__( 'Embed URL' ) }>
192163
<p className="components-placeholder__error"><a href={ url }>{ url }</a></p>
@@ -207,8 +178,8 @@ function getEmbedBlockSettings( { title, icon, category = 'embed' } ) {
207178
inlineToolbar
208179
/>
209180
) : null }
210-
</figure>
211-
);
181+
</figure>,
182+
];
212183
}
213184
},
214185

blocks/library/image/index.js

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,11 @@ import Editable from '../../editable';
1313
import MediaUploadButton from '../../media-upload-button';
1414
import InspectorControls from '../../inspector-controls';
1515
import TextControl from '../../inspector-controls/text-control';
16+
import BlockControls from '../../block-controls';
17+
import BlockAlignmentToolbar from '../../block-alignment-toolbar';
1618

1719
const { attr, children } = query;
1820

19-
/**
20-
* Returns an attribute setter with behavior that if the target value is
21-
* already the assigned attribute value, it will be set to undefined.
22-
*
23-
* @param {string} align Alignment value
24-
* @return {Function} Attribute setter
25-
*/
26-
function toggleAlignment( align ) {
27-
return ( attributes, setAttributes ) => {
28-
const nextAlign = attributes.align === align ? undefined : align;
29-
setAttributes( { align: nextAlign } );
30-
};
31-
}
32-
3321
registerBlockType( 'core/image', {
3422
title: __( 'Image' ),
3523

@@ -43,39 +31,6 @@ registerBlockType( 'core/image', {
4331
caption: children( 'figcaption' ),
4432
},
4533

46-
controls: [
47-
{
48-
icon: 'align-left',
49-
title: __( 'Align left' ),
50-
isActive: ( { align } ) => 'left' === align,
51-
onClick: toggleAlignment( 'left' ),
52-
},
53-
{
54-
icon: 'align-center',
55-
title: __( 'Align center' ),
56-
isActive: ( { align } ) => ! align || 'center' === align,
57-
onClick: toggleAlignment( 'center' ),
58-
},
59-
{
60-
icon: 'align-right',
61-
title: __( 'Align right' ),
62-
isActive: ( { align } ) => 'right' === align,
63-
onClick: toggleAlignment( 'right' ),
64-
},
65-
{
66-
icon: 'align-wide',
67-
title: __( 'Wide width' ),
68-
isActive: ( { align } ) => 'wide' === align,
69-
onClick: toggleAlignment( 'wide' ),
70-
},
71-
{
72-
icon: 'align-full-width',
73-
title: __( 'Full width' ),
74-
isActive: ( { align } ) => 'full' === align,
75-
onClick: toggleAlignment( 'full' ),
76-
},
77-
],
78-
7934
getEditWrapperProps( attributes ) {
8035
const { align } = attributes;
8136
if ( 'left' === align || 'right' === align || 'wide' === align || 'full' === align ) {
@@ -84,13 +39,27 @@ registerBlockType( 'core/image', {
8439
},
8540

8641
edit( { attributes, setAttributes, focus, setFocus } ) {
87-
const { url, alt, caption } = attributes;
42+
const { url, alt, caption, align } = attributes;
8843
const updateAlt = ( newAlt ) => setAttributes( { alt: newAlt } );
44+
const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } );
45+
46+
const controls = (
47+
focus && (
48+
<BlockControls key="controls">
49+
<BlockAlignmentToolbar
50+
value={ align }
51+
onChange={ updateAlignment }
52+
controls={ [ 'left', 'center', 'right', 'wide', 'full' ] }
53+
/>
54+
</BlockControls>
55+
)
56+
);
8957

9058
if ( ! url ) {
9159
const uploadButtonProps = { isLarge: true };
9260
const setMediaURL = ( media ) => setAttributes( { url: media.url } );
9361
return [
62+
controls,
9463
<Placeholder
9564
key="placeholder"
9665
instructions={ __( 'Drag image here or insert from media library' ) }
@@ -115,6 +84,7 @@ registerBlockType( 'core/image', {
11584

11685
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */
11786
return [
87+
controls,
11888
focus && (
11989
<InspectorControls key="inspector">
12090
<TextControl label={ __( 'Alternate Text' ) } value={ alt } onChange={ updateAlt } />

0 commit comments

Comments
 (0)