diff --git a/packages/block-editor/src/components/block-list/index.native.js b/packages/block-editor/src/components/block-list/index.native.js
index c60163cf9a3bee..71bdf217f1b50a 100644
--- a/packages/block-editor/src/components/block-list/index.native.js
+++ b/packages/block-editor/src/components/block-list/index.native.js
@@ -35,9 +35,10 @@ const stylesMemo = {};
const getStyles = (
isRootList,
isStackedHorizontally,
- horizontalAlignment
+ horizontalAlignment,
+ numColumns
) => {
- if ( isRootList ) {
+ if ( isRootList || numColumns ) {
return;
}
const styleName = `${ isStackedHorizontally }-${ horizontalAlignment }`;
@@ -206,7 +207,9 @@ export class BlockList extends Component {
isStackedHorizontally,
horizontalAlignment,
contentResizeMode,
+ // eslint-disable-next-line no-unused-vars
blockWidth,
+ numColumns,
} = this.props;
const { parentScrollRef } = extraProps;
@@ -224,8 +227,11 @@ export class BlockList extends Component {
marginHorizontal: isRootList ? 0 : -marginHorizontal,
};
+ // eslint-disable-next-line no-unused-vars
const isContentStretch = contentResizeMode === 'stretch';
+ // eslint-disable-next-line no-unused-vars
const isMultiBlocks = blockClientIds.length > 1;
+ // eslint-disable-next-line no-unused-vars
const { isWider } = alignmentHelpers;
return (
@@ -260,21 +266,20 @@ export class BlockList extends Component {
horizontal={ horizontal }
extraData={ this.getExtraData() }
scrollEnabled={ isRootList }
- contentContainerStyle={ [
- horizontal && styles.horizontalContentContainer,
- isWider( blockWidth, 'medium' ) &&
- ( isContentStretch && isMultiBlocks
- ? styles.horizontalContentContainerStretch
- : styles.horizontalContentContainerCenter ),
- ] }
+ contentContainerStyle={
+ horizontal && styles.horizontalContentContainer
+ }
style={ getStyles(
isRootList,
isStackedHorizontally,
- horizontalAlignment
+ horizontalAlignment,
+ numColumns
) }
data={ blockClientIds }
keyExtractor={ identity }
renderItem={ this.renderItem }
+ numColumns={ numColumns }
+ key={ numColumns }
shouldPreventAutomaticScroll={
this.shouldFlatListPreventAutomaticScroll
}
@@ -316,22 +321,24 @@ export class BlockList extends Component {
} = this.props;
const { blockWidth } = this.state;
return (
-
+
+
+
);
}
diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js
index 29449bb0a0843d..099ee78bfee765 100644
--- a/packages/block-editor/src/components/index.native.js
+++ b/packages/block-editor/src/components/index.native.js
@@ -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 {
diff --git a/packages/block-editor/src/components/inner-blocks/index.native.js b/packages/block-editor/src/components/inner-blocks/index.native.js
index 0b9401425e8640..50297a561853a9 100644
--- a/packages/block-editor/src/components/inner-blocks/index.native.js
+++ b/packages/block-editor/src/components/inner-blocks/index.native.js
@@ -3,6 +3,7 @@
*/
import { useSelect } from '@wordpress/data';
import { getBlockType, withBlockContentContext } from '@wordpress/blocks';
+import { useRef } from '@wordpress/element';
/**
* Internal dependencies
@@ -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 is a component which allows a single block to have multiple blocks
* as children. The UncontrolledInnerBlocks component is used whenever the inner
@@ -53,6 +92,7 @@ function UncontrolledInnerBlocks( props ) {
filterInnerBlocks,
blockWidth,
__experimentalLayout: layout = defaultLayout,
+ numColumns,
} = props;
const block = useSelect(
@@ -87,6 +127,7 @@ function UncontrolledInnerBlocks( props ) {
onDeleteBlock={ onDeleteBlock }
filterInnerBlocks={ filterInnerBlocks }
blockWidth={ blockWidth }
+ numColumns={ numColumns }
/>
);
diff --git a/packages/block-editor/src/components/media-placeholder/index.native.js b/packages/block-editor/src/components/media-placeholder/index.native.js
index 1193b8a4122d4e..5b1c588c54e02b 100644
--- a/packages/block-editor/src/components/media-placeholder/index.native.js
+++ b/packages/block-editor/src/components/media-placeholder/index.native.js
@@ -38,6 +38,7 @@ function MediaPlaceholder( props ) {
labels = {},
icon,
onSelect,
+ onFocus,
__experimentalOnlyMediaLibrary,
isAppender,
disableMediaButtons,
@@ -171,7 +172,7 @@ function MediaPlaceholder( props ) {
accessibilityRole={ 'button' }
accessibilityHint={ accessibilityHint }
onPress={ ( event ) => {
- props.onFocus( event );
+ onFocus?.( event );
open();
} }
>
diff --git a/packages/block-editor/src/store/defaults.native.js b/packages/block-editor/src/store/defaults.native.js
index 125ee6c85c1f42..bbafc0f71ac7da 100644
--- a/packages/block-editor/src/store/defaults.native.js
+++ b/packages/block-editor/src/store/defaults.native.js
@@ -8,6 +8,8 @@ import {
const SETTINGS_DEFAULTS = {
...SETTINGS,
+ // eslint-disable-next-line no-undef
+ __experimentalGalleryRefactor: __DEV__,
alignWide: true,
};
diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index 83c9a1970dcbaf..2e0e82f767f285 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -9,12 +9,14 @@ import { concat, find } from 'lodash';
*/
import { compose } from '@wordpress/compose';
import {
+ // eslint-disable-next-line no-unused-vars
BaseControl,
PanelBody,
SelectControl,
ToggleControl,
withNotices,
RangeControl,
+ // eslint-disable-next-line no-unused-vars
Spinner,
} from '@wordpress/components';
import {
@@ -490,7 +492,7 @@ function GalleryEdit( props ) {
hideCancelButton={ true }
/>
) }
- { ! imageSizeOptions && (
+ { /* { ! imageSizeOptions && (
{ __( 'Image size' ) }
@@ -500,7 +502,7 @@ function GalleryEdit( props ) {
{ __( 'Loading options…' ) }
- ) }
+ ) } */ }
{ noticeUI }
diff --git a/packages/block-library/src/gallery/gallery-styles.native.scss b/packages/block-library/src/gallery/gallery-styles.native.scss
new file mode 100644
index 00000000000000..ea986c8a573ccf
--- /dev/null
+++ b/packages/block-library/src/gallery/gallery-styles.native.scss
@@ -0,0 +1,5 @@
+@import "./v1/gallery-styles.native.scss";
+
+.galleryAppender {
+ padding-top: 16px;
+}
diff --git a/packages/block-library/src/gallery/gallery.native.js b/packages/block-library/src/gallery/gallery.native.js
new file mode 100644
index 00000000000000..092308b0e18ccd
--- /dev/null
+++ b/packages/block-library/src/gallery/gallery.native.js
@@ -0,0 +1,112 @@
+/**
+ * External dependencies
+ */
+import { View } from 'react-native';
+import { isEmpty } from 'lodash';
+
+/**
+ * Internal dependencies
+ */
+import { defaultColumnsNumber } from './shared';
+import styles from './gallery-styles.scss';
+
+/**
+ * WordPress dependencies
+ */
+import { __, sprintf } from '@wordpress/i18n';
+import {
+ BlockCaption,
+ __experimentalUseInnerBlocksProps as useInnerBlocksProps,
+} from '@wordpress/block-editor';
+import { useState, useEffect } from '@wordpress/element';
+import { mediaUploadSync } from '@wordpress/react-native-bridge';
+import { WIDE_ALIGNMENTS } from '@wordpress/components';
+
+const TILE_SPACING = 8;
+
+// we must limit displayed columns since readable content max-width is 580px
+const MAX_DISPLAYED_COLUMNS = 4;
+const MAX_DISPLAYED_COLUMNS_NARROW = 2;
+
+export const Gallery = ( props ) => {
+ const [ isCaptionSelected, setIsCaptionSelected ] = useState( false );
+ useEffect( mediaUploadSync, [] );
+
+ const {
+ mediaPlaceholder,
+ attributes,
+ isNarrow,
+ onBlur,
+ insertBlocksAfter,
+ clientId,
+ } = props;
+
+ const {
+ imageCount,
+ align,
+ columns = defaultColumnsNumber( imageCount ),
+ // eslint-disable-next-line no-unused-vars
+ imageCrop,
+ } = attributes;
+
+ const displayedColumns = Math.min(
+ columns,
+ isNarrow ? MAX_DISPLAYED_COLUMNS_NARROW : MAX_DISPLAYED_COLUMNS
+ );
+
+ const innerBlocksProps = useInnerBlocksProps(
+ {},
+ {
+ contentResizeMode: 'stretch',
+ allowedBlocks: [ 'core/image' ],
+ orientation: 'horizontal',
+ renderAppender: false,
+ numColumns: displayedColumns,
+ marginHorizontal: TILE_SPACING,
+ marginVertical: TILE_SPACING,
+ }
+ );
+
+ const focusGalleryCaption = () => {
+ if ( ! isCaptionSelected ) {
+ setIsCaptionSelected( true );
+ }
+ };
+
+ const isFullWidth = align === WIDE_ALIGNMENTS.alignments.full;
+
+ return (
+
+
+
+ { mediaPlaceholder }
+
+
+ isEmpty( caption )
+ ? /* translators: accessibility text. Empty gallery caption. */
+
+ 'Gallery caption. Empty'
+ : sprintf(
+ /* translators: accessibility text. %s: gallery caption. */
+ __( 'Gallery caption. %s' ),
+ caption
+ )
+ }
+ onFocus={ focusGalleryCaption }
+ onBlur={ onBlur } // always assign onBlur as props
+ insertBlocksAfter={ insertBlocksAfter }
+ />
+
+ );
+};
+
+export default Gallery;