diff --git a/packages/block-library/src/columns/block.json b/packages/block-library/src/columns/block.json index f3bc49d3d24971..79b82f4b7a5952 100644 --- a/packages/block-library/src/columns/block.json +++ b/packages/block-library/src/columns/block.json @@ -8,6 +8,10 @@ "attributes": { "verticalAlignment": { "type": "string" + }, + "isStackedOnMobile": { + "type": "boolean", + "default": true } }, "supports": { diff --git a/packages/block-library/src/columns/deprecated.js b/packages/block-library/src/columns/deprecated.js index 34b3076904a63f..8c3f7a27d2b6d4 100644 --- a/packages/block-library/src/columns/deprecated.js +++ b/packages/block-library/src/columns/deprecated.js @@ -52,6 +52,7 @@ const migrateCustomColors = ( attributes ) => { return { ...omit( attributes, [ 'customTextColor', 'customBackgroundColor' ] ), style, + isStackedOnMobile: true, }; }; @@ -166,7 +167,13 @@ export default [ createBlock( 'core/column', {}, columnBlocks ) ); - return [ omit( attributes, [ 'columns' ] ), migratedInnerBlocks ]; + return [ + { + ...omit( attributes, [ 'columns' ] ), + isStackedOnMobile: true, + }, + migratedInnerBlocks, + ]; }, save( { attributes } ) { const { columns } = attributes; @@ -186,7 +193,10 @@ export default [ }, }, migrate( attributes, innerBlocks ) { - attributes = omit( attributes, [ 'columns' ] ); + attributes = { + ...omit( attributes, [ 'columns' ] ), + isStackedOnMobile: true, + }; return [ attributes, innerBlocks ]; }, diff --git a/packages/block-library/src/columns/edit.js b/packages/block-library/src/columns/edit.js index 0f77c3f843dbe8..35534d503bb727 100644 --- a/packages/block-library/src/columns/edit.js +++ b/packages/block-library/src/columns/edit.js @@ -8,7 +8,12 @@ import { dropRight, get, times } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { PanelBody, RangeControl, Notice } from '@wordpress/components'; +import { + Notice, + PanelBody, + RangeControl, + ToggleControl, +} from '@wordpress/components'; import { InspectorControls, @@ -49,11 +54,12 @@ const ALLOWED_BLOCKS = [ 'core/column' ]; function ColumnsEditContainer( { attributes, + setAttributes, updateAlignment, updateColumns, clientId, } ) { - const { verticalAlignment } = attributes; + const { isStackedOnMobile, verticalAlignment } = attributes; const { count } = useSelect( ( select ) => { @@ -66,6 +72,7 @@ function ColumnsEditContainer( { const classes = classnames( { [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, + [ `is-not-stacked-on-mobile` ]: ! isStackedOnMobile, } ); const blockProps = useBlockProps( { @@ -101,6 +108,15 @@ function ColumnsEditContainer( { ) } ) } + + setAttributes( { + isStackedOnMobile: ! isStackedOnMobile, + } ) + } + />
diff --git a/packages/block-library/src/columns/save.js b/packages/block-library/src/columns/save.js index a9826c10089899..3c80d0edc21f51 100644 --- a/packages/block-library/src/columns/save.js +++ b/packages/block-library/src/columns/save.js @@ -9,10 +9,11 @@ import classnames from 'classnames'; import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { verticalAlignment } = attributes; + const { isStackedOnMobile, verticalAlignment } = attributes; const className = classnames( { [ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment, + [ `is-not-stacked-on-mobile` ]: ! isStackedOnMobile, } ); return ( diff --git a/packages/block-library/src/columns/style.scss b/packages/block-library/src/columns/style.scss index dc744f46eb2db6..aba4c99297a191 100644 --- a/packages/block-library/src/columns/style.scss +++ b/packages/block-library/src/columns/style.scss @@ -28,17 +28,82 @@ &.are-vertically-aligned-bottom { align-items: flex-end; } + + &:not(.is-not-stacked-on-mobile) > .wp-block-column { + @media (max-width: #{ ($break-small - 1) }) { + // Responsiveness: Show at most one columns on mobile. This must be + // important since the Column assigns its own width as an inline style. + flex-basis: 100% !important; + } + + // Between mobile and large viewports, allow 2 columns. + @media (min-width: #{ ($break-small) }) and (max-width: #{ ($break-medium - 1) }) { + // Only add two column styling if there are two or more columns + &:not(:only-child) { + // As with mobile styles, this must be important since the Column + // assigns its own width as an inline style, which should take effect + // starting at `break-medium`. + flex-basis: calc(50% - 1em) !important; + flex-grow: 0; + } + + // Add space between the multiple columns. Themes can customize this if they wish to work differently. + // Only apply this beyond the mobile breakpoint, as there's only a single column on mobile. + &:nth-child(even) { + margin-left: 2em; + } + } + + // At large viewports, show all columns horizontally. + @include break-medium() { + // Available space should be divided equally amongst columns without an + // assigned width. This is achieved by assigning a flex basis that is + // consistent (equal), would not cause the sum total of column widths to + // exceed 100%, and which would cede to a column with an assigned width. + // The `flex-grow` allows columns to maximally and equally occupy space + // remaining after subtracting the space occupied by columns with + // explicit widths (if any exist). + flex-basis: 0; + flex-grow: 1; + + // Columns with an explicitly-assigned width should maintain their + // `flex-basis` width and not grow. + &[style*="flex-basis"] { + flex-grow: 0; + } + + // When columns are in a single row, add space before all except the first. + &:not(:first-child) { + margin-left: 2em; + } + } + } + + &.is-not-stacked-on-mobile { + flex-wrap: nowrap; + + > .wp-block-column { + // Available space should be divided equally amongst columns. + flex-basis: 0; + flex-grow: 1; + + // Columns with an explicitly-assigned width should maintain their + // `flex-basis` width and not grow. + &[style*="flex-basis"] { + flex-grow: 0; + } + + // When columns are in a single row, add space before all except the first. + &:not(:first-child) { + margin-left: 2em; + } + } + } } .wp-block-column { flex-grow: 1; - @media (max-width: #{ ($break-small - 1) }) { - // Responsiveness: Show at most one columns on mobile. This must be - // important since the Column assigns its own width as an inline style. - flex-basis: 100% !important; - } - // Prevent the columns from growing wider than their distributed sizes. min-width: 0; @@ -46,48 +111,6 @@ word-break: break-word; // For back-compat. overflow-wrap: break-word; // New standard. - // Between mobile and large viewports, allow 2 columns. - @media (min-width: #{ ($break-small) }) and (max-width: #{ ($break-medium - 1) }) { - // Only add two column styling if there are two or more columns - &:not(:only-child) { - // As with mobile styles, this must be important since the Column - // assigns its own width as an inline style, which should take effect - // starting at `break-medium`. - flex-basis: calc(50% - 1em) !important; - flex-grow: 0; - } - - // Add space between the multiple columns. Themes can customize this if they wish to work differently. - // Only apply this beyond the mobile breakpoint, as there's only a single column on mobile. - &:nth-child(even) { - margin-left: 2em; - } - } - - // At large viewports, show all columns horizontally. - @include break-medium() { - // Available space should be divided equally amongst columns without an - // assigned width. This is achieved by assigning a flex basis that is - // consistent (equal), would not cause the sum total of column widths to - // exceed 100%, and which would cede to a column with an assigned width. - // The `flex-grow` allows columns to maximally and equally occupy space - // remaining after subtracting the space occupied by columns with - // explicit widths (if any exist). - flex-basis: 0; - flex-grow: 1; - - // Columns with an explicitly-assigned width should maintain their - // `flex-basis` width and not grow. - &[style*="flex-basis"] { - flex-grow: 0; - } - - // When columns are in a single row, add space before all except the first. - &:not(:first-child) { - margin-left: 2em; - } - } - /** * Individual Column Alignment */ diff --git a/packages/e2e-tests/fixtures/blocks/core__columns.json b/packages/e2e-tests/fixtures/blocks/core__columns.json index b6e16b848abffa..6413a0cea75d75 100644 --- a/packages/e2e-tests/fixtures/blocks/core__columns.json +++ b/packages/e2e-tests/fixtures/blocks/core__columns.json @@ -4,6 +4,7 @@ "name": "core/columns", "isValid": true, "attributes": { + "isStackedOnMobile": true, "backgroundColor": "secondary" }, "innerBlocks": [ diff --git a/packages/e2e-tests/fixtures/blocks/core__columns__deprecated.json b/packages/e2e-tests/fixtures/blocks/core__columns__deprecated.json index ab71d35d661776..d577a0fd6b96c9 100644 --- a/packages/e2e-tests/fixtures/blocks/core__columns__deprecated.json +++ b/packages/e2e-tests/fixtures/blocks/core__columns__deprecated.json @@ -3,7 +3,9 @@ "clientId": "_clientId_0", "name": "core/columns", "isValid": true, - "attributes": {}, + "attributes": { + "isStackedOnMobile": true + }, "innerBlocks": [ { "clientId": "_clientId_0", diff --git a/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.html b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.html new file mode 100644 index 00000000000000..e28fd69aa1611b --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.html @@ -0,0 +1,24 @@ + +
+ +
+ +

Column One, Paragraph One

+ + +

Column One, Paragraph Two

+ +
+ + +
+ +

Column Two, Paragraph One

+ + +

Column Three, Paragraph One

+ +
+ +
+ diff --git a/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.json b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.json new file mode 100644 index 00000000000000..72f1585d5177ea --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.json @@ -0,0 +1,76 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/columns", + "isValid": true, + "attributes": { + "isStackedOnMobile": false, + "backgroundColor": "secondary" + }, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/column", + "isValid": true, + "attributes": {}, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Column One, Paragraph One", + "dropCap": false + }, + "innerBlocks": [], + "originalContent": "

Column One, Paragraph One

" + }, + { + "clientId": "_clientId_1", + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Column One, Paragraph Two", + "dropCap": false + }, + "innerBlocks": [], + "originalContent": "

Column One, Paragraph Two

" + } + ], + "originalContent": "
\n\t\t\n\t\t\n\t
" + }, + { + "clientId": "_clientId_1", + "name": "core/column", + "isValid": true, + "attributes": {}, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Column Two, Paragraph One", + "dropCap": false + }, + "innerBlocks": [], + "originalContent": "

Column Two, Paragraph One

" + }, + { + "clientId": "_clientId_1", + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Column Three, Paragraph One", + "dropCap": false + }, + "innerBlocks": [], + "originalContent": "

Column Three, Paragraph One

" + } + ], + "originalContent": "
\n\t\t\n\t\t\n\t
" + } + ], + "originalContent": "
\n\t\n\t\n
" + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.parsed.json b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.parsed.json new file mode 100644 index 00000000000000..6e12b92b39aa53 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.parsed.json @@ -0,0 +1,83 @@ +[ + { + "blockName": "core/columns", + "attrs": { + "isStackedOnMobile": false, + "backgroundColor": "secondary" + }, + "innerBlocks": [ + { + "blockName": "core/column", + "attrs": {}, + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\t

Column One, Paragraph One

\n\t\t", + "innerContent": [ + "\n\t\t

Column One, Paragraph One

\n\t\t" + ] + }, + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\t

Column One, Paragraph Two

\n\t\t", + "innerContent": [ + "\n\t\t

Column One, Paragraph Two

\n\t\t" + ] + } + ], + "innerHTML": "\n\t
\n\t\t\n\t\t\n\t
\n\t", + "innerContent": [ + "\n\t
\n\t\t", + null, + "\n\t\t", + null, + "\n\t
\n\t" + ] + }, + { + "blockName": "core/column", + "attrs": {}, + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\t

Column Two, Paragraph One

\n\t\t", + "innerContent": [ + "\n\t\t

Column Two, Paragraph One

\n\t\t" + ] + }, + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\t

Column Three, Paragraph One

\n\t\t", + "innerContent": [ + "\n\t\t

Column Three, Paragraph One

\n\t\t" + ] + } + ], + "innerHTML": "\n\t
\n\t\t\n\t\t\n\t
\n\t", + "innerContent": [ + "\n\t
\n\t\t", + null, + "\n\t\t", + null, + "\n\t
\n\t" + ] + } + ], + "innerHTML": "\n
\n\t\n\t\n
\n", + "innerContent": [ + "\n
\n\t", + null, + "\n\t", + null, + "\n
\n" + ] + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.serialized.html b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.serialized.html new file mode 100644 index 00000000000000..ca77f7df2961f6 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__columns__is-not-stacked-on-mobile.serialized.html @@ -0,0 +1,21 @@ + +
+
+

Column One, Paragraph One

+ + + +

Column One, Paragraph Two

+
+ + + +
+

Column Two, Paragraph One

+ + + +

Column Three, Paragraph One

+
+
+