diff --git a/plugin.php b/plugin.php index 7a6403f92b..ed876e36df 100644 --- a/plugin.php +++ b/plugin.php @@ -242,6 +242,7 @@ function is_frontend() { require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/color-schemes/deprecated/index.php' ); // We need to add this so the filter for deprecation gets applied. 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/plugins/global-settings/block-styles/index.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/css-optimize.php' ); require_once( plugin_dir_path( __FILE__ ) . 'src/compatibility/index.php' ); if ( ! is_admin() ) { diff --git a/src/block-components/block-div/attributes.js b/src/block-components/block-div/attributes.js index e01307482d..67fcc8cae2 100644 --- a/src/block-components/block-div/attributes.js +++ b/src/block-components/block-div/attributes.js @@ -23,6 +23,14 @@ export const addAttributes = attrObject => { type: 'string', default: '', }, + blockStyle: { + type: 'string', + default: '', + }, + modifiedBlockStyle: { + type: 'boolean', + default: false, + }, }, versionAdded: '3.0.0', versionDeprecated: '', diff --git a/src/block-components/block-div/index.js b/src/block-components/block-div/index.js index de84319ed1..84e1a1e4e0 100644 --- a/src/block-components/block-div/index.js +++ b/src/block-components/block-div/index.js @@ -56,6 +56,7 @@ export const BlockDiv = memo( props => { 'stk-block', blockHoverClass, attributes.className, // Custom CSS classes. + attributes.blockStyle, { [ uniqueBlockClass ]: withUniqueClass, 'stk-block-background': attributes.hasBackground, @@ -133,6 +134,7 @@ BlockDiv.Content = props => { className, 'stk-block', uniqueBlockClass, + attributes.blockStyle, { 'stk-block-background': attributes.hasBackground, [ `stk--background-scheme--${ attributes.backgroundColorScheme }` ]: attributes.hasBackground && attributes.backgroundColorScheme, diff --git a/src/block/accordion/edit.js b/src/block/accordion/edit.js index 9404bca801..dae03d58b7 100644 --- a/src/block/accordion/edit.js +++ b/src/block/accordion/edit.js @@ -35,7 +35,8 @@ import { useBlockAttributesContext, useBlockSetAttributesContext, } from '~stackable/hooks' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -213,6 +214,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Add another icon picker to the Icon block for picking the icon for the opened accordion. diff --git a/src/block/blockquote/edit.js b/src/block/blockquote/edit.js index e147988ef1..76a51deb83 100644 --- a/src/block/blockquote/edit.js +++ b/src/block/blockquote/edit.js @@ -34,6 +34,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -142,6 +143,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/block/button-group/edit.js b/src/block/button-group/edit.js index 9e6cf8f0ea..471d98a53a 100644 --- a/src/block/button-group/edit.js +++ b/src/block/button-group/edit.js @@ -36,6 +36,7 @@ import { import { useDeviceType } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -265,5 +266,6 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/button/edit.js b/src/block/button/edit.js index cfce33097b..7c8956f49a 100644 --- a/src/block/button/edit.js +++ b/src/block/button/edit.js @@ -22,6 +22,7 @@ import { import { useBlockLayoutDefaults, useBlockStyle } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapper, withQueryLoopContext, } from '~stackable/higher-order' @@ -167,4 +168,5 @@ export default compose( withBlockWrapper, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( buttonStyles ), )( Edit ) diff --git a/src/block/call-to-action/edit.js b/src/block/call-to-action/edit.js index 5319ba768c..4245dcd3fd 100644 --- a/src/block/call-to-action/edit.js +++ b/src/block/call-to-action/edit.js @@ -36,7 +36,8 @@ import { getContentAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -152,4 +153,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/card/edit.js b/src/block/card/edit.js index d51f3c96f1..b572b41610 100644 --- a/src/block/card/edit.js +++ b/src/block/card/edit.js @@ -19,6 +19,7 @@ import { import { useBlockStyle, useDeviceType } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -206,4 +207,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/carousel/edit.js b/src/block/carousel/edit.js index 0b2f8c46db..f8c471463f 100644 --- a/src/block/carousel/edit.js +++ b/src/block/carousel/edit.js @@ -47,6 +47,7 @@ import { import { useDeviceType } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -792,4 +793,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/column/edit.js b/src/block/column/edit.js index d3adb37743..c82c9ae5e1 100644 --- a/src/block/column/edit.js +++ b/src/block/column/edit.js @@ -20,6 +20,7 @@ import { withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockStyleContext, } from '~stackable/higher-order' import { Column, @@ -222,4 +223,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/columns/edit.js b/src/block/columns/edit.js index c2653d9239..137b4df79b 100644 --- a/src/block/columns/edit.js +++ b/src/block/columns/edit.js @@ -37,6 +37,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -199,4 +200,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/count-up/edit.js b/src/block/count-up/edit.js index 28e4672a8b..eeb835a05c 100644 --- a/src/block/count-up/edit.js +++ b/src/block/count-up/edit.js @@ -27,7 +27,8 @@ import { InspectorTabs, InspectorStyleControls, PanelAdvancedSettings, AdvancedRangeControl, useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -135,4 +136,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/countdown/edit.js b/src/block/countdown/edit.js index 2f4c2c0407..588a42444a 100644 --- a/src/block/countdown/edit.js +++ b/src/block/countdown/edit.js @@ -32,6 +32,7 @@ import { } from '~stackable/components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -472,6 +473,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Add meta controls for labels. diff --git a/src/block/divider/edit.js b/src/block/divider/edit.js index 0c39f9ed85..093a6fbb38 100644 --- a/src/block/divider/edit.js +++ b/src/block/divider/edit.js @@ -31,7 +31,8 @@ import { } from '~stackable/components' import { useBlockStyle } from '~stackable/hooks' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -136,4 +137,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/expand/edit.js b/src/block/expand/edit.js index b945daba37..463affa0f2 100644 --- a/src/block/expand/edit.js +++ b/src/block/expand/edit.js @@ -26,7 +26,8 @@ import { Transform, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -146,6 +147,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/block/feature-grid/edit.js b/src/block/feature-grid/edit.js index 6a5aa0506b..a1963aedae 100644 --- a/src/block/feature-grid/edit.js +++ b/src/block/feature-grid/edit.js @@ -33,7 +33,8 @@ import { Columns, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -155,4 +156,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/feature/edit.js b/src/block/feature/edit.js index d1051288d7..a35d742442 100644 --- a/src/block/feature/edit.js +++ b/src/block/feature/edit.js @@ -34,7 +34,8 @@ import { Columns, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -148,4 +149,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/heading/edit.js b/src/block/heading/edit.js index 4f03d565d9..a1de0367ac 100644 --- a/src/block/heading/edit.js +++ b/src/block/heading/edit.js @@ -37,6 +37,7 @@ import { import { createBlockCompleter } from '~stackable/util' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -287,4 +288,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/hero/edit.js b/src/block/hero/edit.js index e93b9b382f..78e41fd107 100644 --- a/src/block/hero/edit.js +++ b/src/block/hero/edit.js @@ -35,7 +35,8 @@ import { getContentAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -154,4 +155,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/horizontal-scroller/edit.js b/src/block/horizontal-scroller/edit.js index dcec641a94..3e46e39ad6 100644 --- a/src/block/horizontal-scroller/edit.js +++ b/src/block/horizontal-scroller/edit.js @@ -39,6 +39,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -267,4 +268,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/icon-box/edit.js b/src/block/icon-box/edit.js index 8ad37547b7..19fcc3cc48 100644 --- a/src/block/icon-box/edit.js +++ b/src/block/icon-box/edit.js @@ -30,7 +30,8 @@ import { Transform, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { substituteCoreIfDisabled } from '~stackable/util' import { substitutionRules } from '../../blocks' @@ -158,4 +159,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/icon-button/edit.js b/src/block/icon-button/edit.js index cfc0764a7a..1b21ab3ed8 100644 --- a/src/block/icon-button/edit.js +++ b/src/block/icon-button/edit.js @@ -16,7 +16,8 @@ import { Transform, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapper, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapper, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -120,4 +121,5 @@ export default compose( withBlockWrapper, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/icon-label/edit.js b/src/block/icon-label/edit.js index af07d08364..bba381256a 100644 --- a/src/block/icon-label/edit.js +++ b/src/block/icon-label/edit.js @@ -30,7 +30,8 @@ import { Transform, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -152,6 +153,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/block/icon-list-item/edit.js b/src/block/icon-list-item/edit.js index 51f183dc96..ec0ff272d1 100644 --- a/src/block/icon-list-item/edit.js +++ b/src/block/icon-list-item/edit.js @@ -32,6 +32,7 @@ import { withBlockAttributeContext, withQueryLoopContext, withBlockWrapperIsHovered, + withBlockStyleContext, } from '~stackable/higher-order' /** @@ -214,6 +215,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) /** diff --git a/src/block/icon-list/edit.js b/src/block/icon-list/edit.js index 982d401ccb..312e91d65a 100644 --- a/src/block/icon-list/edit.js +++ b/src/block/icon-list/edit.js @@ -22,7 +22,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { Typography, @@ -495,6 +496,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) addFilter( 'stackable.edit.margin-bottom.enable-handlers', 'stackable/icon-list', ( enabled, parentBlock ) => { diff --git a/src/block/icon/edit.js b/src/block/icon/edit.js index 9c522a597e..8b452eee56 100644 --- a/src/block/icon/edit.js +++ b/src/block/icon/edit.js @@ -15,7 +15,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { BlockDiv, @@ -131,6 +132,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // When saving block styles, don't save the icons used by the block. diff --git a/src/block/image-box/edit.js b/src/block/image-box/edit.js index 8abe2fb42c..322bac4697 100644 --- a/src/block/image-box/edit.js +++ b/src/block/image-box/edit.js @@ -17,7 +17,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { BlockDiv, @@ -150,6 +151,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/block/image/edit.js b/src/block/image/edit.js index a4b08c7f03..4cdd12fa77 100644 --- a/src/block/image/edit.js +++ b/src/block/image/edit.js @@ -30,6 +30,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -172,6 +173,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) addFilter( 'stackable.block-component.typography.before', 'stackable/image', ( output, props ) => { diff --git a/src/block/map/edit.js b/src/block/map/edit.js index 30675304bc..ab98395cbe 100644 --- a/src/block/map/edit.js +++ b/src/block/map/edit.js @@ -40,7 +40,8 @@ import { getAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { currentUserHasCapability, getAttributeName } from '~stackable/util' @@ -569,4 +570,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/notification/edit.js b/src/block/notification/edit.js index cbe76be9f3..9daf7e4e7d 100644 --- a/src/block/notification/edit.js +++ b/src/block/notification/edit.js @@ -39,7 +39,8 @@ import { getContentAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -222,6 +223,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Prevent the text from being being styled with a saved default style. diff --git a/src/block/number-box/edit.js b/src/block/number-box/edit.js index 8ee3bd6724..8fe3cc77bf 100644 --- a/src/block/number-box/edit.js +++ b/src/block/number-box/edit.js @@ -33,7 +33,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -169,4 +170,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/posts/edit.js b/src/block/posts/edit.js index 1b6345c969..22fb77492d 100644 --- a/src/block/posts/edit.js +++ b/src/block/posts/edit.js @@ -37,6 +37,7 @@ import { } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -456,6 +457,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Add hover selector control diff --git a/src/block/price/edit.js b/src/block/price/edit.js index ece4f0642b..0547411d85 100644 --- a/src/block/price/edit.js +++ b/src/block/price/edit.js @@ -24,7 +24,8 @@ import { Transform, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -122,6 +123,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/block/pricing-box/edit.js b/src/block/pricing-box/edit.js index 1e271d0133..443656815f 100644 --- a/src/block/pricing-box/edit.js +++ b/src/block/pricing-box/edit.js @@ -31,7 +31,8 @@ import { getContentAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -144,4 +145,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/progress-bar/edit.js b/src/block/progress-bar/edit.js index 91395e3dd2..0925b9535e 100644 --- a/src/block/progress-bar/edit.js +++ b/src/block/progress-bar/edit.js @@ -28,7 +28,8 @@ import { } from '~stackable/block-components' import { version as VERSION, i18n } from 'stackable' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import classnames from 'classnames' @@ -162,4 +163,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/progress-circle/edit.js b/src/block/progress-circle/edit.js index f8d6cb8347..68f6d6c812 100644 --- a/src/block/progress-circle/edit.js +++ b/src/block/progress-circle/edit.js @@ -28,7 +28,8 @@ import { } from '~stackable/block-components' import { version as VERSION, i18n } from 'stackable' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import classnames from 'classnames' @@ -175,4 +176,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/separator/edit.js b/src/block/separator/edit.js index 234e6bc36f..04dba9dec5 100644 --- a/src/block/separator/edit.js +++ b/src/block/separator/edit.js @@ -18,7 +18,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { BlockDiv, @@ -157,4 +158,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/spacer/edit.js b/src/block/spacer/edit.js index f8be6ea7a9..f8d925b813 100644 --- a/src/block/spacer/edit.js +++ b/src/block/spacer/edit.js @@ -25,7 +25,8 @@ import { } from '~stackable/components' import { getAttributeName } from '~stackable/util' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -196,4 +197,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/subtitle/edit.js b/src/block/subtitle/edit.js index cd3e887859..f708ae066c 100644 --- a/src/block/subtitle/edit.js +++ b/src/block/subtitle/edit.js @@ -26,6 +26,7 @@ import classnames from 'classnames' import { InspectorTabs, useBlockCssGenerator } from '~stackable/components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -142,4 +143,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/tab-content/edit.js b/src/block/tab-content/edit.js index 1b1792137d..ebba4ec0c6 100644 --- a/src/block/tab-content/edit.js +++ b/src/block/tab-content/edit.js @@ -34,6 +34,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapper, withQueryLoopContext, } from '~stackable/higher-order' @@ -194,4 +195,5 @@ export default compose( withBlockWrapper, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/tab-labels/edit.js b/src/block/tab-labels/edit.js index a54dcbd871..49862e0636 100644 --- a/src/block/tab-labels/edit.js +++ b/src/block/tab-labels/edit.js @@ -49,6 +49,7 @@ import { } from '~stackable/components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapper, withQueryLoopContext, } from '~stackable/higher-order' @@ -768,4 +769,5 @@ export default compose( withBlockWrapper, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( tabBlockStyles ), )( Edit ) diff --git a/src/block/table-of-contents/edit.js b/src/block/table-of-contents/edit.js index d5fa77cd5e..67b99d3e63 100644 --- a/src/block/table-of-contents/edit.js +++ b/src/block/table-of-contents/edit.js @@ -25,7 +25,8 @@ import { useBlockCssGenerator, } from '~stackable/components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' import { Typography, @@ -563,4 +564,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/tabs/edit.js b/src/block/tabs/edit.js index f19da15d54..5075a3ca5e 100644 --- a/src/block/tabs/edit.js +++ b/src/block/tabs/edit.js @@ -39,6 +39,7 @@ import { import { InnerBlocks } from '@wordpress/block-editor' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -321,4 +322,5 @@ export default compose( withQueryLoopContext, withBlockAttributeContext, withActiveTab( 'initialTabOpen' ), + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/team-member/edit.js b/src/block/team-member/edit.js index ba628bb413..745f1582aa 100644 --- a/src/block/team-member/edit.js +++ b/src/block/team-member/edit.js @@ -35,6 +35,7 @@ import { } from '~stackable/block-components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -149,4 +150,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/testimonial/edit.js b/src/block/testimonial/edit.js index a9085dc791..b1757afdf3 100644 --- a/src/block/testimonial/edit.js +++ b/src/block/testimonial/edit.js @@ -34,7 +34,8 @@ import { getContentAlignmentClasses, } from '~stackable/block-components' import { - withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, + withBlockAttributeContext, withBlockStyleContext, + withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' /** @@ -147,4 +148,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) diff --git a/src/block/text/edit.js b/src/block/text/edit.js index b14552f012..f856391524 100644 --- a/src/block/text/edit.js +++ b/src/block/text/edit.js @@ -36,6 +36,7 @@ import { } from '~stackable/components' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -216,4 +217,5 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ) )( Edit ) diff --git a/src/block/timeline/edit.js b/src/block/timeline/edit.js index aadde8f05d..f9bda74999 100644 --- a/src/block/timeline/edit.js +++ b/src/block/timeline/edit.js @@ -38,6 +38,7 @@ import { import { useDeviceType } from '~stackable/hooks' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -603,6 +604,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Change the default bottom margin to 0 for the timeline block because this diff --git a/src/block/video-popup/edit.js b/src/block/video-popup/edit.js index bfd7c9084c..b345915a8b 100644 --- a/src/block/video-popup/edit.js +++ b/src/block/video-popup/edit.js @@ -36,6 +36,7 @@ import { import { getVideoProviderFromURL, urlIsVideo } from '~stackable/util' import { withBlockAttributeContext, + withBlockStyleContext, withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' @@ -289,6 +290,7 @@ export default compose( withBlockWrapperIsHovered, withQueryLoopContext, withBlockAttributeContext, + withBlockStyleContext( blockStyles ), )( Edit ) // Disable bottom margins for child blocks. diff --git a/src/components/advanced-range-control/index.js b/src/components/advanced-range-control/index.js index 8cdd76dcf3..340a38e9f6 100644 --- a/src/components/advanced-range-control/index.js +++ b/src/components/advanced-range-control/index.js @@ -113,10 +113,6 @@ const AdvancedRangeControl = props => { 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 ) @@ -132,6 +128,11 @@ const AdvancedRangeControl = props => { } } + // 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( isMarkValue ) + // Set the markMode when device type changes useEffect( () => { setIsMarkMode( isMarkValue ) diff --git a/src/components/block-attributes-get-button/button.js b/src/components/block-attributes-get-button/button.js index d4023bd3f3..576db791f6 100644 --- a/src/components/block-attributes-get-button/button.js +++ b/src/components/block-attributes-get-button/button.js @@ -2,7 +2,7 @@ * External dependencies */ import { startCase } from 'lodash' -import { applyBlockDesign } from '~stackable/util' +import { applyBlockDesign, getCleanAttributes } from '~stackable/util' /** * WordPress dependencies @@ -29,7 +29,6 @@ const GetBlockAttributesButton = ( { blockName: clientId && getBlockName( clientId ) ? getBlockName( clientId ).replace( /^\w+\//g, '' ) : '', getJSONBlockAttributes: () => { const { getBlockName } = select( 'core/block-editor' ) - const { getBlockType } = select( 'core/blocks' ) if ( ! clientId ) { return {} @@ -39,13 +38,7 @@ const GetBlockAttributesButton = ( { const blockName = getBlockName( clientId ).replace( /^\w+\//g, '' ) // Remove attributes which remain as the default. - const defaultAttributes = getBlockType( getBlockName( clientId ) ).attributes - const cleanedAttributes = Object.keys( blockAttributes ).reduce( ( attrs, attrName ) => { - if ( blockAttributes[ attrName ] !== ( defaultAttributes[ attrName ] ? defaultAttributes[ attrName ].default : '' ) ) { - attrs[ attrName ] = blockAttributes[ attrName ] - } - return attrs - }, {} ) + const cleanedAttributes = getCleanAttributes( blockAttributes, getBlockName( clientId ) ) // Remove the unique class. Since this is generated by the block. cleanedAttributes.uniqueClass = undefined @@ -99,7 +92,7 @@ const GetBlockAttributesButton = ( { setOpenPopover( false ) } } > -

{ 'Copy or modify the attributes of the block directly. Use only double quotes "' }

+

Copy or modify the attributes of the block directly. Use only double quotes "

} diff --git a/src/components/block-css/block-style-generator-class.js b/src/components/block-css/block-style-generator-class.js index ded397c942..c2adb4f6eb 100644 --- a/src/components/block-css/block-style-generator-class.js +++ b/src/components/block-css/block-style-generator-class.js @@ -110,9 +110,10 @@ export class BlockStyleGenerator { * Gets all the block styles for the given attribute names * * @param {Array} attrNames Array of attribute names + * @param {boolean} getNonCssAttributes returns the blockStyles and the non-css attributes if true * @return {Object} Object of blockStyles, keys are the indices */ - getBlockStyles( attrNames ) { + getBlockStyles( attrNames, getNonCssAttributes = false ) { if ( ! attrNames ) { return this._orderedStyles.reduce( ( blockStyles, blockStyle, index ) => { blockStyles[ index ] = blockStyle @@ -158,6 +159,11 @@ export class BlockStyleGenerator { } } ) + if ( getNonCssAttributes && attrNames ) { + const nonCssAttrs = attrNames.filter( attrName => ! ( this.getRootAttrName( attrName ) in blockStyles ) && attrName !== 'uniqueId' ) + return [ orderdBlockStyles, nonCssAttrs ] + } + return orderdBlockStyles } @@ -207,6 +213,7 @@ export class BlockStyleGenerator { instanceId: args.instanceId, attributes, editorMode: true, + generateForAllBlockStates: args.generateForAllBlockStates, } ) if ( css ) { generatedCss.push( css ) @@ -231,6 +238,7 @@ export class BlockStyleGenerator { instanceId: args.instanceId, attributes, editorMode: true, + generateForAllBlockStates: args.generateForAllBlockStates, } ) if ( css ) { diff --git a/src/components/block-css/index.js b/src/components/block-css/index.js index e09641f485..1383eba268 100644 --- a/src/components/block-css/index.js +++ b/src/components/block-css/index.js @@ -39,6 +39,7 @@ import { sprintf } from '@wordpress/i18n' import { applyFilters } from '@wordpress/hooks' export { BlockStyleGenerator } from './block-style-generator-class' export { useBlockCssGenerator } from './use-block-style-generator' +export { default as CssSaveCompiler } from './css-save-compiler' const BlockCss = props => { const { @@ -82,6 +83,8 @@ const BlockCss = props => { clientId = '', // The block's clientId, only used if rendering for the editor. instanceId = '', // Used by the Query Loop block, this is the instance of the template being displayed. blockState = 'normal', // The block's hover state to render the styles for. + + generateForAllBlockStates = false, // If true, it will generate styles for all block states } = props // const editorMode = ! compileCssTo @@ -300,15 +303,20 @@ const BlockCss = props => { // TODO: why do we have this condition for the collapsedSelector, but they just do the same prepending?? if ( hasCollapsed ) { - if ( blockState === 'collapsed' ) { + if ( generateForAllBlockStates ) { + collapsedSelector = prependClass( selector, '%h :where(.stk-block-accordion.stk--is-open) .%s' ) + } else if ( blockState === 'collapsed' ) { collapsedSelector = prependClass( selector, ':where(.stk-block-accordion.stk--is-open) .%s' ) } else { collapsedSelector = prependClass( selector, ':where(.stk-block-accordion.stk--is-open) .%s' ) } } + // Use %h as a placeholder to indicate that a hover state class should be prepended to the selector. if ( hasParentHover ) { - if ( blockState === 'parent-hover' ) { + if ( generateForAllBlockStates ) { + parentHoverSelector = [ prependClass( selector, '%h.%s.stk--is-hovered' ), prependClass( selector, ':where(.stk-hover-parent:hover, .stk-hover-parent.stk--is-hovered) .%s' ) ] + } else if ( blockState === 'parent-hover' ) { parentHoverSelector = prependClass( selector, '.%s.stk--is-hovered' ) } else { parentHoverSelector = prependClass( selector, ':where(.stk-hover-parent:hover, .stk-hover-parent.stk--is-hovered) .%s' ) @@ -321,11 +329,14 @@ const BlockCss = props => { // using the selector `[data-block="clientId"]`, for these scenarios the // method will not work. Instead we just append `:hover` to the block // selector directly. + // Use %h as a placeholder to indicate that a hover state class should be prepended to the selector. if ( hasHover ) { const selectorHasDataBlock = ( hoverSelector || selector ).includes( '[data-block=' ) && ( hoverSelector || selector ).endsWith( ']' ) if ( selectorHasDataBlock ) { // If there is a [data-block] append the :hover or .stk-is-hovered directly to it. - if ( blockState === 'hover' ) { + if ( generateForAllBlockStates ) { + hoverSelector = [ appendClass( selector, '%h.stk--is-hovered' ), hoverSelector || appendClass( selector, ':hover' ) ] + } else if ( blockState === 'hover' ) { // In editor, always use the `selector` instead of the hoverSelector. hoverSelector = appendClass( selector, '.stk--is-hovered' ) } else { @@ -333,6 +344,9 @@ const BlockCss = props => { } } else { // Prepend .%s:hover to the selector. + if ( generateForAllBlockStates ) { + hoverSelector = [ prependClass( selector, '%h.%s.stk--is-hovered' ), hoverSelector || prependClass( selector, '.%s:hover' ) ] + } if ( blockState === 'hover' ) { // eslint-disable-line no-lonely-if // In editor, always use the `selector` instead of the hoverSelector. hoverSelector = prependClass( selector, '.%s.stk--is-hovered' ) @@ -352,8 +366,8 @@ const BlockCss = props => { if ( typeof selector === 'string' ) { // Add instance id to classes. ( e.g. `stk-abc123` -> `stk-abc123-2`, where 2 is `instanceId`. ) selector = selector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) - hoverSelector = hoverSelector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) - parentHoverSelector = parentHoverSelector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) + hoverSelector = typeof hoverSelector === 'string' ? hoverSelector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) : hoverSelector.map( s => s.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) ) + parentHoverSelector = typeof parentHoverSelector === 'string' ? parentHoverSelector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) : parentHoverSelector.map( s => s.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) ) collapsedSelector = collapsedSelector.replace( /[^^?](.%s)([^-])/g, `$1-${ instanceId }$2` ) } } @@ -371,16 +385,20 @@ const BlockCss = props => { if ( Array.isArray( hoverSelector ) ) { hoverSelector = hoverSelector.join( ', ' ) } + if ( Array.isArray( parentHoverSelector ) ) { + parentHoverSelector = parentHoverSelector.join( ', ' ) + } - selector = prependCSSClass( selector, blockUniqueClassName, blockUniqueClassName, editorMode ? '.editor-styles-wrapper' : '' ) + const wrapSelector = editorMode ? '.editor-styles-wrapper' : '' + selector = prependCSSClass( selector, blockUniqueClassName, blockUniqueClassName, wrapSelector ) if ( hasHover ) { - hoverSelector = prependCSSClass( hoverSelector, blockUniqueClassName, blockUniqueClassName, editorMode ? '.editor-styles-wrapper' : '' ) + hoverSelector = prependCSSClass( hoverSelector, blockUniqueClassName, blockUniqueClassName, wrapSelector, generateForAllBlockStates ? '.stk-preview-state--hover' : '' ) } if ( hasParentHover ) { - parentHoverSelector = prependCSSClass( parentHoverSelector, blockUniqueClassName, blockUniqueClassName, editorMode ? '.editor-styles-wrapper' : '' ) + parentHoverSelector = prependCSSClass( parentHoverSelector, blockUniqueClassName, blockUniqueClassName, wrapSelector, generateForAllBlockStates ? '.stk-preview-state--parent-hover' : '' ) } if ( hasCollapsed ) { - collapsedSelector = prependCSSClass( collapsedSelector, blockUniqueClassName, blockUniqueClassName, editorMode ? '.editor-styles-wrapper' : '' ) + collapsedSelector = prependCSSClass( collapsedSelector, blockUniqueClassName, blockUniqueClassName, wrapSelector, generateForAllBlockStates ? '.stk-preview-state--collapsed' : '' ) } let css = '' diff --git a/src/components/block-styles-control/editor.scss b/src/components/block-styles-control/editor.scss new file mode 100644 index 0000000000..c714dd9135 --- /dev/null +++ b/src/components/block-styles-control/editor.scss @@ -0,0 +1,133 @@ +.ugb-block-styles-controls { + padding: 0 16px 8px 8px; + position: relative; + border-top: none !important; + + .ugb-block-styles-controls__wrapper { + position: relative; + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + gap: 4px; + + .ugb-block-styles-controls__block-style-button { + padding-right: 6px; + display: inline-block; + height: auto; + line-height: 1.4; + text-align: left; + place-self: flex-start; + } + + .stk-control__reset-button { + position: relative; + top: 0; + right: 0; + color: var(--stk-skin-error); + } + } + + .ugb-button-component.has-icon:hover { + box-shadow: inset 0 0 0 1px var(--stk-skin-dark); + background-color: var(--stk-skin-bg-secondary); + color: var(--stk-skin-dark); + } + + .stk-panel-modified-indicator { + display: inline-block; + margin-inline: 8px; + } +} + +.ugb-block-styles__new-style-modal { + max-width: 550px; + width: 90vw; + + .notice { + margin: 0 0 16px; + } +} +.ugb-block-styles__new-style-description { + color: #1e1e1e; + margin-top: 0; +} +.ugb-block-styles__new-style-form { + display: flex; + flex-direction: column; + gap: 16px; + + .ugb-block-styles__attributes-list { + p { + margin: 0 0 4px; + } + ul { + margin: 0; + list-style: disc; + padding-inline-start: 20px; + } + li { + margin: 0; + } + } + + .components-button { + margin-right: 0; + margin-left: auto; + } +} + +.ugb-block-styles__update-style-form { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.ugb-block-styles-controls__popover { + .components-popover__content { + width: 350px !important; + } + .components-button { + width: 100%; + position: relative; + + &.ugb-block-styles-controls__selected { + outline: 1px solid var(--stk-skin-dark) !important; + } + + &:focus:not(:disabled) { + box-shadow: 0 0 0 2px var(--stk-skin-dark); + } + + .dashicons-lock { + position: absolute; + right: 8px; + } + } + + .components-panel__body:has(.ugb-pro-control-button__wrapper:not(.ugb-pro-control-button--hidden)) > *:not(.ugb-pro-control-button__wrapper) { + height: 0 !important; + overflow: hidden !important; + min-height: 0 !important; + max-height: 0 !important; + } + + .components-panel__body-description { + margin: -12px 0 1.5em; + } + + .ugb-block-styles-controls__selected-icon { + position: absolute; + } + .ugb-block-styles-controls__label { + margin-inline-start: 24px; + } + + .stk-pulsating-circle { + margin-inline-start: 8px; + } + + .ugb-control-separator { + width: 100% !important; + margin: 0 auto !important; + } +} diff --git a/src/components/block-styles-control/index.js b/src/components/block-styles-control/index.js new file mode 100644 index 0000000000..0b5efd7558 --- /dev/null +++ b/src/components/block-styles-control/index.js @@ -0,0 +1,354 @@ +/** + * External dependencies + */ +import ProControl from '../pro-control' +import { ResetButton } from '../base-control2/reset-button' +import Button from '../button' +import { + useBlockAttributesContext, + useBlockSetAttributesContext, +} from '~stackable/hooks' +import { + getBlockStyleAttributesFilter, + getFilteredAttributes, + isBlockStyleAttributesModified, + currentUserHasCapability, +} from '~stackable/util' +import { i18n, isPro } from 'stackable' +import classnames from 'classnames' + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n' +import { + Dashicon, + Popover, + PanelBody, + Flex, + FlexItem, +} from '@wordpress/components' +import { + Fragment, + useEffect, + useMemo, useRef, useState, +} from '@wordpress/element' +import { useSelect } from '@wordpress/data' +import { getBlockType } from '@wordpress/blocks' +import { applyFilters, doAction } from '@wordpress/hooks' + +export const BlockStylesControl = props => { + const { blockName } = props + const blockType = getBlockType( blockName ) + const blockAttributesFilter = getBlockStyleAttributesFilter( blockName ) + const defaultBlockAttributes = useMemo( () => getFilteredAttributes( blockType.attributes, blockAttributesFilter ), [] ) + + const [ userCanManageOptions, setUserCanManageOptions ] = useState( false ) + const [ openProNotice, setOpenProNotice ] = useState( false ) + const [ openSaveModal, setOpenSaveModal ] = useState( false ) + const [ openPopover, setOpenPopover ] = useState( false ) + const [ focusedIndex, setFocusedIndex ] = useState( 0 ) + + const prevBlockStyleRef = useRef( null ) + const buttonRef = useRef( null ) + const blockStylesListRef = useRef( null ) + const blockStyleButtonsRef = useRef( [] ) + + const id = useSelect( select => select( 'core' ).getCurrentUser()?.id, [] ) + + const attributes = useBlockAttributesContext() + const setAttributes = useBlockSetAttributesContext() + + const { + blockStyle, + modifiedBlockStyle: isModified, + uniqueId: _uniqueId, + generatedCss: _generatedCss, + ...otherAttributes + } = attributes + + const mainClasses = classnames( [ + 'components-panel__body', + 'ugb-block-styles-controls', + ] ) + + const proControlClasses = classnames( [ + 'ugb-pro-control-button__wrapper', + ], { + 'ugb-pro-control-button--hidden': ! openProNotice, + } ) + + // Handle keyboard navigation for block style buttons + const handleKeyDown = event => { + // eslint-disable-next-line @wordpress/no-global-active-element + if ( ! blockStyleButtonsRef.current.includes( document.activeElement ) ) { + return + } + + if ( event.key === 'ArrowDown' ) { + event.preventDefault() + setFocusedIndex( prevIndex => ( prevIndex + 1 ) % blockStyleButtonsRef.current.length ) + } else if ( event.key === 'ArrowUp' ) { + event.preventDefault() + setFocusedIndex( prevIndex => ( prevIndex - 1 + blockStyleButtonsRef.current.length ) % blockStyleButtonsRef.current.length ) + } + } + + // Update focused block style + useEffect( () => { + if ( blockStyleButtonsRef.current[ focusedIndex ] ) { + blockStyleButtonsRef.current[ focusedIndex ].focus() + } + }, [ focusedIndex ] ) + + useEffect( () => { + // Reset openProNotice, focusedIndex, and blockStyleButtonsRef when the popover is closed + if ( ! openPopover ) { + setOpenProNotice( false ) + setFocusedIndex( -1 ) + blockStyleButtonsRef.current = [] + + return + } + + const list = blockStylesListRef.current + + if ( ! list ) { + return + } + + if ( ! blockStyleButtonsRef.current.length ) { + blockStyleButtonsRef.current = Array.from( list.querySelectorAll( 'button' ) ) + } + + // Focus on the selected block style button when the popover is opened. + const selected = list.querySelector( '.ugb-block-styles-controls__selected' ) + + if ( selected && blockStyleButtonsRef.current.length ) { + const index = blockStyleButtonsRef.current.indexOf( selected ) + setFocusedIndex( index ) + } + + list.addEventListener( 'keydown', handleKeyDown ) + + return () => { + if ( list ) { + list.removeEventListener( 'keydown', handleKeyDown ) + } + } + }, [ openPopover ] ) + + // Check if the user has "manage options" capabilities and can manage block styles. + useEffect( () => { + const checkCapabilities = async () => { + const capabilities = await currentUserHasCapability( 'manage_options' ) + setUserCanManageOptions( capabilities ) + } + + checkCapabilities() + }, [ id ] ) + + useEffect( () => { + if ( prevBlockStyleRef.current === null ) { + prevBlockStyleRef.current = blockStyle + return + } + + if ( prevBlockStyleRef.current !== blockStyle ) { + prevBlockStyleRef.current = blockStyle + return + } + + if ( isModified || ! blockStyle ) { + return + } + + const modified = isBlockStyleAttributesModified( blockName, blockStyle, otherAttributes ) + if ( modified ) { + setAttributes( { modifiedBlockStyle: true } ) + } + }, [ attributes ] ) + + const globalBlockStyles = useSelect( select => { + const globalBlockStyles = select( 'stackable/global-block-styles' ).getBlockStyles( blockName ) + return globalBlockStyles + }, [ isModified ] ) + + const { + inBlockStyleOptions, blockStyleLabel, blockStyleAttributes, + } = useMemo( () => { + const selectedIndex = globalBlockStyles.findIndex( item => item.slug === blockStyle ) + + if ( selectedIndex === -1 ) { + return { inBlockStyleOptions: false, blockStyleLabel: __( 'Default', i18n ) } + } + + return { + inBlockStyleOptions: true, + blockStyleLabel: globalBlockStyles[ selectedIndex ].name, + blockStyleAttributes: globalBlockStyles[ selectedIndex ].nonCssAttributes, + } + }, [ blockStyle ] ) + + const onSelectDefaultBlockStyle = () => { + setFocusedIndex( 0 ) + + // Do nothing if block style is already "Default" + if ( ! blockStyle ) { + return + } + + setAttributes( { ...defaultBlockAttributes, modifiedBlockStyle: false } ) + } + + const onSelectBlockStyle = ( option, index ) => { + setFocusedIndex( index ) + + if ( isPro ) { + doAction( 'stackable.global-settings.global-block-styles.select-block-style', + option, blockStyle, globalBlockStyles, defaultBlockAttributes, setAttributes ) + } else { + setOpenProNotice( value => ! value ) + } + } + + const onAddBlockStyle = () => { + if ( isPro ) { + doAction( 'stackable.global-settings.global-block-styles.add-block-style', setOpenSaveModal ) + } else { + setOpenProNotice( value => ! value ) + } + } + + const SaveUpdateModal = applyFilters( 'stackable.global-settings.global-block-styles.save-update-modal', Fragment ) + + return ( + <> +
+
+ + { + if ( ! blockStyle || ! inBlockStyleOptions ) { + setAttributes( defaultBlockAttributes ) + return + } + + setAttributes( { + ...defaultBlockAttributes, + ...blockStyleAttributes, + blockStyle, + } ) + } } + /> +
+
+ { openPopover && ( + setOpenPopover( false ) } + onClose={ () => setOpenPopover( false ) } + focusOnMount={ false } + placement="left-start" + resize={ false } + offset={ 8 } + > + +

{ __( 'Block Styles', i18n ) }

+

+ { __( 'Save the styles of this block to reuse on others. You can also update a saved style, and the changes will apply wherever it\'s used.', i18n ) } +   + { __( 'Learn more', i18n ) } +

+ + { userCanManageOptions && ( + + ) } +
+ +
+ +
+
+ ) } + + + ) +} + +const SaveUpdateButtons = props => { + const { onAddBlockStyle, ...propsToPass } = props + const ActionButtons = applyFilters( 'stackable.global-settings.global-block-styles.action-buttons', Fragment ) + + return ( <> + + + + + + + ) +} diff --git a/src/components/block-wrapper/index.js b/src/components/block-wrapper/index.js index 838b572921..2f2507c699 100644 --- a/src/components/block-wrapper/index.js +++ b/src/components/block-wrapper/index.js @@ -20,6 +20,7 @@ const BlockWrapper = memo( props => { const { align = undefined, className: blockClassName = '', + blockStyle = undefined, blockHoverClass = '', children, hoverRef, @@ -40,6 +41,8 @@ const BlockWrapper = memo( props => { // We force-removed the block alignment wrapper div (see src/blocks.js), // so we need to add our own data-align attribute. 'data-align': align, + // Add data-block-style attribute to replace data-block selectors + ...( blockStyle ? { 'data-block-style': blockStyle } : {} ), } ) // Remove the custom CSS names here because we will be adding it in the BlockDiv component, we need to do this for our current styles to work. diff --git a/src/components/four-range-control/index.js b/src/components/four-range-control/index.js index 92fce42749..ec5bec5dd2 100644 --- a/src/components/four-range-control/index.js +++ b/src/components/four-range-control/index.js @@ -189,7 +189,6 @@ const FourRangeControl = memo( props => { : props.enableBottom ? { desktop: _valueDesktop?.bottom, tablet: _valueTablet?.bottom } : { desktop: _valueDesktop?.left, tablet: _valueTablet?.left } - 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, @@ -232,6 +231,8 @@ const FourRangeControl = memo( props => { } ) } + const [ isFourMarkMode, setIsFourMarkMode ] = useState( isMarkValue ) + // Set the markMode when device type changes useEffect( () => { setIsFourMarkMode( isMarkValue ) diff --git a/src/components/index.js b/src/components/index.js index f2bc0b51cd..89ab886b80 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -108,7 +108,7 @@ export { default as InspectorBottomTip } from './inspector-bottom-tip' export { default as BlockWrapper } from './block-wrapper' // TODO: clean this export { - default as BlockCss, BlockCssCompiler, BlockStyleGenerator, useBlockCssGenerator, + default as BlockCss, BlockCssCompiler, BlockStyleGenerator, useBlockCssGenerator, CssSaveCompiler, } from './block-css' export { default as ColumnsWidthControl } from './columns-width-control' export { default as ColumnsWidthMultiControl } from './columns-width-multi-control' diff --git a/src/components/inspector-tabs/index.js b/src/components/inspector-tabs/index.js index 5d9f925268..74e8e7b3e5 100644 --- a/src/components/inspector-tabs/index.js +++ b/src/components/inspector-tabs/index.js @@ -2,7 +2,9 @@ * External dependencies */ import { PanelTabs, PanelAdvancedSettings } from '~stackable/components' -import { i18n } from 'stackable' +import { + i18n, isPro, showProNotice, +} from 'stackable' /** * WordPress dependencies @@ -13,6 +15,7 @@ import { InspectorControls, useBlockEditContext } from '@wordpress/block-editor' import { useGlobalState } from '~stackable/util/global-state' import { __ } from '@wordpress/i18n' import { getBlockSupport } from '@wordpress/blocks' +import { BlockStylesControl } from '../block-styles-control' const { Slot: LayoutPanelSlot, Fill: LayoutPanelFill } = createSlotFill( 'StackableLayoutPanel' ) @@ -63,13 +66,14 @@ export { } const InspectorTabs = props => { - const { name } = useBlockEditContext() + const { name, clientId } = useBlockEditContext() const defaultTab = getBlockSupport( name, 'stkDefaultTab' ) || 'style' const [ activeTab, setActiveTab ] = useGlobalState( `tabCache-${ name }`, props.tabs.includes( defaultTab ) ? defaultTab : 'style' ) return ( <> + { ( isPro || showProNotice ) && } { __( 'Use Global Typography sizes as presets', i18n ) } , }, + 'global-block-styles': { + title: __( 'Global Block Styles', i18n ), + description:
    +
  • { __( 'Create and use your own block styles', i18n ) }
  • +
  • { __( 'Update your block styles', i18n ) }
  • +
  • { __( 'Organize your custom block styles', i18n ) }
  • +
, + }, } const ProControl = props => { diff --git a/src/components/sortable-picker/index.js b/src/components/sortable-picker/index.js index 1462613b22..b52d7182f8 100644 --- a/src/components/sortable-picker/index.js +++ b/src/components/sortable-picker/index.js @@ -199,7 +199,7 @@ const LabeledItemIndicator = props => { return } - if ( ! isFocused ) { + if ( ItemPicker && ! isFocused ) { onToggle() } } } @@ -235,12 +235,12 @@ const LabeledItemIndicator = props => { setIsFocused( false ) }, 100 ) - if ( isOpen && ! ev.relatedTarget?.closest( '.components-popover' ) ) { + if ( ItemPicker && isOpen && ! ev.relatedTarget?.closest( '.components-popover' ) ) { onToggle() } } } onClick={ () => { - if ( ! isOpen ) { + if ( ItemPicker && ! isOpen ) { onToggle() } } } @@ -258,18 +258,20 @@ const LabeledItemIndicator = props => { ) } } - renderContent={ () => ( - - ) } + renderContent={ ( { onClose } ) => { + return <> { ItemPicker && } + } } /> - { sortable &&