diff --git a/blocks/layout-grid/front.scss b/blocks/layout-grid/front.scss
index 77da87e9..a5aed5d0 100644
--- a/blocks/layout-grid/front.scss
+++ b/blocks/layout-grid/front.scss
@@ -135,5 +135,5 @@
// Ensure inner blocks with deliberate overflows are still constrained to column.
.wp-block-jetpack-layout-grid-column {
- max-width: 100%;
+ max-width: 100%;
}
diff --git a/blocks/layout-grid/src/constants.js b/blocks/layout-grid/src/constants.js
index aa9aee1b..f4aa8b50 100644
--- a/blocks/layout-grid/src/constants.js
+++ b/blocks/layout-grid/src/constants.js
@@ -14,15 +14,17 @@ function getSpacingValues() {
];
}
-export const getPaddingValues = () => ( [
- { value: 'none', label: __( 'No padding', 'layout-grid' ) },
-].concat( getSpacingValues() ) );
+export const getPaddingValues = () =>
+ [ { value: 'none', label: __( 'No padding', 'layout-grid' ) } ].concat(
+ getSpacingValues()
+ );
-export const getGutterValues = () => ( [
- { value: 'none', label: __( 'No gutter', 'layout-grid' ) },
-].concat( getSpacingValues() ) );
+export const getGutterValues = () =>
+ [ { value: 'none', label: __( 'No gutter', 'layout-grid' ) } ].concat(
+ getSpacingValues()
+ );
-export const getColumns = () => ( [
+export const getColumns = () => [
{
label: __( '1 column', 'layout-grid' ),
value: 1,
@@ -39,17 +41,29 @@ export const getColumns = () => ( [
label: __( '4 columns', 'layout-grid' ),
value: 4,
},
-] );
+];
export const DEVICE_DESKTOP = 'Desktop';
export const DEVICE_TABLET = 'Tablet';
export const DEVICE_MOBILE = 'Mobile';
-export const getLayouts = () => ( [
- { value: DEVICE_DESKTOP, label: __( 'Desktop', 'layout-grid' ), icon: desktop },
- { value: DEVICE_TABLET, label: __( 'Tablet', 'layout-grid' ), icon: tablet },
- { value: DEVICE_MOBILE, label: __( 'Mobile', 'layout-grid' ), icon: mobile },
-] );
+export const getLayouts = () => [
+ {
+ value: DEVICE_DESKTOP,
+ label: __( 'Desktop', 'layout-grid' ),
+ icon: desktop,
+ },
+ {
+ value: DEVICE_TABLET,
+ label: __( 'Tablet', 'layout-grid' ),
+ icon: tablet,
+ },
+ {
+ value: DEVICE_MOBILE,
+ label: __( 'Mobile', 'layout-grid' ),
+ icon: mobile,
+ },
+];
export const MAX_COLUMNS = 4;
diff --git a/blocks/layout-grid/src/grid/edit.js b/blocks/layout-grid/src/grid/edit.js
index a1a0ec1c..c537db0b 100644
--- a/blocks/layout-grid/src/grid/edit.js
+++ b/blocks/layout-grid/src/grid/edit.js
@@ -12,12 +12,10 @@ import classnames from 'classnames';
import {
InnerBlocks,
InspectorControls,
-} from '@wordpress/block-editor';
-import { Component, createRef } from '@wordpress/element';
-import {
BlockControls,
BlockVerticalAlignmentToolbar,
} from '@wordpress/block-editor';
+import { Component, createRef } from '@wordpress/element';
import {
PanelBody,
TextControl,
@@ -29,10 +27,6 @@ import {
ToggleControl,
SelectControl,
Disabled,
- ToolbarGroup,
- MenuGroup,
- MenuItem,
- Dropdown,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { ENTER, SPACE } from '@wordpress/keycodes';
@@ -50,23 +44,30 @@ import {
getGutterClasses,
} from './css-classname';
import ColumnIcon from '../icons';
-import { getLayouts, getColumns, DEVICE_BREAKPOINTS, getSpanForDevice, getOffsetForDevice, getGutterValues } from '../constants';
+import {
+ getLayouts,
+ getColumns,
+ DEVICE_BREAKPOINTS,
+ getSpanForDevice,
+ getOffsetForDevice,
+ getGutterValues,
+} from '../constants';
import { getGridWidth, getDefaultSpan } from './grid-defaults';
import ResizeGrid from './resize-grid';
import LayoutGrid from './layout-grid';
+import PreviewDevice from './preview-device';
const ALLOWED_BLOCKS = [ 'jetpack/layout-grid-column' ];
const MINIMUM_RESIZE_SIZE = 50; // Empirically determined to be a good size
-// Note this uses __experimentalGetPreviewDeviceType, but has a fallback for older versions of Gutenberg.
-// The fallback will be removed once WordPress contains supports for __experimentalGetPreviewDeviceType
class Edit extends Component {
constructor( props ) {
super( props );
this.overlayRef = createRef();
this.state = {
- selectedDevice: getLayouts()[ 0 ].value,
+ inspectorDeviceType: 'Desktop',
+ viewPort: 'Desktop',
};
}
@@ -77,60 +78,66 @@ class Edit extends Component {
const columnValues = {};
for ( let pos = 0; pos < columns; pos++ ) {
- for ( let device = 0; device < DEVICE_BREAKPOINTS.length; device++ ) {
- const defaultSpan = getDefaultSpan( DEVICE_BREAKPOINTS[ device ], columns, pos );
-
- columnValues[ getSpanForDevice( pos, DEVICE_BREAKPOINTS[ device ] ) ] = defaultSpan;
- columnValues[ getOffsetForDevice( pos, DEVICE_BREAKPOINTS[ device ] ) ] = 0;
+ for (
+ let device = 0;
+ device < DEVICE_BREAKPOINTS.length;
+ device++
+ ) {
+ const defaultSpan = getDefaultSpan(
+ DEVICE_BREAKPOINTS[ device ],
+ columns,
+ pos
+ );
+
+ columnValues[
+ getSpanForDevice( pos, DEVICE_BREAKPOINTS[ device ] )
+ ] = defaultSpan;
+ columnValues[
+ getOffsetForDevice( pos, DEVICE_BREAKPOINTS[ device ] )
+ ] = 0;
}
}
this.props.updateColumns( this.props.columns, columns, columnValues );
};
- getDeviceType() {
- return this.props.deviceType
- ? this.props.deviceType
- : this.state.selectedDevice;
- }
-
- setDeviceType = ( deviceType ) => {
- if ( this.props.deviceType ) {
- this.props.setDeviceType( deviceType );
- } else {
- this.setState( { selectedDevice: deviceType } );
- }
- };
-
onResize = ( column, adjustment ) => {
const { attributes, columns } = this.props;
- const grid = new LayoutGrid( attributes, this.getDeviceType(), columns );
+ const grid = new LayoutGrid(
+ attributes,
+ this.getPreviewMode(),
+ columns
+ );
const adjustedGrid = grid.getAdjustedGrid( column, adjustment );
if ( adjustedGrid ) {
this.adjustGrid( adjustedGrid );
}
- }
+ };
onChangeSpan = ( column, device, value ) => {
const { attributes, columns } = this.props;
const grid = new LayoutGrid( attributes, device, columns );
- const adjustedGrid = grid.getAdjustedGrid( column, { span: parseInt( value, 10 ) } );
+ const adjustedGrid = grid.getAdjustedGrid( column, {
+ span: parseInt( value, 10 ),
+ } );
if ( adjustedGrid ) {
this.adjustGrid( adjustedGrid );
}
- }
+ };
onChangeOffset = ( column, device, value ) => {
const { attributes, columns } = this.props;
const grid = new LayoutGrid( attributes, device, columns );
- const adjustedGrid = grid.getAdjustedGrid( column, { start: grid.convertOffsetToStart( column, parseInt( value, 10 ) ) } );
+ const adjustedGrid = grid.getAdjustedGrid( column, {
+ start: grid.convertOffsetToStart( column, parseInt( value, 10 ) ),
+ } );
if ( adjustedGrid ) {
this.adjustGrid( adjustedGrid );
}
- }
+ };
adjustGrid( grid ) {
const { setAttributes, attributes } = this.props;
@@ -146,12 +153,16 @@ class Edit extends Component {
const settings = [];
for ( let column = 0; column < columns; column++ ) {
- const span = grid.getSpan( column ) || getDefaultSpan( device, columns, column );
+ const span =
+ grid.getSpan( column ) ||
+ getDefaultSpan( device, columns, column );
const offset = grid.getOffset( column ) || 0;
- settings.push( (
+ settings.push(
-
{ __( 'Column', 'layout-grid' ) } { column + 1 }
+
+ { __( 'Column', 'layout-grid' ) } { column + 1 }
+
this.onChangeOffset( column, device, value ) }
+ onChange={ ( value ) =>
+ this.onChangeOffset( column, device, value )
+ }
/>
this.onChangeSpan( column, device, value ) }
+ onChange={ ( value ) =>
+ this.onChangeSpan( column, device, value )
+ }
/>
- ) );
+ );
}
return settings;
@@ -187,6 +202,37 @@ class Edit extends Component {
return false;
}
+ updateInspectorDevice( device ) {
+ this.setState( { inspectorDeviceType: device } );
+
+ // Only update if not on mobile
+ if ( this.state.viewPort !== 'Mobile' ) {
+ this.props.setPreviewDeviceType( device );
+ }
+ }
+
+ getPreviewMode() {
+ // If we're on desktop, or the preview is set to mobile, then return the preview mode
+ if (
+ this.state.viewPort === 'Desktop' ||
+ this.props.previewDeviceType === 'Mobile'
+ ) {
+ return this.props.previewDeviceType;
+ }
+
+ // Return something appropriate for the viewport (mobile or tablet)
+ return this.state.viewPort;
+ }
+
+ getInspectorMode() {
+ if ( this.state.viewPort === 'Desktop' ) {
+ return this.props.previewDeviceType;
+ }
+
+ // Return something appropriate for the viewport (mobile or tablet)
+ return this.state.inspectorDeviceType;
+ }
+
render() {
const {
className,
@@ -196,25 +242,28 @@ class Edit extends Component {
setAttributes,
updateAlignment,
columnAttributes,
+ previewDeviceType,
} = this.props;
- const deviceType = this.getDeviceType();
+ const { viewPort } = this.state;
+ const previewMode = this.getPreviewMode();
+ const inspectorDeviceType = this.getInspectorMode();
const extra = getAsEditorCSS(
- deviceType,
+ previewMode,
columns,
attributes,
columnAttributes
);
const { gutterSize, addGutterEnds, verticalAlignment } = attributes;
- const layoutGrid = new LayoutGrid( attributes, deviceType, columns );
+ const layoutGrid = new LayoutGrid( attributes, previewMode, columns );
const classes = classnames(
removeGridClasses( className ),
extra,
{
- 'wp-block-jetpack-layout-tablet': deviceType === 'Tablet',
- 'wp-block-jetpack-layout-desktop': deviceType === 'Desktop',
- 'wp-block-jetpack-layout-mobile': deviceType === 'Mobile',
+ 'wp-block-jetpack-layout-tablet': previewMode === 'Tablet',
+ 'wp-block-jetpack-layout-desktop': previewMode === 'Desktop',
+ 'wp-block-jetpack-layout-mobile': previewMode === 'Mobile',
'wp-block-jetpack-layout-resizable': this.canResizeBreakpoint(
- deviceType
+ previewMode
),
[ `are-vertically-aligned-${ verticalAlignment }` ]: verticalAlignment,
},
@@ -226,7 +275,10 @@ class Edit extends Component {
@@ -234,8 +286,12 @@ class Edit extends Component {
-
}
- onClick={ () => this.onChangeLayout( column.value ) }
+ icon={
+
+ }
+ onClick={ () =>
+ this.onChangeLayout( column.value )
+ }
className="block-editor-inner-blocks__template-picker-option"
label={ column.label }
/>
@@ -250,25 +306,55 @@ class Edit extends Component {
setAttributes( { addGutterEnds: newValue } ) }
+ onChange={ ( newValue ) =>
+ setAttributes( { addGutterEnds: newValue } )
+ }
/>
);
return (
<>
+
+ this.setState( {
+ viewPort: newPort,
+ inspectorDeviceType: newPort,
+ } )
+ }
+ />
+
-
- { times( getGridWidth( deviceType ) ).map( ( item ) =>
) }
+
+ { times( getGridWidth( previewMode ) ).map(
+ ( item ) => (
+
+ )
+ ) }
this.onChangeLayout( column.value ) }
+ onClick={ () =>
+ this.onChangeLayout(
+ column.value
+ )
+ }
onKeyDown={ ( event ) => {
- if ( ENTER === event.keyCode || SPACE === event.keyCode ) {
+ if (
+ ENTER === event.keyCode ||
+ SPACE === event.keyCode
+ ) {
event.preventDefault();
- this.onChangeLayout( column.value );
+ this.onChangeLayout(
+ column.value
+ );
}
} }
role="button"
@@ -300,7 +398,9 @@ class Edit extends Component {
aria-label={ column.label }
>
-
+
{ column.label }
@@ -309,24 +409,54 @@ class Edit extends Component {
) ) }
- { __( 'Changing the number of columns will reset your layout and could remove content.', 'layout-grid' ) }
+
+
+ { __(
+ 'Changing the number of columns will reset your layout and could remove content.',
+ 'layout-grid'
+ ) }
+
+
-
- { __( "Note that previewing your post will show your browser's breakpoint, not the currently selected one.", 'layout-grid' ) }
+
+
+
+ { __(
+ "Note that previewing your post will show your browser's breakpoint, not the currently selected one.",
+ 'layout-grid'
+ ) }
+
+
{ getLayouts().map( ( layout ) => (
) ) }
- { this.renderDeviceSettings( columns, deviceType, attributes ) }
+ { this.renderDeviceSettings(
+ columns,
+ inspectorDeviceType,
+ attributes
+ ) }
@@ -334,16 +464,23 @@ class Edit extends Component {
setAttributes( { gutterSize: newValue, addGutterEnds: newValue === 'none' ? false : addGutterEnds } ) }
+ onChange={ ( newValue ) =>
+ setAttributes( {
+ gutterSize: newValue,
+ addGutterEnds:
+ newValue === 'none'
+ ? false
+ : addGutterEnds,
+ } )
+ }
options={ getGutterValues() }
/>
{ gutterSize === 'none' ? (
-
- { toggleControl }
-
- ) : toggleControl }
-
+ { toggleControl }
+ ) : (
+ toggleControl
+ ) }
@@ -354,31 +491,6 @@ class Edit extends Component {
onChange={ updateAlignment }
value={ verticalAlignment }
/>
- (
-
-
- ) }
- renderContent={ ( { onClose } ) => (
-
- { getLayouts().map( ( layout ) => (
-
- ) ) }
-
- ) }
- />
>
);
@@ -390,7 +502,9 @@ function getColumnBlocks( currentBlocks, previous, columns ) {
// Add new blocks to the end
return [
...currentBlocks,
- ...times( columns - previous, () => createBlock( 'jetpack/layout-grid-column' ) ),
+ ...times( columns - previous, () =>
+ createBlock( 'jetpack/layout-grid-column' )
+ ),
];
}
@@ -403,7 +517,10 @@ function getColumnBlocks( currentBlocks, previous, columns ) {
// Remove empty blocks
cleanedBlocks = cleanedBlocks.filter( ( block ) => {
- if ( totalRemoved < previous - columns && block.innerBlocks.length === 0 ) {
+ if (
+ totalRemoved < previous - columns &&
+ block.innerBlocks.length === 0
+ ) {
totalRemoved++;
return false;
}
@@ -446,32 +563,44 @@ export default compose( [
const { clientId } = ownProps;
const { replaceBlock } = dispatch( 'core/block-editor' );
const { getBlocks } = registry.select( 'core/block-editor' );
- const innerBlocks = getColumnBlocks( getBlocks( clientId ), previous, columns );
+ const innerBlocks = getColumnBlocks(
+ getBlocks( clientId ),
+ previous,
+ columns
+ );
// Replace the whole block with a new one so that our changes to both the attributes and innerBlocks are atomic
// This ensures that the undo history has a single entry, preventing traversing to a 'half way' point where innerBlocks are changed
// but the column attributes arent
- const blockCopy = createBlock( ownProps.name, {
- ...ownProps.attributes,
- ...columnValues,
- className: removeGridClasses( ownProps.attributes.className ),
- }, innerBlocks );
+ const blockCopy = createBlock(
+ ownProps.name,
+ {
+ ...ownProps.attributes,
+ ...columnValues,
+ className: removeGridClasses(
+ ownProps.attributes.className
+ ),
+ },
+ innerBlocks
+ );
replaceBlock( clientId, blockCopy );
},
- setDeviceType( type ) {
- const {
- __experimentalSetPreviewDeviceType,
- } = dispatch( 'core/edit-post' );
+ setPreviewDeviceType( type ) {
+ const { __experimentalSetPreviewDeviceType } = dispatch(
+ 'core/edit-post'
+ );
__experimentalSetPreviewDeviceType( type );
- }
+ },
} ) ),
withSelect( ( select, { clientId } ) => {
const { getBlockOrder, getBlockCount, getBlocksByClientId } = select(
'core/block-editor'
);
- const { __experimentalGetPreviewDeviceType = null } = select( 'core/edit-post' );
+ const { __experimentalGetPreviewDeviceType = null } = select(
+ 'core/edit-post'
+ );
return {
columns: getBlockCount( clientId ),
@@ -479,7 +608,7 @@ export default compose( [
( innerBlockClientId ) =>
getBlocksByClientId( innerBlockClientId )[ 0 ].attributes
),
- deviceType: __experimentalGetPreviewDeviceType ? __experimentalGetPreviewDeviceType() : null,
+ previewDeviceType: __experimentalGetPreviewDeviceType(),
};
} ),
] )( Edit );
diff --git a/blocks/layout-grid/src/grid/preview-device.js b/blocks/layout-grid/src/grid/preview-device.js
new file mode 100644
index 00000000..44f85bc0
--- /dev/null
+++ b/blocks/layout-grid/src/grid/preview-device.js
@@ -0,0 +1,96 @@
+/**
+ * WordPress dependencies
+ */
+
+import { useEffect } from '@wordpress/element';
+import { useViewportMatch, useResizeObserver } from '@wordpress/compose';
+import { useSelect, useDispatch } from '@wordpress/data';
+import {
+ Button,
+ ToolbarGroup,
+ MenuGroup,
+ MenuItemsChoice,
+ Dropdown,
+} from '@wordpress/components';
+import { BlockControls } from '@wordpress/block-editor';
+
+/**
+ * Internal dependencies
+ */
+
+import { getLayouts } from '../constants';
+
+function getCurrentViewport( isMobile, isTablet ) {
+ if ( isMobile ) {
+ return 'Mobile';
+ }
+
+ if ( isTablet ) {
+ return 'Tablet';
+ }
+
+ return 'Desktop';
+}
+
+function PreviewDevice( props ) {
+ const { viewPort, updateViewport } = props;
+ const {
+ __experimentalSetPreviewDeviceType: setPreviewDevice,
+ } = useDispatch( 'core/edit-post' );
+ const previewDevice = useSelect(
+ ( select ) =>
+ select( 'core/edit-post' ).__experimentalGetPreviewDeviceType(),
+ []
+ );
+ const [ resizeListener, sizes ] = useResizeObserver();
+ const isTablet = useViewportMatch( 'medium', '<' );
+ const isMobile = useViewportMatch( 'small', '<' );
+
+ useEffect( () => {
+ const newPort = getCurrentViewport( isMobile, isTablet );
+
+ if ( newPort !== viewPort ) {
+ updateViewport( newPort );
+ }
+ }, [ sizes ] );
+
+ return (
+ <>
+ { resizeListener }
+
+ { ! isMobile && (
+
+ (
+
+
+ ) }
+ renderContent={ () => (
+
+
+ setPreviewDevice( mode )
+ }
+ choices={ getLayouts() }
+ />
+
+ ) }
+ />
+
+ ) }
+ >
+ );
+}
+
+export default PreviewDevice;
diff --git a/bundler/bundles/layout-grid.json b/bundler/bundles/layout-grid.json
index e42946cb..ffa81576 100644
--- a/bundler/bundles/layout-grid.json
+++ b/bundler/bundles/layout-grid.json
@@ -2,7 +2,7 @@
"blocks": [
"layout-grid"
],
- "version": "1.4",
+ "version": "1.5",
"name": "Layout Grid",
"description": "Let any blocks align to a global grid",
"resource": "jetpack-layout-grid",
diff --git a/bundler/resources/jetpack-layout-grid/readme.txt b/bundler/resources/jetpack-layout-grid/readme.txt
index a1e575f6..8a0afddf 100644
--- a/bundler/resources/jetpack-layout-grid/readme.txt
+++ b/bundler/resources/jetpack-layout-grid/readme.txt
@@ -1,8 +1,8 @@
=== Layout Grid Block ===
Contributors: automattic, jasmussen, johnny5, mkaz
-Stable tag: 1.4
+Stable tag: trunk
Tested up to: 5.6
-Requires at least: 5.5
+Requires at least: 5.6
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Tags: blocks, layout, grid, design
@@ -24,6 +24,9 @@ You can follow development, file an issue, suggest features, and view the source
== Changelog ==
+= 1.5 - 5th February 2021 =
+* Improve editor responsive behaviour on smaller devices
+
= 1.4 - 15th January 2021 =
* Use hyphenation for text inside a grid column
* Add missing `has-background` for columns with a custom background colour