diff --git a/blocks/layout-grid/src/grid-column/edit.js b/blocks/layout-grid/src/grid-column/edit.js index 1614b477..9c171ac5 100644 --- a/blocks/layout-grid/src/grid-column/edit.js +++ b/blocks/layout-grid/src/grid-column/edit.js @@ -7,7 +7,6 @@ import classnames from 'classnames'; /** * WordPress dependencies */ - import { InnerBlocks, InspectorControls, @@ -18,7 +17,7 @@ import { } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; import { compose } from '@wordpress/compose'; -import { withSelect, withDispatch } from '@wordpress/data'; +import { withSelect } from '@wordpress/data'; import { PanelBody, SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -26,6 +25,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { getPaddingValues } from '../constants'; +import { withUpdateAlignment } from './hooks/with-update-alignment'; class Edit extends Component { constructor( props ) { @@ -151,26 +151,5 @@ export default compose( hasChildBlocks: getBlockOrder( clientId ).length > 0, }; } ), - withDispatch( ( dispatch, ownProps, registry ) => { - return { - updateAlignment( verticalAlignment ) { - const { clientId, setAttributes } = ownProps; - const { updateBlockAttributes } = dispatch( - 'core/block-editor' - ); - const { getBlockRootClientId } = registry.select( - 'core/block-editor' - ); - - // Update own alignment. - setAttributes( { verticalAlignment } ); - - // Reset Parent Columns Block - const rootClientId = getBlockRootClientId( clientId ); - updateBlockAttributes( rootClientId, { - verticalAlignment: null, - } ); - }, - }; - } ) + withUpdateAlignment(), )( Edit ); diff --git a/blocks/layout-grid/src/grid-column/edit.native.js b/blocks/layout-grid/src/grid-column/edit.native.js index d53e745e..7a800fdf 100644 --- a/blocks/layout-grid/src/grid-column/edit.native.js +++ b/blocks/layout-grid/src/grid-column/edit.native.js @@ -6,27 +6,228 @@ import { View } from 'react-native'; /** * WordPress dependencies */ -import { InnerBlocks } from '@wordpress/block-editor'; -import { Component } from '@wordpress/element'; +import { + PanelBody, + BottomSheetSelectControl, + alignmentHelpers, +} from '@wordpress/components'; +import { withViewportMatch } from '@wordpress/viewport'; +import { + InnerBlocks, + InspectorControls, + BlockControls, + BlockVerticalAlignmentToolbar, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; +import { withSelect } from '@wordpress/data'; +import { compose, usePreferredColorSchemeStyle } from '@wordpress/compose'; -class Edit extends Component { - constructor( props ) { - super( props ); +/** + * Internal dependencies + */ +import { getPaddingValues } from '../constants'; +import { withUpdateAlignment } from './hooks/with-update-alignment'; +import styles from './edit.native.scss'; + +/** + * Calculate the column styles. + * + * @param {int} columns + * @param {int} index + * @param {int} fullWidth + * @param {string} viewport + * @return {object} + */ +function getColumnStyles( columns, index, fullWidth, viewport ) { + // Default widths for 1 column layout. + let widths = { + mobile: fullWidth, + tablet: fullWidth, + desktop: fullWidth, + }; + const TWO_COLUMN_MARGIN = 16; + const THREE_COLUMN_MARGIN = 22; + const FOUR_COLUMN_MARGIN = 24; + + switch ( columns ) { + case 2: + widths = { + mobile: fullWidth, + tablet: Math.floor( fullWidth / 2 ) - TWO_COLUMN_MARGIN, + desktop: Math.floor( fullWidth / 2 ) - TWO_COLUMN_MARGIN, + }; + break; + case 3: + widths = { + mobile: fullWidth, + tablet: Math.floor( fullWidth / 2 ) - TWO_COLUMN_MARGIN, + desktop: Math.floor( fullWidth / 3 ) - THREE_COLUMN_MARGIN, + }; + if ( index === 2 ) { + widths.tablet = fullWidth; + } + break; + case 4: + widths = { + mobile: fullWidth, + tablet: Math.floor( fullWidth / 2 ) - TWO_COLUMN_MARGIN, + desktop: Math.floor( fullWidth / 4 ) - FOUR_COLUMN_MARGIN, + }; + break; } - render() { + return { width: widths[ viewport ] }; +} + +function ColumnsEdit( { + hasChildren, + attributes, + isSelected, + setAttributes, + updateAlignment, + isParentSelected, + selectedColumnIndex, + contentStyle, + isMobile, + isTablet, + parentAlign, + parentColumnCount, +} ) { + const { padding, verticalAlignment } = attributes; + + const { isFullWidth } = alignmentHelpers; + + let viewportSize = 'desktop'; + if ( isTablet ) { + viewportSize = 'tablet'; + } + if ( isMobile ) { + viewportSize = 'mobile'; + } + + const stylePlaceholder = usePreferredColorSchemeStyle( + styles.column__placeholder, + styles[ 'column__placeholder-dark' ] + ); + + const calculatedColumnStyles = getColumnStyles( + parentColumnCount, + selectedColumnIndex, + contentStyle.width, + viewportSize + ); + + if ( ! isSelected && ! hasChildren ) { return ( - + + ); + } + + const columnPadding = + isSelected && 'none' === padding + ? styles[ 'column__padding-none-is-selected' ] + : styles[ 'column__padding-' + padding ]; + + const appenderStyle = hasChildren + ? styles[ 'column__appender-has-children' ] + : styles.column__appender; + + return ( + <> + + renderAppender={ + ! hasChildren || isSelected + ? () => ( + + + + ) + : undefined } + parentWidth={ calculatedColumnStyles.width } + blockWidth={ calculatedColumnStyles.width } /> - ); - } + + + + setAttributes( { padding: newValue } ) + } + options={ getPaddingValues() } + /> + + + + + + + + ); } -export default Edit; \ No newline at end of file +export default compose( + withSelect( ( select, { clientId } ) => { + const { + getBlockCount, + getBlockRootClientId, + getSelectedBlockClientId, + getBlocks, + getBlockOrder, + getBlockAttributes, + } = select( blockEditorStore ); + + const selectedBlockClientId = getSelectedBlockClientId(); + const isSelected = selectedBlockClientId === clientId; + + const parentId = getBlockRootClientId( clientId ); + const hasChildren = !! getBlockCount( clientId ); + const isParentSelected = + selectedBlockClientId && selectedBlockClientId === parentId; + + const blockOrder = getBlockOrder( parentId ); + + const selectedColumnIndex = blockOrder.indexOf( clientId ); + const columns = getBlocks( parentId ); + + const parentAlign = getBlockAttributes( parentId )?.align; + const parentColumnCount = getBlockCount( parentId ); + + return { + hasChildren, + isParentSelected, + isSelected, + selectedColumnIndex, + columns, + parentAlign, + parentColumnCount, + }; + } ), + withUpdateAlignment(), + withViewportMatch( { isMobile: '< small', isTablet: '< large' } ) +)( ColumnsEdit ); diff --git a/blocks/layout-grid/src/grid-column/edit.native.scss b/blocks/layout-grid/src/grid-column/edit.native.scss new file mode 100644 index 00000000..1dca1aa7 --- /dev/null +++ b/blocks/layout-grid/src/grid-column/edit.native.scss @@ -0,0 +1,54 @@ +.column__placeholder { + flex: 1; + padding: $block-selected-to-content; + background-color: $white; + border: $border-width dashed $gray; + border-radius: 4px; +} + +.column__placeholder-dark { + background-color: $black; + border: $border-width dashed $gray-70; +} + +.column__placeholder-not-selected { + padding-top: $block-selected-to-content; +} + +.column__appender { + margin-left: 8px; + margin-right: 8px; + margin-bottom: -10px; +} + +.column__appender-has-children { + margin-left: 16px; + margin-right: 16px; + margin-bottom: 6px; +} + +.column__appender-not-full-width { + margin-left: 0; + margin-right: 0; +} + +.column__padding-none { + padding: 0; +} +/* Add extra space to the bottom of the column block make sure that the there is enough space between column block and the settings cog. */ +.column__padding-none-is-selected { + padding: 0 0 10px; +} + +.column__padding-small { + padding: 10px 8px 10px; +} +.column__padding-medium { + padding: 16px; +} +.column__padding-large { + padding: 24px; +} +.column__padding-huge { + padding: 48px; +} diff --git a/blocks/layout-grid/src/grid-column/hooks/with-update-alignment.js b/blocks/layout-grid/src/grid-column/hooks/with-update-alignment.js new file mode 100644 index 00000000..73effdd5 --- /dev/null +++ b/blocks/layout-grid/src/grid-column/hooks/with-update-alignment.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { withDispatch } from '@wordpress/data'; + +export function withUpdateAlignment() { + return withDispatch( ( dispatch, ownProps, registry ) => { + return { + updateAlignment( verticalAlignment ) { + const { clientId, setAttributes } = ownProps; + const { updateBlockAttributes } = dispatch( + 'core/block-editor' + ); + const { getBlockRootClientId } = registry.select( + 'core/block-editor' + ); + + // Update own alignment. + setAttributes( { verticalAlignment } ); + + // Reset Parent Columns Block + const rootClientId = getBlockRootClientId( clientId ); + updateBlockAttributes( rootClientId, { + verticalAlignment: null, + } ); + }, + }; + } ); +} diff --git a/blocks/layout-grid/src/grid/edit.js b/blocks/layout-grid/src/grid/edit.js index 42c656bb..64cde26b 100644 --- a/blocks/layout-grid/src/grid/edit.js +++ b/blocks/layout-grid/src/grid/edit.js @@ -1,7 +1,6 @@ /** * External dependencies */ - import { times } from 'lodash'; import classnames from 'classnames'; @@ -29,9 +28,7 @@ import { } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { ENTER, SPACE } from '@wordpress/keycodes'; -import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; -import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies @@ -56,6 +53,15 @@ import ResizeGrid from './resize-grid'; import LayoutGrid from './layout-grid'; import PreviewDevice from './preview-device'; +import { + withUpdateAlignment, + withUpdateColumns, + withSetPreviewDeviceType, + withColumns, + withColumnAttributes, + withPreviewDeviceType, +} from './higher-order'; + const ALLOWED_BLOCKS = [ 'jetpack/layout-grid-column' ]; const MINIMUM_RESIZE_SIZE = 50; // Empirically determined to be a good size @@ -495,43 +501,6 @@ class Edit extends Component { } } -function getColumnBlocks( currentBlocks, previous, columns ) { - if ( columns > previous ) { - // Add new blocks to the end - return [ - ...currentBlocks, - ...times( columns - previous, () => - createBlock( 'jetpack/layout-grid-column' ) - ), - ]; - } - - // A little ugly but... ideally we remove empty blocks first, and then anything with content from the end - let cleanedBlocks = [ ...currentBlocks ]; - let totalRemoved = 0; - - // Reverse the blocks so we start at the end. This happens in-place - cleanedBlocks.reverse(); - - // Remove empty blocks - cleanedBlocks = cleanedBlocks.filter( ( block ) => { - if ( - totalRemoved < previous - columns && - block.innerBlocks.length === 0 - ) { - totalRemoved++; - return false; - } - - return true; - } ); - - // If we still need to remove blocks then do them from the beginning before flipping it back round - return cleanedBlocks - .slice( Math.max( 0, previous - columns - totalRemoved ) ) - .reverse(); -} - function MaybeDisabledEdit( props ) { return ( @@ -545,80 +514,10 @@ function MaybeDisabledEdit( props ) { } export default compose( [ - withDispatch( ( dispatch, ownProps, registry ) => ( { - /** - * Update all child Column blocks with a new vertical alignment setting - * based on whatever alignment is passed in. This allows change to parent - * to overide anything set on a individual column basis. - * - * @param {string} verticalAlignment the vertical alignment setting - */ - updateAlignment( verticalAlignment ) { - const { clientId, setAttributes } = ownProps; - const { updateBlockAttributes } = dispatch( 'core/block-editor' ); - const { getBlockOrder } = registry.select( 'core/block-editor' ); - - // Update own alignment. - setAttributes( { verticalAlignment } ); - - // Update all child Column Blocks to match - const innerBlockClientIds = getBlockOrder( clientId ); - innerBlockClientIds.forEach( ( innerBlockClientId ) => { - updateBlockAttributes( innerBlockClientId, { - verticalAlignment, - } ); - } ); - }, - updateColumns( previous, columns, columnValues ) { - const { clientId } = ownProps; - const { replaceBlock } = dispatch( 'core/block-editor' ); - const { getBlocks } = registry.select( 'core/block-editor' ); - 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 - ); - - replaceBlock( clientId, blockCopy ); - }, - 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' - ); - - return { - columns: getBlockCount( clientId ), - columnAttributes: getBlockOrder( clientId ).map( - ( innerBlockClientId ) => - getBlocksByClientId( innerBlockClientId )[ 0 ].attributes - ), - previewDeviceType: __experimentalGetPreviewDeviceType(), - }; - } ), + withUpdateAlignment(), + withUpdateColumns(), + withSetPreviewDeviceType(), + withColumns(), + withColumnAttributes(), + withPreviewDeviceType(), ] )( MaybeDisabledEdit ); diff --git a/blocks/layout-grid/src/grid/edit.native.js b/blocks/layout-grid/src/grid/edit.native.js index 752135c9..d4dcf1aa 100644 --- a/blocks/layout-grid/src/grid/edit.native.js +++ b/blocks/layout-grid/src/grid/edit.native.js @@ -1,35 +1,139 @@ /** * External dependencies */ -import { View } from 'react-native'; - +import { View, Dimensions } from 'react-native'; /** * WordPress dependencies */ -import { InnerBlocks } from '@wordpress/block-editor'; -import { Component } from '@wordpress/element'; +import { + InnerBlocks, + InspectorControls, + BlockControls, + BlockVerticalAlignmentToolbar, +} from '@wordpress/block-editor'; +import { PanelBody, alignmentHelpers } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { compose, useResizeObserver } from '@wordpress/compose'; +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import variations from './variations'; +import VariationControl from './variation-control'; +import { + DEVICE_BREAKPOINTS, + getSpanForDevice, + getOffsetForDevice, +} from './../constants'; +import { getDefaultSpan } from './grid-defaults'; +import { + withUpdateAlignment, + withUpdateColumns, + withColumns, + withColumnAttributes, +} from './higher-order'; +import styles from './edit.native.scss'; const ALLOWED_BLOCKS = [ 'jetpack/layout-grid-column' ]; -const TEMPLATE = [ +const DEFAULT_TEMPLATE = [ [ 'jetpack/layout-grid-column', {}, [] ], [ 'jetpack/layout-grid-column', {}, [] ], ]; -class Edit extends Component { - constructor( props ) { - super( props ); - } +const { isFullWidth } = alignmentHelpers; + +function ColumnsEdit( { + clientId, + attributes = {}, + columns, + updateAlignment, + updateColumns, +} ) { + const { verticalAlignment, align } = attributes; + + const [ isDefaultColumns, setDefaultColumns ] = useState( ! columns ); - render() { - return + const [ resizeListener, sizes ] = useResizeObserver(); + const { width } = sizes || {}; + + const onChangeLayout = ( selectedColumn ) => { + const columnValues = {}; + const numberOfColumns = selectedColumn.innerBlocks.length; + // An array containing the [ 0, 1 ... numberOfColumns ] + const columnsArray = [ ...Array( numberOfColumns ).keys() ]; + columnsArray.forEach( ( position ) => { + DEVICE_BREAKPOINTS.forEach( ( deviceName ) => { + const defaultSpan = getDefaultSpan( + deviceName, + numberOfColumns, + position + ); + columnValues[ + getSpanForDevice( position, deviceName ) + ] = defaultSpan; + + columnValues[ getOffsetForDevice( position, deviceName ) ] = 0; + } ); + } ); + + setDefaultColumns( false ); + updateColumns( columns, numberOfColumns, columnValues ); + }; + + const screenWidth = Math.floor( Dimensions.get( 'window' ).width ); + const selectedColumnsName = columns ? variations[ columns - 1 ].name : null; + + return ( + <> + { resizeListener } + + + + + + + + + - ; - } + + { + setDefaultColumns( false ); + } } + clientId={ clientId } + onChange={ onChangeLayout } + hasLeftButton={ true } + isVisible={ isDefaultColumns } + /> + + ); } -export default Edit; \ No newline at end of file +export default compose( [ + withUpdateAlignment(), + withUpdateColumns(), + withColumns(), + withColumnAttributes(), +] )( ColumnsEdit ); diff --git a/blocks/layout-grid/src/grid/edit.native.scss b/blocks/layout-grid/src/grid/edit.native.scss new file mode 100644 index 00000000..76969b0c --- /dev/null +++ b/blocks/layout-grid/src/grid/edit.native.scss @@ -0,0 +1,3 @@ +.grid-columns { + padding-bottom: 8px; +} \ No newline at end of file diff --git a/blocks/layout-grid/src/grid/higher-order.js b/blocks/layout-grid/src/grid/higher-order.js new file mode 100644 index 00000000..42b59acb --- /dev/null +++ b/blocks/layout-grid/src/grid/higher-order.js @@ -0,0 +1,169 @@ +/** + * WordPress dependencies + */ +import { withSelect, withDispatch } from '@wordpress/data'; + +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { removeGridClasses } from './css-classname'; + +function getColumnBlocks( currentBlocks, previous, columns ) { + if ( columns > previous ) { + // Add new blocks to the end + return [ + ...currentBlocks, + ...Array.from( { length: columns - previous }, () => + createBlock( 'jetpack/layout-grid-column' ) + ), + ]; + } + + // A little ugly but... ideally we remove empty blocks first, and then anything with content from the end + let cleanedBlocks = [ ...currentBlocks ]; + let totalRemoved = 0; + + // Reverse the blocks so we start at the end. This happens in-place + cleanedBlocks.reverse(); + + // Remove empty blocks + cleanedBlocks = cleanedBlocks.filter( ( block ) => { + if ( + totalRemoved < previous - columns && + block.innerBlocks.length === 0 + ) { + totalRemoved++; + return false; + } + + return true; + } ); + + // If we still need to remove blocks then do them from the beginning before flipping it back round + return cleanedBlocks + .slice( Math.max( 0, previous - columns - totalRemoved ) ) + .reverse(); +} + +export function withUpdateAlignment() { + return withDispatch( ( dispatch, ownProps, registry ) => { + return { + /** + * Update all child Column blocks with a new vertical alignment setting + * based on whatever alignment is passed in. This allows change to parent + * to overide anything set on a individual column basis. + * + * @param {string} verticalAlignment the vertical alignment setting + */ + updateAlignment( verticalAlignment ) { + const { clientId, setAttributes } = ownProps; + const { updateBlockAttributes } = dispatch( + 'core/block-editor' + ); + const { getBlockOrder } = registry.select( + 'core/block-editor' + ); + + // Update own alignment. + setAttributes( { verticalAlignment } ); + + // Update all child Column Blocks to match + const innerBlockClientIds = getBlockOrder( clientId ); + innerBlockClientIds.forEach( ( innerBlockClientId ) => { + updateBlockAttributes( innerBlockClientId, { + verticalAlignment, + } ); + } ); + }, + }; + } ); +} + +export function withUpdateColumns() { + return withDispatch( ( dispatch, ownProps, registry ) => { + return { + updateColumns( previous, columns, columnValues ) { + const { clientId } = ownProps; + const { replaceBlock } = dispatch( 'core/block-editor' ); + const { getBlocks } = registry.select( 'core/block-editor' ); + 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 + ); + + replaceBlock( clientId, blockCopy ); + }, + }; + } ); +} + +export function withSetPreviewDeviceType() { + return withDispatch( ( dispatch ) => { + return { + setPreviewDeviceType( type ) { + const { __experimentalSetPreviewDeviceType } = dispatch( + 'core/edit-post' + ); + __experimentalSetPreviewDeviceType( type ); + }, + }; + } ); +} + +export function withColumns() { + return withSelect( ( select, { clientId } ) => { + const { getBlockCount } = select( 'core/block-editor' ); + + return { + columns: getBlockCount( clientId ), + }; + } ); +} + +export function withColumnAttributes() { + return withSelect( ( select, { clientId } ) => { + const { getBlockOrder, getBlocksByClientId } = select( + 'core/block-editor' + ); + + return { + columnAttributes: getBlockOrder( clientId ).map( + ( innerBlockClientId ) => + getBlocksByClientId( innerBlockClientId )[ 0 ].attributes + ), + }; + } ); +} + +export function withPreviewDeviceType() { + return withSelect( ( select ) => { + const { __experimentalGetPreviewDeviceType = null } = select( + 'core/edit-post' + ); + + return { + previewDeviceType: __experimentalGetPreviewDeviceType(), + }; + } ); +} diff --git a/blocks/layout-grid/src/grid/variation-control/index.native.js b/blocks/layout-grid/src/grid/variation-control/index.native.js new file mode 100644 index 00000000..11e33dbd --- /dev/null +++ b/blocks/layout-grid/src/grid/variation-control/index.native.js @@ -0,0 +1,210 @@ +/** + * External dependencies + */ +import { + ScrollView, + View, + Text, + TouchableWithoutFeedback, + TouchableHighlight, + Platform, +} from 'react-native'; + +/** + * WordPress dependencies + */ +import { usePreferredColorSchemeStyle } from '@wordpress/compose'; +import { __ } from '@wordpress/i18n'; +import { BottomSheet, InserterButton } from '@wordpress/components'; +import { Icon, close } from '@wordpress/icons'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import styles from './style.native.scss'; + +function VariationControlSelectedButton( { name, icon } ) { + const buttonBorder = usePreferredColorSchemeStyle( + styles[ 'variation-control-selected-button__item' ], + styles[ 'variation-control-selected-button__item-dark' ] + ); + + const labelIconStyle = usePreferredColorSchemeStyle( + styles[ 'variation-control-selected-button__label-icon' ], + styles[ 'variation-control-selected-button__label-icon-dark' ] + ); + + const labelStyle = usePreferredColorSchemeStyle( + styles[ 'variation-control-selected-button__label' ], + styles[ 'variation-control-selected-button__label-dark' ] + ); + return ( + + <> + + + + + + { name } + + + ); +} + +function VariationControlInner( { variations, onChange, selected = null } ) { + return useMemo( + () => ( + <> + + { variations.map( ( variation ) => { + const isSelected = variation.name === selected; + return ( + + { isSelected ? ( + + ) : ( + onChange( variation ) } + /> + ) } + + ); + } ) } + + + { __( + 'Note: Layout may vary between themes and screen sizes', + 'layout-grid' + ) } + + { selected && ( + + { __( + 'Changing the number of columns will reset your layout and could remove content.', + 'layout-grid' + ) } + + ) } + + ), + [ variations, onChange ] + ); +} + +const hitSlop = { top: 22, bottom: 22, left: 22, right: 22 }; +function VariationControl( { + isVisible, + onClose, + variations, + onChange, + hasLeftButton, +} ) { + const isIOS = Platform.OS === 'ios'; + + const cancelButtonStyle = usePreferredColorSchemeStyle( + styles[ 'variation-control__cancel-button' ], + styles[ 'variation-control__cancel-button-dark' ] + ); + + const leftButton = useMemo( + () => ( + + + { isIOS ? ( + + { + __( + 'Cancel' + ) /* This is intentionally without a translation domain. */ + } + + ) : ( + + ) } + + + ), + [ onClose, cancelButtonStyle ] + ); + + const onVariationSelect = ( variation ) => { + onChange( variation ); + onClose(); + }; + + return useMemo( + () => ( + + + + + + ), + [ variations, isVisible, onClose, onChange ] + ); +} + +VariationControl.Inner = VariationControlInner; + +export default VariationControl; diff --git a/blocks/layout-grid/src/grid/variation-control/style.native.scss b/blocks/layout-grid/src/grid/variation-control/style.native.scss new file mode 100644 index 00000000..c2e4328c --- /dev/null +++ b/blocks/layout-grid/src/grid/variation-control/style.native.scss @@ -0,0 +1,89 @@ +.variation-control { + padding-left: 0; + padding-right: 0; +} + +.variation-control__cancel-button { + color: $blue-wordpress; + font-size: 16px; +} +.variation-control__cancel-button-dark { + color: $blue-30; +} + +.variation-control__close-icon { + color: $gray; +} + +.variation-control__inner-shell { + padding: 0 $grid-unit-20; +} + +.variation-control-inner__scrollview-container { + flex-direction: row; + padding-left: 8px; + padding-right: 0; + +} + +.variation-control-inner__scrollview { + padding-top: $grid-unit-15; + margin-left: -16px; + margin-right: -16px; +} + +.variation-control-inner__footer { + padding-top: 21.5px; + padding-bottom: 10.5px; + font-size: 12px; + color: $gray; + flex: 1; +} + +.variation-control-inner__footer-last { + padding-top: 0px; +} + +.variation-control-selected-button { + width: 112px; + height: 84px; +} + +.variation-control-selected-button__item { + border-width: $block-selected-border-width; + border-radius: 8px; + border-style: solid; + border-color: $blue-50; + background-color: $gray-light; +} +.variation-control-selected-button__item-dark { + border-color: $blue-30; + background-color: rgba( $white, 0.07 ); +} + +.variation-control-selected-button__label-icon { + width: 48px; + height: 32px; + justify-content: center; + align-items: center; + fill: $gray-dark; +} + +.variation-control-selected-button__label-icon-dark { + fill: $white; +} + +.variation-control-selected-button__label{ + background-color: transparent; + padding-left: 2; + padding-right: 2; + padding-top: 4; + padding-bottom: 0; + justify-content: center; + font-size: 12; + color: $gray-dark; +} + +.variation-control-selected-button__label-dark { + color: $white; +} \ No newline at end of file diff --git a/blocks/layout-grid/src/grid/variations.js b/blocks/layout-grid/src/grid/variations.js new file mode 100644 index 00000000..fb527556 --- /dev/null +++ b/blocks/layout-grid/src/grid/variations.js @@ -0,0 +1,65 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */ + +/** + * Internal dependencies + */ +import ColumnIcon from './../icons'; +/** + * Template option choices for predefined columns layouts. + * + * @type {WPBlockVariation[]} + */ +const variations = [ + { + name: 'one-column', + title: __( 'One' ), + description: __( 'One column', 'layout-grid' ), + icon: , + isDefault: true, + innerBlocks: [ [ 'jetpack/layout-grid-column' ] ], + scope: [ 'block' ], + }, + { + name: 'two-columns', + title: __( 'Two' ), + description: __( 'Two columns', 'layout-grid' ), + icon: , + innerBlocks: [ + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + ], + scope: [ 'block' ], + }, + { + name: 'three-columns', + title: __( 'Three' ), + description: __( 'Three columns', 'layout-grid' ), + icon: , + innerBlocks: [ + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + ], + scope: [ 'block' ], + }, + { + name: 'four-columns', + title: __( 'Four' ), + description: __( 'Four columns', 'layout-grid' ), + icon: , + innerBlocks: [ + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + [ 'jetpack/layout-grid-column' ], + ], + scope: [ 'block' ], + }, +]; + +export default variations; diff --git a/blocks/layout-grid/src/icons.js b/blocks/layout-grid/src/icons.js index 8d7eb582..dcaddd5a 100644 --- a/blocks/layout-grid/src/icons.js +++ b/blocks/layout-grid/src/icons.js @@ -4,15 +4,22 @@ import { Path, SVG } from '@wordpress/components'; -export const GridIcon = ( props ) => ( - - - -); +export const GridIcon = ( props ) => { + if ( props.size ) { + props.width = props.size; + props.height = props.size; + } + + return ( + + + + ); +}; export const GridColumnIcon = ( props ) => (