Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a context provider for global styles config #35622

Merged
merged 2 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { store as editSiteStore } from '../../store';
*/
import { useGlobalStylesOutput } from '../global-styles/use-global-styles-output';

export function useGlobalStylesRenderer() {
function useGlobalStylesRenderer() {
const [ styles, settings ] = useGlobalStylesOutput();
const { getSettings } = useSelect( editSiteStore );
const { updateSettings } = useDispatch( editSiteStore );
Expand All @@ -35,3 +35,9 @@ export function useGlobalStylesRenderer() {
} );
}, [ styles, settings ] );
}

export function GlobalStylesRenderer() {
useGlobalStylesRenderer();

return null;
}
170 changes: 88 additions & 82 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import ErrorBoundary from '../error-boundary';
import { store as editSiteStore } from '../../store';
import { useGlobalStylesRenderer } from './global-styles-renderer';
import { GlobalStylesRenderer } from './global-styles-renderer';
import { GlobalStylesProvider } from '../global-styles/global-styles-provider';

const interfaceLabels = {
secondarySidebar: __( 'Block Library' ),
Expand Down Expand Up @@ -159,8 +160,6 @@ function Editor( { initialSettings, onError } ) {
}
}, [ isNavigationOpen ] );

useGlobalStylesRenderer();

