From f12a96ce9f758de6cdb765078515e77fe5087bd6 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 9 Feb 2022 17:01:27 +0000 Subject: [PATCH 1/9] Copy across basics from Cover block --- packages/block-library/src/group/edit.js | 80 +++++++++++++-- packages/block-library/src/group/shared.js | 108 +++++++++++++++++++++ 2 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 packages/block-library/src/group/shared.js diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 3209106ff8e80..6a11411c7896d 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -1,6 +1,11 @@ +/** + * External dependencies + */ + /** * WordPress dependencies */ +import { useRef } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { InnerBlocks, @@ -8,10 +13,31 @@ import { InspectorControls, useInnerBlocksProps, useSetting, + withColors, + BlockControls, + MediaReplaceFlow, store as blockEditorStore, } from '@wordpress/block-editor'; import { SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import { compose } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +/* eslint-disable no-unused-vars */ +import { + ALLOWED_MEDIA_TYPES, + attributesFromMedia, + IMAGE_BACKGROUND_TYPE, + VIDEO_BACKGROUND_TYPE, + COVER_MIN_HEIGHT, + backgroundImageStyles, + dimRatioToClass, + isContentPositionCenter, + getPositionClassName, +} from './shared'; +/* eslint-enable no-unused-vars */ const htmlElementMessages = { header: __( @@ -35,6 +61,8 @@ const htmlElementMessages = { }; function GroupEdit( { attributes, setAttributes, clientId } ) { + const { id, url, backgroundType, alt } = attributes; + const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { const { getBlock, getSettings } = select( blockEditorStore ); @@ -46,6 +74,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { }, [ clientId ] ); + const isDarkElement = useRef(); const defaultLayout = useSetting( 'layout' ) || {}; const { tagName: TagName = 'div', templateLock, layout = {} } = attributes; const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; @@ -66,8 +95,33 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { } ); + const isImgElement = true; // ! ( hasParallax || isRepeated ); + const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; + + // const bgStyle = { backgroundColor: overlayColor?.color }; + const mediaStyle = { + // objectPosition: + // focalPoint && isImgElement + // ? mediaPosition( focalPoint ) + // : undefined, + }; + + const onSelectMedia = attributesFromMedia( setAttributes, 1 ); + + const showBgImage = url && isImageBackground && isImgElement; + return ( <> + + + - { layoutSupportEnabled && } - { /* Ideally this is not needed but it's there for backward compatibility reason - to keep this div for themes that might rely on its presence */ } - { ! layoutSupportEnabled && ( - -
- - ) } + + +
+ + { showBgImage && ( + { + ) } + ); } -export default GroupEdit; +export default compose( [ + withColors( { overlayColor: 'background-color' } ), +] )( GroupEdit ); diff --git a/packages/block-library/src/group/shared.js b/packages/block-library/src/group/shared.js new file mode 100644 index 0000000000000..4a45c145518f0 --- /dev/null +++ b/packages/block-library/src/group/shared.js @@ -0,0 +1,108 @@ +/** + * WordPress dependencies + */ +import { getBlobTypeByURL, isBlobURL } from '@wordpress/blob'; + +const POSITION_CLASSNAMES = { + 'top left': 'is-position-top-left', + 'top center': 'is-position-top-center', + 'top right': 'is-position-top-right', + 'center left': 'is-position-center-left', + 'center center': 'is-position-center-center', + center: 'is-position-center-center', + 'center right': 'is-position-center-right', + 'bottom left': 'is-position-bottom-left', + 'bottom center': 'is-position-bottom-center', + 'bottom right': 'is-position-bottom-right', +}; + +export const IMAGE_BACKGROUND_TYPE = 'image'; +export const VIDEO_BACKGROUND_TYPE = 'video'; +export const COVER_MIN_HEIGHT = 50; +export const COVER_MAX_HEIGHT = 1000; +export const COVER_DEFAULT_HEIGHT = 300; +export function backgroundImageStyles( url ) { + return url ? { backgroundImage: `url(${ url })` } : {}; +} +export const ALLOWED_MEDIA_TYPES = [ 'image', 'video' ]; + +export function dimRatioToClass( ratio ) { + return ratio === 50 || ! ratio === undefined + ? null + : 'has-background-dim-' + 10 * Math.round( ratio / 10 ); +} + +export function attributesFromMedia( setAttributes, dimRatio ) { + return ( media ) => { + if ( ! media || ! media.url ) { + setAttributes( { url: undefined, id: undefined } ); + return; + } + + if ( isBlobURL( media.url ) ) { + media.type = getBlobTypeByURL( media.url ); + } + + let mediaType; + // for media selections originated from a file upload. + if ( media.media_type ) { + if ( media.media_type === IMAGE_BACKGROUND_TYPE ) { + mediaType = IMAGE_BACKGROUND_TYPE; + } else { + // only images and videos are accepted so if the media_type is not an image we can assume it is a video. + // Videos contain the media type of 'file' in the object returned from the rest api. + mediaType = VIDEO_BACKGROUND_TYPE; + } + } else { + // for media selections originated from existing files in the media library. + if ( + media.type !== IMAGE_BACKGROUND_TYPE && + media.type !== VIDEO_BACKGROUND_TYPE + ) { + return; + } + mediaType = media.type; + } + + setAttributes( { + dimRatio: dimRatio === 100 ? 50 : dimRatio, + url: media.url, + id: media.id, + alt: media?.alt, + backgroundType: mediaType, + ...( mediaType === VIDEO_BACKGROUND_TYPE + ? { focalPoint: undefined, hasParallax: undefined } + : {} ), + } ); + }; +} + +/** + * Checks of the contentPosition is the center (default) position. + * + * @param {string} contentPosition The current content position. + * @return {boolean} Whether the contentPosition is center. + */ +export function isContentPositionCenter( contentPosition ) { + return ( + ! contentPosition || + contentPosition === 'center center' || + contentPosition === 'center' + ); +} + +/** + * Retrieves the className for the current contentPosition. + * The default position (center) will not have a className. + * + * @param {string} contentPosition The current content position. + * @return {string} The className assigned to the contentPosition. + */ +export function getPositionClassName( contentPosition ) { + /* + * Only render a className if the contentPosition is not center (the default). + */ + if ( isContentPositionCenter( contentPosition ) ) return ''; + + return POSITION_CLASSNAMES[ contentPosition ]; +} From 3f2432b772cd269aa922aad56ed3b908fd77b8a0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 9 Feb 2022 17:15:13 +0000 Subject: [PATCH 2/9] Add very basic styling support --- packages/block-library/src/group/edit.js | 7 ++- packages/block-library/src/group/style.scss | 60 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 6a11411c7896d..b5431fb2ec0a4 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -79,7 +79,10 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { const { tagName: TagName = 'div', templateLock, layout = {} } = attributes; const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; const { type = 'default' } = usedLayout; - const layoutSupportEnabled = themeSupportsLayout || type !== 'default'; + + // TODO - temp disabled + const layoutSupportEnabled = + ( false && themeSupportsLayout ) || type !== 'default'; const blockProps = useBlockProps(); const innerBlocksProps = useInnerBlocksProps( @@ -148,7 +151,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { { showBgImage && ( { Date: Thu, 10 Feb 2022 08:52:51 +0000 Subject: [PATCH 3/9] Add new attributes --- docs/reference-guides/core-blocks.md | 2 +- packages/block-library/src/group/block.json | 38 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 0244c56110908..e3baea4a1fc26 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -258,7 +258,7 @@ Combine blocks into a group. ([Source](https://github.com/WordPress/gutenberg/tr - **Name:** core/group - **Category:** design - **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (blockGap, padding), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** tagName, templateLock +- **Attributes:** alt, backgroundType, customOverlayColor, dimRatio, focalPoint, hasParallax, id, isRepeated, overlayColor, tagName, templateLock, url ## Heading diff --git a/packages/block-library/src/group/block.json b/packages/block-library/src/group/block.json index 5a7617f0321c5..30ad2cab10c37 100644 --- a/packages/block-library/src/group/block.json +++ b/packages/block-library/src/group/block.json @@ -15,6 +15,44 @@ "templateLock": { "type": [ "string", "boolean" ], "enum": [ "all", "insert", false ] + }, + "url": { + "type": "string" + }, + "id": { + "type": "number" + }, + "alt": { + "type": "string", + "source": "attribute", + "selector": "img", + "attribute": "alt", + "default": "" + }, + "hasParallax": { + "type": "boolean", + "default": false + }, + "isRepeated": { + "type": "boolean", + "default": false + }, + "dimRatio": { + "type": "number", + "default": 100 + }, + "overlayColor": { + "type": "string" + }, + "customOverlayColor": { + "type": "string" + }, + "backgroundType": { + "type": "string", + "default": "image" + }, + "focalPoint": { + "type": "object" } }, "supports": { From 5fd4abbd2793a210e025562365425b72b9ae204d Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 10 Feb 2022 08:54:25 +0000 Subject: [PATCH 4/9] Only allow image uploads --- packages/block-library/src/group/edit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index b5431fb2ec0a4..e73c81e43a1a7 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -27,11 +27,8 @@ import { compose } from '@wordpress/compose'; */ /* eslint-disable no-unused-vars */ import { - ALLOWED_MEDIA_TYPES, attributesFromMedia, IMAGE_BACKGROUND_TYPE, - VIDEO_BACKGROUND_TYPE, - COVER_MIN_HEIGHT, backgroundImageStyles, dimRatioToClass, isContentPositionCenter, @@ -39,6 +36,9 @@ import { } from './shared'; /* eslint-enable no-unused-vars */ +// For now let's keep things simple and use only images. +const ALLOWED_MEDIA_TYPES = [ 'image' ]; + const htmlElementMessages = { header: __( 'The
element should represent introductory content, typically a group of introductory or navigational aids.' From 0d3d1fd94e8a7e3dd1cfa9bf618b2ea3306edd73 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 10 Feb 2022 09:10:43 +0000 Subject: [PATCH 5/9] Add focal point --- packages/block-library/src/group/edit.js | 62 +++++++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index e73c81e43a1a7..38df4396e18b9 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -18,9 +18,15 @@ import { MediaReplaceFlow, store as blockEditorStore, } from '@wordpress/block-editor'; -import { SelectControl } from '@wordpress/components'; +import { + SelectControl, + Spinner, + PanelBody, + FocalPointPicker, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { compose } from '@wordpress/compose'; +import { isBlobURL } from '@wordpress/blob'; /** * Internal dependencies @@ -39,6 +45,10 @@ import { // For now let's keep things simple and use only images. const ALLOWED_MEDIA_TYPES = [ 'image' ]; +function mediaPosition( { x, y } ) { + return `${ Math.round( x * 100 ) }% ${ Math.round( y * 100 ) }%`; +} + const htmlElementMessages = { header: __( 'The
element should represent introductory content, typically a group of introductory or navigational aids.' @@ -60,8 +70,11 @@ const htmlElementMessages = { ), }; +// TODO - duplicated from Cover. Should be in shared? +const isTemporaryMedia = ( id, url ) => ! id && isBlobURL( url ); + function GroupEdit( { attributes, setAttributes, clientId } ) { - const { id, url, backgroundType, alt } = attributes; + const { id, url, backgroundType, alt, focalPoint } = attributes; const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { @@ -74,7 +87,10 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { }, [ clientId ] ); + + const ref = useRef(); const isDarkElement = useRef(); + const defaultLayout = useSetting( 'layout' ) || {}; const { tagName: TagName = 'div', templateLock, layout = {} } = attributes; const usedLayout = !! layout && layout.inherit ? defaultLayout : layout; @@ -103,15 +119,24 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { // const bgStyle = { backgroundColor: overlayColor?.color }; const mediaStyle = { - // objectPosition: - // focalPoint && isImgElement - // ? mediaPosition( focalPoint ) - // : undefined, + objectPosition: + focalPoint && isImgElement + ? mediaPosition( focalPoint ) + : undefined, }; const onSelectMedia = attributesFromMedia( setAttributes, 1 ); + const isUploadingMedia = isTemporaryMedia( id, url ); const showBgImage = url && isImageBackground && isImgElement; + const showFocalPointPicker = isImageBackground; + + const imperativeFocalPointPreview = ( value ) => { + const [ styleOfRef, property ] = isDarkElement.current + ? [ isDarkElement.current.style, 'objectPosition' ] + : [ ref.current.style, 'backgroundPosition' ]; + styleOfRef[ property ] = mediaPosition( value ); + }; return ( <> @@ -125,6 +150,27 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { name={ ! url ? __( 'Add Media' ) : __( 'Replace' ) } /> + + { !! url && ( + + { showFocalPointPicker && ( + + setAttributes( { + focalPoint: newFocalPoint, + } ) + } + /> + ) } + + ) } + + -
- { showBgImage && ( ) } + { isUploadingMedia && } +
); From 907753a66b167b8d42bbc3ae28c3d17f53c27d9c Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 14 Feb 2022 10:48:36 +0000 Subject: [PATCH 6/9] Remove unwanted --- packages/block-library/src/group/edit.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 38df4396e18b9..1fae8dabc493d 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -37,8 +37,6 @@ import { IMAGE_BACKGROUND_TYPE, backgroundImageStyles, dimRatioToClass, - isContentPositionCenter, - getPositionClassName, } from './shared'; /* eslint-enable no-unused-vars */ From a7b43c5d099a6829b962eeaeffe6958d6ccd643e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 14 Feb 2022 11:05:19 +0000 Subject: [PATCH 7/9] Add overlap with opacity capacity --- packages/block-library/src/group/edit.js | 72 ++++++++++++++++++++- packages/block-library/src/group/style.scss | 20 ++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 1fae8dabc493d..c46e3b4461950 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import classnames from 'classnames'; /** * WordPress dependencies @@ -17,12 +18,15 @@ import { BlockControls, MediaReplaceFlow, store as blockEditorStore, + __experimentalPanelColorGradientSettings as PanelColorGradientSettings, + __experimentalUseGradient, } from '@wordpress/block-editor'; import { SelectControl, Spinner, PanelBody, FocalPointPicker, + RangeControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { compose } from '@wordpress/compose'; @@ -72,7 +76,22 @@ const htmlElementMessages = { const isTemporaryMedia = ( id, url ) => ! id && isBlobURL( url ); function GroupEdit( { attributes, setAttributes, clientId } ) { - const { id, url, backgroundType, alt, focalPoint } = attributes; + const { + id, + url, + backgroundType, + alt, + focalPoint, + overlayColor, + setOverlayColor, + dimRatio, + } = attributes; + + const { + gradientClass, + gradientValue, + setGradient, + } = __experimentalUseGradient(); const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { @@ -115,7 +134,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { const isImgElement = true; // ! ( hasParallax || isRepeated ); const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; - // const bgStyle = { backgroundColor: overlayColor?.color }; + const bgStyle = { backgroundColor: overlayColor?.color }; const mediaStyle = { objectPosition: focalPoint && isImgElement @@ -167,6 +186,36 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { ) } ) } + + + + setAttributes( { + dimRatio: newDimRation, + } ) + } + min={ 0 } + max={ 100 } + step={ 10 } + required + /> + @@ -190,6 +239,25 @@ function GroupEdit( { attributes, setAttributes, clientId } ) { +