diff --git a/lib/patterns/two-buttons.php b/lib/patterns/two-buttons.php index 90564c4c30487..8cd24997ce20e 100644 --- a/lib/patterns/two-buttons.php +++ b/lib/patterns/two-buttons.php @@ -7,7 +7,7 @@ return array( 'title' => __( 'Two buttons', 'gutenberg' ), - 'content' => "\n
\n
" . __( 'Download now', 'gutenberg' ) . "
\n\n\n\n
" . __( 'About Cervantes', 'gutenberg' ) . "
\n
\n", + 'content' => "\n
\n
" . __( 'Download now', 'gutenberg' ) . "
\n\n\n\n
" . __( 'About Cervantes', 'gutenberg' ) . "
\n
\n", 'viewportWidth' => 500, 'categories' => array( 'buttons' ), 'description' => _x( 'Two buttons, one filled and one outlined, side by side.', 'Block pattern description', 'gutenberg' ), diff --git a/packages/block-library/src/buttons/block.json b/packages/block-library/src/buttons/block.json index a1e4c33c2ed3e..b534316ce8f97 100644 --- a/packages/block-library/src/buttons/block.json +++ b/packages/block-library/src/buttons/block.json @@ -2,9 +2,13 @@ "apiVersion": 2, "name": "core/buttons", "category": "design", + "attributes": { + "contentJustification": { + "type": "string" + } + }, "supports": { "anchor": true, - "align": true, - "alignWide": false + "align": [ "wide", "full" ] } } diff --git a/packages/block-library/src/buttons/content-justification-dropdown.js b/packages/block-library/src/buttons/content-justification-dropdown.js new file mode 100644 index 0000000000000..56c9bef7955ba --- /dev/null +++ b/packages/block-library/src/buttons/content-justification-dropdown.js @@ -0,0 +1,70 @@ +/** + * WordPress dependencies + */ +import { DropdownMenu } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { justifyCenterIcon, justifyLeftIcon, justifyRightIcon } from './icons'; + +const DEFAULT_ALLOWED_VALUES = [ 'left', 'center', 'right' ]; + +const CONTROLS = { + left: { + icon: justifyLeftIcon, + title: __( 'Justify items left' ), + }, + center: { + icon: justifyCenterIcon, + title: __( 'Justify items center' ), + }, + right: { + icon: justifyRightIcon, + title: __( 'Justify items right' ), + }, +}; + +const DEFAULT_ICON = CONTROLS.center.icon; + +/** + * Dropdown for selecting a content justification option. + * + * @param {Object} props Component props. + * @param {string[]} [props.allowedValues] List of options to include. Default: + * ['left', 'center', 'right']. + * @param {()=>void} props.onChange Callback to run when an option is + * selected in the dropdown. + * @param {Object} props.toggleProps Props to pass to the dropdown toggle. + * @param {string} props.value The current content justification + * value. + * + * @return {WPComponent} The component. + */ +export default function ContentJustificationDropdown( { + onChange, + allowedValues = DEFAULT_ALLOWED_VALUES, + toggleProps, + value, +} ) { + function applyOrUnset( align ) { + return () => onChange( value === align ? undefined : align ); + } + + return ( + { + return { + ...CONTROLS[ allowedValue ], + isActive: value === allowedValue, + role: 'menuitemradio', + onClick: applyOrUnset( allowedValue ), + }; + } ) } + toggleProps={ toggleProps } + /> + ); +} diff --git a/packages/block-library/src/buttons/deprecated.js b/packages/block-library/src/buttons/deprecated.js new file mode 100644 index 0000000000000..47d049578ea58 --- /dev/null +++ b/packages/block-library/src/buttons/deprecated.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +import { InnerBlocks } from '@wordpress/block-editor'; + +const deprecated = [ + { + supports: { + align: [ 'center', 'left', 'right' ], + anchor: true, + }, + save() { + return ( +
+ +
+ ); + }, + isEligible( { align } ) { + return align && [ 'center', 'left', 'right' ].includes( align ); + }, + migrate( attributes ) { + return { + ...attributes, + align: undefined, + // Floating Buttons blocks shouldn't have been supported in the + // first place. Most users using them probably expected them to + // act like content justification controls, so these blocks are + // migrated to use content justification. + // As for center-aligned Buttons blocks, the content justification + // equivalent will create an identical end result in most cases. + contentJustification: attributes.align, + }; + }, + }, +]; + +export default deprecated; diff --git a/packages/block-library/src/buttons/edit.js b/packages/block-library/src/buttons/edit.js index 97c4d4fede168..d3ab2e96c17fe 100644 --- a/packages/block-library/src/buttons/edit.js +++ b/packages/block-library/src/buttons/edit.js @@ -1,16 +1,24 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { __experimentalAlignmentHookSettingsProvider as AlignmentHookSettingsProvider, + BlockControls, InnerBlocks, useBlockProps, } from '@wordpress/block-editor'; +import { ToolbarGroup, ToolbarItem } from '@wordpress/components'; /** * Internal dependencies */ -import { name as buttonBlockName } from '../button/'; +import { name as buttonBlockName } from '../button'; +import ContentJustificationDropdown from './content-justification-dropdown'; const ALLOWED_BLOCKS = [ buttonBlockName ]; const BUTTONS_TEMPLATE = [ [ 'core/button' ] ]; @@ -20,18 +28,44 @@ const alignmentHooksSetting = { isEmbedButton: true, }; -function ButtonsEdit() { - const blockProps = useBlockProps(); +function ButtonsEdit( { + attributes: { contentJustification }, + setAttributes, +} ) { + const blockProps = useBlockProps( { + className: classnames( { + [ `is-content-justification-${ contentJustification }` ]: contentJustification, + } ), + } ); return ( - - - + <> + + + + { ( toggleProps ) => ( + { + setAttributes( { + contentJustification: updatedValue, + } ); + } } + /> + ) } + + + + + + + ); } diff --git a/packages/block-library/src/buttons/editor.scss b/packages/block-library/src/buttons/editor.scss index 121ba5f5af5cf..d10bedb1318ec 100644 --- a/packages/block-library/src/buttons/editor.scss +++ b/packages/block-library/src/buttons/editor.scss @@ -16,5 +16,6 @@ } .wp-block-buttons > .block-list-appender { - display: inline-block; + display: inline-flex; + align-items: center; } diff --git a/packages/block-library/src/buttons/icons.js b/packages/block-library/src/buttons/icons.js new file mode 100644 index 0000000000000..b18ef92f2a306 --- /dev/null +++ b/packages/block-library/src/buttons/icons.js @@ -0,0 +1,37 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/components'; + +export const justifyLeftIcon = ( + + + +); + +export const justifyCenterIcon = ( + + + +); + +export const justifyRightIcon = ( + + + +); diff --git a/packages/block-library/src/buttons/index.js b/packages/block-library/src/buttons/index.js index a9070759325a2..81653d1e12d68 100644 --- a/packages/block-library/src/buttons/index.js +++ b/packages/block-library/src/buttons/index.js @@ -7,6 +7,7 @@ import { button as icon } from '@wordpress/icons'; /** * Internal dependencies */ +import deprecated from './deprecated'; import transforms from './transforms'; import edit from './edit'; import metadata from './block.json'; @@ -35,6 +36,7 @@ export const settings = { }, ], }, + deprecated, transforms, edit, save, diff --git a/packages/block-library/src/buttons/save.js b/packages/block-library/src/buttons/save.js index 000acdcd4a605..5c64fc110e0d5 100644 --- a/packages/block-library/src/buttons/save.js +++ b/packages/block-library/src/buttons/save.js @@ -1,11 +1,22 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; -export default function save() { +export default function save( { attributes: { contentJustification } } ) { return ( -
+
); diff --git a/packages/block-library/src/buttons/style.scss b/packages/block-library/src/buttons/style.scss index 45a0d6aed21b1..324e3e3c5addd 100644 --- a/packages/block-library/src/buttons/style.scss +++ b/packages/block-library/src/buttons/style.scss @@ -1,37 +1,69 @@ -// Increased specificity to override blocks default margin. -.wp-block-buttons .wp-block-button { - display: inline-block; - margin-right: 0.5em; - margin-bottom: 0.5em; +.wp-block-buttons { + display: flex; + flex-direction: row; + flex-wrap: wrap; - &:last-child { - margin-right: 0; + // Increased specificity to override blocks default margin. + > .wp-block-button { + display: inline-block; + /*rtl:ignore*/ + margin-right: 0.5em; + margin-bottom: 0.5em; + + &:last-child { + /*rtl:ignore*/ + margin-right: 0; + } } -} -.wp-block-buttons.alignright .wp-block-button { - /*rtl:ignore*/ - margin-right: 0; - /*rtl:ignore*/ - margin-left: 0.5em; + &.is-content-justification-left { + justify-content: flex-start; + } - &:first-child { - margin-left: 0; + &.is-content-justification-center { + justify-content: center; } -} -.wp-block-buttons.alignleft .wp-block-button { - /*rtl:ignore*/ - margin-left: 0; - /*rtl:ignore*/ - margin-right: 0.5em; + &.is-content-justification-right { + justify-content: flex-end; - &:last-child { - margin-right: 0; + > .wp-block-button { + /*rtl:ignore*/ + margin-left: 0.5em; + /*rtl:ignore*/ + margin-right: 0; + + &:first-child { + /*rtl:ignore*/ + margin-left: 0; + } + } } -} -.wp-block-button.aligncenter, // This is to support the legacy Button block. -.wp-block-buttons.aligncenter { - text-align: center; + // Kept for backward compatibiity. + &.aligncenter { + text-align: center; + } + &.alignleft .wp-block-button { + /*rtl:ignore*/ + margin-left: 0; + /*rtl:ignore*/ + margin-right: 0.5em; + + &:last-child { + /*rtl:ignore*/ + margin-right: 0; + } + } + &.alignright .wp-block-button { + /*rtl:ignore*/ + margin-right: 0; + /*rtl:ignore*/ + margin-left: 0.5em; + + &:first-child { + /*rtl:ignore*/ + margin-left: 0; + } + } } diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.html b/packages/e2e-tests/fixtures/blocks/core__buttons.html index e70af7acc72ad..c6cc0e3bf76c2 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.html +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.html @@ -1,5 +1,5 @@ - -
+ +
diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.json b/packages/e2e-tests/fixtures/blocks/core__buttons.json index 044daeb82101a..29df40b187fd3 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.json +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.json @@ -3,7 +3,10 @@ "clientId": "_clientId_0", "name": "core/buttons", "isValid": true, - "attributes": {}, + "attributes": { + "contentJustification": "center", + "align": "wide" + }, "innerBlocks": [ { "clientId": "_clientId_0", @@ -26,6 +29,6 @@ "originalContent": "" } ], - "originalContent": "
\n\t\n\n\t\n
" + "originalContent": "
\n\t\n\n\t\n
" } ] diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json index b96b1f50db1fc..06f7ac796e189 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json @@ -1,7 +1,10 @@ [ { "blockName": "core/buttons", - "attrs": {}, + "attrs": { + "align": "wide", + "contentJustification": "center" + }, "innerBlocks": [ { "blockName": "core/button", @@ -22,9 +25,9 @@ ] } ], - "innerHTML": "\n
\n\t\n\n\t\n
\n", + "innerHTML": "\n
\n\t\n\n\t\n
\n", "innerContent": [ - "\n
\n\t", + "\n
\n\t", null, "\n\n\t", null, diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html index baf0a0226c066..34141befc4da2 100644 --- a/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html @@ -1,5 +1,5 @@ - -
+ +
diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.html b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.html new file mode 100644 index 0000000000000..29411d5421587 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.html @@ -0,0 +1,11 @@ + +
+ + + + + + + +
+ diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.json b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.json new file mode 100644 index 0000000000000..12acc3c2acca8 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.json @@ -0,0 +1,33 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/buttons", + "isValid": true, + "attributes": { + "contentJustification": "center" + }, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/button", + "isValid": true, + "attributes": { + "text": "My button 1" + }, + "innerBlocks": [], + "originalContent": "" + }, + { + "clientId": "_clientId_1", + "name": "core/button", + "isValid": true, + "attributes": { + "text": "My button 2" + }, + "innerBlocks": [], + "originalContent": "" + } + ], + "originalContent": "
\n\t\n\n\t\n
" + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.parsed.json b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.parsed.json new file mode 100644 index 0000000000000..6e9acab313242 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.parsed.json @@ -0,0 +1,45 @@ +[ + { + "blockName": "core/buttons", + "attrs": { + "align": "center" + }, + "innerBlocks": [ + { + "blockName": "core/button", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\n\t", + "innerContent": [ + "\n\t\n\t" + ] + }, + { + "blockName": "core/button", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\n\t", + "innerContent": [ + "\n\t\n\t" + ] + } + ], + "innerHTML": "\n
\n\t\n\n\t\n
\n", + "innerContent": [ + "\n
\n\t", + null, + "\n\n\t", + null, + "\n
\n" + ] + }, + { + "blockName": null, + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n", + "innerContent": [ + "\n" + ] + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.serialized.html b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.serialized.html new file mode 100644 index 0000000000000..b311167cbfed0 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons__deprecated-1.serialized.html @@ -0,0 +1,9 @@ + + + diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/adding-patterns.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/adding-patterns.test.js.snap index 40ef6b14920cd..9fc6885188f49 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/adding-patterns.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/adding-patterns.test.js.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`adding blocks should insert a block pattern 1`] = ` -" -
+" +
@@ -10,4 +10,4 @@ exports[`adding blocks should insert a block pattern 1`] = `
" -`; \ No newline at end of file +`;