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;