Skip to content

Commit

Permalink
Gallery: Convert Gallery block to use Image blocks instead of having …
Browse files Browse the repository at this point in the history
…its own nested image format (#25940)

Co-authored-by: Glen Davies <[email protected]>
Co-authored-by: Aaron Robertshaw <[email protected]>
Co-authored-by: Matthew Kevins <[email protected]>
Co-authored-by: Antonis Lilis <[email protected]>
Co-authored-by: Andrew Serong <[email protected]>
  • Loading branch information
6 people authored Aug 19, 2021
1 parent a1bb2e6 commit 3e645c4
Show file tree
Hide file tree
Showing 62 changed files with 2,631 additions and 673 deletions.
32 changes: 32 additions & 0 deletions lib/experiments-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ function gutenberg_initialize_experiments_settings() {
'id' => 'gutenberg-navigation',
)
);
add_settings_field(
'gutenberg-gallery-refactor',
__( 'Gallery block experiment', 'gutenberg' ),
'gutenberg_display_experiment_field',
'gutenberg-experiments',
'gutenberg_experiments_section',
array(
'label' => __( 'Test a new gallery block that uses nested image blocks (Warning: The new gallery is not compatible with WordPress mobile apps prior to version 18.1. If you use the mobile app, please update to the latest version to avoid content loss.)', 'gutenberg' ),
'id' => 'gutenberg-gallery-refactor',
)
);
register_setting(
'gutenberg-experiments',
'gutenberg-experiments'
Expand Down Expand Up @@ -88,3 +99,24 @@ function gutenberg_display_experiment_section() {

<?php
}

/**
* Extends default editor settings with experiments settings.
*
* @param array $settings Default editor settings.
*
* @return array Filtered editor settings.
*/
function gutenberg_experiments_editor_settings( $settings ) {
$experiments = get_option( 'gutenberg-experiments' );
$experiments_settings = array(
'__unstableGalleryWithImageBlocks' => isset( $experiments['gutenberg-gallery-refactor'] ),
);
return array_merge( $settings, $experiments_settings );
}
// This can be removed when plugin support requires WordPress 5.8.0+.
if ( function_exists( 'get_block_editor_settings' ) ) {
add_filter( 'block_editor_settings_all', 'gutenberg_experiments_editor_settings' );
} else {
add_filter( 'block_editor_settings', 'gutenberg_experiments_editor_settings' );
}
1 change: 1 addition & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ _Properties_
- _\_\_experimentalBlockDirectory_ `boolean`: Whether the user has enabled the Block Directory
- _\_\_experimentalBlockPatterns_ `Array`: Array of objects representing the block patterns
- _\_\_experimentalBlockPatternCategories_ `Array`: Array of objects representing the block pattern categories
- _\_\_unstableGalleryWithImageBlocks_ `boolean`: Whether the user has enabled the refactored gallery block which uses InnerBlocks

### SkipToSelectedBlock

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { ReadableContentView, alignmentHelpers } from '@wordpress/components';
*/
import BlockListBlock from './block';
import BlockInsertionPoint from './insertion-point';
import Grid from './grid-item';

import styles from './block-list-item.native.scss';
import { store as blockEditorStore } from '../../store';

Expand Down Expand Up @@ -104,7 +106,7 @@ export class BlockListItem extends Component {
];
}

