From 53626590985e64a648da87b74f5584d5c932078a Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 21 Jul 2023 16:37:03 +0100 Subject: [PATCH 01/18] feat(schema-components): map properties to React components --- .../components/fields/ThemerComponent.js | 25 ++++++++ src/editor/context/EditorContext.js | 6 ++ src/editor/ui/components/styles/Border.js | 34 +++++++++++ src/editor/ui/utils/component-map.js | 13 +++++ src/editor/ui/utils/get-theme-option.js | 14 +++++ src/editor/ui/utils/schema-to-components.js | 57 +++++++++++++++++++ 6 files changed, 149 insertions(+) create mode 100644 src/editor/context/EditorContext.js create mode 100644 src/editor/ui/components/styles/Border.js create mode 100644 src/editor/ui/utils/component-map.js create mode 100644 src/editor/ui/utils/get-theme-option.js create mode 100644 src/editor/ui/utils/schema-to-components.js diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index a0299d8..93a6c90 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -4,6 +4,9 @@ import { useSelect, dispatch } from '@wordpress/data'; import { useEffect, useState, useMemo } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; +import schemaComponents from '../../ui/utils/schema-to-components'; +import EditorContext from '../../context/EditorContext'; + import Preview from './Preview'; import Fields from './Fields'; import ResponsiveButton from './ResponsiveButton'; @@ -98,6 +101,18 @@ const ThemerComponent = () => { ); }; + /* TODO: refactor */ + const [ components, setComponents ] = useState( {} ); + useEffect( () => { + const generate = async () => { + const mappedComponents = await schemaComponents(); + setComponents( mappedComponents ); + }; + + generate(); + }, [] ); + const { border: Border } = components?.styles ?? {}; + if ( ! themeConfig || ! previewCss ) { return ( <> @@ -114,6 +129,16 @@ const ThemerComponent = () => {
+ { /* demo */ } + + + + { /* demo */ } { + const { globalStylesId, themeConfig } = useContext( EditorContext ); + const value = getThemeOption( selector, themeConfig ); + const colors = getThemeOption( 'settings.color.palette.theme', themeConfig ); + + const onChange = ( newValue ) => { + // need to update styles here with dispatch and globalStylesId + }; + + return ( + + ); +}; + +export default Border; diff --git a/src/editor/ui/utils/component-map.js b/src/editor/ui/utils/component-map.js new file mode 100644 index 0000000..3cd34ac --- /dev/null +++ b/src/editor/ui/utils/component-map.js @@ -0,0 +1,13 @@ +import Border from '../components/styles/Border'; + +/** + * Style properties and their corresponding React components + */ +export const styleComponentMap = { + border: Border, +}; + +/** + * Settings properties and their corresponding React components + */ +export const settingComponentMap = {}; diff --git a/src/editor/ui/utils/get-theme-option.js b/src/editor/ui/utils/get-theme-option.js new file mode 100644 index 0000000..824c6e5 --- /dev/null +++ b/src/editor/ui/utils/get-theme-option.js @@ -0,0 +1,14 @@ +/** + * Returns the value of the specified selector from the base object + * + * @param {string} selector Property target selector + * @param {object} base Theme settings + * + * @returns {*} Value of selector + */ +const getThemeOption = ( selector, base ) => { + const selectorArray = selector.split( '.' ); + return selectorArray.reduce( ( acc, curr ) => acc[ curr ], base ); +}; + +export default getThemeOption; diff --git a/src/editor/ui/utils/schema-to-components.js b/src/editor/ui/utils/schema-to-components.js new file mode 100644 index 0000000..fa84068 --- /dev/null +++ b/src/editor/ui/utils/schema-to-components.js @@ -0,0 +1,57 @@ +import { styleComponentMap } from './component-map'; + +/** + * Maps style properties to React components + * + * @param {object} components Theme to React component map + * @param {object} properties Theme style allowed properties + */ +const generateStyleComponents = ( components, properties ) => { + if ( ! properties ) { + return; + } + + for ( const property in properties ) { + const style = styleComponentMap?.[ property ]; + + if ( ! style ) { + continue; + } + + components.styles[ property ] = style; + } +}; + +/** + * Generates React components for parts of the theme.json schema + * + * @returns {object} Mapped components + */ +const schemaComponents = async () => { + const url = + 'https://raw.githubusercontent.com/WordPress/gutenberg/trunk/schemas/json/theme.json'; + + try { + const response = await fetch( url ); + const components = { settings: {}, styles: {} }; + + if ( ! response?.ok ) { + throw new Error( + `${ response?.status } ${ response?.statusText }` + ); + } + + const schema = await response.json(); + + generateStyleComponents( + components, + schema?.definitions?.stylesProperties?.properties + ); + + return components; + } catch ( error ) { + console.error( error ); // eslint-disable-line no-console -- Output of caught error + } +}; + +export default schemaComponents; From 308b83d5db09f9a8a0ca4005bb0bcc0a860f0abb Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 21 Jul 2023 16:42:37 +0100 Subject: [PATCH 02/18] chore(linting): correct comment parameters and formatting --- src/editor/ui/components/styles/Border.js | 7 +++++-- src/editor/ui/utils/get-theme-option.js | 4 ++-- src/editor/ui/utils/schema-to-components.js | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index 9fc2982..8003365 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -9,13 +9,16 @@ import EditorContext from '../../../context/EditorContext'; /** * Reusable border control style component * - * @param {object} props Component props + * @param {Object} props Component props * @param {string} props.selector Property target selector */ const Border = ( { selector } ) => { const { globalStylesId, themeConfig } = useContext( EditorContext ); const value = getThemeOption( selector, themeConfig ); - const colors = getThemeOption( 'settings.color.palette.theme', themeConfig ); + const colors = getThemeOption( + 'settings.color.palette.theme', + themeConfig + ); const onChange = ( newValue ) => { // need to update styles here with dispatch and globalStylesId diff --git a/src/editor/ui/utils/get-theme-option.js b/src/editor/ui/utils/get-theme-option.js index 824c6e5..1418b56 100644 --- a/src/editor/ui/utils/get-theme-option.js +++ b/src/editor/ui/utils/get-theme-option.js @@ -2,9 +2,9 @@ * Returns the value of the specified selector from the base object * * @param {string} selector Property target selector - * @param {object} base Theme settings + * @param {Object} base Theme settings * - * @returns {*} Value of selector + * @return {*} Value of selector */ const getThemeOption = ( selector, base ) => { const selectorArray = selector.split( '.' ); diff --git a/src/editor/ui/utils/schema-to-components.js b/src/editor/ui/utils/schema-to-components.js index fa84068..de42bfb 100644 --- a/src/editor/ui/utils/schema-to-components.js +++ b/src/editor/ui/utils/schema-to-components.js @@ -3,8 +3,8 @@ import { styleComponentMap } from './component-map'; /** * Maps style properties to React components * - * @param {object} components Theme to React component map - * @param {object} properties Theme style allowed properties + * @param {Object} components Theme to React component map + * @param {Object} properties Theme style allowed properties */ const generateStyleComponents = ( components, properties ) => { if ( ! properties ) { @@ -25,7 +25,7 @@ const generateStyleComponents = ( components, properties ) => { /** * Generates React components for parts of the theme.json schema * - * @returns {object} Mapped components + * @return {Object} Mapped components */ const schemaComponents = async () => { const url = From 985e14669031a639595bdaa5f78dfdf64bdaa4f1 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Jul 2023 10:54:39 +0100 Subject: [PATCH 03/18] chore(schema-component-save): experimental schema component save --- .../components/fields/ThemerComponent.js | 5 +- src/editor/ui/components/styles/Border.js | 46 ++++++++++++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index 93a6c90..9eb758b 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -123,6 +123,7 @@ const ThemerComponent = () => { return ( <> +
{ const { globalStylesId, themeConfig } = useContext( EditorContext ); - const value = getThemeOption( selector, themeConfig ); + console.log( + 'pullquote border', + themeConfig?.styles?.blocks?.[ 'core/pullquote' ]?.border + ); + const colors = getThemeOption( 'settings.color.palette.theme', themeConfig ); + const value = getThemeOption( selector, themeConfig ); + + const [ text, setText ] = useState( value ); + const context = { ...{} }; + + /** + * updates entity record on field edit + * + * @param {*} newValue + */ + const edit = ( newValue ) => { + const updated = set( context, selector, newValue ); + const newObj = merge( themeConfig, updated ); + dispatch( 'core' ).editEntityRecord( + 'root', + 'globalStyles', + globalStylesId, + { + styles: newObj.styles || {}, + settings: newObj.settings || {}, + } + ); + }; - const onChange = ( newValue ) => { - // need to update styles here with dispatch and globalStylesId + /** + * gets field path and value and passes to edit + * + * @param {Event} e Change event. + */ + const onChange = ( e ) => { + setText( e ); + edit( e ); }; return ( @@ -29,7 +63,7 @@ const Border = ( { selector } ) => { colors={ colors } label={ __( 'Borders', 'default' ) } onChange={ onChange } - value={ value } + value={ text || value } /> ); }; From 3ffe8b003193cb13a81d825362dc3966fb84231c Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Jul 2023 20:02:12 +0100 Subject: [PATCH 04/18] refactor(schema-component-save): test new way to save from Border component --- src/editor/ui/components/styles/Border.js | 53 +++++++---------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index d5530f1..190d792 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -1,7 +1,7 @@ -import { set, merge } from 'lodash'; +import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; -import { select, dispatch } from '@wordpress/data'; -import { useContext, useState } from '@wordpress/element'; +import { dispatch } from '@wordpress/data'; +import { useContext, useState, useEffect } from '@wordpress/element'; import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; import getThemeOption from '../../utils/get-theme-option'; @@ -15,55 +15,32 @@ import EditorContext from '../../../context/EditorContext'; */ const Border = ( { selector } ) => { const { globalStylesId, themeConfig } = useContext( EditorContext ); - console.log( - 'pullquote border', - themeConfig?.styles?.blocks?.[ 'core/pullquote' ]?.border - ); - - const colors = getThemeOption( - 'settings.color.palette.theme', - themeConfig - ); const value = getThemeOption( selector, themeConfig ); + const colors = getThemeOption( 'settings.color.palette.theme', themeConfig ); + const [ borders, setBorders ] = useState( value ); - const [ text, setText ] = useState( value ); - const context = { ...{} }; + const onChange = ( newValue ) => { + setBorders( newValue ); + }; - /** - * updates entity record on field edit - * - * @param {*} newValue - */ - const edit = ( newValue ) => { - const updated = set( context, selector, newValue ); - const newObj = merge( themeConfig, updated ); + useEffect( () => { + let config = structuredClone( themeConfig ); + config = set( config, selector, {} ); + config = set( config, selector, borders ); dispatch( 'core' ).editEntityRecord( 'root', 'globalStyles', globalStylesId, - { - styles: newObj.styles || {}, - settings: newObj.settings || {}, - } + config ); - }; - - /** - * gets field path and value and passes to edit - * - * @param {Event} e Change event. - */ - const onChange = ( e ) => { - setText( e ); - edit( e ); - }; + }, [ borders ] ); return ( ); }; From b9ede81271ced930e15f10846e24a3cc30be5d1a Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Jul 2023 20:06:06 +0100 Subject: [PATCH 05/18] chore: removes undo dispatch on save --- src/editor/components/fields/ThemerComponent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index 9eb758b..814a256 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -76,7 +76,7 @@ const ThemerComponent = () => { * saves edited entity data */ const save = async () => { - dispatch( 'core' ).undo(); + // dispatch( 'core' ).undo(); try { await dispatch( 'core' ).saveEditedEntityRecord( 'root', From 84b3bc58ec61faf0bdb481c5ecdc8d1a25d8a185 Mon Sep 17 00:00:00 2001 From: Scott Blackburn Date: Mon, 31 Jul 2023 14:00:13 +0100 Subject: [PATCH 06/18] adds: save moved to context --- .../components/fields/ThemerComponent.js | 12 ++++++++++ src/editor/context/StylesContext.js | 6 +++++ src/editor/ui/components/styles/Border.js | 23 ++++++++++++------- 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/editor/context/StylesContext.js diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index 814a256..fd69bc5 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -19,6 +19,17 @@ const ThemerComponent = () => { const [ previewCss, setPreviewCss ] = useState( '' ); const [ previewSize, setPreviewSize ] = useState(); + const setUserConfig = ( config ) => { + console.log( 'set user config at wrapper level' ); + + dispatch( 'core' ).editEntityRecord( + 'root', + 'globalStyles', + globalStylesId, + config + ); + }; + const { globalStylesId, baseConfig, userConfig } = useSelect( ( select ) => { const { @@ -135,6 +146,7 @@ const ThemerComponent = () => { value={ { globalStylesId, themeConfig, + setUserConfig, } } > diff --git a/src/editor/context/StylesContext.js b/src/editor/context/StylesContext.js new file mode 100644 index 0000000..0fb0b0d --- /dev/null +++ b/src/editor/context/StylesContext.js @@ -0,0 +1,6 @@ +import { createContext } from '@wordpress/element'; + +/** + * Sets a default context for use as state management across the plugin + */ +export default createContext(); diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index 190d792..bf237d4 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -14,9 +14,13 @@ import EditorContext from '../../../context/EditorContext'; * @param {string} props.selector Property target selector */ const Border = ( { selector } ) => { - const { globalStylesId, themeConfig } = useContext( EditorContext ); + const { globalStylesId, themeConfig, setUserConfig } = + useContext( EditorContext ); const value = getThemeOption( selector, themeConfig ); - const colors = getThemeOption( 'settings.color.palette.theme', themeConfig ); + const colors = getThemeOption( + 'settings.color.palette.theme', + themeConfig + ); const [ borders, setBorders ] = useState( value ); const onChange = ( newValue ) => { @@ -27,12 +31,15 @@ const Border = ( { selector } ) => { let config = structuredClone( themeConfig ); config = set( config, selector, {} ); config = set( config, selector, borders ); - dispatch( 'core' ).editEntityRecord( - 'root', - 'globalStyles', - globalStylesId, - config - ); + + setUserConfig( config ); + + // dispatch( 'core' ).editEntityRecord( + // 'root', + // 'globalStyles', + // globalStylesId, + // config + // ); }, [ borders ] ); return ( From e2ead40530e305cee49d4aa5fc50dbb46c549d06 Mon Sep 17 00:00:00 2001 From: Scott Blackburn Date: Mon, 31 Jul 2023 14:47:48 +0100 Subject: [PATCH 07/18] adds: correct usage of styles context --- src/editor/components/fields/ThemerComponent.js | 12 ++++++++---- src/editor/ui/components/styles/Border.js | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index fd69bc5..32e7098 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -6,6 +6,7 @@ import apiFetch from '@wordpress/api-fetch'; import schemaComponents from '../../ui/utils/schema-to-components'; import EditorContext from '../../context/EditorContext'; +import StylesContext from '../../context/StylesContext'; import Preview from './Preview'; import Fields from './Fields'; @@ -20,8 +21,6 @@ const ThemerComponent = () => { const [ previewSize, setPreviewSize ] = useState(); const setUserConfig = ( config ) => { - console.log( 'set user config at wrapper level' ); - dispatch( 'core' ).editEntityRecord( 'root', 'globalStyles', @@ -146,10 +145,15 @@ const ThemerComponent = () => { value={ { globalStylesId, themeConfig, - setUserConfig, } } > - + + + { /* demo */ } { /* { - const { globalStylesId, themeConfig, setUserConfig } = - useContext( EditorContext ); + const { globalStylesId, themeConfig } = useContext( EditorContext ); + const { setUserConfig } = useContext( StylesContext ); const value = getThemeOption( selector, themeConfig ); const colors = getThemeOption( 'settings.color.palette.theme', From 13fdbec0bf103892aad92252037cc34fe38f3611 Mon Sep 17 00:00:00 2001 From: Scott Blackburn Date: Tue, 1 Aug 2023 08:55:23 +0100 Subject: [PATCH 08/18] removes: unused comments from border ui --- src/editor/ui/components/styles/Border.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index 2de1642..b7bdf3b 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -34,13 +34,6 @@ const Border = ( { selector } ) => { config = set( config, selector, borders ); setUserConfig( config ); - - // dispatch( 'core' ).editEntityRecord( - // 'root', - // 'globalStyles', - // globalStylesId, - // config - // ); }, [ borders ] ); return ( From 1b3ca141a69820b2993126844cafc8b84971c116 Mon Sep 17 00:00:00 2001 From: Scott Blackburn Date: Tue, 1 Aug 2023 09:42:26 +0100 Subject: [PATCH 09/18] adds: tidy up of lint issues across border and theme wrapper --- src/editor/components/fields/ThemerComponent.js | 3 +-- src/editor/ui/components/styles/Border.js | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index 32e7098..3e87a6b 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -1,5 +1,5 @@ import { mergeWith, isEmpty } from 'lodash'; -import { Button, Spinner, TabPanel } from '@wordpress/components'; +import { Button, Spinner } from '@wordpress/components'; import { useSelect, dispatch } from '@wordpress/data'; import { useEffect, useState, useMemo } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; @@ -9,7 +9,6 @@ import EditorContext from '../../context/EditorContext'; import StylesContext from '../../context/StylesContext'; import Preview from './Preview'; -import Fields from './Fields'; import ResponsiveButton from './ResponsiveButton'; import ButtonExport from '../ButtonExport'; diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index b7bdf3b..c899bef 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -1,6 +1,5 @@ import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; -import { dispatch } from '@wordpress/data'; import { useContext, useState, useEffect } from '@wordpress/element'; import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; @@ -8,6 +7,8 @@ import getThemeOption from '../../utils/get-theme-option'; import EditorContext from '../../../context/EditorContext'; import StylesContext from '../../../context/StylesContext'; +/* eslint-disable @wordpress/no-unsafe-wp-apis */ + /** * Reusable border control style component * @@ -15,7 +16,7 @@ import StylesContext from '../../../context/StylesContext'; * @param {string} props.selector Property target selector */ const Border = ( { selector } ) => { - const { globalStylesId, themeConfig } = useContext( EditorContext ); + const { themeConfig } = useContext( EditorContext ); const { setUserConfig } = useContext( StylesContext ); const value = getThemeOption( selector, themeConfig ); const colors = getThemeOption( @@ -34,12 +35,12 @@ const Border = ( { selector } ) => { config = set( config, selector, borders ); setUserConfig( config ); - }, [ borders ] ); + }, [ borders, selector, setUserConfig ] ); return ( From 966c928e3b4a8de4f49a1cd7ab14f5ef2195a1e0 Mon Sep 17 00:00:00 2001 From: Scott Blackburn Date: Tue, 1 Aug 2023 09:45:49 +0100 Subject: [PATCH 10/18] adds: linting fixes --- src/editor/ui/components/styles/Border.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index c899bef..4427676 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -1,3 +1,5 @@ +/* eslint-disable @wordpress/no-unsafe-wp-apis */ + import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; import { useContext, useState, useEffect } from '@wordpress/element'; @@ -7,8 +9,6 @@ import getThemeOption from '../../utils/get-theme-option'; import EditorContext from '../../../context/EditorContext'; import StylesContext from '../../../context/StylesContext'; -/* eslint-disable @wordpress/no-unsafe-wp-apis */ - /** * Reusable border control style component * @@ -35,7 +35,7 @@ const Border = ( { selector } ) => { config = set( config, selector, borders ); setUserConfig( config ); - }, [ borders, selector, setUserConfig ] ); + }, [ borders, selector, setUserConfig, themeConfig ] ); return ( Date: Tue, 1 Aug 2023 11:39:06 +0100 Subject: [PATCH 11/18] remove: hook deps to test perofrmance --- src/editor/ui/components/styles/Border.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index 4427676..53de945 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -35,7 +35,7 @@ const Border = ( { selector } ) => { config = set( config, selector, borders ); setUserConfig( config ); - }, [ borders, selector, setUserConfig, themeConfig ] ); + }, [ borders ] ); return ( Date: Mon, 7 Aug 2023 14:31:01 +0100 Subject: [PATCH 12/18] chore(save): remove commented out code --- src/editor/components/fields/ThemerComponent.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index 3e87a6b..c9dc1f3 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -85,7 +85,6 @@ const ThemerComponent = () => { * saves edited entity data */ const save = async () => { - // dispatch( 'core' ).undo(); try { await dispatch( 'core' ).saveEditedEntityRecord( 'root', From ff19703f9f8ab51d3a732c7ac6020788577b4c40 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 7 Aug 2023 15:16:38 +0100 Subject: [PATCH 13/18] chore(themer-component): removes inline preview css --- src/editor/components/fields/ThemerComponent.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/fields/ThemerComponent.js index c9dc1f3..b66144b 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/fields/ThemerComponent.js @@ -131,7 +131,6 @@ const ThemerComponent = () => { return ( <> -
-
-
- { /* demo */ } - - - - - - { /* demo */ } - { /* - { ( tab ) => ( - <> -

{ tab.title }

- - - ) } -
*/ } -
-
- - - -
-
+ + +
+
+
+
+ + { ( tab ) => ( + <> +

{ tab.title }

+ + + + ) } +
+
+
+ + + +
+
+
+
); }; From 7dafb9650c7403f3e89b09d3d49fe49b26104558 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 7 Aug 2023 16:09:34 +0100 Subject: [PATCH 15/18] refactor(border-component): usage of context for component values Removed usage of useState for internal component state due to this state being unaffected by the global Reset button --- src/editor/ui/components/styles/Border.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/ui/components/styles/Border.js index 53de945..be87026 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/ui/components/styles/Border.js @@ -2,7 +2,7 @@ import { set } from 'lodash'; import { __ } from '@wordpress/i18n'; -import { useContext, useState, useEffect } from '@wordpress/element'; +import { useContext } from '@wordpress/element'; import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; import getThemeOption from '../../utils/get-theme-option'; @@ -23,26 +23,20 @@ const Border = ( { selector } ) => { 'settings.color.palette.theme', themeConfig ); - const [ borders, setBorders ] = useState( value ); const onChange = ( newValue ) => { - setBorders( newValue ); - }; - - useEffect( () => { let config = structuredClone( themeConfig ); config = set( config, selector, {} ); - config = set( config, selector, borders ); - + config = set( config, selector, newValue ); setUserConfig( config ); - }, [ borders ] ); + }; return ( ); }; From 36169b9f56f34c1bf2166c62d03c2b06d0b25511 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 8 Aug 2023 22:27:00 +0100 Subject: [PATCH 16/18] feat(blocks): implements the blocks tab - border style component implemented for all supported blocks - placeholder tab components created - placeholder style components created - removal of uneeded files and code - file and folder restructure - new search component --- src/editor/components/Blocks.js | 41 ++++++ src/editor/components/BlocksItem.js | 36 +++++ src/editor/components/Colours.js | 6 + src/editor/components/ComponentWrapper.js | 2 +- src/editor/components/CustomBlocks.js | 6 + src/editor/components/Layout.js | 6 + src/editor/components/{fields => }/Preview.js | 0 .../{fields => }/ResponsiveButton.js | 0 src/editor/components/Search.js | 24 ++++ .../Border.js => components/StylesBorder.js} | 7 +- src/editor/components/StylesColour.js | 12 ++ src/editor/components/StylesDimensions.js | 12 ++ src/editor/components/StylesFilter.js | 12 ++ src/editor/components/StylesOutline.js | 12 ++ src/editor/components/StylesShadow.js | 12 ++ src/editor/components/StylesSpacing.js | 12 ++ src/editor/components/StylesTypography.js | 12 ++ .../{fields => }/ThemerComponent.js | 71 ++++----- src/editor/components/Typography.js | 6 + src/editor/components/fields/ComponentMap.js | 72 ---------- .../fields/Components/FontPicker.js | 136 ------------------ .../fields/Components/SpacingControl.js | 77 ---------- src/editor/components/fields/Field.js | 73 ---------- src/editor/components/fields/Fields.js | 56 -------- src/editor/styles/components/blocks.scss | 37 +++++ src/editor/styles/components/search.scss | 9 ++ src/editor/styles/styles.scss | 12 +- src/utils/block-helpers.js | 15 ++ src/{editor/ui => }/utils/component-map.js | 6 +- src/{editor/ui => }/utils/get-theme-option.js | 2 +- .../ui => }/utils/schema-to-components.js | 0 31 files changed, 322 insertions(+), 462 deletions(-) create mode 100644 src/editor/components/Blocks.js create mode 100644 src/editor/components/BlocksItem.js create mode 100644 src/editor/components/Colours.js create mode 100644 src/editor/components/CustomBlocks.js create mode 100644 src/editor/components/Layout.js rename src/editor/components/{fields => }/Preview.js (100%) rename src/editor/components/{fields => }/ResponsiveButton.js (100%) create mode 100644 src/editor/components/Search.js rename src/editor/{ui/components/styles/Border.js => components/StylesBorder.js} (83%) create mode 100644 src/editor/components/StylesColour.js create mode 100644 src/editor/components/StylesDimensions.js create mode 100644 src/editor/components/StylesFilter.js create mode 100644 src/editor/components/StylesOutline.js create mode 100644 src/editor/components/StylesShadow.js create mode 100644 src/editor/components/StylesSpacing.js create mode 100644 src/editor/components/StylesTypography.js rename src/editor/components/{fields => }/ThemerComponent.js (77%) create mode 100644 src/editor/components/Typography.js delete mode 100644 src/editor/components/fields/ComponentMap.js delete mode 100644 src/editor/components/fields/Components/FontPicker.js delete mode 100644 src/editor/components/fields/Components/SpacingControl.js delete mode 100644 src/editor/components/fields/Field.js delete mode 100644 src/editor/components/fields/Fields.js create mode 100644 src/editor/styles/components/blocks.scss create mode 100644 src/editor/styles/components/search.scss create mode 100644 src/utils/block-helpers.js rename src/{editor/ui => }/utils/component-map.js (63%) rename src/{editor/ui => }/utils/get-theme-option.js (82%) rename src/{editor/ui => }/utils/schema-to-components.js (100%) diff --git a/src/editor/components/Blocks.js b/src/editor/components/Blocks.js new file mode 100644 index 0000000..0a7a8ae --- /dev/null +++ b/src/editor/components/Blocks.js @@ -0,0 +1,41 @@ +import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; + +import Search from './Search'; +import BlocksItem from './BlocksItem'; +import { getCoreBlocks } from '../../utils/block-helpers'; + +/** + * Blocks tab menu component + */ +const Blocks = () => { + const [ searchValue, setSearchValue ] = useState(); + + return ( +
+

{ __( 'Blocks', 'themer' ) }

+

+ { __( + 'Customise the appearance of specific blocks for the whole site.', + 'themer' + ) } +

+ + { getCoreBlocks()?.map( ( block ) => { + if ( + searchValue?.length > 0 && + ! ( + block?.title?.toLowerCase().includes( searchValue ) || + block?.name?.toLowerCase().includes( searchValue ) + ) + ) { + return false; + } + + return ; + } ) } +
+ ); +}; + +export default Blocks; diff --git a/src/editor/components/BlocksItem.js b/src/editor/components/BlocksItem.js new file mode 100644 index 0000000..ebfd598 --- /dev/null +++ b/src/editor/components/BlocksItem.js @@ -0,0 +1,36 @@ +import Border from './StylesBorder'; + +/** + * Individual block item + * + * @param {Object} props Component props + * @param {Object} props.block Block object + */ +const BlocksItem = ( { block } ) => { + if ( ! block?.name ) { + return; + } + + const blockSelector = [ 'styles', 'blocks', block?.name ]; + + return ( +
+ + + { block?.icon?.src } + { block?.title } + + +
+ { block?.supports?.__experimentalBorder && ( + + ) } +
+
+ ); +}; + +export default BlocksItem; diff --git a/src/editor/components/Colours.js b/src/editor/components/Colours.js new file mode 100644 index 0000000..c7ba6ff --- /dev/null +++ b/src/editor/components/Colours.js @@ -0,0 +1,6 @@ +/** + * Colours tab menu component + */ +const Colours = () =>

Colours Tab

; + +export default Colours; diff --git a/src/editor/components/ComponentWrapper.js b/src/editor/components/ComponentWrapper.js index be82459..31c5891 100644 --- a/src/editor/components/ComponentWrapper.js +++ b/src/editor/components/ComponentWrapper.js @@ -1,4 +1,4 @@ -import ThemerComponent from './fields/ThemerComponent'; +import ThemerComponent from './ThemerComponent'; /** * Wrapper for app diff --git a/src/editor/components/CustomBlocks.js b/src/editor/components/CustomBlocks.js new file mode 100644 index 0000000..b1d5c21 --- /dev/null +++ b/src/editor/components/CustomBlocks.js @@ -0,0 +1,6 @@ +/** + * Custom Blocks tab menu component + */ +const CustomBlock = () =>

Custom Block Tab

; + +export default CustomBlock; diff --git a/src/editor/components/Layout.js b/src/editor/components/Layout.js new file mode 100644 index 0000000..796dccb --- /dev/null +++ b/src/editor/components/Layout.js @@ -0,0 +1,6 @@ +/** + * Layout tab menu component + */ +const Layout = () =>

Layout Tab

; + +export default Layout; diff --git a/src/editor/components/fields/Preview.js b/src/editor/components/Preview.js similarity index 100% rename from src/editor/components/fields/Preview.js rename to src/editor/components/Preview.js diff --git a/src/editor/components/fields/ResponsiveButton.js b/src/editor/components/ResponsiveButton.js similarity index 100% rename from src/editor/components/fields/ResponsiveButton.js rename to src/editor/components/ResponsiveButton.js diff --git a/src/editor/components/Search.js b/src/editor/components/Search.js new file mode 100644 index 0000000..0725cff --- /dev/null +++ b/src/editor/components/Search.js @@ -0,0 +1,24 @@ +/** + * Search component + * + * @param {Object} props Component props + * @param {Function} props.setValue Input on change function + * @param {string} props.placeholder Placeholder attribute value + */ +const Search = ( { setValue, placeholder = 'Search' } ) => { + const handleSearch = ( event ) => { + setValue( event?.target?.value?.toLowerCase().trim() ); + }; + + return ( +

+ handleSearch( event ) } + placeholder={ placeholder } + /> +

+ ); +}; + +export default Search; diff --git a/src/editor/ui/components/styles/Border.js b/src/editor/components/StylesBorder.js similarity index 83% rename from src/editor/ui/components/styles/Border.js rename to src/editor/components/StylesBorder.js index be87026..826949c 100644 --- a/src/editor/ui/components/styles/Border.js +++ b/src/editor/components/StylesBorder.js @@ -6,16 +6,17 @@ import { useContext } from '@wordpress/element'; import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; import getThemeOption from '../../utils/get-theme-option'; -import EditorContext from '../../../context/EditorContext'; -import StylesContext from '../../../context/StylesContext'; +import EditorContext from '../context/EditorContext'; +import StylesContext from '../context/StylesContext'; /** * Reusable border control style component * * @param {Object} props Component props + * @param {*} props.settings Block support settings * @param {string} props.selector Property target selector */ -const Border = ( { selector } ) => { +const Border = ( { settings, selector } ) => { const { themeConfig } = useContext( EditorContext ); const { setUserConfig } = useContext( StylesContext ); const value = getThemeOption( selector, themeConfig ); diff --git a/src/editor/components/StylesColour.js b/src/editor/components/StylesColour.js new file mode 100644 index 0000000..dfa94c9 --- /dev/null +++ b/src/editor/components/StylesColour.js @@ -0,0 +1,12 @@ +/** + * Reusable colour control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Colour = ( { settings, selector } ) => { + return

Colour Component

; +}; + +export default Colour; diff --git a/src/editor/components/StylesDimensions.js b/src/editor/components/StylesDimensions.js new file mode 100644 index 0000000..7160b25 --- /dev/null +++ b/src/editor/components/StylesDimensions.js @@ -0,0 +1,12 @@ +/** + * Reusable dimensions control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Dimensions = ( { settings, selector } ) => { + return

Dimensions Component

; +}; + +export default Dimensions; diff --git a/src/editor/components/StylesFilter.js b/src/editor/components/StylesFilter.js new file mode 100644 index 0000000..ca93ebe --- /dev/null +++ b/src/editor/components/StylesFilter.js @@ -0,0 +1,12 @@ +/** + * Reusable filter control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Filter = ( { settings, selector } ) => { + return

Filter Component

; +}; + +export default Filter; diff --git a/src/editor/components/StylesOutline.js b/src/editor/components/StylesOutline.js new file mode 100644 index 0000000..cd47fb5 --- /dev/null +++ b/src/editor/components/StylesOutline.js @@ -0,0 +1,12 @@ +/** + * Reusable outline control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Outline = ( { settings, selector } ) => { + return

Outline Component

; +}; + +export default Outline; diff --git a/src/editor/components/StylesShadow.js b/src/editor/components/StylesShadow.js new file mode 100644 index 0000000..8352fe3 --- /dev/null +++ b/src/editor/components/StylesShadow.js @@ -0,0 +1,12 @@ +/** + * Reusable shadow control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Shadow = ( { settings, selector } ) => { + return

Shadow Component

; +}; + +export default Shadow; diff --git a/src/editor/components/StylesSpacing.js b/src/editor/components/StylesSpacing.js new file mode 100644 index 0000000..9681699 --- /dev/null +++ b/src/editor/components/StylesSpacing.js @@ -0,0 +1,12 @@ +/** + * Reusable spacing control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Spacing = ( { settings, selector } ) => { + return

Spacing Component

; +}; + +export default Spacing; diff --git a/src/editor/components/StylesTypography.js b/src/editor/components/StylesTypography.js new file mode 100644 index 0000000..ebfd16b --- /dev/null +++ b/src/editor/components/StylesTypography.js @@ -0,0 +1,12 @@ +/** + * Reusable typography control style component + * + * @param {Object} props Component props + * @param {*} props.settings Block support settings + * @param {string} props.selector Property target selector + */ +const Typography = ( { settings, selector } ) => { + return

Typography Component

; +}; + +export default Typography; diff --git a/src/editor/components/fields/ThemerComponent.js b/src/editor/components/ThemerComponent.js similarity index 77% rename from src/editor/components/fields/ThemerComponent.js rename to src/editor/components/ThemerComponent.js index e9bd417..0a69209 100644 --- a/src/editor/components/fields/ThemerComponent.js +++ b/src/editor/components/ThemerComponent.js @@ -4,14 +4,16 @@ import { useSelect, dispatch } from '@wordpress/data'; import { useEffect, useState, useMemo } from '@wordpress/element'; import apiFetch from '@wordpress/api-fetch'; -import schemaComponents from '../../ui/utils/schema-to-components'; -import EditorContext from '../../context/EditorContext'; -import StylesContext from '../../context/StylesContext'; - +import Blocks from './Blocks'; +import Layout from './Layout'; +import Colours from './Colours'; import Preview from './Preview'; +import Typography from './Typography'; +import CustomBlocks from './CustomBlocks'; +import ButtonExport from './ButtonExport'; import ResponsiveButton from './ResponsiveButton'; -import ButtonExport from '../ButtonExport'; -import Fields from '../fields/Fields'; +import EditorContext from '../context/EditorContext'; +import StylesContext from '../context/StylesContext'; /** * main component @@ -110,18 +112,6 @@ const ThemerComponent = () => { ); }; - /* TODO: refactor */ - const [ components, setComponents ] = useState( {} ); - useEffect( () => { - const generate = async () => { - const mappedComponents = await schemaComponents(); - setComponents( mappedComponents ); - }; - - generate(); - }, [] ); - const { border: Border } = components?.styles ?? {}; - if ( ! themeConfig || ! previewCss ) { return ( <> @@ -162,29 +152,42 @@ const ThemerComponent = () => { activeClass="active-themer-tab" tabs={ [ { - name: 'placeholder', - title: 'Placeholder', - className: 'placeholder', + name: 'typography', + title: 'Typography', + }, + { + name: 'colours', + title: 'Colours', + }, + { + name: 'layout', + title: 'Layout', }, { - name: 'placeholder2', - title: 'Placeholder 2', - className: 'placeholder2', + name: 'blocks', + title: 'Blocks', }, { - name: 'placeholder3', - title: 'Placeholder 3', - className: 'placeholder3', + name: 'custom-blocks', + title: 'Custom Blocks', }, ] } > - { ( tab ) => ( - <> -

{ tab.title }

- - - - ) } + { ( tab ) => { + switch ( tab?.name ) { + case 'colours': + return ; + case 'layout': + return ; + case 'blocks': + return ; + case 'custom-blocks': + return ; + case 'typography': + default: + return ; + } + } }
diff --git a/src/editor/components/Typography.js b/src/editor/components/Typography.js new file mode 100644 index 0000000..89a1137 --- /dev/null +++ b/src/editor/components/Typography.js @@ -0,0 +1,6 @@ +/** + * Typography tab menu component + */ +const Typography = () =>

Typography Tab

; + +export default Typography; diff --git a/src/editor/components/fields/ComponentMap.js b/src/editor/components/fields/ComponentMap.js deleted file mode 100644 index f896b95..0000000 --- a/src/editor/components/fields/ComponentMap.js +++ /dev/null @@ -1,72 +0,0 @@ -import { TextControl, ColorPicker } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; - -import FontPicker from './Components/FontPicker'; -import SpacingControl from './Components/SpacingControl'; - -/** - * Returns appropriate component depending on field type - * - * @param {Object} props - * @param {string} props.label - * @param {string} props.value - * @param {Function} props.onChange - */ -const ComponentMap = ( { label, value, onChange } ) => { - const { currentThemeBaseGlobalStyles } = useSelect( ( select ) => { - return { - currentThemeBaseGlobalStyles: - select( - 'core' - ).__experimentalGetCurrentThemeBaseGlobalStyles(), - }; - } ); - - const colorPickerArray = [ 'background', 'text' ]; - const fontPickerArray = [ - 'fontFamily', - 'fontSize', - 'lineHeight', - 'textDecoration', - ]; - const blockGapArray = [ 'blockGap', 'top', 'right', 'bottom', 'left' ]; - - switch ( true ) { - case colorPickerArray.includes( label ): - return ( - onChange( val ) } - /> - ); - case fontPickerArray.includes( label ): - return ( -
- onChange( val ) } - base={ currentThemeBaseGlobalStyles } - /> -
- ); - case blockGapArray.includes( label ): - return ( - onChange( val ) } - base={ currentThemeBaseGlobalStyles } - /> - ); - default: - return ( - onChange( val ) } - /> - ); - } -}; - -export default ComponentMap; diff --git a/src/editor/components/fields/Components/FontPicker.js b/src/editor/components/fields/Components/FontPicker.js deleted file mode 100644 index ac4c4ac..0000000 --- a/src/editor/components/fields/Components/FontPicker.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * This component requires use of experimental apis - */ - -/* eslint-disable @wordpress/no-unsafe-wp-apis */ - -import { - FontSizePicker, - SelectControl, - Button, - __experimentalInputControl as InputControl, - __experimentalToggleGroupControl as ToggleGroup, - __experimentalToggleGroupControlOptionIcon as ToggleIcon, -} from '@wordpress/components'; - -/** - * returns component for font options - * - * @param {Object} props - * @param {Object} props.base - * @param {string} props.id - * @param {string|string[]} props.value - * @param {Function} props.onChange - */ -const FontPicker = ( { base, id, value, onChange } ) => { - /** - * returns preset font sizes from theme.json - */ - const getFontSizes = () => { - const sizes = base?.settings?.typography?.fontSizes?.theme; - return sizes; - }; - - /** - * returns preset font families from theme.json - */ - const getFontFamilies = () => { - const fonts = base?.settings?.typography?.fontFamilies?.theme; - const result = []; - fonts.forEach( ( item ) => { - // eslint-disable-next-line no-param-reassign -- remove '-' from slug to use as title - item.slug = item.slug.replace( /\s+/g, '-' ); - result.push( { - value: item.slug, - label: item.name, - } ); - } ); - return result; - }; - - /** - * handles line height incremental input - * - * @param {number} val - * @param {string} dir - */ - const getLineHeight = ( val, dir ) => { - let increment; - if ( dir === 'minus' ) { - increment = -0.1; - } else increment = 0.1; - const number = parseFloat( val ); - const result = parseFloat( number + increment ) - .toFixed( 1 ) - .toString(); - return result; - }; - - switch ( id ) { - case 'fontSize': - return ( - onChange( val ) } - /> - ); - case 'fontFamily': - return ( - onChange( val ) } - /> - ); - case 'lineHeight': - return ( - onChange( val ) } - suffix={ - <> -