components
1 year ago
css
3 years ago
attributes.js
2 years ago
block.js
1 year ago
deprecated.js
3 years ago
edit.js
2 years ago
editor.scss
4 years ago
transforms.js
1 year ago
transforms.js
208 lines
| 1 | import { convertLegacyHtmlAttributes } from '@utils/convertLegacyHtmlAttributes'; |
| 2 | import { convertLocalToStyles } from '@utils/legacyStyleUtils'; |
| 3 | import { createBlock, getBlockType } from '@wordpress/blocks'; |
| 4 | import { getAtRuleValue } from '@edge22/styles-builder'; |
| 5 | import hasNumericValue from '@utils/has-numeric-value'; |
| 6 | |
| 7 | const GRID_MAPPINGS = { |
| 8 | '40,60': '2fr 3fr', |
| 9 | '60,40': '3fr 2fr', |
| 10 | '30,70': '3fr 7fr', |
| 11 | '70,30': '7fr 3fr', |
| 12 | '20,80': '2fr 8fr', |
| 13 | '80,20': '8fr 2fr', |
| 14 | }; |
| 15 | |
| 16 | function getMostCommon( widths ) { |
| 17 | if ( widths.length === 0 ) { |
| 18 | return ''; |
| 19 | } |
| 20 | |
| 21 | const frequencyMap = {}; |
| 22 | let maxFrequency = 0; |
| 23 | let mostCommonElement = widths[ 0 ]; |
| 24 | |
| 25 | for ( const item of widths ) { |
| 26 | frequencyMap[ item ] = ( frequencyMap[ item ] || 0 ) + 1; |
| 27 | |
| 28 | if ( frequencyMap[ item ] > maxFrequency ) { |
| 29 | maxFrequency = frequencyMap[ item ]; |
| 30 | mostCommonElement = item; |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | return mostCommonElement; |
| 35 | } |
| 36 | |
| 37 | function getGridValue( width ) { |
| 38 | let gridValue = ''; |
| 39 | |
| 40 | switch ( width ) { |
| 41 | case '100%': |
| 42 | gridValue = '1fr'; |
| 43 | break; |
| 44 | case '50%': |
| 45 | gridValue = 'repeat(2, minmax(0, 1fr))'; |
| 46 | break; |
| 47 | case '33.33%': |
| 48 | case '33%': |
| 49 | gridValue = 'repeat(3, minmax(0, 1fr))'; |
| 50 | break; |
| 51 | case '25%': |
| 52 | gridValue = 'repeat(4, minmax(0, 1fr))'; |
| 53 | break; |
| 54 | case '20%': |
| 55 | gridValue = 'repeat(5, minmax(0, 1fr))'; |
| 56 | break; |
| 57 | case '16.66%': |
| 58 | case '16%': |
| 59 | gridValue = 'repeat(6, minmax(0, 1fr))'; |
| 60 | break; |
| 61 | default: |
| 62 | gridValue = 'repeat(2, minmax(0, 1fr))'; |
| 63 | break; |
| 64 | } |
| 65 | |
| 66 | return gridValue; |
| 67 | } |
| 68 | |
| 69 | function getGapValue( value ) { |
| 70 | return hasNumericValue( value ) ? `${ value }px` : ''; |
| 71 | } |
| 72 | |
| 73 | function convertToGridValue( widths ) { |
| 74 | // Early return if not exactly 2 widths |
| 75 | if ( ! Array.isArray( widths ) || widths.length !== 2 ) { |
| 76 | return null; |
| 77 | } |
| 78 | |
| 79 | // Normalize widths by removing '%' and creating a key |
| 80 | const normalizedKey = widths |
| 81 | .map( ( width ) => width.replace( '%', '' ) ) |
| 82 | .join( ',' ); |
| 83 | |
| 84 | return GRID_MAPPINGS[ normalizedKey ] || null; |
| 85 | } |
| 86 | |
| 87 | export const transforms = { |
| 88 | to: [ |
| 89 | { |
| 90 | type: 'block', |
| 91 | blocks: [ 'generateblocks/element' ], |
| 92 | isMatch: ( { |
| 93 | isQueryLoop, |
| 94 | } ) => { |
| 95 | if ( |
| 96 | isQueryLoop |
| 97 | ) { |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | return true; |
| 102 | }, |
| 103 | transform: ( attributes, blocks ) => { |
| 104 | const { |
| 105 | htmlAttributes, |
| 106 | blockLabel, |
| 107 | globalClasses, |
| 108 | anchor, |
| 109 | className, |
| 110 | verticalGap, |
| 111 | verticalGapTablet, |
| 112 | verticalGapMobile, |
| 113 | horizontalGap, |
| 114 | horizontalGapTablet, |
| 115 | horizontalGapMobile, |
| 116 | } = attributes; |
| 117 | const attributeData = getBlockType( 'generateblocks/grid' )?.attributes; |
| 118 | const styles = convertLocalToStyles( attributeData, attributes, '&:is(:hover, :focus)' ); |
| 119 | const newHtmlAttributes = convertLegacyHtmlAttributes( htmlAttributes ); |
| 120 | |
| 121 | if ( anchor ) { |
| 122 | newHtmlAttributes.id = anchor; |
| 123 | } |
| 124 | |
| 125 | const metaData = {}; |
| 126 | |
| 127 | if ( blockLabel ) { |
| 128 | metaData.name = blockLabel; |
| 129 | } |
| 130 | |
| 131 | const blockWidths = { |
| 132 | desktop: [], |
| 133 | tablet: [], |
| 134 | mobile: [], |
| 135 | }; |
| 136 | |
| 137 | blocks.forEach( ( block ) => { |
| 138 | blockWidths.desktop.push( block.attributes.sizing?.width ); |
| 139 | blockWidths.tablet.push( block.attributes.sizing?.widthTablet ); |
| 140 | blockWidths.mobile.push( block.attributes.sizing?.widthMobile ); |
| 141 | } ); |
| 142 | |
| 143 | // Get the most common width for each device. |
| 144 | const mostCommonDesktopWidth = getMostCommon( blockWidths.desktop ); |
| 145 | const mostCommonTabletWidth = getMostCommon( blockWidths.tablet ); |
| 146 | const mostCommonMobileWidth = getMostCommon( blockWidths.mobile ); |
| 147 | |
| 148 | // Clone the Blocks to be Grouped |
| 149 | // Failing to create new block references causes the original blocks |
| 150 | // to be replaced in the switchToBlockType call thereby meaning they |
| 151 | // are removed both from their original location and within the |
| 152 | // new group block. |
| 153 | const groupInnerBlocks = blocks.map( ( block ) => { |
| 154 | return createBlock( |
| 155 | block.name, |
| 156 | { |
| 157 | ...block.attributes, |
| 158 | sizing: {}, |
| 159 | }, |
| 160 | block.innerBlocks |
| 161 | ); |
| 162 | } ); |
| 163 | |
| 164 | const tabletAtRule = getAtRuleValue( 'mediumSmallWidth' ); |
| 165 | const mobileAtRule = getAtRuleValue( 'smallWidth' ); |
| 166 | const tabletGridValue = getGridValue( mostCommonTabletWidth ); |
| 167 | const mobileGridValue = getGridValue( mostCommonMobileWidth ); |
| 168 | |
| 169 | const desktopWidths = blockWidths.desktop; |
| 170 | const desktopGridValue = convertToGridValue( desktopWidths ) || getGridValue( mostCommonDesktopWidth ); |
| 171 | |
| 172 | return createBlock( |
| 173 | 'generateblocks/element', |
| 174 | { |
| 175 | tagName: 'div', |
| 176 | styles: { |
| 177 | ...styles, |
| 178 | display: 'grid', |
| 179 | gridTemplateColumns: desktopGridValue, |
| 180 | columnGap: getGapValue( horizontalGap ), |
| 181 | rowGap: getGapValue( verticalGap ), |
| 182 | [ tabletAtRule ]: { |
| 183 | ...styles[ tabletAtRule ], |
| 184 | gridTemplateColumns: tabletGridValue, |
| 185 | columnGap: getGapValue( horizontalGapTablet ), |
| 186 | rowGap: getGapValue( verticalGapTablet ), |
| 187 | }, |
| 188 | [ mobileAtRule ]: { |
| 189 | ...styles[ mobileAtRule ], |
| 190 | gridTemplateColumns: tabletGridValue !== mobileGridValue |
| 191 | ? mobileGridValue |
| 192 | : '', |
| 193 | columnGap: getGapValue( horizontalGapMobile ), |
| 194 | rowGap: getGapValue( verticalGapMobile ), |
| 195 | }, |
| 196 | }, |
| 197 | htmlAttributes: newHtmlAttributes, |
| 198 | metadata: metaData, |
| 199 | globalClasses, |
| 200 | className, |
| 201 | }, |
| 202 | groupInnerBlocks |
| 203 | ); |
| 204 | }, |
| 205 | }, |
| 206 | ], |
| 207 | }; |
| 208 |