Skip to content

Commit 3219779

Browse files
kaeizenGambit
andauthored
Feat: Global Block Layouts (#3445)
* init * working responsive in editor and frontend * hover state * hover states * apply other block layouts * change request part 1 * change request part 2 -hover state notice -orange indicator -reset button -bug fixes * change block components placeholder * fix css * separate into spacing and borders, buttons and icons * fix code * rename functions * fix four range control initial position * border width in block editor override default * include defaults.json * add script for animation if block layout has hover * fix bug (border width and border type) * add import * tweaks to the reset all button * fix borderWidth override * fix breakpoints - use only 1 hook - fix typography breakpoint issue * fix hover animations, use stackable_frontend_css * add desc and tooltips * fix bug with shadow colors that uses rgba * tweaked and rearranged settings. added correct docs. updated text * use block-design-system.json * remove defaults.json from buildInclude in gulp * add documentation * custom icons * update block-design-system files * create array/object for four-range values * fix missing cssvar --------- Co-authored-by: Gambit <[email protected]> Co-authored-by: [email protected] <>
1 parent ee0acca commit 3219779

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3307
-169
lines changed

gulpfile.js

Lines changed: 222 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,220 @@ if ( ! function_exists( 'stackable_get_blocks_array') ) {
197197
cb()
198198
} )
199199

