From 774322c338229376ed7d055c14668bda807e1cb5 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 12:07:47 +0100 Subject: [PATCH 01/15] feat: adding radius option to the Border style --- src/editor/components/StylesBorder.js | 31 ++- src/editor/components/StylesBorderRadius.js | 219 ++++++++++++++++++++ 2 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 src/editor/components/StylesBorderRadius.js diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index 12c40679..45de1c56 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -7,6 +7,8 @@ import getThemeOption from '../../utils/get-theme-option'; import EditorContext from '../context/EditorContext'; import StylesContext from '../context/StylesContext'; +import StylesBorderRadius from './StylesBorderRadius'; + /** * Reusable border control style component * @@ -31,13 +33,30 @@ const Border = ( { selector } ) => { return ( <> - { __( 'Border', 'themer' ) } + { __( 'Border and radius', 'themer' ) } - +
+
+ + { __( 'Border', 'themer' ) } + + +
+
+ + { __( 'Radius', 'themer' ) } + + +
+
); }; diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js new file mode 100644 index 00000000..b68de1fe --- /dev/null +++ b/src/editor/components/StylesBorderRadius.js @@ -0,0 +1,219 @@ +import { set } from 'lodash'; +import { __ } from '@wordpress/i18n'; +import { useContext, useState, useEffect, useRef } from '@wordpress/element'; +import { + __experimentalUnitControl as UnitControl, + RangeControl, + __experimentalHStack as HStack, + __experimentalGrid as Grid, + Button, +} from '@wordpress/components'; + +import getThemeOption from '../../utils/get-theme-option'; +import EditorContext from '../context/EditorContext'; +import StylesContext from '../context/StylesContext'; + +/** + * Reusable border control style component + * + * @param {Object} props Component props + * @param {string} props.selector Property target selector + */ +const BorderRadius = ( { selector } ) => { + const { userConfig, themeConfig } = useContext( EditorContext ); + const { setUserConfig } = useContext( StylesContext ); + const value = getThemeOption( selector, themeConfig ); + + // Set initial state to determine if the values are linked or unlinked + const [ hasLinkedValues, setHasLinkedValues ] = useState( + typeof value === 'object' ? false : true + ); + + // Set initial state for the linked value + const [ linkedValue, setLinkedValue ] = useState( value?.topLeft ?? value ); + + // Set initial state for the unlinked values + const [ unlinkedValues, setUnlinkedValues ] = useState( { + topLeft: value?.topLeft ?? value, + topRight: value?.topRight ?? value, + bottomRight: value?.bottomRight ?? value, + bottomLeft: value?.bottomLeft ?? value, + } ); + + // Set mount reference to avoid unlinked values being changes on initial mount + const isInitialMount = useRef( true ); + + // Main function to push data to the user config + const onChange = ( newValue ) => { + let config = structuredClone( userConfig ); + config = set( config, selector, newValue ); + setUserConfig( config ); + }; + + // When the values change, update the user config + useEffect( () => { + if ( isInitialMount.current ) { + isInitialMount.current = false; + } else { + onChange( hasLinkedValues ? linkedValue : unlinkedValues ); + } + }, [ unlinkedValues, linkedValue, hasLinkedValues ] ); + + /** + * Handle changes to the linked value + * + * @param {string} newValue The updated linked value + */ + const handleLinkedValueChange = ( newValue ) => { + // Set the linked value + setLinkedValue( newValue ); + + // Also set the unlinked values to the new linked value + const updatedUnlinkedValues = { + topLeft: newValue, + topRight: newValue, + bottomRight: newValue, + bottomLeft: newValue, + }; + setUnlinkedValues( updatedUnlinkedValues ); + }; + + /** + * Add the measurement unit to the value from the slider + * + * @param {string} newValue The updated value + */ + const addMeasurement = ( newValue ) => { + // Get the unit of measurement + const measurementUnit = String( linkedValue ).replace( /[0-9.]/g, '' ); + + // Concatenate the new value with the unit of measurement + const updatedValue = newValue + measurementUnit; + + // Update the linked value + handleLinkedValueChange( updatedValue ); + }; + + /** + * A function to handle changes to an unlinked value + * + * @param {string} newValue The updated value + * @param {string} position The border radius position + * + * @return {Object} The updated unlinked values + */ + const handleUnlinkedValueChange = ( newValue, position ) => { + const updatedValue = { + ...unlinkedValues, + [ position ]: newValue, + }; + + return updatedValue; + }; + + return ( + <> + + { hasLinkedValues ? ( + +
+ +
+
+
+ +
+
+
+ ) : ( + + + setUnlinkedValues( + handleUnlinkedValueChange( + topLeftValue, + 'topLeft' + ) + ) + } + value={ value?.topLeft ?? value } + /> + + setUnlinkedValues( + handleUnlinkedValueChange( + topRightValue, + 'topRight' + ) + ) + } + value={ value?.topRight ?? value } + /> + + setUnlinkedValues( + handleUnlinkedValueChange( + bottomLeftValue, + 'bottomLeft' + ) + ) + } + value={ value?.bottomLeft ?? value } + /> + + setUnlinkedValues( + handleUnlinkedValueChange( + bottomRightValue, + 'bottomRight' + ) + ) + } + value={ value?.bottomRight ?? value } + /> + + ) } + +
+ + ); +}; + +export default BorderRadius; From f5500cb86b5b40aefff28fb36a69dea269d8c9b0 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 13:08:50 +0100 Subject: [PATCH 02/15] feat: fixing bug with range slider value --- src/editor/components/StylesBorderRadius.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js index b68de1fe..27c4a44f 100644 --- a/src/editor/components/StylesBorderRadius.js +++ b/src/editor/components/StylesBorderRadius.js @@ -133,7 +133,9 @@ const BorderRadius = ( { selector } ) => { min={ 0 } onChange={ addMeasurement } step={ 1 } - value={ linkedValue || undefined } + value={ + parseInt( linkedValue ) || undefined + } withInputField={ false } /> From 692fc0ab00a153e0a8990e0af4cdd615e35087cb Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 14:23:51 +0100 Subject: [PATCH 03/15] feat: avoiding radius setting overwrite --- src/editor/components/StylesBorder.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index 45de1c56..a7d01029 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -25,8 +25,20 @@ const Border = ( { selector } ) => { ); const onChange = ( newValue ) => { + // If the value has a radius, we need to merge it with the new value + const valueRadius = value?.radius; + console.log( valueRadius ); + let updatedValue = newValue; + if ( valueRadius ) { + updatedValue = { + ...newValue, + radius: valueRadius, + }; + } + + // Set the new value in the user config let config = structuredClone( userConfig ); - config = set( config, selector, newValue ); + config = set( config, selector, updatedValue ); setUserConfig( config ); }; From 181de3063e3d3c7d47167395dd2713a0f4c14874 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 14:24:40 +0100 Subject: [PATCH 04/15] fix: removing console log --- src/editor/components/StylesBorder.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index a7d01029..7e2b275a 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -27,7 +27,6 @@ const Border = ( { selector } ) => { const onChange = ( newValue ) => { // If the value has a radius, we need to merge it with the new value const valueRadius = value?.radius; - console.log( valueRadius ); let updatedValue = newValue; if ( valueRadius ) { updatedValue = { From 1c28ce83c83d07560a44650b198e63b41ddf4bf4 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 15:22:28 +0100 Subject: [PATCH 05/15] feat: adding px unit if none set --- src/editor/components/StylesBorderRadius.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js index 27c4a44f..1bf97ccc 100644 --- a/src/editor/components/StylesBorderRadius.js +++ b/src/editor/components/StylesBorderRadius.js @@ -87,8 +87,9 @@ const BorderRadius = ( { selector } ) => { // Get the unit of measurement const measurementUnit = String( linkedValue ).replace( /[0-9.]/g, '' ); - // Concatenate the new value with the unit of measurement - const updatedValue = newValue + measurementUnit; + // Concatenate the new value with the unit of measurement (or use px if one isn't defined) + const updatedValue = + newValue + ( measurementUnit ? measurementUnit : 'px' ); // Update the linked value handleLinkedValueChange( updatedValue ); From 6834b1d635f9c49bd224bd56e60531b3ae76e4a3 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 15:43:13 +0100 Subject: [PATCH 06/15] fix: extending unit check --- src/editor/components/StylesBorderRadius.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js index 1bf97ccc..172b29e2 100644 --- a/src/editor/components/StylesBorderRadius.js +++ b/src/editor/components/StylesBorderRadius.js @@ -84,12 +84,13 @@ const BorderRadius = ( { selector } ) => { * @param {string} newValue The updated value */ const addMeasurement = ( newValue ) => { - // Get the unit of measurement - const measurementUnit = String( linkedValue ).replace( /[0-9.]/g, '' ); + // Get the unit of measurement, or default to px + const measurementUnit = linkedValue + ? String( linkedValue ).replace( /[0-9.]/g, '' ) + : 'px'; // Concatenate the new value with the unit of measurement (or use px if one isn't defined) - const updatedValue = - newValue + ( measurementUnit ? measurementUnit : 'px' ); + const updatedValue = newValue + ( measurementUnit ?? 'px' ); // Update the linked value handleLinkedValueChange( updatedValue ); From 131278a55f8abab97c4e799d3726ee203d347375 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 7 Oct 2024 18:35:16 +0100 Subject: [PATCH 07/15] refactor: removing useEffect and tidying functions --- src/editor/components/StylesBorderRadius.js | 98 +++++++++------------ 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js index 172b29e2..cadb59da 100644 --- a/src/editor/components/StylesBorderRadius.js +++ b/src/editor/components/StylesBorderRadius.js @@ -1,6 +1,6 @@ import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; -import { useContext, useState, useEffect, useRef } from '@wordpress/element'; +import { useContext, useState } from '@wordpress/element'; import { __experimentalUnitControl as UnitControl, RangeControl, @@ -29,71 +29,45 @@ const BorderRadius = ( { selector } ) => { typeof value === 'object' ? false : true ); - // Set initial state for the linked value - const [ linkedValue, setLinkedValue ] = useState( value?.topLeft ?? value ); - - // Set initial state for the unlinked values - const [ unlinkedValues, setUnlinkedValues ] = useState( { - topLeft: value?.topLeft ?? value, - topRight: value?.topRight ?? value, - bottomRight: value?.bottomRight ?? value, - bottomLeft: value?.bottomLeft ?? value, - } ); - - // Set mount reference to avoid unlinked values being changes on initial mount - const isInitialMount = useRef( true ); - - // Main function to push data to the user config + /** + * Handle changes to the border radius value + * + * @param {string} newValue The updated linked value + */ const onChange = ( newValue ) => { let config = structuredClone( userConfig ); config = set( config, selector, newValue ); setUserConfig( config ); }; - // When the values change, update the user config - useEffect( () => { - if ( isInitialMount.current ) { - isInitialMount.current = false; - } else { - onChange( hasLinkedValues ? linkedValue : unlinkedValues ); - } - }, [ unlinkedValues, linkedValue, hasLinkedValues ] ); - /** - * Handle changes to the linked value - * - * @param {string} newValue The updated linked value + * Handle toggling between linked and unlinked values */ - const handleLinkedValueChange = ( newValue ) => { - // Set the linked value - setLinkedValue( newValue ); + const handleToggleValueType = () => { + setHasLinkedValues( ! hasLinkedValues ); - // Also set the unlinked values to the new linked value - const updatedUnlinkedValues = { - topLeft: newValue, - topRight: newValue, - bottomRight: newValue, - bottomLeft: newValue, - }; - setUnlinkedValues( updatedUnlinkedValues ); + // When switching from unlinked to linked values, set the value to the topleft value + if ( ! hasLinkedValues ) { + onChange( value?.topLeft ); + } }; /** - * Add the measurement unit to the value from the slider + * Handle value changes made via the range control * * @param {string} newValue The updated value */ - const addMeasurement = ( newValue ) => { + const handleRangeValue = ( newValue ) => { // Get the unit of measurement, or default to px - const measurementUnit = linkedValue - ? String( linkedValue ).replace( /[0-9.]/g, '' ) + const valueUnit = value + ? String( value ).replace( /[0-9.]/g, '' ) : 'px'; // Concatenate the new value with the unit of measurement (or use px if one isn't defined) - const updatedValue = newValue + ( measurementUnit ?? 'px' ); + const updatedValue = newValue + ( valueUnit ?? 'px' ); - // Update the linked value - handleLinkedValueChange( updatedValue ); + // Update the value + onChange( updatedValue ); }; /** @@ -105,11 +79,21 @@ const BorderRadius = ( { selector } ) => { * @return {Object} The updated unlinked values */ const handleUnlinkedValueChange = ( newValue, position ) => { + // Define the structure of the unlinked values and set default values, if required + const unlinkedStructure = { + topLeft: value?.topLeft ?? value, + topRight: value?.topRight ?? value, + bottomLeft: value?.bottomLeft ?? value, + bottomRight: value?.bottomRight ?? value, + }; + + // Insert in the updated value const updatedValue = { - ...unlinkedValues, + ...unlinkedStructure, [ position ]: newValue, }; + // Return the updated values return updatedValue; }; @@ -120,8 +104,8 @@ const BorderRadius = ( { selector } ) => {
@@ -133,11 +117,9 @@ const BorderRadius = ( { selector } ) => { initialPosition={ 0 } max={ 100 } min={ 0 } - onChange={ addMeasurement } + onChange={ handleRangeValue } step={ 1 } - value={ - parseInt( linkedValue ) || undefined - } + value={ parseInt( value ) || undefined } withInputField={ false } />
@@ -149,7 +131,7 @@ const BorderRadius = ( { selector } ) => { label={ __( 'Top left border radius', 'themer' ) } hideLabelFromVision onChange={ ( topLeftValue ) => - setUnlinkedValues( + onChange( handleUnlinkedValueChange( topLeftValue, 'topLeft' @@ -162,7 +144,7 @@ const BorderRadius = ( { selector } ) => { label={ __( 'Top right border radius', 'themer' ) } hideLabelFromVision onChange={ ( topRightValue ) => - setUnlinkedValues( + onChange( handleUnlinkedValueChange( topRightValue, 'topRight' @@ -178,7 +160,7 @@ const BorderRadius = ( { selector } ) => { ) } hideLabelFromVision onChange={ ( bottomLeftValue ) => - setUnlinkedValues( + onChange( handleUnlinkedValueChange( bottomLeftValue, 'bottomLeft' @@ -194,7 +176,7 @@ const BorderRadius = ( { selector } ) => { ) } hideLabelFromVision onChange={ ( bottomRightValue ) => - setUnlinkedValues( + onChange( handleUnlinkedValueChange( bottomRightValue, 'bottomRight' @@ -206,7 +188,7 @@ const BorderRadius = ( { selector } ) => { ) } -
+ ); }; From a1df5d86f4b68904aeb1b4765998525cb23e41b7 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 6 Jan 2025 10:05:09 +0000 Subject: [PATCH 12/15] feat: removes unnecessary component --- src/editor/components/StylesBorderRadius.js | 38 --------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/editor/components/StylesBorderRadius.js diff --git a/src/editor/components/StylesBorderRadius.js b/src/editor/components/StylesBorderRadius.js deleted file mode 100644 index 652cc0e3..00000000 --- a/src/editor/components/StylesBorderRadius.js +++ /dev/null @@ -1,38 +0,0 @@ -import { set } from 'lodash'; -import { useContext } from '@wordpress/element'; -import { __experimentalBorderRadiusControl as BorderRadiusControl } from '@wordpress/block-editor'; - -import getThemeOption from '../../utils/get-theme-option'; -import EditorContext from '../context/EditorContext'; -import StylesContext from '../context/StylesContext'; - -/** - * Reusable border control style component - * - * @param {Object} props Component props - * @param {string} props.selector Property target selector - */ -const BorderRadius = ( { selector } ) => { - const { userConfig, themeConfig } = useContext( EditorContext ); - const { setUserConfig } = useContext( StylesContext ); - const value = getThemeOption( selector, themeConfig ); - - /** - * Handle changes to the border radius value - * - * @param {string} newValue The updated linked value - */ - const onChange = ( newValue ) => { - let config = structuredClone( userConfig ); - config = set( config, selector, newValue ); - setUserConfig( config ); - }; - - return ( - <> - - - ); -}; - -export default BorderRadius; From 209b859b7f22469bce7dc952172f1c8a21a2cff6 Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 6 Jan 2025 10:10:09 +0000 Subject: [PATCH 13/15] feat: replaces custom component and adds UI flex element for spacing --- src/editor/components/StylesBorder.js | 37 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index 9ecf05c1..eedad4b5 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -1,14 +1,16 @@ import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; import { useContext } from '@wordpress/element'; -import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; +import { + Flex, + __experimentalBorderBoxControl as BorderBoxControl, +} from '@wordpress/components'; +import { __experimentalBorderRadiusControl as BorderRadiusControl } from '@wordpress/block-editor'; import getThemeOption from '../../utils/get-theme-option'; import EditorContext from '../context/EditorContext'; import StylesContext from '../context/StylesContext'; -import StylesBorderRadius from './StylesBorderRadius'; - /** * Reusable border control style component * @@ -24,6 +26,11 @@ const Border = ( { selector } ) => { themeConfig ); + /** + * General handler for border changes + * + * @param {Object} newValue - Updated border values + */ const onChange = ( newValue ) => { // If the value has a radius, we need to merge it with the new value const valueRadius = value?.radius; @@ -41,13 +48,24 @@ const Border = ( { selector } ) => { setUserConfig( config ); }; + /** + * Specific handler for radius changes + * + * @param {Object} newValue - Updated radius values + */ + const onRadiusChange = ( newValue ) => { + let config = structuredClone( userConfig ); + config = set( config, `${ selector }.radius`, newValue ); + setUserConfig( config ); + }; + return ( <> - { __( 'Border and radius', 'themer' ) } + { __( 'Border', 'themer' ) }
-
+ { __( 'Border', 'themer' ) } @@ -56,12 +74,11 @@ const Border = ( { selector } ) => { onChange={ onChange } value={ value } /> -
+
- onRadiusChange( newValue ) } />
From 527cf70ad52065cdc745736a6c369b7153e39cac Mon Sep 17 00:00:00 2001 From: Richard Walker Date: Mon, 6 Jan 2025 10:26:45 +0000 Subject: [PATCH 14/15] fix: addresses a bug when a radius value is undefined --- src/editor/components/StylesBorder.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index eedad4b5..9fa1bd06 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -54,6 +54,18 @@ const Border = ( { selector } ) => { * @param {Object} newValue - Updated radius values */ const onRadiusChange = ( newValue ) => { + /** + * If the updated value is an object, ensure a value is present for each radius point. + * If no value is present, set it to 0. + * This avoids display issues when a radius value is missing. + */ + if ( typeof newValue === 'object' ) { + newValue.topLeft = newValue.topLeft ?? 0; + newValue.topRight = newValue.topRight ?? 0; + newValue.bottomRight = newValue.bottomRight ?? 0; + newValue.bottomLeft = newValue.bottomLeft ?? 0; + } + let config = structuredClone( userConfig ); config = set( config, `${ selector }.radius`, newValue ); setUserConfig( config ); From 56a9c5fe6d44e03442a1770610f8c837d5cc49b3 Mon Sep 17 00:00:00 2001 From: Gareth Elwell <41474928+g-elwell@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:50:18 +0000 Subject: [PATCH 15/15] fix: prevent error when no border radius value is defined --- src/editor/components/StylesBorder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/components/StylesBorder.js b/src/editor/components/StylesBorder.js index 9fa1bd06..81d96d7a 100644 --- a/src/editor/components/StylesBorder.js +++ b/src/editor/components/StylesBorder.js @@ -89,7 +89,7 @@ const Border = ( { selector } ) => {
onRadiusChange( newValue ) } />