diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 2ea8871df102e..841252da96522 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -69,13 +69,18 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $style .= "$selector > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }"; } } elseif ( 'flex' === $layout_type ) { + $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; + $justify_content_options = array( - 'left' => 'flex-start', - 'right' => 'flex-end', - 'center' => 'center', - 'space-between' => 'space-between', + 'left' => 'flex-start', + 'right' => 'flex-end', + 'center' => 'center', ); + if ( 'horizontal' === $layout_orientation ) { + $justify_content_options += array( 'space-between' => 'space-between' ); + } + $flex_wrap_options = array( 'wrap', 'nowrap' ); $flex_wrap = ! empty( $layout['flexWrap'] ) && in_array( $layout['flexWrap'], $flex_wrap_options, true ) ? $layout['flexWrap'] : @@ -89,14 +94,21 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support $style .= 'gap: 0.5em;'; } $style .= "flex-wrap: $flex_wrap;"; - $style .= 'align-items: center;'; - /** - * Add this style only if is not empty for backwards compatibility, - * since we intend to convert blocks that had flex layout implemented - * by custom css. - */ - if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { - $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; + if ( 'horizontal' === $layout_orientation ) { + $style .= 'align-items: center;'; + /** + * Add this style only if is not empty for backwards compatibility, + * since we intend to convert blocks that had flex layout implemented + * by custom css. + */ + if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { + $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; + } + } else { + $style .= 'flex-direction: column;'; + if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { + $style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};"; + } } $style .= '}'; @@ -204,4 +216,3 @@ function( $matches ) { remove_filter( 'render_block', 'wp_restore_group_inner_container', 10, 2 ); } add_filter( 'render_block', 'gutenberg_restore_group_inner_container', 10, 2 ); - diff --git a/packages/block-editor/src/hooks/layout.scss b/packages/block-editor/src/hooks/layout.scss index 653f9da7b9bda..5589e08b9837c 100644 --- a/packages/block-editor/src/hooks/layout.scss +++ b/packages/block-editor/src/hooks/layout.scss @@ -22,7 +22,8 @@ font-size: $helptext-font-size; } -.block-editor-hooks__flex-layout-justification-controls { +.block-editor-hooks__flex-layout-justification-controls, +.block-editor-hooks__flex-layout-orientation-controls { margin-bottom: $grid-unit-15; legend { margin-bottom: $grid-unit-10; diff --git a/packages/block-editor/src/layouts/flex.js b/packages/block-editor/src/layouts/flex.js index 03ed93d31a266..9e687f6b7d790 100644 --- a/packages/block-editor/src/layouts/flex.js +++ b/packages/block-editor/src/layouts/flex.js @@ -7,8 +7,10 @@ import { justifyCenter, justifyRight, justifySpaceBetween, + arrowRight, + arrowDown, } from '@wordpress/icons'; -import { Button, ToggleControl } from '@wordpress/components'; +import { Button, ToggleControl, Flex, FlexItem } from '@wordpress/components'; /** * Internal dependencies @@ -17,6 +19,7 @@ import { appendSelectors } from './utils'; import useSetting from '../components/use-setting'; import { BlockControls, JustifyContentControl } from '../components'; +// Used with the default, horizontal flex orientation. const justifyContentMap = { left: 'flex-start', right: 'flex-end', @@ -24,6 +27,13 @@ const justifyContentMap = { 'space-between': 'space-between', }; +// Used with the vertical (column) flex orientation. +const alignItemsMap = { + left: 'flex-start', + right: 'flex-end', + center: 'center', +}; + const flexWrapOptions = [ 'wrap', 'nowrap' ]; export default { @@ -33,12 +43,25 @@ export default { layout = {}, onChange, } ) { + const { allowOrientation = true } = layout; return ( <> - + + + + + + { allowOrientation && ( + + ) } + + ); @@ -62,6 +85,7 @@ export default { ); }, save: function FlexLayoutStyle( { selector, layout } ) { + const { orientation = 'horizontal' } = layout; const blockGapSupport = useSetting( 'spacing.blockGap' ); const hasBlockGapStylesSupport = blockGapSupport !== null; const justifyContent = @@ -70,6 +94,17 @@ export default { const flexWrap = flexWrapOptions.includes( layout.flexWrap ) ? layout.flexWrap : 'wrap'; + const rowOrientation = ` + flex-direction: row; + align-items: center; + justify-content: ${ justifyContent }; + `; + const alignItems = + alignItemsMap[ layout.justifyContent ] || alignItemsMap.left; + const columnOrientation = ` + flex-direction: column; + align-items: ${ alignItems }; + `; return ( ); }, - getOrientation() { - return 'horizontal'; + getOrientation( layout ) { + const { orientation = 'horizontal' } = layout; + return orientation; }, getAlignments() { return []; }, }; -const justificationOptions = [ - { - value: 'left', - icon: justifyLeft, - label: __( 'Justify items left' ), - }, - { - value: 'center', - icon: justifyCenter, - label: __( 'Justify items center' ), - }, - { - value: 'right', - icon: justifyRight, - label: __( 'Justify items right' ), - }, - { - value: 'space-between', - icon: justifySpaceBetween, - label: __( 'Space between items' ), - }, -]; function FlexLayoutJustifyContentControl( { layout, onChange, isToolbar = false, } ) { - const { justifyContent = 'left' } = layout; + const { justifyContent = 'left', orientation = 'horizontal' } = layout; const onJustificationChange = ( value ) => { onChange( { ...layout, justifyContent: value, } ); }; + const allowedControls = [ 'left', 'center', 'right' ]; + if ( orientation === 'horizontal' ) { + allowedControls.push( 'space-between' ); + } if ( isToolbar ) { return ( { __( 'Justification' ) } @@ -187,3 +223,34 @@ function FlexWrapControl( { layout, onChange } ) { /> ); } + +function OrientationControl( { layout, onChange } ) { + const { orientation = 'horizontal' } = layout; + return ( +
+ { __( 'Orientation' ) } +
+ ); +} diff --git a/packages/block-library/src/buttons/block.json b/packages/block-library/src/buttons/block.json index 7730867393709..818d4d20e9f8f 100644 --- a/packages/block-library/src/buttons/block.json +++ b/packages/block-library/src/buttons/block.json @@ -6,15 +6,6 @@ "description": "Prompt visitors to take action with a group of button-style links.", "keywords": [ "link" ], "textdomain": "default", - "attributes": { - "contentJustification": { - "type": "string" - }, - "orientation": { - "type": "string", - "default": "horizontal" - } - }, "supports": { "anchor": true, "align": [ "wide", "full" ], @@ -25,6 +16,13 @@ "__experimentalDefaultControls": { "blockGap": true } + }, + "__experimentalLayout": { + "allowSwitching": false, + "allowInheriting": false, + "default": { + "type": "flex" + } } }, "editorStyle": "wp-block-buttons-editor", diff --git a/packages/block-library/src/buttons/deprecated.js b/packages/block-library/src/buttons/deprecated.js index 47d049578ea58..08fb792807d8a 100644 --- a/packages/block-library/src/buttons/deprecated.js +++ b/packages/block-library/src/buttons/deprecated.js @@ -1,9 +1,79 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; /** * WordPress dependencies */ -import { InnerBlocks } from '@wordpress/block-editor'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +/** + * @param {Object} attributes Block's attributes. + */ +const migrateWithLayout = ( attributes ) => { + if ( !! attributes.layout ) { + return attributes; + } + + const { contentJustification, orientation } = attributes; + + const updatedAttributes = { + ...attributes, + }; + + if ( contentJustification || orientation ) { + Object.assign( updatedAttributes, { + layout: { + type: 'flex', + justifyContent: contentJustification || 'left', + orientation: orientation || 'horizontal', + }, + } ); + } + + return updatedAttributes; +}; const deprecated = [ + { + attributes: { + contentJustification: { + type: 'string', + }, + orientation: { + type: 'string', + default: 'horizontal', + }, + }, + supports: { + anchor: true, + align: [ 'wide', 'full' ], + __experimentalExposeControlsToChildren: true, + spacing: { + blockGap: true, + margin: [ 'top', 'bottom' ], + __experimentalDefaultControls: { + blockGap: true, + }, + }, + }, + isEligible: ( { layout } ) => ! layout, + migrate: migrateWithLayout, + save( { attributes: { contentJustification, orientation } } ) { + return ( +
+ +
+ ); + }, + }, { supports: { align: [ 'center', 'left', 'right' ], @@ -20,7 +90,7 @@ const deprecated = [ return align && [ 'center', 'left', 'right' ].includes( align ); }, migrate( attributes ) { - return { + return migrateWithLayout( { ...attributes, align: undefined, // Floating Buttons blocks shouldn't have been supported in the @@ -30,7 +100,7 @@ const deprecated = [ // As for center-aligned Buttons blocks, the content justification // equivalent will create an identical end result in most cases. contentJustification: attributes.align, - }; + } ); }, }, ]; diff --git a/packages/block-library/src/buttons/edit.js b/packages/block-library/src/buttons/edit.js index 348fc7a9eeb92..306f6fce7ac51 100644 --- a/packages/block-library/src/buttons/edit.js +++ b/packages/block-library/src/buttons/edit.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ @@ -10,7 +5,6 @@ import { BlockControls, useBlockProps, useInnerBlocksProps, - JustifyContentControl, store as blockEditorStore, } from '@wordpress/block-editor'; import { useSelect } from '@wordpress/data'; @@ -21,28 +15,9 @@ import { useSelect } from '@wordpress/data'; import { name as buttonBlockName } from '../button'; const ALLOWED_BLOCKS = [ buttonBlockName ]; -const LAYOUT = { - type: 'default', - alignments: [], -}; -const VERTICAL_JUSTIFY_CONTROLS = [ 'left', 'center', 'right' ]; -const HORIZONTAL_JUSTIFY_CONTROLS = [ - 'left', - 'center', - 'right', - 'space-between', -]; -function ButtonsEdit( { - attributes: { contentJustification, orientation }, - setAttributes, -} ) { - const blockProps = useBlockProps( { - className: classnames( { - [ `is-content-justification-${ contentJustification }` ]: contentJustification, - 'is-vertical': orientation === 'vertical', - } ), - } ); +function ButtonsEdit( { attributes: { layout = {} } } ) { + const blockProps = useBlockProps(); const preferredStyle = useSelect( ( select ) => { const preferredStyleVariations = select( blockEditorStore @@ -58,31 +33,16 @@ function ButtonsEdit( { { className: preferredStyle && `is-style-${ preferredStyle }` }, ], ], - orientation, - __experimentalLayout: LAYOUT, + __experimentalLayout: layout, templateInsertUpdatesSelection: true, } ); - const justifyControls = - orientation === 'vertical' - ? VERTICAL_JUSTIFY_CONTROLS - : HORIZONTAL_JUSTIFY_CONTROLS; - return ( <> - - - setAttributes( { contentJustification: value } ) - } - popoverProps={ { - position: 'bottom right', - isAlternate: true, - } } - /> - +
); diff --git a/packages/block-library/src/buttons/editor.scss b/packages/block-library/src/buttons/editor.scss index 672f2b0712358..1f964c32fa940 100644 --- a/packages/block-library/src/buttons/editor.scss +++ b/packages/block-library/src/buttons/editor.scss @@ -1,11 +1,6 @@ // This variable is repeated across Button, Buttons, and Buttons editor styles. $blocks-block__margin: 0.5em; -.wp-block > .wp-block-buttons { - display: flex; - flex-wrap: wrap; -} - .wp-block-buttons { // Override editor auto block margins for button as well as the block appender. > .wp-block { diff --git a/packages/block-library/src/buttons/index.js b/packages/block-library/src/buttons/index.js index 2ee8ca3d371d9..52d406e0ca976 100644 --- a/packages/block-library/src/buttons/index.js +++ b/packages/block-library/src/buttons/index.js @@ -12,7 +12,6 @@ import transforms from './transforms'; import edit from './edit'; import metadata from './block.json'; import save from './save'; -import variations from './variations'; const { name } = metadata; @@ -36,5 +35,4 @@ export const settings = { transforms, edit, save, - variations, }; diff --git a/packages/block-library/src/buttons/save.js b/packages/block-library/src/buttons/save.js index 0c17b5c3d2bc0..6ed6c218d6769 100644 --- a/packages/block-library/src/buttons/save.js +++ b/packages/block-library/src/buttons/save.js @@ -1,22 +1,9 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; -export default function save( { - attributes: { contentJustification, orientation }, -} ) { - const blockProps = useBlockProps.save( { - className: classnames( { - [ `is-content-justification-${ contentJustification }` ]: contentJustification, - 'is-vertical': orientation === 'vertical', - } ), - } ); - const innerBlocksProps = useInnerBlocksProps.save( blockProps ); +export default function save() { + const innerBlocksProps = useInnerBlocksProps.save( useBlockProps.save() ); return
; } diff --git a/packages/block-library/src/buttons/style.scss b/packages/block-library/src/buttons/style.scss index fdd69cc8314b0..6ba301ea7e25c 100644 --- a/packages/block-library/src/buttons/style.scss +++ b/packages/block-library/src/buttons/style.scss @@ -2,10 +2,6 @@ $blocks-block__margin: 0.5em; .wp-block-buttons { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: var(--wp--style--block-gap, $blocks-block__margin); &.is-vertical { flex-direction: column; diff --git a/packages/block-library/src/buttons/variations.js b/packages/block-library/src/buttons/variations.js deleted file mode 100644 index 438a5fc97b5eb..0000000000000 --- a/packages/block-library/src/buttons/variations.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - -const variations = [ - { - name: 'buttons-horizontal', - isDefault: true, - title: __( 'Horizontal' ), - description: __( 'Buttons shown in a row.' ), - attributes: { orientation: 'horizontal' }, - scope: [ 'transform' ], - }, - { - name: 'buttons-vertical', - title: __( 'Vertical' ), - description: __( 'Buttons shown in a column.' ), - attributes: { orientation: 'vertical' }, - scope: [ 'transform' ], - }, -]; - -export default variations; diff --git a/packages/block-library/src/group/variations.js b/packages/block-library/src/group/variations.js index 76de042661f38..55b3a0c9fc5d4 100644 --- a/packages/block-library/src/group/variations.js +++ b/packages/block-library/src/group/variations.js @@ -8,7 +8,7 @@ const variations = [ name: 'group-row', title: __( 'Row' ), description: __( 'Blocks shown in a row.' ), - attributes: { layout: { type: 'flex' } }, + attributes: { layout: { type: 'flex', allowOrientation: false } }, scope: [ 'inserter' ], isActive: ( blockAttributes ) => blockAttributes.layout?.type === 'flex', diff --git a/test/integration/fixtures/blocks/core__buttons.html b/test/integration/fixtures/blocks/core__buttons.html index c6cc0e3bf76c2..5b114e3c7b6f7 100644 --- a/test/integration/fixtures/blocks/core__buttons.html +++ b/test/integration/fixtures/blocks/core__buttons.html @@ -1,5 +1,5 @@ - -
+ +
@@ -8,4 +8,4 @@
- + \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__buttons.json b/test/integration/fixtures/blocks/core__buttons.json index 7668b778d09b0..b736172fa3ef0 100644 --- a/test/integration/fixtures/blocks/core__buttons.json +++ b/test/integration/fixtures/blocks/core__buttons.json @@ -4,9 +4,11 @@ "name": "core/buttons", "isValid": true, "attributes": { - "contentJustification": "center", - "orientation": "horizontal", - "align": "wide" + "align": "wide", + "layout": { + "type": "flex", + "justifyContent": "center" + } }, "innerBlocks": [ { @@ -30,6 +32,6 @@ "originalContent": "" } ], - "originalContent": "
\n\t\n\n\t\n
" + "originalContent": "
\n\t\n\n\t\n
" } ] diff --git a/test/integration/fixtures/blocks/core__buttons.parsed.json b/test/integration/fixtures/blocks/core__buttons.parsed.json index 937cd47942299..03df2f840a4d2 100644 --- a/test/integration/fixtures/blocks/core__buttons.parsed.json +++ b/test/integration/fixtures/blocks/core__buttons.parsed.json @@ -3,7 +3,10 @@ "blockName": "core/buttons", "attrs": { "align": "wide", - "contentJustification": "center" + "layout": { + "type": "flex", + "justifyContent": "center" + } }, "innerBlocks": [ { @@ -25,9 +28,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/test/integration/fixtures/blocks/core__buttons.serialized.html b/test/integration/fixtures/blocks/core__buttons.serialized.html index 34141befc4da2..31157113d05d4 100644 --- a/test/integration/fixtures/blocks/core__buttons.serialized.html +++ b/test/integration/fixtures/blocks/core__buttons.serialized.html @@ -1,5 +1,5 @@ - -
+ +
diff --git a/test/integration/fixtures/blocks/core__buttons__deprecated-1.json b/test/integration/fixtures/blocks/core__buttons__deprecated-1.json index 23484290b0e14..8eeec861f7aed 100644 --- a/test/integration/fixtures/blocks/core__buttons__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-1.json @@ -4,7 +4,12 @@ "name": "core/buttons", "isValid": true, "attributes": { - "contentJustification": "center" + "contentJustification": "center", + "layout": { + "type": "flex", + "justifyContent": "center", + "orientation": "horizontal" + } }, "innerBlocks": [ { diff --git a/test/integration/fixtures/blocks/core__buttons__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__buttons__deprecated-1.serialized.html index b311167cbfed0..f8104335fee06 100644 --- a/test/integration/fixtures/blocks/core__buttons__deprecated-1.serialized.html +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-1.serialized.html @@ -1,5 +1,5 @@ - -
+ +
diff --git a/test/integration/fixtures/blocks/core__buttons__deprecated-2.html b/test/integration/fixtures/blocks/core__buttons__deprecated-2.html new file mode 100644 index 0000000000000..c6cc0e3bf76c2 --- /dev/null +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-2.html @@ -0,0 +1,11 @@ + +
+ + + + + + + +
+ diff --git a/test/integration/fixtures/blocks/core__buttons__deprecated-2.json b/test/integration/fixtures/blocks/core__buttons__deprecated-2.json new file mode 100644 index 0000000000000..8d30fe9ae4f69 --- /dev/null +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-2.json @@ -0,0 +1,40 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/buttons", + "isValid": true, + "attributes": { + "contentJustification": "center", + "orientation": "horizontal", + "align": "wide", + "layout": { + "type": "flex", + "justifyContent": "center", + "orientation": "horizontal" + } + }, + "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/test/integration/fixtures/blocks/core__buttons__deprecated-2.parsed.json b/test/integration/fixtures/blocks/core__buttons__deprecated-2.parsed.json new file mode 100644 index 0000000000000..937cd47942299 --- /dev/null +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-2.parsed.json @@ -0,0 +1,37 @@ +[ + { + "blockName": "core/buttons", + "attrs": { + "align": "wide", + "contentJustification": "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" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__buttons__deprecated-2.serialized.html b/test/integration/fixtures/blocks/core__buttons__deprecated-2.serialized.html new file mode 100644 index 0000000000000..dc4ecfa51732f --- /dev/null +++ b/test/integration/fixtures/blocks/core__buttons__deprecated-2.serialized.html @@ -0,0 +1,9 @@ + + + diff --git a/test/integration/fixtures/blocks/core_buttons__simple__deprecated.json b/test/integration/fixtures/blocks/core_buttons__simple__deprecated.json index 885679a67bfe3..819b6bbb284c4 100644 --- a/test/integration/fixtures/blocks/core_buttons__simple__deprecated.json +++ b/test/integration/fixtures/blocks/core_buttons__simple__deprecated.json @@ -4,7 +4,12 @@ "name": "core/buttons", "isValid": true, "attributes": { - "orientation": "horizontal" + "orientation": "horizontal", + "layout": { + "type": "flex", + "justifyContent": "left", + "orientation": "horizontal" + } }, "innerBlocks": [ { diff --git a/test/integration/fixtures/blocks/core_buttons__simple__deprecated.serialized.html b/test/integration/fixtures/blocks/core_buttons__simple__deprecated.serialized.html index baf0a0226c066..8f9252029d32d 100644 --- a/test/integration/fixtures/blocks/core_buttons__simple__deprecated.serialized.html +++ b/test/integration/fixtures/blocks/core_buttons__simple__deprecated.serialized.html @@ -1,4 +1,4 @@ - +