// Don't render the Editor until the settings are set and loaded
if ( ! settings?.siteUrl ) {
return null;
Expand All @@ -186,87 +185,94 @@ function Editor( { initialSettings, onError } ) {
type={ templateType }
id={ entityId }
>
<BlockContextProvider value={ blockContext }>
<ErrorBoundary onError={ onError }>
<FullscreenMode isActive />
<UnsavedChangesWarning />
<KeyboardShortcuts.Register />
<SidebarComplementaryAreaFills />
<InterfaceSkeleton
labels={ interfaceLabels }
drawer={ <NavigationSidebar /> }
secondarySidebar={ secondarySidebar() }
sidebar={
sidebarIsOpened && (
<ComplementaryArea.Slot scope="core/edit-site" />
)
}
header={
<Header
openEntitiesSavedStates={
openEntitiesSavedStates
}
/>
}
notices={ <EditorSnackbars /> }
content={
<>
<EditorNotices />
{ template && (
<BlockEditor
setIsInserterOpen={
setIsInserterOpened
}
/>
) }
{ templateResolved &&
! template &&
settings?.siteUrl &&
entityId && (
<Notice
status="warning"
isDismissible={ false }
>
{ __(
"You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
) }
</Notice>
<GlobalStylesProvider>
<BlockContextProvider value={ blockContext }>
<GlobalStylesRenderer />
<ErrorBoundary onError={ onError }>
<FullscreenMode isActive />
<UnsavedChangesWarning />
<KeyboardShortcuts.Register />
<SidebarComplementaryAreaFills />
<InterfaceSkeleton
labels={ interfaceLabels }
drawer={ <NavigationSidebar /> }
secondarySidebar={ secondarySidebar() }
sidebar={
sidebarIsOpened && (
<ComplementaryArea.Slot scope="core/edit-site" />
)
}
header={
<Header
openEntitiesSavedStates={
openEntitiesSavedStates
}
/>
}
notices={ <EditorSnackbars /> }
content={
<>
<EditorNotices />
{ template && (
<BlockEditor
setIsInserterOpen={
setIsInserterOpened
}
/>
) }
<KeyboardShortcuts />
</>
}
actions={
<>
{ isEntitiesSavedStatesOpen ? (
<EntitiesSavedStates
close={
closeEntitiesSavedStates
}
/>
) : (
<div className="edit-site-editor__toggle-save-panel">
<Button
variant="secondary"
className="edit-site-editor__toggle-save-panel-button"
onClick={
openEntitiesSavedStates
{ templateResolved &&
! template &&
settings?.siteUrl &&
entityId && (
<Notice
status="warning"
isDismissible={
false
}
>
{ __(
"You attempted to edit an item that doesn't exist. Perhaps it was deleted?"
) }
</Notice>
) }
<KeyboardShortcuts />
</>
}
actions={
<>
{ isEntitiesSavedStatesOpen ? (
<EntitiesSavedStates
close={
closeEntitiesSavedStates
}
aria-expanded={ false }
>
{ __(
'Open save panel'
) }
</Button>
</div>
) }
</>
}
footer={ <BlockBreadcrumb /> }
/>
<Popover.Slot />
<PluginArea />
</ErrorBoundary>
</BlockContextProvider>
/>
) : (
<div className="edit-site-editor__toggle-save-panel">
<Button
variant="secondary"
className="edit-site-editor__toggle-save-panel-button"
onClick={
openEntitiesSavedStates
}
aria-expanded={
false
}
>
{ __(
'Open save panel'
) }
</Button>
</div>
) }
</>
}
footer={ <BlockBreadcrumb /> }
/>
<Popover.Slot />
<PluginArea />
</ErrorBoundary>
</BlockContextProvider>
</GlobalStylesProvider>
</EntityProvider>
</EntityProvider>
</SlotFillProvider>
Expand Down
15 changes: 15 additions & 0 deletions packages/edit-site/src/components/global-styles/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* WordPress dependencies
*/
import { createContext } from '@wordpress/element';

export const DEFAULT_GLOBAL_STYLES_CONTEXT = {
user: {},
base: {},
merged: {},
setUserConfig: () => {},
};

export const GlobalStylesContext = createContext(
DEFAULT_GLOBAL_STYLES_CONTEXT
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/**
* External dependencies
*/
import { get, cloneDeep, set, mergeWith } from 'lodash';

/**
* WordPress dependencies
*/
import { useMemo, useCallback } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../store';
import { PRESET_METADATA } from './utils';
import { GlobalStylesContext } from './context';

function mergeTreesCustomizer( _, srcValue ) {
// We only pass as arrays the presets,
// in which case we want the new array of values
// to override the old array (no merging).
if ( Array.isArray( srcValue ) ) {
return srcValue;
}
}

function mergeBaseAndUserConfigs( base, user ) {
return mergeWith( {}, base, user, mergeTreesCustomizer );
}

function addUserOriginToSettings( settingsToAdd ) {
const newSettings = cloneDeep( settingsToAdd );
PRESET_METADATA.forEach( ( { path } ) => {
const presetData = get( newSettings, path );
if ( presetData ) {
set( newSettings, path, {
user: presetData,
} );
}
} );
return newSettings;
}

function removeUserOriginFromSettings( settingsToRemove ) {
const newSettings = cloneDeep( settingsToRemove );
PRESET_METADATA.forEach( ( { path } ) => {
const presetData = get( newSettings, path );
if ( presetData ) {
set( newSettings, path, ( presetData ?? {} ).user );
}
} );
return newSettings;
}

function useGlobalStylesUserConfig() {
const { globalStylesId, content } = useSelect( ( select ) => {
const _globalStylesId = select( editSiteStore ).getSettings()
.__experimentalGlobalStylesUserEntityId;
return {
globalStylesId: _globalStylesId,
content: select( coreStore ).getEditedEntityRecord(
'postType',
'wp_global_styles',
_globalStylesId
)?.content,
};
}, [] );
const { getEditedEntityRecord } = useSelect( coreStore );
const { editEntityRecord } = useDispatch( coreStore );

const parseContent = ( contentToParse ) => {
let parsedConfig;
try {
parsedConfig = contentToParse ? JSON.parse( contentToParse ) : {};
// It is very important to verify if the flag isGlobalStylesUserThemeJSON is true.
// If it is not true the content was not escaped and is not safe.
if ( ! parsedConfig.isGlobalStylesUserThemeJSON ) {
parsedConfig = {};
} else {
parsedConfig = {
...parsedConfig,
settings: addUserOriginToSettings( parsedConfig.settings ),
};
}
} catch ( e ) {
/* eslint-disable no-console */
console.error( 'Global Styles User data is not valid' );
console.error( e );
/* eslint-enable no-console */
parsedConfig = {};
}

return parsedConfig;
};

const config = useMemo( () => {
return parseContent( content );
}, [ content ] );

const setConfig = useCallback(
( callback ) => {
const currentConfig = parseContent(
getEditedEntityRecord(
'postType',
'wp_global_styles',
globalStylesId
)?.content
);
const updatedConfig = callback( currentConfig );
editEntityRecord( 'postType', 'wp_global_styles', globalStylesId, {
content: JSON.stringify( {
...updatedConfig,
settings: removeUserOriginFromSettings(
updatedConfig.settings
),
} ),
} );
},
[ globalStylesId ]
);

return [ config, setConfig ];
}

function useGlobalStylesBaseConfig() {
const baseConfig = useSelect( ( select ) => {
return select( editSiteStore ).getSettings()
.__experimentalGlobalStylesBaseConfig;
}, [] );

return baseConfig;
}

function useGlobalStylesContext() {
const [ userConfig, setUserConfig ] = useGlobalStylesUserConfig();
const baseConfig = useGlobalStylesBaseConfig();
const mergedConfig = useMemo( () => {
return mergeBaseAndUserConfigs( baseConfig, userConfig );
}, [ userConfig, baseConfig ] );
const context = useMemo( () => {
return {
user: userConfig,
base: baseConfig,
merged: mergedConfig,
setUserConfig,
};
}, [ mergedConfig, userConfig, baseConfig, setUserConfig ] );

return context;
}

export function GlobalStylesProvider( { children } ) {
const context = useGlobalStylesContext();

return (
<GlobalStylesContext.Provider value={ context }>
{ children }
</GlobalStylesContext.Provider>
);
}
Loading