From 224a9b02be1672cee5e3a3bd8b77cc0551219b9b Mon Sep 17 00:00:00 2001 From: Alquen Antonio Sarmiento Date: Thu, 5 Sep 2024 14:44:27 +0800 Subject: [PATCH 01/16] fix (column block): styling not working when used inside a query loop (#3298) * fix(content-align): make getContentAlignmentClasses compatible with adding instanceId * fix: add instanceId to class if inside QueryLoop * fix: rearrange getContentAlignmentClasses parameters --- src/block-components/content-align/use-content-align.js | 9 +++++++-- src/block/columns/edit.js | 5 ++++- src/block/horizontal-scroller/edit.js | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/block-components/content-align/use-content-align.js b/src/block-components/content-align/use-content-align.js index 2e435823a..2be54e053 100644 --- a/src/block-components/content-align/use-content-align.js +++ b/src/block-components/content-align/use-content-align.js @@ -4,10 +4,15 @@ import { applyFilters } from '@wordpress/hooks' import classnames from 'classnames' -export const getContentAlignmentClasses = ( attributes, blockName = 'column' ) => { +export const getContentAlignmentClasses = ( attributes, blockName = 'column', instanceId = '' ) => { + let instanceIdString = '' + if ( instanceId ) { + instanceIdString = `${ instanceId }-` + } + return classnames( 'stk-content-align', - `stk-${ attributes.uniqueId }-${ blockName }`, + `stk-${ attributes.uniqueId }-${ instanceIdString }${ blockName }`, applyFilters( 'stackable.block-components.content-align.getContentAlignmentClasses', { 'stk--flex': attributes.columnJustify, alignwide: attributes.innerBlockContentAlign === 'alignwide', // This will align the columns inside. diff --git a/src/block/columns/edit.js b/src/block/columns/edit.js index b0de7105b..bc251baad 100644 --- a/src/block/columns/edit.js +++ b/src/block/columns/edit.js @@ -41,6 +41,7 @@ import { withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' +import { useQueryLoopInstanceId } from '~stackable/util' /** * WordPress dependencies @@ -74,11 +75,13 @@ const Edit = props => { columnTooltipClass, ], props ) ) + const instanceId = useQueryLoopInstanceId( props.attributes.uniqueId ) + const contentClassNames = classnames( [ 'stk-inner-blocks', blockAlignmentClass, 'stk-block-content', - ], getContentAlignmentClasses( props.attributes ) ) + ], getContentAlignmentClasses( props.attributes, 'column', instanceId ) ) return ( <> diff --git a/src/block/horizontal-scroller/edit.js b/src/block/horizontal-scroller/edit.js index 9755b7e55..081dc0b3b 100644 --- a/src/block/horizontal-scroller/edit.js +++ b/src/block/horizontal-scroller/edit.js @@ -43,6 +43,7 @@ import { withBlockWrapperIsHovered, withQueryLoopContext, } from '~stackable/higher-order' +import { useQueryLoopInstanceId } from '~stackable/util' /** * WordPress dependencies @@ -81,11 +82,13 @@ const Edit = props => { columnTooltipClass, ] ) + const instanceId = useQueryLoopInstanceId( props.attributes.uniqueId ) + const contentClassNames = classnames( [ 'stk-inner-blocks', blockAlignmentClass, 'stk-block-content', - ], getContentAlignmentClasses( props.attributes, 'horizontal-scroller' ), { + ], getContentAlignmentClasses( props.attributes, 'horizontal-scroller', instanceId ), { 'stk--with-scrollbar': showScrollbar, } ) From 761b67f12143424a893f929453468986d8fa3d0f Mon Sep 17 00:00:00 2001 From: Mikhaela Tapia <98727316+mxkae@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:45:28 +0800 Subject: [PATCH 02/16] fix (carousel): display content correctly if column arrangement is set for tablet and mobile (#3267) --- src/block/carousel/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/block/carousel/style.scss b/src/block/carousel/style.scss index 148c76d4a..3e3b08901 100644 --- a/src/block/carousel/style.scss +++ b/src/block/carousel/style.scss @@ -22,6 +22,10 @@ &.stk--is-slide[data-slides-to-show="1"] { --gap: 0px; } + .stk-block-carousel__slider .stk-block-column { + // Reset column order of carousel inner columns in case carousel is in columns block. + order: initial; + } } .stk-block-carousel__slider { display: flex; From 9e02f69e3c8df0f0618d6871447637798b49bdb3 Mon Sep 17 00:00:00 2001 From: Mikhaela Tapia <98727316+mxkae@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:45:52 +0800 Subject: [PATCH 03/16] fix (accordion block): fix timeline block lines if inside accordion block (#3293) * remove transform in accordion content * remove transform if contains timeline block * use :has * Update src/block/accordion/frontend-accordion.js. [skip ci] --------- Co-authored-by: Benjamin Intal --- src/block/accordion/style.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/block/accordion/style.scss b/src/block/accordion/style.scss index 680901309..7d6f7c8b7 100644 --- a/src/block/accordion/style.scss +++ b/src/block/accordion/style.scss @@ -86,6 +86,13 @@ } } + // the transform property causes the background-attachment: fixed to not work as expected. + // remove it to prevent timeline block lines to be glitchy. + // see similar issue: https://www.sitepoint.com/community/t/background-attachment-fixed-not-working-as-expected/35374/4 + .stk-block-accordion__content:has(.stk-block-timeline) { + transform: initial; + } + // Accordion content shows up in the front end. &:not([open]) .stk-block-accordion__content { max-height: 0; From 99e9d3525570195746224203450fa51a6000350b Mon Sep 17 00:00:00 2001 From: Mikhaela Tapia <98727316+mxkae@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:46:51 +0800 Subject: [PATCH 04/16] fix (carousel block): hide column margin settings (#3257) * add wrapper div in frontend * Revert "add wrapper div in frontend" This reverts commit 6be73bda2ab685ab9c6982ee89e32fe0cb14a790. * remove marin in inspector controls --- src/block-components/block-div/edit.js | 1 + src/block/carousel/edit.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/block-components/block-div/edit.js b/src/block-components/block-div/edit.js index 4c1a2da73..8f7df2b5f 100644 --- a/src/block-components/block-div/edit.js +++ b/src/block-components/block-div/edit.js @@ -57,6 +57,7 @@ export const Edit = props => { visualGuide={ { highlight: 'padding', } } + { ...props.sizeControlSpacingProps } /> ) } diff --git a/src/block/carousel/edit.js b/src/block/carousel/edit.js index 72e00de15..a7fc614db 100644 --- a/src/block/carousel/edit.js +++ b/src/block/carousel/edit.js @@ -252,6 +252,9 @@ const Edit = props => { } }, [ maxSlides, activeSlide ] ) + const sizeControlSpacingProps = { + enableMargin: false, + } return ( <> <> @@ -587,7 +590,7 @@ const Edit = props => { - + From 0ae9cfe6c7cfdd2cb8d8ec31e6abc432d4fede9e Mon Sep 17 00:00:00 2001 From: Alquen Antonio Sarmiento Date: Thu, 5 Sep 2024 14:48:25 +0800 Subject: [PATCH 05/16] =?UTF-8?q?fix=20(posts):=20use=20uniqueId=20as=20st?= =?UTF-8?q?kQueryId=20to=20ensure=20uniqueness=20even=20when=E2=80=A6=20(#?= =?UTF-8?q?3289)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(posts): use uniqueId as stkQueryId to ensure uniqueness even when duplicated * fix: change attribute type of stkQueryId * fix: revert uniqueId changes, implement simple condition to ensure uniqueness --- src/block/posts/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block/posts/edit.js b/src/block/posts/edit.js index e257a9be8..6927b06f7 100644 --- a/src/block/posts/edit.js +++ b/src/block/posts/edit.js @@ -155,7 +155,7 @@ const Edit = props => { // Set a unique instance ID for the posts block. // This is used to give unique identifier to our // queries. - if ( ! stkQueryId ) { + if ( stkQueryId !== instanceId ) { setAttributes( { stkQueryId: instanceId } ) } }, [ stkQueryId, instanceId ] ) From 79852590147bd08f04637d94a71c62fc5fde3e26 Mon Sep 17 00:00:00 2001 From: Alquen Antonio Sarmiento Date: Thu, 5 Sep 2024 14:49:21 +0800 Subject: [PATCH 06/16] fix (hover transitions): added new custom property --stk-transition-default (#3295) * fix: lower specificity for hover transitions * fix: added variable --stk-transition-default to be used for overwriting the transition * chore: revert specificity changes * chore: revert deleted comment --- src/styles/block-transitions.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles/block-transitions.scss b/src/styles/block-transitions.scss index 1f0e1f8be..d5f55fafa 100644 --- a/src/styles/block-transitions.scss +++ b/src/styles/block-transitions.scss @@ -32,16 +32,16 @@ body.stk--anim-init { .stk-img-wrapper::before, // Image block hover ovelay. .stk-block li::marker, // For icon list marker .stk-block-tabs__tab { // Tabs block - transition: all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95), flex 0s, max-width 0s, visibility 0s; // Don't include flex & max-width since column widths would animate. + transition: var(--stk-transition-default, all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95), flex 0s, max-width 0s, visibility 0s); // Don't include flex & max-width since column widths would animate. border-width: 1px; border-style: none; } .stk--svg-wrapper :is(.stk--shape-icon, .stk--inner-svg, .stk--inner-svg *) { - transition: all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95); + transition: var(--stk-transition-default, all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95)); } // Icons can have a delay in transitions. It's more apparent when transitioning fill, removing it seems to fix this. .stk--svg-wrapper .stk--inner-svg svg:last-child { - transition: all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95), fill 0s; + transition: var(--stk-transition-default, all var(--stk-transition-duration, 0.12s) cubic-bezier(0.45, 0.05, 0.55, 0.95), fill 0s); } } From a8af5f40670e0851e2c6574f9e32a473773231cd Mon Sep 17 00:00:00 2001 From: Mikhaela Tapia <98727316+mxkae@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:49:49 +0800 Subject: [PATCH 07/16] Fix (icon list block): fix error on transform for saved icon list block (#3285) * disable saved styles for icon list item * fix error on transform for saved icon list block --- src/block/icon-list-item/index.js | 2 ++ src/hooks/use-saved-default-block-style.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/block/icon-list-item/index.js b/src/block/icon-list-item/index.js index ce8886c3f..496734572 100644 --- a/src/block/icon-list-item/index.js +++ b/src/block/icon-list-item/index.js @@ -20,6 +20,8 @@ export const settings = { supports: { anchor: true, __experimentalSelector: 'li', + reusable: false, + stkSaveBlockStyle: false, }, example, edit, diff --git a/src/hooks/use-saved-default-block-style.js b/src/hooks/use-saved-default-block-style.js index b7e9a614e..f6007390c 100644 --- a/src/hooks/use-saved-default-block-style.js +++ b/src/hooks/use-saved-default-block-style.js @@ -91,7 +91,9 @@ export const useSavedDefaultBlockStyle = blockProps => { } ) // Create and apply the innerBlocks. - if ( blockData.innerBlocks?.length ) { + // Do not do this for icon lists because it causes an error on transform. + // The icon list inner blocks are created by the icon list block itself. See src/blocks/icon-list/transforms.js + if ( blockData.innerBlocks?.length && name !== 'stackable/icon-list' ) { const innerBlocks = createBlocksFromInnerBlocksTemplate( blockData.innerBlocks ) // We need to add unique Ids to prevent the default styles from getting applied. recursivelyAddUniqueIdToInnerBlocks( innerBlocks ) From c1994bbfc8eb7701f9542648f116ceb40c3c2659 Mon Sep 17 00:00:00 2001 From: Alquen Antonio Sarmiento Date: Thu, 5 Sep 2024 14:50:33 +0800 Subject: [PATCH 08/16] feat: added new option to use Stackable text block as the default text block (#3283) * feat: create an editor setting for enabling default block as stackable text * feat: set default block to stackable text when the setting is enabled * fix: create dedicated plugin for setting default block * Updated option description * fix: use raw transform to prevent pasting multiline text of having core/paragraph in between * fix: make sure setting of default block only run once * chore: add comments * fix: load initial enable_text_default_block setting --------- Co-authored-by: Benjamin Intal --- src/block/text/transforms.js | 14 ++++++++++++++ src/editor-settings.php | 13 +++++++++++++ src/plugins/index.js | 4 ++++ src/plugins/text-default-block/index.js | 14 ++++++++++++++ src/welcome/admin.js | 15 +++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/plugins/text-default-block/index.js diff --git a/src/block/text/transforms.js b/src/block/text/transforms.js index e10714264..b18f9a805 100644 --- a/src/block/text/transforms.js +++ b/src/block/text/transforms.js @@ -7,9 +7,23 @@ import { createBlock, createBlocksFromInnerBlocksTemplate } from '@wordpress/blo * Internal dependencies */ import { TEMPLATE as ICON_LABEL_TEMPLATE } from '../icon-label/edit' +import { settings } from 'stackable' const transforms = { from: [ + // When pasting, ensure that the default text block setting is followed + { + type: 'raw', + isMatch: node => + node.nodeName === 'P' && + settings.stackable_enable_text_default_block, + transform: node => { + return createBlock( 'stackable/text', { + text: node.textContent.trim(), + } ) + }, + priority: 11, + }, { type: 'block', isMultiBlock: true, diff --git a/src/editor-settings.php b/src/editor-settings.php index 79d4a0db6..072499d06 100644 --- a/src/editor-settings.php +++ b/src/editor-settings.php @@ -154,6 +154,18 @@ public function register_settings() { 'default' => true, ) ); + + register_setting( + 'stackable_editor_settings', + 'stackable_enable_text_default_block', + array( + 'type' => 'boolean', + 'description' => __( 'If this is enabled, the default block when adding a new block will be the Stackable Text block.', STACKABLE_I18N ), + 'sanitize_callback' => 'sanitize_text_field', + 'show_in_rest' => true, + 'default' => false, + ) + ); } public function sanitize_array_setting( $input ) { @@ -174,6 +186,7 @@ public function add_settings( $settings ) { $settings['stackable_auto_collapse_panels'] = get_option( 'stackable_auto_collapse_panels' ); $settings['stackable_enable_block_linking'] = get_option( 'stackable_enable_block_linking' ); $settings['stackable_enable_carousel_lazy_loading'] = get_option( 'stackable_enable_carousel_lazy_loading' ); + $settings['stackable_enable_text_default_block'] = get_option( 'stackable_enable_text_default_block' ); return $settings; } diff --git a/src/plugins/index.js b/src/plugins/index.js index 3170764f7..fc5f874cd 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -14,6 +14,7 @@ import { ContentAlign } from './content-align' import { EditorDom } from './get-editor-dom' import { ClientTree } from './get-client-id-tree' import { StackableThemeFonts } from './get-theme-fonts' +import { TextDefaultBlock } from './text-default-block' /** * WordPress dependencies @@ -42,4 +43,7 @@ fetchSettings().then( response => { if ( response.stackable_enable_block_linking ) { registerPlugin( 'stackable-block-linking', { render: BlockLinking } ) } + if ( response.stackable_enable_text_default_block ) { + registerPlugin( 'stackable-text-default-block', { render: TextDefaultBlock } ) + } } ) diff --git a/src/plugins/text-default-block/index.js b/src/plugins/text-default-block/index.js new file mode 100644 index 000000000..5f655db4d --- /dev/null +++ b/src/plugins/text-default-block/index.js @@ -0,0 +1,14 @@ +import { setDefaultBlockName, getDefaultBlockName } from '@wordpress/blocks' +import { useEffect } from '@wordpress/element' + +export const TextDefaultBlock = () => { + // Set the default block to stackable/text + useEffect( () => { + if ( getDefaultBlockName() === 'stackable/text' ) { + return null + } + setDefaultBlockName( 'stackable/text' ) + }, [] ) + + return null +} diff --git a/src/welcome/admin.js b/src/welcome/admin.js index e124aaaff..42d6987e2 100644 --- a/src/welcome/admin.js +++ b/src/welcome/admin.js @@ -264,6 +264,7 @@ const EditorSettings = () => { 'stackable_auto_collapse_panels', 'stackable_enable_block_linking', 'stackable_enable_carousel_lazy_loading', + 'stackable_enable_text_default_block', ] ) ) } ) } ) @@ -413,6 +414,20 @@ const EditorSettings = () => { } } help={ __( 'Disable this if you encounter layout or spacing issues when using images inside carousel-type blocks because of image lazy loading.', i18n ) } /> + { + setIsBusy( true ) + const model = new models.Settings( { stackable_enable_text_default_block: value } ) // eslint-disable-line camelcase + model.save().then( () => setIsBusy( false ) ) + setSettings( { + ...settings, + stackable_enable_text_default_block: value, // eslint-disable-line camelcase + } ) + } } + help={ __( 'If enabled, Stackable Text blocks will be added by default instead of the native Paragraph Block.', i18n ) } + /> { isBusy &&
From 7308fa029501329ee3a849717456e8e8571cb8da Mon Sep 17 00:00:00 2001 From: Alquen Antonio Sarmiento Date: Thu, 5 Sep 2024 14:50:51 +0800 Subject: [PATCH 09/16] fix (horizontal-scroller): set draggable to false for images inside horizontal scroller (#3282) --- .../horizontal-scroller/frontend-horizontal-scroller.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/block/horizontal-scroller/frontend-horizontal-scroller.js b/src/block/horizontal-scroller/frontend-horizontal-scroller.js index c7ba14085..28dec41d3 100644 --- a/src/block/horizontal-scroller/frontend-horizontal-scroller.js +++ b/src/block/horizontal-scroller/frontend-horizontal-scroller.js @@ -17,6 +17,12 @@ class StackableHorizontalScroller { // get all links, because we will need to disable them during drag const children = el.querySelectorAll( '.stk-block-link, a' ) + // Get all images and set draggable to false + const images = el.querySelectorAll( 'img' ) + images.forEach( image => { + image.draggable = false + } ) + // prevents redirecting to the inner column link const onClickHandler = function( e ) { e.preventDefault() From da1bfb891a014b21d6428685edb23fe7745dc248 Mon Sep 17 00:00:00 2001 From: Mikhaela Tapia <98727316+mxkae@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:52:32 +0800 Subject: [PATCH 10/16] fix (carousel block): jumping slides on infinite scroll when slides to show and number of slides are equal (#3291) --- src/block/carousel/frontend-carousel.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/block/carousel/frontend-carousel.js b/src/block/carousel/frontend-carousel.js index b57fb2ad7..b83e15b5c 100644 --- a/src/block/carousel/frontend-carousel.js +++ b/src/block/carousel/frontend-carousel.js @@ -226,6 +226,10 @@ class _StackableCarousel { swapSlides = ( slide, dir ) => { let setScrollToClone = false + if ( this.slidesToShow === this.slideEls.length ) { + setScrollToClone = true + } + if ( dir === 'N' && slide > this.slideEls.length ) { slide = this.slideOffset setScrollToClone = true @@ -242,6 +246,16 @@ class _StackableCarousel { original.map( node => this.sliderEl.insertBefore( node, this.clones[ needToSwap ] ) ) clones.map( node => this.sliderEl.insertBefore( node, this.slideEls[ needToSwap ] ) ) + + // This ensures that the cloned slides are in the right position when slides to show === number of slides + if ( this.slidesToShow === this.slideEls.length && dir === 'N' ) { + const children = this.sliderEl.children + this.sliderEl.append( children[ 0 ] ) + } else if ( this.slidesToShow === this.slideEls.length && dir === 'P' ) { + const children = [ ...Array.from( this.sliderEl.children ).slice( -2 ) ].reverse() + children.map( node => this.sliderEl.insertBefore( node, this.sliderEl.children[ 0 ] ) ) + } + this.swappedSlides = needToSwap } else if ( this.swappedSlides > needToSwap ) { // unswap original and clone slides that are not needed @@ -251,6 +265,12 @@ class _StackableCarousel { original.map( node => this.sliderEl.insertBefore( node, this.slideEls[ this.swappedSlides ] ) ) clones.map( node => this.sliderEl.insertBefore( node, this.clones[ this.swappedSlides ] ) ) this.swappedSlides = _needToSwap + + // This ensures that the cloned slides are in the right position when slides to show === number of slides + if ( this.slidesToShow === this.slideEls.length ) { + const children = this.sliderEl.children + this.sliderEl.insertBefore( children[ children.length - 1 ], children[ 0 ] ) + } } if ( setScrollToClone ) { From 0288c5da33fb8a1c5df8a8979c798da37a7c37ac Mon Sep 17 00:00:00 2001 From: Benjamin Intal Date: Thu, 5 Sep 2024 14:52:52 +0800 Subject: [PATCH 11/16] fix (posts block): " --- src/block/posts/index.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/block/posts/index.php b/src/block/posts/index.php index b21e7e934..3f590d1f8 100644 --- a/src/block/posts/index.php +++ b/src/block/posts/index.php @@ -413,7 +413,11 @@ public static function get_excerpt_by_post_id( $post_id, $post = null, $max_exce $exploded_excerpt = explode( ' ', $excerpt ); $trim_to_length = (int) $max_excerpt; if ( count( $exploded_excerpt ) > $trim_to_length ) { - $excerpt = implode( ' ', array_slice( $exploded_excerpt, 0, $trim_to_length ) ) . '...'; + $excerpt = wp_trim_words( $excerpt, $trim_to_length, '' ); + // If last word does not contain '…' or '...', add it + if ( substr( $excerpt, -1 ) !== '…' && substr( $excerpt, -3 ) !== '...' && substr( $excerpt, -3 ) !== '…' ) { + $excerpt .= '...'; + } } } From 8122cccf59ebf2769c12bbff464a7b413cc9667e Mon Sep 17 00:00:00 2001 From: Benjamin Intal Date: Mon, 23 Sep 2024 14:20:52 +0800 Subject: [PATCH 12/16] Fix: Editor Performance Rework (#3290) * added generator * partial implementation in the column block * optimized AdvancedRangeControl * useMemo instead of useRafMemo * removed caching * added implementation for text block * Optimized useBlockCssGenerator for edit and save * converted alignment * finalized styles for inner column and text blocks * modified columns block style implementation * optimized string concat to array join * optimized column edit to remove useBlockContext * optimized group placeholder * changed use context * optimized some useBlockContext * since render appender is now undefined if a block has contents, then we also need to change this to last child * removed minification from save css, let's not worry about this so we can save speed * optimize css save compiler * cache previous css generated * sometimes do not use useAttributeEditHandlers * memoed the alignment toolbar * fixed number of columns * fixed useSelect where we're not getting the innerBlocks but just block order * fixed css of attributes with valuePreCallback are not generated * memo renderAppender * optimized column component * apply to heading * apply to subtitle * apply to spacer * apply to divider * optimized block hover state hook to prevent rerenders * added memo to some components * separated the inspector controls into a separated memoed component to prevent rerenders * changed component name to InspectorControls * optimize divider inspector controls * fix hover state * optimize heading and spacer inspector controls * apply to accordion and blockquote * apply to button and button group * optimize inspector controls * fix block errors for timeline, progress bar and circle * apply block changes to all blocks * fix posts and separator block * fix separator layer styles * fix separator block * fix adding button block * fix desktop column wrap in feature block * fix background responsive * fix generatedCss * delete from this.addedStyles * fix style generation for save * fix tabs block * remove render appender * revert appender * remove conditional for background * use orderedStyles * add dynamicBlockStyles in orderedStyles * small changes to avoid confusion * remove unused function * return ordered block styles if no attrNames passed * remove old styles --------- Co-authored-by: bfintal@gmail.com <> Co-authored-by: mxkae --- src/__block-container-template/edit.js | 2 +- src/block-components/advanced/index.js | 4 +- src/block-components/advanced/style.js | 637 ++++++------ src/block-components/alignment/edit.js | 10 +- src/block-components/alignment/index.js | 4 +- src/block-components/alignment/style.js | 579 ++++++----- src/block-components/block-div/edit.js | 5 +- src/block-components/block-div/index.js | 9 +- src/block-components/block-div/style.js | 38 +- src/block-components/button/edit.js | 30 +- src/block-components/button/index.js | 4 +- src/block-components/button/style.js | 422 ++++---- .../column/get-column-handlers.js | 142 +++ src/block-components/column/index.js | 32 +- src/block-components/column/style.js | 172 ++-- .../columns/column-settings-button.js | 14 +- src/block-components/columns/edit.js | 19 +- src/block-components/columns/index.js | 4 +- src/block-components/columns/style.js | 316 +++--- src/block-components/container-div/index.js | 4 +- src/block-components/container-div/style.js | 111 +- src/block-components/content-align/index.js | 2 +- .../effects-animations/index.js | 4 +- .../effects-animations/style.js | 12 +- .../helpers/backgrounds/style.js | 598 ++++++----- src/block-components/helpers/borders/style.js | 419 ++++---- .../helpers/flex-gap/style.js | 78 +- src/block-components/helpers/size/edit.js | 6 +- src/block-components/helpers/size/style.js | 529 +++++----- src/block-components/icon/index.js | 4 +- src/block-components/icon/style.js | 545 +++++----- src/block-components/image/index.js | 4 +- src/block-components/image/style.js | 951 +++++++++--------- src/block-components/margin-bottom/index.js | 53 +- src/block-components/margin-bottom/style.js | 37 +- src/block-components/progress-bar/index.js | 4 +- src/block-components/progress-bar/style.js | 434 ++++---- src/block-components/row/index.js | 19 +- src/block-components/separator/edit.js | 8 +- src/block-components/separator/index.js | 6 +- src/block-components/separator/style.js | 258 +++-- src/block-components/transform/index.js | 4 +- src/block-components/transform/style.js | 12 +- src/block-components/typography/index.js | 4 +- src/block-components/typography/style.js | 512 ++++++---- src/block/accordion/edit.js | 118 ++- src/block/accordion/save.js | 7 +- src/block/accordion/style.js | 54 +- src/block/blockquote/edit.js | 74 +- src/block/blockquote/save.js | 7 +- src/block/blockquote/style.js | 60 +- src/block/button-group/edit.js | 160 +-- src/block/button-group/save.js | 7 +- src/block/button-group/style.js | 452 ++++----- src/block/button-group/variations.js | 6 + src/block/button/edit.js | 103 +- src/block/button/save.js | 7 +- src/block/button/style.js | 99 +- src/block/call-to-action/edit.js | 74 +- src/block/call-to-action/save.js | 7 +- src/block/call-to-action/style.js | 62 +- src/block/card/edit.js | 96 +- src/block/card/save.js | 7 +- src/block/card/style.js | 109 +- src/block/carousel/edit.js | 836 +++++++-------- src/block/carousel/save.js | 7 +- src/block/carousel/style.js | 475 ++++----- src/block/column/edit.js | 178 ++-- src/block/column/save.js | 7 +- src/block/column/style.js | 260 ++--- src/block/columns/edit.js | 112 ++- src/block/columns/save.js | 7 +- src/block/columns/style.js | 83 +- src/block/count-up/edit.js | 104 +- src/block/count-up/save.js | 7 +- src/block/count-up/style.js | 53 +- src/block/countdown/divider.js | 93 +- src/block/countdown/edit.js | 348 ++++--- src/block/countdown/save.js | 3 +- src/block/countdown/style.js | 165 +-- src/block/divider/edit.js | 105 +- src/block/divider/save.js | 3 +- src/block/divider/style.js | 277 +++-- src/block/expand/edit.js | 67 +- src/block/expand/save.js | 8 +- src/block/expand/style.js | 54 +- src/block/feature-grid/edit.js | 77 +- src/block/feature-grid/save.js | 7 +- src/block/feature-grid/style.js | 66 +- src/block/feature/edit.js | 73 +- src/block/feature/save.js | 7 +- src/block/feature/style.js | 144 +-- src/block/heading/edit.js | 268 ++--- src/block/heading/save.js | 7 +- src/block/heading/style.js | 269 ++--- src/block/hero/edit.js | 71 +- src/block/hero/save.js | 7 +- src/block/hero/style.js | 61 +- src/block/horizontal-scroller/edit.js | 261 ++--- src/block/horizontal-scroller/save.js | 7 +- src/block/horizontal-scroller/style.js | 269 ++--- src/block/icon-box/edit.js | 75 +- src/block/icon-box/save.js | 7 +- src/block/icon-box/style.js | 59 +- src/block/icon-button/edit.js | 89 +- src/block/icon-button/save.js | 7 +- src/block/icon-button/style.js | 53 +- src/block/icon-label/edit.js | 99 +- src/block/icon-label/save.js | 7 +- src/block/icon-label/style.js | 110 +- src/block/icon-list-item/edit.js | 69 +- src/block/icon-list-item/save.js | 7 +- src/block/icon-list-item/style.js | 55 +- src/block/icon-list/deprecated/save.js | 2 +- src/block/icon-list/deprecated/style.js | 274 +++++ src/block/icon-list/edit.js | 527 +++++----- src/block/icon-list/save.js | 3 +- src/block/icon-list/style.js | 455 ++++----- src/block/icon/edit.js | 93 +- src/block/icon/save.js | 7 +- src/block/icon/style.js | 56 +- src/block/image-box/edit.js | 66 +- src/block/image-box/save.js | 6 +- src/block/image-box/style.js | 49 +- src/block/image/edit.js | 89 +- src/block/image/save.js | 7 +- src/block/image/style.js | 89 +- src/block/map/edit.js | 461 +++++---- src/block/map/save.js | 3 +- src/block/map/style.js | 103 +- src/block/notification/edit.js | 176 ++-- src/block/notification/save.js | 3 +- src/block/notification/style.js | 116 +-- src/block/number-box/edit.js | 133 +-- src/block/number-box/save.js | 7 +- src/block/number-box/style.js | 157 +-- src/block/posts/edit.js | 477 ++++----- src/block/posts/save.js | 3 +- src/block/posts/style.js | 670 ++++++------ src/block/price/edit.js | 56 +- src/block/price/save.js | 7 +- src/block/price/style.js | 51 +- src/block/pricing-box/edit.js | 73 +- src/block/pricing-box/save.js | 7 +- src/block/pricing-box/style.js | 57 +- src/block/progress-bar/edit.js | 84 +- src/block/progress-bar/save.js | 3 +- src/block/progress-bar/style.js | 62 +- src/block/progress-circle/edit.js | 86 +- src/block/progress-circle/save.js | 3 +- src/block/progress-circle/style.js | 64 +- src/block/separator/edit.js | 127 +-- src/block/separator/save.js | 7 +- src/block/separator/style.js | 81 +- src/block/spacer/edit.js | 89 +- src/block/spacer/save.js | 8 +- src/block/spacer/style.js | 84 +- src/block/subtitle/edit.js | 74 +- src/block/subtitle/save.js | 4 +- src/block/subtitle/style.js | 58 +- src/block/tab-content/edit.js | 58 +- src/block/tab-content/save.js | 7 +- src/block/tab-content/style.js | 63 +- src/block/tab-labels/edit.js | 728 +++++++------- src/block/tab-labels/save.js | 7 +- src/block/tab-labels/style.js | 387 +++---- src/block/table-of-contents/edit.js | 254 ++--- src/block/table-of-contents/save.js | 3 +- src/block/table-of-contents/style.js | 346 +++---- src/block/tabs/edit.js | 239 +++-- src/block/tabs/save.js | 7 +- src/block/tabs/style.js | 136 +-- src/block/team-member/edit.js | 71 +- src/block/team-member/save.js | 7 +- src/block/team-member/style.js | 59 +- src/block/testimonial/edit.js | 71 +- src/block/testimonial/save.js | 7 +- src/block/testimonial/style.js | 59 +- src/block/text/edit.js | 151 +-- src/block/text/save.js | 4 +- src/block/text/style.js | 109 +- src/block/timeline/edit.js | 267 ++--- src/block/timeline/save.js | 7 +- src/block/timeline/style.js | 361 +++---- src/block/video-popup/edit.js | 194 ++-- src/block/video-popup/save.js | 7 +- src/block/video-popup/style.js | 86 +- .../advanced-range-control/range-control.js | 40 +- .../block-css/block-style-generator-class.js | 309 ++++++ src/components/block-css/css-save-compiler.js | 38 +- src/components/block-css/index.js | 8 +- .../block-css/use-block-style-generator.js | 77 ++ .../color-palette-popup.js | 5 +- src/components/column-inserter/index.js | 4 +- .../dynamic-content-control/index.js | 101 ++ src/components/group-placeholder/index.js | 8 +- src/components/index.js | 5 +- src/components/resizable-column/index.js | 48 +- src/higher-order/with-block-wrapper/index.js | 15 +- src/hooks/use-block-hover-state.js | 61 +- src/util/attributes/index.js | 8 + 201 files changed, 11514 insertions(+), 12078 deletions(-) create mode 100644 src/block-components/column/get-column-handlers.js create mode 100644 src/block/icon-list/deprecated/style.js create mode 100644 src/components/block-css/block-style-generator-class.js create mode 100644 src/components/block-css/use-block-style-generator.js diff --git a/src/__block-container-template/edit.js b/src/__block-container-template/edit.js index d8452808e..5e62860a5 100644 --- a/src/__block-container-template/edit.js +++ b/src/__block-container-template/edit.js @@ -118,7 +118,7 @@ const Edit = props => { /> - { ! hasInnerBlocks && } + { ! hasInnerBlocks && }
{ return null @@ -10,4 +10,4 @@ Advanced.InspectorControls = Edit Advanced.addAttributes = addAttributes -Advanced.Style = Style +Advanced.addStyles = addStyles diff --git a/src/block-components/advanced/style.js b/src/block-components/advanced/style.js index 7f789c624..0e76a3525 100644 --- a/src/block-components/advanced/style.js +++ b/src/block-components/advanced/style.js @@ -1,9 +1,4 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -15,333 +10,315 @@ const Styles = props => { dependencies = [], } = props - return ( - <> - { - // If position is sticky, we need to set top: 0px or else the sticky won't show. - if ( device === 'desktop' && state === 'normal' ) { - const isSticky = getAttribute( 'position', device, 'normal', true ) === 'sticky' - const isTopBlank = ! value || ( value && value.top === '' ) - if ( isSticky && isTopBlank ) { - return 0 - } - } + blockStyleGenerator.addBlockStyles( 'positionNum', [ { + ...propsToPass, + renderIn: 'save', + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'top', + attrName: 'positionNum', + key: 'positionNum-save-top', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: ( value, getAttribute, device, state ) => { + // If position is sticky, we need to set top: 0px or else the sticky won't show. + if ( device === 'desktop' && state === 'normal' ) { + const isSticky = getAttribute( 'position', device, 'normal', true ) === 'sticky' + const isTopBlank = ! value || ( value && value.top === '' ) + if ( isSticky && isTopBlank ) { + return 0 + } + } - return value?.top - } } - dependencies={ [ - 'position', - ...dependencies, - ] } - /> - value?.right } - /> - value?.bottom } - /> - value?.left } - /> - - { /** - * For positions (top, right, bottom, left) and postiion (absolute, - * sticky) we need to apply these to the block itself so it would look - * correctly in the editor. - */ } - `[data-block="${ clientId }"]` } - hoverSelectorCallback={ ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined } - styleRule="top" - attrName="positionNum" - key="positionNum-top" - responsive="all" - hover="all" - hasUnits="px" - valuePreCallback={ ( value, getAttribute, device, state ) => { - // If position is sticky, we need to set top: 0px or else the sticky won't show. - if ( device === 'desktop' && state === 'normal' ) { - const isSticky = getAttribute( 'position', device, 'normal', true ) === 'sticky' - const isTopBlank = ! value || ( value && value.top === '' ) - if ( isSticky && isTopBlank ) { - return 0 - } - } + return value?.top + }, + dependencies: [ + 'position', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'right', + attrName: 'positionNum', + key: 'positionNum-save-right', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.right, + }, { + ...propsToPass, + renderIn: 'save', + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'bottom', + attrName: 'positionNum', + key: 'positionNum-save-bottom', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.bottom, + }, { + ...propsToPass, + renderIn: 'save', + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'left', + attrName: 'positionNum', + key: 'positionNum-save-left', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.left, + } ] ) - return value?.top - } } - dependencies={ [ - 'position', - ...dependencies, - ] } - /> - `[data-block="${ clientId }"]` } - hoverSelectorCallback={ ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined } - selector={ positionSelector } - hoverSelector={ positionSelector ? `${ positionSelector }:hover` : undefined } - styleRule="bottom" - attrName="positionNum" - key="positionNum-bottom" - responsive="all" - hover="all" - hasUnits="px" - valuePreCallback={ value => value?.bottom } - /> - `[data-block="${ clientId }"]` } - hoverSelectorCallback={ ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined } - selector={ positionSelector } - hoverSelector={ positionSelector ? `${ positionSelector }:hover` : undefined } - styleRule="left" - attrName="positionNum" - key="positionNum-left" - responsive="all" - hover="all" - hasUnits="px" - valuePreCallback={ value => value?.left } - /> - `[data-block="${ clientId }"]` } - hoverSelectorCallback={ ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined } - selector={ positionSelector } - hoverSelector={ positionSelector ? `${ positionSelector }:hover` : undefined } - styleRule="right" - attrName="positionNum" - key="positionNum-right" - responsive="all" - hover="all" - hasUnits="px" - valuePreCallback={ value => value?.right } - /> - { - if ( value && ( value.top !== '' || value.right !== '' || value.bottom !== '' || value.left !== '' ) ) { - if ( getAttribute( 'position', device ) === '' ) { - return 'relative' - } - } - return undefined - } } - dependencies={ [ - 'position', - ...dependencies, - ] } - /> - `[data-block="${ clientId }"]` } - styleRule="position" - attrName="position" - key="position" - responsive="all" - /> - - `[data-block="${ clientId }"]` } - styleRule="zIndex" - attrName="zIndex" - key="zIndex" - responsive="all" - /> - - - getAttribute( 'overflow' ) === 'visible' } - responsive="all" - /> - + blockStyleGenerator.addBlockStyles( 'position', [ { + ...propsToPass, + renderIn: 'save', + selector: '', + styleRule: 'position', + attrName: 'position', + key: 'position-save', + responsive: 'all', + } ] ) - { - // If a top, right, bottom, left hover state position was given, it will not - // animate since there is no initial value for the position (e.g. top: 0). This - // function adds a `top: 0` for the normal state of the CSS if there's a hover - // state position e.g. hover `top: 20px` given but no initial state. - } - { - if ( ( ! value || value.top === '' ) && state === 'normal' ) { - const hoverValue = getAttribute( 'positionNum', device, 'hover' ) - const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) - if ( ( hoverValue && hoverValue.top !== '' ) || ( parentHoverValue && parentHoverValue.top !== '' ) ) { - return 0 - } - } - return undefined - } } - /> - { - if ( ( ! value || value.right === '' ) && state === 'normal' ) { - const hoverValue = getAttribute( 'positionNum', device, 'hover' ) - const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) - if ( ( hoverValue && hoverValue.right !== '' ) || ( parentHoverValue && parentHoverValue.right !== '' ) ) { - return 0 - } - } - return undefined - } } - /> - { - if ( ( ! value || value.bottom === '' ) && state === 'normal' ) { - const hoverValue = getAttribute( 'positionNum', device, 'hover' ) - const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) - if ( ( hoverValue && hoverValue.bottom !== '' ) || ( parentHoverValue && parentHoverValue.bottom !== '' ) ) { - return 0 - } - } - return undefined - } } - /> - { - if ( ( ! value || value.left === '' ) && state === 'normal' ) { - const hoverValue = getAttribute( 'positionNum', device, 'hover' ) - const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) - if ( ( hoverValue && hoverValue.left !== '' ) || ( parentHoverValue && parentHoverValue.left !== '' ) ) { - return 0 - } - } - return undefined - } } - /> - - ) -} + /** + * For positions (top, right, bottom, left) and postiion (absolute, + * sticky) we need to apply these to the block itself so it would look + * correctly in the editor. + */ + blockStyleGenerator.addBlockStyles( 'positionNum', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + hoverSelectorCallback: ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined, + styleRule: 'top', + attrName: 'positionNum', + key: 'positionNum-top', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: ( value, getAttribute, device, state ) => { + // If position is sticky, we need to set top: 0px or else the sticky won't show. + if ( device === 'desktop' && state === 'normal' ) { + const isSticky = getAttribute( 'position', device, 'normal', true ) === 'sticky' + const isTopBlank = ! value || ( value && value.top === '' ) + if ( isSticky && isTopBlank ) { + return 0 + } + } -export const Style = props => { - return -} + return value?.top + }, + dependencies: [ + 'position', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + hoverSelectorCallback: ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined, + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'bottom', + attrName: 'positionNum', + key: 'positionNum-bottom', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.bottom, + }, { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + hoverSelectorCallback: ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined, + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'left', + attrName: 'positionNum', + key: 'positionNum-left', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.left, + }, { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + hoverSelectorCallback: ( getAttributes, attributes, clientId ) => positionSelector ? `.editor-styles-wrapper [data-block="${ clientId }"]:hover` : undefined, + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'right', + attrName: 'positionNum', + key: 'positionNum-right', + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.right, + }, { + ...propsToPass, + renderIn: 'edit', + selector: positionSelector, + hoverSelector: positionSelector ? `${ positionSelector }:hover` : undefined, + styleRule: 'position', + attrName: 'positionNum', + key: 'positionNum', + responsive: 'all', + hover: 'all', + valuePreCallback: ( value, getAttribute, device ) => { + if ( value && ( value.top !== '' || value.right !== '' || value.bottom !== '' || value.left !== '' ) ) { + if ( getAttribute( 'position', device ) === '' ) { + return 'relative' + } + } + return undefined + }, + dependencies: [ + 'position', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'position', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + styleRule: 'position', + attrName: 'position', + key: 'position', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'opacity', [ { + ...propsToPass, + selector: '', + styleRule: 'opacity', + attrName: 'opacity', + key: 'opacity', + responsive: 'all', + hover: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'zIndex', [ { + ...propsToPass, + // We need to implement z-index on the block itself or else it won't look correct in the editor. + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + styleRule: 'zIndex', + attrName: 'zIndex', + key: 'zIndex', + responsive: 'all', + }, { + ...propsToPass, + renderIn: 'save', + selector: '', + styleRule: 'zIndex', + attrName: 'zIndex', + key: 'zIndex-save', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'overflow', [ { + ...propsToPass, + selector: '', + styleRule: 'overflow', + attrName: 'overflow', + key: 'overflow', + responsive: 'all', + }, { + ...propsToPass, + selector: '.stk-container', + styleRule: 'overflow', + attrName: 'overflow', + key: 'overflow-container', + enabledCallback: getAttribute => getAttribute( 'overflow' ) === 'visible', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'clear', [ { + ...propsToPass, + selector: '', + styleRule: 'clear', + attrName: 'clear', + key: 'clear', + } ] ) + + // If a top, right, bottom, left hover state position was given, it will not + // animate since there is no initial value for the position (e.g. top: 0). This + // function adds a `top: 0` for the normal state of the CSS if there's a hover + // state position e.g. hover `top: 20px` given but no initial state. -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'positionNum', [ { + ...propsToPass, + selector: positionSelector, + styleRule: 'top', + attrName: 'positionNum', + key: 'positionNum-hover-top', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ( ! value || value.top === '' ) && state === 'normal' ) { + const hoverValue = getAttribute( 'positionNum', device, 'hover' ) + const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) + if ( ( hoverValue && hoverValue.top !== '' ) || ( parentHoverValue && parentHoverValue.top !== '' ) ) { + return 0 + } + } + return undefined + }, + }, { + ...propsToPass, + selector: positionSelector, + styleRule: 'right', + attrName: 'positionNum', + key: 'positionNum-hover-right', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ( ! value || value.right === '' ) && state === 'normal' ) { + const hoverValue = getAttribute( 'positionNum', device, 'hover' ) + const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) + if ( ( hoverValue && hoverValue.right !== '' ) || ( parentHoverValue && parentHoverValue.right !== '' ) ) { + return 0 + } + } + return undefined + }, + }, { + ...propsToPass, + selector: positionSelector, + styleRule: 'bottom', + attrName: 'positionNum', + key: 'positionNum-hover-bottom', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ( ! value || value.bottom === '' ) && state === 'normal' ) { + const hoverValue = getAttribute( 'positionNum', device, 'hover' ) + const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) + if ( ( hoverValue && hoverValue.bottom !== '' ) || ( parentHoverValue && parentHoverValue.bottom !== '' ) ) { + return 0 + } + } + return undefined + }, + }, { + ...propsToPass, + selector: positionSelector, + styleRule: 'left', + attrName: 'positionNum', + key: 'positionNum-hover-left', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ( ! value || value.left === '' ) && state === 'normal' ) { + const hoverValue = getAttribute( 'positionNum', device, 'hover' ) + const parentHoverValue = getAttribute( 'positionNum', device, 'parent-hover' ) + if ( ( hoverValue && hoverValue.left !== '' ) || ( parentHoverValue && parentHoverValue.left !== '' ) ) { + return 0 + } + } + return undefined + }, + } ] ) } diff --git a/src/block-components/alignment/edit.js b/src/block-components/alignment/edit.js index 648c8095d..dd02239e3 100644 --- a/src/block-components/alignment/edit.js +++ b/src/block-components/alignment/edit.js @@ -22,7 +22,7 @@ import { AlignmentToolbar, BlockControls, } from '@wordpress/block-editor' -import { Fragment } from '@wordpress/element' +import { memo } from '@wordpress/element' import { sprintf, __ } from '@wordpress/i18n' import { addFilter } from '@wordpress/hooks' import { useSelect } from '@wordpress/data' @@ -52,7 +52,7 @@ const ALIGN_OPTIONS = [ const ALIGN_OPTIONS_NO_JUSTIFY = ALIGN_OPTIONS.filter( option => option.align !== 'justify' ) -export const Edit = props => { +export const Edit = memo( props => { const { contentAlign, columnJustify, @@ -137,7 +137,7 @@ export const Edit = props => { return ( - + <> { /> } - + ) -} +} ) // Add additional classes when browser is Firefox to fix alignment const userAgent = navigator?.userAgent diff --git a/src/block-components/alignment/index.js b/src/block-components/alignment/index.js index 28b948b40..b5c242a37 100644 --- a/src/block-components/alignment/index.js +++ b/src/block-components/alignment/index.js @@ -1,6 +1,6 @@ import { addAttributes } from './attributes' import { Edit } from './edit' -import { Style } from './style' +import { addStyles } from './style' export * from './use-alignment' @@ -12,4 +12,4 @@ Alignment.InspectorControls = Edit Alignment.addAttributes = addAttributes -Alignment.Style = Style +Alignment.addStyles = addStyles diff --git a/src/block-components/alignment/style.js b/src/block-components/alignment/style.js index 4068db1d8..5efa60abf 100644 --- a/src/block-components/alignment/style.js +++ b/src/block-components/alignment/style.js @@ -1,314 +1,305 @@ -/** - * Internal dependencies - */ -import { BlockCss } from '~stackable/components' - -const AlignmentStyles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { selectorCallback = getAttribute => `.stk--block-align-${ getAttribute( 'uniqueId' ) }`, editorSelectorCallback = getAttribute => `.stk--block-align-${ getAttribute( 'uniqueId' ) }`, - columnAlignSelectorCallback = ( () => '' ), + columnAlignSelectorEditCallback = ( () => '' ), + columnAlignSelectorSaveCallback = ( () => '' ), innerBlockSelectorCallback = getAttribute => `.stk-${ getAttribute( 'uniqueId' ) }-inner-blocks > .block-editor-inner-blocks > .block-editor-block-list__layout`, editorInnerBlockSelectorCallback = getAttribute => `.stk-${ getAttribute( 'uniqueId' ) }-inner-blocks`, dependencies = [], } = props - return ( - <> - - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - { /* When blocks are vertical */ } - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) !== 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - { /* When blocks are horizontal */ } - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> + blockStyleGenerator.addBlockStyles( 'columnAlign', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: columnAlignSelectorEditCallback, + responsive: 'all', + styleRule: 'alignSelf', + attrName: 'columnAlign', + key: 'columnAlign', + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: columnAlignSelectorSaveCallback, + responsive: 'all', + styleRule: 'alignSelf', + attrName: 'columnAlign', + key: 'columnAlign', + } ] ) - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> + blockStyleGenerator.addBlockStyles( 'rowAlign', [ { + ...propsToPass, + renderIn: 'save', + selectorCallback, + styleRule: 'alignItems', + attrName: 'rowAlign', + key: 'rowAlign-save', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'edit', + selectorCallback: editorSelectorCallback, + styleRule: 'alignItems', + attrName: 'rowAlign', + key: 'rowAlign', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' } - dependencies={ [ - 'innerBlockOrientation', - ...dependencies, - ] } - /> - { - return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || - ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) - } } - dependencies={ [ - 'innerBlockOrientation', - 'innerBlockWrap', - ...dependencies, - ] } - /> - { - return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || - ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) - } } - dependencies={ [ - 'innerBlockOrientation', - 'innerBlockWrap', - ...dependencies, - ] } - /> + { /* When blocks are vertical */ } + blockStyleGenerator.addBlockStyles( 'innerBlockJustify', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'alignItems', + attrName: 'innerBlockJustify', + key: 'innerBlockJustifyVerticalEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'alignItems', + attrName: 'innerBlockJustify', + key: 'innerBlockJustifyVerticalSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) - { /* On flex wrap, we also need to set alignContent so that the wrapped elements would align correctly. Or else we will have huge gaps. */ } - getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' } - dependencies={ [ - 'innerBlockOrientation', - 'innerBlockWrap', - ...dependencies, - ] } - /> - getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' } - dependencies={ [ - 'innerBlockOrientation', - 'innerBlockWrap', - ...dependencies, - ] } - /> - - ) -} + blockStyleGenerator.addBlockStyles( 'innerBlockAlign', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'justifyContent', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignVerticalEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'justifyContent', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignVerticalSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) !== 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) -export const Style = props => { - return -} + { /* When blocks are horizontal */ } + blockStyleGenerator.addBlockStyles( 'innerBlockJustify', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'justifyContent', + attrName: 'innerBlockJustify', + key: 'innerBlockJustifyHorizontalEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'justifyContent', + attrName: 'innerBlockJustify', + key: 'innerBlockJustifyHorizontalSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'innerBlockAlign', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'alignItems', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignHorizontalEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'alignItems', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignHorizontalSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'innerBlockWrap', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'flexWrap', + attrName: 'innerBlockWrap', + key: 'innerBlockWrapEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'flexWrap', + attrName: 'innerBlockWrap', + key: 'innerBlockWrapSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'innerBlockColumnGap', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'columnGap', + attrName: 'innerBlockColumnGap', + key: 'innerBlockColumnGapEdit', + format: `%spx`, + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'columnGap', + attrName: 'innerBlockColumnGap', + key: 'innerBlockColumnGapSave', + format: `%spx`, + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal', + dependencies: [ + 'innerBlockOrientation', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'innerBlockRowGap', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'rowGap', + attrName: 'innerBlockRowGap', + key: 'innerBlockRowGapEdit', + format: `%spx`, + responsive: 'all', + enabledCallback: getAttribute => { + return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || + ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) + }, + dependencies: [ + 'innerBlockOrientation', + 'innerBlockWrap', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'rowGap', + attrName: 'innerBlockRowGap', + key: 'innerBlockRowGapSave', + format: `%spx`, + responsive: 'all', + enabledCallback: getAttribute => { + return getAttribute( 'innerBlockOrientation' ) !== 'horizontal' || + ( getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap' ) + }, + dependencies: [ + 'innerBlockOrientation', + 'innerBlockWrap', + ...dependencies, + ], + } ] ) -Style.Content = props => { - return + { /* On flex wrap, we also need to set alignContent so that the wrapped elements would align correctly. Or else we will have huge gaps. */ } + blockStyleGenerator.addBlockStyles( 'innerBlockAlign', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: innerBlockSelectorCallback, + styleRule: 'alignContent', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignWrapEdit', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap', + dependencies: [ + 'innerBlockOrientation', + 'innerBlockWrap', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selectorCallback: editorInnerBlockSelectorCallback, + styleRule: 'alignContent', + attrName: 'innerBlockAlign', + key: 'innerBlockAlignWrapSave', + responsive: 'all', + enabledCallback: getAttribute => getAttribute( 'innerBlockOrientation' ) === 'horizontal' && getAttribute( 'innerBlockWrap' ) === 'wrap', + dependencies: [ + 'innerBlockOrientation', + 'innerBlockWrap', + ...dependencies, + ], + } ] ) } diff --git a/src/block-components/block-div/edit.js b/src/block-components/block-div/edit.js index 8f7df2b5f..30f28a123 100644 --- a/src/block-components/block-div/edit.js +++ b/src/block-components/block-div/edit.js @@ -25,8 +25,9 @@ import { * WordPress dependencies */ import { __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' -export const Edit = props => { +export const Edit = memo( props => { const { hasSizeSpacing, initialOpen, @@ -88,7 +89,7 @@ export const Edit = props => { ) -} +} ) Edit.defaultProps = { hasSizeSpacing: true, diff --git a/src/block-components/block-div/index.js b/src/block-components/block-div/index.js index 15bda697f..5327af98d 100644 --- a/src/block-components/block-div/index.js +++ b/src/block-components/block-div/index.js @@ -1,7 +1,7 @@ import './deprecated' import { addAttributes } from './attributes' import { createUniqueClass, useUniqueId } from './use-unique-id' -import { Style } from './style' +import { addStyles } from './style' import { Edit } from './edit' import { firefoxHasPolyfill } from './firefox-has-polyfill' @@ -9,6 +9,7 @@ import classnames from 'classnames/dedupe' import { Div } from '~stackable/components' import { useVariationPicker } from '~stackable/hooks' import { getUniqueBlockClass, useQueryLoopInstanceId } from '~stackable/util' +import { memo } from '@wordpress/element' import { useBlockProps } from '@wordpress/block-editor' import { applyFilters } from '@wordpress/hooks' @@ -19,7 +20,7 @@ import { version as VERSION } from 'stackable' export { useUniqueId } export { deprecateBlockBackgroundColorOpacity, deprecateBlockShadowColor } from './deprecated' -export const BlockDiv = props => { +export const BlockDiv = memo( props => { const { className, applyCustomAttributes, @@ -96,7 +97,7 @@ export const BlockDiv = props => { { props.children } { firefoxHasPolyfill( clientId, attributes ) }
-} +} ) BlockDiv.defaultProps = { className: '', @@ -174,4 +175,4 @@ BlockDiv.InspectorControls = Edit BlockDiv.addAttributes = addAttributes -BlockDiv.Style = Style +BlockDiv.addStyles = addStyles diff --git a/src/block-components/block-div/style.js b/src/block-components/block-div/style.js index e0dfdac4d..bef2ba76e 100644 --- a/src/block-components/block-div/style.js +++ b/src/block-components/block-div/style.js @@ -1,30 +1,22 @@ /** * Internal dependencies */ -import { Fragment } from '@wordpress/element' -import { useBlockAttributesContext } from '~stackable/hooks' import { - BorderStyle, SizeStyle, BackgroundStyle, + addBorderStyles, addSizeStyles, addBackgroundStyles, } from '../helpers' -export const Style = props => { - const hasBackground = useBlockAttributesContext( attributes => attributes.hasBackground ) - - return ( - <> - { hasBackground && } - - - - ) -} - -Style.Content = props => { - return ( - <> - { props.attributes.hasBackground && } - - - - ) +export const addStyles = ( blockStyleGenerator, props = {} ) => { + addBackgroundStyles( blockStyleGenerator, { + ...props, + renderCondition: 'hasBackground', + attrNameTemplate: 'block%s', + } ) + addBorderStyles( blockStyleGenerator, { + ...props, + attrNameTemplate: 'block%s', + } ) + addSizeStyles( blockStyleGenerator, { + ...props, + attrNameTemplate: 'block%s', + } ) } diff --git a/src/block-components/button/edit.js b/src/block-components/button/edit.js index dacf0542f..a75fd68d6 100644 --- a/src/block-components/button/edit.js +++ b/src/block-components/button/edit.js @@ -12,11 +12,7 @@ import { AdvancedSelectControl, } from '~stackable/components' import { i18n } from 'stackable' -import { - useAttributeEditHandlers, - useBlockAttributesContext, - useBlockContext, -} from '~stackable/hooks' +import { useBlockAttributesContext } from '~stackable/hooks' /** * WordPress dependencies @@ -30,6 +26,9 @@ import { BorderControls as _BorderControls } from '../helpers/borders' import { Link as _Link } from '../link' import { Icon as _Icon } from '../icon' import { applyFilters } from '@wordpress/hooks' +import { useSelect } from '@wordpress/data' +import { useBlockEditContext } from '@wordpress/block-editor' +import { getAttributeNameFunc } from '~stackable/util' export const Icon = props => ( <_Icon.InspectorControls @@ -110,9 +109,7 @@ export const ColorsControls = props => { attrNameTemplate = 'button%s', } = props - const { - getAttrName, - } = useAttributeEditHandlers( attrNameTemplate ) + const getAttrName = getAttributeNameFunc( attrNameTemplate ) const buttonBackgroundColorType = useBlockAttributesContext( attributes => { return attributes[ getAttrName( 'backgroundColorType' ) ] @@ -181,9 +178,7 @@ const SizeControls = props => { attrNameTemplate = 'button%s', } = props - const { - getAttrName, - } = useAttributeEditHandlers( attrNameTemplate ) + const getAttrName = getAttributeNameFunc( attrNameTemplate ) return ( <> { props.hasFullWidth && ( @@ -289,7 +284,18 @@ export const Edit = props => { ...propsToPass } = props - const { parentBlock } = useBlockContext() + const { clientId } = useBlockEditContext() + const { parentBlock } = useSelect( + select => { + const { getBlockRootClientId, getBlock } = select( 'core/block-editor' ) + const rootClientId = getBlockRootClientId( clientId ) + + return { + parentBlock: getBlock( rootClientId ), + } + }, + [ clientId ] + ) const enableLink = applyFilters( 'stackable.edit.button.enable-link', true, parentBlock ) diff --git a/src/block-components/button/index.js b/src/block-components/button/index.js index 561529d61..a789c658f 100644 --- a/src/block-components/button/index.js +++ b/src/block-components/button/index.js @@ -8,7 +8,7 @@ import { useBlockAttributesContext } from '~stackable/hooks' * Internal dependencies */ import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' import { Edit } from './edit' import { Link } from '../link' import { Icon } from '../icon' @@ -81,4 +81,4 @@ Button.InspectorControls = Edit Button.addAttributes = addAttributes -Button.Style = Style +Button.addStyles = addStyles diff --git a/src/block-components/button/style.js b/src/block-components/button/style.js index aac6d8b0f..7a06f6db8 100644 --- a/src/block-components/button/style.js +++ b/src/block-components/button/style.js @@ -1,251 +1,219 @@ /** * Internal dependencies */ -import { BorderStyle } from '../helpers/borders' +import { addBorderStyles } from '../helpers/borders' import { Icon } from '../icon' -import { BlockCss } from '~stackable/components' -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { + selector = '', attrNameTemplate = 'button%s', - selector, + borderSelector = `${ selector }:before`, + borderHoverSelector = `${ selector }:hover:before`, backgroundSelector = `${ selector }:after`, hoverSelector, dependencies = [], } = props - return ( - <> - '100%' } - format="%spx" - enabledCallback={ getAttribute => getAttribute( 'fullWidth' ) } - /> - { - // This makes the full-width button occupy the available space, but make - // others wrap when it's too small. + blockStyleGenerator.addBlockStyles( 'fullWidth', [ { + ...propsToPass, + selector: [ '', '.stk-button' ], + styleRule: 'width', + attrName: 'fullWidth', + attrNameTemplate, + key: 'buttonFullWidth', + valueCallback: () => '100%', + format: '%spx', + enabledCallback: getAttribute => getAttribute( 'fullWidth' ), + } ] ) + + { + // This makes the full-width button occupy the available space, but make + // others wrap when it's too small. + } + + blockStyleGenerator.addBlockStyles( 'fullWidth', [ { + ...propsToPass, + renderIn: 'save', + selector: '', + styleRule: 'flex', + attrName: 'fullWidth', + attrNameTemplate, + key: 'buttonFullWidth-save', + valueCallback: () => '1 0 var(--stk-button-group-flex-wrap, 0)', + enabledCallback: getAttribute => getAttribute( 'fullWidth' ), + } ] ) + + blockStyleGenerator.addBlockStyles( 'fullWidth', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + styleRule: 'flex', + attrName: 'fullWidth', + attrNameTemplate, + key: 'buttonFullWidth-flex', + valueCallback: () => '1 0 var(--stk-button-group-flex-wrap, 0)', + enabledCallback: getAttribute => getAttribute( 'fullWidth' ), + } ] ) + + blockStyleGenerator.addBlockStyles( 'minHeight', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'minHeight', + attrName: 'minHeight', + attrNameTemplate, + key: 'buttonMinHeight', + format: '%spx', + } ] ) + + blockStyleGenerator.addBlockStyles( 'width', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'width', + attrName: 'width', + attrNameTemplate, + key: 'buttonWidth', + format: '%spx', + enabledCallback: getAttribute => ! getAttribute( 'fullWidth' ), + dependencies: [ + 'fullWidth', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'padding', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'paddingTop', + attrName: 'padding', + attrNameTemplate, + key: 'buttonPadding-top', + hasUnits: 'px', + valuePreCallback: value => value?.top, + } ] ) + + blockStyleGenerator.addBlockStyles( 'padding', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'paddingRight', + attrName: 'padding', + attrNameTemplate, + key: 'buttonPadding-right', + hasUnits: 'px', + valuePreCallback: value => value?.right, + } ] ) + + blockStyleGenerator.addBlockStyles( 'padding', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'paddingBottom', + attrName: 'padding', + attrNameTemplate, + key: 'buttonPadding-bottom', + hasUnits: 'px', + valuePreCallback: value => value?.bottom, + + } ] ) + + blockStyleGenerator.addBlockStyles( 'padding', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: 'paddingLeft', + attrName: 'padding', + attrNameTemplate, + key: 'buttonPadding-left', + hasUnits: 'px', + valuePreCallback: value => value?.left, + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector, + styleRule: 'background', + attrName: 'backgroundColor', + attrNameTemplate, + key: 'buttonBackgroundColor', + dependencies: [ + 'backgroundColorType', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector: backgroundSelector || `${ selector }:after`, + styleRule: 'background', + attrName: 'backgroundColor', + attrNameTemplate, + key: 'buttonBackgroundColor-after', + hover: 'all', + hoverSelector: hoverSelector ? hoverSelector : `${ selector }:hover:after`, + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( state === 'normal' ) { + return undefined } - '1 0 var(--stk-button-group-flex-wrap, 0)' } - enabledCallback={ getAttribute => getAttribute( 'fullWidth' ) } - /> - `[data-block="${ clientId }"]` } - styleRule="flex" - attrName="fullWidth" - attrNameTemplate={ attrNameTemplate } - key="buttonFullWidth-flex" - valueCallback={ () => '1 0 var(--stk-button-group-flex-wrap, 0)' } - enabledCallback={ getAttribute => getAttribute( 'fullWidth' ) } - /> - - ! getAttribute( 'fullWidth' ) } - dependencies={ [ - 'fullWidth', - ...dependencies, - ] } - /> - value?.top } - /> - value?.right } - /> - value?.bottom } - /> - value?.left } - /> - - { - if ( state === 'normal' ) { - return undefined - } - return value - } } - dependencies={ [ - 'backgroundColorType', - ...dependencies, - ] } - /> - { - if ( state === 'normal' ) { - return undefined - } - - const buttonBackgroundColor = getAttribute( 'backgroundColor', 'desktop', state ) - - if ( - typeof buttonBackgroundColor !== 'undefined' && - buttonBackgroundColor !== '' - ) { - return 1 - } - - return undefined - } } - /> - - ) -} + return value + }, + dependencies: [ + 'backgroundColorType', + ...dependencies, + ], + } ] ) -export const Style = props => { - const { - selector = '', - attrNameTemplate = 'button%s', - borderSelector = `${ selector }:before`, - borderHoverSelector = `${ selector }:hover:before`, - } = props + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector: backgroundSelector || `${ selector }:after`, + styleRule: 'opacity', + attrName: 'backgroundColor', + attrNameTemplate, + key: 'buttonBackgroundColor-opacity', + hover: 'all', + hoverSelector: hoverSelector ? hoverSelector : `${ selector }:hover:after`, + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( state === 'normal' ) { + return undefined + } - return ( - <> - - - - - ) -} + const buttonBackgroundColor = getAttribute( 'backgroundColor', 'desktop', state ) -Style.Content = props => { - const { - selector = '', - attrNameTemplate = 'button%s', - borderSelector = `${ selector }:before`, - borderHoverSelector = `${ selector }:hover:before`, - } = props + if ( + typeof buttonBackgroundColor !== 'undefined' && + buttonBackgroundColor !== '' + ) { + return 1 + } + + return undefined + }, + } ] ) - return ( - <> - - - - - ) + addBorderStyles( blockStyleGenerator, { + ...propsToPass, + selector: borderSelector, + // Adding border radius clips button's shadow. + // This prevents this from happening. + // @see src/block-components/borders/style.js, + addBorderRadiusOverflow: false, + hoverSelector: borderHoverSelector, + borderRadiusSelector: selector, + attrNameTemplate, + } ) + + Icon.addStyles( blockStyleGenerator, { + ...propsToPass, + } ) } + diff --git a/src/block-components/column/get-column-handlers.js b/src/block-components/column/get-column-handlers.js new file mode 100644 index 000000000..90e36efc9 --- /dev/null +++ b/src/block-components/column/get-column-handlers.js @@ -0,0 +1,142 @@ +/** + * WordPress Dependencies + */ +import { dispatch } from '@wordpress/data' +import classnames from 'classnames' +import { getRowsFromColumns } from './util' + +export const getColumnHandlers = ( clientId, parentBlock ) => { + // console.log( 'testing' ) + const onChangeDesktop = widths => { + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + // Update multiple blocks. + const [ clientIds, attributes ] = widths.reduce( ( results, width, i ) => { + const clientId = adjacentBlocks[ i ].clientId + results[ 0 ].push( clientId ), + results[ 1 ][ clientId ] = { + columnWidth: width, + columnAdjacentCount: widths.length, + columnWrapDesktop: false, + } + return results + }, [ [], {} ] ) + + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, attributes, true ) // eslint-disable-line stackable/no-update-block-attributes + } + } + + const onChangeDesktopWrap = ( width, widths ) => { + const clientIds = [ clientId ] + const attributes = { + [ clientId ]: { columnWidth: width }, + } + + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + const columnRows = getRowsFromColumns( widths ) + + // Update multiple blocks. + widths.forEach( ( width, i ) => { + const clientId = adjacentBlocks[ i ].clientId + clientIds.push( clientId ) + attributes[ clientId ] = { + columnWidth: width, + columnAdjacentCount: columnRows.filter( n => n === columnRows[ i ] ).length, + columnWrapDesktop: true, + } + } ) + } + + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, attributes, true ) // eslint-disable-line stackable/no-update-block-attributes + } + + const onChangeTablet = ( width, widths ) => { + const clientIds = [ clientId ] + const attributes = { + [ clientId ]: { columnWidthTablet: width }, + } + + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + const columnRows = getRowsFromColumns( widths ) + + // Update multiple blocks. + widths.forEach( ( width, i ) => { + const clientId = adjacentBlocks[ i ].clientId + clientIds.push( clientId ) + attributes[ clientId ] = { + columnWidthTablet: width, + columnAdjacentCountTablet: columnRows.filter( n => n === columnRows[ i ] ).length, + } + } ) + } + + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, attributes, true ) // eslint-disable-line stackable/no-update-block-attributes + } + + const onChangeMobile = ( width, widths ) => { + const clientIds = [ clientId ] + const attributes = { + [ clientId ]: { columnWidthMobile: width }, + } + + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + const columnRows = getRowsFromColumns( widths ) + + // Update multiple blocks. + widths.forEach( ( width, i ) => { + const clientId = adjacentBlocks[ i ].clientId + clientIds.push( clientId ) + attributes[ clientId ] = { + columnWidthMobile: width, + columnAdjacentCountMobile: columnRows.filter( n => n === columnRows[ i ] ).length, + } + } ) + } + + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, attributes, true ) // eslint-disable-line stackable/no-update-block-attributes + } + + const onResetDesktop = () => { + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + const clientIds = adjacentBlocks.map( block => block.clientId ) + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, { columnWidth: '' } ) // eslint-disable-line stackable/no-update-block-attributes + } + } + + const onResetTabletMobile = () => { + const adjacentBlocks = parentBlock?.innerBlocks || [] + + if ( adjacentBlocks.length ) { + const clientIds = adjacentBlocks.map( block => block.clientId ) + dispatch( 'core/block-editor' ).updateBlockAttributes( clientIds, { columnWidthTablet: '', columnWidthMobile: '' } ) // eslint-disable-line stackable/no-update-block-attributes + } + } + + return { + onChangeDesktop, + onChangeDesktopWrap, + onChangeTablet, + onChangeMobile, + onResetDesktop, + onResetTabletMobile, + } +} + +export const getColumnClasses = () => { + const columnClasses = classnames( [ + 'stk-column', + ] ) + return [ + columnClasses, + 'stk-column-wrapper', + ] +} diff --git a/src/block-components/column/index.js b/src/block-components/column/index.js index 6e1423693..99b851909 100644 --- a/src/block-components/column/index.js +++ b/src/block-components/column/index.js @@ -1,37 +1,31 @@ import { addAttributes } from './attributes' -import { Style } from './style' -import { useColumn } from './use-column' +import { getColumnHandlers } from './get-column-handlers' +import { addStyles } from './style' +export { getColumnClasses } from './use-column' import { ResizableColumn } from '~stackable/components' -import { useBlockAttributesContext } from '~stackable/hooks' - -export { getColumnClasses } from './use-column' +import { memo } from '@wordpress/element' -export const Column = props => { +export const Column = memo( props => { const { isHovered, + clientId, + parentBlock, ...propsToPass } = props - const setHandlers = useColumn() - const attributes = useBlockAttributesContext( attributes => { - return { - columnWidth: attributes.columnWidth, - columnWidthTablet: attributes.columnWidthTablet, - columnWidthMobile: attributes.columnWidthMobile, - } - } ) + const setHandlers = getColumnHandlers( clientId, parentBlock ) return -} +} ) Column.defaultProps = { isHovered: true, @@ -41,4 +35,4 @@ Column.InspectorControls = null Column.addAttributes = addAttributes -Column.Style = Style +Column.addStyles = addStyles diff --git a/src/block-components/column/style.js b/src/block-components/column/style.js index 0d240cd5d..073727ca4 100644 --- a/src/block-components/column/style.js +++ b/src/block-components/column/style.js @@ -2,110 +2,100 @@ * External dependencies */ import { __getValue } from '~stackable/util' -import { BlockCss } from '~stackable/components' -const ColumnStyles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { selector = '', dependencies = [], } = props - return ( - <> - `[data-block="${ clientId }"]` } - styleRule="flex" - attrName="columnWidth" - key="columnWidth-flex" - responsive={ [ 'desktopTablet', 'tabletOnly', 'mobile' ] } - format="1 1 %s%" - dependencies={ [ - 'columnAdjacentCount', - ...dependencies, - ] } - valueCallback={ ( value, getAttribute, device ) => { - if ( device === 'desktop' ) { - return value - } - const adjacentCount = getAttribute( 'columnAdjacentCount', device ) - if ( adjacentCount ) { - return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) - } - return value - } } - /> - `[data-block="${ clientId }"]` } - styleRule="maxWidth" - attrName="columnWidth" - key="columnWidth-maxwidth" - responsive={ [ 'desktopTablet', 'tabletOnly', 'mobile' ] } - format="%s%" - dependencies={ [ - 'columnAdjacentCount', - ...dependencies, - ] } - valueCallback={ ( value, getAttribute, device ) => { - const adjacentCount = getAttribute( 'columnAdjacentCount', device ) - if ( adjacentCount ) { - return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) - } - return value - } } - /> - { - // Flex grow should be turned on in desktop, so negative margins - // can make the columns expand. (e.g. 50% 50% then -200px margin - // left on 2nd column). - // - // In tablet/mobile, don't allow expanding since columns would - // always expand to the available space (so you can't do a 30% - // 30% columns in tablet/mobile, they will expand to 50% 50%) - // - // No need to do this in the editor since it already does this. - const value = device === 'desktop' && ! getAttribute( 'columnWrapDesktop' ) ? _value : _value.replace( /^var(--stk-flex-grow, 1) 1/, '0 1' ) + blockStyleGenerator.addBlockStyles( 'columnWidth', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + styleRule: 'flex', + attrName: 'columnWidth', + key: 'columnWidth-flex', + responsive: [ 'desktopTablet', 'tabletOnly', 'mobile' ], + format: '1 1 %s%', + dependencies: [ + 'columnAdjacentCount', + ...dependencies, + ], + valueCallback: ( value, getAttribute, device ) => { + if ( device === 'desktop' ) { + return value + } + const adjacentCount = getAttribute( 'columnAdjacentCount', device ) + if ( adjacentCount ) { + return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) + } + return value + }, + } ] ) - const adjacentCount = getAttribute( 'columnAdjacentCount', device ) - if ( adjacentCount ) { - return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) - } - return value - } } - /> - - ) -} + // We need to add a maxWidth in the editor since the re-resizable box + // can mess up the snapping if the column width is too small, then + // resizes to a larger size. + blockStyleGenerator.addBlockStyles( 'columnWidth', [ { + ...propsToPass, + renderIn: 'edit', + selectorCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, + styleRule: 'maxWidth', + attrName: 'columnWidth', + key: 'columnWidth-maxwidth', + responsive: [ 'desktopTablet', 'tabletOnly', 'mobile' ], + format: '%s%', + dependencies: [ + 'columnAdjacentCount', + ...dependencies, + ], + valueCallback: ( value, getAttribute, device ) => { + const adjacentCount = getAttribute( 'columnAdjacentCount', device ) + if ( adjacentCount ) { + return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) + } + return value + }, + } ] ) -export const Style = props => { - return -} + blockStyleGenerator.addBlockStyles( 'columnWidth', [ { + ...propsToPass, + renderIn: 'save', + selector, + styleRule: 'flex', + attrName: 'columnWidth', + key: 'columnWidth-save-flex', + responsive: [ 'desktopTablet', 'tabletOnly', 'mobile' ], + format: 'var(--stk-flex-grow, 1) 1 %s%', + dependencies: [ + 'columnAdjacentCount', + ...dependencies, + ], + valueCallback: ( _value, getAttribute, device ) => { + // Flex grow should be turned on in desktop, so negative margins + // can make the columns expand. (e.g. 50% 50% then -200px margin + // left on 2nd column). + // + // In tablet/mobile, don't allow expanding since columns would + // always expand to the available space (so you can't do a 30% + // 30% columns in tablet/mobile, they will expand to 50% 50%) + // + // No need to do this in the editor since it already does this. + const value = device === 'desktop' && ! getAttribute( 'columnWrapDesktop' ) ? _value : _value.replace( /^var(--stk-flex-grow, 1) 1/, '0 1' ) -Style.Content = props => { - return + const adjacentCount = getAttribute( 'columnAdjacentCount', device ) + if ( adjacentCount ) { + return value.replace( /([\d\.]+%)$/, `calc($1 - var(--stk-column-gap, 0px) * ${ adjacentCount - 1 } / ${ adjacentCount } )` ) + } + return value + }, + } ] ) } diff --git a/src/block-components/columns/column-settings-button.js b/src/block-components/columns/column-settings-button.js index c6209c6a6..1e083c0a8 100644 --- a/src/block-components/columns/column-settings-button.js +++ b/src/block-components/columns/column-settings-button.js @@ -1,6 +1,5 @@ import { i18n } from 'stackable' import { last, pick } from 'lodash' -import { useBlockContext } from '~stackable/hooks' import { AdvancedRangeControl, Tooltip } from '~stackable/components' import { __ } from '@wordpress/i18n' @@ -26,7 +25,18 @@ export const ColumnsControl = props => { const clientId = rootClientId || _clientId const { numInnerBlocks, innerBlocks, - } = useBlockContext( rootClientId ) + } = useSelect( + select => { + const { getBlock } = select( 'core/block-editor' ) + const { innerBlocks } = getBlock( clientId ) + return { + innerBlocks, + numInnerBlocks: innerBlocks.length, + } + }, + [ clientId ] + ) + const { multiClientIds, multiNumInnerBlocks, multiInnerBlocks, hasMultiSelectedBlocks, } = useSelect( select => { diff --git a/src/block-components/columns/edit.js b/src/block-components/columns/edit.js index 134fe138f..bab92e1ae 100644 --- a/src/block-components/columns/edit.js +++ b/src/block-components/columns/edit.js @@ -19,7 +19,9 @@ import { } from '~stackable/components' import { getAttributeName } from '~stackable/util' import { - useBlockAttributesContext, useBlockContext, useBlockSetAttributesContext, useDeviceType, + useBlockAttributesContext, + useBlockSetAttributesContext, + useDeviceType, } from '~stackable/hooks' import { range } from 'lodash' @@ -37,7 +39,20 @@ export const Controls = props => { const [ , setColumnsUpdate ] = useState( 0 ) const deviceType = useDeviceType() const { clientId } = useBlockEditContext() - const { numInnerBlocks, innerBlocks } = useBlockContext() + const { + numInnerBlocks, innerBlocks, + } = useSelect( + select => { + const { getBlock } = select( 'core/block-editor' ) + const innerBlocks = getBlock( clientId )?.innerBlocks + + return { + innerBlocks, + numInnerBlocks: innerBlocks.length, + } + }, + [ clientId ] + ) const { multiClientIds, multiInnerBlocks, hasMultiSelectedBlocks, diff --git a/src/block-components/columns/index.js b/src/block-components/columns/index.js index 89c0b74b0..53398ebe9 100644 --- a/src/block-components/columns/index.js +++ b/src/block-components/columns/index.js @@ -1,6 +1,6 @@ import { addAttributes } from './attributes' import { Edit } from './edit' -import { Style } from './style' +import { addStyles } from './style' export const Columns = () => { return null @@ -8,6 +8,6 @@ export const Columns = () => { Columns.InspectorControls = Edit -Columns.Style = Style +Columns.addStyles = addStyles Columns.addAttributes = addAttributes diff --git a/src/block-components/columns/style.js b/src/block-components/columns/style.js index 5d855194a..8e2c614d5 100644 --- a/src/block-components/columns/style.js +++ b/src/block-components/columns/style.js @@ -3,18 +3,7 @@ */ import { range } from 'lodash' -/** - * Internal dependencies - */ -import { BlockCss } from '~stackable/components' -import { useBlockAttributesContext } from '~stackable/hooks' - -/** - * WordPress dependencies - */ -import { Fragment } from '@wordpress/element' - -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -24,175 +13,146 @@ const Styles = props => { const { hasRowGap = true, columnWrapDesktopSaveStyleRule = '', - numColumns, } = props - return ( - <> - - - - value ? 'wrap' : undefined } - /> - value ? 'wrap' : undefined } - /> - { /* - * Desktop columns stretch to the whole width because of flex-grow, - * we need to force it to not grow or else we cannot specify a - * column that's 50% (and alone without any column beside it) - * because it will always stretch to 100%. */ - } - value ? '0' : undefined } - /> - { hasRowGap && <> - - - } - - + blockStyleGenerator.addBlockStyles( 'columnSpacing', [ { + ...propsToPass, + selector: '.%s-column', + styleRule: '--stk-columns-spacing', + attrName: 'columnSpacing', + hasUnits: 'px', + responsive: 'all', + } ] ) - { range( 1, numColumns + 1 ).map( i => { - return ( - - .stk-block-content > .block-editor-inner-blocks > .block-editor-block-list__layout > :nth-child(${ i })` } - styleRule="order" - responsive="all" - attrName="columnArrangement" - key="columnArrangement" - valueCallback={ value => { - // Look for the order in the values list for the column i - return ( value.split( ',' ) || [] ).indexOf( i.toString() ) + 1 - } } - valuePreCallback={ ( value, getAttribute, device ) => { - const tabletAttribute = getAttribute( 'columnArrangement', 'tablet' ) - if ( device === 'mobile' && ! value && tabletAttribute ) { - return [ ...Array( numColumns ).keys() ].map( i => i + 1 ).join( ',' ) - } - return value - } } - /> - " in the saved CSS or else non-admin users in multisite - // will encounter block errors (this is a WP issue) - renderIn="save" - styleRule={ `--stk-col-order-${ i }` } - responsive="all" - attrName="columnArrangement" - key="columnArrangement-save" - valueCallback={ value => { - // Look for the order in the values list for the column i - return ( value.split( ',' ) || [] ).indexOf( i.toString() ) + 1 - } } - valuePreCallback={ ( value, getAttribute, device ) => { - const tabletAttribute = getAttribute( 'columnArrangement', 'tablet' ) - if ( device === 'mobile' && ! value && tabletAttribute ) { - return [ ...Array( numColumns ).keys() ].map( i => i + 1 ).join( ',' ) - } - return value - } } - /> - - ) - } ) } - - ) -} + blockStyleGenerator.addBlockStyles( 'columnGap', [ { + ...propsToPass, + renderIn: 'save', + selector: '.%s-column', + styleRule: '--stk-column-gap', + attrName: 'columnGap', + format: '%spx', + responsive: 'all', + }, { + ...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', + } ] ) -export const Style = props => { - const columnArrangement = useBlockAttributesContext( attributes => attributes.columnArrangementMobile || attributes.columnArrangementTablet ) - const numColumns = ( columnArrangement || '' ).split( ',' ).length - return -} + blockStyleGenerator.addBlockStyles( 'columnWrapDesktop', [ { + ...propsToPass, + renderIn: 'save', + selector: '.%s-column', + styleRule: columnWrapDesktopSaveStyleRule || 'flexWrap', + attrName: 'columnWrapDesktop', + valueCallback: value => value ? 'wrap' : undefined, + }, { + ...propsToPass, + renderIn: 'edit', + selector: '.%s-column > .block-editor-inner-blocks > .block-editor-block-list__layout', + styleRule: 'flexWrap', + attrName: 'columnWrapDesktop', + valueCallback: value => value ? 'wrap' : undefined, + } ] ) + + // Desktop columns stretch to the whole width because of flex-grow, we need + // to force it to not grow or else we cannot specify a column that's 50% + // (and alone without any column beside it) because it will always stretch + // to 100%. + blockStyleGenerator.addBlockStyles( 'columnWrapDesktop', [ { + ...propsToPass, + renderIn: 'save', + selector: '.%s-column', + styleRule: '--stk-flex-grow', + attrName: 'columnWrapDesktop', + valueCallback: value => value ? '0' : undefined, + } ] ) + + if ( hasRowGap ) { + blockStyleGenerator.addBlockStyles( 'rowGap', [ { + ...propsToPass, + renderIn: 'save', + selector: '.%s-column', + styleRule: 'rowGap', + attrName: 'rowGap', + format: '%spx', + responsive: 'all', + }, { + ...propsToPass, + renderIn: 'edit', + selector: '.%s-column > .block-editor-inner-blocks > .block-editor-block-list__layout', + styleRule: 'rowGap', + attrName: 'rowGap', + format: '%spx', + responsive: 'all', + } ] ) + } + + blockStyleGenerator.addBlockStyles( 'columnJustify', [ { + ...propsToPass, + renderIn: 'save', + selector: '.%s-column', + styleRule: 'justifyContent', + attrName: 'columnJustify', + responsive: 'all', + }, { + ...propsToPass, + renderIn: 'edit', + selector: '.%s-column > .block-editor-inner-blocks > .block-editor-block-list__layout', + styleRule: 'justifyContent', + attrName: 'columnJustify', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyleConditionally( ( attributes, addBlockCssFunc ) => { + const numColumns = ( attributes.columnArrangementMobile || attributes.columnArrangementTablet || '' ).split( ',' ).length + + range( 1, numColumns + 1 ).forEach( i => { + addBlockCssFunc( { + ...propsToPass, + // In the editor, target the specific column to change the order. + renderIn: 'edit', + selector: `> .stk-block-content > .block-editor-inner-blocks > .block-editor-block-list__layout > :nth-child(${ i })`, + styleRule: 'order', + responsive: 'all', + attrName: 'columnArrangement', + valueCallback: value => { + // Look for the order in the values list for the column i + return ( value.split( ',' ) || [] ).indexOf( i.toString() ) + 1 + }, + valuePreCallback: ( value, getAttribute, device ) => { + const tabletAttribute = getAttribute( 'columnArrangement', 'tablet' ) + if ( device === 'mobile' && ! value && tabletAttribute ) { + return [ ...Array( numColumns ).keys() ].map( i => i + 1 ).join( ',' ) + } + return value + }, + } ) -Style.Content = props => { - const numColumns = ( props.attributes.columnArrangementMobile || props.attributes.columnArrangementTablet || '' ).split( ',' ).length - return + addBlockCssFunc( { + // In the frontend, use the css custom property to specify the order. + // See style.scss We do this because we cannot use the direct descendent + // selector ">" in the saved CSS or else non-admin users in multisite + // will encounter block errors (this is a WP issue) + renderIn: 'save', + styleRule: `--stk-col-order-${ i }`, + responsive: 'all', + attrName: 'columnArrangement', + valueCallback: value => { + // Look for the order in the values list for the column i + return ( value.split( ',' ) || [] ).indexOf( i.toString() ) + 1 + }, + valuePreCallback: ( value, getAttribute, device ) => { + const tabletAttribute = getAttribute( 'columnArrangement', 'tablet' ) + if ( device === 'mobile' && ! value && tabletAttribute ) { + return [ ...Array( numColumns ).keys() ].map( i => i + 1 ).join( ',' ) + } + return value + }, + } ) + } ) + } ) } diff --git a/src/block-components/container-div/index.js b/src/block-components/container-div/index.js index 89fdb5e93..140f6d274 100644 --- a/src/block-components/container-div/index.js +++ b/src/block-components/container-div/index.js @@ -1,5 +1,5 @@ import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' import { Edit } from './edit' import classnames from 'classnames' @@ -93,4 +93,4 @@ ContainerDiv.InspectorControls = Edit ContainerDiv.addAttributes = addAttributes -ContainerDiv.Style = Style +ContainerDiv.addStyles = addStyles diff --git a/src/block-components/container-div/style.js b/src/block-components/container-div/style.js index 7a75965fe..4281bc0a5 100644 --- a/src/block-components/container-div/style.js +++ b/src/block-components/container-div/style.js @@ -2,11 +2,10 @@ * Internal dependencies */ import { - BorderStyle, SizeStyle, BackgroundStyle, + addBorderStyles, addSizeStyles, addBackgroundStyles, } from '../helpers' -import { useBlockAttributesContext } from '~stackable/hooks' -export const Style = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const { backgroundSelector = '.%s-container', borderSelector = '.%s-container', @@ -18,86 +17,28 @@ export const Style = props => { // sizeVerticalAlignSelectorEdit = '', } = props - const hasContainer = useBlockAttributesContext( attributes => attributes.hasContainer ) - - return ( - <> - { hasContainer && - - } - { hasContainer && - - } - - - ) -} - -Style.defaultProps = { - options: {}, + addBackgroundStyles( blockStyleGenerator, { + ...props, + renderCondition: 'hasContainer', + attrNameTemplate: 'container%s', + selector: backgroundSelector, + } ) + addBorderStyles( blockStyleGenerator, { + ...props, + renderCondition: 'hasContainer', + attrNameTemplate: 'container%s', + selector: borderSelector, + hoverSelector: `${ borderSelector }:hover`, + } ) + addSizeStyles( blockStyleGenerator, { + ...props, + attrNameTemplate: 'container%s', + selector: sizeSelector, + verticalAlignRule: sizeVerticalAlignRule, + verticalAlignSelector: sizeVerticalAlignSelector, + // verticalAlignSelectorEdit: sizeVerticalAlignSelectorEdit, + horizontalAlignRule: sizeHorizontalAlignRule, + wrapperSelector, + // hasPaddings: hasContainer, + } ) } - -Style.Content = props => { - const { - backgroundSelector = '.%s-container', - borderSelector = '.%s-container', - sizeSelector = '.%s-container', - sizeVerticalAlignRule = null, - sizeHorizontalAlignRule = 'margin', - wrapperSelector = '', - sizeVerticalAlignSelector = '', - // sizeVerticalAlignSelectorEdit = '', - attributes, - } = props - - return ( - <> - { attributes.hasContainer && - - } - { attributes.hasContainer && - - } - - - ) -} - diff --git a/src/block-components/content-align/index.js b/src/block-components/content-align/index.js index 059e707c6..966fbb9c7 100644 --- a/src/block-components/content-align/index.js +++ b/src/block-components/content-align/index.js @@ -10,7 +10,7 @@ export { getContentAlignmentClasses } from './use-content-align' ContentAlign.InspectorControls = Edit -ContentAlign.Style = null +ContentAlign.addStyles = () => {} ContentAlign.addAttributes = addAttributes diff --git a/src/block-components/effects-animations/index.js b/src/block-components/effects-animations/index.js index e083605f5..d8c94ed3b 100644 --- a/src/block-components/effects-animations/index.js +++ b/src/block-components/effects-animations/index.js @@ -1,6 +1,6 @@ import { addAttributes } from './attributes' import { Edit } from './edit' -import { Style } from './style' +import { addStyles } from './style' import { applyFilters } from '@wordpress/hooks' @@ -24,4 +24,4 @@ EffectsAnimations.InspectorControls = Edit EffectsAnimations.addAttributes = addAttributes -EffectsAnimations.Style = Style +EffectsAnimations.addStyles = addStyles diff --git a/src/block-components/effects-animations/style.js b/src/block-components/effects-animations/style.js index 6cba3bbf1..091ef95dc 100644 --- a/src/block-components/effects-animations/style.js +++ b/src/block-components/effects-animations/style.js @@ -1,14 +1,8 @@ /** * WordPress dependencies */ -import { applyFilters } from '@wordpress/hooks' +import { doAction } from '@wordpress/hooks' -export const Style = props => { - const EffectStyles = applyFilters( 'stackable.block-component.effects-animations.style', null ) - return EffectStyles && -} - -Style.Content = props => { - const EffectStyles = applyFilters( 'stackable.block-component.effects-animations.style.content', null ) - return EffectStyles && +export const addStyles = ( blockStyleGenerator, props = {} ) => { + doAction( 'stackable.block-component.effects-animations.style.addStyles', blockStyleGenerator, props ) } diff --git a/src/block-components/helpers/backgrounds/style.js b/src/block-components/helpers/backgrounds/style.js index 365516895..c5f00b77c 100644 --- a/src/block-components/helpers/backgrounds/style.js +++ b/src/block-components/helpers/backgrounds/style.js @@ -1,9 +1,4 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addBackgroundStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -17,305 +12,308 @@ const Styles = props => { selectorCallback = null, } = props - return ( - <> - { - return getAttribute( 'backgroundColorType' ) !== 'gradient' - ? 'all' : false - } } - valueCallback={ ( value, getAttribute ) => { - const backgroundColorType = getAttribute( 'backgroundColorType' ) + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector, + hoverSelector: `${ selector }:hover`, + styleRule: 'backgroundColor', + attrName: 'backgroundColor', + key: 'backgroundColor-hover', + attrNameTemplate, + selectorCallback, + hoverCallback: getAttribute => { + return getAttribute( 'backgroundColorType' ) !== 'gradient' + ? 'all' : false + }, + valueCallback: ( value, getAttribute ) => { + const backgroundColorType = getAttribute( 'backgroundColorType' ) + + if ( backgroundColorType === 'gradient' && ( value.match( /rgba\(([^\)]*?)\s*0\s*\.?0?0?\)/ ) || value.includes( 'transparent' ) ) ) { + return 'transparent' + } + + return value + }, + dependencies: [ + 'backgroundColorType', + ...dependencies, + ], + } ] ) + + // To allow smaller screensizes to override the larger screensize + // background images, we need to split these css rules to individual + // ones: desktop, tablet and mobile + + /* Desktop */ + blockStyleGenerator.addBlockStyles( 'backgroundMediaUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaUrl', + key: 'backgroundMediaUrl', + attrNameTemplate, + format: 'url(%s)', + responsive: [ 'desktop' ], + valuePreCallback: value => { + // If it's a video, don't print out the style because + // it's handled by a video element. And this will cause + // the video to show up twice in the network requests. + if ( typeof value === 'string' ) { + if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { + return undefined + } + } + return value + }, + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundMediaExternalUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaExternalUrl', + key: 'backgroundMediaExternalUrl', + responsive: [ 'desktop' ], + attrNameTemplate, + format: 'url(%s)', + } ] ) + + /* Tablet */ + blockStyleGenerator.addBlockStyles( 'backgroundMediaUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaUrl', + key: 'backgroundMediaUrlTablet', + attrNameTemplate, + format: 'url(%s)', + responsive: [ 'tablet' ], + valuePreCallback: value => { + // If it's a video, don't print out the style because + // it's handled by a video element. And this will cause + // the video to show up twice in the network requests. + if ( typeof value === 'string' ) { + if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { + return undefined + } + } + return value + }, + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundMediaExternalUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaExternalUrl', + key: 'backgroundMediaExternalUrlTablet', + responsive: [ 'tablet' ], + attrNameTemplate, + format: 'url(%s)', + } ] ) + + /* Mobile */ + blockStyleGenerator.addBlockStyles( 'backgroundMediaUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaUrl', + key: 'backgroundMediaUrlMobile', + attrNameTemplate, + format: 'url(%s)', + responsive: [ 'mobile' ], + valuePreCallback: value => { + // If it's a video, don't print out the style because + // it's handled by a video element. And this will cause + // the video to show up twice in the network requests. + if ( typeof value === 'string' ) { + if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { + return undefined + } + } + return value + }, + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundMediaExternalUrl', [ { + ...propsToPass, + selector, + styleRule: 'backgroundImage', + attrName: 'backgroundMediaExternalUrl', + key: 'backgroundMediaExternalUrlMobile', + responsive: [ 'mobile' ], + attrNameTemplate, + format: 'url(%s)', + } ] ) + + blockStyleGenerator.addBlockStyles( 'fixedBackground', [ { + ...propsToPass, + selector, + styleRule: 'backgroundAttachment', + attrName: 'fixedBackground', + key: 'fixedBackground', + attrNameTemplate, + valueCallback: value => value ? 'fixed' : undefined, + } ] ) - if ( backgroundColorType === 'gradient' && ( value.match( /rgba\(([^\)]*?)\s*0\s*\.?0?0?\)/ ) || value.includes( 'transparent' ) ) ) { - return 'transparent' - } + blockStyleGenerator.addBlockStyles( 'backgroundPosition', [ { + ...propsToPass, + selector, + styleRule: 'backgroundPosition', + attrName: 'backgroundPosition', + key: 'backgroundPosition', + attrNameTemplate, + responsive: 'all', + } ] ) - return value - } } - dependencies={ [ - 'backgroundColorType', - ...dependencies, - ] } - /> - { - // To allow smaller screensizes to override the larger screensize - // background images, we need to split these css rules to individual - // ones: desktop, tablet and mobile + blockStyleGenerator.addBlockStyles( 'backgroundRepeat', [ { + ...propsToPass, + selector, + styleRule: 'backgroundRepeat', + attrName: 'backgroundRepeat', + key: 'backgroundRepeat', + attrNameTemplate, + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundSize', [ { + ...propsToPass, + selector, + styleRule: 'backgroundSize', + attrName: 'backgroundSize', + key: 'backgroundSize', + attrNameTemplate, + responsive: 'all', + valueCallback: ( value, getAttribute, device ) => { + if ( value === 'custom' ) { + if ( getAttribute( 'backgroundCustomSize', device ) ) { + return getAttribute( 'backgroundCustomSize', device ) + ( getAttribute( 'backgroundCustomSizeUnit', device ) || '%' ) + } } - { /* Desktop */ } - { - // If it's a video, don't print out the style because - // it's handled by a video element. And this will cause - // the video to show up twice in the network requests. - if ( typeof value === 'string' ) { - if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { - return undefined - } - } - return value - } } - /> - - { /* Tablet */ } - { - // If it's a video, don't print out the style because - // it's handled by a video element. And this will cause - // the video to show up twice in the network requests. - if ( typeof value === 'string' ) { - if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { - return undefined - } - } - return value - } } - /> - - { /* Mobile */ } - { - // If it's a video, don't print out the style because - // it's handled by a video element. And this will cause - // the video to show up twice in the network requests. - if ( typeof value === 'string' ) { - if ( value.match( /\.(mp4|ogg|webm)$/i ) ) { - return undefined - } - } - return value - } } - /> - - value ? 'fixed' : undefined } - /> - - - { - if ( value === 'custom' ) { - if ( getAttribute( 'backgroundCustomSize', device ) ) { - return getAttribute( 'backgroundCustomSize', device ) + ( getAttribute( 'backgroundCustomSizeUnit', device ) || '%' ) - } - } - return value - } } - dependencies={ [ - 'backgroundCustomSize', + return value + }, + dependencies: [ + 'backgroundCustomSize', 'backgroundCustomSizeUnit', ...dependencies, - ] } - /> - - { - if ( value === '' ) { - if ( getAttribute( 'backgroundTintStrength', device, state ) ) { - return '#000000' - } - } - return value - } } - valueCallback={ ( value, getAttribute ) => { - const isGradient = getAttribute( 'backgroundColorType' ) === 'gradient' - return ! isGradient && value ? value : undefined - } } - dependencies={ [ - 'backgroundColorType', - 'backgroundTintStrength', - ...dependencies, - ] } - /> - !! ( getAttribute( 'backgroundMediaUrl', 'mobile', 'normal', true ) || getAttribute( 'backgroundMediaExternalUrl', 'mobile', 'normal', true ) ) } - valuePreCallback={ ( value, getAttribute, device, state ) => { - if ( value === '' ) { - if ( getAttribute( 'backgroundColor', device, state ) ) { - return 5 - } - } - return value - } } - valueCallback={ value => { - return parseInt( value, 10 ) / 10 - } } - dependencies={ [ - 'backgroundColor', - 'backgroundMediaUrl', - 'backgroundMediaExternalUrl', - ...dependencies, - ] } - /> - getAttribute( 'backgroundColorType' ) === 'gradient' } - dependencies={ [ - 'backgroundColorType', - ...dependencies, - ] } - /> - getAttribute( 'backgroundColorType' ) === 'gradient' } - dependencies={ [ - 'backgroundColorType', - 'backgroundColor', - ...dependencies, - ] } - /> - - getAttribute( 'backgroundColorType' ) === 'gradient' || - getAttribute( 'backgroundColor' ) || - getAttribute( 'backgroundColor', 'desktop', 'hover' ) || - getAttribute( 'backgroundColor', 'desktop', 'parent-hover' ) } - dependencies={ [ - 'backgroundColorType', - 'backgroundColor', - ...dependencies, - ] } - /> - - ) -} + ], + } ] ) -export const BackgroundStyle = props => { - return -} + blockStyleGenerator.addBlockStyles( 'backgroundImageBlendMode', [ { + ...propsToPass, + selector, + styleRule: 'backgroundBlendMode', + attrName: 'backgroundImageBlendMode', + key: 'backgroundImageBlendMode', + attrNameTemplate, + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector: `${ selector }:before`, + hoverSelector: `${ selector }:hover:before`, + styleRule: 'backgroundColor', + attrName: 'backgroundColor', + key: 'backgroundColor-before', + attrNameTemplate, + selectorCallback, + hover: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( value === '' ) { + if ( getAttribute( 'backgroundTintStrength', device, state ) ) { + return '#000000' + } + } + return value + }, + valueCallback: ( value, getAttribute ) => { + const isGradient = getAttribute( 'backgroundColorType' ) === 'gradient' + return ! isGradient && value ? value : undefined + }, + dependencies: [ + 'backgroundColorType', + 'backgroundTintStrength', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundTintStrength', [ { + ...propsToPass, + selector: `${ selector }:before`, + hoverSelector: `${ selector }:hover:before`, + styleRule: 'opacity', + attrName: 'backgroundTintStrength', + key: 'backgroundTintStrength', + attrNameTemplate, + hover: 'all', + enabledCallback: getAttribute => !! ( getAttribute( 'backgroundMediaUrl', 'mobile', 'normal', true ) || getAttribute( 'backgroundMediaExternalUrl', 'mobile', 'normal', true ) ), + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( value === '' ) { + if ( getAttribute( 'backgroundColor', device, state ) ) { + return 5 + } + } + return value + }, + valueCallback: value => { + return parseInt( value, 10 ) / 10 + }, + dependencies: [ + 'backgroundColor', + 'backgroundMediaUrl', + 'backgroundMediaExternalUrl', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundGradientBlendMode', [ { + ...propsToPass, + selector: `${ selector }:before`, + styleRule: 'mixBlendMode', + attrName: 'backgroundGradientBlendMode', + key: 'backgroundGradientBlendMode', + attrNameTemplate, + enabledCallback: getAttribute => getAttribute( 'backgroundColorType' ) === 'gradient', + dependencies: [ + 'backgroundColorType', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'backgroundColor', [ { + ...propsToPass, + selector: `${ selector }:before`, + styleRule: 'backgroundImage', + attrName: 'backgroundColor', + key: 'backgroundColor-image', + attrNameTemplate, + enabledCallback: getAttribute => getAttribute( 'backgroundColorType' ) === 'gradient', + dependencies: [ + 'backgroundColorType', + 'backgroundColor', + ...dependencies, + ], + } ] ) -BackgroundStyle.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'borderRadius', [ { + ...propsToPass, + // In the editor, the background overlay can go outside the block if there's a border radius. + renderIn: 'edit', + selector: `${ selector }:before`, + styleRule: 'borderRadius', + attrName: 'borderRadius', + key: 'borderRadius', + attrNameTemplate, + format: '%spx', + enabledCallback: getAttribute => + getAttribute( 'backgroundColorType' ) === 'gradient' || + getAttribute( 'backgroundColor' ) || + getAttribute( 'backgroundColor', 'desktop', 'hover' ) || + getAttribute( 'backgroundColor', 'desktop', 'parent-hover' ), + dependencies: [ + 'backgroundColorType', + 'backgroundColor', + ...dependencies, + ], + } ] ) } diff --git a/src/block-components/helpers/borders/style.js b/src/block-components/helpers/borders/style.js index 3e1e8d7ca..90ffbf079 100644 --- a/src/block-components/helpers/borders/style.js +++ b/src/block-components/helpers/borders/style.js @@ -1,9 +1,4 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addBorderStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -19,218 +14,206 @@ const Styles = props => { borderEnabledCallback = getAttribute => getAttribute( 'borderType' ), } = props - return ( - <> - { /* The style below is deprecated. We have to keep it - because users who have updated will suddenly see that they have lost their - border radius */ } - - value?.top } - hoverSelector={ borderRadiusSelector ? undefined : hoverSelector } - /> - value?.right } - hoverSelector={ borderRadiusSelector ? undefined : hoverSelector } - /> - value?.left } - hoverSelector={ borderRadiusSelector ? undefined : hoverSelector } - /> - value?.bottom } - hoverSelector={ borderRadiusSelector ? undefined : hoverSelector } - /> - { - if ( addBorderRadiusOverflow && attrNameTemplate === 'block%s' && attributes.overflow ) { - return false - } - return addBorderRadiusOverflow - } } - valueCallback={ () => 'hidden' } - dependencies={ [ 'overflow' ] } - /> - { - if ( addBorderRadiusOverflow && attrNameTemplate === 'block%s' && attributes.overflow ) { - return false - } - return addBorderRadiusOverflow - } } - valueCallback={ () => 'hidden' } - dependencies={ [ 'overflow' ] } - /> - - - - value?.top } - dependencies={ [ 'borderType' ] } - /> - value?.right } - dependencies={ [ 'borderType' ] } - /> - value?.bottom } - dependencies={ [ 'borderType' ] } - /> - value?.left } - dependencies={ [ 'borderType' ] } - /> - - ) -} + // The style below is deprecated. We have to keep it because users who have + // updated will suddenly see that they have lost their border radius + blockStyleGenerator.addBlockStyles( 'borderRadius', [ { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'borderRadius', + attrName: 'borderRadius', + key: 'borderRadius', + attrNameTemplate, + format: '%spx', + responsive: 'all', + hover: 'all', + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + } ] ) -export const BorderStyle = props => { - return -} + blockStyleGenerator.addBlockStyles( 'borderRadius2', [ { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'borderTopLeftRadius', + attrName: 'borderRadius2', + key: 'borderTopLeftRadius2', + attrNameTemplate, + format: '%spx', + responsive: 'all', + hover: 'all', + valuePreCallback: value => value?.top, + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + }, { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'borderTopRightRadius', + attrName: 'borderRadius2', + key: 'borderTopRightRadius2', + attrNameTemplate, + format: '%spx', + responsive: 'all', + hover: 'all', + valuePreCallback: value => value?.right, + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + }, { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'borderBottomRightRadius', + attrName: 'borderRadius2', + key: 'borderBottomRightRadius2', + attrNameTemplate, + format: '%spx', + responsive: 'all', + hover: 'all', + valuePreCallback: value => value?.left, + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + }, { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'borderBottomLeftRadius', + attrName: 'borderRadius2', + key: 'borderBottomLeftRadius2', + attrNameTemplate, + format: '%spx', + responsive: 'all', + hover: 'all', + valuePreCallback: value => value?.bottom, + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + } ] ) + + // Adding a border radius should append `overflow: hidden`. This is to + // prevent gradient background from overflowing. borderRadius is + // deprecated, see comment below. + blockStyleGenerator.addBlockStyles( 'borderRadius', [ { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'overflow', + attrName: 'borderRadius', + key: 'borderRadius-overflow', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + enabledCallback: ( _getAttribute, attributes ) => { + if ( addBorderRadiusOverflow && attrNameTemplate === 'block%s' && attributes.overflow ) { + return false + } + return addBorderRadiusOverflow + }, + valueCallback: () => 'hidden', + dependencies: [ 'overflow' ], + } ] ) + + // borderRadius is deprecated, so we had to duplicate the style generated by + // the borderRadius to be used by borderRadius2. Adding a border radius + // should append `overflow: hidden`. This is to prevent gradient background + // from overflowing. + blockStyleGenerator.addBlockStyles( 'borderRadius2', [ { + ...propsToPass, + selector: borderRadiusSelector || selector, + styleRule: 'overflow', + attrName: 'borderRadius2', + key: 'borderRadius2-overflow', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector: borderRadiusSelector ? undefined : hoverSelector, + enabledCallback: ( _getAttribute, attributes ) => { + if ( addBorderRadiusOverflow && attrNameTemplate === 'block%s' && attributes.overflow ) { + return false + } + return addBorderRadiusOverflow + }, + valueCallback: () => 'hidden', + dependencies: [ 'overflow' ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'shadow', [ { + ...propsToPass, + selector, + styleRule: 'boxShadow', + attrName: 'shadow', + key: 'shadow', + attrNameTemplate, + hover: 'all', + hoverSelector, + } ] ) -BorderStyle.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'borderType', [ { + ...propsToPass, + selector, + styleRule: 'borderStyle', + attrName: 'borderType', + key: 'borderType', + attrNameTemplate, + } ] ) + + blockStyleGenerator.addBlockStyles( 'borderColor', [ { + ...propsToPass, + selector, + styleRule: 'borderColor', + attrName: 'borderColor', + key: 'borderColor', + attrNameTemplate, + enabledCallback: borderEnabledCallback, + hover: 'all', + hoverSelector, + dependencies: [ 'borderType' ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'borderWidth', [ { + ...propsToPass, + selector, + styleRule: 'borderTopWidth', + attrName: 'borderWidth', + key: 'borderWidth-top', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector, + format: '%spx', + enabledCallback: borderEnabledCallback, + valuePreCallback: value => value?.top, + dependencies: [ 'borderType' ], + }, { + ...propsToPass, + selector, + styleRule: 'borderRightWidth', + attrName: 'borderWidth', + key: 'borderWidth-right', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector, + format: '%spx', + enabledCallback: borderEnabledCallback, + valuePreCallback: value => value?.right, + dependencies: [ 'borderType' ], + }, { + ...propsToPass, + selector, + styleRule: 'borderBottomWidth', + attrName: 'borderWidth', + key: 'borderWidth-bottom', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector, + format: '%spx', + enabledCallback: borderEnabledCallback, + valuePreCallback: value => value?.bottom, + dependencies: [ 'borderType' ], + }, { + ...propsToPass, + selector, + styleRule: 'borderLeftWidth', + attrName: 'borderWidth', + key: 'borderWidth-left', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hoverSelector, + format: '%spx', + enabledCallback: borderEnabledCallback, + valuePreCallback: value => value?.left, + dependencies: [ 'borderType' ], + } ] ) } diff --git a/src/block-components/helpers/flex-gap/style.js b/src/block-components/helpers/flex-gap/style.js index 93f580699..7b999b746 100644 --- a/src/block-components/helpers/flex-gap/style.js +++ b/src/block-components/helpers/flex-gap/style.js @@ -1,9 +1,4 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addFlexGapStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -12,38 +7,51 @@ const Styles = props => { } const { selector, + editSelector = '', + saveSelector = '', enableColumnGap = true, } = props - return ( - <> - enableColumnGap } - /> - - - ) -} + blockStyleGenerator.addBlockStyles( 'columnGap', [ { + ...propsToPass, -export const FlexGapStyles = props => { - return -} + renderIn: 'edit', + selector: editSelector || selector, + styleRule: 'columnGap', + attrName: 'columnGap', + key: 'columnGap', + format: '%spx', + responsive: 'all', + enabledCallback: () => enableColumnGap, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + styleRule: 'columnGap', + attrName: 'columnGap', + key: 'columnGap', + format: '%spx', + responsive: 'all', + enabledCallback: () => enableColumnGap, + } ] ) -FlexGapStyles.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'rowGap', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + styleRule: 'rowGap', + attrName: 'rowGap', + key: 'rowGap', + format: '%spx', + responsive: 'all', + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + styleRule: 'rowGap', + attrName: 'rowGap', + key: 'rowGap', + format: '%spx', + responsive: 'all', + } ] ) } diff --git a/src/block-components/helpers/size/edit.js b/src/block-components/helpers/size/edit.js index a2b736b30..6c555fbb0 100644 --- a/src/block-components/helpers/size/edit.js +++ b/src/block-components/helpers/size/edit.js @@ -13,6 +13,7 @@ import { useAttributeEditHandlers, useDeviceType } from '~stackable/hooks' * WordPress dependencies */ import { __ } from '@wordpress/i18n' +import { getAttributeNameFunc } from '~stackable/util' const Layout = props => { const deviceType = useDeviceType() @@ -114,9 +115,8 @@ Layout.defaultProps = { } const Spacing = props => { - const { - getAttrName, - } = useAttributeEditHandlers( props.attrNameTemplate ) + // Don't use the hook form so we don't rerender + const getAttrName = getAttributeNameFunc( props.attrNameTemplate ) const { labelPaddings = __( 'Paddings', i18n ), diff --git a/src/block-components/helpers/size/style.js b/src/block-components/helpers/size/style.js index c45b9a87d..7daae3267 100644 --- a/src/block-components/helpers/size/style.js +++ b/src/block-components/helpers/size/style.js @@ -1,278 +1,291 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addSizeStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { selector = '', attrNameTemplate = '%s', horizontalAlignRule = 'margin', verticalAlignRule = 'alignItems', - // verticalAlignSelectorEdit = '', + verticalAlignSelectorEdit = '', + verticalAlignSelectorSave = '', verticalAlignSelector = '', hasPaddings = true, // Disallow the padding styles wrapperSelector = '', // The outer wrapper element that where the outer flex alignments, widths and margins are applied to. dependencies = [], } = props - return ( - <> - - - - { - return value !== '' ? 'auto' : undefined - } } - /> - { hasPaddings && <> - value?.top } - /> - value?.right } - /> - value?.bottom } - /> - value?.left } - /> - } - value?.top } - valueCallback={ value => { - return value.startsWith( 'auto' ) ? 'auto' : value - } } - /> - { - const right = value?.right - const horizontalAlign = getAttribute( 'horizontalAlign', device ) - const blockWidth = getAttribute( 'width', device ) - if ( blockWidth || typeof right !== 'undefined' ) { - switch ( horizontalAlign ) { - case 'flex-start': - case 'center': - return 'auto' - case 'flex-end': - return right || 0 - default: return right - } - } else { - return '' - } - } } - valueCallback={ value => { - return value.startsWith( 'auto' ) ? 'auto' : value - } } - dependencies={ [ - 'horizontalAlign', - 'width', - ...dependencies, - ] } - /> - value?.bottom } - valueCallback={ value => { - return value.startsWith( 'auto' ) ? 'auto' : value - } } - /> - { - const left = value?.left - const horizontalAlign = getAttribute( 'horizontalAlign', device ) - const blockWidth = getAttribute( 'width', device ) - if ( blockWidth || typeof left !== 'undefined' ) { - switch ( horizontalAlign ) { - case 'flex-start': - return left || 0 - case 'center': - case 'flex-end': - return 'auto' - default: return left - } - } else { - return '' - } - } } - valueCallback={ value => { - return value.startsWith( 'auto' ) ? 'auto' : value - } } - dependencies={ [ - 'horizontalAlign', - 'width', - ...dependencies, - ] } - /> - { - return 'flex' - } } - /> - { /* { - return ( verticalAlignRule || 'alignItems' ) === 'justifyContent' ? 'column' : undefined - } } - /> - { - return 'column' - } } - /> */ } - { horizontalAlignRule !== 'margin' && - } - - ) -} + blockStyleGenerator.addBlockStyles( 'height', [ { + ...propsToPass, + selector, + styleRule: 'minHeight', + attrName: 'height', + key: 'height', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + } ] ) -export const SizeStyle = props => { - return -} + if ( verticalAlignSelectorEdit ) { + blockStyleGenerator.addBlockStyles( 'verticalAlign', [ { + ...propsToPass, + renderIn: 'edit', + selector: verticalAlignSelectorEdit, + styleRule: verticalAlignRule || 'alignItems', + attrName: 'verticalAlign', + key: 'verticalAlign-edit', + attrNameTemplate, + responsive: 'all', + } ] ) + } + + if ( verticalAlignSelectorSave ) { + blockStyleGenerator.addBlockStyles( 'verticalAlign', [ { + ...propsToPass, + renderIn: 'save', + selector: verticalAlignSelectorSave, + styleRule: verticalAlignRule || 'alignItems', + attrName: 'verticalAlign', + key: 'verticalAlign-save', + attrNameTemplate, + responsive: 'all', + } ] ) + } + + if ( ! verticalAlignSelectorEdit && ! verticalAlignSelectorSave ) { + blockStyleGenerator.addBlockStyles( 'verticalAlign', [ { + ...propsToPass, + selector: verticalAlignSelector || selector, + styleRule: verticalAlignRule || 'alignItems', + attrName: 'verticalAlign', + key: 'verticalAlign', + attrNameTemplate, + responsive: 'all', + } ] ) + } -SizeStyle.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'width', [ { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'maxWidth', + attrName: 'width', + key: 'width-maxwidth', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + }, { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'minWidth', + attrName: 'width', + key: 'width-minwidth', + attrNameTemplate, + responsive: 'all', + hover: 'all', + versionAdded: '3.0.0', + versionDeprecated: '3.0.2', + valueCallback: value => { + return value !== '' ? 'auto' : undefined + }, + } ] ) + + if ( hasPaddings ) { + blockStyleGenerator.addBlockStyles( 'padding', [ { + ...propsToPass, + selector, + styleRule: 'paddingTop', + attrName: 'padding', + key: 'padding-top', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.top, + }, { + ...propsToPass, + selector, + styleRule: 'paddingRight', + attrName: 'padding', + key: 'padding-right', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.right, + }, { + ...propsToPass, + selector, + styleRule: 'paddingBottom', + attrName: 'padding', + key: 'padding-bottom', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.bottom, + }, { + ...propsToPass, + selector, + styleRule: 'paddingLeft', + attrName: 'padding', + key: 'padding-left', + attrNameTemplate, + responsive: 'all', + hover: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.left, + } ] ) + } + + blockStyleGenerator.addBlockStyles( 'margin', [ { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'marginTop', + attrName: 'margin', + key: 'margin-top', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.top, + valueCallback: value => { + return value.startsWith( 'auto' ) ? 'auto' : value + }, + }, { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'marginRight', + attrName: 'margin', + key: 'margin-right', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + valuePreCallback: ( value, getAttribute, device ) => { + const right = value?.right + const horizontalAlign = getAttribute( 'horizontalAlign', device ) + const blockWidth = getAttribute( 'width', device ) + if ( blockWidth || typeof right !== 'undefined' ) { + switch ( horizontalAlign ) { + case 'flex-start': + case 'center': + return 'auto' + case 'flex-end': + return right || 0 + default: return right + } + } else { + return '' + } + }, + valueCallback: value => { + return value.startsWith( 'auto' ) ? 'auto' : value + }, + dependencies: [ + 'horizontalAlign', + 'width', + ...dependencies, + ], + }, { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'marginBottom', + attrName: 'margin', + key: 'margin-bottom', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + valuePreCallback: value => value?.bottom, + valueCallback: value => { + return value.startsWith( 'auto' ) ? 'auto' : value + }, + }, { + ...propsToPass, + selector: wrapperSelector || selector, + styleRule: 'marginLeft', + attrName: 'margin', + key: 'margin-left', + attrNameTemplate, + responsive: 'all', + hasUnits: 'px', + valuePreCallback: ( value, getAttribute, device ) => { + const left = value?.left + const horizontalAlign = getAttribute( 'horizontalAlign', device ) + const blockWidth = getAttribute( 'width', device ) + if ( blockWidth || typeof left !== 'undefined' ) { + switch ( horizontalAlign ) { + case 'flex-start': + return left || 0 + case 'center': + case 'flex-end': + return 'auto' + default: return left + } + } else { + return '' + } + }, + valueCallback: value => { + return value.startsWith( 'auto' ) ? 'auto' : value + }, + dependencies: [ + 'horizontalAlign', + 'width', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'verticalAlign', [ { + ...propsToPass, + selector, + styleRule: 'display', + attrName: 'verticalAlign', + key: 'verticalAlign-display', + attrNameTemplate, + responsive: 'all', + valueCallback: () => { + return 'flex' + }, + } ] ) + + // blockStyleGenerator.addBlockStyles( 'verticalAlign', [ { + // ...propsToPass, + // renderIn: 'save', + // selector, + // styleRule: 'flexDirection', + // attrName: 'verticalAlign', + // key: 'verticalAlign-save-flex', + // responsive: 'all', + // attrNameTemplate, + // valueCallback: () => { + // return ( verticalAlignRule || 'alignItems' ) === 'justifyContent' ? 'column' : undefined + // }, + // }, { + // ...propsToPass, + // renderIn: 'edit', + // selector, + // styleRule: 'flexDirection', + // attrName: 'verticalAlign', + // key: 'verticalAlign-flex', + // responsive: 'all', + // attrNameTemplate, + // valueCallback: () => { + // return 'column' + // }, + // } ] ) + + if ( horizontalAlignRule !== 'margin' ) { + blockStyleGenerator.addBlockStyles( 'horizontalAlign', [ { + ...propsToPass, + renderIn: 'save', + selector: wrapperSelector || selector, + styleRule: horizontalAlignRule || 'justifyContent', + attrName: 'horizontalAlign', + key: 'horizontalAlign', + attrNameTemplate, + responsive: 'all', + } ] ) + } } diff --git a/src/block-components/icon/index.js b/src/block-components/icon/index.js index 070598222..206baa9c5 100644 --- a/src/block-components/icon/index.js +++ b/src/block-components/icon/index.js @@ -14,7 +14,7 @@ import { IconSearchPopover, SvgIcon } from '~stackable/components' */ import { Edit } from './edit' import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' /** * WordPress dependencies @@ -255,5 +255,5 @@ Icon.InspectorControls = Edit Icon.addAttributes = addAttributes -Icon.Style = Style +Icon.addStyles = addStyles diff --git a/src/block-components/icon/style.js b/src/block-components/icon/style.js index 454cb4139..2a1444c55 100644 --- a/src/block-components/icon/style.js +++ b/src/block-components/icon/style.js @@ -1,14 +1,9 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - /** * WordPress dependencies */ -import { applyFilters } from '@wordpress/hooks' +import { doAction } from '@wordpress/hooks' -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -38,286 +33,282 @@ const Styles = props => { const shapeSelector = `${ selector } .stk--inner-svg` const shapeHoverSelector = `${ hoverSelector } .stk--inner-svg` - return ( - <> - { /* Icon Styles */ } - getSvgSelector( getAttribute ) } - hoverSelectorCallback={ getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ) } - styleRule="height" - attrName="iconSize" - key="iconSize" - responsive="all" - format="%spx" - /> - getSvgSelector( getAttribute ) } - hoverSelectorCallback={ getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ) } - styleRule="width" - attrName="iconSize" - key="iconSize-width" - responsive="all" - format="%spx" - /> - getSvgSelector( getAttribute ) } - hoverSelectorCallback={ getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ) } - styleRule="opacity" - attrName="iconOpacity" - key="iconOpacity" - hover="all" - /> - getSvgSelector( getAttribute ) } - hoverSelectorCallback={ getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ) } - styleRule="transform" - attrName="iconRotation" - key="iconRotation" - hover="all" - format="rotate(%sdeg)" - /> - { hasIconGap && - getSvgSelector( getAttribute ) } - hoverSelectorCallback={ getAttribute => getSvgSelector( getAttribute, hoverSelector ) } - styleRuleCallback={ getAttribute => getAttribute( 'iconPosition' ) === 'right' ? 'marginInlineStart' : 'marginInlineEnd' } - attrName="iconGap" - key="iconGap" - format="%spx" - dependencies={ [ - 'iconPosition', - ...dependencies, - ] } - /> + { /* Icon Styles */ } + blockStyleGenerator.addBlockStyles( 'iconSize', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute ), + hoverSelectorCallback: getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ), + styleRule: 'height', + attrName: 'iconSize', + key: 'iconSize', + responsive: 'all', + format: '%spx', + } ] ) + + blockStyleGenerator.addBlockStyles( 'iconSize', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute ), + hoverSelectorCallback: getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ), + styleRule: 'width', + attrName: 'iconSize', + key: 'iconSize-width', + responsive: 'all', + format: '%spx', + } ] ) + + blockStyleGenerator.addBlockStyles( 'iconOpacity', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute ), + hoverSelectorCallback: getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ), + styleRule: 'opacity', + attrName: 'iconOpacity', + key: 'iconOpacity', + hover: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'iconRotation', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute ), + hoverSelectorCallback: getAttribute => getSvgHoverSelector( getAttribute, hoverSelector ), + styleRule: 'transform', + attrName: 'iconRotation', + key: 'iconRotation', + hover: 'all', + format: 'rotate(%sdeg)', + } ] ) + + if ( hasIconGap ) { + blockStyleGenerator.addBlockStyles( 'iconGap', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute ), + hoverSelectorCallback: getAttribute => getSvgSelector( getAttribute, hoverSelector ), + styleRuleCallback: getAttribute => getAttribute( 'iconPosition' ) === 'right' ? 'marginInlineStart' : 'marginInlineEnd', + attrName: 'iconGap', + key: 'iconGap', + format: '%spx', + dependencies: [ + 'iconPosition', + ...dependencies, + ], + } ] ) + } + + blockStyleGenerator.addBlockStyles( 'iconColor1', [ { + ...propsToPass, + selectorCallback: getAttribute => getSvgSelector( getAttribute, selector, [ 'g', 'path', 'rect', 'polygon', 'ellipse' ] ), + hoverSelectorCallback: getAttribute => getSvgHoverSelector( getAttribute, hoverSelector, [ 'g', 'path', 'rect', 'polygon', 'ellipse' ] ), + styleRule: 'fill', + attrName: 'iconColor1', + key: 'iconColor1-fill', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( getAttribute( 'iconColorType' ) === 'gradient' && getAttribute( 'iconColor1', 'desktop', state ) && getAttribute( 'iconColor2', 'desktop', state ) ) { + return `url(#linear-gradient-${ getAttribute( 'uniqueId' ) })` } - getSvgSelector( getAttribute, selector, [ 'g', 'path', 'rect', 'polygon', 'ellipse' ] ) } - hoverSelectorCallback={ getAttribute => getSvgHoverSelector( getAttribute, hoverSelector, [ 'g', 'path', 'rect', 'polygon', 'ellipse' ] ) } - styleRule="fill" - attrName="iconColor1" - key="iconColor1-fill" - valuePreCallback={ ( value, getAttribute, device, state ) => { - if ( getAttribute( 'iconColorType' ) === 'gradient' && getAttribute( 'iconColor1', 'desktop', state ) && getAttribute( 'iconColor2', 'desktop', state ) ) { - return `url(#linear-gradient-${ getAttribute( 'uniqueId' ) })` - } - if ( ! getAttribute( 'iconColorType' ) ) { - return value - } + if ( ! getAttribute( 'iconColorType' ) ) { + return value + } + + return undefined + }, + dependencies: [ + 'iconColorType', + 'iconColor1', + 'iconColor2', + 'uniqueId', + ...dependencies, + ], + hover: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'iconColorGradientDirection', [ { + ...propsToPass, + selectorCallback: getAttribute => `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + styleRule: 'transform', + format: 'rotate(%sdeg)', + attrName: 'iconColorGradientDirection', + key: 'iconColorGradientDirection', + hoverSelectorCallback: getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + } ] ) - return undefined - } } - dependencies={ [ - 'iconColorType', - 'iconColor1', - 'iconColor2', - 'uniqueId', - ...dependencies, - ] } - hover="all" - /> - `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - styleRule="transform" - format="rotate(%sdeg)" - attrName="iconColorGradientDirection" - key="iconColorGradientDirection" - hoverSelectorCallback={ getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - /> - `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - styleRuleCallback={ getAttribute => `--linear-gradient-${ getAttribute( 'uniqueId' ) }-color-1` } - attrName="iconColor1" - key="iconColor1" - valuePreCallback={ ( value, getAttribute, device, state ) => { - if ( getAttribute( 'iconColorType' ) !== 'gradient' || - ! getAttribute( 'iconColor1', 'desktop', state ) || - ! getAttribute( 'iconColor2', 'desktop', state ) - ) { - return undefined - } - return value - } } - hoverSelectorCallback={ getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - dependencies={ [ - 'iconColorType', - 'iconColor1', - 'iconColor2', - ...dependencies, - ] } - /> - `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - styleRuleCallback={ getAttribute => `--linear-gradient-${ getAttribute( 'uniqueId' ) }-color-2` } - attrName="iconColor2" - key="iconColor2" - valuePreCallback={ ( value, getAttribute, device, state ) => { - if ( getAttribute( 'iconColorType' ) !== 'gradient' || + blockStyleGenerator.addBlockStyles( 'iconColor1', [ { + ...propsToPass, + selectorCallback: getAttribute => `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + styleRuleCallback: getAttribute => `--linear-gradient-${ getAttribute( 'uniqueId' ) }-color-1`, + attrName: 'iconColor1', + key: 'iconColor1', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( getAttribute( 'iconColorType' ) !== 'gradient' || ! getAttribute( 'iconColor1', 'desktop', state ) || ! getAttribute( 'iconColor2', 'desktop', state ) - ) { - return undefined - } - return value - } } - hoverSelectorCallback={ getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }` } - dependencies={ [ - 'iconColorType', - 'iconColor1', - 'iconColor2', - ...dependencies, - ] } - /> + ) { + return undefined + } + return value + }, + hoverSelectorCallback: getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + dependencies: [ + 'iconColorType', + 'iconColor1', + 'iconColor2', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'iconColor2', [ { + ...propsToPass, + selectorCallback: getAttribute => `${ selector } #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + styleRuleCallback: getAttribute => `--linear-gradient-${ getAttribute( 'uniqueId' ) }-color-2`, + attrName: 'iconColor2', + key: 'iconColor2', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( getAttribute( 'iconColorType' ) !== 'gradient' || + ! getAttribute( 'iconColor1', 'desktop', state ) || + ! getAttribute( 'iconColor2', 'desktop', state ) + ) { + return undefined + } + return value + }, + hoverSelectorCallback: getAttribute => `${ selector }:hover #linear-gradient-${ getAttribute( 'uniqueId' ) }`, + dependencies: [ + 'iconColorType', + 'iconColor1', + 'iconColor2', + ...dependencies, + ], + } ] ) - { /* Shape Styles */ } - { - const shapeColorType = getAttribute( 'shapeColorType' ) - if ( state !== 'normal' && shapeColorType === 'gradient' ) { - return undefined - } + { /* Shape Styles */ } + blockStyleGenerator.addBlockStyles( 'shapeColor1', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'backgroundColor', + attrName: 'shapeColor1', + key: 'shapeColor1', + hover: 'all', + valuePreCallback: ( value, getAttribute, device, state ) => { + const shapeColorType = getAttribute( 'shapeColorType' ) + if ( state !== 'normal' && shapeColorType === 'gradient' ) { + return undefined + } - return value - } } - dependencies={ [ - 'shapeColorType', - 'shapeColor2', - 'shapeColorType', - 'shapeGradientDirection', - ...dependencies, - ] } - /> - - - - { - if ( - ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.top || - ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.right || - ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.bottom || - ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.left - ) { - return undefined - } + return value + }, + dependencies: [ + 'shapeColorType', + 'shapeColor2', + 'shapeColorType', + 'shapeGradientDirection', + ...dependencies, + ], + } ] ) - return 'solid' - } } - hover="all" - dependencies={ [ - 'shapeOutlineWidth', - ...dependencies, - ] } - /> - value?.top } - /> - value?.right } - /> - value?.bottom } - /> - value?.left } - /> - - ) -} + blockStyleGenerator.addBlockStyles( 'shapeBorderRadius', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderRadius', + attrName: 'shapeBorderRadius', + key: 'shapeBorderRadius', + format: '%s%', + hover: 'all', + } ] ) -export const Style = props => { - const IndivIconStyles = applyFilters( 'stackable.block-component.icon.indiv-icon-style', null ) + blockStyleGenerator.addBlockStyles( 'shapePadding', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'padding', + attrName: 'shapePadding', + key: 'shapePadding', + format: '%spx', + } ] ) - return <> - - { IndivIconStyles && } - -} + blockStyleGenerator.addBlockStyles( 'shapeOutlineColor', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderColor', + attrName: 'shapeOutlineColor', + key: 'shapeOutlineColor', + hover: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'borderStyle', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderStyle', + attrName: 'borderStyle', + key: 'borderStyle', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( + ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.top || + ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.right || + ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.bottom || + ! getAttribute( 'shapeOutlineWidth', 'desktop', state )?.left + ) { + return undefined + } + + return 'solid' + }, + hover: 'all', + dependencies: [ + 'shapeOutlineWidth', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'shapeOutlineWidth', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderTopWidth', + attrName: 'shapeOutlineWidth', + key: 'shapeOutlineWidth-top', + responsive: 'all', + format: '%spx', + valuePreCallback: value => value?.top, + } ] ) + + blockStyleGenerator.addBlockStyles( 'shapeOutlineWidth', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderRightWidth', + attrName: 'shapeOutlineWidth', + key: 'shapeOutlineWidth-right', + responsive: 'all', + format: '%spx', + valuePreCallback: value => value?.right, + } ] ) + + blockStyleGenerator.addBlockStyles( 'shapeOutlineWidth', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderBottomWidth', + attrName: 'shapeOutlineWidth', + key: 'shapeOutlineWidth-bottom', + responsive: 'all', + format: '%spx', + valuePreCallback: value => value?.bottom, + } ] ) -Style.Content = props => { - const IndivIconStyles = applyFilters( 'stackable.block-component.icon.indiv-icon-style', null ) + blockStyleGenerator.addBlockStyles( 'shapeOutlineWidth', [ { + ...propsToPass, + selector: shapeSelector, + hoverSelector: shapeHoverSelector, + styleRule: 'borderLeftWidth', + attrName: 'shapeOutlineWidth', + key: 'shapeOutlineWidth-left', + responsive: 'all', + format: '%spx', + valuePreCallback: value => value?.left, + } ] ) - return <> - - { IndivIconStyles && } - + doAction( 'stackable.block-component.icon.indiv-icon-style.addStyles', blockStyleGenerator ) } diff --git a/src/block-components/image/index.js b/src/block-components/image/index.js index 17fb2b197..70f6cd1d4 100644 --- a/src/block-components/image/index.js +++ b/src/block-components/image/index.js @@ -2,7 +2,7 @@ * Internal dependencies */ import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' import { useImage } from './use-image' import { Edit } from './edit' import Image_ from './image' @@ -176,4 +176,4 @@ Image.InspectorControls = Edit Image.addAttributes = addAttributes -Image.Style = Style +Image.addStyles = addStyles diff --git a/src/block-components/image/style.js b/src/block-components/image/style.js index 6b65b4e69..62dc4d15e 100644 --- a/src/block-components/image/style.js +++ b/src/block-components/image/style.js @@ -7,7 +7,6 @@ import { getShapeCSS } from './get-shape-css' * External dependencies */ import { toNumber } from 'lodash' -import { BlockCss } from '~stackable/components' const focalPointToPosition = ( { x, y } ) => { let _x = toNumber( x ) @@ -17,501 +16,509 @@ const focalPointToPosition = ( { x, y } ) => { return `${ _x }% ${ _y }%` } -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { selector = '.stk-img-wrapper', hoverSelector = '.stk-img-wrapper:hover', hoverSelectorCallback = null, enableWidth = true, + enableWidthCallback = null, + saveEnableWidthCallback = null, enableHeight = true, + enableHeightCallback = null, enableAspectRatio = true, + enableAspectRatioCallback = null, widthStyleRule = null, - widthUnitCallback = null, + widthStyleRuleCallback = null, + editorWidthUnitCallback = null, + saveWidthUnitCallback = null, heightUnitCallback = null, dependencies = [], } = props - return ( - <> - enableAspectRatio } - /> - enableAspectRatio } - /> - enableWidth } - valueCallback={ ( value, getAttribute ) => { - // If there's an aspect ratio and the other dimension is not given, use auto - if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageHeight' ) ) { - return 'auto' - } - return value - } } - dependencies={ [ - 'imageAspectRatio', - 'imageHeight', - ] } - /> - enableWidth } - valueCallback={ ( value, getAttribute ) => { - // If there's an aspect ratio and the other dimension is not given, use auto - if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageHeight' ) ) { - return 'auto' - } - return value - } } - dependencies={ [ - 'imageAspectRatio', - 'imageHeight', - ] } - /> - enableHeight } - valueCallback={ ( value, getAttribute ) => { - // If there's an aspect ratio and the other dimension is not given, use auto - if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageWidth' ) ) { - return 'auto' - } - return value - } } - valuePreCallback={ ( value, getAttribute ) => { - if ( enableAspectRatio && value === '' && getAttribute( 'imageAspectRatio' ) && ! getAttribute( 'imageWidth' ) ) { - return 'auto' - } - return value - } } - dependencies={ [ - 'imageAspectRatio', - 'imageWidth', - ] } - /> - enableHeight } - valueCallback={ ( value, getAttribute ) => { - // If there's an aspect ratio and the other dimension is not given, use auto - if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageWidth' ) ) { - return 'auto' - } - return value - } } - valuePreCallback={ ( value, getAttribute ) => { - if ( enableAspectRatio && value === '' && getAttribute( 'imageAspectRatio' ) && ! getAttribute( 'imageHeight' ) ) { - return 'auto' - } - return value - } } - dependencies={ [ - 'imageAspectRatio', - 'imageWidth', - ] } - /> - - - - - - - - - { /** Image shape */ } - !! getAttribute( 'imageShape' ) } - valueCallback={ ( value, getAttribute ) => { - return getShapeCSS( value, getAttribute( 'imageShapeFlipX' ), getAttribute( 'imageShapeFlipY' ), getAttribute( 'imageShapeStretch' ) ) - } } - dependencies={ [ - 'imageShapeFlipX', - 'imageShapeFlipY', - 'imageShapeStretch', - ...dependencies, - ] } - /> - !! getAttribute( 'imageShape' ) } - valueCallback={ ( value, getAttribute ) => { - return getShapeCSS( value, getAttribute( 'imageShapeFlipX' ), getAttribute( 'imageShapeFlipY' ), getAttribute( 'imageShapeStretch' ) ) - } } - dependencies={ [ - 'imageShapeFlipX', - 'imageShapeFlipY', - 'imageShapeStretch', - ...dependencies, - ] } - /> - { /* These 2 components are for the gradient overlay normal states */ } - { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' - } } - attrName="imageOverlayColor" - key="imageOverlayColor-save" - hoverCallback={ getAttribute => { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? null : 'all' - } } - valueCallback={ ( value, getAttribute ) => { - const textColorType = getAttribute( 'imageOverlayColorType' ) - const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + const _enableWidthCallback = enableWidthCallback || ( () => enableWidth ) + const _enableHeightCallback = enableHeightCallback || ( () => enableHeight ) + const _enableAspectRatioCallback = enableAspectRatioCallback || ( () => enableAspectRatio ) + const _widthStyleRuleCallback = widthStyleRuleCallback || ( () => widthStyleRule || 'width' ) - // If the type was switched, adjust the value so that gradient will show up. - if ( textColorType === 'gradient' && ! isGradient ) { - return `linear-gradient(${ value } 0%, ${ value } 100%)` - } else if ( textColorType !== 'gradient' && isGradient ) { - const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) - if ( color ) { - return color[ 0 ] - } - } - return value - } } - dependencies={ [ - 'imageOverlayColorType', - ...dependencies, - ] } - /> - { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' - } } - attrName="imageOverlayColor" - key="imageOverlayColor" - hoverCallback={ getAttribute => { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? null : 'all' - } } - valueCallback={ ( value, getAttribute ) => { - const textColorType = getAttribute( 'imageOverlayColorType' ) - const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + blockStyleGenerator.addBlockStyles( 'imageAspectRatio', [ { + ...propsToPass, + selector: [ + selector, + `${ selector } .stk-img-resizer-wrapper`, + ], + renderIn: 'edit', + styleRule: 'aspectRatio', + attrName: 'imageAspectRatio', + key: 'imageAspectRatio', + responsive: 'all', + enabledCallback: _enableAspectRatioCallback, + }, { + ...propsToPass, + selector, + renderIn: 'save', + styleRule: 'aspectRatio', + attrName: 'imageAspectRatio', + key: 'imageAspectRatio', + responsive: 'all', + enabledCallback: _enableAspectRatioCallback, + } ] ) - // If the type was switched, adjust the value so that gradient will show up. - if ( textColorType === 'gradient' && ! isGradient ) { - return `linear-gradient(${ value } 0%, ${ value } 100%)` - } else if ( textColorType !== 'gradient' && isGradient ) { - const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) - if ( color ) { - return color[ 0 ] - } - } - return value - } } - dependencies={ [ - 'imageOverlayColorType', - ...dependencies, - ] } - /> - { /* These 2 components are for the gradient overlay for hover states */ } - { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' - } } - attrName="imageOverlayColor" - key="imageOverlayColor-edit-image" - hoverCallback={ getAttribute => { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'all' : null - } } - enabledCallback={ getAttribute => getAttribute( 'imageOverlayColorType' ) === 'gradient' } - valueCallback={ ( value, getAttribute, device, state ) => { - if ( state === 'normal' ) { - return undefined - } + blockStyleGenerator.addBlockStyles( 'imageWidth', [ { + ...propsToPass, + selector: `${ selector }:not(.stk--is-resizing)`, + renderIn: 'edit', + styleRule: 'width', + attrName: 'imageWidth', + key: 'imageWidth', + hasUnits: '%', + unitCallback: editorWidthUnitCallback, + responsive: 'all', + enabledCallback: _enableWidthCallback, + valueCallback: ( value, getAttribute ) => { + // If there's an aspect ratio and the other dimension is not given, use auto + if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageHeight' ) ) { + return 'auto' + } + return value + }, + dependencies: [ + 'imageAspectRatio', + 'imageHeight', + ], + }, { + ...propsToPass, + selector, + renderIn: 'save', + styleRuleCallback: _widthStyleRuleCallback, + attrName: 'imageWidth', + key: 'imageWidth-save', + hasUnits: '%', + unitCallback: saveWidthUnitCallback, + responsive: 'all', + enabledCallback: saveEnableWidthCallback || _enableWidthCallback, + valueCallback: ( value, getAttribute ) => { + // If there's an aspect ratio and the other dimension is not given, use auto + if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageHeight' ) ) { + return 'auto' + } + return value + }, + dependencies: [ + 'imageAspectRatio', + 'imageHeight', + ], + } ] ) - const textColorType = getAttribute( 'imageOverlayColorType' ) - const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + blockStyleGenerator.addBlockStyles( 'imageHeight', [ { + ...propsToPass, + selector: `${ selector }:not(.stk--is-resizing)`, + renderIn: 'edit', + styleRule: 'height', + attrName: 'imageHeight', + key: 'imageHeight', + hasUnits: 'px', + unitCallback: heightUnitCallback, + responsive: 'all', + enabledCallback: _enableHeightCallback, + valueCallback: ( value, getAttribute ) => { + // If there's an aspect ratio and the other dimension is not given, use auto + if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageWidth' ) ) { + return 'auto' + } + return value + }, + valuePreCallback: ( value, getAttribute ) => { + if ( enableAspectRatio && value === '' && getAttribute( 'imageAspectRatio' ) && ! getAttribute( 'imageWidth' ) ) { + return 'auto' + } + return value + }, + dependencies: [ + 'imageAspectRatio', + 'imageWidth', + ], + }, { + ...propsToPass, + selector, + renderIn: 'save', + styleRule: 'height', + attrName: 'imageHeight', + key: 'imageHeight-save', + hasUnits: 'px', + unitCallback: heightUnitCallback, + responsive: 'all', + enabledCallback: _enableHeightCallback, + valueCallback: ( value, getAttribute ) => { + // If there's an aspect ratio and the other dimension is not given, use auto + if ( enableAspectRatio && ! value && getAttribute( 'imageAspectRatio' ) && getAttribute( 'imageWidth' ) ) { + return 'auto' + } + return value + }, + valuePreCallback: ( value, getAttribute ) => { + if ( enableAspectRatio && value === '' && getAttribute( 'imageAspectRatio' ) && ! getAttribute( 'imageHeight' ) ) { + return 'auto' + } + return value + }, + dependencies: [ + 'imageAspectRatio', + 'imageWidth', + ], + }, + ] ) - // If the type was switched, adjust the value so that gradient will show up. - if ( textColorType === 'gradient' && ! isGradient ) { - return `linear-gradient(${ value } 0%, ${ value } 100%)` - } else if ( textColorType !== 'gradient' && isGradient ) { - const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) - if ( color ) { - return color[ 0 ] - } - } - return value - } } - dependencies={ [ - 'imageOverlayColorType', - 'imageOverlayOpacity', - ...dependencies, - ] } - /> - { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' - } } - attrName="imageOverlayColor" - key="imageOverlayColor-save-image" - hoverCallback={ getAttribute => { - const colorType = getAttribute( 'imageOverlayColorType' ) - return colorType === 'gradient' ? 'all' : null - } } - enabledCallback={ getAttribute => getAttribute( 'imageOverlayColorType' ) === 'gradient' } - valueCallback={ ( value, getAttribute, device, state ) => { - if ( state === 'normal' ) { - return undefined - } + blockStyleGenerator.addBlockStyles( 'imageShadow', [ { + ...propsToPass, + /** + * `box-shadow` will not work alongside + * `mask-image`. Use `drop-shadow` instead. + * + * @see https://stackoverflow.com/questions/12492006/box-shadow-on-element-with-webkit-mask-image + */ + selector: `${ selector } .stk-img-resizer-wrapper`, + hoverSelector: hoverSelector ? `${ hoverSelector } .stk-img-resizer-wrapper` : undefined, + hoverSelectorCallback, + renderIn: 'edit', + styleRule: 'filter', + attrName: 'imageShadow', + key: 'imageShadow', + format: 'drop-shadow(%s)', + hover: 'all', + }, { + ...propsToPass, + selector, + hoverSelector, + renderIn: 'save', + styleRule: 'filter', + attrName: 'imageShadow', + key: 'imageShadow-save', + format: 'drop-shadow(%s)', + hover: 'all', + } ] ) - const textColorType = getAttribute( 'imageOverlayColorType' ) - const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + blockStyleGenerator.addBlockStyles( 'imageFilter', [ { + ...propsToPass, + selector: `${ selector } img`, + hoverSelector: `${ hoverSelector } img`, + hoverSelectorCallback, + styleRule: 'filter', + attrName: 'imageFilter', + key: 'imageFilter', + hover: 'all', + } ] ) - // If the type was switched, adjust the value so that gradient will show up. - if ( textColorType === 'gradient' && ! isGradient ) { - return `linear-gradient(${ value } 0%, ${ value } 100%)` - } else if ( textColorType !== 'gradient' && isGradient ) { - const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) - if ( color ) { - return color[ 0 ] - } - } - return value - } } - dependencies={ [ - 'imageOverlayColorType', - 'imageOverlayOpacity', - ...dependencies, - ] } - /> - - - - - - ) -} + blockStyleGenerator.addBlockStyles( 'imageZoom', [ { + ...propsToPass, + selector: `${ selector } img`, + hoverSelector: `${ hoverSelector } img`, + hoverSelectorCallback, + styleRule: 'transform', + attrName: 'imageZoom', + key: 'imageZoom', + format: 'scale(%s)', + hover: 'all', + } ] ) -export const Style = props => { - return -} + blockStyleGenerator.addBlockStyles( 'imageBorderRadius', [ { + ...propsToPass, + /** + * Add the border radius in the actual image since + * filter CSS style values (e.g. `brightness`) can sometimes mess up + * the border radius of the image. So add the border-radius alongside filters. + * + * @see https://github.com/gambitph/Stackable/issues/1833 + */ + selector: `${ selector } .stk-img-resizer-wrapper img`, + renderIn: 'edit', + styleRule: 'borderRadius', + attrName: 'imageBorderRadius', + key: 'imageBorderRadius', + format: '%spx', + }, { + ...propsToPass, + selector: `${ selector } img`, + renderIn: 'save', + styleRule: 'borderRadius', + attrName: 'imageBorderRadius', + key: 'imageBorderRadius-save', + format: '%spx', + } ] ) + + blockStyleGenerator.addBlockStyles( 'imageFocalPoint', [ { + ...propsToPass, + selector: `${ selector } img`, + hoverSelector: `${ hoverSelector } img`, + hoverSelectorCallback, + styleRule: 'objectPosition', + attrName: 'imageFocalPoint', + key: 'imageFocalPoint', + valueCallback: focalPointToPosition, + responsive: 'all', + hover: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'imageFit', [ { + ...propsToPass, + selector: `${ selector } img`, + styleRule: 'objectFit', + attrName: 'imageFit', + key: 'imageFit', + responsive: 'all', + } ] ) + + { /** Image shape */ } + + blockStyleGenerator.addBlockStyles( 'imageShape', [ { + ...propsToPass, + renderIn: 'edit', + // This is so that the resizer won't get clipped. + selector: [ + `${ selector } .stk-img-resizer-wrapper img`, + `${ selector } .stk-img-resizer-wrapper::after`, + `${ selector } .stk-img-resizer-wrapper::before`, + ], + styleRule: 'mask-image', + vendorPrefixes: [ '-webkit-' ], + attrName: 'imageShape', + key: 'imageShape', + responsive: 'all', + enabledCallback: getAttribute => !! getAttribute( 'imageShape' ), + valueCallback: ( value, getAttribute ) => { + return getShapeCSS( value, getAttribute( 'imageShapeFlipX' ), getAttribute( 'imageShapeFlipY' ), getAttribute( 'imageShapeStretch' ) ) + }, + dependencies: [ + 'imageShapeFlipX', + 'imageShapeFlipY', + 'imageShapeStretch', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selector: [ + `${ selector } img`, + `${ selector }::after`, + `${ selector }::before`, + ], + styleRule: 'mask-image', + vendorPrefixes: [ '-webkit-' ], + attrName: 'imageShape', + key: 'imageShape-save', + responsive: 'all', + enabledCallback: getAttribute => !! getAttribute( 'imageShape' ), + valueCallback: ( value, getAttribute ) => { + return getShapeCSS( value, getAttribute( 'imageShapeFlipX' ), getAttribute( 'imageShapeFlipY' ), getAttribute( 'imageShapeStretch' ) ) + }, + dependencies: [ + 'imageShapeFlipX', + 'imageShapeFlipY', + 'imageShapeStretch', + ...dependencies, + ], + } ] ) + + { /* These 2 components are for the gradient overlay normal states */ } + + blockStyleGenerator.addBlockStyles( 'imageOverlayColor', [ { + ...propsToPass, + renderIn: 'save', + selector: `${ selector }::after`, + hoverSelector: `${ hoverSelector }::after`, + hoverSelectorCallback, + styleRuleCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' + }, + attrName: 'imageOverlayColor', + key: 'imageOverlayColor-save', + hoverCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? null : 'all' + }, + valueCallback: ( value, getAttribute ) => { + const textColorType = getAttribute( 'imageOverlayColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ + 'imageOverlayColorType', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'edit', + selector: `${ selector } .stk-img-resizer-wrapper::after`, + hoverSelector: `${ hoverSelector } .stk-img-resizer-wrapper::after`, + hoverSelectorCallback, + styleRuleCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' + }, + attrName: 'imageOverlayColor', + key: 'imageOverlayColor', + hoverCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? null : 'all' + }, + valueCallback: ( value, getAttribute ) => { + const textColorType = getAttribute( 'imageOverlayColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ + 'imageOverlayColorType', + ...dependencies, + ], + + } ] ) + + { /* These 2 components are for the gradient overlay for hover states */ } + blockStyleGenerator.addBlockStyles( 'imageOverlayColor', [ { + ...propsToPass, + renderIn: 'edit', + selector: `${ selector }::after`, + hoverSelector: `${ selector }::before`, + styleRuleCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' + }, + attrName: 'imageOverlayColor', + key: 'imageOverlayColor-edit-image', + hoverCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'all' : null + }, + enabledCallback: getAttribute => getAttribute( 'imageOverlayColorType' ) === 'gradient', + valueCallback: ( value, getAttribute, device, state ) => { + if ( state === 'normal' ) { + return undefined + } + + const textColorType = getAttribute( 'imageOverlayColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ + 'imageOverlayColorType', + 'imageOverlayOpacity', + ...dependencies, + ], + }, { + ...propsToPass, + renderIn: 'save', + selector: `${ selector }::after`, + hoverSelector: `${ selector }::before`, + styleRuleCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'backgroundImage' : 'backgroundColor' + }, + attrName: 'imageOverlayColor', + key: 'imageOverlayColor-save-image', + hoverCallback: getAttribute => { + const colorType = getAttribute( 'imageOverlayColorType' ) + return colorType === 'gradient' ? 'all' : null + }, + enabledCallback: getAttribute => getAttribute( 'imageOverlayColorType' ) === 'gradient', + valueCallback: ( value, getAttribute, device, state ) => { + if ( state === 'normal' ) { + return undefined + } + + const textColorType = getAttribute( 'imageOverlayColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ + 'imageOverlayColorType', + 'imageOverlayOpacity', + ...dependencies, + ], + }, + ] ) + + blockStyleGenerator.addBlockStyles( 'imageOverlayOpacity', [ { + ...propsToPass, + renderIn: 'save', + selector: `${ selector }`, + hoverSelector: `${ selector }::before`, + styleRule: '--stk-gradient-overlay', + attrName: 'imageOverlayOpacity', + key: 'imageOverlayOpacity-save', + hover: 'all', + }, { + ...propsToPass, + renderIn: 'edit', + selector: `${ selector } .stk-img-resizer-wrapper`, + hoverSelector: `${ selector } .stk-img-resizer-wrapper::before`, + styleRule: '--stk-gradient-overlay', + attrName: 'imageOverlayOpacity', + key: 'imageOverlayOpacity', + hover: 'all', + } ] ) -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'imageOverlayBlendMode', [ { + ...propsToPass, + renderIn: 'save', + selector: `${ selector }::after, ${ selector }::before`, + styleRule: 'mix-blend-mode', + attrName: 'imageOverlayBlendMode', + key: 'imageOverlayBlendMode-save', + }, { + ...propsToPass, + renderIn: 'edit', + selector: `${ selector } .stk-img-resizer-wrapper::after, ${ selector } .stk-img-resizer-wrapper::before`, + hoverSelectorCallback, + styleRule: 'mix-blend-mode', + attrName: 'imageOverlayBlendMode', + key: 'imageOverlayBlendMode', + } ] ) } diff --git a/src/block-components/margin-bottom/index.js b/src/block-components/margin-bottom/index.js index 8fdd19f28..975927e5d 100644 --- a/src/block-components/margin-bottom/index.js +++ b/src/block-components/margin-bottom/index.js @@ -2,12 +2,10 @@ * Internal dependencies */ import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' import { ResizableBottomMargin } from '~stackable/components' import { getUniqueBlockClass } from '~stackable/util' -import { - useBlockAttributesContext, useBlockContext, useBlockContextContext, -} from '~stackable/hooks' +import { useBlockAttributesContext, useBlockContextContext } from '~stackable/hooks' /** * WordPress dependencies @@ -15,7 +13,7 @@ import { import { useBlockEditContext } from '@wordpress/block-editor' import { applyFilters } from '@wordpress/hooks' import { memo } from '@wordpress/element' -import { select } from '@wordpress/data' +import { useSelect } from '@wordpress/data' export const MarginBottom = memo( props => { const { clientId } = useBlockEditContext() @@ -32,7 +30,36 @@ export const MarginBottom = memo( props => { } } ) - const { isLastBlock, parentBlock } = useBlockContext( clientId ) + const { + isLastBlock, + parentBlock, + isGroupBlock, + isRowLayout, + } = useSelect( + select => { + const { + getBlockOrder, getBlockRootClientId, getBlock, + } = select( 'core/block-editor' ) + + const rootClientId = getBlockRootClientId( clientId ) + const parentBlock = getBlock( rootClientId ) + const parentInnerBlocks = getBlockOrder( rootClientId ) + + const isGroupBlock = parentBlock?.name === 'core/group' + let isRowLayout = false + if ( isGroupBlock ) { + isRowLayout = parentBlock.attributes.layout?.type === 'flex' && parentBlock.attributes.layout?.flexWrap === 'nowrap' + } + + return { + parentBlock, + isLastBlock: parentInnerBlocks[ parentInnerBlocks.length - 1 ] === clientId, + isGroupBlock, + isRowLayout, + } + }, + [ clientId ] + ) // Check if the parent block (like a Column block) is displaying blocks // horizontally, we don't want to show the margin bottom draggable @@ -44,20 +71,16 @@ export const MarginBottom = memo( props => { return null } - // Don't show the margin bottom draggable indicator if this is in a row block. - const isGroupBlock = parentBlock && parentBlock.name === 'core/group' - let isRowLayout = false - if ( isGroupBlock ) { - const attributes = select( 'core/block-editor' ).getBlockAttributes( parentBlock.clientId ) - isRowLayout = attributes.layout?.type === 'flex' && attributes.layout?.flexWrap === 'nowrap' + if ( isGroupBlock && isRowLayout ) { + return null } - if ( isGroupBlock && isRowLayout ) { + if ( isLastBlock || ! attributes.uniqueId ) { return null } const enable = applyFilters( 'stackable.edit.margin-bottom.enable-handlers', true, parentBlock ) - if ( isLastBlock || ! enable || ! attributes.uniqueId ) { + if ( ! enable ) { return null } @@ -73,4 +96,4 @@ export const MarginBottom = memo( props => { MarginBottom.addAttributes = addAttributes -MarginBottom.Style = Style +MarginBottom.addStyles = addStyles diff --git a/src/block-components/margin-bottom/style.js b/src/block-components/margin-bottom/style.js index 8e9449492..4911bb9bd 100644 --- a/src/block-components/margin-bottom/style.js +++ b/src/block-components/margin-bottom/style.js @@ -1,9 +1,4 @@ -/** - * External dependencies - */ -import { BlockCss } from '~stackable/components' - -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -14,25 +9,13 @@ const Styles = props => { selector = '', } = props - return ( - <> - - - ) -} - -export const Style = props => { - return -} - -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'blockMarginBottom', [ { + ...propsToPass, + selector, + styleRule: 'marginBottom', + attrName: 'blockMarginBottom', + key: 'blockMarginBottom', + responsive: 'all', + format: '%spx', + } ] ) } diff --git a/src/block-components/progress-bar/index.js b/src/block-components/progress-bar/index.js index 179f4eae5..d894df5d4 100644 --- a/src/block-components/progress-bar/index.js +++ b/src/block-components/progress-bar/index.js @@ -1,9 +1,9 @@ import { Edit } from './edit' -import { Style } from './style' +import { addStyles } from './style' import { addAttributes } from './attributes' export const ProgressBar = () =>
ProgressBar.InspectorControls = Edit -ProgressBar.Style = Style +ProgressBar.addStyles = addStyles ProgressBar.addAttributes = addAttributes diff --git a/src/block-components/progress-bar/style.js b/src/block-components/progress-bar/style.js index 6ea479914..ab1a86c2d 100644 --- a/src/block-components/progress-bar/style.js +++ b/src/block-components/progress-bar/style.js @@ -1,7 +1,6 @@ import { hexToRgba } from '~stackable/util' -import { BlockCss } from '~stackable/components' -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -15,226 +14,219 @@ const Styles = props => { const selector = isCircle ? '.stk-progress-circle' : '.stk-progress-bar' - return ( - <> - - - { ! isCircle && ( - - ) } - { isCircle && ( - { - if ( getAttribute( 'progressColorType' ) === 'gradient' ) { - const uniqueId = getAttribute( 'uniqueId' ) - return `url(#gradient-${ uniqueId })` - } - return value - } } - /> - ) } - - - { /* Only use these stylRules when it's a circular progress */ } - { isCircle && - <> - { - if ( getAttribute( 'progressColorType' ) === 'gradient' ) { - // generate custom identifier on the editor as uniqueId can be blank. - // This happens when adding block with default block styling created. - // should use uniqueId upon saving - const color1 = getAttribute( 'progressColor1' ) || '-' - const color2 = getAttribute( 'progressColor2' ) || '-' - const direction = getAttribute( 'progressColorGradientDirection' ) || '' - const customGradientId = ( color1 + color2 + direction ).replace( /[^0-9A-Z]+/gi, '' ) - return `url(#gradient-${ customGradientId })` - } - return value - } } - dependencies={ [ - 'progressColorType', - 'progressColor2', - 'progressColorGradientDirection', - ...dependencies, - ] } - /> - { - if ( typeof value === 'string' || value === false ) { - return undefined - } - return 'round' - } } - /> - - - } - { /* Only use these stylRules for progress bars */ } - { ! isCircle && - <> - - - { - const borderRadius = getAttribute( 'progressBorderRadius' ) - return value ? borderRadius : undefined - } } - format="%spx" - dependencies={ [ - 'progressBorderRadius', - ...dependencies, - ] } - /> - getAttribute( 'progressColorType' ) === 'gradient' } - dependencies={ [ - 'progressColorType', - ...dependencies, - ] } - /> - getAttribute( 'progressColorType' ) === 'gradient' } - valueCallback={ ( value, getAttribute ) => { - if ( ! getAttribute( 'progressColor2' ) ) { - return undefined - } - // The default color is the same as the other one but transparent. Same so that there won't be a weird transition to transparent. - const defaultColor1 = hexToRgba( getAttribute( 'progressColor2' ) || '#ffffff', 0 ) - const defaultColor2 = hexToRgba( getAttribute( 'progressColor1' ) || '#3498db', 0 ) - - // Gradient location. - const color1Location = `${ getAttribute( 'progressColorGradientLocation1' ) || '0' }%` - const color2Location = `${ getAttribute( 'progressColorGradientLocation2' ) || '100' }%` - - const directionAngle = getAttribute( 'progressColorGradientDirection' ) - const angle = typeof directionAngle === 'string' ? '90deg' : `${ directionAngle }deg` - - return `linear-gradient(${ angle }, ${ getAttribute( 'progressColor1' ) || defaultColor1 } ${ color1Location }, ${ getAttribute( 'progressColor2' ) || defaultColor2 } ${ color2Location })` - } } - dependencies={ [ - 'progressColorType', - 'progressColor1', - 'progressColor2', - 'progressColorGradientLocation1', - 'progressColorGradientLocation2', - 'progressColorGradientDirection', - ...dependencies, - ] } - /> - + blockStyleGenerator.addBlockStyles( 'progressMax', [ { + ...propsToPass, + selector, + styleRule: '--progress-max', + attrName: 'progressMax', + key: 'progressMax', + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressValue', [ { + ...propsToPass, + selector, + renderIn: 'save', + styleRule: '--progress-value', + attrName: 'progressValue', + key: 'progressValue', + format: ! isCircle ? '%s%' : undefined, + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressColor1', [ { + ...propsToPass, + renderCondition: () => ! isCircle, + selector, + styleRule: '--progress-color-1', + attrName: 'progressColor1', + key: 'progressColor1-bar', + dependencies: [ + 'progressColorType', + 'progressColor2', + ...dependencies, + ], + }, { + ...propsToPass, + renderCondition: () => isCircle, + selector, + styleRule: '--progress-color-1', + attrName: 'progressColor1', + key: 'progressColor1-circle', + dependencies: [ + 'progressColorType', + 'progressColor2', + ...dependencies, + ], + renderIn: 'save', + valuePreCallback: ( value, getAttribute ) => { + if ( getAttribute( 'progressColorType' ) === 'gradient' ) { + const uniqueId = getAttribute( 'uniqueId' ) + return `url(#gradient-${ uniqueId })` } - - ) -} + return value + }, + } ] ) -export const Style = props => { - return -} + blockStyleGenerator.addBlockStyles( 'progressBackgroundColor', [ { + ...propsToPass, + selector, + styleRule: '--progress-background', + attrName: 'progressBackgroundColor', + key: 'progressBackgroundColor', + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressSize', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: '--progress-size', + attrName: 'progressSize', + key: 'progressSize', + format: '%spx', + } ] ) + + { /* Only use these stylRules when it's a circular progress */ } + if ( isCircle ) { + blockStyleGenerator.addBlockStyles( 'progressColor1', [ { + ...propsToPass, + selector, + renderIn: 'edit', + styleRule: '--progress-color-1', + attrName: 'progressColor1', + key: 'progressColor1-circle-var', + valuePreCallback: ( value, getAttribute ) => { + if ( getAttribute( 'progressColorType' ) === 'gradient' ) { + // generate custom identifier on the editor as uniqueId can be blank. + // This happens when adding block with default block styling created. + // should use uniqueId upon saving + const color1 = getAttribute( 'progressColor1' ) || '-' + const color2 = getAttribute( 'progressColor2' ) || '-' + const direction = getAttribute( 'progressColorGradientDirection' ) || '' + const customGradientId = ( color1 + color2 + direction ).replace( /[^0-9A-Z]+/gi, '' ) + return `url(#gradient-${ customGradientId })` + } + return value + }, + dependencies: [ + 'progressColorType', + 'progressColor2', + 'progressColorGradientDirection', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressRounded', [ { + ...propsToPass, + selector, + styleRule: '--progress-rounded', + attrName: 'progressRounded', + key: 'progressRounded', + valuePreCallback: value => { + if ( typeof value === 'string' || value === false ) { + return undefined + } + return 'round' + }, + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressThickness', [ { + ...propsToPass, + selector, + responsive: 'all', + styleRule: '--progress-thickness', + attrName: 'progressThickness', + key: 'progressThickness', + format: '%spx', + } ] ) + } + + { /* Only use these stylRules for progress bars */ } + if ( ! isCircle ) { + blockStyleGenerator.addBlockStyles( 'progressWidth', [ { + ...propsToPass, + selector, + styleRule: '--progress-bar-width', + attrName: 'progressWidth', + key: 'progressWidth', + hasUnits: '%', + responsive: 'all', + dependencies: [ + 'progressWidthUnit', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressBorderRadius', [ { + ...propsToPass, + selector, + styleRule: '--progress-border-radius', + attrName: 'progressBorderRadius', + key: 'progressBorderRadius', + hasUnits: 'px', + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressApplyBarRadius', [ { + ...propsToPass, + selector, + styleRule: '--progress-bar-border-radius', + attrName: 'progressApplyBarRadius', + key: 'progressApplyBarRadius', + valuePreCallback: ( value, getAttribute ) => { + const borderRadius = getAttribute( 'progressBorderRadius' ) + return value ? borderRadius : undefined + }, + format: '%spx', + dependencies: [ + 'progressBorderRadius', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'progressColorGradientBlendMode', [ { + ...propsToPass, + selector: '.stk-progress-bar__bar.stk--has-background-overlay:before', + styleRule: 'mixBlendMode', + attrName: 'progressColorGradientBlendMode', + key: 'progressColorGradientBlendMode', + enabledCallback: getAttribute => getAttribute( 'progressColorType' ) === 'gradient', + dependencies: [ + 'progressColorType', + ...dependencies, + ], + } ] ) -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'progressColor1', [ { + ...propsToPass, + selector: '.stk-progress-bar__bar.stk--has-background-overlay:before', + styleRule: 'backgroundImage', + attrName: 'progressColor1', + key: 'progressColor1-overlay', + enabledCallback: getAttribute => getAttribute( 'progressColorType' ) === 'gradient', + valueCallback: ( value, getAttribute ) => { + if ( ! getAttribute( 'progressColor2' ) ) { + return undefined + } + // The default color is the same as the other one but transparent. Same so that there won't be a weird transition to transparent. + const defaultColor1 = hexToRgba( getAttribute( 'progressColor2' ) || '#ffffff', 0 ) + const defaultColor2 = hexToRgba( getAttribute( 'progressColor1' ) || '#3498db', 0 ) + + // Gradient location. + const color1Location = `${ getAttribute( 'progressColorGradientLocation1' ) || '0' }%` + const color2Location = `${ getAttribute( 'progressColorGradientLocation2' ) || '100' }%` + + const directionAngle = getAttribute( 'progressColorGradientDirection' ) + const angle = typeof directionAngle === 'string' ? '90deg' : `${ directionAngle }deg` + + return `linear-gradient(${ angle }, ${ getAttribute( 'progressColor1' ) || defaultColor1 } ${ color1Location }, ${ getAttribute( 'progressColor2' ) || defaultColor2 } ${ color2Location })` + }, + dependencies: [ + 'progressColorType', + 'progressColor1', + 'progressColor2', + 'progressColorGradientLocation1', + 'progressColorGradientLocation2', + 'progressColorGradientDirection', + ...dependencies, + ], + } ] ) + } } diff --git a/src/block-components/row/index.js b/src/block-components/row/index.js index 9a7f5f328..472564ae2 100644 --- a/src/block-components/row/index.js +++ b/src/block-components/row/index.js @@ -1,13 +1,26 @@ import { addAttributes } from './attributes' -import { useBlockAttributesContext, useBlockContext } from '~stackable/hooks' - +import { useBlockAttributesContext } from '~stackable/hooks' +import { useBlockEditContext } from '@wordpress/block-editor' import { Fragment, useEffect } from '@wordpress/element' +import { useSelect } from '@wordpress/data' export * from './use-row' export const Row = props => { - const { numInnerBlocks } = useBlockContext() + const { clientId } = useBlockEditContext() + const { numInnerBlocks } = useSelect( + select => { + const { getBlockRootClientId, getBlockOrder } = select( 'core/block-editor' ) + const rootClientId = getBlockRootClientId( clientId ) + + return { + numInnerBlocks: getBlockOrder( rootClientId ).length, + } + }, + [ clientId ] + ) + const attributes = useBlockAttributesContext() useEffect( () => { diff --git a/src/block-components/separator/edit.js b/src/block-components/separator/edit.js index e7abb76de..32065bf10 100644 --- a/src/block-components/separator/edit.js +++ b/src/block-components/separator/edit.js @@ -12,7 +12,8 @@ import { InspectorStyleControls, } from '~stackable/components' import { - useAttributeEditHandlers, useBlockAttributesContext, useBlockSetAttributesContext, + useBlockAttributesContext, + useBlockSetAttributesContext, } from '~stackable/hooks' /* @@ -26,6 +27,7 @@ import { i18n, showProNotice } from 'stackable' import { __ } from '@wordpress/i18n' import { applyFilters } from '@wordpress/hooks' import { useMemo } from '@wordpress/element' +import { getAttributeNameFunc } from '~stackable/util' const SEPARATOR_SHADOWS = [ 'none', @@ -47,9 +49,7 @@ const SeparatorControls = props => { hasFlipVertically, } = props - const { - getAttrName, - } = useAttributeEditHandlers( attrNameTemplate ) + const getAttrName = getAttributeNameFunc( attrNameTemplate ) const separatorShadowOptions = applyFilters( 'stackable.separator.shadows', SEPARATOR_SHADOWS ) diff --git a/src/block-components/separator/index.js b/src/block-components/separator/index.js index b5dfc99be..cd4e60cf0 100644 --- a/src/block-components/separator/index.js +++ b/src/block-components/separator/index.js @@ -8,13 +8,13 @@ import { Separator2 } from '~stackable/components' /** * Internal dependencies */ -import { Style, SeparatorStyles } from './style' +import { addStyles, addSeparatorStyles } from './style' import { Edit } from './edit' import { addAttributes, createSeparatorAttributes, createSeparatorLayerAttributes, } from './attributes' export { - createSeparatorAttributes, createSeparatorLayerAttributes, SeparatorStyles, + createSeparatorAttributes, createSeparatorLayerAttributes, addSeparatorStyles, } /** @@ -111,4 +111,4 @@ Separator.InspectorControls = Edit Separator.addAttributes = addAttributes -Separator.Style = Style +Separator.addStyles = addStyles diff --git a/src/block-components/separator/style.js b/src/block-components/separator/style.js index b6b41e480..3ae82e80c 100644 --- a/src/block-components/separator/style.js +++ b/src/block-components/separator/style.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { BlockCss } from '~stackable/components' - /** * External dependencies */ @@ -11,15 +6,16 @@ import { compact } from 'lodash' /** * WordPress dependencies */ -import { applyFilters } from '@wordpress/hooks' +import { doAction } from '@wordpress/hooks' -export const SeparatorStyles = props => { +export const addSeparatorStyles = ( blockStyleGenerator, props ) => { const propsToPass = { ...props, version: props.version, versionAdded: '3.0.0', versionDeprecated: '', } + const { location = '', selector: _selector, @@ -32,100 +28,95 @@ export const SeparatorStyles = props => { const selector = _selector !== undefined ? _selector : ` > .stk-separator__${ location }` - return ( - <> - { - if ( value ) { - return 6 - } - return undefined - } } - /> - { - const flipHorizontally = value - const flipVertically = getAttribute( 'separatorFlipVertically' ) - - if ( ! enableFlipVertically && ! enableFlipHorizontally ) { - return undefined - } - - if ( ! flipHorizontally && ! flipVertically ) { - return undefined - } - - const shouldApplyScaleX = enableFlipHorizontally && flipHorizontally - const shouldAddScaleYAlongsideScaleX = shouldApplyScaleX && isInitiallyFlippedVertically - const shouldApplyScaleY = enableFlipVertically && flipVertically - - return compact( [ - shouldApplyScaleX ? 'scaleX(-1)' : undefined, - shouldAddScaleYAlongsideScaleX ? 'scaleY(-1)' : undefined, - shouldApplyScaleY ? 'scaleY(-1)' : undefined, - ] ).join( ' ' ) - } } - dependencies={ [ - 'separatorFlipVertically', - ...dependencies, - ] } - /> - - - - { - return value === 'drop-shadow(none)' ? 'none' : value - } } - /> - - ) + blockStyleGenerator.addBlockStyles( 'separatorBringToFront', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector, + styleRule: 'zIndex', + attrName: 'separatorBringToFront', + valuePreCallback: value => { + if ( value ) { + return 6 + } + return undefined + }, + } ] ) + + blockStyleGenerator.addBlockStyles( 'separatorFlipHorizontally', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector, + styleRule: 'transform', + attrName: 'separatorFlipHorizontally', + valuePreCallback: ( value, getAttribute ) => { + const flipHorizontally = value + const flipVertically = getAttribute( 'separatorFlipVertically' ) + + if ( ! enableFlipVertically && ! enableFlipHorizontally ) { + return undefined + } + + if ( ! flipHorizontally && ! flipVertically ) { + return undefined + } + + const shouldApplyScaleX = enableFlipHorizontally && flipHorizontally + const shouldAddScaleYAlongsideScaleX = shouldApplyScaleX && isInitiallyFlippedVertically + const shouldApplyScaleY = enableFlipVertically && flipVertically + + return compact( [ + shouldApplyScaleX ? 'scaleX(-1)' : undefined, + shouldAddScaleYAlongsideScaleX ? 'scaleY(-1)' : undefined, + shouldApplyScaleY ? 'scaleY(-1)' : undefined, + ] ).join( ' ' ) + }, + dependencies: [ + 'separatorFlipVertically', + ...dependencies, + ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'separatorColor', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector: selector + ' svg', + styleRule: 'fill', + attrName: 'separatorColor', + } ] ) + + blockStyleGenerator.addBlockStyles( 'separatorWidth', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector: selector + ` ${ wrapperSelector }`, + styleRule: 'transform', + attrName: 'separatorWidth', + format: 'scaleX(%s)', + } ] ) + + blockStyleGenerator.addBlockStyles( 'separatorHeight', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector: selector + ` ${ wrapperSelector }`, + styleRule: 'height', + responsive: 'all', + attrName: 'separatorHeight', + format: '%spx', + } ] ) + + blockStyleGenerator.addBlockStyles( 'separatorShadow', [ { + ...propsToPass, + attrNameTemplate: `${ location }%s`, + selector: selector + ' svg', + styleRule: 'filter', + attrName: 'separatorShadow', + format: 'drop-shadow(%s)', + valueCallback: value => { + return value === 'drop-shadow(none)' ? 'none' : value + }, + } ] ) } -const MarginBottomStyles = props => { +const addMarginBottomStyles = ( blockStyleGenerator, props ) => { const propsToPass = { ...props, version: props.version, @@ -136,46 +127,35 @@ const MarginBottomStyles = props => { selector: _selector, } = props - return ( - <> - .stk-separator__bottom` } - styleRule="bottom" - attrName="blockMargin" - key="blockMargin" - responsive="all" - valuePreCallback={ value => value?.bottom } - format="%spx" - /> - - ) -} - -export const Style = props => { - const SeparatorLayerStyles = applyFilters( 'stackable.block-component.separator.layer-styles', null ) - - return ( - <> - - - - { SeparatorLayerStyles && } - { SeparatorLayerStyles && } - - ) + blockStyleGenerator.addBlockStyles( 'textShadow', [ { + ...propsToPass, + renderIn: 'edit', + selector: _selector !== undefined ? _selector : ` > .stk-separator__bottom`, + styleRule: 'bottom', + attrName: 'blockMargin', + responsive: 'all', + valuePreCallback: value => value?.bottom, + format: '%spx', + } ] ) } -Style.Content = props => { - const SeparatorLayerStyles = applyFilters( 'stackable.block-component.separator.layer-styles', null ) - - return ( - <> - - - { SeparatorLayerStyles && } - { SeparatorLayerStyles && } - - ) +export const addStyles = ( blockStyleGenerator, props = {} ) => { + addSeparatorStyles( blockStyleGenerator, { + ...props, + location: 'top', + } ) + addSeparatorStyles( blockStyleGenerator, { + ...props, + isInitiallyFlippedVertically: false, + location: 'bottom', + } ) + addMarginBottomStyles( blockStyleGenerator, props ) + doAction( 'stackable.block-component.separator.layer-styles.addStyles', blockStyleGenerator, { + ...props, + location: 'top', + } ) + doAction( 'stackable.block-component.separator.layer-styles.addStyles', blockStyleGenerator, { + ...props, + location: 'bottom', + } ) } diff --git a/src/block-components/transform/index.js b/src/block-components/transform/index.js index 3f05d8a67..9892ef9d5 100644 --- a/src/block-components/transform/index.js +++ b/src/block-components/transform/index.js @@ -1,6 +1,6 @@ import { addAttributes } from './attributes' import { Edit } from './edit' -import { Style } from './style' +import { addStyles } from './style' export const Transform = () => { return null @@ -10,4 +10,4 @@ Transform.InspectorControls = Edit Transform.addAttributes = addAttributes -Transform.Style = Style +Transform.addStyles = addStyles diff --git a/src/block-components/transform/style.js b/src/block-components/transform/style.js index b04d086a8..e248bb71c 100644 --- a/src/block-components/transform/style.js +++ b/src/block-components/transform/style.js @@ -1,14 +1,8 @@ /** * WordPress dependencies */ -import { applyFilters } from '@wordpress/hooks' +import { doAction } from '@wordpress/hooks' -export const Style = props => { - const TransformStyles = applyFilters( 'stackable.block-component.transform.style', null ) - return TransformStyles && -} - -Style.Content = props => { - const TransformStyles = applyFilters( 'stackable.block-component.transform.style.content', null ) - return TransformStyles && +export const addStyles = ( blockStyleGenerator, props = {} ) => { + doAction( 'stackable.block-component.transform.style.addStyles', blockStyleGenerator, props ) } diff --git a/src/block-components/typography/index.js b/src/block-components/typography/index.js index ec6198113..33f5d196a 100644 --- a/src/block-components/typography/index.js +++ b/src/block-components/typography/index.js @@ -3,7 +3,7 @@ */ import { Edit } from './edit' import { addAttributes } from './attributes' -import { Style } from './style' +import { addStyles } from './style' export { getTypographyClasses } from './get-typography-classes' /** @@ -171,5 +171,5 @@ Typography.InspectorControls = Edit Typography.addAttributes = addAttributes -Typography.Style = Style +Typography.addStyles = addStyles diff --git a/src/block-components/typography/style.js b/src/block-components/typography/style.js index e789002d8..f40bc0f88 100644 --- a/src/block-components/typography/style.js +++ b/src/block-components/typography/style.js @@ -2,9 +2,8 @@ * Internal dependencies */ import { getFontFamily, clampInheritedStyle } from '~stackable/util' -import { BlockCss } from '~stackable/components' -const Styles = props => { +export const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -13,6 +12,8 @@ const Styles = props => { } const { selector = '', + editSelector = '', + saveSelector = '', selectorCallback = null, attrNameTemplate = '%s', inherit = true, @@ -20,181 +21,350 @@ const Styles = props => { inheritMax = 50, hoverSelector = '', hoverSelectorCallback = null, + editHoverSelectorCallback = null, + saveHoverSelectorCallback = null, dependencies = [], } = props - return ( - <> - - { - const currentValue = getAttribute( 'fontSize', device, state ) - const isMobile = device === 'mobile' - - let value = _value - const clampedValue = inherit && clampInheritedStyle( - _value, - { - min: inheritMin, max: inheritMax, - } - ) - - /** - * When clamping values in mobile, make sure to get the - * clamped desktop value first before checking the clamped - * tablet value. - * - * When the tablet is already clamped, the fallback value should - * be undefined already to avoid generating 2 identical styles. - */ - if ( isMobile ) { - const clampedDesktopValue = inherit && clampInheritedStyle( - getAttribute( 'fontSize', 'desktop', state ), - { - min: inheritMin, max: inheritMax, - } - ) - value = clampedDesktopValue ? clampedDesktopValue : value - } + blockStyleGenerator.addBlockStyles( 'textShadow', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'textShadow', + attrName: 'textShadow', + key: 'textShadow', + hover: 'all', + hoverSelector, + hoverSelectorCallback: editHoverSelectorCallback || hoverSelectorCallback, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'textShadow', + attrName: 'textShadow', + key: 'textShadow', + hover: 'all', + hoverSelector, + hoverSelectorCallback: saveHoverSelectorCallback || hoverSelectorCallback, + } ] ) + + blockStyleGenerator.addBlockStyles( 'fontSize', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontSize', + attrName: 'fontSize', + key: 'fontSize', + hasUnits: 'px', + responsive: 'all', + clampCallback: ( _value, getAttribute, device, state ) => { + const currentValue = getAttribute( 'fontSize', device, state ) + const isMobile = device === 'mobile' - value = clampedValue ? clampedValue : value - value = typeof currentValue !== 'undefined' && currentValue !== '' - ? currentValue - : isMobile ? undefined : value - return value - } } - dependencies={ [ 'fontSizeUnit', 'fontSize', ...dependencies ] } - /> - { - const textColorType = getAttribute( 'textColorType' ) - return textColorType === 'gradient' ? 'backgroundImage' : 'color' - } } - hover="all" - hoverSelector={ hoverSelector } - hoverSelectorCallback={ hoverSelectorCallback } - attrName="textColor1" - key="textColor1-color" - valuePreCallback={ ( value, getAttribute, device, state ) => { - if ( ! value && getAttribute( 'textColorType', 'desktop', state ) === 'gradient' ) { - return 'currentColor' + let value = _value + const clampedValue = inherit && clampInheritedStyle( + _value, + { + min: inheritMin, max: inheritMax, + } + ) + + /** + * When clamping values in mobile, make sure to get the + * clamped desktop value first before checking the clamped + * tablet value. + * + * When the tablet is already clamped, the fallback value should + * be undefined already to avoid generating 2 identical styles. + */ + if ( isMobile ) { + const clampedDesktopValue = inherit && clampInheritedStyle( + getAttribute( 'fontSize', 'desktop', state ), + { + min: inheritMin, max: inheritMax, } - return value - } } - valueCallback={ ( value, getAttribute ) => { - const textColorType = getAttribute( 'textColorType' ) - const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) - - // If the type was switched, adjust the value so that gradient will show up. - if ( textColorType === 'gradient' && ! isGradient ) { - return `linear-gradient(${ value } 0%, ${ value } 100%)` - } else if ( textColorType !== 'gradient' && isGradient ) { - const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) - if ( color ) { - return color[ 0 ] - } + ) + value = clampedDesktopValue ? clampedDesktopValue : value + } + + value = clampedValue ? clampedValue : value + value = typeof currentValue !== 'undefined' && currentValue !== '' + ? currentValue + : isMobile ? undefined : value + return value + }, + dependencies: [ 'fontSizeUnit', 'fontSize', ...dependencies ], + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontSize', + attrName: 'fontSize', + key: 'fontSize', + hasUnits: 'px', + responsive: 'all', + clampCallback: ( _value, getAttribute, device, state ) => { + const currentValue = getAttribute( 'fontSize', device, state ) + const isMobile = device === 'mobile' + + let value = _value + const clampedValue = inherit && clampInheritedStyle( + _value, + { + min: inheritMin, max: inheritMax, + } + ) + + /** + * When clamping values in mobile, make sure to get the + * clamped desktop value first before checking the clamped + * tablet value. + * + * When the tablet is already clamped, the fallback value should + * be undefined already to avoid generating 2 identical styles. + */ + if ( isMobile ) { + const clampedDesktopValue = inherit && clampInheritedStyle( + getAttribute( 'fontSize', 'desktop', state ), + { + min: inheritMin, max: inheritMax, } - return value - } } - dependencies={ [ 'textColorType', ...dependencies ] } - /> - - - - - getFontFamily( value ) } - dependencies={ dependencies } - /> - - - ) -} + ) + value = clampedDesktopValue ? clampedDesktopValue : value + } -export const Style = props => { - return -} + value = clampedValue ? clampedValue : value + value = typeof currentValue !== 'undefined' && currentValue !== '' + ? currentValue + : isMobile ? undefined : value + return value + }, + dependencies: [ 'fontSizeUnit', 'fontSize', ...dependencies ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'textColor1', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRuleCallback: getAttribute => { + const textColorType = getAttribute( 'textColorType' ) + return textColorType === 'gradient' ? 'backgroundImage' : 'color' + }, + hover: 'all', + hoverSelector, + hoverSelectorCallback: editHoverSelectorCallback || hoverSelectorCallback, + attrName: 'textColor1', + key: 'textColor1-color', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ! value && getAttribute( 'textColorType', 'desktop', state ) === 'gradient' ) { + return 'currentColor' + } + return value + }, + valueCallback: ( value, getAttribute ) => { + const textColorType = getAttribute( 'textColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ 'textColorType', ...dependencies ], + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRuleCallback: getAttribute => { + const textColorType = getAttribute( 'textColorType' ) + return textColorType === 'gradient' ? 'backgroundImage' : 'color' + }, + hover: 'all', + hoverSelector, + hoverSelectorCallback: saveHoverSelectorCallback || hoverSelectorCallback, + attrName: 'textColor1', + key: 'textColor1-color', + valuePreCallback: ( value, getAttribute, device, state ) => { + if ( ! value && getAttribute( 'textColorType', 'desktop', state ) === 'gradient' ) { + return 'currentColor' + } + return value + }, + valueCallback: ( value, getAttribute ) => { + const textColorType = getAttribute( 'textColorType' ) + const isGradient = value?.startsWith( 'linear-' ) || value?.startsWith( 'radial-' ) + + // If the type was switched, adjust the value so that gradient will show up. + if ( textColorType === 'gradient' && ! isGradient ) { + return `linear-gradient(${ value } 0%, ${ value } 100%)` + } else if ( textColorType !== 'gradient' && isGradient ) { + const color = value.match( /((rgba?|var)\([^\)]+\)|#[\w\d]+)/ ) + if ( color ) { + return color[ 0 ] + } + } + return value + }, + dependencies: [ 'textColorType', ...dependencies ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'lineHeight', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'lineHeight', + attrName: 'lineHeight', + key: 'lineHeight', + responsive: 'all', + hasUnits: 'em', + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'lineHeight', + attrName: 'lineHeight', + key: 'lineHeight', + responsive: 'all', + hasUnits: 'em', + dependencies, + } ] ) + + blockStyleGenerator.addBlockStyles( 'fontWeight', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontWeight', + attrName: 'fontWeight', + key: 'fontWeight', + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontWeight', + attrName: 'fontWeight', + key: 'fontWeight', + dependencies, + } ] ) + + blockStyleGenerator.addBlockStyles( 'textTransform', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'textTransform', + attrName: 'textTransform', + key: 'textTransform', + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'textTransform', + attrName: 'textTransform', + key: 'textTransform', + dependencies, + } ] ) + + blockStyleGenerator.addBlockStyles( 'fontStyle', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontStyle', + attrName: 'fontStyle', + key: 'fontStyle', + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontStyle', + attrName: 'fontStyle', + key: 'fontStyle', + dependencies, + } ] ) + + blockStyleGenerator.addBlockStyles( 'fontFamily', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontFamily', + attrName: 'fontFamily', + key: 'fontFamily', + valueCallback: value => getFontFamily( value ), + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'fontFamily', + attrName: 'fontFamily', + key: 'fontFamily', + valueCallback: value => getFontFamily( value ), + dependencies, + } ] ) -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'letterSpacing', [ { + ...propsToPass, + renderIn: 'edit', + selector: editSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'letterSpacing', + attrName: 'letterSpacing', + key: 'letterSpacing', + format: '%spx', + responsive: 'all', + dependencies, + }, { + ...propsToPass, + renderIn: 'save', + selector: saveSelector || selector, + selectorCallback, + attrNameTemplate, + styleRule: 'letterSpacing', + attrName: 'letterSpacing', + key: 'letterSpacing', + format: '%spx', + responsive: 'all', + dependencies, + } ] ) } diff --git a/src/block/accordion/edit.js b/src/block/accordion/edit.js index a5c7b427d..b5f6d4dbc 100644 --- a/src/block/accordion/edit.js +++ b/src/block/accordion/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import BlockStyles from './style' +import blockStyles from './style' /** * External dependencies @@ -16,10 +16,10 @@ import { InspectorTabs, PanelAdvancedSettings, InspectorAdvancedControls, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, getAlignmentClasses, Alignment, Advanced, @@ -50,7 +50,7 @@ import { InnerBlocks } from '@wordpress/block-editor' import { __ } from '@wordpress/i18n' import { compose } from '@wordpress/compose' import { useSelect } from '@wordpress/data' -import { useState, useEffect } from '@wordpress/element' +import { useState, useEffect, memo } from '@wordpress/element' import { addFilter, applyFilters } from '@wordpress/hooks' import { findLast } from 'lodash' @@ -61,11 +61,8 @@ const Edit = props => { const { clientId, className, - isSelected, } = props - useGeneratedCss( props.attributes ) - const [ isOpen, setIsOpen ] = useState( props.attributes.startOpen ) const { hasInnerBlocks } = useBlockContext() const [ hasInitClickHandler, setHasInitClickHandler ] = useState( false ) @@ -123,57 +120,22 @@ const Edit = props => { 'stk--is-open': isOpen, // This opens the accordion in the editor. } ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - - - - - - + - + { blockCss && } { ) } +const InspectorControls = memo( () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/accordion/save.js b/src/block/accordion/save.js index a6ad73308..81e54c4ba 100644 --- a/src/block/accordion/save.js +++ b/src/block/accordion/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import BlockStyles from './style' - /** * External dependencies */ @@ -49,7 +44,7 @@ export const Save = props => { open={ attributes.startOpen || undefined } version={ props.version } > - + { attributes.generatedCss && } diff --git a/src/block/accordion/style.js b/src/block/accordion/style.js index 8a8c270db..345c590d4 100644 --- a/src/block/accordion/style.js +++ b/src/block/accordion/style.js @@ -9,50 +9,18 @@ import { EffectsAnimations, Transform, } from '~stackable/block-components' -import { BlockCssCompiler } from '~stackable/components' +import { BlockStyleGenerator } from '~stackable/components' -/** - * WordPress dependencies - */ -import { memo } from '@wordpress/element' - -const BlockStyles = memo( props => { - return ( - <> - - - - - - - - ) +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', } ) -BlockStyles.defaultProps = { - version: '', -} - -BlockStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - ) -} - -BlockStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +Alignment.addStyles( blockStyles ) +BlockDiv.addStyles( blockStyles ) +Column.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +EffectsAnimations.addStyles( blockStyles ) -export default BlockStyles +export default blockStyles diff --git a/src/block/blockquote/edit.js b/src/block/blockquote/edit.js index 2373417c6..6db7dcb26 100644 --- a/src/block/blockquote/edit.js +++ b/src/block/blockquote/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { ContainerStyles } from './style' +import blockStyles from './style' import SVGDefaultQuote from './images/round-thin.svg' import { QUOTE_ICONS } from './quotes' import variations from './variations' @@ -16,10 +16,10 @@ import { InspectorBottomTip, InspectorStyleControls, InspectorTabs, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, ContainerDiv, ConditionalDisplay, Alignment, @@ -44,7 +44,7 @@ import { */ import { InnerBlocks } from '@wordpress/block-editor' import { compose } from '@wordpress/compose' -import { renderToString } from '@wordpress/element' +import { renderToString, memo } from '@wordpress/element' import { __ } from '@wordpress/i18n' import { addFilter } from '@wordpress/hooks' @@ -54,12 +54,9 @@ const TEMPLATE = variations[ 0 ].innerBlocks const Edit = props => { const { - clientId, className, } = props - useGeneratedCss( props.attributes ) - const blockAlignmentClass = getAlignmentClasses( props.attributes ) const { hasInnerBlocks } = useBlockContext() @@ -75,30 +72,19 @@ const Edit = props => { 'stk-block-blockquote__content', ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) return ( <> - <> - - - - - - - - - - - - - - - - - - + { className={ blockClassNames } enableVariationPicker={ true } > - + { blockCss && } @@ -125,6 +107,32 @@ const Edit = props => { ) } +const InspectorControls = memo( () => { + return ( + <> + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/blockquote/save.js b/src/block/blockquote/save.js index 66c0eb9e1..45e2ce608 100644 --- a/src/block/blockquote/save.js +++ b/src/block/blockquote/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { ContainerStyles } from './style' - /** * External dependencies */ @@ -55,7 +50,7 @@ export const Save = props => { version={ props.version } data-v={ props.attributes.version } > - + { attributes.generatedCss && } { - return ( - <> - - - - - - - - - ) } ) +MarginBottom.addStyles( blockStyles ) -ContainerStyles.defaultProps = { - version: '', -} - -ContainerStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - ) -} - -ContainerStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +export default blockStyles diff --git a/src/block/button-group/edit.js b/src/block/button-group/edit.js index ff903d470..b718591d9 100644 --- a/src/block/button-group/edit.js +++ b/src/block/button-group/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { ButtonGroupStyles } from './style' +import blockStyles from './style' /** * External dependencies @@ -17,10 +17,10 @@ import { AlignButtonsControl, advancedToolbarControlControls, AdvancedToolbarControl, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, MarginBottom, getRowClasses, getAlignmentClasses, @@ -48,6 +48,7 @@ import { AlignmentToolbar, BlockControls, InnerBlocks, } from '@wordpress/block-editor' import { sprintf, __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' const ALLOWED_INNER_BLOCKS = [ 'stackable/button', 'stackable/icon-button' ] @@ -98,12 +99,9 @@ const Edit = props => { const { className, attributes, - clientId, setAttributes, } = props - useGeneratedCss( props.attributes ) - const { collapseOn = '', } = attributes @@ -148,67 +146,25 @@ const Edit = props => { } } + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - setAttributes( { contentAlign } ) } - alignmentControls={ TOOLBAR_ALIGN_OPTIONS } - /> - - - - - - - - - - - - - - - - + { attributes={ props.attributes } className={ blockClassNames } > - + { blockCss && } - { ! hasInnerBlocks && } - <> + { ! hasInnerBlocks && } + { hasInnerBlocks &&
{ templateInsertUpdatesSelection={ true } />
- + }
{ props.isHovered && hasInnerBlocks && } ) } +const InspectorControls = memo( props => { + return ( + <> + + + + + + props.setAttributes( { contentAlign } ) } + alignmentControls={ TOOLBAR_ALIGN_OPTIONS } + /> + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/button-group/save.js b/src/block/button-group/save.js index dae8b9d57..cf4409329 100644 --- a/src/block/button-group/save.js +++ b/src/block/button-group/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { ButtonGroupStyles } from './style' - /** * External dependencies */ @@ -58,7 +53,7 @@ export const Save = props => { attributes={ attributes } version={ props.version } > - + { attributes.generatedCss && }
diff --git a/src/block/button-group/style.js b/src/block/button-group/style.js index 5ac0c3880..7e807f244 100644 --- a/src/block/button-group/style.js +++ b/src/block/button-group/style.js @@ -7,277 +7,209 @@ import { BlockDiv, EffectsAnimations, MarginBottom, - FlexGapStyles, + addFlexGapStyles, Transform, } from '~stackable/block-components' -import { BlockCss, BlockCssCompiler } from '~stackable/components' +import { BlockStyleGenerator } from '~stackable/components' -/** - * WordPress dependencies - */ -import { memo } from '@wordpress/element' +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', +} ) -const flexGapOptionsEdit = { - selector: '.block-editor-block-list__layout', -} +blockStyles.addBlockStyles( 'flexWrap', [ { + renderIn: 'save', + selector: '.stk-button-group', + styleRule: 'flexWrap', + attrName: 'flexWrap', + key: 'flexWrap-save', + responsive: 'all', +}, { + renderIn: 'edit', + selector: '.stk-button-group .block-editor-block-list__layout', + styleRule: 'flexWrap', + attrName: 'flexWrap', + key: 'flexWrap', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device ) => { + // In the editor, it should correctly wrap in mobile. + if ( device === 'mobile' ) { + return 'wrap' + } + return value || 'nowrap' + }, +} ] ) -const flexGapOptionsSave = { - selector: '.stk-inner-blocks', -} +blockStyles.addBlockStyles( 'buttonAlign', [ { + renderIn: 'save', + selector: '.stk-button-group', + styleRule: 'flexDirection', + attrName: 'buttonAlign', + key: 'buttonAlign-save-group', + responsive: 'all', + valuePreCallback: value => { + if ( value === 'vertical' ) { + return 'column' + } -const Styles = props => { - const propsToPass = { - ...props, - version: props.version, - versionAdded: '3.0.0', - versionDeprecated: '', - } + return 'row' + }, +}, { + renderIn: 'edit', + selector: '.stk-button-group .block-editor-block-list__layout', + styleRule: 'flexDirection', + attrName: 'buttonAlign', + key: 'buttonAlign-list-layout', + responsive: 'all', + valuePreCallback: value => { + if ( value === 'vertical' ) { + return 'column' + } else if ( value === 'horizontal' ) { + return 'row' + } + return value + }, +}, { +// If the buttons are set to vertical, we also need to reset the flex +// basis or else full-width buttons (set per button block) will overlap +// each other vertically. + renderIn: 'save', + selector: '.stk-block', + styleRule: 'flexBasis', + attrName: 'buttonAlign', + key: 'buttonAlign-save-block', + responsive: 'all', + valuePreCallback: value => { + return value === 'vertical' ? 'auto' + : value === 'horizontal' ? 0 + : undefined + }, +}, { + renderIn: 'save', + selector: '.stk-button-group', + styleRule: 'alignItems', + attrName: 'buttonAlign', + key: 'buttonAlign-save-button-group', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device ) => { + const getInherited = true + const contentAlign = getAttribute( 'contentAlign', device, 'normal', getInherited ) - return ( - <> - - { - // In the editor, it should correctly wrap in mobile. - if ( device === 'mobile' ) { - return 'wrap' - } - return value || 'nowrap' - } } - /> - { - if ( value === 'vertical' ) { - return 'column' - } else if ( value === 'horizontal' ) { - return 'row' - } - return value - } } - /> - { - if ( value === 'vertical' ) { - return 'column' - } else if ( value === 'horizontal' ) { - return 'row' - } - return value - } } - /> + if ( value === 'vertical' ) { + const buttonFullWidth = getAttribute( 'buttonFullWidth' ) + if ( buttonFullWidth ) { + return 'stretch' + } + if ( contentAlign === 'center' ) { + return 'center' + } else if ( contentAlign === 'right' ) { + return 'flex-end' + } + return 'flex-start' + } else if ( value === 'horizontal' ) { + return 'center' + } + return value + }, + dependencies: [ 'contentAlign', 'buttonFullWidth' ], +}, { + renderIn: 'edit', + selector: '.stk-button-group .block-editor-block-list__layout', + styleRule: 'alignItems', + attrName: 'buttonAlign', + key: 'buttonAlign-group-list-layout', + responsive: 'all', + valuePreCallback: ( value, getAttribute, device ) => { + const getInherited = true + const contentAlign = getAttribute( 'contentAlign', device, 'normal', getInherited ) - { - // If the buttons are set to vertical, we also need to reset the flex - // basis or else full-width buttons (set per button block) will overlap - // each other vertically. + if ( value === 'vertical' ) { + const buttonFullWidth = getAttribute( 'buttonFullWidth' ) + if ( buttonFullWidth ) { + return 'stretch' + } + if ( contentAlign === 'center' ) { + return 'center' + } else if ( contentAlign === 'right' ) { + return 'flex-end' } - { - return value === 'vertical' ? 'auto' - : value === 'horizontal' ? 0 - : undefined - } } - /> - { - const getInherited = true - const contentAlign = getAttribute( 'contentAlign', device, 'normal', getInherited ) + return 'flex-start' + } else if ( value === 'horizontal' ) { + return 'center' + } + return value + }, + dependencies: [ 'contentAlign', 'buttonFullWidth' ], +} ] ) - if ( value === 'vertical' ) { - const buttonFullWidth = getAttribute( 'buttonFullWidth' ) - if ( buttonFullWidth ) { - return 'stretch' - } - if ( contentAlign === 'center' ) { - return 'center' - } else if ( contentAlign === 'right' ) { - return 'flex-end' - } - return 'flex-start' - } else if ( value === 'horizontal' ) { - return 'center' - } - return value - } } - dependencies={ [ 'contentAlign', 'buttonFullWidth' ] } - /> - { - const getInherited = true - const contentAlign = getAttribute( 'contentAlign', device, 'normal', getInherited ) +blockStyles.addBlockStyles( 'buttonFullWidth', [ { + renderIn: 'save', + selector: '.stk-block-button, .stk-block-icon-button', + styleRule: 'flex', + attrName: 'buttonFullWidth', + key: 'buttonFullWidth-save', + valueCallback: ( value, getAttribute ) => { + let basis = '0%' // This is the default value of flex-basis + // If we're wrapping, we need to set flex-basis to auto so + // that it will wrap and go full-width. + if ( getAttribute( 'flexWrap' ) ) { + basis = 'auto' + } + return value ? ( '1 0 ' + basis ) : undefined + }, + dependencies: [ 'flexWrap' ], +}, { + renderIn: 'edit', + selector: `.stk-block-button, .stk-block-icon-button, [data-type^="stackable/"]`, + styleRule: 'flex', + attrName: 'buttonFullWidth', + key: 'buttonFullWidth', + valueCallback: ( value, getAttribute ) => { + let basis = '0%' // This is the default value of flex-basis + // If we're wrapping, we need to set flex-basis to auto so + // that it will wrap and go full-width. + if ( getAttribute( 'flexWrap' ) ) { + basis = 'auto' + } + return value ? ( '1 0 ' + basis ) : undefined + }, + dependencies: [ 'flexWrap' ], +} ] ) - if ( value === 'vertical' ) { - const buttonFullWidth = getAttribute( 'buttonFullWidth' ) - if ( buttonFullWidth ) { - return 'stretch' - } - if ( contentAlign === 'center' ) { - return 'center' - } else if ( contentAlign === 'right' ) { - return 'flex-end' - } - return 'flex-start' - } else if ( value === 'horizontal' ) { - return 'center' - } - return value - } } - dependencies={ [ 'contentAlign', 'buttonFullWidth' ] } - /> - { - let basis = '0%' // This is the default value of flex-basis - // If we're wrapping, we need to set flex-basis to auto so - // that it will wrap and go full-width. - if ( getAttribute( 'flexWrap' ) ) { - basis = 'auto' - } - return value ? ( '1 0 ' + basis ) : undefined - } } - dependencies={ [ 'flexWrap' ] } - /> - { - let basis = '0%' // This is the default value of flex-basis - // If we're wrapping, we need to set flex-basis to auto so - // that it will wrap and go full-width. - if ( getAttribute( 'flexWrap' ) ) { - basis = 'auto' - } - return value ? ( '1 0 ' + basis ) : undefined - } } - dependencies={ [ 'flexWrap' ] } - /> - { - return value ? 'auto' : undefined - } } - /> - { - return value ? 'unset' : undefined - } } - /> - - ) -} +blockStyles.addBlockStyles( 'flexWrap', [ { + renderIn: 'save', + selector: '.stk-button-group', + styleRule: '--stk-button-group-flex-wrap', + attrName: 'flexWrap', + key: 'flexWrap-save-button-group', + responsive: 'all', + valueCallback: value => { + return value ? 'auto' : undefined + }, +}, { + renderIn: 'save', + selector: '.stk-button-group .stk-block-button', + styleRule: 'width', + attrName: 'flexWrap', + key: 'flexWrap-save-button-group-unset-width', + responsive: 'all', + valueCallback: value => { + return value ? 'unset' : undefined + }, +} ] ) -export const ButtonGroupStyles = memo( props => { - return ( - <> - - - - - - - - - - ) +Alignment.addStyles( blockStyles ) +BlockDiv.addStyles( blockStyles, { + verticalAlignSelectorEdit: '.stk-button-group > .block-editor-inner-blocks > .block-editor-block-list__layout', + verticalAlignSelectorSave: '.stk-button-group', +} ) +MarginBottom.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +EffectsAnimations.addStyles( blockStyles ) +addFlexGapStyles( blockStyles, { + editSelector: '.block-editor-block-list__layout', + saveSelector: '.stk-inner-blocks', } ) -ButtonGroupStyles.defaultProps = { - version: '', -} - -ButtonGroupStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - - ) -} - -ButtonGroupStyles.Content.defaultProps = { - version: '', - attributes: {}, -} - +export default blockStyles diff --git a/src/block/button-group/variations.js b/src/block/button-group/variations.js index f341e34aa..8753be419 100644 --- a/src/block/button-group/variations.js +++ b/src/block/button-group/variations.js @@ -31,6 +31,12 @@ const variations = [ 'stk-type': 'essential', 'stk-demo': 'https://wpstackable.com/button-block/?utm_source=welcome&utm_medium=settings&utm_campaign=view_demo&utm_content=demolink', isDefault: true, + innerBlocks: [ + [ + 'stackable/button', + {}, + ], + ], example: buttonExample, }, { diff --git a/src/block/button/edit.js b/src/block/button/edit.js index 23e3dcf0a..8fc08c1c0 100644 --- a/src/block/button/edit.js +++ b/src/block/button/edit.js @@ -3,11 +3,10 @@ */ import classnames from 'classnames' import { version as VERSION, i18n } from 'stackable' -import { InspectorTabs } from '~stackable/components' +import { InspectorTabs, useBlockCssGenerator } from '~stackable/components' import { getTypographyClasses, BlockDiv, - useGeneratedCss, Advanced, CustomCSS, Responsive, @@ -34,11 +33,12 @@ import { __ } from '@wordpress/i18n' import { compose } from '@wordpress/compose' import { createBlock } from '@wordpress/blocks' import { AlignmentToolbar, BlockControls } from '@wordpress/block-editor' +import { memo } from '@wordpress/element' /** * Internal dependencies */ -import { ButtonStyles } from './style' +import buttonStyles from './style' import { blockStyles } from './block-styles' const Edit = props => { @@ -47,11 +47,8 @@ const Edit = props => { onReplace, attributes, setAttributes, - clientId, } = props - useGeneratedCss( props.attributes ) - const typographyInnerClasses = getTypographyClasses( props.attributes ) const customAttributes = CustomAttributes.getCustomAttributes( props.attributes ) @@ -75,49 +72,25 @@ const Edit = props => { 'stk-button__inner-text', ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles: buttonStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - setAttributes( { contentAlign } ) } - /> - - - - - - - - - - - - - - - - - - - - - - + { blockCss && } { ) } +const InspectorControls = memo( props => { + return ( + <> + + props.setAttributes( { contentAlign } ) } + /> + + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapper, withQueryLoopContext, diff --git a/src/block/button/save.js b/src/block/button/save.js index a3f836c04..65c965e5d 100644 --- a/src/block/button/save.js +++ b/src/block/button/save.js @@ -21,11 +21,6 @@ import { import { compose } from '@wordpress/compose' import { useBlockProps } from '@wordpress/block-editor' -/** - * Internal dependencies - */ -import { ButtonStyles } from './style' - export const Save = props => { const { className, @@ -57,7 +52,7 @@ export const Save = props => { applyCustomAttributes={ false } version={ props.version } > - + { props.attributes.generatedCss && } `.editor-styles-wrapper [data-block="${ clientId }"]`, + styleRule: 'width', + attrName: 'buttonFullWidth', + key: 'buttonFullWidth', + valueCallback: value => { + return value ? '100%' : undefined + }, +} ] ) + +BlockDiv.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +Button.addStyles( blockStyles, { selector: '.stk-button', -} - -const typographyOptions = { +} ) +Typography.addStyles( blockStyles, { selector: '.stk-button__inner-text', hoverSelector: '.stk-button:hover .stk-button__inner-text', -} - -const Styles = props => { - const propsToPass = { - ...props, - version: props.version, - versionAdded: '3.0.0', - versionDeprecated: '', - } - - return ( - <> - `.editor-styles-wrapper [data-block="${ clientId }"]` } - styleRule="width" - attrName="buttonFullWidth" - key="buttonFullWidth" - valueCallback={ value => { - return value ? '100%' : undefined - } } - /> - - ) -} - -export const ButtonStyles = memo( props => { - return ( - <> - - - - - - - - - ) } ) +EffectsAnimations.addStyles( blockStyles ) -ButtonStyles.defaultProps = { - version: '', -} - -ButtonStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - ) -} - -ButtonStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +export default blockStyles diff --git a/src/block/call-to-action/edit.js b/src/block/call-to-action/edit.js index 450686e7b..83062f94d 100644 --- a/src/block/call-to-action/edit.js +++ b/src/block/call-to-action/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { ContainerStyles } from './style' +import blockStyles from './style' import variations from './variations' /** @@ -14,10 +14,10 @@ import { InspectorBottomTip, InspectorStyleControls, InspectorTabs, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, ContainerDiv, ConditionalDisplay, Alignment, @@ -46,17 +46,15 @@ import { import { InnerBlocks } from '@wordpress/block-editor' import { compose } from '@wordpress/compose' import { __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' const TEMPLATE = variations[ 0 ].innerBlocks const Edit = props => { const { - clientId, className, } = props - useGeneratedCss( props.attributes ) - const { hasInnerBlocks, innerBlocks } = useBlockContext() const blockAlignmentClass = getAlignmentClasses( props.attributes ) const separatorClass = getSeparatorClasses( props.attributes ) @@ -78,30 +76,20 @@ const Edit = props => { const lastBlockName = last( innerBlocks )?.name const renderAppender = hasInnerBlocks ? ( [ 'stackable/text', 'core/paragraph' ].includes( lastBlockName ) ? () => <> : InnerBlocks.DefaultBlockAppender ) : InnerBlocks.ButtonBlockAppender + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - - - + { className={ blockClassNames } enableVariationPicker={ true } > - + { blockCss && } @@ -131,6 +115,32 @@ const Edit = props => { ) } +const InspectorControls = memo( () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/call-to-action/save.js b/src/block/call-to-action/save.js index 1d62c520e..961fd3333 100644 --- a/src/block/call-to-action/save.js +++ b/src/block/call-to-action/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { ContainerStyles } from './style' - /** * External dependencies */ @@ -66,7 +61,7 @@ export const Save = props => { version={ props.version } data-v={ props.attributes.version } > - + { attributes.generatedCss && } { - return ( - <> - - - - - - - - - - ) } ) +MarginBottom.addStyles( blockStyles ) +Separator.addStyles( blockStyles ) -ContainerStyles.defaultProps = { - version: '', -} - -ContainerStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - - ) -} - -ContainerStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +export default blockStyles diff --git a/src/block/card/edit.js b/src/block/card/edit.js index 6cdb8b3ff..e83140bd7 100644 --- a/src/block/card/edit.js +++ b/src/block/card/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { CardStyles } from './style' +import blockStyles from './style' import variations from './variations' /** @@ -14,6 +14,7 @@ import { InspectorBottomTip, InspectorStyleControls, InspectorTabs, + useBlockCssGenerator, } from '~stackable/components' import { useBlockContext, useBlockStyle, useDeviceType, @@ -25,7 +26,6 @@ import { } from '~stackable/higher-order' import { BlockDiv, - useGeneratedCss, Image, getAlignmentClasses, Alignment, @@ -48,6 +48,7 @@ import { import { InnerBlocks } from '@wordpress/block-editor' import { compose } from '@wordpress/compose' import { __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' const TEMPLATE = variations[ 0 ].innerBlocks @@ -63,10 +64,7 @@ const Edit = props => { hasContainer, } = props.attributes - useGeneratedCss( props.attributes ) - const { - clientId, className, //isHovered, } = props @@ -106,45 +104,25 @@ const Edit = props => { const imageWidthUnit = props.attributes.imageWidthUnit || 'px' const imageHeightUnit = props.attributes.imageHeightUnit || 'px' + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - - - + + { blockCss && } { ) } +const InspectorControls = memo( props => { + return ( + <> + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/card/save.js b/src/block/card/save.js index e6feb4420..75a5005d2 100644 --- a/src/block/card/save.js +++ b/src/block/card/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { CardStyles } from './style' - /** * External dependencies */ @@ -72,7 +67,7 @@ export const Save = props => { version={ props.version } data-v={ props.attributes.version } > - + { attributes.generatedCss && } { attributes.uniqueId && { - const className = useBlockAttributesContext( attributes => attributes.className ) - const blockStyle = getBlockStyle( variations, className ) - - return ( - <> - - - - - - - - { - if ( blockStyle.name === 'horizontal' ) { - if ( device === 'tablet' ) { - return 'px' - } - } - return unit - } } - enableAspectRatio={ ! [ 'horizontal', 'full', 'faded' ].includes( blockStyle.name ) } - selector=".stk-block-card__image" - /> - - ) +} ) +Image.addStyles( blockStyles, { + enableWidthCallback: getAttribute => { + const className = getAttribute( 'className' ) + const blockStyle = getBlockStyle( variations, className ) + return blockStyle.name === 'horizontal' + }, + editorWidthUnitCallback: ( unit, device, state, getAttribute ) => { + const className = getAttribute( 'className' ) + const blockStyle = getBlockStyle( variations, className ) + if ( blockStyle.name === 'horizontal' ) { + if ( device === 'tablet' ) { + return 'px' + } + } + return unit + }, + enableAspectRatio: getAttribute => { + const className = getAttribute( 'className' ) + const blockStyle = getBlockStyle( variations, className ) + return ! [ 'horizontal', 'full', 'faded' ].includes( blockStyle.name ) + }, + selector: '.stk-block-card__image', } ) -CardStyles.defaultProps = { - version: '', -} - -CardStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - const blockStyle = getBlockStyle( variations, props.attributes.className ) - - return ( - - - - - - - - - - - ) -} - -CardStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +export default blockStyles diff --git a/src/block/carousel/edit.js b/src/block/carousel/edit.js index a7fc614db..4f11b1035 100644 --- a/src/block/carousel/edit.js +++ b/src/block/carousel/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import BlockStyles from './style' +import blockStyles from './style' /** * External dependencies @@ -24,10 +24,10 @@ import { ColorPaletteControl, InspectorAdvancedControls, AdvancedTextControl, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, MarginBottom, getRowClasses, Alignment, @@ -55,7 +55,7 @@ import { * WordPress dependencies */ import { - useState, useRef, useEffect, + useState, useRef, useEffect, memo, } from '@wordpress/element' import { compose } from '@wordpress/compose' import { __, sprintf } from '@wordpress/i18n' @@ -73,13 +73,10 @@ const TEMPLATE = [ const Edit = props => { const { className, - clientId, attributes, setAttributes, } = props - useGeneratedCss( props.attributes ) - const rowClass = getRowClasses( props.attributes ) const separatorClass = getSeparatorClasses( props.attributes ) const blockAlignmentClass = getAlignmentClasses( props.attributes ) @@ -252,401 +249,38 @@ const Edit = props => { } }, [ maxSlides, activeSlide ] ) - const sizeControlSpacingProps = { - enableMargin: false, - } + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - { carouselType === 'slide' && - setAttributes( { infiniteScroll } ) } - defaultValue={ false } - help={ __( 'Only visible in the frontend.', i18n ) } - /> - } - { carouselType === 'slide' && ( - <> - - - - ) } - { carouselType === 'fade' && ( - - ) } - - - setAttributes( { autoplay } ) } - defaultValue={ true } - /> - { attributes.autoplay && ( - - ) } - - - - - setAttributes( { showArrows } ) } - > - { - if ( arrowIconPrev === defaultIcon.prev ) { - setAttributes( { arrowIconPrev: '' } ) - } else { - setAttributes( { arrowIconPrev } ) - } - } } - /> - { - if ( arrowIconNext === defaultIcon.next ) { - setAttributes( { arrowIconNext: '' } ) - } else { - setAttributes( { arrowIconNext } ) - } - } } - /> - { - setAttributes( { - arrowPosition, - arrowJustify: '', - arrowAlign: '', - } ) - } } - /> - - { - if ( ! arrowAlign && attributes.arrowPosition === 'outside' ) { - setAttributes( { - arrowAlign, - arrowJustify: '', - } ) - } else { - setAttributes( { arrowAlign } ) - } - } } - /> - - { [ 'flex-start', 'center', 'flex-end' ].includes( attributes.arrowJustify ) && - - } - - - - - - - - - setAttributes( { showArrowsOnMobile } ) } - defaultValue={ true } - /> - - - setAttributes( { showDots } ) } - > - - - - - - - - - - - - - - - setAttributes( { showDotsOnMobile } ) } - defaultValue={ true } - /> - - - - - - - - - - - - - - - - - - - - - - - - + { attributes={ props.attributes } className={ blockClassNames } > - + { blockCss && } { ! hasInnerBlocks && } @@ -753,6 +383,404 @@ const Edit = props => { ) } +const InspectorControls = memo( props => { + const sizeControlSpacingProps = { + enableMargin: false, + } + return ( + <> + + + + + + { props.carouselType === 'slide' && + props.setAttributes( { infiniteScroll } ) } + defaultValue={ false } + help={ __( 'Only visible in the frontend.', i18n ) } + /> + } + { props.carouselType === 'slide' && ( + <> + + + + ) } + { props.carouselType === 'fade' && ( + + ) } + + + props.setAttributes( { autoplay } ) } + defaultValue={ true } + /> + { props.autoplay && ( + + ) } + + + + + props.setAttributes( { showArrows } ) } + > + { + if ( arrowIconPrev === props.defaultIcon.prev ) { + props.setAttributes( { arrowIconPrev: '' } ) + } else { + props.setAttributes( { arrowIconPrev } ) + } + } } + /> + { + if ( arrowIconNext === props.defaultIcon.next ) { + props.setAttributes( { arrowIconNext: '' } ) + } else { + props.setAttributes( { arrowIconNext } ) + } + } } + /> + { + props.setAttributes( { + arrowPosition, + arrowJustify: '', + arrowAlign: '', + } ) + } } + /> + + { + if ( ! arrowAlign && props.arrowPosition === 'outside' ) { + props.setAttributes( { + arrowAlign, + arrowJustify: '', + } ) + } else { + props.setAttributes( { arrowAlign } ) + } + } } + /> + + { [ 'flex-start', 'center', 'flex-end' ].includes( props.arrowJustify ) && + + } + + + + + + + + + props.setAttributes( { showArrowsOnMobile } ) } + defaultValue={ true } + /> + + + props.setAttributes( { showDots } ) } + > + + + + + + + + + + + + + + + props.setAttributes( { showDotsOnMobile } ) } + defaultValue={ true } + /> + + + + + + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/carousel/save.js b/src/block/carousel/save.js index a58d22ec3..39ce16570 100644 --- a/src/block/carousel/save.js +++ b/src/block/carousel/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import BlockStyles from './style' - /** * External dependencies */ @@ -76,7 +71,7 @@ export const Save = props => { version={ props.version } data-slides-to-show={ attributes.slidesToShow } > - + { attributes.generatedCss && }
diff --git a/src/block/carousel/style.js b/src/block/carousel/style.js index 0e5f52c47..753053e5c 100644 --- a/src/block/carousel/style.js +++ b/src/block/carousel/style.js @@ -10,289 +10,222 @@ import { Separator, Transform, } from '~stackable/block-components' -import { useBlockAttributesContext } from '~stackable/hooks' -import { BlockCss, BlockCssCompiler } from '~stackable/components' +// import { useBlockAttributesContext } from '~stackable/hooks' +// import { applyFilters } from '@wordpress/hooks' +import { BlockStyleGenerator } from '~stackable/components' -/** - * WordPress dependencies - */ -import { memo } from '@wordpress/element' -import { applyFilters } from '@wordpress/hooks' +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', +} ) -const alignmentOptions = { - editorSelectorCallback: getAttribute => `.stk--block-align-${ getAttribute( 'uniqueId' ) } > .block-editor-inner-blocks > .block-editor-block-list__layout`, -} +blockStyles.addBlockStyles( 'slidesToShow', [ { + styleRule: '--slides-to-show', + attrName: 'slidesToShow', + key: 'slidesToShow', + responsive: 'all', +} ] ) -const Styles = props => { - const propsToPass = { - ...props, - version: props.version, - versionAdded: '3.8.0', - versionDeprecated: '', - } +blockStyles.addBlockStyles( 'slideColumnGap', [ { + styleRule: '--gap', + attrName: 'slideColumnGap', + key: 'slideColumnGap', + format: '%spx', + responsive: 'all', +} ] ) - return ( - <> - - - +blockStyles.addBlockStyles( 'fadeDuration', [ { + styleRule: '--transition-duration', + attrName: 'fadeDuration', + key: 'fadeDuration', + format: '%ss', +} ] ) - { /* Arrows */ } - - getAttribute( 'arrowPosition' ) !== 'outside' } - dependencies={ [ 'arrowPosition' ] } - /> - - - - - - - - - - - +{ /* Arrows */ } +blockStyles.addBlockStyles( 'arrowJustify', [ { + selector: '.stk-block-carousel__buttons', + styleRule: 'justifyContent', + attrName: 'arrowJustify', + key: 'arrowJustify', +} ] ) - { /* Dots */ } - - - - - - - - - - - ) -} +blockStyles.addBlockStyles( 'arrowAlign', [ { + selector: '.stk-block-carousel__buttons', + styleRule: 'alignItems', + attrName: 'arrowAlign', + key: 'arrowAlign', + enabledCallback: getAttribute => getAttribute( 'arrowPosition' ) !== 'outside', + dependencies: [ 'arrowPosition' ], +} ] ) -const BlockStyles = memo( props => { - const columnArrangement = useBlockAttributesContext( attributes => attributes.columnArrangementMobile || attributes.columnArrangementTablet ) - const numColumns = ( columnArrangement || '' ).split( ',' ).length +blockStyles.addBlockStyles( 'arrowButtonOffset', [ { + styleRule: '--button-offset', + attrName: 'arrowButtonOffset', + key: 'arrowButtonOffset', + format: '%spx', + responsive: 'all', +} ] ) - const ColumnOrderStyle = applyFilters( 'stackable.block-component.columns.column-order-style', null ) +blockStyles.addBlockStyles( 'arrowButtonGap', [ { + styleRule: '--button-gap', + attrName: 'arrowButtonGap', + key: 'arrowButtonGap', + format: '%spx', + responsive: 'all', +} ] ) - return ( - <> - - - - - - - - - { ColumnOrderStyle && } - - ) -} ) +blockStyles.addBlockStyles( 'arrowButtonColor', [ { + selector: '.stk-block-carousel__button', + hoverSelector: '.stk-block-carousel__button:hover', + styleRule: 'background', + attrName: 'arrowButtonColor', + key: 'arrowButtonColor', + hover: 'all', +} ] ) + +blockStyles.addBlockStyles( 'arrowIconColor', [ { + selector: '.stk-block-carousel__button', + hoverSelector: '.stk-block-carousel__button:hover', + styleRule: 'fill', + attrName: 'arrowIconColor', + key: 'arrowIconColor', + hover: 'all', +}, { + selector: '.stk-block-carousel__button svg.ugb-custom-icon :is(g,path,rect,polygon,ellipse)', + hoverSelector: '.stk-block-carousel__button svg.ugb-custom-icon :is(g,path,rect,polygon,ellipse):hover', + styleRule: 'fill', + attrName: 'arrowIconColor', + key: 'arrowIconColor', + hover: 'all', +} ] ) + +blockStyles.addBlockStyles( 'arrowWidth', [ { + styleRule: '--button-width', + attrName: 'arrowWidth', + key: 'arrowWidth', + hasUnits: 'px', + responsive: 'all', +} ] ) + +blockStyles.addBlockStyles( 'arrowHeight', [ { + styleRule: '--button-height', + attrName: 'arrowHeight', + key: 'arrowHeight', + hasUnits: 'px', + responsive: 'all', +} ] ) + +blockStyles.addBlockStyles( 'arrowBorderRadius', [ { + selector: '.stk-block-carousel__button', + styleRule: 'borderRadius', + attrName: 'arrowBorderRadius', + key: 'arrowBorderRadius', + format: '%spx', +} ] ) -BlockStyles.defaultProps = { - version: '', -} +blockStyles.addBlockStyles( 'arrowIconSize', [ { + selector: '.stk-block-carousel__button svg', + styleRule: 'width', + attrName: 'arrowIconSize', + key: 'arrowIconSize-width', + format: '%spx', + responsive: 'all', +}, { + selector: '.stk-block-carousel__button svg', + styleRule: 'height', + attrName: 'arrowIconSize', + key: 'arrowIconSize-height', + format: '%spx', + responsive: 'all', +} ] ) -BlockStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } +blockStyles.addBlockStyles( 'arrowOpacity', [ { + selector: '.stk-block-carousel__button', + hoverSelector: '.stk-block-carousel__button:hover', + styleRule: 'opacity', + attrName: 'arrowOpacity', + key: 'arrowOpacity', + hover: 'all', +} ] ) - const numColumns = ( props.attributes.columnArrangementMobile || props.attributes.columnArrangementTablet || '' ).split( ',' ).length - const ColumnOrderStyle = applyFilters( 'stackable.block-component.columns.column-order-style', null ) +{ /* Dots */ } +blockStyles.addBlockStyles( 'dotsJustify', [ { + selector: '.stk-block-carousel__dots', + styleRule: 'justifyContent', + attrName: 'dotsJustify', + key: 'dotsJustify', +} ] ) - return ( - - - - - - - - - - { ColumnOrderStyle && } - - ) -} +blockStyles.addBlockStyles( 'dotsOffset', [ { + selector: '.stk-block-carousel__dots', + styleRule: '--dot-offset', + attrName: 'dotsOffset', + key: 'dotsOffset', + format: '%spx', + responsive: 'all', +} ] ) -BlockStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +blockStyles.addBlockStyles( 'dotsGap', [ { + styleRule: '--dot-gap', + attrName: 'dotsGap', + key: 'dotsGap', + format: '%spx', +} ] ) + +blockStyles.addBlockStyles( 'dotsColor', [ { + selector: '.stk-block-carousel__dot', + hoverSelector: '.stk-block-carousel__dot', + styleRule: '--dot-color', + hoverStyleRule: '--dot-color-hover', + attrName: 'dotsColor', + key: 'dotsColor', + hover: 'all', +} ] ) + +blockStyles.addBlockStyles( 'dotsActiveColor', [ { + selector: '.stk-block-carousel__dot.stk-block-carousel__dot--active:before', + styleRule: 'backgroundColor', + attrName: 'dotsActiveColor', + key: 'dotsActiveColor', +} ] ) + +blockStyles.addBlockStyles( 'dotsSize', [ { + styleRule: '--dot-size', + attrName: 'dotsSize', + key: 'dotsSize', + format: '%spx', +} ] ) + +blockStyles.addBlockStyles( 'dotsBorderRadius', [ { + selector: '.stk-block-carousel__dot:before', + styleRule: 'borderRadius', + attrName: 'dotsBorderRadius', + key: 'dotsBorderRadius', + format: '%spx', +} ] ) + +blockStyles.addBlockStyles( 'dotsActiveWidth', [ { + styleRule: '--dot-active-width', + attrName: 'dotsActiveWidth', + key: 'dotsActiveWidth', + format: '%spx', +} ] ) + +blockStyles.addBlockStyles( 'dotsActiveHeight', [ { + styleRule: '--dot-active-height', + attrName: 'dotsActiveHeight', + key: 'dotsActiveHeight', + format: '%spx', +} ] ) + +Alignment.addStyles( blockStyles, { + editorSelectorCallback: getAttribute => `.stk--block-align-${ getAttribute( 'uniqueId' ) } > .block-editor-inner-blocks > .block-editor-block-list__layout`, +} ) +BlockDiv.addStyles( blockStyles ) +MarginBottom.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +EffectsAnimations.addStyles( blockStyles ) +Separator.addStyles( blockStyles ) -export default BlockStyles +export default blockStyles diff --git a/src/block/column/edit.js b/src/block/column/edit.js index 77cacedda..e42354432 100644 --- a/src/block/column/edit.js +++ b/src/block/column/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import BlockStyles from './style' +import blockStyles from './style' /** * External dependencies @@ -13,8 +13,8 @@ import { FourRangeControl, InspectorLayoutControls, InspectorTabs, + useBlockCssGenerator, } from '~stackable/components' -import { useBlockContext } from '~stackable/hooks' import { withBlockAttributeContext, withBlockWrapperIsHovered, @@ -24,7 +24,6 @@ import { Column, getColumnClasses, BlockDiv, - useGeneratedCss, getAlignmentClasses, Alignment, Advanced, @@ -47,27 +46,47 @@ import { compose } from '@wordpress/compose' import { InnerBlocks } from '@wordpress/block-editor' import { __ } from '@wordpress/i18n' import { applyFilters } from '@wordpress/hooks' +import { useSelect } from '@wordpress/data' +import { memo } from '@wordpress/element' -const Edit = props => { - const { - hasInnerBlocks, isOnlyBlock, parentBlock, - } = useBlockContext() +const ButtonBlockAppender = memo( props => { + return +} ) +const Edit = props => { const { + clientId, className, isHovered, - clientId, } = props - useGeneratedCss( props.attributes ) + const { + hasInnerBlocks, isOnlyBlock, useZeroColumnSpacing, parentBlock, + } = useSelect( + select => { + const { + getBlockOrder, getBlockRootClientId, getBlock, + } = + select( 'core/block-editor' ) + + const rootClientId = getBlockRootClientId( clientId ) + const parentBlock = getBlock( rootClientId ) + + return { + hasInnerBlocks: getBlockOrder( clientId ).length > 0, + rootClientId, + isOnlyBlock: getBlockOrder( rootClientId ).length === 1, + parentBlock, + useZeroColumnSpacing: ! [ 'stackable/timeline' ].includes( parentBlock.name ), + } + }, + [ clientId ] + ) const blockOrientation = getBlockOrientation( props.attributes ) const [ columnClass, columnWrapperClass ] = getColumnClasses( props.attributes ) const blockAlignmentClass = getAlignmentClasses( props.attributes ) - const nonZeroColumnSpacingBlocks = [ 'stackable/timeline' ] - const useZeroColumnSpacing = parentBlock ? ! nonZeroColumnSpacingBlocks.includes( parentBlock.name ) : false - const ALLOWED_INNER_BLOCKS = applyFilters( 'stackable.block.column.allowed-inner-blocks', undefined, props ) const blockClassNames = classnames( [ @@ -86,64 +105,38 @@ const Edit = props => { { 'stk--align-last-block-to-bottom': props.attributes.alignLastBlockToBottom }, ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - - <> - - - - - - - - - - - - - - - - - - - props.setAttributes( { alignLastBlockToBottom } ) } - /> - - - - - - + { blockCss && } - + { allowedBlocks={ ALLOWED_INNER_BLOCKS } templateLock={ props.attributes.templateLock || false } orientation={ blockOrientation } - renderAppender={ ! hasInnerBlocks ? InnerBlocks.ButtonBlockAppender : InnerBlocks.DefaultBlockAppender } + renderAppender={ hasInnerBlocks ? undefined : ButtonBlockAppender } /> @@ -166,6 +159,59 @@ const Edit = props => { ) } +// Inspector controls for the block, it's important that we only pass only the +// props used by controls to prevent rerenders of all the inspector controls. +const InspectorControls = memo( props => { + return ( + <> + + + + + + + + + + + + + + + + + + + props.setAttributes( { alignLastBlockToBottom } ) } + /> + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/column/save.js b/src/block/column/save.js index 9f08d1bf9..0b1dca47c 100644 --- a/src/block/column/save.js +++ b/src/block/column/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import BlockStyles from './style' - /** * External dependencies */ @@ -65,7 +60,7 @@ export const Save = props => { version={ props.version } data-v={ props.attributes.version } > - + { attributes.generatedCss && } .block-editor-inner-blocks > .block-editor-block-list__layout', - // sizeVerticalAlignSelectorEdit: '.%s-inner-blocks', -} +import { BlockStyleGenerator } from '~stackable/components' const callbacks = { marginTop: { @@ -41,154 +27,108 @@ const callbacks = { }, } -const ColumnStyles = props => { - const propsToPass = { - ...props, - version: props.version, - versionAdded: '3.0.0', - versionDeprecated: '', - } - - return ( - <> - - - - - - { - // The styles below are used purely for the block highligher feature - // where the edges of the element where the padding will be applied - // is highlighted. - } - - - - - - ) -} - -const BlockStyles = memo( props => { - return ( - <> - - `[data-block="${ clientId }"]` } - /> - - - - - - - - ) +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', } ) -BlockStyles.defaultProps = { - version: '', -} +blockStyles.addBlockStyles( 'columnSpacing', [ { + selector: '.%s-container', + styleRule: 'marginTop', + attrName: 'columnSpacing', + key: 'columnSpacing-top', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginTop.valuePreCallback, +}, +{ + selector: '.%s-container', + styleRule: 'marginRight', + attrName: 'columnSpacing', + key: 'columnSpacing-right', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginRight.valuePreCallback, +}, +{ + selector: '.%s-container', + styleRule: 'marginBottom', + attrName: 'columnSpacing', + key: 'columnSpacing-bottom', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginBottom.valuePreCallback, +}, +{ + selector: '.%s-container', + styleRule: 'marginLeft', + attrName: 'columnSpacing', + key: 'columnSpacing-left', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginLeft.valuePreCallback, +}, -BlockStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } +// The styles below are used purely for the block highligher feature +// where the edges of the element where the padding will be applied +// is highlighted. - return ( - - - - - - - - - - - ) -} +{ + renderIn: 'edit', + selector: '.%s-container', + styleRule: '--column-spacing-top', + attrName: 'columnSpacing', + key: 'columnSpacing-top-edit-for-highlight', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginTop.valuePreCallback, +}, +{ + renderIn: 'edit', + selector: '.%s-container', + styleRule: '--column-spacing-right', + attrName: 'columnSpacing', + key: 'columnSpacing-right-edit-for-highlight', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginRight.valuePreCallback, +}, +{ + renderIn: 'edit', + selector: '.%s-container', + styleRule: '--column-spacing-bottom', + attrName: 'columnSpacing', + key: 'columnSpacing-bottom-edit-for-highlight', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginBottom.valuePreCallback, +}, +{ + renderIn: 'edit', + selector: '.%s-container', + styleRule: '--column-spacing-left', + attrName: 'columnSpacing', + key: 'columnSpacing-left-edit-for-highlight', + responsive: 'all', + hasUnits: 'px', + valuePreCallback: callbacks.marginLeft.valuePreCallback, +} ] ) -BlockStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +Alignment.addStyles( blockStyles, { + columnAlignSelectorEditCallback: ( getAttributes, attributes, clientId ) => `[data-block="${ clientId }"]`, +} ) +BlockDiv.addStyles( blockStyles ) +Column.addStyles( blockStyles ) +ContainerDiv.addStyles( blockStyles, { + sizeSelector: '.%s-container', + sizeHorizontalAlignRule: 'margin', + sizeVerticalAlignRule: 'justifyContent', + sizeVerticalAlignSelector: '.%s-inner-blocks', + // sizeVerticalAlignSelectorEdit: '.%s-inner-blocks > .block-editor-inner-blocks > .block-editor-block-list__layout', + // sizeVerticalAlignSelectorEdit: '.%s-inner-blocks', +} ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +EffectsAnimations.addStyles( blockStyles ) -export default BlockStyles +export default blockStyles diff --git a/src/block/columns/edit.js b/src/block/columns/edit.js index bc251baad..c2653d923 100644 --- a/src/block/columns/edit.js +++ b/src/block/columns/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import BlockStyles from './style' +import blockStyles from './style' /** * External dependencies @@ -14,10 +14,10 @@ import { GroupPlaceholder, InspectorLayoutControls, InspectorTabs, + useBlockCssGenerator, } from '~stackable/components' import { BlockDiv, - useGeneratedCss, MarginBottom, getRowClasses, Alignment, @@ -35,7 +35,6 @@ import { getContentAlignmentClasses, Columns, } from '~stackable/block-components' -import { useBlockContext } from '~stackable/hooks' import { withBlockAttributeContext, withBlockWrapperIsHovered, @@ -49,23 +48,33 @@ import { useQueryLoopInstanceId } from '~stackable/util' import { compose } from '@wordpress/compose' import { __ } from '@wordpress/i18n' import { addFilter, applyFilters } from '@wordpress/hooks' +import { useSelect } from '@wordpress/data' +import { memo } from '@wordpress/element' const ALLOWED_INNER_BLOCKS = [ 'stackable/column' ] const Edit = props => { const { - className, clientId, + className, } = props - useGeneratedCss( props.attributes ) - const rowClass = getRowClasses( props.attributes ) const separatorClass = getSeparatorClasses( props.attributes ) const blockAlignmentClass = getAlignmentClasses( props.attributes ) - const { hasInnerBlocks } = useBlockContext() const [ columnProviderValue, columnTooltipClass ] = ColumnInnerBlocks.useContext() + const { hasInnerBlocks } = useSelect( + select => { + const { getBlockOrder } = select( 'core/block-editor' ) + + return { + hasInnerBlocks: getBlockOrder( clientId ).length > 0, + } + }, + [ clientId ] + ) + const blockClassNames = classnames( applyFilters( 'stackable.columns.edit.blockClassNames', [ className, @@ -83,35 +92,21 @@ const Edit = props => { 'stk-block-content', ], getContentAlignmentClasses( props.attributes, 'column', instanceId ) ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - + { className={ blockClassNames } enableVariationPicker={ true } > - + { blockCss && } { ! hasInnerBlocks && } @@ -152,8 +143,17 @@ const Edit = props => { // Load the polyfill for columns block :has() selector for Firefox const userAgent = navigator?.userAgent if ( userAgent && userAgent.indexOf( 'Firefox' ) !== -1 ) { - addFilter( 'stackable.columns.edit.blockClassNames', 'stackable/columns-has-single-block-polyfill', classes => { - const { numInnerBlocks } = useBlockContext() + addFilter( 'stackable.columns.edit.blockClassNames', 'stackable/columns-has-single-block-polyfill', ( classes, props ) => { + const { numInnerBlocks } = useSelect( + select => { + const { getBlockOrder } = select( 'core/block-editor' ) + + return { + numInnerBlocks: getBlockOrder( props.clientId ).length, + } + }, + [ props.clientId ] + ) if ( numInnerBlocks === 1 ) { classes.push( 'stk-block-columns--has-single-block-polyfill' ) @@ -163,6 +163,38 @@ if ( userAgent && userAgent.indexOf( 'Firefox' ) !== -1 ) { } ) } +// Inspector controls for the block, it's important that we only pass only the +// props used by controls to prevent rerenders of all the inspector controls. +const InspectorControls = memo( () => { + return ( + <> + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/columns/save.js b/src/block/columns/save.js index ff6ff56e4..18a13b9a8 100644 --- a/src/block/columns/save.js +++ b/src/block/columns/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import BlockStyles from './style' - /** * External dependencies */ @@ -59,7 +54,7 @@ export const Save = props => { attributes={ attributes } version={ props.version } > - + { attributes.generatedCss && }
diff --git a/src/block/columns/style.js b/src/block/columns/style.js index f5bf3944a..f9fdb692c 100644 --- a/src/block/columns/style.js +++ b/src/block/columns/style.js @@ -12,78 +12,27 @@ import { Columns, ContainerDiv, } from '~stackable/block-components' -import { useBlockAttributesContext } from '~stackable/hooks' -import { BlockCssCompiler } from '~stackable/components' +import { BlockStyleGenerator } from '~stackable/components' -/** - * WordPress dependencies - */ -import { memo } from '@wordpress/element' -import { applyFilters } from '@wordpress/hooks' +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', +} ) -const alignmentOptions = { +Alignment.addStyles( blockStyles, { editorSelectorCallback: getAttribute => `.stk--block-align-${ getAttribute( 'uniqueId' ) } > .block-editor-inner-blocks > .block-editor-block-list__layout`, -} - -const containerDivOptions = { +} ) +BlockDiv.addStyles( blockStyles ) +MarginBottom.addStyles( blockStyles ) +ContainerDiv.addStyles( blockStyles, { sizeSelector: '.%s-column', sizeVerticalAlignRule: 'justifyContent', sizeVerticalAlignSelector: '.%s-column', -} - -const BlockStyles = memo( props => { - const columnArrangement = useBlockAttributesContext( attributes => attributes.columnArrangementMobile || attributes.columnArrangementTablet ) - const numColumns = ( columnArrangement || '' ).split( ',' ).length - - const ColumnOrderStyle = applyFilters( 'stackable.block-component.columns.column-order-style', null ) - - return ( - <> - - - - - - - - - - { ColumnOrderStyle && } - - ) } ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +EffectsAnimations.addStyles( blockStyles ) +Separator.addStyles( blockStyles ) +Columns.addStyles( blockStyles ) -BlockStyles.defaultProps = { - version: '', -} - -BlockStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - const numColumns = ( props.attributes.columnArrangementMobile || props.attributes.columnArrangementTablet || '' ).split( ',' ).length - const ColumnOrderStyle = applyFilters( 'stackable.block-component.columns.column-order-style', null ) - - return ( - - - - - - - - - - - { ColumnOrderStyle && } - - ) -} - -BlockStyles.Content.defaultProps = { - version: '', - attributes: {}, -} - -export default BlockStyles +export default blockStyles diff --git a/src/block/count-up/edit.js b/src/block/count-up/edit.js index 982061d7d..28e4672a8 100644 --- a/src/block/count-up/edit.js +++ b/src/block/count-up/edit.js @@ -1,14 +1,13 @@ /** * Internal dependencies */ -import { HeadingStyles } from './style' +import blockStyles from './style' /** * External dependencies */ import { BlockDiv, - useGeneratedCss, CustomCSS, Responsive, Advanced, @@ -25,7 +24,7 @@ import { import { version as VERSION, i18n } from 'stackable' import classnames from 'classnames' import { - InspectorTabs, InspectorStyleControls, PanelAdvancedSettings, AdvancedRangeControl, + InspectorTabs, InspectorStyleControls, PanelAdvancedSettings, AdvancedRangeControl, useBlockCssGenerator, } from '~stackable/components' import { withBlockAttributeContext, withBlockWrapperIsHovered, withQueryLoopContext, @@ -36,15 +35,13 @@ import { */ import { compose } from '@wordpress/compose' import { __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' const Edit = props => { const { - clientId, className, } = props - useGeneratedCss( props.attributes ) - const textClasses = getTypographyClasses( props.attributes ) const blockAlignmentClass = getAlignmentClasses( props.attributes ) const blockClassNames = classnames( [ @@ -58,50 +55,22 @@ const Edit = props => { blockAlignmentClass, ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - - + + { blockCss && } { ) } +const InspectorControls = memo( props => { + return ( + <> + + + + + + + + + + + + + + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/count-up/save.js b/src/block/count-up/save.js index db15422e2..9ff334c35 100644 --- a/src/block/count-up/save.js +++ b/src/block/count-up/save.js @@ -1,8 +1,3 @@ -/** - * Internal dependencies - */ -import { HeadingStyles } from './style' - import { BlockDiv, CustomCSS, @@ -50,7 +45,7 @@ export const Save = props => { attributes={ attributes } version={ props.version } > - + { attributes.generatedCss && } { - return ( - <> - - - - - - - - ) +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', } ) -HeadingStyles.defaultProps = { - version: '', -} - -HeadingStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - ) -} +Alignment.addStyles( blockStyles ) +BlockDiv.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +Typography.addStyles( blockStyles, { + selector: '.stk-block-count-up__text', + hoverSelector: '.stk-block-count-up__text:hover', +} ) +EffectsAnimations.addStyles( blockStyles ) -HeadingStyles.Content.defaultProps = { - version: '', - attributes: {}, -} +export default blockStyles diff --git a/src/block/countdown/divider.js b/src/block/countdown/divider.js index 3af2686f0..0ee6f47c6 100644 --- a/src/block/countdown/divider.js +++ b/src/block/countdown/divider.js @@ -6,7 +6,6 @@ import { useBlockSetAttributesContext, } from '~stackable/hooks' import { - BlockCss, InspectorStyleControls, PanelAdvancedSettings, AdvancedToolbarControl, @@ -146,7 +145,7 @@ Divider.Content = props => { ) } -const Styles = props => { +const addStyles = ( blockStyleGenerator, props = {} ) => { const propsToPass = { ...props, version: props.version, @@ -154,59 +153,49 @@ const Styles = props => { versionDeprecated: '', } - return ( - <> - { getAttribute( 'dividerType' ) === ':' ? '.stk-block-countdown__divider-colon' : '.stk-block-countdown__divider-line' } - styleRuleCallback={ getAttribute => getAttribute( 'dividerType' ) === ':' ? 'color' : 'backgroundColor' } - attrName="dividerColor" - key="dividerColor" - responsive="all" - dependencies={ [ 'dividerType' ] } - /> } - - - - - ) -} - -const Style = props => { - return -} - -Style.Content = props => { - return + blockStyleGenerator.addBlockStyles( 'dividerColor', [ { + ...propsToPass, + selectorCallback: getAttribute => getAttribute( 'dividerType' ) === ':' ? '.stk-block-countdown__divider-colon' : '.stk-block-countdown__divider-line', + styleRuleCallback: getAttribute => getAttribute( 'dividerType' ) === ':' ? 'color' : 'backgroundColor', + attrName: 'dividerColor', + key: 'dividerColor', + responsive: 'all', + dependencies: [ 'dividerType' ], + } ] ) + + blockStyleGenerator.addBlockStyles( 'dividerSizeLine', [ { + ...propsToPass, + selector: '.stk-block-countdown__divider-line', + styleRule: 'height', + attrName: 'dividerSizeLine', + key: 'dividerSizeLine', + hasUnits: '%', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'dividerSizeColon', [ { + ...propsToPass, + selector: '.stk-block-countdown__divider-colon', + styleRule: 'fontSize', + attrName: 'dividerSizeColon', + key: 'dividerSizeColon', + hasUnits: 'px', + responsive: 'all', + } ] ) + + blockStyleGenerator.addBlockStyles( 'dividerTopOffset', [ { + ...propsToPass, + selector: '.stk-block-countdown__divider-colon', + styleRule: 'top', + attrName: 'dividerTopOffset', + key: 'dividerTopOffset', + hasUnits: 'px', + responsive: 'all', + } ] ) } Divider.InspectorControls = Edit Divider.addAttributes = addAttributes -Divider.Style = Style - +Divider.addStyles = addStyles diff --git a/src/block/countdown/edit.js b/src/block/countdown/edit.js index 4232d77dc..2f4c2c040 100644 --- a/src/block/countdown/edit.js +++ b/src/block/countdown/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { CountdownStyles } from './style' +import blockStyles from './style' import { CountdownNumber } from './countdown-number' import { Divider } from './divider' import { timezones as TIMEZONE_OPTIONS } from './timezones' @@ -12,7 +12,6 @@ import { timezones as TIMEZONE_OPTIONS } from './timezones' import { BlockDiv, ContainerDiv, - useGeneratedCss, CustomCSS, Responsive, Advanced, @@ -29,6 +28,7 @@ import classnames from 'classnames' import { InspectorStyleControls, InspectorTabs, PanelAdvancedSettings, AdvancedSelectControl, AdvancedToolbarControl, AdvancedRangeControl, AdvancedToggleControl, AdvancedTextControl, AlignButtonsControl, ControlSeparator, InspectorLayoutControls, + useBlockCssGenerator, } from '~stackable/components' import { withBlockAttributeContext, @@ -40,7 +40,7 @@ import { * WordPress dependencies */ import { __ } from '@wordpress/i18n' -import { Fragment } from '@wordpress/element' +import { Fragment, memo } from '@wordpress/element' import { compose } from '@wordpress/compose' import { DateTimePicker } from '@wordpress/components' import { useBlockEditContext } from '@wordpress/block-editor' @@ -84,11 +84,8 @@ const Edit = props => { className, setAttributes, attributes, - clientId, } = props - useGeneratedCss( props.attributes ) - const digitTextClasses = getTypographyClasses( attributes, 'digit%s' ) const labelTextClasses = getTypographyClasses( attributes, 'label%s' ) @@ -158,170 +155,26 @@ const Edit = props => { messageTextClasses, ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) return ( <> - <> - - - - { - if ( value === 'recurring' ) { - setAttributes( { - countdownType: 'recurring', actionOnExpiration: '', timezone: '', - } ) - } else { - setAttributes( { - countdownType: 'dueDate', daysLeft: '', hoursLeft: '', minutesLeft: '', secondsLeft: '', restartInterval: '', timezone: '', - } ) - } - } } - /> -

- { attributes.countdownType === 'dueDate' ? __( 'End Date', i18n ) : __( 'Start Date', i18n ) } -

- { - // Do not include seconds - setAttributes( { date: currentDate.slice( 0, currentDate.length - 3 ) } ) - } } - __nextRemoveResetButton={ true } - /> - - { attributes.countdownType === 'dueDate' && ( - <> - - { attributes.actionOnExpiration === 'showMessage' } - - ) } - { attributes.countdownType === 'recurring' && ( - - -

{ __( 'Countdown Duration', i18n ) }

- - - - - - -
- ) } - - - -
-
- - - - - - - - - - - { attributes.actionOnExpiration === 'showMessage' && - } - - - - - - - - + + { blockCss && } { ) } +const InspectorControls = memo( props => { + return ( + <> + + + + { + if ( value === 'recurring' ) { + props.setAttributes( { + countdownType: 'recurring', actionOnExpiration: '', timezone: '', + } ) + } else { + props.setAttributes( { + countdownType: 'dueDate', daysLeft: '', hoursLeft: '', minutesLeft: '', secondsLeft: '', restartInterval: '', timezone: '', + } ) + } + } } + /> +

+ { props.countdownType === 'dueDate' ? __( 'End Date', i18n ) : __( 'Start Date', i18n ) } +

+ { + // Do not include seconds + props.setAttributes( { date: currentDate.slice( 0, currentDate.length - 3 ) } ) + } } + __nextRemoveResetButton={ true } + /> + + { props.countdownType === 'dueDate' && ( + <> + + { props.actionOnExpiration === 'showMessage' } + + ) } + { props.countdownType === 'recurring' && ( + + +

{ __( 'Countdown Duration', i18n ) }

+ + + + + + +
+ ) } + + + +
+
+ + + + + + + + + + + { props.actionOnExpiration === 'showMessage' && + } + + + + + + + ) +} ) + export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/countdown/save.js b/src/block/countdown/save.js index e75c374fa..de517fcf4 100644 --- a/src/block/countdown/save.js +++ b/src/block/countdown/save.js @@ -1,4 +1,3 @@ -import { CountdownStyles } from './style' import { CountdownNumber } from './countdown-number' import { Divider } from './divider' import { getCountdownAlignment } from './edit' @@ -130,7 +129,7 @@ export const Save = props => { >
- + { attributes.generatedCss && } { attributes.dayShow &&
diff --git a/src/block/countdown/style.js b/src/block/countdown/style.js index 95dd42c12..e0c813630 100644 --- a/src/block/countdown/style.js +++ b/src/block/countdown/style.js @@ -8,133 +8,72 @@ import { ContainerDiv, Advanced, Alignment, - MarginBottom, EffectsAnimations, Transform, Typography, } from '~stackable/block-components' -import { BlockCssCompiler, BlockCss } from '~stackable/components' +import { BlockStyleGenerator } from '~stackable/components' -/** - * WordPress dependencies - */ -import { memo } from '@wordpress/element' +const blockStyles = new BlockStyleGenerator( { + versionAdded: '3.0.0', + versionDeprecated: '', +} ) + +blockStyles.addBlockStyles( 'contentAlignment', [ { + selector: '.%s.stk-block-countdown .stk-block-countdown__container', + styleRule: 'display', + responsive: 'all', + attrName: 'contentAlignment', + valueCallback: () => { + return 'flex' + }, +}, { + selector: '.%s.stk-block-countdown .stk-block-countdown__container', + styleRule: 'justifyContent', + attrName: 'contentAlignment', + key: 'contentAlignment', + responsive: 'all', +} ] ) + +blockStyles.addBlockStyles( 'boxGap', [ { + selector: '.%s.stk-block-countdown .stk-block-countdown__container', + styleRule: 'gap', + attrName: 'boxGap', + key: 'boxGap', + responsive: 'all', + hasUnits: 'px', +} ] ) -const digitTypographyOptions = { +blockStyles.addBlockStyles( 'labelMarginTop', [ { + selector: '.stk-block-countdown__label', + styleRule: 'marginTop', + attrName: 'labelMarginTop', + key: 'labelMarginTop', + responsive: 'all', + hasUnits: 'px', +} ] ) + +Divider.addStyles( blockStyles ) +ContainerDiv.addStyles( blockStyles ) +Alignment.addStyles( blockStyles ) +BlockDiv.addStyles( blockStyles ) +Advanced.addStyles( blockStyles ) +Transform.addStyles( blockStyles ) +Typography.addStyles( blockStyles, { selector: '.stk-block-countdown__digit', hoverSelector: '.stk-block-countdown__digit:hover', attrNameTemplate: 'digit%s', -} - -const labelTypographyOptions = { +} ) +Typography.addStyles( blockStyles, { selector: '.stk-block-countdown__label', hoverSelector: '.stk-block-countdown__label:hover', attrNameTemplate: 'label%s', -} - -const messageTypographyOptions = { +} ) +Typography.addStyles( blockStyles, { selector: '.stk-block-countdown__message', hoverSelector: '.stk-block-countdown__message:hover', attrNameTemplate: 'message%s', -} - -const Styles = props => { - const propsToPass = { - ...props, - version: props.version, - versionAdded: '3.0.0', - versionDeprecated: '', - } - - return ( - <> - { - return 'flex' - } } - /> - - - - - ) -} - -export const CountdownStyles = memo( props => { - return ( - <> - - - - - - - - - - - - - ) } ) +EffectsAnimations.addStyles( blockStyles ) -CountdownStyles.defaultProps = { - version: '', -} - -CountdownStyles.Content = props => { - if ( props.attributes.generatedCss ) { - return - } - - return ( - - - - - - - - - - - - - - - ) -} - -CountdownStyles.Content.defaultProps = { - version: '', - attributes: {}, -} - +export default blockStyles diff --git a/src/block/divider/edit.js b/src/block/divider/edit.js index 34ab9db71..0c39f9ed8 100644 --- a/src/block/divider/edit.js +++ b/src/block/divider/edit.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { DividerStyles } from './style' +import dividerStyles from './style' import { blockStyles } from './block-styles' /** @@ -10,7 +10,6 @@ k*/ import { BlockStyle, BlockDiv, - useGeneratedCss, CustomCSS, Responsive, Advanced, @@ -28,6 +27,7 @@ import { InspectorTabs, AdvancedRangeControl, ColorPaletteControl, + useBlockCssGenerator, } from '~stackable/components' import { useBlockStyle } from '~stackable/hooks' import { @@ -39,15 +39,13 @@ import { */ import { compose } from '@wordpress/compose' import { __ } from '@wordpress/i18n' +import { memo } from '@wordpress/element' const Edit = props => { const { - clientId, className, } = props - useGeneratedCss( props.attributes ) - const blockAlignmentClass = getAlignmentClasses( props.attributes ) const blockStyle = useBlockStyle( blockStyles ) @@ -57,51 +55,21 @@ const Edit = props => { blockAlignmentClass, ] ) + // Generate the CSS styles for the block. + const blockCss = useBlockCssGenerator( { + attributes: props.attributes, + blockStyles: dividerStyles, + clientId: props.clientId, + context: props.context, + setAttributes: props.setAttributes, + blockState: props.blockState, + version: VERSION, + } ) + return ( <> - <> - - - - - - - - - - - - - - - - - - - - - + + { blockCss && } { ) } +const InspectorControls = memo( () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + ) +} ) export default compose( withBlockWrapperIsHovered, withQueryLoopContext, diff --git a/src/block/divider/save.js b/src/block/divider/save.js index f4ac1595d..7c4399908 100644 --- a/src/block/divider/save.js +++ b/src/block/divider/save.js @@ -1,7 +1,6 @@ /** * Internal dependencies */ -import { DividerStyles } from './style' import { blockStyles } from './block-styles' import { @@ -43,7 +42,7 @@ export const Save = props => { attributes={ attributes } version={ props.version } > - + { attributes.generatedCss && } { [ 'dots', 'asterisks' ].includes( blockStyle ) ? (