Skip to content

Commit

Permalink
Add color and typography presets to Global Styles (#56622)
Browse files Browse the repository at this point in the history
* Add colors and typography to the styles tab

* refactor

* refactor

* Add font family names

* add heading and body previews

* use palettes

* make typograpgy a grid

* make the styles look nicer

* move component to its own file

* move color and type variations to different locations in the UI

* revert

* revert

* revert

* revert

* code dedupe

* Add typesets

* reorg typogrpahy

* tidy up

* tidy up code

* restyle color palettes

* restyle color palettes

* remove typesets

* add padding back

* refactor

* Show theme_name + style where there is no typography font family info.
Remove unused file.

* Consolidating logic into a hook phase 1

* 2022 borks getFamilyPreviewStyle because `face.fontStyle` doesn't exist

* comments

* Filtering results

* Create new convenience hook `useCurrentMergeThemeStyleVariationsWithUserConfig()`
Replace usage with utils created in #58803

* add a todo

* A bit of clean up. Remove comments, adjust margins.

* move variation to a new component

* make variation a composible component

* use the variation component for typography

* Update typography preview

* Add animation

* move variation to a component

* move preset to the higher level

* Remove unneeded CSS

* updawte the design

* remove unsed css

* Ensuring the cursor for the color previews is a pointer, which is the same as the typography preview
Reducing the vheight of the color panel to match typography
Some light refactoring

* Reinstate removing property from user config before merging with variation.
We do this in order that any user config changes with the same property don't "bleed" into variations. The variation should be "pure".
For example, if the user has defined a background color, but the variation has not, we shouldn't merge the two and allow the user background color to persist.
Rather the variation's color properties should take the place of all color properties.

* i18n for letters

* Refactor unique font calculation

* move color and type variations higher

* Use same box shadow as ColorIndicator so that there's a border around colors
This is so that theme colors that are the same value as the background are more noticeable

---------

Co-authored-by: ramon <ramonjd@gmail.com>
  • Loading branch information
scruffian and ramonjd authored Feb 28, 2024
1 parent faf60a4 commit ed72f48
Show file tree
Hide file tree
Showing 12 changed files with 809 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import ColorVariations from './variations-color';
import { useCurrentMergeThemeStyleVariationsWithUserConfig } from '../../hooks/use-theme-style-variations/use-theme-style-variations-by-property';

const { useGlobalSetting } = unlock( blockEditorPrivateApis );
const mobilePopoverProps = { placement: 'bottom-start', offset: 8 };
Expand Down Expand Up @@ -45,7 +47,12 @@ export default function ColorPalettePanel( { name } ) {
'color.defaultPalette',
name
);

const colorVariations = useCurrentMergeThemeStyleVariationsWithUserConfig( {
property: 'color',
filter: ( variation ) =>
variation?.settings?.color &&
Object.keys( variation?.settings?.color ).length,
} );
const isMobileViewport = useViewportMatch( 'small', '<' );
const popoverProps = isMobileViewport ? mobilePopoverProps : undefined;

Expand Down Expand Up @@ -78,6 +85,9 @@ export default function ColorPalettePanel( { name } ) {
popoverProps={ popoverProps }
/>
) }
{ !! colorVariations.length && (
<ColorVariations variations={ colorVariations } />
) }
<PaletteEdit
colors={ customColors }
onChange={ setCustomColors }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ export function getFamilyPreviewStyle( family ) {
if ( family.fontFace ) {
//get all the font faces with normal style
const normalFaces = family.fontFace.filter(
( face ) => face.fontStyle.toLowerCase() === 'normal'
( face ) =>
face?.fontStyle && face.fontStyle.toLowerCase() === 'normal'
);
if ( normalFaces.length > 0 ) {
style.fontStyle = 'normal';
Expand Down
216 changes: 216 additions & 0 deletions packages/edit-site/src/components/global-styles/preview-colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/**
* WordPress dependencies
*/
import {
__unstableIframe as Iframe,
__unstableEditorStyles as EditorStyles,
privateApis as blockEditorPrivateApis,
} from '@wordpress/block-editor';
import {
__unstableMotion as motion,
__experimentalHStack as HStack,
} from '@wordpress/components';
import {
useThrottle,
useReducedMotion,
useResizeObserver,
} from '@wordpress/compose';
import { useLayoutEffect, useState, useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import { useStylesPreviewColors } from './hooks';

const { useGlobalStyle, useGlobalStylesOutput } = unlock(
blockEditorPrivateApis
);

const firstFrame = {
start: {
scale: 1,
opacity: 1,
},
hover: {
scale: 0,
opacity: 0,
},
};

const normalizedWidth = 248;
const normalizedHeight = 152;

const normalizedColorSwatchSize = 66;

// Throttle options for useThrottle. Must be defined outside of the component,
// so that the object reference is the same on each render.
const THROTTLE_OPTIONS = {
leading: true,
trailing: true,
};

const StylesPreviewColors = ( { label, isFocused, withHoverView } ) => {
const [ backgroundColor = 'white' ] = useGlobalStyle( 'color.background' );
const [ gradientValue ] = useGlobalStyle( 'color.gradient' );
const [ styles ] = useGlobalStylesOutput();
const disableMotion = useReducedMotion();
const [ isHovered, setIsHovered ] = useState( false );
const [ containerResizeListener, { width } ] = useResizeObserver();
const [ throttledWidth, setThrottledWidthState ] = useState( width );
const [ ratioState, setRatioState ] = useState();

const setThrottledWidth = useThrottle(
setThrottledWidthState,
250,
THROTTLE_OPTIONS
);

// Must use useLayoutEffect to avoid a flash of the iframe at the wrong
// size before the width is set.
useLayoutEffect( () => {
if ( width ) {
setThrottledWidth( width );
}
}, [ width, setThrottledWidth ] );

// Must use useLayoutEffect to avoid a flash of the iframe at the wrong
// size before the width is set.
useLayoutEffect( () => {
const newRatio = throttledWidth ? throttledWidth / normalizedWidth : 1;
const ratioDiff = newRatio - ( ratioState || 0 );

// Only update the ratio state if the difference is big enough
// or if the ratio state is not yet set. This is to avoid an
// endless loop of updates at particular viewport heights when the
// presence of a scrollbar causes the width to change slightly.
const isRatioDiffBigEnough = Math.abs( ratioDiff ) > 0.1;

if ( isRatioDiffBigEnough || ! ratioState ) {
setRatioState( newRatio );
}
}, [ throttledWidth, ratioState ] );

// Set a fallbackRatio to use before the throttled ratio has been set.
const fallbackRatio = width ? width / normalizedWidth : 1;
/*
* Use the throttled ratio if it has been calculated, otherwise
* use the fallback ratio. The throttled ratio is used to avoid
* an endless loop of updates at particular viewport heights.
* See: https://github.com/WordPress/gutenberg/issues/55112
*/
const ratio = ratioState ? ratioState : fallbackRatio;

const { highlightedColors } = useStylesPreviewColors();

/*
* Reset leaked styles from WP common.css and remove main content layout padding and border.
* Add pointer cursor to the body to indicate the iframe is interactive,
* similar to Typography variation previews.
*/
const editorStyles = useMemo( () => {
if ( styles ) {
return [
...styles,
{
css: 'html{overflow:hidden}body{min-width: 0;padding: 0;border: none;cursor: pointer;}',
isGlobalStyles: true,
},
];
}

return styles;
}, [ styles ] );
const isReady = !! width;

return (
<>
<div style={ { position: 'relative' } }>
{ containerResizeListener }
</div>
{ isReady && (
<Iframe
className="edit-site-global-styles-preview__iframe"
style={ {
width: '100%',
height: normalizedHeight * ratio,
} }
onMouseEnter={ () => setIsHovered( true ) }
onMouseLeave={ () => setIsHovered( false ) }
tabIndex={ -1 }
>
<EditorStyles styles={ editorStyles } />
<motion.div
style={ {
height: normalizedHeight * ratio,
width: '100%',
background: gradientValue ?? backgroundColor,
cursor: withHoverView ? 'pointer' : undefined,
} }
initial="start"
animate={
( isHovered || isFocused ) &&
! disableMotion &&
label
? 'hover'
: 'start'
}
>
<motion.div
variants={ firstFrame }
style={ {
height: '100%',
overflow: 'hidden',
} }
>
<HStack
spacing={ 10 * ratio }
justify="center"
style={ {
height: '100%',
overflow: 'hidden',
} }
>
{ highlightedColors.map(
( { slug, color }, index ) => (
<motion.div
key={ slug }
style={ {
boxShadow:
'inset 0 0 0 1px #0003',
height:
normalizedColorSwatchSize *
ratio,
width:
normalizedColorSwatchSize *
ratio,
background: color,
borderRadius:
( normalizedColorSwatchSize *
ratio ) /
2,
} }
animate={ {
scale: 1,
opacity: 1,
} }
initial={ {
scale: 0.1,
opacity: 0,
} }
transition={ {
delay: index === 1 ? 0.2 : 0.1,
} }
/>
)
) }
</HStack>
</motion.div>
</motion.div>
</Iframe>
) }
</>
);
};

export default StylesPreviewColors;
14 changes: 13 additions & 1 deletion packages/edit-site/src/components/global-styles/screen-colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
import ScreenHeader from './header';
import Palette from './palette';
import { unlock } from '../../lock-unlock';
import ColorVariations from './variations-color';
import { useCurrentMergeThemeStyleVariationsWithUserConfig } from '../../hooks/use-theme-style-variations/use-theme-style-variations-by-property';

const {
useGlobalStyle,
Expand All @@ -29,6 +31,12 @@ function ScreenColors() {
const [ rawSettings ] = useGlobalSetting( '' );
const settings = useSettingsForBlockElement( rawSettings );

const colorVariations = useCurrentMergeThemeStyleVariationsWithUserConfig( {
property: 'color',
filter: ( variation ) =>
variation?.settings?.color &&
Object.keys( variation?.settings?.color ).length,
} );
return (
<>
<ScreenHeader
Expand All @@ -38,7 +46,11 @@ function ScreenColors() {
) }
/>
<div className="edit-site-global-styles-screen-colors">
<VStack spacing={ 10 }>
<VStack spacing={ 3 }>
{ !! colorVariations.length && (
<ColorVariations variations={ colorVariations } />
) }

<Palette />

<StylesColorPanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@ import { useSelect } from '@wordpress/data';
* Internal dependencies
*/
import TypographyElements from './typography-elements';
import TypographyVariations from './variations-typography';
import FontFamilies from './font-families';
import ScreenHeader from './header';
import { useCurrentMergeThemeStyleVariationsWithUserConfig } from '../../hooks/use-theme-style-variations/use-theme-style-variations-by-property';

function ScreenTypography() {
const fontLibraryEnabled = useSelect(
( select ) =>
select( editorStore ).getEditorSettings().fontLibraryEnabled,
[]
);
const typographyVariations =
useCurrentMergeThemeStyleVariationsWithUserConfig( {
property: 'typography',
filter: ( variation ) =>
variation?.settings?.typography?.fontFamilies &&
Object.keys( variation?.settings?.typography?.fontFamilies )
.length,
} );

return (
<>
Expand All @@ -30,7 +40,14 @@ function ScreenTypography() {
/>
<div className="edit-site-global-styles-screen-typography">
<VStack spacing={ 6 }>
{ fontLibraryEnabled && <FontFamilies /> }
{ !! typographyVariations.length && (
<TypographyVariations />
) }
{ ! window.__experimentalDisableFontLibrary && (
<VStack spacing={ 3 }>
{ fontLibraryEnabled && <FontFamilies /> }
</VStack>
) }
<TypographyElements />
</VStack>
</div>
Expand Down
Loading

0 comments on commit ed72f48

Please sign in to comment.