diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 322f0873c83049..6b9af74d03a3ab 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -780,7 +780,6 @@ _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 diff --git a/packages/block-editor/src/store/defaults.js b/packages/block-editor/src/store/defaults.js index acd40244cb2604..54877eafc36901 100644 --- a/packages/block-editor/src/store/defaults.js +++ b/packages/block-editor/src/store/defaults.js @@ -33,7 +33,6 @@ export const PREFERENCES_DEFAULTS = { * @property {boolean} __experimentalBlockDirectory Whether the user has enabled the Block Directory * @property {Array} __experimentalBlockPatterns Array of objects representing the block patterns * @property {Array} __experimentalBlockPatternCategories Array of objects representing the block pattern categories - * @property {boolean} __unstableGalleryWithImageBlocks Whether the user has enabled the refactored gallery block which uses InnerBlocks */ export const SETTINGS_DEFAULTS = { alignWide: false, @@ -168,7 +167,6 @@ export const SETTINGS_DEFAULTS = { __mobileEnablePageTemplates: false, __experimentalBlockPatterns: [], __experimentalBlockPatternCategories: [], - __unstableGalleryWithImageBlocks: false, __unstableIsPreviewMode: false, // These settings will be completely revamped in the future. diff --git a/packages/block-editor/src/store/defaults.native.js b/packages/block-editor/src/store/defaults.native.js index fddf7cdb647b97..e951c39b3d1a41 100644 --- a/packages/block-editor/src/store/defaults.native.js +++ b/packages/block-editor/src/store/defaults.native.js @@ -10,9 +10,6 @@ const SETTINGS_DEFAULTS = { ...SETTINGS, // Don't add the default font sizes for standard themes fontSizes: undefined, - // FOR TESTING ONLY - Later, this will come from a REST API - // eslint-disable-next-line no-undef - __unstableGalleryWithImageBlocks: __DEV__, alignWide: true, supportsLayout: false, __experimentalFeatures: { diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js index 722890c0de0133..c2d3778d463f8a 100644 --- a/packages/block-library/src/gallery/deprecated.js +++ b/packages/block-library/src/gallery/deprecated.js @@ -22,7 +22,6 @@ import { LINK_DESTINATION_MEDIA, LINK_DESTINATION_NONE, } from './constants'; -import { isGalleryV2Enabled } from './shared'; const DEPRECATED_LINK_DESTINATION_MEDIA = 'file'; const DEPRECATED_LINK_DESTINATION_ATTACHMENT = 'post'; @@ -408,11 +407,7 @@ const v6 = { ); }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - - return attributes; + return runV2Migration( attributes ); }, }; const v5 = { @@ -498,23 +493,7 @@ const v5 = { return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - - let linkTo = attributes.linkTo; - - if ( ! attributes.linkTo ) { - linkTo = 'none'; - } else if ( attributes.linkTo === 'attachment' ) { - linkTo = 'post'; - } else if ( attributes.linkTo === 'media' ) { - linkTo = 'file'; - } - return { - ...attributes, - linkTo, - }; + return runV2Migration( attributes ); }, save( { attributes } ) { const { @@ -661,17 +640,7 @@ const v4 = { return ids && ids.some( ( id ) => typeof id === 'string' ); }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - - return { - ...attributes, - ids: ( attributes.ids ?? [] ).map( ( id ) => { - const parsedId = parseInt( id, 10 ); - return Number.isInteger( parsedId ) ? parsedId : null; - } ), - }; + return runV2Migration( attributes ); }, save( { attributes } ) { const { @@ -867,10 +836,7 @@ const v3 = { ); }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - return attributes; + return runV2Migration( attributes ); }, }; const v2 = { @@ -936,18 +902,7 @@ const v2 = { ); }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - return { - ...attributes, - ids: ( attributes.images ?? [] ).map( ( { id } ) => { - if ( ! id ) { - return null; - } - return parseInt( id, 10 ); - } ), - }; + return runV2Migration( attributes ); }, supports: { align: true, @@ -1100,11 +1055,7 @@ const v1 = { ); }, migrate( attributes ) { - if ( isGalleryV2Enabled() ) { - return runV2Migration( attributes ); - } - - return attributes; + return runV2Migration( attributes ); }, }; diff --git a/packages/block-library/src/gallery/edit-wrapper.js b/packages/block-library/src/gallery/edit-wrapper.js deleted file mode 100644 index 2c81271902d312..00000000000000 --- a/packages/block-library/src/gallery/edit-wrapper.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * WordPress dependencies - */ -import { compose } from '@wordpress/compose'; -import { withNotices } from '@wordpress/components'; - -/** - * Internal dependencies - */ -import EditWithInnerBlocks from './edit'; -import EditWithoutInnerBlocks from './v1/edit'; -import { isGalleryV2Enabled } from './shared'; - -/* - * Using a wrapper around the logic to load the edit for v1 of Gallery block - * or the refactored version with InnerBlocks. This is to prevent conditional - * use of hooks lint errors if adding this logic to the top of the edit component. - */ -function GalleryEditWrapper( props ) { - if ( ! isGalleryV2Enabled() ) { - return ; - } - - return ; -} - -export default compose( [ withNotices ] )( GalleryEditWrapper ); diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 1191968032a7b5..e853e20f23319c 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -14,6 +14,7 @@ import { ToggleControl, RangeControl, Spinner, + withNotices, } from '@wordpress/components'; import { store as blockEditorStore, @@ -633,6 +634,7 @@ function GalleryEdit( props ) { ); } -export default compose( [ withViewportMatch( { isNarrow: '< small' } ) ] )( - GalleryEdit -); +export default compose( [ + withNotices, + withViewportMatch( { isNarrow: '< small' } ), +] )( GalleryEdit ); diff --git a/packages/block-library/src/gallery/gallery-styles.native.scss b/packages/block-library/src/gallery/gallery-styles.native.scss index a3073592291b93..f9b4d63c55b815 100644 --- a/packages/block-library/src/gallery/gallery-styles.native.scss +++ b/packages/block-library/src/gallery/gallery-styles.native.scss @@ -1,5 +1,3 @@ -@import "./v1/gallery-styles.native.scss"; - .galleryAppender { padding-top: $grid-unit-20; } diff --git a/packages/block-library/src/gallery/index.js b/packages/block-library/src/gallery/index.js index f865072526098b..65a2cee3c5fec2 100644 --- a/packages/block-library/src/gallery/index.js +++ b/packages/block-library/src/gallery/index.js @@ -8,7 +8,7 @@ import { gallery as icon } from '@wordpress/icons'; */ import initBlock from '../utils/init-block'; import deprecated from './deprecated'; -import edit from './edit-wrapper'; +import edit from './edit'; import metadata from './block.json'; import save from './save'; import transforms from './transforms'; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index c57f8ef3b73506..cd8d35444285c9 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -13,17 +13,7 @@ import { __experimentalGetElementClassName, } from '@wordpress/block-editor'; -/** - * Internal dependencies - */ -import saveWithoutInnerBlocks from './v1/save'; -import { isGalleryV2Enabled } from './shared'; - export default function saveWithInnerBlocks( { attributes } ) { - if ( ! isGalleryV2Enabled() ) { - return saveWithoutInnerBlocks( { attributes } ); - } - const { caption, columns, imageCrop } = attributes; const className = clsx( 'has-nested-images', { diff --git a/packages/block-library/src/gallery/shared.js b/packages/block-library/src/gallery/shared.js index 18fce746a79885..f904a9e13d0d5e 100644 --- a/packages/block-library/src/gallery/shared.js +++ b/packages/block-library/src/gallery/shared.js @@ -1,8 +1,3 @@ -/** - * WordPress dependencies - */ -import { Platform } from '@wordpress/element'; - export function defaultColumnsNumber( imageCount ) { return imageCount ? Math.min( 3, imageCount ) : 3; } @@ -27,26 +22,3 @@ export const pickRelevantMediaFiles = ( image, sizeSlug = 'large' ) => { } return imageProps; }; - -function getGalleryBlockV2Enabled() { - // We want to fail early here, at least during beta testing phase, to ensure - // there aren't instances where undefined values cause false negatives. - if ( ! window.wp || typeof window.wp.galleryBlockV2Enabled !== 'boolean' ) { - throw 'window.wp.galleryBlockV2Enabled is not defined'; - } - return window.wp.galleryBlockV2Enabled; -} - -/** - * The new gallery block format is not compatible with the use_BalanceTags option - * in WP versions <= 5.8 https://core.trac.wordpress.org/ticket/54130. The - * window.wp.galleryBlockV2Enabled flag is set in lib/compat.php. This method - * can be removed when minimum supported WP version >=5.9. - */ -export function isGalleryV2Enabled() { - if ( Platform.isNative ) { - return getGalleryBlockV2Enabled(); - } - - return true; -} diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 6e76cd93ef560d..f040fdb12fb235 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -13,7 +13,6 @@ import { LINK_DESTINATION_NONE, LINK_DESTINATION_MEDIA, } from './constants'; -import { pickRelevantMediaFiles, isGalleryV2Enabled } from './shared'; const parseShortcodeIds = ( ids ) => { if ( ! ids ) { @@ -39,7 +38,6 @@ const parseShortcodeIds = ( ids ) => { */ function updateThirdPartyTransformToGallery( block ) { if ( - isGalleryV2Enabled() && block.name === 'core/gallery' && block.attributes?.images.length > 0 ) { @@ -137,37 +135,21 @@ const transforms = { const validImages = attributes.filter( ( { url } ) => url ); - if ( isGalleryV2Enabled() ) { - const innerBlocks = validImages.map( ( image ) => { - // Gallery images can't currently be resized so make sure height and width are undefined. - image.width = undefined; - image.height = undefined; - return createBlock( 'core/image', image ); - } ); - - return createBlock( - 'core/gallery', - { - align, - sizeSlug, - }, - innerBlocks - ); - } - - return createBlock( 'core/gallery', { - images: validImages.map( - ( { id, url, alt, caption } ) => ( { - id: id.toString(), - url, - alt, - caption, - } ) - ), - ids: validImages.map( ( { id } ) => parseInt( id, 10 ) ), - align, - sizeSlug, + const innerBlocks = validImages.map( ( image ) => { + // Gallery images can't currently be resized so make sure height and width are undefined. + image.width = undefined; + image.height = undefined; + return createBlock( 'core/image', image ); } ); + + return createBlock( + 'core/gallery', + { + align, + sizeSlug, + }, + innerBlocks + ); }, }, { @@ -220,23 +202,13 @@ const transforms = { ); }, transform( files ) { - if ( isGalleryV2Enabled() ) { - const innerBlocks = files.map( ( file ) => - createBlock( 'core/image', { - blob: createBlobURL( file ), - } ) - ); + const innerBlocks = files.map( ( file ) => + createBlock( 'core/image', { + blob: createBlobURL( file ), + } ) + ); - return createBlock( 'core/gallery', {}, innerBlocks ); - } - const block = createBlock( 'core/gallery', { - images: files.map( ( file ) => - pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ) - ), - } ); - return block; + return createBlock( 'core/gallery', {}, innerBlocks ); }, }, ], @@ -244,57 +216,42 @@ const transforms = { { type: 'block', blocks: [ 'core/image' ], - transform: ( { align, images, ids, sizeSlug }, innerBlocks ) => { - if ( isGalleryV2Enabled() ) { - if ( innerBlocks.length > 0 ) { - return innerBlocks.map( - ( { - attributes: { - url, - alt, - caption, - title, - href, - rel, - linkClass, - id, - sizeSlug: imageSizeSlug, - linkDestination, - linkTarget, - anchor, - className, - }, - } ) => - createBlock( 'core/image', { - align, - url, - alt, - caption, - title, - href, - rel, - linkClass, - id, - sizeSlug: imageSizeSlug, - linkDestination, - linkTarget, - anchor, - className, - } ) - ); - } - return createBlock( 'core/image', { align } ); - } - if ( images.length > 0 ) { - return images.map( ( { url, alt, caption }, index ) => - createBlock( 'core/image', { - id: ids[ index ], - url, - alt, - caption, - align, - sizeSlug, - } ) + transform: ( { align }, innerBlocks ) => { + if ( innerBlocks.length > 0 ) { + return innerBlocks.map( + ( { + attributes: { + url, + alt, + caption, + title, + href, + rel, + linkClass, + id, + sizeSlug: imageSizeSlug, + linkDestination, + linkTarget, + anchor, + className, + }, + } ) => + createBlock( 'core/image', { + align, + url, + alt, + caption, + title, + href, + rel, + linkClass, + id, + sizeSlug: imageSizeSlug, + linkDestination, + linkTarget, + anchor, + className, + } ) ); } return createBlock( 'core/image', { align } ); diff --git a/packages/block-library/src/gallery/v1/constants.js b/packages/block-library/src/gallery/v1/constants.js deleted file mode 100644 index f4b6e7af56d473..00000000000000 --- a/packages/block-library/src/gallery/v1/constants.js +++ /dev/null @@ -1,3 +0,0 @@ -export const LINK_DESTINATION_NONE = 'none'; -export const LINK_DESTINATION_MEDIA = 'file'; -export const LINK_DESTINATION_ATTACHMENT = 'post'; diff --git a/packages/block-library/src/gallery/v1/edit.js b/packages/block-library/src/gallery/v1/edit.js deleted file mode 100644 index 6793a901dc7c54..00000000000000 --- a/packages/block-library/src/gallery/v1/edit.js +++ /dev/null @@ -1,450 +0,0 @@ -/** - * WordPress dependencies - */ -import { compose } from '@wordpress/compose'; -import { - PanelBody, - SelectControl, - ToggleControl, - withNotices, - RangeControl, -} from '@wordpress/components'; -import { - MediaPlaceholder, - InspectorControls, - useBlockProps, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { Platform, useEffect, useState, useMemo } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; -import { useDispatch, useSelect } from '@wordpress/data'; -import { withViewportMatch } from '@wordpress/viewport'; -import { View } from '@wordpress/primitives'; -import { store as coreStore } from '@wordpress/core-data'; - -/** - * Internal dependencies - */ -import { sharedIcon } from '../shared-icon'; -import { pickRelevantMediaFiles } from './shared'; -import { defaultColumnsNumberV1 } from '../deprecated'; -import Gallery from './gallery'; -import { - LINK_DESTINATION_ATTACHMENT, - LINK_DESTINATION_MEDIA, - LINK_DESTINATION_NONE, -} from './constants'; - -const MAX_COLUMNS = 8; -const linkOptions = [ - { value: LINK_DESTINATION_ATTACHMENT, label: __( 'Attachment Page' ) }, - { value: LINK_DESTINATION_MEDIA, label: __( 'Media File' ) }, - { value: LINK_DESTINATION_NONE, label: __( 'None' ) }, -]; -const ALLOWED_MEDIA_TYPES = [ 'image' ]; - -const PLACEHOLDER_TEXT = Platform.select( { - web: __( - 'Drag images, upload new ones or select files from your library.' - ), - native: __( 'ADD MEDIA' ), -} ); - -const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { - web: {}, - native: { type: 'stepper' }, -} ); - -function GalleryEdit( props ) { - const { - attributes, - clientId, - isSelected, - noticeUI, - noticeOperations, - onFocus, - } = props; - const { - columns = defaultColumnsNumberV1( attributes ), - imageCrop, - images, - linkTo, - sizeSlug, - } = attributes; - const [ selectedImage, setSelectedImage ] = useState(); - const [ attachmentCaptions, setAttachmentCaptions ] = useState(); - const { __unstableMarkNextChangeAsNotPersistent } = - useDispatch( blockEditorStore ); - - const { imageSizes, mediaUpload, getMedia, wasBlockJustInserted } = - useSelect( ( select ) => { - const settings = select( blockEditorStore ).getSettings(); - - return { - imageSizes: settings.imageSizes, - mediaUpload: settings.mediaUpload, - getMedia: select( coreStore ).getMedia, - wasBlockJustInserted: select( - blockEditorStore - ).wasBlockJustInserted( clientId, 'inserter_menu' ), - }; - } ); - - const resizedImages = useMemo( () => { - if ( isSelected ) { - return ( attributes.ids ?? [] ).reduce( - ( currentResizedImages, id ) => { - if ( ! id ) { - return currentResizedImages; - } - const image = getMedia( id ); - const sizes = imageSizes.reduce( ( currentSizes, size ) => { - const defaultUrl = image?.sizes?.[ size.slug ]?.url; - const mediaDetailsUrl = - image?.media_details?.sizes?.[ size.slug ] - ?.source_url; - return { - ...currentSizes, - [ size.slug ]: defaultUrl || mediaDetailsUrl, - }; - }, {} ); - return { - ...currentResizedImages, - [ parseInt( id, 10 ) ]: sizes, - }; - }, - {} - ); - } - return {}; - }, [ isSelected, attributes.ids, imageSizes ] ); - - function onFocusGalleryCaption() { - setSelectedImage(); - } - - function setAttributes( newAttrs ) { - if ( newAttrs.ids ) { - throw new Error( - 'The "ids" attribute should not be changed directly. It is managed automatically when "images" attribute changes' - ); - } - - if ( newAttrs.images ) { - newAttrs = { - ...newAttrs, - // Unlike images[ n ].id which is a string, always ensure the - // ids array contains numbers as per its attribute type. - ids: newAttrs.images.map( ( { id } ) => parseInt( id, 10 ) ), - }; - } - - props.setAttributes( newAttrs ); - } - - function onSelectImage( index ) { - return () => { - setSelectedImage( index ); - }; - } - - function onDeselectImage() { - return () => { - setSelectedImage(); - }; - } - - function onMove( oldIndex, newIndex ) { - const newImages = [ ...images ]; - newImages.splice( newIndex, 1, images[ oldIndex ] ); - newImages.splice( oldIndex, 1, images[ newIndex ] ); - setSelectedImage( newIndex ); - setAttributes( { images: newImages } ); - } - - function onMoveForward( oldIndex ) { - return () => { - if ( oldIndex === images.length - 1 ) { - return; - } - onMove( oldIndex, oldIndex + 1 ); - }; - } - - function onMoveBackward( oldIndex ) { - return () => { - if ( oldIndex === 0 ) { - return; - } - onMove( oldIndex, oldIndex - 1 ); - }; - } - - function onRemoveImage( index ) { - return () => { - const newImages = images.filter( ( img, i ) => index !== i ); - setSelectedImage(); - setAttributes( { - images: newImages, - columns: attributes.columns - ? Math.min( newImages.length, attributes.columns ) - : attributes.columns, - } ); - }; - } - - function selectCaption( newImage ) { - // The image id in both the images and attachmentCaptions arrays is a - // string, so ensure comparison works correctly by converting the - // newImage.id to a string. - const newImageId = newImage.id.toString(); - const currentImage = images.find( ( { id } ) => id === newImageId ); - const currentImageCaption = currentImage - ? currentImage.caption - : newImage.caption; - - if ( ! attachmentCaptions ) { - return currentImageCaption; - } - - const attachment = attachmentCaptions.find( - ( { id } ) => id === newImageId - ); - - // If the attachment caption is updated. - if ( attachment && attachment.caption !== newImage.caption ) { - return newImage.caption; - } - - return currentImageCaption; - } - - function onSelectImages( newImages ) { - setAttachmentCaptions( - newImages.map( ( newImage ) => ( { - // Store the attachmentCaption id as a string for consistency - // with the type of the id in the images attribute. - id: newImage.id.toString(), - caption: newImage.caption, - } ) ) - ); - setAttributes( { - images: newImages.map( ( newImage ) => ( { - ...pickRelevantMediaFiles( newImage, sizeSlug ), - caption: selectCaption( newImage, images, attachmentCaptions ), - // The id value is stored in a data attribute, so when the - // block is parsed it's converted to a string. Converting - // to a string here ensures it's type is consistent. - id: newImage.id.toString(), - } ) ), - columns: attributes.columns - ? Math.min( newImages.length, attributes.columns ) - : attributes.columns, - } ); - } - - function onUploadError( message ) { - noticeOperations.removeAllNotices(); - noticeOperations.createErrorNotice( message ); - } - - function setLinkTo( value ) { - setAttributes( { linkTo: value } ); - } - - function setColumnsNumber( value ) { - setAttributes( { columns: value } ); - } - - function toggleImageCrop() { - setAttributes( { imageCrop: ! imageCrop } ); - } - - function getImageCropHelp( checked ) { - return checked - ? __( 'Thumbnails are cropped to align.' ) - : __( 'Thumbnails are not cropped.' ); - } - - function setImageAttributes( index, newAttributes ) { - if ( ! images[ index ] ) { - return; - } - - setAttributes( { - images: [ - ...images.slice( 0, index ), - { - ...images[ index ], - ...newAttributes, - }, - ...images.slice( index + 1 ), - ], - } ); - } - - function getImagesSizeOptions() { - const resizedImageSizes = Object.values( resizedImages ); - return imageSizes - .filter( ( { slug } ) => - resizedImageSizes.some( ( sizes ) => sizes[ slug ] ) - ) - .map( ( { name, slug } ) => ( { value: slug, label: name } ) ); - } - - function updateImagesSize( newSizeSlug ) { - const updatedImages = ( images ?? [] ).map( ( image ) => { - if ( ! image.id ) { - return image; - } - const url = - resizedImages[ parseInt( image.id, 10 ) ]?.[ newSizeSlug ]; - return { - ...image, - ...( url && { url } ), - }; - } ); - - setAttributes( { images: updatedImages, sizeSlug: newSizeSlug } ); - } - - useEffect( () => { - if ( - Platform.OS === 'web' && - images && - images.length > 0 && - images.every( ( { url } ) => isBlobURL( url ) ) - ) { - const filesList = images.map( ( { url } ) => getBlobByURL( url ) ); - images.forEach( ( { url } ) => revokeBlobURL( url ) ); - mediaUpload( { - filesList, - onFileChange: onSelectImages, - allowedTypes: [ 'image' ], - } ); - } - }, [] ); - - useEffect( () => { - // Deselect images when deselecting the block. - if ( ! isSelected ) { - setSelectedImage(); - } - }, [ isSelected ] ); - - useEffect( () => { - // linkTo attribute must be saved so blocks don't break when changing - // image_default_link_type in options.php. - if ( ! linkTo ) { - __unstableMarkNextChangeAsNotPersistent(); - setAttributes( { - linkTo: - window?.wp?.media?.view?.settings?.defaultProps?.link || - LINK_DESTINATION_NONE, - } ); - } - }, [ linkTo ] ); - - const hasImages = !! images.length; - const hasImageIds = hasImages && images.some( ( image ) => !! image.id ); - - const mediaPlaceholder = ( - - ); - - const blockProps = useBlockProps(); - - if ( ! hasImages ) { - return { mediaPlaceholder }; - } - - const imageSizeOptions = getImagesSizeOptions(); - const shouldShowSizeOptions = hasImages && imageSizeOptions.length > 0; - - return ( - <> - - - { images.length > 1 && ( - - ) } - - - { shouldShowSizeOptions && ( - - ) } - - - { noticeUI } - - - ); -} - -export default compose( [ - withNotices, - withViewportMatch( { isNarrow: '< small' } ), -] )( GalleryEdit ); diff --git a/packages/block-library/src/gallery/v1/gallery-button.native.js b/packages/block-library/src/gallery/v1/gallery-button.native.js deleted file mode 100644 index 4dc9abd9753ee4..00000000000000 --- a/packages/block-library/src/gallery/v1/gallery-button.native.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * External dependencies - */ -import { StyleSheet, TouchableOpacity } from 'react-native'; - -/** - * WordPress dependencies - */ -import { Icon } from '@wordpress/components'; - -/** - * Internal dependencies - */ -import style from './gallery-image-style.scss'; - -export function Button( props ) { - const { - icon, - iconSize = 24, - onClick, - disabled, - 'aria-disabled': ariaDisabled, - accessibilityLabel = 'button', - style: customStyle, - } = props; - - const buttonStyle = StyleSheet.compose( style.buttonActive, customStyle ); - - const isDisabled = disabled || ariaDisabled; - - const { fill } = isDisabled ? style.buttonDisabled : style.button; - - return ( - - - - ); -} - -export default Button; diff --git a/packages/block-library/src/gallery/v1/gallery-image-style.native.scss b/packages/block-library/src/gallery/v1/gallery-image-style.native.scss deleted file mode 100644 index 9b221a56981f6d..00000000000000 --- a/packages/block-library/src/gallery/v1/gallery-image-style.native.scss +++ /dev/null @@ -1,109 +0,0 @@ -$gallery-image-container-height: 150px; -$overlay-border-width: 2px; -$caption-background-color: rgba(0, 0, 0, 0.4); - -.galleryImageContainer { - flex: 1; - height: $gallery-image-container-height; - overflow: hidden; - background-color: $gray-lighten-30; -} - -.galleryImageContainerDark { - background-color: $gray-90; -} - -.image { - height: 100%; -} - -.button { - fill: $gray-0; - width: 30px; -} - -.buttonDisabled { - fill: $gray-30; -} - -.buttonActive { - flex-direction: row; - justify-content: center; - align-items: center; - border-radius: 6px; - border-color: $gray-70; - background-color: $gray-70; -} - -.moverButtonContainer { - flex-direction: row; - align-items: center; - border-radius: 3px; - background-color: $gray-70; -} - -.separator { - border-right-color: $gray-30; - border-right-width: 1px; - height: 20px; -} - -.toolbarContainer { - position: absolute; -} - -.toolbar { - padding: 5px; - flex-direction: row; - justify-content: space-between; -} - -.captionContainer { - flex: 1; - flex-direction: row; - align-items: flex-end; - position: absolute; - bottom: $overlay-border-width; - left: $overlay-border-width; - right: $overlay-border-width; - top: 45; -} - -@mixin caption-shared { - font-size: 12px; - background-color: #0000; - color: #fff; - font-family: $default-regular-font; - text-align: center; -} - -.caption { - @include caption-shared; - background-color: $caption-background-color; - padding-top: $grid-unit; - padding-bottom: $grid-unit; -} - -.captionPlaceholder { - color: #ccc; -} - -// expand caption container to compensate for overlay border -.captionExpandedContainer { - // constrain height to gallery image height for caption scroll - max-height: $gallery-image-container-height; - position: absolute; - bottom: 0; - left: 0; - right: 0; - padding-top: $grid-unit; - padding-bottom: $overlay-border-width + $grid-unit; - padding-left: $overlay-border-width; - padding-right: $overlay-border-width; - // use caption background color on container when expanded - background-color: $caption-background-color; -} - -.captionExpanded { - @include caption-shared; -} diff --git a/packages/block-library/src/gallery/v1/gallery-image.js b/packages/block-library/src/gallery/v1/gallery-image.js deleted file mode 100644 index 5384944b2335d9..00000000000000 --- a/packages/block-library/src/gallery/v1/gallery-image.js +++ /dev/null @@ -1,293 +0,0 @@ -/** - * External dependencies - */ -import clsx from 'clsx'; - -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; -import { Button, Spinner, ButtonGroup } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { BACKSPACE, DELETE } from '@wordpress/keycodes'; -import { withSelect, withDispatch } from '@wordpress/data'; -import { - RichText, - MediaPlaceholder, - store as blockEditorStore, - __experimentalGetElementClassName, -} from '@wordpress/block-editor'; -import { isBlobURL } from '@wordpress/blob'; -import { compose } from '@wordpress/compose'; -import { - closeSmall, - chevronLeft, - chevronRight, - edit, - image as imageIcon, -} from '@wordpress/icons'; -import { store as coreStore } from '@wordpress/core-data'; - -/** - * Internal dependencies - */ -import { pickRelevantMediaFiles } from './shared'; -import { - LINK_DESTINATION_ATTACHMENT, - LINK_DESTINATION_MEDIA, -} from './constants'; - -const isTemporaryImage = ( id, url ) => ! id && isBlobURL( url ); - -class GalleryImage extends Component { - constructor() { - super( ...arguments ); - - this.onSelectImage = this.onSelectImage.bind( this ); - this.onRemoveImage = this.onRemoveImage.bind( this ); - this.bindContainer = this.bindContainer.bind( this ); - this.onEdit = this.onEdit.bind( this ); - this.onSelectImageFromLibrary = - this.onSelectImageFromLibrary.bind( this ); - this.onSelectCustomURL = this.onSelectCustomURL.bind( this ); - this.state = { - isEditing: false, - }; - } - - bindContainer( ref ) { - this.container = ref; - } - - onSelectImage() { - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - } - - onRemoveImage( event ) { - if ( - this.container === this.container.ownerDocument.activeElement && - this.props.isSelected && - [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1 - ) { - event.preventDefault(); - this.props.onRemove(); - } - } - - onEdit() { - this.setState( { - isEditing: true, - } ); - } - - componentDidUpdate() { - const { image, url, __unstableMarkNextChangeAsNotPersistent } = - this.props; - if ( image && ! url ) { - __unstableMarkNextChangeAsNotPersistent(); - this.props.setAttributes( { - url: image.source_url, - alt: image.alt_text, - } ); - } - } - - deselectOnBlur() { - this.props.onDeselect(); - } - - onSelectImageFromLibrary( media ) { - const { setAttributes, id, url, alt, caption, sizeSlug } = this.props; - if ( ! media || ! media.url ) { - return; - } - - let mediaAttributes = pickRelevantMediaFiles( media, sizeSlug ); - - // If the current image is temporary but an alt text was meanwhile - // written by the user, make sure the text is not overwritten. - if ( isTemporaryImage( id, url ) ) { - if ( alt ) { - const { alt: omittedAlt, ...restMediaAttributes } = - mediaAttributes; - mediaAttributes = restMediaAttributes; - } - } - - // If a caption text was meanwhile written by the user, - // make sure the text is not overwritten by empty captions. - if ( caption && ! mediaAttributes.caption ) { - const { caption: omittedCaption, ...restMediaAttributes } = - mediaAttributes; - mediaAttributes = restMediaAttributes; - } - - setAttributes( mediaAttributes ); - this.setState( { - isEditing: false, - } ); - } - - onSelectCustomURL( newURL ) { - const { setAttributes, url } = this.props; - if ( newURL !== url ) { - setAttributes( { - url: newURL, - id: undefined, - } ); - this.setState( { - isEditing: false, - } ); - } - } - - render() { - const { - url, - alt, - id, - linkTo, - link, - isFirstItem, - isLastItem, - isSelected, - caption, - onRemove, - onMoveForward, - onMoveBackward, - setAttributes, - 'aria-label': ariaLabel, - } = this.props; - const { isEditing } = this.state; - - let href; - - switch ( linkTo ) { - case LINK_DESTINATION_MEDIA: - href = url; - break; - case LINK_DESTINATION_ATTACHMENT: - href = link; - break; - } - - const img = ( - // Disable reason: Image itself is not meant to be interactive, but should - // direct image selection and unfocus caption fields. - /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ - <> - { - { isBlobURL( url ) && } - - /* eslint-enable jsx-a11y/no-noninteractive-element-interactions */ - ); - - const className = clsx( { - 'is-selected': isSelected, - 'is-transient': isBlobURL( url ), - } ); - - return ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions -
- { ! isEditing && ( href ? { img } : img ) } - { isEditing && ( - - ) } - -
- ); - } -} - -export default compose( [ - withSelect( ( select, ownProps ) => { - const { getMedia } = select( coreStore ); - const { id } = ownProps; - - return { - image: id ? getMedia( parseInt( id, 10 ) ) : null, - }; - } ), - withDispatch( ( dispatch ) => { - const { __unstableMarkNextChangeAsNotPersistent } = - dispatch( blockEditorStore ); - return { - __unstableMarkNextChangeAsNotPersistent, - }; - } ), -] )( GalleryImage ); diff --git a/packages/block-library/src/gallery/v1/gallery-image.native.js b/packages/block-library/src/gallery/v1/gallery-image.native.js deleted file mode 100644 index fc07a209d8c6a5..00000000000000 --- a/packages/block-library/src/gallery/v1/gallery-image.native.js +++ /dev/null @@ -1,348 +0,0 @@ -/** - * External dependencies - */ -import { - StyleSheet, - View, - ScrollView, - TouchableWithoutFeedback, -} from 'react-native'; - -/** - * WordPress dependencies - */ -import { - requestImageFailedRetryDialog, - requestImageUploadCancelDialog, - requestImageFullscreenPreview, -} from '@wordpress/react-native-bridge'; -import { Component } from '@wordpress/element'; -import { Image } from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; -import { Caption, MediaUploadProgress } from '@wordpress/block-editor'; -import { getProtocol } from '@wordpress/url'; -import { withPreferredColorScheme } from '@wordpress/compose'; -import { arrowLeft, arrowRight, warning } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import Button from './gallery-button'; -import style from './gallery-image-style.scss'; - -const { compose } = StyleSheet; - -const separatorStyle = compose( style.separator, { - borderRightWidth: StyleSheet.hairlineWidth, -} ); -const buttonStyle = compose( style.button, { aspectRatio: 1 } ); -const ICON_SIZE_ARROW = 15; - -class GalleryImage extends Component { - constructor() { - super( ...arguments ); - - this.onSelectImage = this.onSelectImage.bind( this ); - this.onSelectCaption = this.onSelectCaption.bind( this ); - this.onMediaPressed = this.onMediaPressed.bind( this ); - this.onCaptionChange = this.onCaptionChange.bind( this ); - this.onSelectMedia = this.onSelectMedia.bind( this ); - - this.updateMediaProgress = this.updateMediaProgress.bind( this ); - this.finishMediaUploadWithSuccess = - this.finishMediaUploadWithSuccess.bind( this ); - this.finishMediaUploadWithFailure = - this.finishMediaUploadWithFailure.bind( this ); - this.renderContent = this.renderContent.bind( this ); - - this.state = { - captionSelected: false, - isUploadInProgress: false, - didUploadFail: false, - }; - } - - onSelectCaption() { - if ( ! this.state.captionSelected ) { - this.setState( { - captionSelected: true, - } ); - } - - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - } - - onMediaPressed() { - const { id, url, isSelected } = this.props; - const { captionSelected, isUploadInProgress, didUploadFail } = - this.state; - - this.onSelectImage(); - - if ( isUploadInProgress ) { - requestImageUploadCancelDialog( id ); - } else if ( - didUploadFail || - ( id && getProtocol( url ) === 'file:' ) - ) { - requestImageFailedRetryDialog( id ); - } else if ( isSelected && ! captionSelected ) { - requestImageFullscreenPreview( url ); - } - } - - onSelectImage() { - if ( ! this.props.isBlockSelected ) { - this.props.onSelectBlock(); - } - - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - - if ( this.state.captionSelected ) { - this.setState( { - captionSelected: false, - } ); - } - } - - onSelectMedia( media ) { - const { setAttributes } = this.props; - setAttributes( media ); - } - - onCaptionChange( caption ) { - const { setAttributes } = this.props; - setAttributes( { caption } ); - } - - componentDidUpdate( prevProps ) { - const { isSelected, image, url } = this.props; - if ( image && ! url ) { - this.props.setAttributes( { - url: image.source_url, - alt: image.alt_text, - } ); - } - - // Unselect the caption so when the user selects other image and comeback - // the caption is not immediately selected. - if ( - this.state.captionSelected && - ! isSelected && - prevProps.isSelected - ) { - this.setState( { - captionSelected: false, - } ); - } - } - - updateMediaProgress() { - if ( ! this.state.isUploadInProgress ) { - this.setState( { isUploadInProgress: true } ); - } - } - - finishMediaUploadWithSuccess( payload ) { - this.setState( { - isUploadInProgress: false, - didUploadFail: false, - } ); - - this.props.setAttributes( { - id: payload.mediaServerId, - url: payload.mediaUrl, - } ); - } - - finishMediaUploadWithFailure() { - this.setState( { - isUploadInProgress: false, - didUploadFail: true, - } ); - } - - renderContent( params ) { - const { - url, - isFirstItem, - isLastItem, - isSelected, - caption, - onRemove, - onMoveForward, - onMoveBackward, - 'aria-label': ariaLabel, - isCropped, - getStylesFromColorScheme, - isRTL, - } = this.props; - - const { isUploadInProgress, captionSelected } = this.state; - const { isUploadFailed, retryMessage } = params; - const resizeMode = isCropped ? 'cover' : 'contain'; - - const captionPlaceholderStyle = getStylesFromColorScheme( - style.captionPlaceholder, - style.captionPlaceholderDark - ); - - const shouldShowCaptionEditable = ! isUploadFailed && isSelected; - const shouldShowCaptionExpanded = - ! isUploadFailed && ! isSelected && !! caption; - - const captionContainerStyle = shouldShowCaptionExpanded - ? style.captionExpandedContainer - : style.captionContainer; - - const captionStyle = shouldShowCaptionExpanded - ? style.captionExpanded - : style.caption; - - const mediaPickerOptions = [ - { - destructiveButton: true, - id: 'removeImage', - label: __( 'Remove' ), - onPress: onRemove, - separated: true, - value: 'removeImage', - }, - ]; - - return ( - <> - { - - { ! isUploadInProgress && isSelected && ( - - - -