@gechiui/components
Version:
UI components for GeChiUI.
330 lines (287 loc) • 8.04 kB
JavaScript
/**
* External dependencies
*/
import { find, startsWith, get, camelCase, has } from 'lodash';
import { Dimensions } from 'react-native';
/**
* GeChiUI dependencies
*/
import { getPxFromCssUnit } from '@gechiui/block-editor';
export const BLOCK_STYLE_ATTRIBUTES = [
'textColor',
'backgroundColor',
'style',
'color',
'fontSize',
];
// Mapping style properties name to native
const BLOCK_STYLE_ATTRIBUTES_MAPPING = {
textColor: 'color',
text: 'color',
background: 'backgroundColor',
link: 'linkColor',
placeholder: 'placeholderColor',
};
const PADDING = 12; // $solid-border-space
const UNKNOWN_VALUE = 'undefined';
export function getBlockPaddings(
mergedStyle,
wrapperPropsStyle,
blockStyleAttributes,
blockColors
) {
const blockPaddings = {};
if (
! mergedStyle.padding &&
( wrapperPropsStyle?.backgroundColor ||
blockStyleAttributes?.backgroundColor ||
blockColors?.backgroundColor )
) {
blockPaddings.padding = PADDING;
return blockPaddings;
}
// Prevent adding extra paddings to inner blocks without background colors
if (
mergedStyle?.padding &&
! wrapperPropsStyle?.backgroundColor &&
! blockStyleAttributes?.backgroundColor &&
! blockColors?.backgroundColor
) {
blockPaddings.padding = undefined;
}
return blockPaddings;
}
export function getBlockColors(
blockStyleAttributes,
defaultColors,
blockName,
baseGlobalStyles
) {
const blockStyles = {};
const customBlockStyles = blockStyleAttributes?.style?.color || {};
const blockGlobalStyles = baseGlobalStyles?.blocks?.[ blockName ];
// Global styles colors
if ( blockGlobalStyles?.color ) {
Object.entries( blockGlobalStyles.color ).forEach(
( [ key, value ] ) => {
const styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING[ key ];
if ( styleKey && value !== UNKNOWN_VALUE ) {
const color = customBlockStyles[ key ] ?? value;
blockStyles[ styleKey ] = color;
}
}
);
} else if ( baseGlobalStyles?.styles?.color?.text ) {
blockStyles[ BLOCK_STYLE_ATTRIBUTES_MAPPING.text ] =
baseGlobalStyles?.styles?.color?.text;
}
// Global styles elements
if ( blockGlobalStyles?.elements ) {
const linkColor = blockGlobalStyles.elements?.link?.color?.text;
const styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING.link;
if ( styleKey && linkColor && linkColor !== UNKNOWN_VALUE ) {
blockStyles[ styleKey ] = linkColor;
}
}
// Custom colors
Object.entries( blockStyleAttributes ).forEach( ( [ key, value ] ) => {
const isCustomColor = startsWith( value, '#' );
let styleKey = key;
if ( BLOCK_STYLE_ATTRIBUTES_MAPPING[ styleKey ] ) {
styleKey = BLOCK_STYLE_ATTRIBUTES_MAPPING[ styleKey ];
}
if ( ! isCustomColor ) {
const mappedColor = find( defaultColors, {
slug: value,
} );
if ( mappedColor ) {
blockStyles[ styleKey ] = mappedColor.color;
}
} else {
blockStyles[ styleKey ] = value;
}
} );
// Color placeholder
if ( blockStyles?.color ) {
blockStyles[ BLOCK_STYLE_ATTRIBUTES_MAPPING.placeholder ] =
blockStyles.color;
}
return blockStyles;
}
export function getBlockTypography(
blockStyleAttributes,
fontSizes,
blockName,
baseGlobalStyles
) {
const typographyStyles = {};
const customBlockStyles = blockStyleAttributes?.style?.typography || {};
const blockGlobalStyles = baseGlobalStyles?.blocks?.[ blockName ];
// Global styles
if ( blockGlobalStyles?.typography ) {
const fontSize = blockGlobalStyles?.typography?.fontSize;
const lineHeight = blockGlobalStyles?.typography?.lineHeight;
if ( fontSize ) {
if ( parseInt( fontSize, 10 ) ) {
typographyStyles.fontSize = fontSize;
} else {
const mappedFontSize = find( fontSizes, {
slug: fontSize,
} );
if ( mappedFontSize ) {
typographyStyles.fontSize = mappedFontSize?.size;
}
}
}
if ( lineHeight ) {
typographyStyles.lineHeight = lineHeight;
}
}
if ( blockStyleAttributes?.fontSize ) {
const mappedFontSize = find( fontSizes, {
slug: blockStyleAttributes?.fontSize,
} );
if ( mappedFontSize ) {
typographyStyles.fontSize = mappedFontSize?.size;
}
}
// Custom styles
if ( customBlockStyles?.fontSize ) {
typographyStyles.fontSize = customBlockStyles?.fontSize;
}
if ( customBlockStyles?.lineHeight ) {
typographyStyles.lineHeight = customBlockStyles?.lineHeight;
}
return typographyStyles;
}
export function parseStylesVariables( styles, mappedValues, customValues ) {
let stylesBase = styles;
const variables = [ 'preset', 'custom' ];
if ( ! stylesBase ) {
return styles;
}
variables.forEach( ( variable ) => {
// Examples
// var(--gc--preset--color--gray)
// var(--gc--custom--body--typography--font-family)
const regex = new RegExp( `var\\(--gc--${ variable }--(.*?)\\)`, 'g' );
if ( variable === 'preset' ) {
stylesBase = stylesBase.replace( regex, ( _$1, $2 ) => {
const path = $2.split( '--' );
const mappedPresetValue = mappedValues[ path[ 0 ] ];
if ( mappedPresetValue && mappedPresetValue.slug ) {
const matchedValue = find( mappedPresetValue.values, {
slug: path[ 1 ],
} );
return matchedValue?.[ mappedPresetValue.slug ];
}
return UNKNOWN_VALUE;
} );
}
if ( variable === 'custom' ) {
const customValuesData = customValues ?? JSON.parse( stylesBase );
stylesBase = stylesBase.replace( regex, ( _$1, $2 ) => {
const path = $2.split( '--' );
if ( has( customValuesData, path ) ) {
return get( customValuesData, path );
}
// Check for camelcase properties
return get( customValuesData, [
...path.slice( 0, path.length - 1 ),
camelCase( path[ path.length - 1 ] ),
] );
} );
}
} );
return JSON.parse( stylesBase );
}
export function getMappedValues( features, palette ) {
const typography = features?.typography;
const colors = { ...palette?.theme, ...palette?.custom };
const fontSizes = {
...typography?.fontSizes?.theme,
...typography?.fontSizes?.custom,
};
const mappedValues = {
color: {
values: colors,
slug: 'color',
},
'font-size': {
values: fontSizes,
slug: 'size',
},
};
return mappedValues;
}
/**
* Returns the normalized fontSizes to include the sizePx value for each of the different sizes.
*
* @param {Object} fontSizes found in global styles.
* @return {Object} normalized sizes.
*/
function normalizeFontSizes( fontSizes ) {
// Adds normalized PX values for each of the different keys
if ( ! fontSizes ) {
return fontSizes;
}
const normalizedFontSizes = {};
const dimensions = Dimensions.get( 'window' );
[ 'default', 'theme', 'user' ].forEach( ( key ) => {
if ( fontSizes[ key ] ) {
normalizedFontSizes[ key ] = fontSizes[ key ]?.map(
( fontSizeObject ) => {
fontSizeObject.sizePx = getPxFromCssUnit(
fontSizeObject.size,
{
width: dimensions.width,
height: dimensions.height,
fontSize: 16,
}
);
return fontSizeObject;
}
);
}
} );
return normalizedFontSizes;
}
export function getGlobalStyles( rawStyles, rawFeatures ) {
const features = rawFeatures ? JSON.parse( rawFeatures ) : {};
const mappedValues = getMappedValues( features, features?.color?.palette );
const colors = parseStylesVariables(
JSON.stringify( features?.color ),
mappedValues
);
const gradients = parseStylesVariables(
JSON.stringify( features?.color?.gradients ),
mappedValues
);
const customValues = parseStylesVariables(
JSON.stringify( features?.custom ),
mappedValues
);
const globalStyles = parseStylesVariables(
rawStyles,
mappedValues,
customValues
);
const fontSizes = normalizeFontSizes( features?.typography?.fontSizes );
return {
colors,
gradients,
__experimentalFeatures: {
color: {
palette: colors?.palette,
gradients,
text: features?.color?.text ?? true,
background: features?.color?.background ?? true,
},
typography: {
fontSizes,
customLineHeight: features?.custom?.[ 'line-height' ],
},
},
__experimentalGlobalStylesBaseStyles: globalStyles,
};
}