diff --git a/e2e/tests/global-settings.spec.ts b/e2e/tests/global-settings.spec.ts index 9f59b43091..c4fe99e360 100644 --- a/e2e/tests/global-settings.spec.ts +++ b/e2e/tests/global-settings.spec.ts @@ -85,18 +85,18 @@ test.describe( 'Global Settings', () => { await page.getByLabel( 'Stackable Settings' ).click() await page.getByRole( 'button', { name: 'Global Typography' } ).click() - // Set Global Typography Styles of Heading 2 to have a font-size of 32 + // Set Global Typography Styles of Heading 2 to have a text-transform uppercase await page.locator( '.ugb-global-settings-typography-control' ).nth( 1 ).locator( '.components-base-control__field > .ugb-button-icon-control__wrapper > .components-button' ).click() - await page.locator( '.stk-popover .components-base-control:nth-of-type(2)', { hasText: /Size/ } ).getByRole( 'textbox' ).fill( '32' ) + await page.locator( '.stk-popover .components-base-control:nth-of-type(4)', { hasText: /Transform/ } ).getByRole( 'listbox' ).selectOption( 'uppercase' ) await page.locator( '.ugb-global-settings-typography-control' ).nth( 1 ).locator( '.components-base-control__field > .ugb-button-icon-control__wrapper > .components-button' ).click() - // Verify if the Heading 2 in Global Typography Styles has correct font size - await expect( page.getByRole( 'heading', { name: 'Heading 2' } ) ).toHaveCSS( 'font-size', '32px' ) + // Verify if the Heading 2 in Global Typography Styles has correct text-transform + await expect( page.getByRole( 'heading', { name: 'Heading 2' } ) ).toHaveCSS( 'text-transform', 'uppercase' ) // Open Block Settings await page.getByLabel( 'Settings', { exact: true } ).click() - // Check if the added Stackable Heading Block has a font-size of 32 + // Check if the added Stackable Heading Block has a text-transform uppercase editor.insertBlock( { name: 'stackable/heading', attributes: { @@ -104,7 +104,7 @@ test.describe( 'Global Settings', () => { }, } ) - await expect( editor.canvas.locator( '[data-type="stackable/heading"] > .stk-block-heading > h2[role="textbox"]' ) ).toHaveCSS( 'font-size', '32px' ) + await expect( editor.canvas.locator( '[data-type="stackable/heading"] > .stk-block-heading > h2[role="textbox"]' ) ).toHaveCSS( 'text-transform', 'uppercase' ) // Reset Global Typography Styles await page.getByLabel( 'Stackable Settings' ).click() diff --git a/plugin.php b/plugin.php index f8214c0dd9..2bacde1da5 100644 --- a/plugin.php +++ b/plugin.php @@ -6,7 +6,7 @@ * Author: Gambit Technologies, Inc * Author URI: http://gambit.ph * Text Domain: stackable-ultimate-gutenberg-blocks - * Version: 3.15.3 + * Version: 3.16.0 * * @package Stackable */ @@ -24,7 +24,7 @@ defined( 'STACKABLE_SHOW_PRO_NOTICES' ) || define( 'STACKABLE_SHOW_PRO_NOTICES', true ); defined( 'STACKABLE_BUILD' ) || define( 'STACKABLE_BUILD', 'free' ); -defined( 'STACKABLE_VERSION' ) || define( 'STACKABLE_VERSION', '3.15.3' ); +defined( 'STACKABLE_VERSION' ) || define( 'STACKABLE_VERSION', '3.16.0' ); defined( 'STACKABLE_FILE' ) || define( 'STACKABLE_FILE', __FILE__ ); defined( 'STACKABLE_I18N' ) || define( 'STACKABLE_I18N', 'stackable-ultimate-gutenberg-blocks' ); // Plugin slug. defined( 'STACKABLE_DESIGN_LIBRARY_URL' ) || define( 'STACKABLE_DESIGN_LIBRARY_URL', 'https://storage.googleapis.com/stackable-plugin-assets' ); // Design Library CDN URL @@ -235,6 +235,7 @@ function is_frontend() { require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/spacing-and-borders/index.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/buttons-and-icons/index.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/color-schemes/index.php' ); +require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/preset-controls/index.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/custom-block-styles.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/css-optimize.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/compatibility/index.php' ); diff --git a/src/block-components/alignment/attributes.js b/src/block-components/alignment/attributes.js index 7c635d8691..0fb8f5eb1f 100644 --- a/src/block-components/alignment/attributes.js +++ b/src/block-components/alignment/attributes.js @@ -1,4 +1,8 @@ -export const addAttributes = attrObject => { +import { deprecatedAddAttributes } from './deprecated/index' + +export const addAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + deprecatedAddAttributes( attrObject, attrNameTemplate ) + // Assume that the block uses the BlockDiv Block Component and has a // uniqueId attribute attrObject.add( { @@ -53,13 +57,26 @@ export const addAttributes = attrObject => { type: 'number', default: '', }, + }, + versionAdded: '3.0.0', + versionDeprecated: '', + } ) + + attrObject.add( { + attributes: { innerBlockRowGap: { stkResponsive: true, - type: 'number', + type: 'string', + default: '', + }, + containerHeight: { + stkResponsive: true, + type: 'string', default: '', }, }, - versionAdded: '3.0.0', + attrNameTemplate, + versionAdded: '3.16.0', versionDeprecated: '', } ) } diff --git a/src/block-components/alignment/deprecated/index.js b/src/block-components/alignment/deprecated/index.js new file mode 100644 index 0000000000..1cdd79218b --- /dev/null +++ b/src/block-components/alignment/deprecated/index.js @@ -0,0 +1,44 @@ +import { getAttrNameFunction } from '~stackable/util' + +export const deprecatedAddAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + attrObject.add( { + attributes: { + innerBlockRowGap: { + stkResponsive: true, + type: 'number', + default: '', + }, + }, + attrNameTemplate, + versionAdded: '3.0.0', + versionDeprecated: '3.16.0', + } ) +} + +export const deprecateInnerBlockRowGapAndContainerHeight = { + isEligible: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const containerHeight = getAttribute( 'containerHeight' ) + const innerBlockRowGap = getAttribute( 'innerBlockRowGap' ) + + return typeof containerHeight === 'number' || typeof innerBlockRowGap === 'number' + }, + migrate: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const containerHeight = getAttribute( 'containerHeight' ) + const innerBlockRowGap = getAttribute( 'innerBlockRowGap' ) + + const newAttributes = { + ...attributes, + [ getAttrName( 'containerHeight' ) ]: String( containerHeight ), + [ getAttrName( 'innerBlockRowGap' ) ]: String( innerBlockRowGap ), + } + + return newAttributes + }, +} + diff --git a/src/block-components/alignment/edit.js b/src/block-components/alignment/edit.js index dd02239e32..a6efa2435d 100644 --- a/src/block-components/alignment/edit.js +++ b/src/block-components/alignment/edit.js @@ -13,6 +13,7 @@ import { useBlockAttributesContext, useBlockSetAttributesContext, useDeviceType, + usePresetControls, } from '~stackable/hooks' /** @@ -86,6 +87,9 @@ export const Edit = memo( props => { enableContentAlign = true, } = props + const blockHeightMarks = usePresetControls( 'blockHeights' )?.getPresetMarks() || null + const spacingSizeMarks = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + const containerSize = props.hasContainerSize && <> { props.hasContainerHeight && @@ -100,6 +104,7 @@ export const Edit = memo( props => { allowReset={ true } placeholder="0" visualGuide={ { selector: '.stk-%s-container', highlight: 'outline' } } + marks={ blockHeightMarks } /> } { highlight: 'row-gap', value: innerBlockRowGap, } } + marks={ spacingSizeMarks } /> } { ( innerBlockOrientation && innerBlockWrap === 'wrap' ) && diff --git a/src/block-components/alignment/index.js b/src/block-components/alignment/index.js index b5c242a374..08e242a83f 100644 --- a/src/block-components/alignment/index.js +++ b/src/block-components/alignment/index.js @@ -4,6 +4,8 @@ import { addStyles } from './style' export * from './use-alignment' +export { deprecateInnerBlockRowGapAndContainerHeight } from './deprecated/index' + export const Alignment = () => { return null } diff --git a/src/block-components/alignment/style.js b/src/block-components/alignment/style.js index 5efa60abf9..7b7258a680 100644 --- a/src/block-components/alignment/style.js +++ b/src/block-components/alignment/style.js @@ -211,8 +211,14 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { styleRule: 'columnGap', attrName: 'innerBlockColumnGap', key: 'innerBlockColumnGapEdit', - format: `%spx`, responsive: 'all', + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', dependencies: [ 'innerBlockOrientation', @@ -225,8 +231,14 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { styleRule: 'columnGap', attrName: 'innerBlockColumnGap', key: 'innerBlockColumnGapSave', - format: `%spx`, responsive: 'all', + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', dependencies: [ 'innerBlockOrientation', @@ -241,12 +253,18 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { styleRule: 'rowGap', attrName: 'innerBlockRowGap', key: 'innerBlockRowGapEdit', - format: `%spx`, responsive: 'all', enabledCallback: getAttribute => { return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) }, + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, dependencies: [ 'innerBlockOrientation', 'innerBlockWrap', @@ -259,8 +277,14 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { styleRule: 'rowGap', attrName: 'innerBlockRowGap', key: 'innerBlockRowGapSave', - format: `%spx`, responsive: 'all', + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, enabledCallback: getAttribute => { return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) diff --git a/src/block-components/block-div/deprecated.js b/src/block-components/block-div/deprecated.js index f8f2655b80..f6571a9513 100644 --- a/src/block-components/block-div/deprecated.js +++ b/src/block-components/block-div/deprecated.js @@ -1,4 +1,6 @@ -import { deprecationBackgrounColorOpacity, deprecateShadowColor } from '../helpers' +import { + deprecationBackgrounColorOpacity, deprecateShadowColor, deprecateSizeControlHeight, +} from '../helpers' import { addFilter } from '@wordpress/hooks' import { semverCompare } from '~stackable/util' @@ -38,3 +40,12 @@ export const deprecateBlockShadowColor = { return deprecateShadowColor.migrate( 'block%s' )( attributes ) }, } + +export const deprecateBlockHeight = { + isEligible: attributes => { + return deprecateSizeControlHeight.isEligible( 'block%s' )( attributes ) + }, + migrate: attributes => { + return deprecateSizeControlHeight.migrate( 'block%s' )( attributes ) + }, +} diff --git a/src/block-components/block-div/index.js b/src/block-components/block-div/index.js index 123eaacbe2..de84319ed1 100644 --- a/src/block-components/block-div/index.js +++ b/src/block-components/block-div/index.js @@ -18,7 +18,9 @@ import { CustomAttributes } from '../custom-attributes' import { version as VERSION } from 'stackable' export { useUniqueId } -export { deprecateBlockBackgroundColorOpacity, deprecateBlockShadowColor } from './deprecated' +export { + deprecateBlockBackgroundColorOpacity, deprecateBlockShadowColor, deprecateBlockHeight, +} from './deprecated' export const BlockDiv = memo( props => { const { diff --git a/src/block-components/button/edit.js b/src/block-components/button/edit.js index ed363ca0c1..3c8fb034fc 100644 --- a/src/block-components/button/edit.js +++ b/src/block-components/button/edit.js @@ -12,7 +12,9 @@ import { AdvancedSelectControl, } from '~stackable/components' import { i18n } from 'stackable' -import { useBlockAttributesContext, useBlockLayoutDefaults } from '~stackable/hooks' +import { + useBlockAttributesContext, useBlockLayoutDefaults, usePresetControls, +} from '~stackable/hooks' /** * WordPress dependencies @@ -185,6 +187,9 @@ const SizeControls = props => { const { getPlaceholder } = useBlockLayoutDefaults() const buttonPaddingPlaceholder = getPlaceholder( paddingPlaceholderName, { single: false } ) + + const presetMarks = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + return ( <> { props.hasFullWidth && ( { title: __( 'Button padding', i18n ), description: __( 'Adjusts the space between the button text and button borders', i18n ), } } + marks={ presetMarks } /> > ) } diff --git a/src/block-components/columns/attributes.js b/src/block-components/columns/attributes.js index fe482cd786..0ed1283695 100644 --- a/src/block-components/columns/attributes.js +++ b/src/block-components/columns/attributes.js @@ -1,28 +1,40 @@ -export const addAttributes = attrObject => { +import { deprecatedAddAttributes } from './deprecated/index' + +export const addAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + deprecatedAddAttributes( attrObject, attrNameTemplate ) + attrObject.add( { attributes: { - columnSpacing: { - stkResponsive: true, - stkUnits: 'px', - type: 'number', - default: '', + columnWrapDesktop: { // Only applies to desktops + type: 'boolean', + default: false, }, + }, + versionAdded: '3.0.0', + versionDeprecated: '', + } ) + + attrObject.add( { + attributes: { columnGap: { stkResponsive: true, - type: 'number', + type: 'string', default: '', }, rowGap: { stkResponsive: true, - type: 'number', + type: 'string', default: '', }, - columnWrapDesktop: { // Only applies to desktops - type: 'boolean', - default: false, + columnSpacing: { + stkResponsive: true, + stkUnits: 'px', + type: 'string', + default: '', }, }, - versionAdded: '3.0.0', + attrNameTemplate, + versionAdded: '3.16.0', versionDeprecated: '', } ) } diff --git a/src/block-components/columns/deprecated/index.js b/src/block-components/columns/deprecated/index.js new file mode 100644 index 0000000000..75113249f3 --- /dev/null +++ b/src/block-components/columns/deprecated/index.js @@ -0,0 +1,57 @@ +import { getAttrNameFunction } from '~stackable/util' + +export const deprecatedAddAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + attrObject.add( { + attributes: { + columnGap: { + stkResponsive: true, + type: 'number', + default: '', + }, + rowGap: { + stkResponsive: true, + type: 'number', + default: '', + }, + columnSpacing: { + stkResponsive: true, + stkUnits: 'px', + type: 'number', + default: '', + }, + }, + attrNameTemplate, + versionAdded: '3.0.0', + versionDeprecated: '3.16.0', + } ) +} + +export const deprecateColumnAndRowGap = { + isEligible: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const columnSpacing = getAttribute( 'columnSpacing' ) + const columnGap = getAttribute( 'columnGap' ) + const rowGap = getAttribute( 'rowGap' ) + + return typeof columnSpacing === 'number' || typeof columnGap === 'number' || typeof rowGap === 'number' + }, + migrate: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const columnSpacing = getAttribute( 'columnSpacing' ) + const columnGap = getAttribute( 'columnGap' ) + const rowGap = getAttribute( 'rowGap' ) + + const newAttributes = { + ...attributes, + [ getAttrName( 'columnSpacing' ) ]: String( columnSpacing ), + [ getAttrName( 'columnGap' ) ]: String( columnGap ), + [ getAttrName( 'rowGap' ) ]: String( rowGap ), + } + + return newAttributes + }, +} diff --git a/src/block-components/columns/edit.js b/src/block-components/columns/edit.js index 83dbee0376..eec4bc4d6a 100644 --- a/src/block-components/columns/edit.js +++ b/src/block-components/columns/edit.js @@ -23,6 +23,7 @@ import { useBlockSetAttributesContext, useDeviceType, useBlockLayoutDefaults, + usePresetControls, } from '~stackable/hooks' import { range } from 'lodash' @@ -124,6 +125,8 @@ export const Controls = props => { : deviceType === 'Tablet' ? ( attributes.columnArrangementTablet || defaultArrangement ) : ( attributes.columnArrangementMobile || defaultArrangement ) + const presetMarks = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + return ( <> { props.hasColumnsControl && } @@ -267,6 +270,7 @@ export const Controls = props => { // Add a working video description: __( 'Sets column paddings, the space inside the block between the block elements and the column container border', i18n ), } } + marks={ presetMarks } /> { video: 'column-gap', description: __( 'Sets the distance between two or more columns', i18n ), } } + marks={ presetMarks } /> { // TODO: Add a working video description: __( 'Sets the distance between two or more columns', i18n ), } } + marks={ presetMarks } /> > ) } diff --git a/src/block-components/columns/index.js b/src/block-components/columns/index.js index 53398ebe93..bb0ec6397e 100644 --- a/src/block-components/columns/index.js +++ b/src/block-components/columns/index.js @@ -6,6 +6,8 @@ export const Columns = () => { return null } +export { deprecateColumnAndRowGap } from './deprecated/index' + Columns.InspectorControls = Edit Columns.addStyles = addStyles diff --git a/src/block-components/columns/style.js b/src/block-components/columns/style.js index 8e2c614d5a..4dc4a3a17a 100644 --- a/src/block-components/columns/style.js +++ b/src/block-components/columns/style.js @@ -20,8 +20,14 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { selector: '.%s-column', styleRule: '--stk-columns-spacing', attrName: 'columnSpacing', - hasUnits: 'px', responsive: 'all', + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, } ] ) blockStyleGenerator.addBlockStyles( 'columnGap', [ { @@ -30,16 +36,27 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { selector: '.%s-column', styleRule: '--stk-column-gap', attrName: 'columnGap', - format: '%spx', responsive: 'all', + valueCallback: value => { + // Substitute with using format to work with preset controls + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, }, { ...propsToPass, renderIn: 'edit', selector: '.%s-column > .block-editor-inner-blocks > .block-editor-block-list__layout', styleRule: '--stk-column-gap', attrName: 'columnGap', - format: '%spx', responsive: 'all', + valueCallback: value => { + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, } ] ) blockStyleGenerator.addBlockStyles( 'columnWrapDesktop', [ { @@ -78,16 +95,26 @@ export const addStyles = ( blockStyleGenerator, props = {} ) => { selector: '.%s-column', styleRule: 'rowGap', attrName: 'rowGap', - format: '%spx', responsive: 'all', + valueCallback: value => { + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, }, { ...propsToPass, renderIn: 'edit', selector: '.%s-column > .block-editor-inner-blocks > .block-editor-block-list__layout', styleRule: 'rowGap', attrName: 'rowGap', - format: '%spx', responsive: 'all', + valueCallback: value => { + if ( typeof value === 'string' && value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, } ] ) } diff --git a/src/block-components/helpers/borders/edit.js b/src/block-components/helpers/borders/edit.js index 44ab25c4cb..5eefbb78d1 100644 --- a/src/block-components/helpers/borders/edit.js +++ b/src/block-components/helpers/borders/edit.js @@ -15,7 +15,7 @@ import { import { Fragment } from '@wordpress/element' import { __ } from '@wordpress/i18n' import { - useAttributeEditHandlers, useBlockLayoutDefaults, useBlockSetAttributesContext, + useAttributeEditHandlers, useBlockLayoutDefaults, useBlockSetAttributesContext, usePresetControls, } from '~stackable/hooks' import { applyFilters } from '@wordpress/hooks' @@ -71,6 +71,8 @@ export const BorderControls = props => { applyFilters( 'stackable.block-component.helpers.borders', null, getAttribute, updateAttributes ) + const presetMarks = usePresetControls( 'borderRadius' )?.getPresetMarks() || null + return ( { props.hasBorderType && @@ -132,6 +134,7 @@ export const BorderControls = props => { isCorner={ true } sliderMax={ props.borderSliderMax } placeholder={ props.borderRadiusPlaceholder } + marks={ presetMarks } /> } { attrName: 'borderRadius2', key: 'borderTopLeftRadius2', attrNameTemplate, - format: '%spx', + valueCallback: value => { + // Substitute with using format to work with preset controls + value = typeof value === 'number' ? value.toString() : value + if ( value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, responsive: 'all', hover: 'all', valuePreCallback: value => value?.top, @@ -48,7 +55,13 @@ export const addBorderStyles = ( blockStyleGenerator, props = {} ) => { attrName: 'borderRadius2', key: 'borderTopRightRadius2', attrNameTemplate, - format: '%spx', + valueCallback: value => { + value = typeof value === 'number' ? value.toString() : value + if ( value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, responsive: 'all', hover: 'all', valuePreCallback: value => value?.right, @@ -60,7 +73,13 @@ export const addBorderStyles = ( blockStyleGenerator, props = {} ) => { attrName: 'borderRadius2', key: 'borderBottomRightRadius2', attrNameTemplate, - format: '%spx', + valueCallback: value => { + value = typeof value === 'number' ? value.toString() : value + if ( value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, responsive: 'all', hover: 'all', valuePreCallback: value => value?.left, @@ -72,7 +91,13 @@ export const addBorderStyles = ( blockStyleGenerator, props = {} ) => { attrName: 'borderRadius2', key: 'borderBottomLeftRadius2', attrNameTemplate, - format: '%spx', + valueCallback: value => { + value = typeof value === 'number' ? value.toString() : value + if ( value.startsWith( 'var' ) ) { + return value + } + return value + 'px' + }, responsive: 'all', hover: 'all', valuePreCallback: value => value?.bottom, diff --git a/src/block-components/helpers/size/attributes.js b/src/block-components/helpers/size/attributes.js index 83f73deb1d..0a3ac2d116 100644 --- a/src/block-components/helpers/size/attributes.js +++ b/src/block-components/helpers/size/attributes.js @@ -1,10 +1,6 @@ +import { deprecatedAddAttributes } from './deprecated' + export const sizeAttributes = { - height: { - stkResponsive: true, - stkUnits: 'px', - type: 'number', - default: '', - }, width: { stkResponsive: true, stkUnits: 'px', @@ -37,10 +33,26 @@ export const sizeAttributes = { } export const addSizeAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + deprecatedAddAttributes( attrObject, attrNameTemplate ) + attrObject.add( { attributes: sizeAttributes, attrNameTemplate, versionAdded: '3.0.0', versionDeprecated: '', } ) + + attrObject.add( { + attributes: { + height: { + stkResponsive: true, + stkUnits: 'px', + type: 'string', + default: '', + }, + }, + attrNameTemplate, + versionAdded: '3.16.0', + versionDeprecated: '', + } ) } diff --git a/src/block-components/helpers/size/deprecated.js b/src/block-components/helpers/size/deprecated.js new file mode 100644 index 0000000000..3871874a00 --- /dev/null +++ b/src/block-components/helpers/size/deprecated.js @@ -0,0 +1,41 @@ +import { getAttrNameFunction } from '~stackable/util' + +export const deprecatedAddAttributes = ( attrObject, attrNameTemplate = '%s' ) => { + attrObject.add( { + attributes: { + height: { + stkResponsive: true, + stkUnits: 'px', + type: 'number', + default: '', + }, + }, + attrNameTemplate, + versionAdded: '3.0.0', + versionDeprecated: '3.16.0', + } ) +} + +export const deprecateSizeControlHeight = { + isEligible: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const height = getAttribute( 'height' ) + + return typeof height === 'number' + }, + migrate: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const height = getAttribute( 'height' ) + + const newAttributes = { + ...attributes, + [ getAttrName( 'height' ) ]: String( height ), + } + + return newAttributes + }, +} diff --git a/src/block-components/helpers/size/edit.js b/src/block-components/helpers/size/edit.js index 6c555fbb03..7d547355e7 100644 --- a/src/block-components/helpers/size/edit.js +++ b/src/block-components/helpers/size/edit.js @@ -7,7 +7,9 @@ import { AdvancedRangeControl, FourRangeControl, } from '~stackable/components' -import { useAttributeEditHandlers, useDeviceType } from '~stackable/hooks' +import { + useAttributeEditHandlers, useDeviceType, usePresetControls, +} from '~stackable/hooks' /** * WordPress dependencies @@ -30,16 +32,18 @@ const Layout = props => { labelVerticalAlign = __( 'Content Vertical Align', i18n ), } = props.labels + const presetMarks = usePresetControls( 'blockHeights' )?.getPresetMarks() || null + return ( <> { props.hasMinHeight && { description: __( 'Adjusts the minimum allowable height of the block', i18n ), } } visualGuide={ props.visualGuide } + marks={ presetMarks } /> } { props.hasContentVerticalAlign && @@ -133,6 +138,15 @@ const Spacing = props => { highlight: 'margin', } + // Add additional presets for setting margins and paddings to None + const nonePreset = { + name: __( 'None', i18n ), + size: '0rem', + slug: 'none', + } + const presetMarks = usePresetControls( 'spacingSizes' ) + ?.getPresetMarks( { additionalPresets: [ nonePreset ] } ) || null + return ( <> { attribute={ getAttrName( 'padding' ) } responsive="all" hover="all" - units={ [ 'px', 'em', '%' ] } + units={ [ 'px', 'em', 'rem', '%' ] } defaultLocked={ true } - min={ [ 0, 0, 0 ] } - sliderMax={ [ 200, 30, 100 ] } + min={ [ 0, 0, 0, 0 ] } + sliderMax={ [ 200, 30, 30, 100 ] } helpTooltip={ { video: 'inner-block-padding', description: __( 'Sets the block paddings, i.e the space between the inner columns and the block border', i18n ), } } visualGuide={ paddingVisualGuide } placeholder={ props.paddingPlaceholder } + marks={ presetMarks } /> { props.enableMargin && @@ -157,16 +172,17 @@ const Spacing = props => { label={ labelMargins } attribute={ getAttrName( 'margin' ) } responsive="all" - units={ [ 'px', '%' ] } + units={ [ 'px', 'rem', '%' ] } defaultLocked={ false } - sliderMin={ [ -200, -100 ] } - sliderMax={ [ 200, 100 ] } + sliderMin={ [ -200, -15, -100 ] } + sliderMax={ [ 200, 15, 100 ] } placeholder="0" helpTooltip={ { video: 'advanced-block-margin', description: __( 'Sets the block margin, i.e. the space outside the block between the block border and the next block.', i18n ), } } visualGuide={ marginVisualGuide } + marks={ presetMarks } /> } > diff --git a/src/block-components/helpers/size/index.js b/src/block-components/helpers/size/index.js index 3303c5b46a..71d4d32c99 100644 --- a/src/block-components/helpers/size/index.js +++ b/src/block-components/helpers/size/index.js @@ -1,3 +1,4 @@ export * from './attributes' export * from './style' export * from './edit' +export { deprecateSizeControlHeight } from './deprecated' diff --git a/src/block-components/typography/attributes.js b/src/block-components/typography/attributes.js index 9013f62d4d..c2b5cfc9e3 100644 --- a/src/block-components/typography/attributes.js +++ b/src/block-components/typography/attributes.js @@ -1,12 +1,6 @@ import { deprecatedAddAttributes } from './deprecated' const typographyAttributes = { - fontSize: { - stkResponsive: true, - type: 'number', - default: '', - stkUnits: 'px', - }, lineHeight: { stkResponsive: true, type: 'number', @@ -104,4 +98,18 @@ export const addAttributes = ( attrObject, selector = '.stk-content', options = versionDeprecated: '', attrNameTemplate, } ) + + attrObject.add( { + attributes: { + fontSize: { + stkResponsive: true, + type: 'string', + default: '', + stkUnits: 'px', + }, + }, + versionAdded: '3.16.0', + versionDeprecated: '', + attrNameTemplate, + } ) } diff --git a/src/block-components/typography/deprecated.js b/src/block-components/typography/deprecated.js index 968b066982..773034113c 100644 --- a/src/block-components/typography/deprecated.js +++ b/src/block-components/typography/deprecated.js @@ -22,6 +22,20 @@ export const deprecatedAddAttributes = ( attrObject, options ) => { versionDeprecated: '3.12.0', attrNameTemplate, } ) + + attrObject.add( { + attributes: { + fontSize: { + stkResponsive: true, + type: 'number', + default: '', + stkUnits: 'px', + }, + }, + versionAdded: '3.0.0', + versionDeprecated: '3.16.0', + attrNameTemplate, + } ) } export const deprecateTypographyGradientColor = { @@ -96,3 +110,27 @@ export const deprecateTypographyShadowColor = { return newAttributes }, } + +export const deprecateTypographyFontSize = { + isEligible: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const fontSize = getAttribute( 'fontSize' ) + + return typeof fontSize === 'number' + }, + migrate: attrNameTemplate => attributes => { + const getAttrName = getAttrNameFunction( attrNameTemplate ) + const getAttribute = _attrName => attributes[ getAttrName( _attrName ) ] + + const fontSize = getAttribute( 'fontSize' ) + + const newAttributes = { + ...attributes, + [ getAttrName( 'fontSize' ) ]: String( fontSize ), + } + + return newAttributes + }, +} diff --git a/src/block-components/typography/edit.js b/src/block-components/typography/edit.js index 9c10a370bd..fc34d1fb3b 100644 --- a/src/block-components/typography/edit.js +++ b/src/block-components/typography/edit.js @@ -3,7 +3,7 @@ */ import { unescape } from 'lodash' import { i18n } from 'stackable' -import { useAttributeEditHandlers } from '~stackable/hooks' +import { useAttributeEditHandlers, usePresetControls } from '~stackable/hooks' import { AlignButtonsControl, AdvancedRangeControl, @@ -30,6 +30,7 @@ import { } from '@wordpress/element' import { __ } from '@wordpress/i18n' import { applyFilters } from '@wordpress/hooks' +import { useSelect } from '@wordpress/data' const TYPOGRAPHY_SHADOWS = [ 'none', @@ -80,6 +81,9 @@ export const Controls = props => { const attributeName = getAttrNameFunction( attrNameTemplate ) const text = getAttribute( 'text' ) const [ debouncedText, setDebouncedText ] = useState( text ) + const useTypographyAsPresets = useSelect( select => + select( 'stackable/global-preset-controls.custom' )?.getUseTypographyAsPresets() ?? false + ) useEffect( () => { if ( text !== debouncedText ) { @@ -100,6 +104,9 @@ export const Controls = props => { const onChangeContent = useCallback( text => setDebouncedText( escapeHTMLIfInvalid( text ) ), [] ) + const presetMarks = usePresetControls( 'fontSizes' ) + ?.getPresetMarks( { customOnly: useTypographyAsPresets } ) || null + return ( <> { applyFilters( 'stackable.block-component.typography.before', null, props ) } @@ -259,9 +266,9 @@ export const Controls = props => { allowReset={ true } attribute={ attributeName( 'fontSize' ) } units={ [ 'px', 'em', 'rem' ] } - min={ [ 0, 0 ] } - sliderMax={ [ 150, 7 ] } - step={ [ 1, 0.05 ] } + min={ [ 0, 0, 0 ] } + sliderMax={ [ 150, 7, 7 ] } + step={ [ 1, 0.05, 0.05 ] } placeholder={ props.sizePlaceholder } responsive="all" helpTooltip={ { @@ -269,6 +276,7 @@ export const Controls = props => { title: __( 'Font size', i18n ), description: __( 'Sets the size of text characters', i18n ), } } + marks={ presetMarks } /> { hasColor && ( diff --git a/src/block-components/typography/index.js b/src/block-components/typography/index.js index 33f5d196a5..664ca2e384 100644 --- a/src/block-components/typography/index.js +++ b/src/block-components/typography/index.js @@ -28,7 +28,9 @@ import { memo, } from '@wordpress/element' -export { deprecateTypographyGradientColor, deprecateTypographyShadowColor } from './deprecated' +export { + deprecateTypographyGradientColor, deprecateTypographyShadowColor, deprecateTypographyFontSize, +} from './deprecated' export const Typography = memo( forwardRef( ( props, ref ) => { const { diff --git a/src/block/accordion/deprecated.js b/src/block/accordion/deprecated.js index 962ab17155..bce1e02cec 100644 --- a/src/block/accordion/deprecated.js +++ b/src/block/accordion/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/blockquote/deprecated.js b/src/block/blockquote/deprecated.js index da35e425a2..ceb5fa453c 100644 --- a/src/block/blockquote/deprecated.js +++ b/src/block/blockquote/deprecated.js @@ -4,10 +4,34 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return isNotV4 || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + version: 2, + } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/button-group/deprecated/index.js b/src/block/button-group/deprecated/index.js index 55251ee121..cc9d3534ad 100644 --- a/src/block/button-group/deprecated/index.js +++ b/src/block/button-group/deprecated/index.js @@ -6,10 +6,29 @@ import { attributes } from '../schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/button/deprecated.js b/src/block/button/deprecated.js index e7b1f9febc..f2e6caf5d6 100644 --- a/src/block/button/deprecated.js +++ b/src/block/button/deprecated.js @@ -6,9 +6,34 @@ import { deprecateBlockBackgroundColorOpacity, deprecateButtonGradientColor, deprecateContainerBackgroundColorOpacity, deprecateShadowColor, deprecateContainerShadowColor, deprecateBlockShadowColor, + deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'button%s' )( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateButtonGradientColor.migrate( 'button%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'button%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/call-to-action/deprecated.js b/src/block/call-to-action/deprecated.js index e185c0314b..d7c8e0c7d4 100644 --- a/src/block/call-to-action/deprecated.js +++ b/src/block/call-to-action/deprecated.js @@ -10,7 +10,8 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' import compareVersions from 'compare-versions' @@ -35,6 +36,79 @@ addFilter( 'stackable.call-to-action.save.innerClassNames', 'stackable/3.8.0', ( } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return [ newAttributes, innerBlocks ] + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -44,9 +118,8 @@ const deprecated = [ const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) const hasTopSeparatorShadow = deprecateShadowColor.isEligible( 'topSeparator%s' )( attributes ) const hasBottomSeparatorShadow = deprecateShadowColor.isEligible( 'bottomSeparator%s' )( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || hasTopSeparatorShadow || hasBottomSeparatorShadow || isNotV4 + return hasBlockShadow || hasContainerShadow || hasTopSeparatorShadow || hasBottomSeparatorShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -116,9 +189,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -186,11 +258,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/card/deprecated.js b/src/block/card/deprecated.js index da6cd555bd..032439e3c5 100644 --- a/src/block/card/deprecated.js +++ b/src/block/card/deprecated.js @@ -12,7 +12,8 @@ import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecationImageOverlayOpacity, getAlignmentClasses, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** @@ -86,6 +87,78 @@ addFilter( 'stackable.card.save.innerClassNames', 'stackable/3.0.2', ( output, p } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecationImageOverlayOpacity.migrate( newAttributes ), + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return [ newAttributes, innerBlocks ] + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -93,9 +166,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -164,9 +236,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 || deprecationImageOverlayOpacity.isEligible( attributes ) + return hasContainerOpacity || hasBlockOpacity || deprecationImageOverlayOpacity.isEligible( attributes ) }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -233,11 +304,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/carousel/deprecated.js b/src/block/carousel/deprecated.js index 047bfa76c6..8ad029e728 100644 --- a/src/block/carousel/deprecated.js +++ b/src/block/carousel/deprecated.js @@ -1,6 +1,7 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateBlockHeight, + deprecateColumnAndRowGap, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +9,30 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for block height and gaps + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberGaps = deprecateColumnAndRowGap.isEligible( '%s' )( attributes ) + return hasNumberBlockHeight || hasNumberGaps + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateColumnAndRowGap.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/column/deprecated.js b/src/block/column/deprecated.js index 1c889b75e5..bd56ff8659 100644 --- a/src/block/column/deprecated.js +++ b/src/block/column/deprecated.js @@ -17,7 +17,8 @@ import { addFilter } from '@wordpress/hooks' import { semverCompare } from '~stackable/util' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' // Version 3.8 added horizontal flex, we changed the stk--block-orientation-* to stk--block-horizontal-flex. @@ -75,6 +76,81 @@ addFilter( 'stackable.column.save.blockClassNames', 'stackable/3.8.0', ( output, } ) const deprecated = [ + { + // Support the change of type for block height, innerBlockRowGap and containerHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 4, + className: classnames( attributes.className, { + 'stk-block-column--v2': false, + 'stk-block-column--v3': false, + } ), + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return [ newAttributes, innerBlocks ] + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -82,9 +158,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' @@ -156,9 +231,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' @@ -228,11 +302,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 4 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/column/edit.js b/src/block/column/edit.js index 72b8f7e085..a2c2a6707e 100644 --- a/src/block/column/edit.js +++ b/src/block/column/edit.js @@ -8,7 +8,7 @@ import blockStyles from './style' */ import classnames from 'classnames' import { i18n, version as VERSION } from 'stackable' -import { useBlockLayoutDefaults } from '~stackable/hooks' +import { useBlockLayoutDefaults, usePresetControls } from '~stackable/hooks' import { AdvancedToggleControl, FourRangeControl, @@ -164,6 +164,8 @@ const Edit = props => { // props used by controls to prevent rerenders of all the inspector controls. const InspectorControls = memo( props => { const { getPlaceholder } = useBlockLayoutDefaults() + const presets = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + return ( <> @@ -187,6 +189,7 @@ const InspectorControls = memo( props => { highlight: 'column-spacing', defaultValue: '12px', } } + marks={ presets } /> diff --git a/src/block/columns/deprecated.js b/src/block/columns/deprecated.js index 8b6d5db023..2a9a521b85 100644 --- a/src/block/columns/deprecated.js +++ b/src/block/columns/deprecated.js @@ -17,6 +17,7 @@ import { semverCompare } from '~stackable/util' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockHeight, deprecateColumnAndRowGap, } from '~stackable/block-components' // Version 3.6.2 Deprecations, we now don't need the stk--has-column-order class. @@ -36,6 +37,36 @@ addFilter( 'stackable.columns.save.contentClassNames', 'stackable/3.8.0', ( clas } ) const deprecated = [ + { + // Support the change of type for block height and gaps + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasColumnFit = !! attributes.columnFit + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberGaps = deprecateColumnAndRowGap.isEligible( '%s' )( attributes ) + return hasColumnFit || hasNumberBlockHeight || hasNumberGaps + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + columnFit: '', + columnFitAlign: '', + columnJustify: !! attributes.columnFit ? ( attributes.columnFitAlign || 'flex-start' ) : '', + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateColumnAndRowGap.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/count-up/deprecated.js b/src/block/count-up/deprecated.js index 0db6560075..f2f6276b34 100644 --- a/src/block/count-up/deprecated.js +++ b/src/block/count-up/deprecated.js @@ -4,10 +4,35 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/countdown/deprecated.js b/src/block/countdown/deprecated.js index 31e834a1aa..cd79416fee 100644 --- a/src/block/countdown/deprecated.js +++ b/src/block/countdown/deprecated.js @@ -1,6 +1,6 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +8,37 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasDigitFontSize = deprecateTypographyFontSize.isEligible( 'digit%s' )( attributes ) + const hasLabelFontSize = deprecateTypographyFontSize.isEligible( 'label%s' )( attributes ) + const hasMessageFontSize = deprecateTypographyFontSize.isEligible( 'message%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + return hasDigitFontSize || hasLabelFontSize || hasMessageFontSize || hasNumberBlockHeight || isNotV4 + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'digit%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'label%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'message%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'digit%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'label%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'message%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/divider/deprecated.js b/src/block/divider/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/divider/deprecated.js +++ b/src/block/divider/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/expand/deprecated.js b/src/block/expand/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/expand/deprecated.js +++ b/src/block/expand/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/feature-grid/deprecated.js b/src/block/feature-grid/deprecated.js index d8792d68d8..54f389c38f 100644 --- a/src/block/feature-grid/deprecated.js +++ b/src/block/feature-grid/deprecated.js @@ -13,6 +13,7 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, getResponsiveClasses, getSeparatorClasses, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockHeight, deprecateColumnAndRowGap, } from '~stackable/block-components' /** @@ -60,6 +61,36 @@ addFilter( 'stackable.feature-grid.save.blockClassNames', 'stackable/3.1.0', ( o } ) const deprecated = [ + { + // Support the change of type for block height and gaps + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasColumnFit = !! attributes.columnFit + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberGaps = deprecateColumnAndRowGap.isEligible( '%s' )( attributes ) + return hasColumnFit || hasNumberBlockHeight || hasNumberGaps + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + columnFit: '', + columnFitAlign: '', + columnJustify: !! attributes.columnFit ? ( attributes.columnFitAlign || 'flex-start' ) : '', + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateColumnAndRowGap.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/feature/deprecated.js b/src/block/feature/deprecated.js index 851ca5574a..8c571f29d9 100644 --- a/src/block/feature/deprecated.js +++ b/src/block/feature/deprecated.js @@ -14,6 +14,7 @@ import { deprecateContainerBackgroundColorOpacity, getAlignmentClasses, getContentAlignmentClasses, getRowClasses, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockHeight, deprecateColumnAndRowGap, } from '~stackable/block-components' /** @@ -62,6 +63,45 @@ addFilter( 'stackable.feature.save.innerClassNames', 'stackable/3.8.0', ( output } ) const deprecated = [ + { + // Support the change of type for block height and gaps + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberGaps = deprecateColumnAndRowGap.isEligible( '%s' )( attributes ) + return isNotV4 || hasNumberBlockHeight || hasNumberGaps + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + version: 2, + } + + // Update the old column fit into flexbox + const hasOldColumnFit = !! attributes.columnFit + if ( hasOldColumnFit ) { + newAttributes = { + ...newAttributes, + columnFit: '', + columnFitAlign: '', + columnJustify: attributes.columnFitAlign, + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateColumnAndRowGap.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/heading/deprecated.js b/src/block/heading/deprecated.js index e8cc3be197..940d743ed1 100644 --- a/src/block/heading/deprecated.js +++ b/src/block/heading/deprecated.js @@ -11,7 +11,7 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, getResponsiveClasses, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyShadowColor, deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' /** @@ -34,6 +34,30 @@ addFilter( 'stackable.heading.save.blockClassNames', 'stackable/3.6.1', ( output } ) const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/hero/deprecated.js b/src/block/hero/deprecated.js index cc43238e39..6f4530145c 100644 --- a/src/block/hero/deprecated.js +++ b/src/block/hero/deprecated.js @@ -12,6 +12,7 @@ import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockHeight, deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** @@ -35,6 +36,79 @@ addFilter( 'stackable.hero.save.innerClassNames', 'stackable/3.8.0', ( output, p } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'topSeparator%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'bottomSeparator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -44,9 +118,8 @@ const deprecated = [ const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) const hasTopSeparatorShadow = deprecateShadowColor.isEligible( 'topSeparator%s' )( attributes ) const hasBottomSeparatorShadow = deprecateShadowColor.isEligible( 'bottomSeparator%s' )( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || hasTopSeparatorShadow || hasBottomSeparatorShadow || isNotV4 + return hasBlockShadow || hasContainerShadow || hasTopSeparatorShadow || hasBottomSeparatorShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -116,9 +189,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -186,11 +258,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/horizontal-scroller/deprecated.js b/src/block/horizontal-scroller/deprecated.js index a3d054b758..649edab8b7 100644 --- a/src/block/horizontal-scroller/deprecated.js +++ b/src/block/horizontal-scroller/deprecated.js @@ -4,7 +4,7 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' import { addFilter } from '@wordpress/hooks' import compareVersions from 'compare-versions' @@ -22,6 +22,25 @@ addFilter( 'stackable.horizontal-scroller.save.contentClassNames', 'stackable/3_ } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/icon-box/deprecated.js b/src/block/icon-box/deprecated.js index 7a6bc048e0..e1ccc1cf3c 100644 --- a/src/block/icon-box/deprecated.js +++ b/src/block/icon-box/deprecated.js @@ -4,10 +4,45 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return isNotV4 || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/icon-button/deprecated.js b/src/block/icon-button/deprecated.js index 9bf89108c1..cab6b3f206 100644 --- a/src/block/icon-button/deprecated.js +++ b/src/block/icon-button/deprecated.js @@ -5,10 +5,31 @@ import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateButtonGradientColor, deprecateContainerBackgroundColorOpacity, deprecateShadowColor, - deprecateContainerShadowColor, deprecateBlockShadowColor, + deprecateContainerShadowColor, deprecateBlockShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateButtonGradientColor.migrate( 'button%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'button%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/icon-label/deprecated.js b/src/block/icon-label/deprecated.js index 99014e6cbb..9ae19d5cd8 100644 --- a/src/block/icon-label/deprecated.js +++ b/src/block/icon-label/deprecated.js @@ -4,10 +4,25 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { attributes: attributes( '3.13.1' ), save: withVersion( '3.13.1' )( Save ), diff --git a/src/block/icon-list-item/deprecated.js b/src/block/icon-list-item/deprecated.js index 2c6633b1ac..1afa1eaa31 100644 --- a/src/block/icon-list-item/deprecated.js +++ b/src/block/icon-list-item/deprecated.js @@ -2,9 +2,31 @@ import { Save } from './save' import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' -import { deprecateBlockShadowColor, deprecateContainerShadowColor } from '~stackable/block-components' +import { + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, deprecateBlockHeight, +} from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/icon-list/deprecated/index.js b/src/block/icon-list/deprecated/index.js index a137d3593c..38173ea3cf 100644 --- a/src/block/icon-list/deprecated/index.js +++ b/src/block/icon-list/deprecated/index.js @@ -4,7 +4,7 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' import { createUniqueClass } from '~stackable/util' @@ -68,6 +68,69 @@ const getEquivalentIconSize = iconSize => { } const deprecated = [ + { + // Support the change of type for font size and block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + supports: { + anchor: true, + spacing: true, + __unstablePasteTextInline: true, + __experimentalSelector: 'ol,ul', + __experimentalOnMerge: true, + }, + migrate: ( attributes, innerBlocks ) => { + let newAttributes = { ...attributes } + const { + text, icons, iconSize, ordered, iconGap, + } = attributes + + const _iconSize = iconSize ? iconSize : 1 + const _iconGap = iconGap ? iconGap : 0 + + newAttributes = { + ...newAttributes, + listFullWidth: false, + iconVerticalAlignment: 'baseline', + iconGap: _iconGap + 4, // Our gap is smaller now. + iconSize: ordered + ? getEquivalentFontSize( _iconSize ) + : getEquivalentIconSize( _iconSize ), + } + + if ( ! text ) { + const block = createBlock( 'stackable/icon-list-item' ) + innerBlocks = [ block ] + } else { + const contents = textToArray( text ) + const blocks = contents.map( ( content, index ) => { + const newBlock = createBlock( 'stackable/icon-list-item', { + text: content, + icon: getUniqueIcon( icons, index ), + } ) + newBlock.attributes.uniqueId = createUniqueClass( newBlock.clientId ) + + return newBlock + } ) + innerBlocks = blocks + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return [ newAttributes, innerBlocks ] + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/icon/deprecated.js b/src/block/icon/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/icon/deprecated.js +++ b/src/block/icon/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/image-box/deprecated.js b/src/block/image-box/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/image-box/deprecated.js +++ b/src/block/image-box/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/image/deprecated.js b/src/block/image/deprecated.js index 04e709ee1a..94d231f322 100644 --- a/src/block/image/deprecated.js +++ b/src/block/image/deprecated.js @@ -4,7 +4,8 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecationImageOverlayOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' import { RichText } from '@wordpress/block-editor' @@ -59,6 +60,30 @@ addFilter( 'stackable.image.save.wrapper', 'stackable/image-caption-wrapper', ( } ) const deprecated = [ + { + // Support the change of type for fontSize + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( 'figcaption%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecationImageOverlayOpacity.migrate( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'image%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'figcaption%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/map/deprecated.js b/src/block/map/deprecated.js index 90e9210c9c..06a727f8d6 100644 --- a/src/block/map/deprecated.js +++ b/src/block/map/deprecated.js @@ -7,7 +7,7 @@ import { withVersion } from '~stackable/higher-order' import { semverCompare, createElementFromHTMLString } from '~stackable/util' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' import { addFilter } from '@wordpress/hooks' @@ -35,6 +35,25 @@ addFilter( 'stackable.map.icon-options', 'stackable/3.13.0', ( output, attribute } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/notification/deprecated.js b/src/block/notification/deprecated.js index 843109e860..7301fc146c 100644 --- a/src/block/notification/deprecated.js +++ b/src/block/notification/deprecated.js @@ -11,7 +11,8 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** @@ -35,6 +36,77 @@ addFilter( 'stackable.notification.save.innerClassNames', 'stackable/3.8.0', ( o } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -42,9 +114,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -112,9 +183,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -180,11 +250,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/number-box/deprecated.js b/src/block/number-box/deprecated.js index 45adeda965..cc3107628a 100644 --- a/src/block/number-box/deprecated.js +++ b/src/block/number-box/deprecated.js @@ -4,7 +4,8 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateTypographyGradientColor, deprecationBackgrounColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, BlockDiv, CustomCSS, Typography, getResponsiveClasses, getTypographyClasses, getAlignmentClasses, } from '~stackable/block-components' @@ -53,6 +54,28 @@ const depecatedSave_3_13_11 = props => { } const deprecated = [ + { + // Support the change of type for fontSize + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = deprecateBlockBackgroundColorOpacity.migrate( attributes ) + newAttributes = deprecationBackgrounColorOpacity.migrate( 'shape%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'shape%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { attributes: attributes( '3.13.11' ), save: depecatedSave_3_13_11, diff --git a/src/block/posts/deprecated.js b/src/block/posts/deprecated.js index 88bb28a624..a46cecb9d7 100644 --- a/src/block/posts/deprecated.js +++ b/src/block/posts/deprecated.js @@ -13,6 +13,7 @@ import { Image, deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, deprecationImageOverlayOpacity, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' /** @@ -41,6 +42,80 @@ addFilter( 'stackable.posts.title.readmore-content', 'stackable/3_0_2', addUndef addFilter( 'stackable.posts.feature-image', 'stackable/3_6_3', determineFeatureImage ) const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSizeTitle = deprecateTypographyFontSize.isEligible( 'title%s' )( attributes ) + const hasNumberFontSizeCategory = deprecateTypographyFontSize.isEligible( 'category%s' )( attributes ) + const hasNumberFontSizeExcerpt = deprecateTypographyFontSize.isEligible( 'excerpt%s' )( attributes ) + const hasNumberFontSizeMeta = deprecateTypographyFontSize.isEligible( 'meta%s' )( attributes ) + const hasNumberFontSizeReadmore = deprecateTypographyFontSize.isEligible( 'readmore%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + return hasNumberFontSizeTitle || hasNumberFontSizeCategory || hasNumberFontSizeExcerpt || + hasNumberFontSizeMeta || hasNumberFontSizeReadmore || hasNumberBlockHeight || isNotV4 + }, + migrate: attributes => { + let newAttributes = { + ...attributes, + version: 2, + } + + // We used to have an "Inner content width" which is now just the block width + const hasOldInnerContentWidth = attributes.innerBlockContentWidth || attributes.innerBlockContentWidthTablet || attributes.innerBlockContentWidthMobile + + if ( hasOldInnerContentWidth ) { + newAttributes = { + ...newAttributes, + innerBlockContentWidth: '', + innerBlockContentWidthTablet: '', + innerBlockContentWidthMobile: '', + innerBlockContentWidthUnit: 'px', + innerBlockContentWidthUnitTablet: '', + innerBlockContentWidthUnitMobile: '', + blockWidth: attributes.innerBlockContentWidth, + blockWidthTablet: attributes.innerBlockContentWidthTablet, + blockWidthMobile: attributes.innerBlockContentWidthMobile, + blockWidthUnit: attributes.innerBlockContentWidthUnit, + blockWidthUnitTablet: attributes.innerBlockContentWidthUnitTablet, + blockWidthUnitMobile: attributes.innerBlockContentWidthUnitMobile, + innerBlockAlign: '', + innerBlockAlignTablet: '', + innerBlockAlignMobile: '', + blockHorizontalAlign: attributes.innerBlockAlign, + blockHorizontalAlignTablet: attributes.innerBlockAlignTablet, + blockHorizontalAlignMobile: attributes.innerBlockAlignMobile, + } + } + + newAttributes = deprecationImageOverlayOpacity.migrate( newAttributes ) + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + + newAttributes = deprecateTypographyGradientColor.migrate( 'title%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'category%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'excerpt%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'meta%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'readmore%s' )( newAttributes ) + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'image%s' )( newAttributes ) + + newAttributes = deprecateTypographyFontSize.migrate( 'title%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'category%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'excerpt%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'meta%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'readmore%s' )( newAttributes ) + + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/price/deprecated.js b/src/block/price/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/price/deprecated.js +++ b/src/block/price/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/pricing-box/deprecated.js b/src/block/pricing-box/deprecated.js index aa0e1113fa..194bed3fbf 100644 --- a/src/block/pricing-box/deprecated.js +++ b/src/block/pricing-box/deprecated.js @@ -11,7 +11,8 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** * WordPress dependencies @@ -34,6 +35,77 @@ addFilter( 'stackable.pricing-box.save.innerClassNames', 'stackable/3.8.0', ( ou } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -41,9 +113,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -111,9 +182,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -179,11 +249,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/progress-bar/deprecated.js b/src/block/progress-bar/deprecated.js index 0db6560075..f2f6276b34 100644 --- a/src/block/progress-bar/deprecated.js +++ b/src/block/progress-bar/deprecated.js @@ -4,10 +4,35 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/progress-circle/deprecated.js b/src/block/progress-circle/deprecated.js index 0db6560075..f2f6276b34 100644 --- a/src/block/progress-circle/deprecated.js +++ b/src/block/progress-circle/deprecated.js @@ -4,10 +4,35 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/separator/deprecated.js b/src/block/separator/deprecated.js index 329d461cd9..d5f04d49c5 100644 --- a/src/block/separator/deprecated.js +++ b/src/block/separator/deprecated.js @@ -5,9 +5,30 @@ import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'separator%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/spacer/deprecated.js b/src/block/spacer/deprecated.js index 395ffb36b0..12f770094a 100644 --- a/src/block/spacer/deprecated.js +++ b/src/block/spacer/deprecated.js @@ -4,10 +4,29 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/subtitle/deprecated.js b/src/block/subtitle/deprecated.js index a0c6c42406..67a57c8e50 100644 --- a/src/block/subtitle/deprecated.js +++ b/src/block/subtitle/deprecated.js @@ -4,10 +4,35 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/tab-content/deprecated.js b/src/block/tab-content/deprecated.js index 57fd88d266..fe39c800d5 100644 --- a/src/block/tab-content/deprecated.js +++ b/src/block/tab-content/deprecated.js @@ -1,6 +1,7 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateColumnAndRowGap, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +9,28 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for block height and gaps + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberGaps = deprecateColumnAndRowGap.isEligible( '%s' )( attributes ) + return hasNumberBlockHeight || hasNumberGaps + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateColumnAndRowGap.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/tab-labels/deprecated.js b/src/block/tab-labels/deprecated.js index 6f6cca19d5..81268855a2 100644 --- a/src/block/tab-labels/deprecated.js +++ b/src/block/tab-labels/deprecated.js @@ -1,6 +1,7 @@ import { deprecateBlockBackgroundColorOpacity, deprecateButtonGradientColor, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateTypographyShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateShadowColor, deprecateTypographyShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +9,34 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( 'tab%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'tab%s' )( newAttributes ) + newAttributes = deprecateButtonGradientColor.migrate( 'tab%s' )( newAttributes ) + newAttributes = deprecateButtonGradientColor.migrate( 'activeTab%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'tab%s' )( newAttributes ) + newAttributes = deprecateShadowColor.migrate( 'activeTab%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'tab%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/table-of-contents/deprecated.js b/src/block/table-of-contents/deprecated.js index 1aa3cccf62..b1e3ebcdd5 100644 --- a/src/block/table-of-contents/deprecated.js +++ b/src/block/table-of-contents/deprecated.js @@ -11,7 +11,7 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, deprecateBlockHeight, } from '~stackable/block-components' /** @@ -36,6 +36,31 @@ addFilter( 'stackable.table-of-contents.save.tableOfContentsClasses', 'stackable } ) const deprecated = [ + { + // Support the change of type for fontSize and blockHeight + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( 'title%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( 'title%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( 'title%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/tabs/deprecated.js b/src/block/tabs/deprecated.js index 85ccf8730f..5935646d95 100644 --- a/src/block/tabs/deprecated.js +++ b/src/block/tabs/deprecated.js @@ -1,6 +1,6 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +8,36 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) + if ( hasContainerOpacity ) { + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + } + + const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) + if ( hasBlockOpacity ) { + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + } + + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return { + ...newAttributes, + equalTabHeight: true, + } + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/team-member/deprecated.js b/src/block/team-member/deprecated.js index ef5c7d6b2a..5b53977354 100644 --- a/src/block/team-member/deprecated.js +++ b/src/block/team-member/deprecated.js @@ -11,7 +11,8 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** @@ -35,6 +36,77 @@ addFilter( 'stackable.team-member.save.innerClassNames', 'stackable/3.8.0', ( ou } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -42,9 +114,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -112,9 +183,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -180,11 +250,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/testimonial/deprecated.js b/src/block/testimonial/deprecated.js index cc64e5fd2e..c2223e61da 100644 --- a/src/block/testimonial/deprecated.js +++ b/src/block/testimonial/deprecated.js @@ -11,7 +11,8 @@ import { withVersion } from '~stackable/higher-order' import compareVersions from 'compare-versions' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, + deprecateInnerBlockRowGapAndContainerHeight, } from '~stackable/block-components' /** @@ -35,6 +36,77 @@ addFilter( 'stackable.testimonial.save.innerClassNames', 'stackable/3.8.0', ( ou } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + const hasNumberInnerBlockRowGapAndContainerHeight = deprecateInnerBlockRowGapAndContainerHeight.isEligible( '%s' )( attributes ) + + return hasNumberBlockHeight || hasNumberInnerBlockRowGapAndContainerHeight + }, + migrate: ( attributes, innerBlocks ) => { + const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' + + let newAttributes = { + ...attributes, + } + + if ( isNotV4 ) { + newAttributes = { + ...newAttributes, + version: 2, + } + + // Update the vertical align into flexbox + const hasOldVerticalAlign = !! attributes.containerVerticalAlign // Column only, this was changed to flexbox + + if ( hasOldVerticalAlign ) { + newAttributes = { + ...newAttributes, + containerVerticalAlign: '', + innerBlockAlign: attributes.containerVerticalAlign, + } + } + + // If the inner blocks are horizontal, adjust to accomodate the new + // column gap, it will modify blocks because people used block + // margins before instead of a proper column gap. + if ( attributes.innerBlockOrientation === 'horizontal' ) { + innerBlocks.forEach( ( block, index ) => { + if ( index ) { + if ( ! block.attributes.blockMargin ) { + block.attributes.blockMargin = { + top: '', + right: '', + bottom: '', + left: '', + } + } + if ( block.attributes.blockMargin.left === '' ) { + block.attributes.blockMargin.left = 24 + } + } + } ) + + newAttributes = { + ...newAttributes, + innerBlockColumnGap: 0, + } + } + } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + newAttributes = deprecateInnerBlockRowGapAndContainerHeight.migrate( '%s' )( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), @@ -42,9 +114,8 @@ const deprecated = [ isEligible: attributes => { const hasBlockShadow = deprecateBlockShadowColor.isEligible( attributes ) const hasContainerShadow = deprecateContainerShadowColor.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasBlockShadow || hasContainerShadow || isNotV4 + return hasBlockShadow || hasContainerShadow }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -112,9 +183,8 @@ const deprecated = [ isEligible: attributes => { const hasContainerOpacity = deprecateContainerBackgroundColorOpacity.isEligible( attributes ) const hasBlockOpacity = deprecateBlockBackgroundColorOpacity.isEligible( attributes ) - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - return hasContainerOpacity || hasBlockOpacity || isNotV4 + return hasContainerOpacity || hasBlockOpacity }, migrate: ( attributes, innerBlocks ) => { const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' @@ -180,11 +250,6 @@ const deprecated = [ // layout & containers work. attributes: attributes( '3.7.9' ), save: withVersion( '3.7.9' )( Save ), - isEligible: attributes => { - const isNotV4 = attributes.version < 2 || typeof attributes.version === 'undefined' - - return isNotV4 - }, migrate: ( attributes, innerBlocks ) => { let newAttributes = { ...attributes, diff --git a/src/block/text/deprecated.js b/src/block/text/deprecated.js index 57d902aa2b..09db68cd5f 100644 --- a/src/block/text/deprecated.js +++ b/src/block/text/deprecated.js @@ -4,10 +4,35 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' const deprecated = [ + { + // Support the change of type for fontSize + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/timeline/deprecated.js b/src/block/timeline/deprecated.js index 8ef5054ff1..c4979c84ac 100644 --- a/src/block/timeline/deprecated.js +++ b/src/block/timeline/deprecated.js @@ -1,6 +1,7 @@ import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, deprecateTypographyGradientColor, - deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateTypographyShadowColor, deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateTypographyFontSize, + deprecateBlockHeight, } from '~stackable/block-components' import { Save } from './save' import { attributes } from './schema' @@ -8,6 +9,30 @@ import { attributes } from './schema' import { withVersion } from '~stackable/higher-order' const deprecated = [ + { + // Support the change of type for fontSize + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + const hasNumberFontSize = deprecateTypographyFontSize.isEligible( '%s' )( attributes ) + const hasNumberBlockHeight = deprecateBlockHeight.isEligible( attributes ) + return hasNumberFontSize || hasNumberBlockHeight + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateContainerBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateBlockBackgroundColorOpacity.migrate( newAttributes ) + newAttributes = deprecateTypographyGradientColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockShadowColor.migrate( newAttributes ) + newAttributes = deprecateContainerShadowColor.migrate( newAttributes ) + newAttributes = deprecateTypographyShadowColor.migrate( '%s' )( newAttributes ) + newAttributes = deprecateTypographyFontSize.migrate( '%s' )( newAttributes ) + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { // Support the new shadow color. attributes: attributes( '3.12.11' ), diff --git a/src/block/video-popup/deprecated.js b/src/block/video-popup/deprecated.js index 7d84849ead..471924dfde 100644 --- a/src/block/video-popup/deprecated.js +++ b/src/block/video-popup/deprecated.js @@ -6,7 +6,7 @@ import { semverCompare } from '~stackable/util' import { i18n } from 'stackable' import { deprecateBlockBackgroundColorOpacity, deprecateContainerBackgroundColorOpacity, - deprecateBlockShadowColor, deprecateContainerShadowColor, + deprecateBlockShadowColor, deprecateContainerShadowColor, deprecateBlockHeight, } from '~stackable/block-components' /** @@ -28,6 +28,21 @@ addFilter( 'stackable.video-popup.save.div.content', 'stackable/3.12.14', ( outp } ) const deprecated = [ + { + // Support the change of type for block height + attributes: attributes( '3.15.3' ), + save: withVersion( '3.15.3' )( Save ), + isEligible: attributes => { + return deprecateBlockHeight.isEligible( attributes ) + }, + migrate: attributes => { + let newAttributes = { ...attributes } + + newAttributes = deprecateBlockHeight.migrate( newAttributes ) + + return newAttributes + }, + }, { attributes: attributes( '3.12.14' ), save: withVersion( '3.12.14' )( Save ), diff --git a/src/components/advanced-range-control/editor.scss b/src/components/advanced-range-control/editor.scss index cf8dcd26fb..5e437de64e 100644 --- a/src/components/advanced-range-control/editor.scss +++ b/src/components/advanced-range-control/editor.scss @@ -46,4 +46,30 @@ .components-number-control { width: unset; } + + // For displaying marks + .components-range-control__thumb-wrapper { + z-index: 2; + } + .components-range-control__mark { + background: var(--stk-skin-bg-default) !important; + z-index: 1; + transform: translateX(-50%); + width: 3px; + } + .components-range-control__root { + min-height: 35px; + } + .stk-range-control__custom-button { + margin-inline-start: 8px; + top: -1px; + position: relative; + } +} +.stk-range-control--with-marks.stk-range-control--mark-mode .components-range-control__wrapper { + margin-inline-end: 8px; +} + +div.components-base-control.stk-preset-controls { + flex-grow: 1; } diff --git a/src/components/advanced-range-control/index.js b/src/components/advanced-range-control/index.js index 07031eeed9..e36589efdb 100644 --- a/src/components/advanced-range-control/index.js +++ b/src/components/advanced-range-control/index.js @@ -6,22 +6,31 @@ import { useControlHandlers } from '../base-control2/hooks' import AdvancedControl, { extractControlProps } from '../base-control2' import DynamicContentControl, { useDynamicContentControlProps } from '../dynamic-content-control' import { ResetButton } from '../base-control2/reset-button' +/** + * External dependencies + */ +import { isEqual } from 'lodash' import { useAttributeName, useBlockAttributesContext, useBlockHoverState, + useBlockSetAttributesContext, useDeviceType, } from '~stackable/hooks' - -/** - * External dependencies - */ -import { isEqual } from 'lodash' +import { + extractNumbersAndUnits, getCSSVarName, convertToPxIfUnsupported, +} from '~stackable/util' +import { settings as stackableSettings } from 'stackable' /** * WordPress dependencies */ -import { memo } from '@wordpress/element' +import { + memo, useState, useEffect, useRef, +} from '@wordpress/element' +import { Button } from '@wordpress/components' +import { settings } from '@wordpress/icons' +import { dispatch } from '@wordpress/data' const AdvancedRangeControl = props => { const [ value, onChange ] = useControlHandlers( props.attribute, props.responsive, props.hover, props.valueCallback, props.changeCallback ) @@ -30,6 +39,7 @@ const AdvancedRangeControl = props => { const deviceType = useDeviceType() const [ currentHoverState ] = useBlockHoverState() const hasUnits = !! props.units?.length + const setAttributes = useBlockSetAttributesContext() const unitAttrName = useAttributeName( `${ props.attribute }Unit`, props.responsive, props.hover ) const { unitAttribute, @@ -51,6 +61,8 @@ const AdvancedRangeControl = props => { ? ( props.unit || props.units?.[ 0 ] || 'px' ) : ( unitAttribute || '' ) + const isMarkModeDefault = !! ( stackableSettings?.stackable_use_size_presets_by_default ?? true ) + // Change the min, max & step values depending on the unit used. if ( hasUnits ) { const i = props.units.indexOf( unit ) < 0 ? 0 : props.units.indexOf( unit ) @@ -98,11 +110,39 @@ const AdvancedRangeControl = props => { placeholderRender = null } - // If this supports dynamic content, then the value should be saved as a String. + let derivedValue = typeof props.value === 'undefined' + ? value : props.value + + // Is value at first render the same as a step value? If so, do mark mode + // at the start, or show custom + // If no initial value, use the given default from the settings + const [ isMarkMode, setIsMarkMode ] = useState( false ) + // Ensure the convesion of value from preset to custom with regards to the unit is donce once. + const isConversionDone = useRef( false ) + + let isMarkValue = !! props.marks && isMarkModeDefault + if ( props.marks && derivedValue ) { + // Check if the current value exists in the marks only by their CSS variable name + // to match in case the fallback size changes. + const derivedValueCssVarName = getCSSVarName( derivedValue ) + const matchedMark = props.marks.find( mark => getCSSVarName( mark.value ) === derivedValueCssVarName ) + isMarkValue = !! matchedMark + if ( matchedMark ) { + derivedValue = matchedMark.value + } + } + + // Set the markMode when device type changes + useEffect( () => { + setIsMarkMode( isMarkValue ) + }, [ deviceType ] ) + + // If this supports dynamic content, the value should be saved as a String. + // Similar if using marks to accomodate CSS variable // Important, the attribute type for this option should be a string. const _onChange = value => { const onChangeFunc = typeof props.onChange === 'undefined' ? onChange : props.onChange - let newValue = props.isDynamic ? value.toString() : value + let newValue = props.isDynamic || props.marks ? value.toString() : value // On reset, allow overriding the value. if ( newValue === '' ) { @@ -114,13 +154,126 @@ const AdvancedRangeControl = props => { onChangeFunc( newValue ) } - const derivedValue = typeof props.value === 'undefined' ? value : props.value - const dynamicContentProps = useDynamicContentControlProps( { value: derivedValue, onChange: _onChange, } ) + // Support for steps. Modify the props to make the range control show steps. + if ( props.marks && isMarkMode ) { + // Steps only have 1 increment values + propsToPass.min = 0 + propsToPass.max = props.marks.length - 1 + propsToPass.sliderMax = props.marks.length - 1 + propsToPass.step = 1 + + // Show the marks and names + propsToPass.marks = props.marks.reduce( ( acc, mark, index ) => { + return [ + { + value: index, + name: undefined, + }, + ...acc, + ] + }, [] ) + propsToPass.renderTooltipContent = value => { + return props.marks[ value ]?.name || props.marks[ value ]?.slug || '' + } + + // Other necessary props for steps. + propsToPass.withInputField = false + controlProps.units = false + } else { + propsToPass.marks = undefined + } + + if ( props.marks ) { + controlProps.className = controlProps.className || '' + controlProps.className += 'stk-range-control--with-marks' + controlProps.className += isMarkMode ? ' stk-range-control--mark-mode' : '' + } + + if ( props.isCustomPreset ) { + controlProps.className = controlProps.className || '' + controlProps.className += 'stk-preset-controls' + } + + // We need to change the way we handle the value and onChange if we're doing marks + // Convert to float if the attribute is string to work with the slider + let rangeValue = propsToPass.isDynamic || props.marks ? parseFloat( derivedValue ) : derivedValue + let rangeOnChange = _onChange + if ( isMarkMode ) { + rangeValue = props.marks.findIndex( mark => { + let _unit, _value + // If the derivedValue is a CSS variable, compare with mark's CSS variable. + // Otherwise, the derivedValue is custom from the previous switch from custom to preset mode, + // so compare with raw size and units to convert to preset. + if ( typeof derivedValue === 'string' && derivedValue.startsWith( 'var' ) ) { + [ _value, _unit ] = extractNumbersAndUnits( mark.value )[ 0 ] + } else { + [ _value, _unit ] = extractNumbersAndUnits( mark.size )[ 0 ] + } + return _value === derivedValue && ( _unit === '' || _unit === unit ) + } ) + rangeOnChange = ( value, property = 'value' ) => { + if ( value === '' ) { + return _onChange( value ) + } + // Extract the unit and value. + const markValue = props.marks[ value ]?.[ property ] || '0' + let [ newValue, unit ] = extractNumbersAndUnits( markValue )[ 0 ] + + // If the attribute has no support for rem or em, and the + // preset units is rem or em, convert to px + const converted = convertToPxIfUnsupported( props.units, unit, newValue ) + newValue = converted.value + unit = converted.unit + + // Update the unit. + if ( unit ) { + dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent() + setAttributes( { [ unitAttrName ]: unit } ) + if ( props.onChangeUnit ) { + props.onChangeUnit( unit ) + } + } + + _onChange( newValue ) + isConversionDone.current = false + } + } else if ( typeof derivedValue === 'string' && derivedValue.startsWith( 'var' ) ) { + // If the derivedValue is a preset and currently not in mark mode, the derivedValue is from + // the previous switch from preset to custom mode. Convert to custom. + const currentSize = props.marks.find( mark => { + return derivedValue === mark.value + } )?.size + let [ _newValue, _unit ] = extractNumbersAndUnits( currentSize )[ 0 ] + + // If the attribute has no support for rem or em, and the + // preset units is rem or em, convert to px + const converted = convertToPxIfUnsupported( props.units, _unit, _newValue ) + _newValue = converted.value + _unit = converted.unit + + rangeValue = parseFloat( _newValue ) + + if ( _unit && ! isConversionDone.current ) { + dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent() + setAttributes( { [ unitAttrName ]: _unit } ) + if ( props.onChangeUnit ) { + props.onChangeUnit( _unit ) + } + isConversionDone.current = true + } + // Since the actual previous value is a preset, force the new custom value + // when changing unit + controlProps.onChangeUnit = ( unit, unitAttrName ) => { + setAttributes( { [ unitAttrName ]: unit } ) + _onChange( _newValue ) + } + } + return ( { > + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsMarkMode( ! isMarkMode ) + } } + icon={ settings } + > + + ) } + ) @@ -148,6 +318,8 @@ const AdvancedRangeControl = props => { AdvancedRangeControl.defaultProps = { allowReset: true, + onReset: undefined, + showReset: undefined, isDynamic: false, default: '', @@ -159,6 +331,11 @@ AdvancedRangeControl.defaultProps = { onChange: undefined, onOverrideReset: undefined, forcePlaceholder: false, + + marks: undefined, // [{ value: 'var(--stk-preset-font-size-small', name: 'S' }] + allowCustom: true, + isCustomPreset: false, + isMarkModeDefault: true, } export default memo( AdvancedRangeControl, isEqual ) diff --git a/src/components/advanced-range-control/range-control.js b/src/components/advanced-range-control/range-control.js index 48ecc75fc4..a3b025a64e 100644 --- a/src/components/advanced-range-control/range-control.js +++ b/src/components/advanced-range-control/range-control.js @@ -43,6 +43,7 @@ const StackableRangeControl = memo( props => { isShiftStepEnabled, placeholderRender, defaultValue: _defaultValue, // Don't pass this. + children: _children, // Don't pass this. ...propsToPass } = props @@ -143,6 +144,11 @@ const StackableRangeControl = memo( props => { placeholderValue = initialPosition } + // Remove placeholder if it's a custom CSS + if ( typeof placeholderValue === 'string' && placeholderValue.startsWith( 'var' ) ) { + placeholderValue = '' + } + return { type="text" /> ) } + { _children } { allowReset && { } if ( unit ) { // Note: this will only work for non-objects. - // If the value is `auto`, don't add units. - value = value === 'auto' ? value : `${ value }${ unit }` + // If the value is `auto` or a CSS variable, don't add units. + if ( ! ( value === 'auto' || ( typeof value === 'string' && value.startsWith( 'var' ) ) ) ) { + value = `${ value }${ unit }` + } } if ( format !== '%s' && format !== '' ) { value = sprintf( diff --git a/src/components/font-size-control/index.js b/src/components/font-size-control/index.js index 415578e748..49035e6351 100644 --- a/src/components/font-size-control/index.js +++ b/src/components/font-size-control/index.js @@ -39,11 +39,11 @@ const FontSizeControl = props => { placeholder={ passedPlaceholder } onChangeUnit={ value => { // Change font-size so as not to surprise the user. - if ( props.value !== '' ) { + if ( props.value !== '' && ! isNaN( Number( value ) ) ) { if ( value === 'em' || value === 'rem' ) { - props.onChange( pxToEm( props.value ) ) + props.onChange( String( pxToEm( props.value ) ) ) } else if ( value === 'px' ) { - props.onChange( emToPx( props.value ) ) + props.onChange( String( emToPx( props.value ) ) ) } } diff --git a/src/components/four-range-control/index.js b/src/components/four-range-control/index.js index 633fd21170..ac2480868b 100644 --- a/src/components/four-range-control/index.js +++ b/src/components/four-range-control/index.js @@ -25,22 +25,28 @@ import { useControlHandlers } from '../base-control2/hooks' import { Tooltip } from '@wordpress/components' import { __ } from '@wordpress/i18n' import { - Fragment, useState, memo, + Fragment, useState, memo, useEffect, useRef, } from '@wordpress/element' +import { settings } from '@wordpress/icons' +import { dispatch } from '@wordpress/data' /** * External dependencies */ import { isEqual } from 'lodash' import classnames from 'classnames' -import { i18n } from 'stackable' +import { i18n, settings as stackableSettings } from 'stackable' import { Button } from '~stackable/components' import { useAttributeName, useBlockAttributesContext, useDeviceType, useBlockHoverState, + useBlockSetAttributesContext, } from '~stackable/hooks' +import { + extractNumbersAndUnits, getCSSVarName, convertToPxIfUnsupported, +} from '~stackable/util' const isEqualInitial = ( props, value, firstValue ) => { let isEqual = true @@ -77,7 +83,7 @@ const FourRangeControl = memo( props => { ( props.enableBottom && value.bottom === '' ) && ( props.enableLeft && value.left === '' ) - const firstValue = props.enableTop ? value.top + let firstValue = props.enableTop ? value.top : props.enableRight ? value.right : props.enableBottom ? value.bottom : value.left @@ -98,6 +104,7 @@ const FourRangeControl = memo( props => { label={ isLocked ? __( 'Individual sides', i18n ) : __( 'All sides', i18n ) } /> + const setAttributes = useBlockSetAttributesContext() const hasUnits = !! props.units?.length const unitAttrName = useAttributeName( `${ props.attribute }Unit`, props.responsive, props.hover ) @@ -117,6 +124,8 @@ const FourRangeControl = memo( props => { } } ) + const isMarkModeDefault = !! ( stackableSettings?.stackable_use_size_presets_by_default ?? true ) + // Change the min, max & step values depending on the unit used. if ( hasUnits ) { const i = props.units.indexOf( unit ) < 0 ? 0 : props.units.indexOf( unit ) @@ -180,77 +189,336 @@ const FourRangeControl = memo( props => { : props.enableBottom ? { desktop: _valueDesktop?.bottom, tablet: _valueTablet?.bottom } : { desktop: _valueDesktop?.left, tablet: _valueTablet?.left } - const onChangeAll = newValue => { + const [ isFourMarkMode, setIsFourMarkMode ] = useState( false ) + // Ensure the convesion of value from preset to custom with regards to the unit is donce once. + const isConversionDone = useRef( { + first: false, + top: false, + right: false, + bottom: false, + left: false, + vertical: false, + horizontal: false, + } ) + + // Is value at first render the same as a step value? If so, do mark mode + // at the start, or show custom + // If no initial value, use the given default from the settings + const isMarkValue = { + first: !! props.marks && isMarkModeDefault, + top: !! props.marks && isMarkModeDefault, + right: !! props.marks && isMarkModeDefault, + bottom: !! props.marks && isMarkModeDefault, + left: !! props.marks && isMarkModeDefault, + } + + if ( props.marks && firstValue ) { + // Check if the current value exists in the marks only by their CSS variable name + // to match in case the fallback size changes. + const firstValueCssVarName = getCSSVarName( firstValue ) + const firstMatchedMark = props.marks.find( mark => getCSSVarName( mark.value ) === firstValueCssVarName ) + isMarkValue.first = !! firstMatchedMark + if ( firstMatchedMark ) { + firstValue = firstMatchedMark.value + } + + [ 'top', 'right', 'bottom', 'left' ].forEach( side => { + const sideCssVarName = getCSSVarName( value[ side ] ) + const matchedMark = props.marks.find( mark => getCSSVarName( mark.value ) === sideCssVarName ) + isMarkValue[ side ] = !! matchedMark + if ( matchedMark ) { + value[ side ] = matchedMark.value + } + } ) + } + + // Set the markMode when device type changes + useEffect( () => { + setIsFourMarkMode( isMarkValue ) + }, [ deviceType ] ) + + const onChangeAll = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: props.enableTop ? newValue : value.top, right: props.enableRight ? newValue : value.right, bottom: props.enableBottom ? newValue : value.bottom, left: props.enableLeft ? newValue : value.left, } ) + setIsFourMarkMode( prev => ( { + ...prev, + top: prev.first, + right: prev.first, + bottom: prev.first, + left: prev.first, + } ) ) } - const onChangeTop = newValue => { + const onChangeTop = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: newValue, right: value.right, bottom: value.bottom, left: value.left, } ) + setIsFourMarkMode( prev => ( { ...prev, first: prev.top } ) ) } - const onChangeRight = newValue => { + const onChangeRight = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: value.top, right: newValue, bottom: value.bottom, left: value.left, } ) + setIsFourMarkMode( prev => ( { ...prev, first: prev.right } ) ) } - const onChangeBottom = newValue => { + const onChangeBottom = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: value.top, right: value.right, bottom: newValue, left: value.left, } ) + setIsFourMarkMode( prev => ( { ...prev, first: prev.bottom } ) ) } - const onChangeLeft = newValue => { + const onChangeLeft = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: value.top, right: value.right, bottom: value.bottom, left: newValue, } ) + setIsFourMarkMode( prev => ( { ...prev, first: prev.left } ) ) } - const onChangeVertical = newValue => { + const onChangeVertical = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: newValue, right: value.right, bottom: newValue, left: value.left, } ) + setIsFourMarkMode( prev => ( { + ...prev, + top: prev.top, + bottom: prev.top, + } ) ) } - const onChangeHorizontal = newValue => { + const onChangeHorizontal = _newValue => { + const newValue = props.marks ? String( _newValue ) : _newValue onChange( { top: value.top, right: newValue, bottom: value.bottom, left: newValue, } ) + setIsFourMarkMode( prev => ( { + ...prev, + right: prev.left, + left: prev.left, + } ) ) } + // Support for steps. Modify the props to make the range control show steps. + const stepSupport = ( isMarkMode, initialValue, initialOnChange, conversionKey = null ) => { + const newProps = { ...propsToPass } + + if ( props.marks && isMarkMode ) { + // Steps only have 1 increment values + newProps.min = 0 + newProps.max = props.marks.length - 1 + newProps.sliderMin = 0 + newProps.sliderMax = props.marks.length - 1 + newProps.step = 1 + + // Show the marks and names + newProps.marks = props.marks.reduce( ( acc, mark, index ) => { + return [ + { + value: index, + name: undefined, + }, + ...acc, + ] + }, [] ) + newProps.renderTooltipContent = value => { + return props.marks[ value ]?.name || props.marks[ value ]?.slug || '' + } + + // Other necessary props for steps. + newProps.withInputField = false + } else { + newProps.marks = undefined + } + + if ( props.marks ) { + controlProps.className = controlProps.className || '' + controlProps.className += 'stk-range-control--with-marks' + controlProps.className += isMarkMode ? ' stk-range-control--mark-mode' : '' + } + + // We need to change the way we handle the value and onChange if we're doing marks + let rangeValue = props.marks ? parseFloat( initialValue ) : initialValue + let rangeOnChange = initialOnChange + if ( props.marks && isMarkMode ) { + rangeValue = props.marks.findIndex( mark => { + let _unit, _value + // If the initialValue is a CSS variable, compare with mark's CSS variable. + // Otherwise, the initialValue is custom from the previous switch from custom to preset mode, + // so compare with raw size and units to convert to preset. + if ( typeof initialValue === 'string' && initialValue.startsWith( 'var' ) ) { + [ _value, _unit ] = extractNumbersAndUnits( mark.value )[ 0 ] + } else { + [ _value, _unit ] = extractNumbersAndUnits( mark.size )[ 0 ] + } + return _value === initialValue && ( _unit === '' || _unit === unit ) + } ) + rangeOnChange = ( value, property = 'value' ) => { + if ( value === '' ) { + return initialOnChange( value ) + } + + // Extract the unit and value. + const markValue = props.marks[ value ]?.[ property ] || '0' + let [ newValue, unit ] = extractNumbersAndUnits( markValue )[ 0 ] + + // If the attribute has no support for rem or em, and the + // preset units is rem or em, convert to px + const converted = convertToPxIfUnsupported( props.units, unit, newValue ) + newValue = converted.value + unit = converted.unit + + // Update the unit. + if ( unit ) { + dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent() + setAttributes( { [ unitAttrName ]: unit } ) + if ( props.onChangeUnit ) { + props.onChangeUnit( unit ) + } + } + + initialOnChange( newValue ) + isConversionDone.current[ conversionKey ] = false + } + } else if ( typeof initialValue === 'string' && initialValue.startsWith( 'var' ) && + ( ( isLocked && conversionKey === 'first' ) || + ( ! isLocked && [ 'top', 'right', 'left', 'bottom' ].includes( conversionKey ) ) || + ( isLocked && props.vhMode && [ 'vertical', 'horizontal' ].includes( conversionKey ) ) ) + ) { + // If the derivedValue is a preset and currently not in mark mode, the derivedValue is from + // the previous switch from preset to custom mode. Convert to custom. + const currentSize = props.marks.find( mark => { + return initialValue === mark.value + } )?.size + let [ _newValue, _unit ] = extractNumbersAndUnits( currentSize )[ 0 ] + + // If the attribute has no support for rem or em, and the + // preset units is rem or em, convert to px + const converted = convertToPxIfUnsupported( props.units, _unit, _newValue ) + _newValue = converted.value + _unit = converted.unit + + rangeValue = parseFloat( _newValue ) + + if ( _unit && conversionKey && ! isConversionDone.current[ conversionKey ] ) { + isConversionDone.current[ conversionKey ] = true + dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent() + setAttributes( { [ unitAttrName ]: _unit } ) + if ( props.onChangeUnit ) { + props.onChangeUnit( _unit ) + } + } + // Since the actual previous value is a preset, force the new custom value + // when changing unit + controlProps.onChangeUnit = ( unit, unitAttrName ) => { + initialOnChange( _newValue ) + setAttributes( { [ unitAttrName ]: unit } ) + } + } + + return [ + newProps, parseFloat( rangeValue ), rangeOnChange, + ] + } + + // Remove the unit picker if not in mark mode for every four range mode + if ( isLocked && ! props.vhMode ) { + controlProps.units = isFourMarkMode.first + ? false : controlProps.units + } else if ( isLocked && props.vhMode ) { + controlProps.units = isFourMarkMode.top && isFourMarkMode.right + ? false : controlProps.units + } else { + controlProps.units = isFourMarkMode.top && isFourMarkMode.right && isFourMarkMode.bottom && isFourMarkMode.left + ? false : controlProps.units + } + + // Create step supports for each side + const [ propsToPassFirst, rangeValueFirst, rangeOnChangeFirst ] = stepSupport( + isFourMarkMode.first, + firstValue, + onChangeAll, + 'first', + ) + + const [ propsToPassTop, rangeValueTop, rangeOnChangeTop ] = stepSupport( + isFourMarkMode.top, + value.top, + onChangeTop, + 'top' + ) + + const [ propsToPassRight, rangeValueRight, rangeOnChangeRight ] = stepSupport( + isFourMarkMode.right, + value.right, + onChangeRight, + 'right' + ) + + const [ propsToPassBottom, rangeValueBottom, rangeOnChangeBottom ] = stepSupport( + isFourMarkMode.bottom, + value.bottom, + onChangeBottom, + 'bottom' + ) + + const [ propsToPassLeft, rangeValueLeft, rangeOnChangeLeft ] = stepSupport( + isFourMarkMode.left, + value.left, + onChangeLeft, + 'left' + ) + + const [ propsToPassVertical, rangeValueVertical, rangeOnChangeVertical ] = stepSupport( + isFourMarkMode.top, + value.top, + onChangeVertical, + 'vertical' + ) + + const [ propsToPassHorizontal, rangeValueHorizontal, rangeOnChangeHorizontal ] = stepSupport( + isFourMarkMode.left, + value.left, + onChangeHorizontal, + 'horizontal' + ) return ( { isLocked && ! props.vhMode && ( { if ( currentHoverState !== 'normal' ) { @@ -278,7 +546,21 @@ const FourRangeControl = memo( props => { return propsToPass.placeholder } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, first: ! prev.first } ) ) + } } + icon={ settings } + > + + ) } + { { if ( currentHoverState !== 'normal' ) { @@ -324,7 +606,21 @@ const FourRangeControl = memo( props => { return typeof props.placeholderTop === 'undefined' ? propsToPass.placeholder : props.placeholderTop } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, top: ! prev.top } ) ) + } } + icon={ settings } + > + + ) } + { { if ( currentHoverState !== 'normal' ) { @@ -366,7 +662,21 @@ const FourRangeControl = memo( props => { } return typeof props.placeholderLeft === 'undefined' ? propsToPass.placeholder : props.placeholderLeft } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, left: ! prev.left } ) ) + } } + icon={ settings } + > + + ) } + { { props.isCorner ? : } { if ( currentHoverState !== 'normal' ) { @@ -414,7 +724,21 @@ const FourRangeControl = memo( props => { return typeof props.placeholderTop === 'undefined' ? propsToPass.placeholder : props.placeholderTop } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, top: ! prev.top } ) ) + } } + icon={ settings } + > + + ) } + { { props.isCorner ? : } { if ( currentHoverState !== 'normal' ) { @@ -459,7 +783,21 @@ const FourRangeControl = memo( props => { return typeof props.placeholderRight === 'undefined' ? propsToPass.placeholder : props.placeholderRight } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, right: ! prev.right } ) ) + } } + icon={ settings } + > + + ) } + { { props.isCorner ? : } { if ( currentHoverState !== 'normal' ) { @@ -504,7 +842,21 @@ const FourRangeControl = memo( props => { return typeof props.placeholderBottom === 'undefined' ? propsToPass.placeholder : props.placeholderBottom } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, bottom: ! prev.bottom } ) ) + } } + icon={ settings } + > + + ) } + { { props.isCorner ? : } { if ( currentHoverState !== 'normal' ) { @@ -549,7 +901,21 @@ const FourRangeControl = memo( props => { return typeof props.placeholderLeft === 'undefined' ? propsToPass.placeholder : props.placeholderLeft } )() } - /> + __nextHasNoMarginBottom + > + { props.allowCustom && props.marks && ( + { + setIsFourMarkMode( prev => ( { ...prev, left: ! prev.left } ) ) + } } + icon={ settings } + > + + ) } + { __( 'Streamline your design workflow', i18n ) } , }, + 'preset-controls': { + title: __( 'Premium Preset Controls', i18n ), + description: + { __( 'Customize your own presets like small, medium, large & x-large', i18n ) } + { __( 'Use Global Typography sizes as presets', i18n ) } + , + }, } const ProControl = props => { diff --git a/src/global-settings.php b/src/global-settings.php index ec8796676c..2859bb62a2 100644 --- a/src/global-settings.php +++ b/src/global-settings.php @@ -144,6 +144,26 @@ public static function get_four_range_properties() { return Stackable_Global_Settings::create_global_schema( $four_range_type ); } + + /** + * This function defines a schema for a string four-range type and utilizes the + * `create_global_schema` function to generate the complete schema. + * + * @return array The generated schema for four-range type. + */ + public static function get_string_four_range_properties() { + $string_four_range_type = array( + 'type' => 'object', + 'properties' => array( + 'top' => array( 'type' => 'string', 'default' => '' ), + 'right' => array( 'type' => 'string', 'default' => '' ), + 'bottom' => array( 'type' => 'string', 'default' => '' ), + 'left' => array( 'type' => 'string', 'default' => '' ), + ) + ); + + return Stackable_Global_Settings::create_global_schema( $string_four_range_type ); + } /** * This function defines a schema for a string type and utilizes the @@ -279,13 +299,13 @@ public function register_global_settings() { 'type' => 'string', ), 'fontSize' => array( - 'type' => 'number', + 'type' => 'string', ), 'tabletFontSize' => array( - 'type' => 'number', + 'type' => 'string', ), 'mobileFontSize' => array( - 'type' => 'number', + 'type' => 'string', ), 'fontSizeUnit' => array( 'type' => 'string', @@ -412,6 +432,30 @@ public function register_global_settings() { ) ); + register_setting( + 'stackable_global_settings', + 'stackable_use_typography_as_presets', + array( + 'type' => 'boolean', + 'description' => __( 'Use Global Typography font sizes as preset', STACKABLE_I18N ), + 'sanitize_callback' => 'sanitize_text_field', + 'show_in_rest' => true, + 'default' => '', + ) + ); + + register_setting( + 'stackable_global_settings', + 'stackable_is_apply_body_to_html', + array( + 'type' => 'boolean', + 'description' => __( 'Stackable global typography apply to setting', STACKABLE_I18N ), + 'sanitize_callback' => 'sanitize_text_field', + 'show_in_rest' => true, + 'default' => '', + ) + ); + register_setting( 'stackable_global_settings', 'stackable_icon_library', @@ -638,11 +682,27 @@ public function form_tag_selector( $tag ) { } public function form_paragraph_selector() { - return array_merge( - $this->form_tag_selector( 'p' ), // Core text. - $this->form_tag_selector( 'li' ), // Core lists. - $this->form_tag_selector( 'td' ) // Core table cells. + $selectors = array_merge( + $this->form_tag_selector( 'p' ), // Core text + $this->form_tag_selector( 'li' ), // Core lists + $this->form_tag_selector( 'td' ) // Core table cells ); + + // Add 'html' only if is_apply_body_to_html is true + $is_apply_body_to_html = get_option( 'stackable_is_apply_body_to_html' ); + if ( $is_apply_body_to_html ) { + $selectors[] = 'html'; + } + + return $selectors; + } + + public function clean_font_size( $font_size, $font_size_unit = '' ) { + if ( is_string( $font_size ) && str_starts_with( $font_size, 'var' ) ) { + return $font_size; + } + + return $font_size . $font_size_unit; } /** @@ -701,7 +761,7 @@ public function generate_typography_styles( $selector, $styles ) { $css['desktop'][] = $this->create_style( 'font-family', $this->get_font_family( $styles['fontFamily'] ) ); } if ( isset( $styles['fontSize'] ) ) { - $css['desktop'][] = $this->create_style( 'font-size', $styles['fontSize'] . $styles['fontSizeUnit'] ); + $css['desktop'][] = $this->create_style( 'font-size', $this->clean_font_size( $styles['fontSize'], $styles['fontSizeUnit'] ) ); } if ( isset( $styles['fontWeight'] ) ) { $css['desktop'][] = $this->create_style( 'font-weight', $styles['fontWeight'] ); @@ -730,12 +790,12 @@ public function generate_typography_styles( $selector, $styles ) { if ( isset( $styles['fontSize'] ) ) { $clamp_desktop_value = $this->clamp_inherited_style( $styles['fontSize'], $inherit_max ); if ( ! empty( $clamp_desktop_value ) ) { - $font_size = $this->create_style( 'font-size', $clamp_desktop_value . $styles['fontSizeUnit'] ); + $font_size = $this->create_style( 'font-size', $this->clean_font_size( $clamp_desktop_value, $styles['fontSizeUnit'] ) ); } } } if ( isset( $styles['tabletFontSize'] ) ) { - $font_size = $this->create_style( 'font-size', $styles['tabletFontSize'] . $styles['tabletFontSizeUnit'] ); + $font_size = $this->create_style( 'font-size', $this->clean_font_size( $styles['tabletFontSize'], $styles['tabletFontSizeUnit'] ) ); } if ( ! empty( $font_size ) ) { $css['tablet'][] = $font_size; @@ -758,7 +818,7 @@ public function generate_typography_styles( $selector, $styles ) { if ( isset( $styles['fontSize'] ) ) { $clamp_desktop_value = $this->clamp_inherited_style( $styles['fontSize'], $inherit_max ); if ( ! empty( $clamp_desktop_value ) ) { - $font_size = $this->create_style( 'font-size', $clamp_desktop_value . $styles['fontSizeUnit'] ); + $font_size = $this->create_style( 'font-size', $this->clean_font_size( $clamp_desktop_value, $styles['fontSizeUnit'] ) ); } } @@ -766,7 +826,7 @@ public function generate_typography_styles( $selector, $styles ) { if ( isset( $styles['tabletFontSize'] ) ) { $clamp_tablet_value = $this->clamp_inherited_style( $styles['tabletFontSize'], $inherit_max ); if ( ! empty( $clamp_tablet_value ) ) { - $font_size = $this->create_style( 'font-size', $clamp_tablet_value . $styles['tabletFontSizeUnit'] ); + $font_size = $this->create_style( $this->clean_font_size( 'font-size', $clamp_tablet_value, $styles['tabletFontSizeUnit'] ) ); } } if ( empty( $clamp_tablet_value ) ) { @@ -779,7 +839,7 @@ public function generate_typography_styles( $selector, $styles ) { } } if ( isset( $styles['mobileFontSize'] ) ) { - $font_size = $this->create_style( 'font-size', $styles['mobileFontSize'] . $styles['mobileFontSizeUnit'] ); + $font_size = $this->create_style( 'font-size', $this->clean_font_size( $styles['mobileFontSize'], $styles['mobileFontSizeUnit'] ) ); } if ( ! empty( $font_size ) ) { $css['mobile'][] = $font_size; @@ -838,7 +898,7 @@ public function get_font_family( $font_name ) { * @param {Object} options */ public function clamp_inherited_style( $value, $max = 999999, $min = -999999 ) { - if ( isset( $value ) ) { + if ( isset( $value ) && is_numeric( $value ) ) { $clamped_value = max( $min, min( $max, $value ) ); return $clamped_value !== $value ? $clamped_value : null; } @@ -987,7 +1047,7 @@ public static function generate_global_block_layouts( $option_name, $settings_na $custom_property .= '-' . $hover_state; } - if ( is_string( $value ) ) { + if ( is_string( $value ) && ! is_numeric( $value ) ) { if ( strpos( $value, 'rgb' ) ) { // Convert rgba colors to hex alpha colors because // the function wp_style_engine_get_stylesheet_from_css_rules() doesn't allow css values to have '(' @@ -1018,7 +1078,10 @@ public static function generate_global_block_layouts( $option_name, $settings_na $bottom = isset( $value[ 'bottom' ] ) ? $value[ 'bottom' ] : $default_value[ 'bottom' ]; $left = isset( $value[ 'left' ] ) ? $value[ 'left' ] : $default_value[ 'left' ]; - $style = $top . $unit . ' ' . $right . $unit . ' ' . $bottom . $unit . ' ' . $left . $unit; + $style = Stackable_Global_Settings::append_unit_if_needed( $top, $unit ) . ' ' + . Stackable_Global_Settings::append_unit_if_needed( $right, $unit ) . ' ' + . Stackable_Global_Settings::append_unit_if_needed( $bottom, $unit ) . ' ' + . Stackable_Global_Settings::append_unit_if_needed( $left, $unit ); } else { $style = $value . $unit; } @@ -1068,6 +1131,14 @@ public static function generate_global_block_layouts( $option_name, $settings_na return $generated_css; } + public static function append_unit_if_needed( $value, $unit ) { + if ( is_string( $value ) && str_starts_with( trim( $value ), 'var(' ) ) { + return $value; + } + return $value . $unit; + } + + public static function extract_rgba($value) { $options = $value; $color = ''; diff --git a/src/hooks/index.js b/src/hooks/index.js index 579c1467f1..26a2e2bc77 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -20,3 +20,4 @@ export * from './use-raf-memo' export * from './use-raf-effect' export * from './use-global-block-layout-defaults' export * from './use-block-color-schemes' +export * from './use-preset-controls' diff --git a/src/hooks/use-preset-controls.js b/src/hooks/use-preset-controls.js new file mode 100644 index 0000000000..d2e3cc69df --- /dev/null +++ b/src/hooks/use-preset-controls.js @@ -0,0 +1,79 @@ +import { useSettings } from '@wordpress/block-editor' +import { useSelect } from '@wordpress/data' +import DEFAULT_PRESETS from '~stackable/plugins/global-settings/preset-controls/presets.json' + +const PRESET_MAPPING = { + fontSizes: { + settings: [ 'typography', 'fontSizes' ], + prefix: 'font-size', + }, + spacingSizes: { + settings: [ 'spacing', 'spacingSizes' ], + prefix: 'spacing', + }, + blockHeights: { + settings: [ 'blockHeights' ], + prefix: 'block-height', + }, + borderRadius: { + settings: [ 'borderRadius' ], + prefix: 'border-radius', + }, +} + +export const usePresetControls = property => { + // Get the theme presets for the property + const [ themePresets ] = useSettings( PRESET_MAPPING[ property ].settings.join( '.' ) ) + // Get all custom presets + const { allCustomPresets } = useSelect( select => { + const _customPresetControls = select( 'stackable/global-preset-controls.custom' )?.getCustomPresetControls() + return { allCustomPresets: { ..._customPresetControls } } + }, [] ) + + const hasThemePresets = Array.isArray( themePresets ) && themePresets.length > 0 + + // Get the theme/default presets if the user have one, else return the stackable presets + const basePresets = hasThemePresets + ? themePresets + : PRESET_MAPPING[ property ].settings.reduce( ( acc, key ) => acc?.[ key ], DEFAULT_PRESETS.settings ) + + // Returns the base presets overriden by the custom presets + const getMergedPresets = () => { + const customPresets = allCustomPresets[ property ] ?? [] + // Convert custom presets into a lookup object for fast access + const customMap = customPresets.reduce( ( acc, item ) => { + acc[ item.slug ] = item + return acc + }, {} ) + + // Merge base presets with custom presets (priority) + return basePresets.map( baseItem => + customMap[ baseItem.slug ] + ? { ...baseItem, ...customMap[ baseItem.slug ] } + : baseItem + ) + } + + // Get the merge preset marks with the CSS Variable value + // Setting customOnly to true returns the preset marks for custom presets only + const getPresetMarks = ( { customOnly = false, additionalPresets = [] } = {} ) => { + const prefix = PRESET_MAPPING[ property ].prefix + let presets = customOnly ? allCustomPresets[ property ] ?? [] : getMergedPresets() + presets = [ ...additionalPresets, ...presets ] + + return presets + .filter( preset => ! ( preset?.isDiscarded ) ) + .map( preset => ( { + ...preset, + value: `var(--stk--preset--${ prefix }--${ preset.slug }, ${ preset.size })`, + } ) ) + } + + return { + hasThemePresets, + basePresets, + allCustomPresets, + getMergedPresets, + getPresetMarks, + } +} diff --git a/src/plugins/global-settings/buttons-and-icons/index.js b/src/plugins/global-settings/buttons-and-icons/index.js index 00b117c9b2..776611352e 100644 --- a/src/plugins/global-settings/buttons-and-icons/index.js +++ b/src/plugins/global-settings/buttons-and-icons/index.js @@ -23,6 +23,7 @@ import { } from '../utils' import { BORDER_CONTROLS } from '~stackable/block-components' import { i18n } from 'stackable' +import { usePresetControls } from '~stackable/hooks' /** * WordPress dependencies @@ -54,6 +55,17 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-buttons-and- saveTimeout ) + // Add additional presets for setting margins and paddings to None + const nonePreset = { + name: 'None', + size: '0rem', + slug: 'none', + } + const sizePresetMarks = usePresetControls( 'spacingSizes' ) + ?.getPresetMarks( { additionalPresets: [ nonePreset ] } ) || null + const gapPresetMarks = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + const borderRadiusPresetMarks = usePresetControls( 'borderRadius' )?.getPresetMarks() || null + return ( <> { output } @@ -112,6 +124,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-buttons-and- onChange={ value => onChange( 'button-min-height', value, STATES.RESPONSIVE ) } hasTabletValue={ getHasDeviceValue( 'button-min-height', 'tablet' ) } hasMobileValue={ getHasDeviceValue( 'button-min-height', 'mobile' ) } + marks={ sizePresetMarks } /> onChange( 'button-column-gap', value, STATES.RESPONSIVE ) } hasTabletValue={ getHasDeviceValue( 'button-column-gap', 'tablet' ) } hasMobileValue={ getHasDeviceValue( 'button-column-gap', 'mobile' ) } + marks={ gapPresetMarks } /> onChange( 'button-row-gap', value, STATES.RESPONSIVE ) } hasTabletValue={ getHasDeviceValue( 'button-row-gap', 'tablet' ) } hasMobileValue={ getHasDeviceValue( 'button-row-gap', 'mobile' ) } + marks={ gapPresetMarks } /> @@ -294,6 +311,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-buttons-and- title: __( 'Button padding', i18n ), description: __( 'Adjusts the space between the button text and button borders', i18n ), } } + marks={ sizePresetMarks } /> onChange( 'icon-list-row-gap', value, STATES.RESPONSIVE ) } hasTabletValue={ getHasDeviceValue( 'icon-list-row-gap', 'tablet' ) } hasMobileValue={ getHasDeviceValue( 'icon-list-row-gap', 'mobile' ) } + marks={ gapPresetMarks } /> array( 'schema' => array( 'properties' => array( - 'button-min-height' => $number_properties, - 'button-padding' => $four_range_properties, - 'icon-button-padding' => $four_range_properties, + 'button-min-height' => $string_properties, + 'button-padding' => $string_four_range_properties, + 'icon-button-padding' => $string_four_range_properties, 'button-border-style' => $string_properties, 'button-border-width' => $four_range_properties, 'button-ghost-border-width' => $four_range_properties, - 'button-border-radius' => $four_range_properties, + 'button-border-radius' => $string_four_range_properties, 'button-box-shadow' => $string_properties, 'button-icon-size' => $number_properties, - 'button-icon-gap' => $number_properties, - 'button-column-gap' => $number_properties, - 'button-row-gap' => $number_properties, + 'button-icon-gap' => $string_properties, + 'button-column-gap' => $string_properties, + 'button-row-gap' => $string_properties, 'icon-list-icon-size' => $number_properties, - 'icon-list-row-gap' => $number_properties, + 'icon-list-row-gap' => $string_properties, 'icon-list-icon-gap' => $number_properties, 'icon-list-indentation' => $number_properties, diff --git a/src/plugins/global-settings/editor-loader.js b/src/plugins/global-settings/editor-loader.js index c516283d8d..0aa84a6390 100644 --- a/src/plugins/global-settings/editor-loader.js +++ b/src/plugins/global-settings/editor-loader.js @@ -10,6 +10,7 @@ import { GlobalColorStyles } from './colors' import { GlobalTypographyStyles } from './typography' import { GlobalSpacingAndBordersStyles } from './spacing-and-borders' import { GlobalButtonsAndIconsStyles } from './buttons-and-icons' +import { GlobalPresetControlsStyles } from './preset-controls' import './block-defaults' /** @@ -50,6 +51,7 @@ const GlobalSettingsLoader = () => { editorBody.appendChild( globalSpacingAndBorderWrapper ) editorBody.appendChild( globalButtonsAndIconsWrapper ) editorBody.appendChild( globalColorSchemesWrapper ) + editorBody.appendChild( globalPresetControlsWrapper ) } }, [ deviceType, editorDom ] ) @@ -65,20 +67,24 @@ const globalColorWrapper = document?.createElement( 'style' ) const globalSpacingAndBorderWrapper = document?.createElement( 'style' ) const globalButtonsAndIconsWrapper = document?.createElement( 'style' ) const globalColorSchemesWrapper = document?.createElement( 'style' ) +const globalPresetControlsWrapper = document?.createElement( 'style' ) globalTypographyWrapper?.setAttribute( 'id', 'stk-global-typography-styles' ) globalColorWrapper?.setAttribute( 'id', 'stk-global-color-styles' ) globalSpacingAndBorderWrapper?.setAttribute( 'id', 'stk-global-spacing-and-borders-styles' ) globalButtonsAndIconsWrapper?.setAttribute( 'id', 'stk-global-buttons-and-icons-styles' ) globalColorSchemesWrapper?.setAttribute( 'id', 'stk-global-color-schemes-styles' ) +globalPresetControlsWrapper?.setAttribute( 'id', 'stk-global-preset-controls-styles' ) domReady( () => { document?.body?.appendChild( globalTypographyWrapper ) document?.body?.appendChild( globalColorWrapper ) document?.body?.appendChild( globalSpacingAndBorderWrapper ) document?.body?.appendChild( globalButtonsAndIconsWrapper ) document?.body?.appendChild( globalColorSchemesWrapper ) + document?.body?.appendChild( globalPresetControlsWrapper ) createRoot( globalTypographyWrapper ).render( ) createRoot( globalColorWrapper ).render( ) createRoot( globalSpacingAndBorderWrapper ).render( ) createRoot( globalButtonsAndIconsWrapper ).render( ) createRoot( globalColorSchemesWrapper ).render( ) + createRoot( globalPresetControlsWrapper ).render( ) } ) diff --git a/src/plugins/global-settings/index.js b/src/plugins/global-settings/index.js index 77bcdbb8b5..b1502e8685 100644 --- a/src/plugins/global-settings/index.js +++ b/src/plugins/global-settings/index.js @@ -7,6 +7,7 @@ import './buttons-and-icons' import './spacing-and-borders' import './block-defaults' import './icon-library' +import './preset-controls' /** * External dependencies diff --git a/src/plugins/global-settings/preset-controls/editor-loader.js b/src/plugins/global-settings/preset-controls/editor-loader.js new file mode 100644 index 0000000000..25042dff93 --- /dev/null +++ b/src/plugins/global-settings/preset-controls/editor-loader.js @@ -0,0 +1,57 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data' +import { useEffect, useState } from '@wordpress/element' + +/** + * External dependencies + */ +import { compact } from 'lodash' + +const PRESET_MAPPING = { + fontSizes: { + prefix: 'font-size', + }, + spacingSizes: { + prefix: 'spacing', + }, + blockHeights: { + prefix: 'block-height', + }, + borderRadius: { + prefix: 'border-radius', + }, +} + +const renderGlobalStyles = ( customPresets, setStyles ) => { + let css = '' + + Object.entries( customPresets ).forEach( ( [ key, presets ] ) => { + const styleRules = presets?.map( preset => { + return preset && ( ! preset?.isDiscarded ) + ? `--stk--preset--${ PRESET_MAPPING[ key ]?.prefix }--${ preset?.slug || '' }: ${ preset?.size || '' };` + : '' + } ) + css += compact( styleRules ).join( '' ) + } ) + + css = `:root { ${ css } }` + setStyles( css ) +} + +export const GlobalPresetControlsStyles = () => { + const { customPresets } = useSelect( select => { + const _customPresetControls = select( 'stackable/global-preset-controls.custom' )?.getCustomPresetControls() + return { customPresets: { ..._customPresetControls } ?? [] } + }, [] ) + const [ styles, setStyles ] = useState( '' ) + + useEffect( () => { + if ( customPresets && typeof customPresets === 'object' ) { + renderGlobalStyles( customPresets, setStyles ) + } + }, [ customPresets ] ) + + return styles +} diff --git a/src/plugins/global-settings/preset-controls/index.js b/src/plugins/global-settings/preset-controls/index.js new file mode 100644 index 0000000000..b6681180fa --- /dev/null +++ b/src/plugins/global-settings/preset-controls/index.js @@ -0,0 +1,47 @@ +/** + * Internal dependencies + */ +import { GlobalPresetControlsStyles } from './editor-loader' + +/** + * External dependencies + */ +import { + i18n, showProNotice, isPro, +} from 'stackable' +import { + PanelAdvancedSettings, + ProControl, +} from '~stackable/components' + +/** + * WordPress dependencies + */ + +import { addFilter, applyFilters } from '@wordpress/hooks' +import { Fragment } from '@wordpress/element' +import { __ } from '@wordpress/i18n' + +export { GlobalPresetControlsStyles } + +if ( showProNotice || isPro ) { + addFilter( 'stackable.global-settings.inspector', 'stackable/preset-controls', output => { + return ( + + { output } + + + { ! isPro && } + { isPro && + applyFilters( 'stackable.global-settings.inspector.preset-controls.control', null ) + } + + + + ) + }, 12 ) +} diff --git a/src/plugins/global-settings/preset-controls/index.php b/src/plugins/global-settings/preset-controls/index.php new file mode 100644 index 0000000000..2e16f04258 --- /dev/null +++ b/src/plugins/global-settings/preset-controls/index.php @@ -0,0 +1,233 @@ + array( + 'settings' => array('typography', 'fontSizes' ), + 'prefix' => 'font-size', + ), + 'spacingSizes' => array( + 'settings' => array( 'spacing', 'spacingSizes' ), + 'prefix' => 'spacing', + ), + 'blockHeights' => array( + 'settings' => array( 'blockHeights' ), + 'prefix' => 'block-height', + ), + 'borderRadius' => array( + 'settings' => array( 'borderRadius' ), + 'prefix' => 'border-radius', + ), + ); + + public $custom_presets; + public $theme_presets; + public $default_presets; + public $stackable_presets; + + /** + * Initialize + */ + function __construct() { + add_action( 'register_stackable_global_settings', array( $this, 'register_use_size_presets_by_default' ) ); + add_action( 'stackable_early_version_upgraded', array( $this, 'use_size_presets_by_default_set_default' ), 10, 2 ); + add_filter( 'stackable_js_settings', array( $this, 'add_setting' ) ); + + add_filter( 'stackable_inline_styles_nodep', array( $this, 'add_preset_controls_styles' ) ); + add_filter( 'stackable_inline_editor_styles', array( $this, 'add_preset_controls_styles' ) ); + } + + // Register the setting for using presets by default + function register_use_size_presets_by_default() { + register_setting( + 'stackable_global_settings', + 'stackable_use_size_presets_by_default', + array( + 'type' => 'boolean', + 'description' => __( 'If enabled, range controls will be on preset mode by default', STACKABLE_I18N ), + 'sanitize_callback' => 'sanitize_text_field', + 'show_in_rest' => true, + 'default' => true, + ) + ); + } + + /** + * When upgrading to v3.16.0 and above, set option to false. + * If new installation, set option to true. + * + * @since 3.16.0 + */ + public function use_size_presets_by_default_set_default( $old_version, $new_version ) { + if ( ! empty( $old_version ) && version_compare( $old_version, "3.16.0", "<" ) ) { + if ( ! get_option( 'stackable_use_size_presets_by_default' ) ) { + update_option( 'stackable_use_size_presets_by_default', '' ); + } + } + } + + // Make the setting available in the editor + public function add_setting( $settings ) { + $settings['stackable_use_size_presets_by_default'] = get_option( 'stackable_use_size_presets_by_default' ); + return $settings; + } + + /** + * Loads the different preset values. + * + * @return void + */ + public function load_presets() { + $this->custom_presets = get_option( 'stackable_global_custom_preset_controls' ); + $this->theme_presets = WP_Theme_JSON_Resolver::get_theme_data()->get_settings(); + $this->default_presets = WP_Theme_JSON_Resolver::get_core_data()->get_settings(); + $this->stackable_presets = $this->load_json_file( __DIR__ . '/presets.json'); + } + + public static function sanitize_array_setting( $input ) { + return ! is_array( $input ) ? array( array() ) : $input; + } + + /** + * Loads and decodes a JSON file, returning the settings array if available. + * + * @param string $json_path Absolute path to the JSON file. + * @return array The settings array from the decoded JSON file, or an empty array. + */ + private function load_json_file( $json_path ) { + if ( file_exists( $json_path ) ) { + $decoded_data = wp_json_file_decode( $json_path, [ + 'associative' => true, + ] ); + return $decoded_data[ 'settings' ] ?? []; + } + return []; + } + + /** + * Generate CSS variable style definitions based on the property (e.g., fontSizes, spacing). + * The given presets will be overriden it match with a preset from custom. + * + * @param array $property + * @param array $presets + * @param array $prefix + * @param bool $isTheme + * @return mixed + */ + public function generate_css_variables_styles( $property, $presets, $prefix, $isTheme = false ) { + $filter_name = current_filter(); + $custom_presets = $this->custom_presets[ $property ] ?? []; + + $presets_by_slug = []; + // Convert presets into an associative array with key 'slug' + foreach ( $presets as $preset ) { + $presets_by_slug[ $preset[ 'slug' ] ] = $preset; + } + + // There is no need to generate custom presets in the editor. + // The custom presets are generated dynamically. + if ( $filter_name !== 'stackable_inline_editor_styles' ) { + // Override values in base presets if it exist in custom presets + foreach ( $custom_presets as $custom ) { + $custom[ '__is_custom' ] = true; + $presets_by_slug[ $custom[ 'slug' ] ] = $custom; + } + } + + // Build the CSS variables array. + // If custom presets or using stackable presets, use the given size. + // If using theme presets, use WP generated --wp-preset to support theme.json specific + // configuration (fluid, clamping, etc.) + $css_vars = []; + foreach ( $presets_by_slug as $slug => $preset ) { + $is_custom = $preset['__is_custom'] ?? false; + + $value = $is_custom || ! $isTheme + ? $preset['size'] + : "var(--wp--preset--$prefix--$slug)"; + + $css_vars[ "--stk--preset--$prefix--$slug" ] = $value; + } + + return array( + 'selector' => ':root', + 'declarations' => $css_vars, + ); + } + + /** + * Get the value from an array with an array of keys + * + * @param array $array + * @param array $keys + * @return mixed + */ + public function deepGet( $array, $keys ) { + return array_reduce( $keys, fn( $value, $key ) => $value[ $key ] ?? null, $array ); + } + + /** + * Add our global preset control styles. + * + * @param String $current_css + * @return String + */ + public function add_preset_controls_styles( $current_css ) { + $this->load_presets(); + $generated_styles = array(); + + foreach ( self::PRESET_MAPPING as $key => $value ) { + if ( ! empty( $this->deepGet( $this->theme_presets, $value[ 'settings' ] )[ 'theme' ] ) ) { + $styles = $this->generate_css_variables_styles( + $key, + $this->deepGet( $this->theme_presets, $value[ 'settings' ] )[ 'theme' ], + $value[ 'prefix' ], + true + ); + $generated_styles[] = $styles; + + } elseif ( ! empty( $this->deepGet( $this->default_presets, $value[ 'settings' ] )[ 'default' ] ) ) { + $styles = $this->generate_css_variables_styles( + $key, + $this->deepGet( $this->default_presets, $value[ 'settings' ] )[ 'default' ], + $value[ 'prefix' ], + true + ); + $generated_styles[] = $styles; + } else { + $styles = $this->generate_css_variables_styles( + $key, + $this->deepGet( $this->stackable_presets, $value[ 'settings' ] ), + $value[ 'prefix' ], + ); + $generated_styles[] = $styles; + } + } + + $generated_css = wp_style_engine_get_stylesheet_from_css_rules( $generated_styles ); + if ( ! $generated_css ) { + return $current_css; + } + + $current_css .= "\n/* Global Preset Controls */\n"; + $current_css .= $generated_css; + + return apply_filters( 'stackable_frontend_css' , $current_css ); + } + } + + new Stackable_Size_And_Spacing_Preset_Controls(); +} \ No newline at end of file diff --git a/src/plugins/global-settings/preset-controls/presets.json b/src/plugins/global-settings/preset-controls/presets.json new file mode 100644 index 0000000000..60ce0169ef --- /dev/null +++ b/src/plugins/global-settings/preset-controls/presets.json @@ -0,0 +1,181 @@ +{ + "settings": { + "spacing": { + "spacingSizes": [ + { + "name": "XS", + "size": "0.25rem", + "slug": "x-small" + }, + { + "name": "S", + "size": "0.5rem", + "slug": "small" + }, + { + "name": "M", + "size": "1rem", + "slug": "medium" + }, + { + "name": "L", + "size": "1.5rem", + "slug": "large" + }, + { + "name": "XL", + "size": "2rem", + "slug": "x-large" + }, + { + "name": "2XL", + "size": "3rem", + "slug": "xx-large" + }, + { + "name": "3XL", + "size": "4rem", + "slug": "xxx-large" + }, + { + "name": "4XL", + "size": "6rem", + "slug": "xxxx-large" + } + ] + }, + "typography": { + "fontSizes": [ + { + "name": "XS", + "size": "0.75rem", + "slug": "x-small" + }, + { + "name": "S", + "size": "0.875rem", + "slug": "small" + }, + { + "name": "M", + "size": "1rem", + "slug": "medium" + }, + { + "name": "L", + "size": "1.125rem", + "slug": "large" + }, + { + "name": "XL", + "size": "1.5rem", + "slug": "x-large" + }, + { + "name": "2XL", + "size": "2rem", + "slug": "xx-large" + }, + { + "name": "3XL", + "size": "2.5rem", + "slug": "xxx-large" + }, + { + "name": "4XL", + "size": "3rem", + "slug": "xxxx-large" + }, + { + "name": "5XL", + "size": "4rem", + "slug": "xxxxx-large" + } + ] + }, + "blockHeights": [ + { + "name": "XS", + "size": "4rem", + "slug": "x-small" + }, + { + "name": "S", + "size": "8rem", + "slug": "small" + }, + { + "name": "M", + "size": "12rem", + "slug": "medium" + }, + { + "name": "L", + "size": "16rem", + "slug": "large" + }, + { + "name": "XL", + "size": "24rem", + "slug": "x-large" + }, + { + "name": "2XL", + "size": "32rem", + "slug": "xx-large" + }, + { + "name": "3XL", + "size": "40rem", + "slug": "xxx-large" + }, + { + "name": "Full", + "size": "100vh", + "slug": "full" + } + ], + "borderRadius": [ + { + "name": "None", + "size": "0px", + "slug": "none" + }, + { + "name": "XS", + "size": "2px", + "slug": "x-small" + }, + { + "name": "S", + "size": "4px", + "slug": "small" + }, + { + "name": "M", + "size": "8px", + "slug": "medium" + }, + { + "name": "L", + "size": "16px", + "slug": "large" + }, + { + "name": "XL", + "size": "24px", + "slug": "x-large" + }, + { + "name": "2XL", + "size": "32px", + "slug": "xx-large" + }, + { + "name": "Full", + "size": "9999px", + "slug": "full" + } + ] + } +} diff --git a/src/plugins/global-settings/spacing-and-borders/index.js b/src/plugins/global-settings/spacing-and-borders/index.js index 966d3d1eb0..552cc9ea38 100644 --- a/src/plugins/global-settings/spacing-and-borders/index.js +++ b/src/plugins/global-settings/spacing-and-borders/index.js @@ -23,7 +23,9 @@ import { } from '../utils' import { BORDER_CONTROLS, IMAGE_SHADOWS } from '~stackable/block-components' import { i18n } from 'stackable' -import { useDeviceType, useBlockLayoutDefaults } from '~stackable/hooks' +import { + useDeviceType, useBlockLayoutDefaults, usePresetControls, +} from '~stackable/hooks' /** * WordPress dependencies @@ -54,6 +56,16 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- setDisplayHoverNotice, saveTimeout ) + // Add additional presets for setting margins and paddings to None + const nonePreset = { + name: 'None', + size: '0rem', + slug: 'none', + } + const sizePresetMarks = usePresetControls( 'spacingSizes' ) + ?.getPresetMarks( { additionalPresets: [ nonePreset ] } ) || null + const gapPresetMarks = usePresetControls( 'spacingSizes' )?.getPresetMarks() || null + const borderRadiusPresetMarks = usePresetControls( 'borderRadius' )?.getPresetMarks() || null return ( <> @@ -120,6 +132,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- video: 'advanced-block-margin', description: __( 'Sets the block margin bottom, i.e. the space outside the block between the block border and the next block.', i18n ), } } + marks={ sizePresetMarks } /> @@ -159,6 +172,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- video: 'column-gap', description: __( 'Sets the distance between two or more columns', i18n ), } } + marks={ sizePresetMarks } /> @@ -187,9 +202,9 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- responsive="all" // hover="all" forceUpdateHoverState={ true } - min={ [ 0, 0, 0 ] } - sliderMax={ [ 200, 30, 100 ] } - units={ [ 'px', 'em', '%' ] } + min={ [ 0, 0, 0, 0 ] } + sliderMax={ [ 200, 30, 30, 100 ] } + units={ [ 'px', 'em', 'rem', '%' ] } unit={ getValue( 'block-background-padding', STATES.ALL_UNIT ) || 'px' } onChangeUnit={ value => onChange( 'block-background-padding', value, STATES.ALL_UNIT ) } top={ getValue( 'block-background-padding', STATES.ALL )?.top } @@ -204,6 +219,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- video: 'inner-block-padding', description: __( 'Sets the block paddings, i.e the space between the inner columns and the block border', i18n ), } } + marks={ sizePresetMarks } /> onChange( 'container-padding', value, STATES.ALL_UNIT ) } top={ getValue( 'container-padding', STATES.ALL )?.top } @@ -291,7 +308,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-spacing-and- video: 'inner-block-padding', description: __( 'Sets the block paddings, i.e the space between the inner columns and the block border', i18n ), } } - + marks={ sizePresetMarks } /> array( 'container-border-style' => $string_properties, 'container-border-width' => $four_range_properties, - 'container-border-radius' => $four_range_properties, + 'container-border-radius' => $string_four_range_properties, 'container-box-shadow' => $string_properties, - 'container-padding' => $four_range_properties, + 'container-padding' => $string_four_range_properties, 'block-background-border-style' => $string_properties, 'block-background-border-width' => $four_range_properties, - 'block-background-border-radius' => $four_range_properties, + 'block-background-border-radius' => $string_four_range_properties, 'block-background-box-shadow' => $string_properties, - 'block-background-padding' => $four_range_properties, + 'block-background-padding' => $string_four_range_properties, - 'block-margin-bottom' => $number_properties, + 'block-margin-bottom' => $string_properties, 'column-margin' => $number_properties, - 'columns-column-gap' => $number_properties, - 'columns-row-gap' => $number_properties, + 'columns-column-gap' => $string_properties, + 'columns-row-gap' => $string_properties, 'image-drop-shadow' => $string_properties, - 'image-border-radius' => $four_range_properties, + 'image-border-radius' => $string_four_range_properties, ) ) ), diff --git a/src/plugins/global-settings/typography/editor-loader.js b/src/plugins/global-settings/typography/editor-loader.js index 6c7f39da55..29e56a05e0 100644 --- a/src/plugins/global-settings/typography/editor-loader.js +++ b/src/plugins/global-settings/typography/editor-loader.js @@ -1,6 +1,9 @@ /** * Loads all the typography styles for the blocks in the editor. */ +/** + * Internal dependencies + */ /** * External dependencies @@ -9,6 +12,7 @@ import { createTypographyStyles, fetchSettings, loadGoogleFont, + getDefaultFontSize, } from '~stackable/util' import { generateStyles } from '~stackable/block-components' import deepmerge from 'deepmerge' @@ -24,11 +28,20 @@ import { import { addAction, removeAction, applyFilters, doAction, addFilter, } from '@wordpress/hooks' -import { useSelect } from '@wordpress/data' +import { useSelect, dispatch } from '@wordpress/data' +import { models } from '@wordpress/api' + +let saveTypographyAsPresetsThrottle = null export const GlobalTypographyStyles = () => { + const { allCustomPresets } = useSelect( select => { + const _customPresetControls = select( 'stackable/global-preset-controls.custom' )?.getCustomPresetControls() ?? {} + return { allCustomPresets: { ..._customPresetControls } } + }, [] ) + const [ typographySettings, setTypographySettings ] = useState( [] ) const [ applySettingsTo, setApplySettingsTo ] = useState( '' ) + const [ isApplyBodyToHTML, setIsApplyBodyToHTML ] = useState( false ) // These are for debouncing the style generation to make things faster. const [ styles, setStyles ] = useState( '' ) @@ -49,17 +62,70 @@ export const GlobalTypographyStyles = () => { return select( 'core/edit-site' )?.getEditorMode() || select( 'core/edit-post' )?.getEditorMode() } ) + // Update the custom presets when using typography as presets + const updatePresetsWithTypography = ( useTypographyAsPresets, typographySettings, tags ) => { + if ( useTypographyAsPresets ) { + const fontSizePresets = tags + .filter( ( { presetSlug } ) => !! presetSlug ) + .map( ( { + selector, presetName, presetSlug, + } ) => { + // If no fontSize available, the unit should default to px + const size = typographySettings[ selector ]?.fontSize + const unit = size ? typographySettings[ selector ]?.fontSizeUnit : 'px' + return { + name: presetName, + slug: presetSlug, + size: `${ size ?? getDefaultFontSize( selector ) ?? 16 }${ unit ?? 'px' }`, + } + } ) + // Add the preset for extra small + let xSmallSize = typographySettings[ '.stk-subtitle' ]?.fontSize ?? getDefaultFontSize( '.stk-subtitle' ) ?? 16 + let xSmallUnit = typographySettings[ '.stk-subtitle' ]?.fontSizeUnit ?? 'px' + if ( xSmallUnit === 'px' ) { + xSmallSize = Math.pow( xSmallSize / 16, 2 ) + xSmallUnit = 'rem' + } else { + xSmallSize = Math.pow( xSmallSize, 2 ) + } + + fontSizePresets.push( { + name: 'XS', + slug: 'x-small', + size: `${ xSmallSize }${ xSmallUnit ?? 'px' }`, + } ) + // Reverse the presets so it's from smallest to biggest + fontSizePresets.reverse() + + const newSettings = { ...allCustomPresets, fontSizes: fontSizePresets } + + clearTimeout( saveTypographyAsPresetsThrottle ) + saveTypographyAsPresetsThrottle = setTimeout( () => { + const settings = new models.Settings( { stackable_global_custom_preset_controls: newSettings } ) // eslint-disable-line camelcase + settings.save() + }, 300 ) + + dispatch( 'stackable/global-preset-controls.custom' ).updateCustomPresetControls( newSettings ) + } + } + useEffect( () => { // Get settings. fetchSettings().then( response => { setTypographySettings( ( head( response.stackable_global_typography ) ) || {} ) setApplySettingsTo( response.stackable_global_typography_apply_to || 'blocks-stackable-native' ) + setIsApplyBodyToHTML( response.stackable_is_apply_body_to_html || false ) } ) // Allow actions to trigger styles to update. - addAction( 'stackable.global-settings.typography.update-trigger', 'stackable/typography-styles', ( newTypographySettings, newAapplySettingsTo ) => { + addAction( 'stackable.global-settings.typography.update-trigger', 'stackable/typography-styles', ( + newTypographySettings, newAapplySettingsTo, newUseTypographyAsPresets, newIsApplyBodyToHTML, tags + ) => { + updatePresetsWithTypography( newUseTypographyAsPresets, newTypographySettings, tags ) + setTypographySettings( newTypographySettings ) setApplySettingsTo( newAapplySettingsTo ) + setIsApplyBodyToHTML( newIsApplyBodyToHTML ) } ) return () => { removeAction( 'stackable.global-settings.typography.update-trigger', 'stackable/typography-styles' ) @@ -71,7 +137,7 @@ export const GlobalTypographyStyles = () => { addAction( 'stackable.global-settings.typography-update-global-styles', 'stackable/typography-styles', typographySettings => { // Generate all the typography styles. const styleObject = Object.keys( typographySettings ).map( tag => { - const selectors = formSelectors( tag, applySettingsTo ) + const selectors = formSelectors( tag, applySettingsTo, isApplyBodyToHTML ) // Build our selector, target h2.block or .block h2. // Some blocks may output the heading tag right away. @@ -118,16 +184,16 @@ export const GlobalTypographyStyles = () => { setStyleTimeout( setTimeout( () => doAction( 'stackable.global-settings.typography-update-global-styles', typographySettings ), 200 ) ) return () => removeAction( 'stackable.global-settings.typography-update-global-styles', 'stackable/typography-styles' ) - }, [ JSON.stringify( typographySettings ), applySettingsTo, device, editorMode ] ) + }, [ JSON.stringify( typographySettings ), applySettingsTo, isApplyBodyToHTML, device, editorMode ] ) return styles } -export const formSelectors = ( selector, applyTo ) => { +export const formSelectors = ( selector, applyTo, isApplyBodyToHTML ) => { if ( [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].includes( selector ) || selector.startsWith( '.' ) ) { return formClassOrTagSelectors( selector, applyTo ) } - return formParagraphSelectors( applyTo ) + return formParagraphSelectors( applyTo, isApplyBodyToHTML ) } export const formClassOrTagSelectors = ( selector, applyTo ) => { @@ -152,8 +218,8 @@ export const formClassOrTagSelectors = ( selector, applyTo ) => { return applyFilters( 'stackable.global-settings.typography-selectors', selectors, selector ) } -export const formParagraphSelectors = applyTo => { - return applyFilters( 'stackable.global-settings.typography-selectors', [ +export const formParagraphSelectors = ( applyTo, isApplyBodyToHTML ) => { + const selectors = [ ...formClassOrTagSelectors( 'p', applyTo ), ...formClassOrTagSelectors( 'li', applyTo ), `.editor-styles-wrapper p.block-editor-block-list__block[data-type^="core/"]`, @@ -162,7 +228,13 @@ export const formParagraphSelectors = applyTo => { `.editor-styles-wrapper .block-editor-block-list__block[data-type^="core/"] td`, // Apply the font styles to the content placeholder text when the post is blank. '.block-editor-default-block-appender.has-visible-prompt', - ], '' ) + ] + + // Add 'html' only if is_apply_body_to_html is true + if ( isApplyBodyToHTML ) { + selectors.push( 'html' ) + } + return applyFilters( 'stackable.global-settings.typography-selectors', selectors, '' ) } // Make sure that this isn't applied to the native query loop block, otherwise diff --git a/src/plugins/global-settings/typography/editor.scss b/src/plugins/global-settings/typography/editor.scss index 6715415711..418d565c26 100644 --- a/src/plugins/global-settings/typography/editor.scss +++ b/src/plugins/global-settings/typography/editor.scss @@ -137,4 +137,7 @@ .stk-inspector-sub-header { margin-bottom: 16px; } + .stk-toggle-control { + margin-top: 28px; + } } diff --git a/src/plugins/global-settings/typography/index.js b/src/plugins/global-settings/typography/index.js index 5750f59620..11d3ad98a7 100644 --- a/src/plugins/global-settings/typography/index.js +++ b/src/plugins/global-settings/typography/index.js @@ -5,18 +5,21 @@ 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' /** * External dependencies */ import { - PanelAdvancedSettings, AdvancedSelectControl, ControlSeparator, FontPairPicker, ProControlButton, + PanelAdvancedSettings, AdvancedSelectControl, ControlSeparator, FontPairPicker, ProControlButton, AdvancedToggleControl, } from '~stackable/components' import { fetchSettings } from '~stackable/util' import { i18n, isPro, showProNotice, } from 'stackable' -import { head, isEqual } from 'lodash' +import { + head, isEqual, cloneDeep, +} from 'lodash' /** * WordPress dependencies @@ -29,6 +32,7 @@ import { addFilter, applyFilters, doAction, } from '@wordpress/hooks' import { __, sprintf } from '@wordpress/i18n' +import { useSelect } from '@wordpress/data' export { GlobalTypographyStyles } @@ -36,34 +40,50 @@ const TYPOGRAPHY_TAGS = [ { label: sprintf( __( 'Heading %d', i18n ), 1 ), selector: 'h1', + presetName: '5XL', + presetSlug: 'xxxxx-large', }, { label: sprintf( __( 'Heading %d', i18n ), 2 ), selector: 'h2', + presetName: '4XL', + presetSlug: 'xxxx-large', }, { label: sprintf( __( 'Heading %d', i18n ), 3 ), selector: 'h3', + presetName: '3XL', + presetSlug: 'xxx-large', }, { label: sprintf( __( 'Heading %d', i18n ), 4 ), selector: 'h4', + presetName: '2XL', + presetSlug: 'xx-large', }, { label: sprintf( __( 'Heading %d', i18n ), 5 ), selector: 'h5', + presetName: 'XL', + presetSlug: 'x-large', }, { label: sprintf( __( 'Heading %d', i18n ), 6 ), selector: 'h6', + presetName: 'L', + presetSlug: 'large', }, { label: __( 'Body Text', i18n ), selector: 'p', + presetName: 'M', + presetSlug: 'medium', }, { label: __( 'Subtitle', i18n ), selector: '.stk-subtitle', + presetName: 'S', + presetSlug: 'small', help: ( <> { sprintf( __( "To apply this typography style, just add `%s` in your block\'s Additional CSS classes. Also make sure that `%s` tag is set to avoid conflict with other typography styles", i18n ), 'stk-subtitle', 'p' ) } @@ -75,11 +95,60 @@ const TYPOGRAPHY_TAGS = [ }, ] +const TYPE_SCALE = [ + { + label: __( 'None', i18n ), + value: 'none', + }, + { + label: __( 'Custom', i18n ), + value: 'custom', + disabled: true, + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.067', __( 'Minor Second', i18n ) ), + value: '1.067', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.125', __( 'Major Second', i18n ) ), + value: '1.125', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.2', __( 'Minor Third', i18n ) ), + value: '1.2', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.25', __( 'Major Third', i18n ) ), + value: '1.25', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.333', __( 'Perfect Fourth', i18n ) ), + value: '1.333', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.414', __( 'Augmented Fourth', i18n ) ), + value: '1.414', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.5', __( 'Perfect Fifth', i18n ) ), + value: '1.5', + }, + { + label: sprintf( __( '%s - %s', i18n ), '1.618', __( 'Golden Ratio', i18n ) ), + value: '1.618', + }, +] + let saveTypographyThrottle = null let saveSelectedFontPairThrottle = null let saveCustomFontPairsThrottle = null addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', output => { + const { useTypographyAsPresets } = useSelect( select => { + const _useTypographyAsPresets = select( 'stackable/global-preset-controls.custom' )?.getUseTypographyAsPresets() ?? false + return { useTypographyAsPresets: _useTypographyAsPresets } + }, [] ) + const FONT_PAIRS = applyFilters( 'stackable.global-settings.typography.font-pairs.premium-font-pairs', FREE_FONT_PAIRS ) const [ isPanelOpen, setIsPanelOpen ] = useState( false ) @@ -88,23 +157,44 @@ 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 [ isApplyBodyToHTML, setIsApplyBodyToHTML ] = useState( false ) const fontPairContainerRef = useRef( null ) useEffect( () => { fetchSettings().then( response => { // Get settings. - setTypographySettings( ( head( response.stackable_global_typography ) ) || {} ) + const _typographySettings = ( head( response.stackable_global_typography ) ) || {} + setTypographySettings( _typographySettings ) setApplySettingsTo( response.stackable_global_typography_apply_to || 'blocks-stackable-native' ) setCustomFontPairs( response.stackable_custom_font_pairs || [] ) - setSelectedFontPairName( response.stackable_selected_font_pair || '' ) + 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 ) + } } ) }, [] ) - // When typography styles are changed, trigger our editor style generator to update. useEffect( () => { - doAction( 'stackable.global-settings.typography.update-trigger', typographySettings, applySettingsTo ) - }, [ JSON.stringify( typographySettings ), applySettingsTo ] ) + // 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. + doAction( 'stackable.global-settings.typography.update-trigger', + typographySettings, applySettingsTo, useTypographyAsPresets, isApplyBodyToHTML, TYPOGRAPHY_TAGS, + ) + }, [ JSON.stringify( typographySettings ), applySettingsTo, useTypographyAsPresets, isApplyBodyToHTML ] ) // Scroll to the selected font pair when Global Typography tab is toggled useEffect( () => { @@ -170,33 +260,72 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', model.save() } - const changeStyles = typography => { - const newSettings = { ...typographySettings } + const changeIsApplyBodyToHTML = value => { + setIsApplyBodyToHTML( value ) + const model = new models.Settings( { + stackable_is_apply_body_to_html: value, // eslint-disable-line + } ) + model.save() + } + + const updateTypeScale = value => { + setSelectedTypeScale( value ) - Object.entries( typography ).forEach( ( [ selector, styles ] ) => { - if ( ! selector || typeof styles !== 'object' ) { - return - } - /** - * Delete the object keys with empty strings. - * Otherwise, the API will throw an error code 400 - * because of incompatible schema type. - */ - Object.keys( styles ).forEach( key => { - if ( styles[ key ] === '' ) { - delete styles[ key ] + // 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: '' } + return acc + }, {} ) + changeStyles( newSettings ) + return + } + + // If value is valid type scale, apply to the styles + const newSettings = getAppliedTypeScale( value ) + changeStyles( newSettings ) + } + + const changeStyles = _typography => { + setTypographySettings( prevTypographySettings => { + const typography = cloneDeep( _typography ) + const newSettings = { ...prevTypographySettings } + + Object.entries( typography ).forEach( ( [ selector, styles ] ) => { + if ( ! selector || typeof styles !== 'object' ) { + return } - } ) - newSettings[ selector ] = styles - } ) + // Merge the new styles with the previous, while overwritting similar styles. + // This allow adding styles without removing the previous ones. + // Check if the object is empty, used for resetting the whole setting. + if ( Object.keys( styles ).length !== 0 ) { + styles = { ...newSettings[ selector ], ...styles } + } + /** + * Delete the object keys with empty strings. + * Otherwise, the API will throw an error code 400 + * because of incompatible schema type. + */ + const cleanStyles = cleanTypographyStyle( styles ) || {} + + newSettings[ selector ] = cleanStyles + } ) - // Update the global styles immediately when reset font size is triggered. - if ( Object.values( typography ).some( styles => styles && ! styles.fontSize ) ) { - doAction( 'stackable.global-settings.typography-update-global-styles', newSettings ) - } + // Update the global styles immediately when reset font size is triggered. + if ( Object.values( typography ).some( styles => styles && ! styles.fontSize ) ) { + doAction( 'stackable.global-settings.typography-update-global-styles', newSettings ) + } - updateTypography( newSettings ) + updateTypography( newSettings ) + return newSettings + } ) } const resetStyles = selector => { @@ -220,9 +349,10 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', const getIsAllowReset = selector => { const currentFontPair = getCurrentFontPair() - const typographyStyle = typographySettings[ selector ] + const typographyStyle = cleanTypographyStyle( typographySettings[ selector ] ) || {} if ( ! isEditingFontPair && currentFontPair ) { - const fontPairStyle = currentFontPair.typography[ selector ] + // Clean style object to be consistent with changeStyles operation + const fontPairStyle = cleanTypographyStyle( currentFontPair.typography?.[ selector ] ) || {} if ( ! isEqual( fontPairStyle, typographyStyle ) && ! Array.isArray( typographyStyle ) ) { return true } @@ -238,15 +368,30 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', return false } - const getIsChangeConfirmed = () => { + const getIsFontPairChangeConfirmed = () => { // No need to confirm when the current font pair is custom // since changes are saved if ( customFontPairs.find( fontPair => fontPair.name === selectedFontPairName ) ) { return true } + // The confirmation should only occur if the font family has been edited + // since selecting font pair only changes font family + const currentFontPair = getCurrentFontPair() const isDirty = TYPOGRAPHY_TAGS.some( ( { selector } ) => { - return getIsAllowReset( selector ) + if ( isEditingFontPair || ! currentFontPair ) { + return false + } + // Clean style object to be consistent with changeStyles operation + const fontPairStyle = cleanTypographyStyle( currentFontPair.typography?.[ selector ] ) || {} + const typographyStyle = cleanTypographyStyle( typographySettings[ selector ] ) || {} + + if ( ! Array.isArray( typographyStyle ) && + fontPairStyle.fontFamily && + fontPairStyle.fontFamily !== typographyStyle.fontFamily ) { + return true + } + return false } ) if ( isDirty ) { @@ -321,7 +466,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', fontPair={ FONT_PAIRS[ 0 ] } isSelected={ selectedFontPairName === FONT_PAIRS[ 0 ].name } onClick={ () => { - if ( ! getIsChangeConfirmed() ) { + if ( ! getIsFontPairChangeConfirmed() ) { return } updateSelectedFontPair( FONT_PAIRS[ 0 ].name ) @@ -333,7 +478,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', customFontPairs={ customFontPairs } selected={ selectedFontPairName } onClick={ ( name, typography ) => { - if ( ! getIsChangeConfirmed() ) { + if ( ! getIsFontPairChangeConfirmed() ) { return } updateSelectedFontPair( name ) @@ -352,7 +497,7 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', fontPair={ fontPair } isSelected={ selectedFontPairName === fontPair.name } onClick={ () => { - if ( ! getIsChangeConfirmed() ) { + if ( ! getIsFontPairChangeConfirmed() ) { return } updateSelectedFontPair( fontPair.name ) @@ -365,6 +510,13 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', { __( 'Typography Settings' ) } + { TYPOGRAPHY_TAGS.map( ( { label, selector, help, }, index ) => { @@ -377,8 +529,21 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', value={ ( typographySettings[ selector ] ) || {} } defaultFontFamily={ getDefaultFontFamily( selector ) } isAllowReset={ getIsAllowReset( selector ) } - onChange={ styles => changeStyles( { [ selector ]: styles } ) } - onReset={ () => resetStyles( 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' ) + } + } } /> ) } ) } @@ -404,6 +569,13 @@ addFilter( 'stackable.global-settings.inspector', 'stackable/global-typography', getIsAllowReset={ getIsAllowReset } /> } + ) diff --git a/src/plugins/global-settings/typography/typography-picker.js b/src/plugins/global-settings/typography/typography-picker.js index 9b5ae1e7d3..3e8779d681 100644 --- a/src/plugins/global-settings/typography/typography-picker.js +++ b/src/plugins/global-settings/typography/typography-picker.js @@ -6,9 +6,12 @@ import { createTypographyStyles, getFontFamilyLabel, loadGoogleFont, } from '~stackable/util' import { i18n } from 'stackable' -import { upperFirst, omit } from 'lodash' +import { + upperFirst, omit, startCase, last, +} from 'lodash' import classnames from 'classnames' import { generateStyles } from '~stackable/block-components' +import { usePresetControls } from '~stackable/hooks' /** * WordPress dependencies @@ -20,10 +23,9 @@ import { Dashicon } from '@wordpress/components' const TypographyPicker = props => { const { value, help } = props - // On style change, gather all the styles then trigger the onChange. + // On style change, only get the new style then trigger the onChange. const onChange = ( style, value ) => { const newStyles = { - ...props.value, [ style ]: value, } props.onChange( newStyles ) @@ -46,9 +48,22 @@ const TypographyPicker = props => { 'ugb-global-settings-typography-control--with-description': createDescription( value ), } ) + const useTypographyAsPresets = useSelect( select => + select( 'stackable/global-preset-controls.custom' )?.getUseTypographyAsPresets() ?? false + ) + + const presetMarks = usePresetControls( 'fontSizes' ) + ?.getPresetMarks( { customOnly: useTypographyAsPresets } ) || null + return ( { description.push( upperFirst( styleObject.textTransform ) ) } - return description.join( ', ' ) + // If a css custom property, get just the name names + return description.map( value => { + if ( value.includes( 'var(' ) ) { + const propName = value.match( /var\(([^\),]*)/ )?.[ 1 ] + return startCase( last( propName.split( '--' ) ) ) + } + return value + } ).join( ', ' ) } const TypographyPreview = props => { diff --git a/src/plugins/global-settings/typography/utils.js b/src/plugins/global-settings/typography/utils.js new file mode 100644 index 0000000000..9758c63c80 --- /dev/null +++ b/src/plugins/global-settings/typography/utils.js @@ -0,0 +1,45 @@ +/** + * Generates a typographic scale based on the given value. + * + * This function returns an object where each key represents a text element + * (e.g., `h1`, `h2`, `p`, etc.) and its value contains a `fontSize` and `fontSizeUnit`, + * calculated using an exponential scale. + * + * @param {string|number} value - The base number to use for the typographic scale. + * @return {Object|undefined} An object mapping CSS selectors to their corresponding + * font size settings. Returns `undefined` if input is invalid. + */ + +export const getAppliedTypeScale = value => { + 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' }, + } +} + +/** + * Remove empty string properties from the given styles object + * + * @param {Object} styles - The typography styles object + * @return {Object} An object with removed empty string properties + */ + +export const cleanTypographyStyle = styles => { + if ( ! styles ) { + return {} + } + return Object.fromEntries( + Object.entries( styles ).filter( ( [ , value ] ) => value !== '' ) + ) +} diff --git a/src/plugins/global-settings/utils/use-block-layout-editor-loader.js b/src/plugins/global-settings/utils/use-block-layout-editor-loader.js index 409dba75dd..6320229663 100644 --- a/src/plugins/global-settings/utils/use-block-layout-editor-loader.js +++ b/src/plugins/global-settings/utils/use-block-layout-editor-loader.js @@ -15,6 +15,10 @@ import { useEffect, useState } from '@wordpress/element' import { compact } from 'lodash' import { useBlockHoverState, useBlockLayoutDefaults } from '~stackable/hooks' +function appendUnitIfNeeded( value, unit ) { + return ( typeof value === 'string' && value.trim().startsWith( 'var' ) ) ? value : `${ value }${ unit }` +} + const renderGlobalStyles = ( blockLayouts, blockLayoutDefaults, @@ -51,7 +55,7 @@ const renderGlobalStyles = ( } let style = '' - if ( typeof value === 'string' ) { + if ( typeof value === 'string' && isNaN( Number( value ) ) ) { style = `${ property }: ${ value };` } else if ( typeof value === 'object' ) { let defaultValue = getDefault( blockLayoutDefaults, _property, device ) @@ -72,7 +76,7 @@ const renderGlobalStyles = ( const bottom = value.bottom !== undefined ? value.bottom : defaultValue.bottom const left = value.left !== undefined ? value.left : defaultValue.left - style = `${ property }: ${ top }${ unit } ${ right }${ unit } ${ bottom }${ unit } ${ left }${ unit };` + style = `${ property }: ${ appendUnitIfNeeded( top, unit ) } ${ appendUnitIfNeeded( right, unit ) } ${ appendUnitIfNeeded( bottom, unit ) } ${ appendUnitIfNeeded( left, unit ) };` } else { style = `${ property }: ${ value }${ unit };` } diff --git a/src/util/index.js b/src/util/index.js index 3d011c095c..a727607cb6 100644 --- a/src/util/index.js +++ b/src/util/index.js @@ -388,3 +388,74 @@ export const createUniqueClass = uid => `${ uid.substring( 0, 7 ) }` export const semverCompare = ( version1, operator, version2 ) => { return compare( version1, version2, operator ) } + +/** + * Extracts all number-unit pairs from a CSS value. + * + * @param { string } value - The CSS value to extract from. + * @return { Array } An array of tuples, each containing a number and its corresponding unit. + * + * @example + * extractNumbersAndUnits( "min(1.5rem, 2vw)" ) + * // Returns: [["1.5", "rem"], ["2", "vw"]] + */ +export const extractNumbersAndUnits = value => { + if ( value.startsWith( 'var' ) ) { + return [ [ value, '' ] ] + } + // Match numbers followed by a unit, including decimals and negative values. + const regex = /(-?\d*\.?\d+)([a-zA-Z%]*)/g + const matches = [ ...value.matchAll( regex ) ] + + if ( matches.length ) { + return matches.map( match => [ match[ 1 ], match[ 2 ] || 'px' ] ) + } + + // If the input is purely numeric (e.g., "10"), assume "px" + if ( /^-?\d*\.?\d+$/.test( value ) ) { + return [ [ value, 'px' ] ] + } + return [ [ '0', 'px' ] ] +} + +// Return only the CSS variable name given a CSS variable +export const getCSSVarName = value => { + if ( typeof value !== 'string' ) { + return null + } + const match = value?.match( /var\(\s*([^,)\s]+)/ ) + return match ? match[ 1 ] : null +} + +/** + * Convert a value from rem/em to px if the units array doesn't support it. + * + * @param {string[]} units - The list of supported units. + * @param {string} currentUnit - The current unit of the value. + * @param {string|number} currentValue - The current value to convert. + * + * @return {Object} An object containing the converted value and unit. + */ +export function convertToPxIfUnsupported( units, currentUnit, currentValue ) { + const unitMultipliers = { + rem: 16, + em: 16, + } + + const normalizedUnit = currentUnit?.toLowerCase() + + if ( + ( ! units?.length || ! units.includes( normalizedUnit ) ) && + unitMultipliers[ normalizedUnit ] + ) { + return { + value: `${ parseFloat( currentValue ) * unitMultipliers[ normalizedUnit ] }`, + unit: 'px', + } + } + + return { + value: currentValue, + unit: currentUnit, + } +} diff --git a/src/util/styles/style-object.js b/src/util/styles/style-object.js index 53b1eaaf8e..d486dfdab4 100644 --- a/src/util/styles/style-object.js +++ b/src/util/styles/style-object.js @@ -335,8 +335,10 @@ class StyleObject { } if ( unit ) { // Note: this will only work for non-objects. - // If the value is `auto`, don't add units. - value = value === 'auto' ? value : `${ value }${ unit }` + // If the value is `auto` or a CSS variable, don't add units. + if ( ! ( value === 'auto' || ( typeof value === 'string' && value.startsWith( 'var' ) ) ) ) { + value = `${ value }${ unit }` + } } if ( format !== '%s' && format !== '' ) { value = sprintf( diff --git a/src/util/typography/styles.js b/src/util/typography/styles.js index c3ca3b59a1..3009bbddc9 100644 --- a/src/util/typography/styles.js +++ b/src/util/typography/styles.js @@ -16,6 +16,10 @@ import { camelCase } from 'lodash' */ import { sprintf } from '@wordpress/i18n' +const isCSSVarValue = value => { + return typeof value === 'string' && value.startsWith( 'var' ) +} + export const createTypographyStyles = ( attrNameTemplate = '%s', screen = 'desktop', blockAttributes = {}, options = {} ) => { const getAttrName = attrName => camelCase( sprintf( attrNameTemplate, attrName ) ) const getValue = __getValue( blockAttributes, getAttrName, '' ) @@ -34,10 +38,14 @@ export const createTypographyStyles = ( attrNameTemplate = '%s', screen = 'deskt const tabletFontSize = getValue( 'TabletFontSize' ) 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' + if ( screen !== 'tablet' && screen !== 'mobile' ) { // Desktop. styles = { fontFamily: getValue( 'FontFamily' ) !== '' ? getFontFamily( getValue( 'FontFamily' ) ) : undefined, - fontSize: desktopFontSize !== '' ? appendImportant( `${ desktopFontSize }${ getValue( 'FontSizeUnit' ) || 'px' }`, importantSize ) : undefined, + fontSize: desktopFontSize !== '' ? appendImportant( `${ desktopFontSize }${ desktopFontSizeUnit }`, importantSize ) : undefined, fontWeight: getValue( 'FontWeight' ) !== '' ? getValue( 'FontWeight' ) : undefined, textTransform: getValue( 'TextTransform' ) !== '' ? getValue( 'TextTransform' ) : undefined, letterSpacing: getValue( 'LetterSpacing' ) !== '' ? `${ getValue( 'LetterSpacing' ) }px` : undefined, @@ -56,7 +64,7 @@ export const createTypographyStyles = ( attrNameTemplate = '%s', screen = 'deskt } } if ( tabletFontSize ) { - styles.fontSize = getValue( 'TabletFontSize', `%s${ getValue( 'TabletFontSizeUnit' ) || 'px' }` ) + styles.fontSize = getValue( 'TabletFontSize', `%s${ tabletFontSizeUnit }` ) } } else { // Mobile. styles = { @@ -79,7 +87,7 @@ export const createTypographyStyles = ( attrNameTemplate = '%s', screen = 'deskt } } if ( mobileFontSize ) { - styles.fontSize = getValue( 'MobileFontSize', `%s${ getValue( 'MobileFontSizeUnit' ) || 'px' }` ) + styles.fontSize = getValue( 'MobileFontSize', `%s${ mobileFontSizeUnit }` ) } } diff --git a/src/welcome/admin.js b/src/welcome/admin.js index a428c661f0..70a71699c1 100644 --- a/src/welcome/admin.js +++ b/src/welcome/admin.js @@ -77,14 +77,15 @@ const SEARCH_TREE = [ children: [ __( 'Nested Block Width', i18n ), __( 'Nested Wide Block Width', i18n ), - __( 'Stackable Text as Default Block', i18n ), ], }, { id: 'editor', children: [ + __( 'Stackable Text as Default Block', i18n ), __( 'Design Library', i18n ), __( 'Stackable Settings', i18n ), + __( 'Use Size Presets by Default', i18n ), __( 'Block Linking (Beta)', i18n ), ], }, @@ -672,7 +673,7 @@ const EditorSettings = props => { { __( 'You can customize some of the features and behavior of Stackable in the editor here.' ) } { handleSettingsChange( { stackable_enable_text_default_block: value } ) // eslint-disable-line camelcase @@ -697,6 +698,17 @@ const EditorSettings = props => { } } help={ __( 'Adds a button on the top of the editor which gives access to Stackable settings. Note: You won\'t be able to access Stackable settings when this is disabled.', i18n ) } /> + { + props.handleSettingsChange( { stackable_use_size_presets_by_default: value } ) // eslint-disable-line camelcase + } } + help={ __( 'If enabled, range controls will be on preset mode by default.', i18n ) } + disabled={ __( 'Use custom values', i18n ) } + enabled={ __( 'Use presets', i18n ) } + />
{ __( 'You can customize some of the features and behavior of Stackable in the editor here.' ) }