200+
gulp.task( 'generate-block-design-system-php', function( cb ) {
201+
const fs = require( 'fs' )
202+
203+
let blockDesignSystem = 'array()'
204+
205+
const toAssocArray = ( key, value, cb, indent ) => {
206+
if ( typeof value === 'object' ) {
207+
const parsed = cb( value, indent + 1 )
208+
return `"${ key }" => ${ parsed }`
209+
}
210+
211+
if ( typeof value === 'string' ) {
212+
return `"${ key }" => "${ value }"`
213+
}
214+
215+
return `"${ key }" => ${ value }`
216+
}
217+
218+
const parseBlockDesignSystem = ( obj, indent ) => {
219+
let content = ''
220+
const tab = '\t'.repeat( indent )
221+
222+
if ( typeof obj === 'object' ) {
223+
content += 'array(\n'
224+
225+
Object.entries( obj ).forEach( ( [ key, value ], index, bds ) => {
226+
if ( key === 'hoverStates' ) {
227+
return
228+
}
229+
230+
content += tab + toAssocArray( key, value, parseBlockDesignSystem, indent )
231+
232+
if ( index !== bds.length - 1 ) {
233+
content += ',\n'
234+
} else {
235+
content += '\n'
236+
}
237+
} )
238+
content += `\t`.repeat( indent - 1 ) + ')'
239+
}
240+
return content
241+
}
242+
243+
const parseBlockDesignSystemSections = ( sections, indent ) => {
244+
const combined = {}
245+
Object.values( sections ).forEach( section => {
246+
Object.entries( section ).forEach( ( [ key, value ] ) => {
247+
combined[ key ] = value
248+
} )
249+
} )
250+
251+
return parseBlockDesignSystem( combined, indent )
252+
}
253+
const jsonPath = path.resolve( __dirname, `src/styles/block-design-system.json` )
254+
if ( fs.existsSync( jsonPath ) ) {
255+
const fileContent = fs.readFileSync( jsonPath, 'utf-8' )
256+
const raw = JSON.parse( fileContent )
257+
blockDesignSystem = parseBlockDesignSystemSections( raw, 4 )
258+
}
259+
260+
// Generate PHP variable string
261+
const script = `<?php
262+
// This is a generated file by gulp generate-block-design-system-php
263+
// Use block-design-system.json if you want to edit this file.
264+
265+
// Exit if accessed directly.
266+
if ( ! defined( 'ABSPATH' ) ) {
267+
exit;
268+
}
269+
270+
if ( ! class_exists( 'Stackable_Block_Design_System') ) {
271+
class Stackable_Block_Design_System {
272+
273+
function __construct() {
274+
}
275+
276+
public static function get_block_design_system() {
277+
$block_design_system = ${ blockDesignSystem };
278+
279+
return $block_design_system;
280+
}
281+
}
282+
283+
new Stackable_Block_Design_System();
284+
}
285+
?>
286+
`
287+
// Write PHP variable to file
288+
fs.writeFileSync( path.resolve( __dirname, 'src/styles/block-design-system.php' ), script )
289+
290+
cb()
291+
} )
292+
293+
gulp.task( 'generate-block-design-system-scss', function( cb ) {
294+
const fs = require( 'fs' )
295+
296+
let blockDesignSystem = ''
297+
298+
const getFourRangeValue = sides => {
299+
if ( Object.values( sides ).every( s => s === sides.top ) ) {
300+
return `${ sides.top }px`
301+
}
302+
303+
if ( sides.top === sides.bottom && sides.right === sides.left ) {
304+
return `${ sides.top }px ${ sides.right }px`
305+
}
306+
307+
return `${ sides.top }px ${ sides.right }px ${ sides.bottom }px ${ sides.left }px`
308+
}
309+
310+
const getDeviceValue = ( obj, device = 'desktop' ) => {
311+
const value = obj[ device ]
312+
313+
if ( typeof value === 'number' ) {
314+
return `${ value }px`
315+
}
316+
317+
if ( typeof value === 'object' ) {
318+
return `${ getFourRangeValue( value ) }`
319+
}
320+
321+
if ( value === '' ) {
322+
return 'none'
323+
}
324+
325+
return value
326+
}
327+
328+
const getValue = ( property, obj, indent ) => {
329+
if ( Object.keys( obj ).length === 1 ) {
330+
return getDeviceValue( obj )
331+
}
332+
333+
const tab = `\t`.repeat( indent )
334+
let content = getDeviceValue( obj )
335+
let hoverProperties = ''
336+
if ( 'hoverStates' in obj ) {
337+
hoverProperties += ',\n'
338+
const _hoverProperties = []
339+
Object.keys( obj.hoverStates ).forEach( state => {
340+
if ( obj.hoverStates[ state ] ) {
341+
_hoverProperties.push( tab + `${ property }-${ state }: cssvar(${ property })` )
342+
}
343+
} )
344+
hoverProperties += _hoverProperties.join( ',\n' )
345+
}
346+
347+
if ( 'hoverStates' in obj && Object.keys( obj ).length === 2 ) {
348+
content += hoverProperties
349+
return content
350+
}
351+
352+
content = '(\n'
353+
Object.keys( obj ).forEach( device => {
354+
if ( device === 'hoverStates' ) {
355+
return
356+
}
357+
content += `\t`.repeat( indent + 1 ) + `${ device }: ${ getDeviceValue( obj, device ) },\n`
358+
} )
359+
content += tab + ')'
360+
content += hoverProperties
361+
362+
return content
363+
}
364+
365+
const parseBlockDesignSystem = ( obj, indent ) => {
366+
let content = ''
367+
const tab = `\t`.repeat( indent )
368+
Object.entries( obj ).forEach( ( [ key, v ] ) => {
369+
const value = getValue( key, v, indent )
370+
content += tab + `${ key }: ${ value },\n`
371+
} )
372+
return content
373+
}
374+
375+
const parseBlockDesignSystemSections = ( sections, indent ) => {
376+
let content = ''
377+
if ( typeof sections === 'object' ) {
378+
Object.entries( sections ).forEach( ( [ section, obj ], index, s ) => {
379+
content += ` /**
380+
* ${ section }
381+
*/
382+
`
383+
content += parseBlockDesignSystem( obj, indent )
384+
content += index !== s.length - 1 ? '\n' : ''
385+
} )
386+
}
387+
return content
388+
}
389+
390+
const jsonPath = path.resolve( __dirname, `src/styles/block-design-system.json` )
391+
if ( fs.existsSync( jsonPath ) ) {
392+
const fileContent = fs.readFileSync( jsonPath, 'utf-8' )
393+
const raw = JSON.parse( fileContent )
394+
blockDesignSystem = parseBlockDesignSystemSections( raw, 1 )
395+
}
396+
397+
// Generate PHP variable string
398+
const script = `@import "cssvars";
399+
// This is a generated file by gulp generate-block-design-system-scss
400+
// Use block-design-system.json if you want to edit this file.
401+
402+
/**
403+
* Default Stackable UI Kit design.
404+
*/
405+
$block-design-system: (
406+
${ blockDesignSystem });
407+
`
408+
// Write to SCSS file
409+
fs.writeFileSync( path.resolve( __dirname, 'src/styles/block-design-system.scss' ), script )
410+
411+
cb()
412+
} )
413+
200414
gulp.task( 'generate-translations-js', gulp.series(
201415
// The collect function has an issue where it will not continue if the
202416
// folder will it writes to doesn't exist, create it to prevent an error.
@@ -491,7 +705,9 @@ gulp.task( 'style-deprecated', gulp.parallel(
491705

492706
gulp.task( 'build-process', gulp.parallel( 'style', 'style-editor', 'welcome-styles', 'style-deprecated', 'generate-translations-js', 'generate-stk-block-typesphp' ) )
493707

494-
gulp.task( 'build', gulp.series( 'build-process' ) )
708+
gulp.task( 'build-block-design-system', gulp.parallel( 'generate-block-design-system-php', 'generate-block-design-system-scss' ) )
709+
710+
gulp.task( 'build', gulp.series( 'build-block-design-system', 'build-process' ) )
495711

496712
gulp.task( 'package', function() {
497713
return gulp.src( buildInclude, { base: './' } )
@@ -506,6 +722,10 @@ gulp.task( 'zip', function() {
506722
} )
507723

508724
const watchFuncs = ( basePath = '.' ) => {
725+
gulp.watch(
726+
[ `${ basePath }/src/styles/block-design-system.json` ],
727+
gulp.parallel( [ 'generate-block-design-system-php', 'generate-block-design-system-scss' ] )
728+
)
509729
gulp.watch(
510730
[ `${ basePath }/src/**/*.scss` ],
511731
gulp.parallel( [ 'style', 'style-editor', 'welcome-styles', 'style-deprecated' ] )
@@ -522,7 +742,7 @@ const watchFuncs = ( basePath = '.' ) => {
522742
)
523743
}
524744

525-
gulp.task( 'watch', gulp.series( 'build-process', function watch( done ) {
745+
gulp.task( 'watch', gulp.series( 'build-block-design-system', 'build-process', function watch( done ) {
526746
watchFuncs()
527747
done()
528748
} ) )

plugin.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,10 @@ function is_frontend() {
229229
require_once( plugin_dir_path( __FILE__ ) . 'src/kses.php' );
230230
require_once( plugin_dir_path( __FILE__ ) . 'src/dynamic-breakpoints.php' );
231231
require_once( plugin_dir_path( __FILE__ ) . 'src/design-library/init.php' );
232+
require_once( plugin_dir_path( __FILE__ ) . 'src/styles/block-design-system.php' );
232233
require_once( plugin_dir_path( __FILE__ ) . 'src/global-settings.php' );
234+
require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/spacing-and-borders/index.php' );
235+
require_once( plugin_dir_path( __FILE__ ) . 'src/plugins/global-settings/buttons-and-icons/index.php' );
233236
require_once( plugin_dir_path( __FILE__ ) . 'src/custom-block-styles.php' );
234237
require_once( plugin_dir_path( __FILE__ ) . 'src/css-optimize.php' );
235238
require_once( plugin_dir_path( __FILE__ ) . 'src/compatibility/index.php' );

src/block-components/block-div/edit.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from '~stackable/components'
1919
import {
2020
useBlockAttributesContext,
21+
useBlockLayoutDefaults,
2122
useBlockSetAttributesContext,
2223
} from '~stackable/hooks'
2324

@@ -35,6 +36,7 @@ export const Edit = memo( props => {
3536
} = props
3637
const hasBackground = useBlockAttributesContext( attributes => attributes.hasBackground )
3738
const setAttributes = useBlockSetAttributesContext()
39+
const { getPlaceholder } = useBlockLayoutDefaults()
3840

3941
return (
4042
<>
@@ -55,6 +57,7 @@ export const Edit = memo( props => {
5557
/>
5658
<SizeControls.Spacing
5759
attrNameTemplate="block%s"
60+
paddingPlaceholder={ hasBackground ? getPlaceholder( 'block-background-padding' ) : '' }
5861
visualGuide={ {
5962
highlight: 'padding',
6063
} }
@@ -84,6 +87,9 @@ export const Edit = memo( props => {
8487
>
8588
<BorderControls
8689
attrNameTemplate="block%s"
90+
placeholderTemplate="block-background"
91+
borderTypeValue={ getPlaceholder( 'block-background-border-style' ) }
92+
borderRadiusPlaceholder={ getPlaceholder( 'block-background-border-radius' ) }
8793
/>
8894
</PanelAdvancedSettings>
8995
</InspectorStyleControls>

src/block-components/button/edit.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
AdvancedSelectControl,
1313
} from '~stackable/components'
1414
import { i18n } from 'stackable'
15-
import { useBlockAttributesContext } from '~stackable/hooks'
15+
import { useBlockAttributesContext, useBlockLayoutDefaults } from '~stackable/hooks'
1616

1717
/**
1818
* WordPress dependencies
@@ -39,6 +39,8 @@ export const Icon = props => (
3939
hasIconGap={ props.hasIconGap }
4040
hasIconPosition={ props.hasIconPosition }
4141
defaultValue={ props.defaultValue }
42+
iconSizePlaceholderName="button-icon-size"
43+
iconGapPlaceholderName={ props.iconGapPlaceholderName }
4244
/>
4345
)
4446

@@ -176,10 +178,13 @@ Colors.defaultProps = {
176178
const SizeControls = props => {
177179
const {
178180
attrNameTemplate = 'button%s',
181+
paddingPlaceholderName = 'button-padding',
179182
} = props
180183

181184
const getAttrName = getAttributeNameFunc( attrNameTemplate )
185+
const { getPlaceholder } = useBlockLayoutDefaults()
182186

187+
const buttonPaddingPlaceholder = getPlaceholder( paddingPlaceholderName, { single: false } )
183188
return ( <>
184189
{ props.hasFullWidth && (
185190
<AdvancedToggleControl
@@ -193,6 +198,7 @@ const SizeControls = props => {
193198
attribute={ getAttrName( 'minHeight' ) }
194199
min={ 0 }
195200
max={ 100 }
201+
placeholder={ getPlaceholder( 'button-min-height' ) }
196202
/>
197203
{ props.hasWidth && ! props.hasFullWidth && (
198204
<AdvancedRangeControl
@@ -213,6 +219,10 @@ const SizeControls = props => {
213219
sliderMin={ [ 0, 0 ] }
214220
sliderMax={ [ 40, 100 ] }
215221
vhMode={ true }
222+
placeholderTop={ buttonPaddingPlaceholder?.top || '' }
223+
placeholderRight={ buttonPaddingPlaceholder?.right || '' }
224+
placeholderBottom={ buttonPaddingPlaceholder?.bottom || '' }
225+
placeholderLeft={ buttonPaddingPlaceholder?.left || '' }
216226
helpTooltip={ {
217227
// TODO: Add a working video
218228
title: __( 'Button padding', i18n ),
@@ -240,11 +250,21 @@ Size.defaultProps = {
240250
}
241251

242252
const BorderControls = props => {
253+
const className = useBlockAttributesContext( attributes => {
254+
return attributes.className
255+
} )
256+
const { getPlaceholder } = useBlockLayoutDefaults()
257+
258+
const borderWidthPlaceholder = className === 'is-style-ghost' ? getPlaceholder( 'button-ghost-border-width' ) : getPlaceholder( 'button-border-width' )
259+
243260
return (
244261
<_BorderControls
245262
hasBorderRadiusHover={ false }
246263
borderSelector={ props.borderSelector }
247264
borderRadiusPlaceholder={ props.placeholder }
265+
borderTypeValue={ getPlaceholder( 'button-border-style' ) }
266+
borderWidthPlaceholder={ borderWidthPlaceholder }
267+
placeholderTemplate="button"
248268
{ ...props }
249269
/>
250270
)
@@ -281,6 +301,7 @@ export const Edit = props => {
281301
hasIconPosition,
282302
borderRadiusPlaceholder,
283303
hasFullWidth,
304+
iconGapPlaceholderName,
284305
...propsToPass
285306
} = props
286307

@@ -312,6 +333,7 @@ export const Edit = props => {
312333
<Icon
313334
hasIconGap={ hasIconGap }
314335
hasIconPosition={ hasIconPosition }
336+
iconGapPlaceholderName={ iconGapPlaceholderName }
315337
/>
316338
) }
317339
</>
@@ -326,6 +348,7 @@ Edit.defaultProps = {
326348
hasIconGap: true,
327349
hasIconPosition: true,
328350
hasFullWidth: false,
351+
iconGapPlaceholderName: undefined,
329352
}
330353

331354
Edit.Link = Link

0 commit comments

Comments
 (0)