From 244376690d18fbcc82334062ccb6e585c782cf22 Mon Sep 17 00:00:00 2001 From: Tom Usborne Date: Thu, 5 Dec 2024 21:57:43 -0500 Subject: [PATCH 1/5] Feature: Add alignment toolbar --- src/blocks/element/block.json | 4 + src/blocks/element/edit.js | 16 +- src/blocks/media/edit.js | 14 +- src/blocks/text/edit.js | 11 +- .../alignment-toolbar/AlignmentToolbar.jsx | 174 ++++++++++++++++++ .../alignment-toolbar/BlockWidth.jsx | 73 ++++++++ src/components/index.js | 2 + src/hoc/withHtmlAttributes.js | 19 ++ 8 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 src/components/alignment-toolbar/AlignmentToolbar.jsx create mode 100644 src/components/alignment-toolbar/BlockWidth.jsx diff --git a/src/blocks/element/block.json b/src/blocks/element/block.json index 26a05830b..fa12c2b1e 100644 --- a/src/blocks/element/block.json +++ b/src/blocks/element/block.json @@ -50,6 +50,10 @@ "htmlAttributes": { "type": "object", "default": {} + }, + "align": { + "type": "string", + "default": "" } }, "supports": { diff --git a/src/blocks/element/edit.js b/src/blocks/element/edit.js index 1f14da5a8..28854237b 100644 --- a/src/blocks/element/edit.js +++ b/src/blocks/element/edit.js @@ -7,7 +7,7 @@ import RootElement from '../../components/root-element/index.js'; import { BlockSettings } from './components/BlockSettings'; import { selectorShortcuts } from '@utils/selectorShortcuts.js'; import { withStyles } from '@hoc/withStyles'; -import { BlockStylesBuilder, StylesOnboarder } from '@components/index.js'; +import { AlignmentToolbar, BlockStylesBuilder, StylesOnboarder } from '@components/index.js'; import { withHtmlAttributes } from '@hoc/withHtmlAttributes.js'; import { getBlockClasses } from '@utils/getBlockClasses.js'; import { BlockAppender } from '@components'; @@ -19,6 +19,7 @@ function EditBlock( props ) { clientId, isSelected, name, + getStyleValue, onStyleChange, editorHtmlAttributes, styles, @@ -26,6 +27,7 @@ function EditBlock( props ) { const { tagName, + align, } = attributes; const classNames = getBlockClasses( @@ -95,6 +97,17 @@ function EditBlock( props ) { <> + + + diff --git a/src/blocks/media/edit.js b/src/blocks/media/edit.js index 567b679b1..4d472db49 100644 --- a/src/blocks/media/edit.js +++ b/src/blocks/media/edit.js @@ -11,7 +11,7 @@ import { withDynamicTag } from '../../hoc/withDynamicTag.js'; import RootElement from '../../components/root-element/index.js'; import { BlockSettings } from './components/BlockSettings'; import { withStyles } from '@hoc/withStyles'; -import { BlockStylesBuilder, StylesOnboarder } from '@components/index'; +import { AlignmentToolbar, BlockStylesBuilder, StylesOnboarder } from '@components/index'; import { withHtmlAttributes } from '@hoc/withHtmlAttributes.js'; import { getBlockClasses } from '@utils/getBlockClasses.js'; @@ -23,6 +23,7 @@ function EditBlock( props ) { name, clientId, onStyleChange, + getStyleValue, editorHtmlAttributes, htmlAttributes, styles, @@ -171,6 +172,17 @@ function EditBlock( props ) { <> + + { 'img' === tagName && ( + + ) } + + + { ! iconOnly && ( + ( + + ) } + renderContent={ () => ( + <> + { !! withTextAlign && ( + + { textAlignments.map( ( { icon, value, label } ) => ( + { + if ( value === getStyleValue( 'textAlign', currentAtRule ) ) { + onStyleChange( 'textAlign', '', currentAtRule ); + return; + } + + onStyleChange( 'textAlign', value, currentAtRule ); + } } + > + { label } + + ) ) } + + ) } + + { !! withFloat && ( + + { floats.map( ( { icon, value, label } ) => ( + { + if ( value === getStyleValue( 'float', currentAtRule ) ) { + onStyleChange( 'float', '', currentAtRule ); + return; + } + + onStyleChange( 'float', value, currentAtRule ); + } } + > + { label } + + ) ) } + + ) } + + { !! withBlockWidth && '' === currentAtRule && undefined !== align && ( + setAttributes( { align: value } ) } + clientId={ clientId } + /> + ) } + + ) } + /> + + ); +} diff --git a/src/components/alignment-toolbar/BlockWidth.jsx b/src/components/alignment-toolbar/BlockWidth.jsx new file mode 100644 index 000000000..4abd6ca51 --- /dev/null +++ b/src/components/alignment-toolbar/BlockWidth.jsx @@ -0,0 +1,73 @@ +import { __ } from '@wordpress/i18n'; +import { MenuGroup, MenuItem } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { store as blockEditorStore, useSetting } from '@wordpress/block-editor'; +import { alignNone, stretchWide, stretchFullWidth } from '@wordpress/icons'; +import { applyFilters } from '@wordpress/hooks'; + +export function BlockWidth( { align, onChange, clientId } ) { + const hasWideSize = useSetting( 'layout.wideSize' ); + const { themeSupportsAlignWide } = useSelect( + ( select ) => { + const { getSettings } = select( blockEditorStore ); + return { + themeSupportsAlignWide: getSettings()?.alignWide, + }; + }, + [] + ); + const { + getBlockRootClientId, + } = useSelect( ( select ) => select( blockEditorStore ), [] ); + + const removeBlockWidthOptions = applyFilters( + 'generateblocks.editor.removeBlockWidthOptions', + false, + { clientId } + ); + + if ( ( ! themeSupportsAlignWide && ! hasWideSize ) || removeBlockWidthOptions ) { + return null; + } + + const parentBlockId = getBlockRootClientId( clientId ); + + if ( parentBlockId ) { + return null; + } + + const options = [ + { + label: __( 'Default', 'generateblocks' ), + value: '', + icon: alignNone, + }, + { + label: __( 'Wide', 'generateblocks' ), + value: 'wide', + icon: stretchWide, + }, + { + label: __( 'Full', 'generateblocks' ), + value: 'full', + icon: stretchFullWidth, + }, + ]; + + return ( + + { options.map( ( option ) => { + return ( + onChange( option.value ) } + icon={ option.icon } + > + { option.label } + + ); + } ) } + + ); +} diff --git a/src/components/index.js b/src/components/index.js index c0a8b55bf..42ff0ef7f 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -44,6 +44,7 @@ import { NoticePanel } from './notice-panel/NoticePanel'; import { OnboardNotice } from './onboard-notice/OnboardNotice'; import { TagNameToolbar } from './TagNameToolbar/TagNameToolbar'; import { BlockAppender } from './block-appender/BlockAppender'; +import { AlignmentToolbar } from './alignment-toolbar/AlignmentToolbar'; export { AdvancedSelect, @@ -92,4 +93,5 @@ export { UnitControl, UnitPicker, URLControls, + AlignmentToolbar, }; diff --git a/src/hoc/withHtmlAttributes.js b/src/hoc/withHtmlAttributes.js index 6b5dd7e2c..31a424c5c 100644 --- a/src/hoc/withHtmlAttributes.js +++ b/src/hoc/withHtmlAttributes.js @@ -2,6 +2,8 @@ import { useEffect, useMemo, useState } from '@wordpress/element'; import { InspectorAdvancedControls } from '@wordpress/block-editor'; import { TextControl } from '@wordpress/components'; +import { useUpdateEffect } from 'react-use'; + import { convertInlineStyleStringToObject } from '@utils/convertInlineStyleStringToObject'; import { replaceTags } from '../dynamic-tags/utils'; @@ -67,6 +69,8 @@ export function withHtmlAttributes( WrappedComponent ) { const { htmlAttributes = {}, uniqueId, + className, + align, } = attributes; const [ styleWithReplacements, setStyleWithReplacements ] = useState( '' ); @@ -101,6 +105,20 @@ export function withHtmlAttributes( WrappedComponent ) { getReplacements(); }, [ style, context ] ); + useUpdateEffect( () => { + const layoutClasses = [ 'alignwide', 'alignfull' ]; + const existingClasses = className?.split( ' ' ) || []; + const newClasses = existingClasses.filter( + ( existingClass ) => ! layoutClasses.includes( existingClass ) + ); + + if ( align ) { + newClasses.push( 'align' + align ); + } + + setAttributes( { className: newClasses.join( ' ' ) } ); + }, [ align ] ); + const inlineStyleObject = typeof styleWithReplacements === 'string' ? convertInlineStyleStringToObject( styleWithReplacements ) : ''; @@ -109,6 +127,7 @@ export function withHtmlAttributes( WrappedComponent ) { style: inlineStyleObject, 'data-gb-id': uniqueId, 'data-context-post-id': context?.postId ?? context?.[ 'generateblocks/loopIndex' ] ?? 0, + 'data-align': align, }; const frontendHtmlAttributes = useMemo( () => { From 032b863c3318fcee6c86cb43d1ea6f283558de69 Mon Sep 17 00:00:00 2001 From: Tom Usborne Date: Fri, 6 Dec 2024 10:52:38 -0500 Subject: [PATCH 2/5] Fix: Image floating editor issue --- src/blocks/media/block.json | 2 +- src/blocks/media/components/Image.jsx | 9 +++++++++ src/blocks/media/editor.scss | 11 ----------- src/editor/editor.scss | 5 +++++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/blocks/media/block.json b/src/blocks/media/block.json index 870597f63..9ab2f6afc 100644 --- a/src/blocks/media/block.json +++ b/src/blocks/media/block.json @@ -51,7 +51,7 @@ }, "editorScript": "file:./index.js", "editorStyle": [ - "file:./editor.scss" + "file:./index.css" ], "usesContext": [ "postId", diff --git a/src/blocks/media/components/Image.jsx b/src/blocks/media/components/Image.jsx index 7973008b1..69a9fafa9 100644 --- a/src/blocks/media/components/Image.jsx +++ b/src/blocks/media/components/Image.jsx @@ -44,6 +44,14 @@ export function Image( { imageRef.current?.complete, ] ); + const computedStyles = useMemo( () => { + if ( ! imageRef.current ) { + return false; + } + + return getComputedStyle( imageRef.current ); + }, [ imageRef.current ] ); + const imageSrc = useMemo( () => { if ( dynamicTagValue?.[ 0 ]?.replacement && isURL( dynamicTagValue?.[ 0 ]?.replacement ) ) { return dynamicTagValue?.[ 0 ]?.replacement; @@ -103,6 +111,7 @@ export function Image( { } } role={ ! isSelected ? 'button' : undefined } tabIndex={ ! isSelected ? 0 : undefined } + data-is-floating={ 'none' !== computedStyles?.float } /> ); diff --git a/src/blocks/media/editor.scss b/src/blocks/media/editor.scss index 6afae9a34..e69de29bb 100644 --- a/src/blocks/media/editor.scss +++ b/src/blocks/media/editor.scss @@ -1,11 +0,0 @@ -.wp-block-generateblocks-media { - display: block; - - &:not(.is-selected) { - display: none; - } - - &.is-selected + [class*="gb-media"] { - display: none; - } -} diff --git a/src/editor/editor.scss b/src/editor/editor.scss index 40b3bfbf5..cd64809c2 100644 --- a/src/editor/editor.scss +++ b/src/editor/editor.scss @@ -11,3 +11,8 @@ $blue: #1e72bd; color: $blue; } } + +:where([data-is-floating="true"]) { + position: relative; + z-index: 22; +} From f0ff964e120d9a93972ef5d9b5fc0f9836e18bbc Mon Sep 17 00:00:00 2001 From: Tom Usborne Date: Fri, 6 Dec 2024 21:26:12 -0500 Subject: [PATCH 3/5] Tweak: Remove image float options --- src/blocks/media/edit.js | 13 +--- .../alignment-toolbar/AlignmentToolbar.jsx | 59 +------------------ 2 files changed, 3 insertions(+), 69 deletions(-) diff --git a/src/blocks/media/edit.js b/src/blocks/media/edit.js index 4d472db49..cfe62c097 100644 --- a/src/blocks/media/edit.js +++ b/src/blocks/media/edit.js @@ -11,7 +11,7 @@ import { withDynamicTag } from '../../hoc/withDynamicTag.js'; import RootElement from '../../components/root-element/index.js'; import { BlockSettings } from './components/BlockSettings'; import { withStyles } from '@hoc/withStyles'; -import { AlignmentToolbar, BlockStylesBuilder, StylesOnboarder } from '@components/index'; +import { BlockStylesBuilder, StylesOnboarder } from '@components/index'; import { withHtmlAttributes } from '@hoc/withHtmlAttributes.js'; import { getBlockClasses } from '@utils/getBlockClasses.js'; @@ -23,7 +23,6 @@ function EditBlock( props ) { name, clientId, onStyleChange, - getStyleValue, editorHtmlAttributes, htmlAttributes, styles, @@ -173,16 +172,6 @@ function EditBlock( props ) { - { 'img' === tagName && ( - - ) } - ) } - { !! withFloat && ( - - { floats.map( ( { icon, value, label } ) => ( - { - if ( value === getStyleValue( 'float', currentAtRule ) ) { - onStyleChange( 'float', '', currentAtRule ); - return; - } - - onStyleChange( 'float', value, currentAtRule ); - } } - > - { label } - - ) ) } - - ) } - { !! withBlockWidth && '' === currentAtRule && undefined !== align && ( Date: Fri, 6 Dec 2024 21:28:39 -0500 Subject: [PATCH 4/5] Remove image floating --- src/blocks/media/components/Image.jsx | 9 --------- src/editor/editor.scss | 5 ----- 2 files changed, 14 deletions(-) diff --git a/src/blocks/media/components/Image.jsx b/src/blocks/media/components/Image.jsx index 69a9fafa9..7973008b1 100644 --- a/src/blocks/media/components/Image.jsx +++ b/src/blocks/media/components/Image.jsx @@ -44,14 +44,6 @@ export function Image( { imageRef.current?.complete, ] ); - const computedStyles = useMemo( () => { - if ( ! imageRef.current ) { - return false; - } - - return getComputedStyle( imageRef.current ); - }, [ imageRef.current ] ); - const imageSrc = useMemo( () => { if ( dynamicTagValue?.[ 0 ]?.replacement && isURL( dynamicTagValue?.[ 0 ]?.replacement ) ) { return dynamicTagValue?.[ 0 ]?.replacement; @@ -111,7 +103,6 @@ export function Image( { } } role={ ! isSelected ? 'button' : undefined } tabIndex={ ! isSelected ? 0 : undefined } - data-is-floating={ 'none' !== computedStyles?.float } /> ); diff --git a/src/editor/editor.scss b/src/editor/editor.scss index cd64809c2..40b3bfbf5 100644 --- a/src/editor/editor.scss +++ b/src/editor/editor.scss @@ -11,8 +11,3 @@ $blue: #1e72bd; color: $blue; } } - -:where([data-is-floating="true"]) { - position: relative; - z-index: 22; -} From 8fd66b52efbcfec51188be3f1fc6f796120f0994 Mon Sep 17 00:00:00 2001 From: Tom Usborne Date: Fri, 6 Dec 2024 21:29:07 -0500 Subject: [PATCH 5/5] Improve align check --- src/hoc/withHtmlAttributes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hoc/withHtmlAttributes.js b/src/hoc/withHtmlAttributes.js index c0d4a8324..ed52262c9 100644 --- a/src/hoc/withHtmlAttributes.js +++ b/src/hoc/withHtmlAttributes.js @@ -128,7 +128,7 @@ export function withHtmlAttributes( WrappedComponent ) { style: inlineStyleObject, 'data-gb-id': uniqueId, 'data-context-post-id': context?.postId ?? context?.[ 'generateblocks/loopIndex' ] ?? 0, - 'data-align': align, + 'data-align': align ? align : undefined, }; const frontendHtmlAttributes = useMemo( () => {