render() {
renderContent() {
const {
blockAlignment,
clientId,
Expand All @@ -123,10 +125,6 @@ export class BlockListItem extends Component {
contentResizeMode === 'stretch' && stretchStyle;
const { isContainerRelated } = alignmentHelpers;

if ( ! blockWidth ) {
return null;
}

return (
<ReadableContentView
align={ blockAlignment }
Expand Down Expand Up @@ -162,6 +160,34 @@ export class BlockListItem extends Component {
</ReadableContentView>
);
}

render() {
const {
gridProperties,
clientId,
parentWidth,
items,
blockWidth,
} = this.props;

if ( ! blockWidth ) {
return null;
}

if ( gridProperties ) {
return (
<Grid
numOfColumns={ gridProperties.numColumns }
tileCount={ items.length }
index={ items.indexOf( clientId ) }
maxWidth={ parentWidth }
>
{ this.renderContent() }
</Grid>
);
}
return this.renderContent();
}
}

export default compose( [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
.fullAlignmentPadding {
padding: $block-edge-to-content;
}

.gridItem {
overflow: visible;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* External dependencies
*/
import { View } from 'react-native';

/**
* Internal dependencies
*/
import styles from './block-list-item.scss';

function Grid( props ) {
/**
* Since we don't have `calc()`, we must calculate our spacings here in
* order to preserve even spacing between tiles and equal width for tiles
* in a given row.
*
* In order to ensure equal sizing of tile contents, we distribute the
* spacing such that each tile has an equal "share" of the fixed spacing. To
* keep the tiles properly aligned within their rows, we calculate the left
* and right paddings based on the tile's relative position within the row.
*
* Note: we use padding instead of margins so that the fixed spacing is
* included within the relative spacing (i.e. width percentage), and
* wrapping behavior is preserved.
*
* - The left most tile in a row must have left padding of zero.
* - The right most tile in a row must have a right padding of zero.
*
* The values of these left and right paddings are interpolated for tiles in
* between. The right padding is complementary with the left padding of the
* next tile (i.e. the right padding of [tile n] + the left padding of
* [tile n + 1] will be equal for all tiles except the last one in a given
* row).
*
*/
const { numOfColumns, children, tileCount, index, maxWidth } = props;
const lastTile = tileCount - 1;
const lastRow = Math.floor( lastTile / numOfColumns );

const row = Math.floor( index / numOfColumns );
const rowLength =
row === lastRow ? ( lastTile % numOfColumns ) + 1 : numOfColumns;

return (
<View
style={ [
{
width: maxWidth / rowLength,
},
styles.gridItem,
] }
>
{ children }
</View>
);
}

export default Grid;
10 changes: 9 additions & 1 deletion packages/block-editor/src/components/block-list/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const getStyles = (
const computedStyles = [
isStackedHorizontally && styles.horizontal,
horizontalAlignment && styles[ `is-aligned-${ horizontalAlignment }` ],
styles.overflowVisible,
];
stylesMemo[ styleName ] = computedStyles;
return computedStyles;
Expand Down Expand Up @@ -128,6 +129,7 @@ export class BlockList extends Component {
onDeleteBlock,
contentStyle,
renderAppender,
gridProperties,
} = this.props;
const { blockWidth } = this.state;
if (
Expand All @@ -136,7 +138,8 @@ export class BlockList extends Component {
this.extraData.onDeleteBlock !== onDeleteBlock ||
this.extraData.contentStyle !== contentStyle ||
this.extraData.renderAppender !== renderAppender ||
this.extraData.blockWidth !== blockWidth
this.extraData.blockWidth !== blockWidth ||
this.extraData.gridProperties !== gridProperties
) {
this.extraData = {
parentWidth,
Expand All @@ -145,6 +148,7 @@ export class BlockList extends Component {
contentStyle,
renderAppender,
blockWidth,
gridProperties,
};
}
return this.extraData;
Expand Down Expand Up @@ -312,9 +316,11 @@ export class BlockList extends Component {
onDeleteBlock,
rootClientId,
isStackedHorizontally,
blockClientIds,
parentWidth,
marginVertical = styles.defaultBlock.marginTop,
marginHorizontal = styles.defaultBlock.marginLeft,
gridProperties,
} = this.props;
const { blockWidth } = this.state;
return (
Expand All @@ -333,6 +339,8 @@ export class BlockList extends Component {
this.shouldShowInnerBlockAppender
}
blockWidth={ blockWidth }
gridProperties={ gridProperties }
items={ blockClientIds }
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
index: getBlockIndex( clientId, rootClientId ),
mode: getBlockMode( clientId ),
name: blockName,
blockTitle: blockType.title,
blockTitle: blockType?.title,
isPartOfSelection: isSelected || isPartOfMultiSelection,
adjustScrolling:
isSelected || isFirstMultiSelectedBlock( clientId ),
enableAnimation:
! isTyping() &&
getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD,
lightBlockWrapper:
blockType.apiVersion > 1 ||
blockType?.apiVersion > 1 ||
hasBlockSupport( blockType, 'lightBlockWrapper', false ),
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ export function useBlockCustomClassName( clientId ) {
const { getBlockName, getBlockAttributes } = select(
blockEditorStore
);
const { className } = getBlockAttributes( clientId );
const attributes = getBlockAttributes( clientId );

if ( ! className ) {
if ( ! attributes?.className ) {
return;
}

Expand All @@ -40,7 +40,7 @@ export function useBlockCustomClassName( clientId ) {
return;
}

return className;
return attributes.className;
},
[ clientId ]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function useBlockDefaultClassName( clientId ) {
const name = select( blockEditorStore ).getBlockName( clientId );
const blockType = getBlockType( name );
const hasLightBlockWrapper =
blockType.apiVersion > 1 ||
blockType?.apiVersion > 1 ||
hasBlockSupport( blockType, 'lightBlockWrapper', false );

if ( ! hasLightBlockWrapper ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function StylePreview( { onPress, isActive, style, url } ) {
return (
<Animated.View
style={ [ outlineStyle, { opacity }, styles[ name ] ] }
key={ outlineStyle.borderColor }
key={ JSON.stringify( outlineStyle ) }
/>
);
} );
Expand Down
5 changes: 4 additions & 1 deletion packages/block-editor/src/components/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export * from './colors';
export * from './gradients';
export * from './font-sizes';
export { AlignmentControl, AlignmentToolbar } from './alignment-control';
export { default as InnerBlocks } from './inner-blocks';
export {
default as InnerBlocks,
useInnerBlocksProps as __experimentalUseInnerBlocksProps,
} from './inner-blocks';
export { default as InspectorAdvancedControls } from './inspector-advanced-controls';
export { default as InspectorControls } from './inspector-controls';
export {
Expand Down
41 changes: 41 additions & 0 deletions packages/block-editor/src/components/inner-blocks/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { useSelect } from '@wordpress/data';
import { getBlockType, withBlockContentContext } from '@wordpress/blocks';
import { useRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -23,6 +24,44 @@ import { BlockContextProvider } from '../block-context';
import { defaultLayout, LayoutProvider } from '../block-list/layout';
import { store as blockEditorStore } from '../../store';

/**
* This hook is used to lightly mark an element as an inner blocks wrapper
* element. Call this hook and pass the returned props to the element to mark as
* an inner blocks wrapper, automatically rendering inner blocks as children. If
* you define a ref for the element, it is important to pass the ref to this
* hook, which the hook in turn will pass to the component through the props it
* returns. Optionally, you can also pass any other props through this hook, and
* they will be merged and returned.
*
* @param {Object} props Optional. Props to pass to the element. Must contain
* the ref if one is defined.
* @param {Object} options Optional. Inner blocks options.
*
* @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/inner-blocks/README.md
*/
export function useInnerBlocksProps( props = {}, options = {} ) {
const fallbackRef = useRef();
const { clientId } = useBlockEditContext();

const ref = props.ref || fallbackRef;
const InnerBlocks =
options.value && options.onChange
? ControlledInnerBlocks
: UncontrolledInnerBlocks;

return {
...props,
ref,
children: (
<InnerBlocks
{ ...options }
clientId={ clientId }
wrapperRef={ ref }
/>
),
};
}

/**
* InnerBlocks is a component which allows a single block to have multiple blocks
* as children. The UncontrolledInnerBlocks component is used whenever the inner
Expand Down Expand Up @@ -53,6 +92,7 @@ function UncontrolledInnerBlocks( props ) {
filterInnerBlocks,
blockWidth,
__experimentalLayout: layout = defaultLayout,
gridProperties,
} = props;

const block = useSelect(
Expand Down Expand Up @@ -86,6 +126,7 @@ function UncontrolledInnerBlocks( props ) {
onAddBlock={ onAddBlock }
onDeleteBlock={ onDeleteBlock }
filterInnerBlocks={ filterInnerBlocks }
gridProperties={ gridProperties }
blockWidth={ blockWidth }
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ Callback called when urls can be configured. No media insertion from url will be
- Required: No
- Platform: Web

### handleUpload

When set to false the handling of the upload is left to the calling component.

- Type: `Boolean`
- Required: No
- Default: `true`
- Platform: Web

## Extend

It includes a `wp.hooks` filter `editor.MediaPlaceholder` that enables developers to replace or extend it.
Expand Down
Loading

0 comments on commit 3e645c4

Please sign in to comment.