Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions src/components/advanced-range-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ const AdvancedRangeControl = props => {
// Since the actual previous value is a preset, force the new custom value
// when changing unit
controlProps.onChangeUnit = ( unit, unitAttrName ) => {
dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent()
setAttributes( { [ unitAttrName ]: unit } )
if ( props.onChangeUnit ) {
props.onChangeUnit( unit )
}
_onChange( _newValue )
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/font-size-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const FontSizeControl = props => {
placeholder={ passedPlaceholder }
onChangeUnit={ value => {
// Change font-size so as not to surprise the user.
if ( props.value !== '' && ! isNaN( Number( value ) ) ) {
if ( props.value !== '' && ! isNaN( Number( props.value ) ) ) {
if ( value === 'em' || value === 'rem' ) {
props.onChange( String( pxToEm( props.value ) ) )
} else if ( value === 'px' ) {
Expand Down
6 changes: 5 additions & 1 deletion src/components/four-range-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,12 @@ const FourRangeControl = memo( props => {
// Since the actual previous value is a preset, force the new custom value
// when changing unit
controlProps.onChangeUnit = ( unit, unitAttrName ) => {
initialOnChange( _newValue )
dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent()
setAttributes( { [ unitAttrName ]: unit } )
if ( props.onChangeUnit ) {
props.onChangeUnit( unit )
}
initialOnChange( _newValue )
}
}

Expand Down
82 changes: 45 additions & 37 deletions src/plugins/global-settings/typography/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,26 @@ import { GlobalTypographyStyles } from './editor-loader'
import TypographyPicker from './typography-picker'
import { getThemeStyles } from './get-theme-styles'
import FREE_FONT_PAIRS from './font-pairs.json'
import { getAppliedTypeScale, cleanTypographyStyle } from './utils'
import {
getDevicePropertyKey,
getAppliedTypeScale,
cleanTypographyStyle,
getTypographyTypeScale,
} from './utils'

/**
* External dependencies
*/
import {
PanelAdvancedSettings, AdvancedSelectControl, ControlSeparator, FontPairPicker, ProControlButton, AdvancedToggleControl,
PanelAdvancedSettings,
AdvancedSelectControl,
ControlSeparator,
FontPairPicker,
ProControlButton,
AdvancedToggleControl,
} from '~stackable/components'
import { fetchSettings } from '~stackable/util'
import { useDeviceType } from '~stackable/hooks'
import {
i18n, isPro, showProNotice,
} from 'stackable'
Expand Down Expand Up @@ -148,6 +159,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
const _useTypographyAsPresets = select( 'stackable/global-preset-controls.custom' )?.getUseTypographyAsPresets() ?? false
return { useTypographyAsPresets: _useTypographyAsPresets }
}, [] )
const deviceType = useDeviceType()?.toLowerCase() || 'desktop'

const FONT_PAIRS = applyFilters( 'stackable.global-settings.typography.font-pairs.premium-font-pairs', FREE_FONT_PAIRS )

Expand All @@ -157,7 +169,11 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
const [ customFontPairs, setCustomFontPairs ] = useState( [] )
const [ selectedFontPairName, setSelectedFontPairName ] = useState( '' )
const [ isEditingFontPair, setIsEditingFontPair ] = useState( false )
const [ selectedTypeScale, setSelectedTypeScale ] = useState( 'none' )
const [ selectedTypeScale, setSelectedTypeScale ] = useState( {
desktop: 'none',
tablet: 'none',
mobile: 'none',
} )
const [ isApplyBodyToHTML, setIsApplyBodyToHTML ] = useState( false )

const fontPairContainerRef = useRef( null )
Expand All @@ -172,22 +188,21 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
setSelectedFontPairName( response.stackable_selected_font_pair || 'theme-heading-default/theme-body-default' )
setIsApplyBodyToHTML( response.stackable_is_apply_body_to_html || false )

// Reversely compute the type scale from the font sizes
let typeScale = _typographySettings?.h6?.fontSize
if ( typeScale ) {
const computedApplied = getAppliedTypeScale( typeScale ) ?? {}
const tags = Object.keys( _typographySettings )
for ( const tag of tags ) {
// If font size mismatch, set typography scale to Custom
if ( _typographySettings[ tag ]?.fontSize !== computedApplied[ tag ]?.fontSize ) {
typeScale = 'custom'
}
}
setSelectedTypeScale( typeScale )
}
// Reversely compute initial typescale for highlighting
const typeScaleDesktop = getTypographyTypeScale( _typographySettings, 'desktop' )
const typeScaleTablet = getTypographyTypeScale( _typographySettings, 'tablet' )
const typeScaleMobile = getTypographyTypeScale( _typographySettings, 'mobile' )
setSelectedTypeScale( {
desktop: typeScaleDesktop, tablet: typeScaleTablet, mobile: typeScaleMobile,
} )
} )
}, [] )

useEffect( () => {
const typeScale = getTypographyTypeScale( typographySettings, deviceType )
setSelectedTypeScale( prev => ( { ...prev, [ deviceType ]: typeScale } ) )
}, [ deviceType, typographySettings ] )

useEffect( () => {
// When typography styles are changed, trigger our editor style generator to update.
// This also triggers updating presets with typography, and applying body font size to html.
Expand Down Expand Up @@ -269,26 +284,25 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
}

const updateTypeScale = value => {
setSelectedTypeScale( value )

// If value is custom, do not do anything
if ( value === 'custom ' ) {
return
}

// If value is none, reset the font sizes and units
if ( value === 'none' ) {
const selectors = TYPOGRAPHY_TAGS.map( tag => tag.selector )
const newSettings = selectors.reduce( ( acc, selector, ) => {
acc[ selector ] = { fontSize: '', fontSizeUnit: '' }
const fontSizeKey = getDevicePropertyKey( 'fontSize', deviceType )
const fontSizeUnitKey = getDevicePropertyKey( 'fontSizeUnit', deviceType )

const newSettings = selectors.reduce( ( acc, selector ) => {
acc[ selector ] = {
[ fontSizeKey ]: '',
[ fontSizeUnitKey ]: '',
}
return acc
}, {} )

changeStyles( newSettings )
return
}

// If value is valid type scale, apply to the styles
const newSettings = getAppliedTypeScale( value )
const newSettings = getAppliedTypeScale( value, deviceType )
changeStyles( newSettings )
}

Expand Down Expand Up @@ -513,9 +527,12 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
<AdvancedSelectControl
label={ __( 'Type Scale', i18n ) }
options={ TYPE_SCALE }
value={ selectedTypeScale }
value={ selectedTypeScale[ deviceType ] }
onChange={ updateTypeScale }
responsive="all"
default="none"
hasTabletValue={ selectedTypeScale.tablet !== 'none' }
hasMobileValue={ selectedTypeScale.mobile !== 'none' }
/>
{ TYPOGRAPHY_TAGS.map( ( {
label, selector, help,
Expand All @@ -531,18 +548,9 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography',
isAllowReset={ getIsAllowReset( selector ) }
onChange={ styles => {
changeStyles( { [ selector ]: styles } )
// Set typeScale to custom when editing font size or units
if ( 'fontSize' in styles || 'fontSizeUnit' in styles ) {
setSelectedTypeScale( 'custom' )
}
} }
onReset={ () => {
resetStyles( selector )
// Set typeScale to custom when editing font size or units
const styles = typographySettings[ selector ]
if ( 'fontSize' in styles || 'fontSizeUnit' in styles ) {
setSelectedTypeScale( 'custom' )
}
} }
/>
)
Expand Down
101 changes: 90 additions & 11 deletions src/plugins/global-settings/typography/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
/**
* Returns the reversely computed typescale based on the typography settings and device type
*
* @param {Object} typographySettings - The typography settings object
* @param {string} deviceType - The device type
* @return {string} The computed typescale. Values can be none, custom, or the numeric scale.
*/
export const getTypographyTypeScale = ( typographySettings, deviceType ) => {
const fontSizeKey = getDevicePropertyKey( 'fontSize', deviceType )
const fontSizeUnitKey = getDevicePropertyKey( 'fontSizeUnit', deviceType )
const tags = Object.keys( typographySettings )

// Reversely compute the type scale from the font sizes
let typeScale = typographySettings?.h6?.[ fontSizeKey ]
typeScale = typeScale && parseFloat( typeScale ).toString()

if ( typeScale ) {
const computedApplied = getAppliedTypeScale( typeScale, deviceType ) ?? {}
for ( const tag of tags ) {
// console.log( typographySettings[ tag ]?.[ fontSizeKey ], computedApplied[ tag ]?.[ fontSizeKey ] )
// If font size mismatch, set typography scale to Custom
if ( typographySettings[ tag ]?.[ fontSizeKey ] !== computedApplied[ tag ]?.[ fontSizeKey ] ||
typographySettings[ tag ]?.[ fontSizeUnitKey ] !== computedApplied[ tag ]?.[ fontSizeUnitKey ]
) {
typeScale = 'custom'
}
}
} else {
typeScale = 'none'
for ( const tag of tags ) {
if ( typographySettings[ tag ]?.[ fontSizeKey ] ) {
typeScale = 'custom'
}
}
}
return typeScale
}

/**
* Returns the property key adjusted for the given device type.
*
* @param {string} baseProperty - The base property name
* @param {string} deviceType - The device type
* @return {string} The adjusted property key based on the device type.
*
*/
export const getDevicePropertyKey = ( baseProperty, deviceType ) => {
deviceType = deviceType.toLowerCase()
if ( deviceType && deviceType !== 'desktop' ) {
return `${ deviceType }${ baseProperty.charAt( 0 ).toUpperCase() }${ baseProperty.slice( 1 ) }`
}
return baseProperty
}

/**
* Generates a typographic scale based on the given value.
*
Expand All @@ -6,26 +60,51 @@
* calculated using an exponential scale.
*
* @param {string|number} value - The base number to use for the typographic scale.
* @param {string} deviceType - The device type
* @return {Object|undefined} An object mapping CSS selectors to their corresponding
* font size settings. Returns `undefined` if input is invalid.
*/

export const getAppliedTypeScale = value => {
export const getAppliedTypeScale = ( value, deviceType = '' ) => {
const typeScale = Number( value )
if ( Number.isNaN( typeScale ) ) {
return
}
return {
h1: { fontSize: String( Math.pow( typeScale, 6 ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
h2: { fontSize: String( Math.pow( typeScale, 5 ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
h3: { fontSize: String( Math.pow( typeScale, 4 ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
h4: { fontSize: String( Math.pow( typeScale, 3 ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
h5: { fontSize: String( Math.pow( typeScale, 2 ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
h6: { fontSize: String( typeScale.toFixed( 3 ) ), fontSizeUnit: 'rem' },
p: { fontSize: '1', fontSizeUnit: 'rem' },
'.stk-subtitle': { fontSize: String( ( 1 / typeScale ).toFixed( 3 ) ), fontSizeUnit: 'rem' },
'.stk-button__inner-text': { fontSize: '1', fontSizeUnit: 'rem' },

const headings = {
Comment thread
bfintal marked this conversation as resolved.
h1: 6,
h2: 5,
h3: 4,
h4: 3,
h5: 2,
h6: 1,
p: 0,
'.stk-subtitle': -1,
'.stk-button__inner-text': 0,
}

const result = {}

Object.entries( headings ).forEach( ( [ key, power ] ) => {
let fontSize
if ( power > 0 ) {
fontSize = String( Math.pow( typeScale, power ).toFixed( 3 ) )
} else if ( power === 0 ) {
fontSize = '1'
} else {
fontSize = String( ( 1 / typeScale ).toFixed( 3 ) )
}

const fontSizeKey = getDevicePropertyKey( 'fontSize', deviceType )
const fontSizeUnitKey = getDevicePropertyKey( 'fontSizeUnit', deviceType )

result[ key ] = {
[ fontSizeKey ]: fontSize,
[ fontSizeUnitKey ]: 'rem',
}
} )

return result
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/util/typography/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export const createTypographyStyles = ( attrNameTemplate = '%s', screen = 'deskt
const mobileFontSize = getValue( 'MobileFontSize' )

const desktopFontSizeUnit = isCSSVarValue( desktopFontSize ) ? '' : getValue( 'FontSizeUnit' ) || 'px'
const tabletFontSizeUnit = isCSSVarValue( tabletFontSize ) ? '' : getValue( 'FontSizeUnit' ) || 'px'
const mobileFontSizeUnit = isCSSVarValue( mobileFontSize ) ? '' : getValue( 'FontSizeUnit' ) || 'px'
const tabletFontSizeUnit = isCSSVarValue( tabletFontSize ) ? '' : getValue( 'TabletFontSizeUnit' ) || 'px'
const mobileFontSizeUnit = isCSSVarValue( mobileFontSize ) ? '' : getValue( 'MobileFontSizeUnit' ) || 'px'

if ( screen !== 'tablet' && screen !== 'mobile' ) { // Desktop.
styles = {
Expand Down
Loading