PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.4.0
GenerateBlocks v1.4.0
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / src / blocks / container / edit.js
generateblocks / src / blocks / container Last commit date
css 4 years ago attributes.js 4 years ago block-controls.js 4 years ago block.js 4 years ago deprecated.js 5 years ago edit.js 4 years ago editor.scss 4 years ago
edit.js
2612 lines
1 /**
2 * Block: Container
3 */
4
5 import Element from '../../components/element';
6 import ColorPicker from '../../components/color-picker';
7 import UnitPicker from '../../components/unit-picker';
8 import getIcon from '../../utils/get-icon';
9 import classnames from 'classnames';
10 import DimensionsControl from '../../components/dimensions/';
11 import PanelArea from '../../components/panel-area/';
12 import TypographyControls from '../../components/typography';
13 import GradientControl from '../../components/gradient/';
14 import sanitizeSVG from '../../utils/sanitize-svg';
15 import ResponsiveTabs from '../../components/responsive-tabs';
16 import RangeControlInput from '../../components/range-control';
17 import MainCSS from './css/main.js';
18 import DesktopCSS from './css/desktop.js';
19 import TabletCSS from './css/tablet.js';
20 import TabletOnlyCSS from './css/tablet-only.js';
21 import MobileCSS from './css/mobile.js';
22 import getAllUniqueIds from '../../utils/get-all-unique-ids';
23 import getResponsivePlaceholder from '../../utils/get-responsive-placeholder';
24 import hasNumericValue from '../../utils/has-numeric-value';
25 import isBlockVersionLessThan from '../../utils/check-block-version';
26 import wasBlockJustInserted from '../../utils/was-block-just-inserted';
27
28 import {
29 __,
30 sprintf,
31 } from '@wordpress/i18n';
32
33 import {
34 RangeControl,
35 Button,
36 ButtonGroup,
37 ToggleControl,
38 SelectControl,
39 TextControl,
40 BaseControl,
41 Notice,
42 PanelBody,
43 PanelRow,
44 Tooltip,
45 Dropdown,
46 } from '@wordpress/components';
47
48 import {
49 Fragment,
50 Component,
51 } from '@wordpress/element';
52
53 import {
54 InspectorControls,
55 InnerBlocks,
56 MediaUpload,
57 AlignmentToolbar,
58 InspectorAdvancedControls,
59 BlockControls,
60 } from '@wordpress/block-editor';
61
62 import {
63 applyFilters,
64 } from '@wordpress/hooks';
65
66 import {
67 withSelect,
68 withDispatch,
69 } from '@wordpress/data';
70
71 import {
72 compose,
73 } from '@wordpress/compose';
74
75 /**
76 * Regular expression matching invalid anchor characters for replacement.
77 *
78 * @type {RegExp}
79 */
80 const ANCHOR_REGEX = /[\s#]/g;
81
82 class GenerateBlockContainer extends Component {
83 constructor() {
84 super( ...arguments );
85
86 this.state = {
87 selectedDevice: 'Desktop',
88 };
89
90 this.getDeviceType = this.getDeviceType.bind( this );
91 this.setDeviceType = this.setDeviceType.bind( this );
92 }
93
94 componentDidMount() {
95 // Generate a unique ID if none exists or if the same ID exists on this page.
96 const allBlocks = wp.data.select( 'core/block-editor' ).getBlocks();
97 const uniqueIds = getAllUniqueIds( allBlocks, [], this.props.clientId );
98
99 if ( ! this.props.attributes.uniqueId || uniqueIds.includes( this.props.attributes.uniqueId ) ) {
100 this.props.setAttributes( {
101 uniqueId: this.props.clientId.substr( 2, 9 ).replace( '-', '' ),
102 } );
103 }
104
105 const thisBlock = document.getElementById( 'block-' + this.props.clientId );
106
107 if ( thisBlock && 'full' === this.props.attributes.align ) {
108 thisBlock.setAttribute( 'data-align', 'full' );
109 }
110
111 // This block used to be static. Set it to dynamic by default from now on.
112 if ( 'undefined' === typeof this.props.attributes.isDynamic || ! this.props.attributes.isDynamic ) {
113 this.props.setAttributes( {
114 isDynamic: true,
115 } );
116 }
117
118 // Set our inner z-index if we're using a gradient overlay or pseudo background.
119 // @since 1.4.0.
120 if ( 'undefined' === typeof this.props.attributes.blockVersion || this.props.attributes.blockVersion < 2 ) {
121 let updateOldZindex = this.props.attributes.gradient && 'pseudo-element' === this.props.attributes.gradientSelector && ! hasNumericValue( this.props.attributes.innerZindex );
122
123 if ( ! updateOldZindex ) {
124 updateOldZindex = !! this.props.attributes.bgImage && 'undefined' !== typeof this.props.attributes.bgOptions.selector && 'pseudo-element' === this.props.attributes.bgOptions.selector;
125 }
126
127 if ( ! updateOldZindex ) {
128 updateOldZindex = 'undefined' !== typeof this.props.attributes.useAdvBackgrounds && this.props.attributes.useAdvBackgrounds;
129 }
130
131 if ( updateOldZindex ) {
132 this.props.setAttributes( {
133 innerZindex: 1,
134 } );
135 }
136 }
137
138 // Set our old defaults as static values.
139 // @since 1.4.0.
140 if ( ! wasBlockJustInserted( this.props.attributes ) && isBlockVersionLessThan( this.props.attributes.blockVersion, 2 ) ) {
141 const legacyDefaults = generateBlocksLegacyDefaults.v_1_4_0.container;
142 const useGlobalStyle = 'undefined' !== typeof this.props.attributes.useGlobalStyle && this.props.attributes.useGlobalStyle;
143
144 const newAttrs = {};
145 const items = [];
146
147 if ( ! useGlobalStyle ) {
148 items.push(
149 'paddingTop',
150 'paddingRight',
151 'paddingBottom',
152 'paddingLeft',
153 );
154 }
155
156 if ( this.props.attributes.isGrid ) {
157 items.push(
158 'width',
159 'widthMobile',
160 );
161 }
162
163 if ( this.props.attributes.gradient ) {
164 items.push(
165 'gradientDirection',
166 'gradientColorOne',
167 'gradientColorOneOpacity',
168 'gradientColorTwo',
169 'gradientColorTwoOpacity'
170 );
171 }
172
173 items.forEach( ( item ) => {
174 if ( ! hasNumericValue( this.props.attributes[ item ] ) ) {
175 newAttrs[ item ] = legacyDefaults[ item ];
176 }
177 } );
178
179 if ( Object.keys( newAttrs ).length > 0 ) {
180 this.props.setAttributes( newAttrs );
181 }
182 }
183
184 // Update block version flag if it's out of date.
185 if ( isBlockVersionLessThan( this.props.attributes.blockVersion, 2 ) ) {
186 this.props.setAttributes( { blockVersion: 2 } );
187 }
188 }
189
190 componentDidUpdate() {
191 const thisBlock = document.getElementById( 'block-' + this.props.clientId );
192
193 if ( thisBlock ) {
194 const alignValue = this.props.attributes.align;
195 let currentDataAlign = '';
196
197 if ( thisBlock.getAttribute( 'data-align' ) ) {
198 currentDataAlign = thisBlock.getAttribute( 'data-align' );
199 }
200
201 if ( alignValue !== currentDataAlign ) {
202 if ( ( '' === alignValue || undefined === alignValue ) && '' !== currentDataAlign ) {
203 thisBlock.removeAttribute( 'data-align' );
204 } else {
205 thisBlock.setAttribute( 'data-align', alignValue );
206 }
207 }
208 }
209 }
210
211 getDeviceType() {
212 let deviceType = this.props.deviceType ? this.props.deviceType : this.state.selectedDevice;
213
214 if ( ! generateBlocksInfo.syncResponsivePreviews ) {
215 deviceType = this.state.selectedDevice;
216 }
217
218 return deviceType;
219 }
220
221 setDeviceType( deviceType ) {
222 if ( generateBlocksInfo.syncResponsivePreviews && this.props.deviceType ) {
223 this.props.setDeviceType( deviceType );
224 this.setState( { selectedDevice: deviceType } );
225 } else {
226 this.setState( { selectedDevice: deviceType } );
227 }
228 }
229
230 render() {
231 const {
232 attributes,
233 setAttributes,
234 hasChildBlocks,
235 clientId,
236 } = this.props;
237
238 const {
239 uniqueId,
240 className,
241 anchor,
242 tagName,
243 isGrid,
244 width,
245 widthTablet,
246 widthMobile,
247 autoWidthTablet,
248 autoWidthMobile,
249 flexGrow,
250 flexGrowTablet,
251 flexGrowMobile,
252 flexShrink,
253 flexShrinkTablet,
254 flexShrinkMobile,
255 flexBasis,
256 flexBasisTablet,
257 flexBasisMobile,
258 flexBasisUnit,
259 outerContainer,
260 innerContainer,
261 containerWidth,
262 minHeight,
263 minHeightUnit,
264 minHeightTablet,
265 minHeightUnitTablet,
266 minHeightMobile,
267 minHeightUnitMobile,
268 borderColor,
269 borderColorOpacity,
270 backgroundColor,
271 backgroundColorOpacity,
272 textColor,
273 linkColor,
274 linkColorHover,
275 bgImage,
276 bgOptions,
277 bgImageSize,
278 verticalAlignment,
279 verticalAlignmentTablet,
280 verticalAlignmentMobile,
281 zindex,
282 innerZindex,
283 removeVerticalGap,
284 removeVerticalGapTablet,
285 removeVerticalGapMobile,
286 orderTablet,
287 orderMobile,
288 alignment,
289 alignmentTablet,
290 alignmentMobile,
291 fontFamily,
292 googleFont,
293 googleFontVariants,
294 align,
295 shapeDividers,
296 } = attributes;
297
298 // Attribute defaults added to an object late don't get defaults.
299 if ( 'undefined' === typeof attributes.bgOptions.selector ) {
300 attributes.bgOptions.selector = 'element';
301 }
302
303 if ( 'undefined' === typeof attributes.bgOptions.opacity ) {
304 attributes.bgOptions.opacity = 1;
305 }
306
307 const tagNames = applyFilters(
308 'generateblocks.editor.containerTagNames',
309 [
310 { label: 'div', value: 'div' },
311 { label: 'section', value: 'section' },
312 { label: 'header', value: 'header' },
313 { label: 'footer', value: 'footer' },
314 { label: 'aside', value: 'aside' },
315 ],
316 this.props,
317 this.state
318 );
319
320 const allowedTagNames = applyFilters(
321 'generateblocks.editor.allowedContainerTagNames',
322 [
323 'div',
324 'section',
325 'header',
326 'footer',
327 'aside',
328 'a',
329 ]
330 );
331
332 const filterTagName = ( tagValue ) => allowedTagNames.includes( tagValue ) ? tagValue : 'div';
333
334 let googleFontsAttr = '';
335
336 if ( googleFontVariants ) {
337 googleFontsAttr = ':' + googleFontVariants;
338 }
339
340 let parentBlockId = false,
341 parentBlock = false,
342 hasGridContainer = false,
343 gridContainerId = '';
344
345 if ( typeof wp.data.select( 'core/block-editor' ).getBlockParents === 'function' ) {
346 parentBlockId = wp.data.select( 'core/block-editor' ).getBlockParents( clientId, true )[ 0 ];
347
348 if ( parentBlockId ) {
349 parentBlock = wp.data.select( 'core/block-editor' ).getBlocksByClientId( parentBlockId );
350
351 if ( parentBlock && 'generateblocks/grid' === parentBlock[ 0 ].name ) {
352 hasGridContainer = true;
353 gridContainerId = parentBlock[ 0 ].attributes.uniqueId;
354 }
355 }
356 }
357
358 const handleAddShape = () => {
359 const shapeDividersValues = [ ...shapeDividers ];
360
361 shapeDividersValues.push( {
362 shape: generateBlocksStyling.container.shapeDividers.shape,
363 color: generateBlocksStyling.container.shapeDividers.color,
364 colorOpacity: generateBlocksStyling.container.shapeDividers.colorOpacity,
365 location: generateBlocksStyling.container.shapeDividers.location,
366 height: generateBlocksStyling.container.shapeDividers.height,
367 heightTablet: generateBlocksStyling.container.shapeDividers.heightTablet,
368 heightMobile: generateBlocksStyling.container.shapeDividers.heightMobile,
369 width: generateBlocksStyling.container.shapeDividers.width,
370 widthTablet: generateBlocksStyling.container.shapeDividers.widthTablet,
371 widthMobile: generateBlocksStyling.container.shapeDividers.widthMobile,
372 flipHorizontally: generateBlocksStyling.container.shapeDividers.flipHorizontally,
373 zindex: generateBlocksStyling.container.shapeDividers.zindex,
374 } );
375
376 setAttributes( { shapeDividers: shapeDividersValues } );
377 };
378
379 const handleRemoveShape = ( index ) => {
380 const shapeDividersValues = [ ...shapeDividers ];
381
382 shapeDividersValues.splice( index, 1 );
383 setAttributes( { shapeDividers: shapeDividersValues } );
384 };
385
386 const allShapes = [];
387
388 Object.keys( generateBlocksInfo.svgShapes ).forEach( ( key ) => {
389 const shapes = generateBlocksInfo.svgShapes[ key ].svgs;
390
391 Object.keys( shapes ).forEach( ( name ) => {
392 allShapes[ name ] = {
393 label: shapes[ name ].label,
394 icon: shapes[ name ].icon,
395 };
396 } );
397 } );
398
399 const allShapeDividers = () => {
400 return (
401 <Fragment>
402 { !! attributes.shapeDividers.length &&
403 <div className="gb-shapes">
404 {
405 attributes.shapeDividers.map( ( location, index ) => {
406 const shapeNumber = index + 1;
407
408 return <Fragment key={ index }>
409 { 'undefined' !== typeof allShapes[ shapeDividers[ index ].shape ] &&
410 <div
411 className={ classnames( {
412 'gb-shape': true,
413 [ `gb-shape-${ shapeNumber }` ]: true,
414 } ) }
415 dangerouslySetInnerHTML={ { __html: sanitizeSVG( allShapes[ shapeDividers[ index ].shape ].icon ) } }
416 />
417 }
418 </Fragment>;
419 } )
420 }
421 </div>
422 }
423 </Fragment>
424 );
425 };
426
427 const bgImageSizes = [];
428
429 Object.keys( generateBlocksInfo.imageSizes ).forEach( ( size ) => {
430 bgImageSizes.push( {
431 label: generateBlocksInfo.imageSizes[ size ],
432 value: generateBlocksInfo.imageSizes[ size ],
433 } );
434 } );
435
436 const hasFlexBasis = ( attribute ) => {
437 return hasNumericValue( attribute ) && 'auto' !== attribute;
438 };
439
440 const hideWidthDesktop = hasFlexBasis( flexBasis );
441 const hideWidthTablet = 'auto' !== flexBasisTablet && ( hasFlexBasis( flexBasis ) || hasFlexBasis( flexBasisTablet ) );
442 const hideWidthMobile = 'auto' !== flexBasisMobile && ( hasFlexBasis( flexBasis ) || hasFlexBasis( flexBasisTablet ) || hasFlexBasis( flexBasisMobile ) );
443
444 let hasStyling = (
445 !! backgroundColor ||
446 attributes.borderSizeTop || attributes.borderSizeRight || attributes.borderSizeBottom || attributes.borderSizeLeft
447 );
448
449 hasStyling = applyFilters( 'generateblocks.editor.containerHasStyling', hasStyling, this.props );
450
451 let htmlAttributes = {
452 className: classnames( {
453 'gb-container': true,
454 [ `gb-container-${ uniqueId }` ]: true,
455 [ `${ className }` ]: undefined !== className,
456 'gb-container-empty': ! hasChildBlocks,
457 'gb-container-visual-guides': ! hasChildBlocks && ! hasStyling && ! this.props.isSelected,
458 } ),
459 id: anchor ? anchor : null,
460 };
461
462 htmlAttributes = applyFilters( 'generateblocks.frontend.htmlAttributes', htmlAttributes, 'generateblocks/container', attributes );
463
464 return (
465 <Fragment>
466 <BlockControls>
467 { 'Desktop' === this.getDeviceType() && (
468 <AlignmentToolbar
469 value={ alignment }
470 onChange={ ( value ) => {
471 setAttributes( { alignment: value } );
472 } }
473 />
474 ) }
475
476 { 'Tablet' === this.getDeviceType() && (
477 <AlignmentToolbar
478 value={ alignmentTablet }
479 onChange={ ( value ) => {
480 setAttributes( { alignmentTablet: value } );
481 } }
482 />
483 ) }
484
485 { 'Mobile' === this.getDeviceType() && (
486 <AlignmentToolbar
487 value={ alignmentMobile }
488 onChange={ ( value ) => {
489 setAttributes( { alignmentMobile: value } );
490 } }
491 />
492 ) }
493 </BlockControls>
494
495 <InspectorControls>
496 <ResponsiveTabs { ...this.props }
497 selectedDevice={ this.getDeviceType() }
498 onClick={ ( device ) => {
499 this.setDeviceType( device );
500 } }
501 />
502
503 { ! isGrid && (
504 <PanelArea { ...this.props }
505 title={ __( 'Layout', 'generateblocks' ) }
506 initialOpen={ true }
507 icon={ getIcon( 'layout' ) }
508 className={ 'gblocks-panel-label' }
509 id={ 'containerLayout' }
510 state={ this.state }
511 >
512 { 'Desktop' === this.getDeviceType() &&
513 <Fragment>
514 { hasGridContainer &&
515 <ToggleControl
516 label={ __( 'Grid Item', 'generateblocks' ) }
517 help={ __( 'This Container is inside a Grid Block but is not set as a grid item. Enable this option for optimal results.', 'generateblocks' ) }
518 checked={ !! isGrid }
519 onChange={ ( value ) => {
520 setAttributes( {
521 isGrid: value,
522 gridId: gridContainerId,
523 } );
524 } }
525 />
526 }
527
528 <SelectControl
529 label={ __( 'Container', 'generateblocks' ) }
530 value={ outerContainer }
531 options={ [
532 { label: __( 'Full width', 'generateblocks' ), value: 'full' },
533 { label: __( 'Contained width', 'generateblocks' ), value: 'contained' },
534 ] }
535 onChange={ ( value ) => {
536 setAttributes( {
537 outerContainer: value,
538 } );
539
540 if ( 'contained' === value && 'full' === align ) {
541 setAttributes( {
542 align: '',
543 } );
544 }
545 } }
546 />
547
548 { 'full' === outerContainer &&
549 <SelectControl
550 label={ __( 'Inner Container', 'generateblocks' ) }
551 value={ innerContainer }
552 options={ [
553 { label: __( 'Full width', 'generateblocks' ), value: 'full' },
554 { label: __( 'Contained width', 'generateblocks' ), value: 'contained' },
555 ] }
556 onChange={ ( value ) => {
557 setAttributes( {
558 innerContainer: value,
559 } );
560 } }
561 />
562 }
563
564 { ( 'contained' === outerContainer || 'contained' === innerContainer ) &&
565 <Fragment>
566 <UnitPicker
567 label={ __( 'Container Width', 'generateblocks' ) }
568 value={ 'px' }
569 units={ [ 'px' ] }
570 onClick={ () => {
571 return false;
572 } }
573 />
574
575 <TextControl
576 type={ 'number' }
577 className="gblocks-container-width"
578 value={ parseFloat( containerWidth ) || '' }
579 placeholder={ generateBlocksDefaults.container.containerWidth }
580 onChange={ ( value ) => {
581 setAttributes( {
582 containerWidth: '' !== value ? parseFloat( value ) : undefined,
583 } );
584 } }
585 />
586 </Fragment>
587 }
588
589 <SelectControl
590 label={ __( 'Tag Name', 'generateblocks' ) }
591 value={ tagName }
592 options={ tagNames }
593 onChange={ ( value ) => {
594 setAttributes( {
595 tagName: filterTagName( value ),
596 } );
597 } }
598 />
599
600 { applyFilters( 'generateblocks.editor.controls', '', 'containerAfterElementTag', this.props, this.state ) }
601 </Fragment>
602 }
603
604 { applyFilters( 'generateblocks.editor.controls', '', 'containerLayout', this.props, this.state ) }
605 </PanelArea>
606 ) }
607
608 { isGrid && (
609 <PanelArea { ...this.props }
610 title={ __( 'Layout', 'generateblocks' ) }
611 initialOpen={ true }
612 icon={ getIcon( 'layout' ) }
613 className={ 'gblocks-panel-label' }
614 id={ 'containerGridLayout' }
615 state={ this.state }
616 >
617 { ! hasGridContainer &&
618 <ToggleControl
619 label={ __( 'Grid Item', 'generateblocks' ) }
620 help={ __( 'This container is set as a grid item but is not inside a grid block. Deactivate this option for optimal results.', 'generateblocks' ) }
621 checked={ !! isGrid }
622 onChange={ ( value ) => {
623 setAttributes( {
624 isGrid: value,
625 gridId: '',
626 } );
627 } }
628 />
629 }
630
631 { 'Desktop' === this.getDeviceType() && (
632 <Fragment>
633 <BaseControl>
634 <UnitPicker
635 label={ __( 'Container Width', 'generateblocks' ) }
636 value={ '%' }
637 units={ [ '%' ] }
638 onClick={ () => {
639 return false;
640 } }
641 />
642
643 { !! hideWidthDesktop &&
644 <div className="gblocks-small-notice-description">
645 { __( 'Width disabled as Flex Basis is not "auto".', 'generateblocks' ) }
646 </div>
647 }
648
649 <ButtonGroup className={ 'widthButtons' }>
650 <Button isPrimary={ width === 25 } onClick={ () => setAttributes( { width: 25 } ) } disabled={ hideWidthDesktop }>25</Button>
651 <Button isPrimary={ width === 33.33 } onClick={ () => setAttributes( { width: 33.33 } ) } disabled={ hideWidthDesktop }>33</Button>
652 <Button isPrimary={ width === 50 } onClick={ () => setAttributes( { width: 50 } ) } disabled={ hideWidthDesktop }>50</Button>
653 <Button isPrimary={ width === 66.66 } onClick={ () => setAttributes( { width: 66.66 } ) } disabled={ hideWidthDesktop }>66</Button>
654 <Button isPrimary={ width === 75 } onClick={ () => setAttributes( { width: 75 } ) } disabled={ hideWidthDesktop }>75</Button>
655 <Button isPrimary={ width === 100 } onClick={ () => setAttributes( { width: 100 } ) } disabled={ hideWidthDesktop }>100</Button>
656 </ButtonGroup>
657
658 <RangeControlInput
659 value={ hasNumericValue( width ) ? width : '' }
660 onChange={ ( value ) => {
661 // No zero value or values that start with zero.
662 if ( String( value ).startsWith( 0 ) ) {
663 value = '';
664 }
665
666 setAttributes( {
667 width: value,
668 } );
669 } }
670 rangeMin={ 10 }
671 rangeMax={ 100 }
672 step={ 5 }
673 initialPosition={ generateBlocksDefaults.container.width }
674 disabled={ hideWidthDesktop }
675 />
676 </BaseControl>
677
678 <BaseControl
679 className="gblocks-flex-controls"
680 >
681 <div className="gblocks-utility-label">
682 <label
683 htmlFor="gblocks-flex-grow-desktop"
684 className="components-base-control__label"
685 >
686 { __( 'Flex', 'generateblocks' ) }
687 </label>
688
689 <Tooltip text={ __( 'Reset', 'generateblocks' ) } position="top">
690 <Button
691 className="gblocks-reset-button"
692 icon={ getIcon( 'reset' ) }
693 onClick={ () => {
694 setAttributes( {
695 flexGrow: '',
696 flexShrink: '',
697 flexBasis: '',
698 } );
699 } }
700 />
701 </Tooltip>
702 </div>
703
704 <div className="gblocks-flex-controls-inner">
705 <TextControl
706 help={ __( 'Grow', 'generateblocks' ) }
707 id="gblocks-flex-grow-desktop"
708 type={ 'number' }
709 value={ flexGrow }
710 min="0"
711 step="1"
712 placeholder="0"
713 onChange={ ( value ) => {
714 setAttributes( {
715 flexGrow: value,
716 } );
717 } }
718 onBlur={ () => {
719 if ( '' !== flexGrow ) {
720 setAttributes( {
721 flexGrow: parseFloat( flexGrow ),
722 } );
723 }
724 } }
725 onClick={ ( e ) => {
726 // Make sure onBlur fires in Firefox.
727 e.currentTarget.focus();
728 } }
729 />
730
731 <TextControl
732 help={ __( 'Shrink', 'generateblocks' ) }
733 type={ 'number' }
734 value={ flexShrink }
735 min="0"
736 step="1"
737 placeholder="1"
738 onChange={ ( value ) => {
739 setAttributes( {
740 flexShrink: value,
741 } );
742 } }
743 onBlur={ () => {
744 if ( '' !== flexShrink ) {
745 setAttributes( {
746 flexShrink: parseFloat( flexShrink ),
747 } );
748 }
749 } }
750 onClick={ ( e ) => {
751 // Make sure onBlur fires in Firefox.
752 e.currentTarget.focus();
753 } }
754 />
755
756 <div className="gblocks-flex-basis-wrapper">
757 { ! isNaN( flexBasis ) &&
758 <UnitPicker
759 value={ flexBasisUnit }
760 units={ [ 'px', '%' ] }
761 onClick={ ( value ) => {
762 setAttributes( {
763 flexBasisUnit: value,
764 } );
765 } }
766 />
767 }
768
769 <TextControl
770 help={ __( 'Basis', 'generateblocks' ) }
771 type={ 'text' }
772 placeholder="auto"
773 value={ flexBasis }
774 onChange={ ( value ) => {
775 setAttributes( {
776 flexBasis: value,
777 } );
778 } }
779 onBlur={ () => {
780 if ( ! flexBasis.match( /(auto|fill|max-content|min-content|fit-content|content|inherit|initial|revert|unset|[0-9.]+)/g ) ) {
781 setAttributes( {
782 flexBasis: '',
783 } );
784 }
785 } }
786 />
787 </div>
788 </div>
789 </BaseControl>
790
791 <SelectControl
792 label={ __( 'Vertical Alignment', 'generateblocks' ) }
793 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
794 value={ verticalAlignment }
795 options={ [
796 { label: __( 'Default', 'generateblocks' ), value: '' },
797 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
798 { label: __( 'Center', 'generateblocks' ), value: 'center' },
799 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
800 ] }
801 onChange={ ( value ) => {
802 setAttributes( {
803 verticalAlignment: value,
804 } );
805 } }
806 />
807
808 <ToggleControl
809 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
810 checked={ !! removeVerticalGap }
811 onChange={ ( value ) => {
812 setAttributes( {
813 removeVerticalGap: value,
814 } );
815 } }
816 />
817
818 <SelectControl
819 label={ __( 'Tag Name', 'generateblocks' ) }
820 value={ tagName }
821 options={ tagNames }
822 onChange={ ( value ) => {
823 setAttributes( {
824 tagName: filterTagName( value ),
825 } );
826 } }
827 />
828
829 { applyFilters( 'generateblocks.editor.controls', '', 'containerAfterElementTag', this.props, this.state ) }
830 </Fragment>
831 ) }
832
833 { 'Tablet' === this.getDeviceType() && (
834 <Fragment>
835 <BaseControl>
836 <UnitPicker
837 label={ __( 'Container Width', 'generateblocks' ) }
838 value={ '%' }
839 units={ [ '%' ] }
840 onClick={ () => {
841 return false;
842 } }
843 />
844
845 { !! hideWidthTablet &&
846 <div className="gblocks-small-notice-description">
847 { __( 'Width disabled as Flex Basis is not "auto".', 'generateblocks' ) }
848 </div>
849 }
850
851 <ButtonGroup className={ 'widthButtons' }>
852 <Button isPrimary={ !! autoWidthTablet } disabled={ hideWidthTablet } onClick={ () => {
853 if ( autoWidthTablet ) {
854 setAttributes( { autoWidthTablet: false } );
855 } else {
856 setAttributes( { autoWidthTablet: true } );
857 }
858 } }>
859 { __( 'Auto', 'generateblocks' ) }
860 </Button>
861
862 <Button isPrimary={ widthTablet === 25 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 25, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>25</Button>
863 <Button isPrimary={ widthTablet === 33.33 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 33.33, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>33</Button>
864 <Button isPrimary={ widthTablet === 50 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 50, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>50</Button>
865 <Button isPrimary={ widthTablet === 66.66 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 66.66, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>66</Button>
866 <Button isPrimary={ widthTablet === 75 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 75, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>75</Button>
867 <Button isPrimary={ widthTablet === 100 && ! autoWidthTablet } onClick={ () => setAttributes( { widthTablet: 100, autoWidthTablet: false } ) } disabled={ hideWidthTablet }>100</Button>
868 </ButtonGroup>
869
870 { ! autoWidthTablet &&
871 <RangeControlInput
872 value={ hasNumericValue( widthTablet ) ? widthTablet : '' }
873 onChange={ ( value ) => {
874 // No zero value or values that start with zero.
875 if ( String( value ).startsWith( 0 ) ) {
876 value = '';
877 }
878
879 setAttributes( {
880 widthTablet: value,
881 autoWidthTablet: false,
882 } );
883 } }
884 rangeMin={ 10 }
885 rangeMax={ 100 }
886 step={ 5 }
887 initialPosition={ generateBlocksDefaults.container.widthTablet }
888 disabled={ hideWidthTablet }
889 />
890 }
891 </BaseControl>
892
893 <BaseControl
894 className="gblocks-flex-controls"
895 >
896 <div className="gblocks-utility-label">
897 <label
898 htmlFor="gblocks-flex-grow-tablet"
899 className="components-base-control__label"
900 >
901 { __( 'Flex', 'generateblocks' ) }
902 </label>
903
904 <Tooltip text={ __( 'Reset', 'generateblocks' ) } position="top">
905 <Button
906 className="gblocks-reset-button"
907 icon={ getIcon( 'reset' ) }
908 onClick={ () => {
909 setAttributes( {
910 flexGrowTablet: '',
911 flexShrinkTablet: '',
912 flexBasisTablet: '',
913 } );
914 } }
915 />
916 </Tooltip>
917 </div>
918
919 <div className="gblocks-flex-controls-inner">
920 <TextControl
921 help={ __( 'Grow', 'generateblocks' ) }
922 id="gblocks-flex-grow-tablet"
923 type={ 'number' }
924 value={ flexGrowTablet }
925 min="0"
926 step="1"
927 placeholder={ getResponsivePlaceholder( 'flexGrow', attributes, 'Tablet', '0' ) }
928 onChange={ ( value ) => {
929 setAttributes( {
930 flexGrowTablet: value,
931 } );
932 } }
933 onBlur={ () => {
934 if ( '' !== flexGrowTablet ) {
935 setAttributes( {
936 flexGrowTablet: parseFloat( flexGrowTablet ),
937 } );
938 }
939 } }
940 onClick={ ( e ) => {
941 // Make sure onBlur fires in Firefox.
942 e.currentTarget.focus();
943 } }
944 />
945
946 <TextControl
947 help={ __( 'Shrink', 'generateblocks' ) }
948 type={ 'number' }
949 value={ flexShrinkTablet }
950 min="0"
951 step="1"
952 placeholder={ getResponsivePlaceholder( 'flexShrink', attributes, 'Tablet', '1' ) }
953 onChange={ ( value ) => {
954 setAttributes( {
955 flexShrinkTablet: value,
956 } );
957 } }
958 onBlur={ () => {
959 if ( '' !== flexShrinkTablet ) {
960 setAttributes( {
961 flexShrinkTablet: parseFloat( flexShrinkTablet ),
962 } );
963 }
964 } }
965 onClick={ ( e ) => {
966 // Make sure onBlur fires in Firefox.
967 e.currentTarget.focus();
968 } }
969 />
970
971 <div className="gblocks-flex-basis-wrapper">
972 { ! isNaN( flexBasisTablet ) &&
973 <UnitPicker
974 value={ flexBasisUnit }
975 units={ [ 'px', '%' ] }
976 onClick={ ( value ) => {
977 setAttributes( {
978 flexBasisUnit: value,
979 } );
980 } }
981 />
982 }
983
984 <TextControl
985 help={ __( 'Basis', 'generateblocks' ) }
986 type={ 'text' }
987 value={ flexBasisTablet }
988 placeholder={ getResponsivePlaceholder( 'flexBasis', attributes, 'Tablet', 'auto' ) }
989 onChange={ ( value ) => {
990 setAttributes( {
991 flexBasisTablet: value,
992 } );
993 } }
994 onBlur={ () => {
995 if ( ! flexBasisTablet.match( /(auto|fill|max-content|min-content|fit-content|content|inherit|initial|revert|unset|[0-9.]+)/g ) ) {
996 setAttributes( {
997 flexBasisTablet: '',
998 } );
999 }
1000 } }
1001 />
1002 </div>
1003 </div>
1004 </BaseControl>
1005
1006 <SelectControl
1007 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1008 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
1009 value={ verticalAlignmentTablet }
1010 options={ [
1011 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1012 { label: __( 'Default', 'generateblocks' ), value: '' },
1013 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1014 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1015 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1016 ] }
1017 onChange={ ( value ) => {
1018 setAttributes( {
1019 verticalAlignmentTablet: value,
1020 } );
1021 } }
1022 />
1023
1024 <ToggleControl
1025 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
1026 checked={ !! removeVerticalGapTablet }
1027 onChange={ ( value ) => {
1028 setAttributes( {
1029 removeVerticalGapTablet: value,
1030 } );
1031 } }
1032 />
1033
1034 <TextControl
1035 type={ 'number' }
1036 label={ __( 'Order', 'generateblocks' ) }
1037 value={ orderTablet || 0 === orderTablet ? orderTablet : '' }
1038 onChange={ ( value ) => {
1039 setAttributes( {
1040 orderTablet: parseFloat( value ),
1041 } );
1042 } }
1043 />
1044 </Fragment>
1045 ) }
1046
1047 { 'Mobile' === this.getDeviceType() && (
1048 <Fragment>
1049 <BaseControl>
1050 <UnitPicker
1051 label={ __( 'Container Width', 'generateblocks' ) }
1052 value={ '%' }
1053 units={ [ '%' ] }
1054 onClick={ () => {
1055 return false;
1056 } }
1057 />
1058
1059 { !! hideWidthMobile &&
1060 <div className="gblocks-small-notice-description">
1061 { __( 'Width disabled as Flex Basis is not "auto".', 'generateblocks' ) }
1062 </div>
1063 }
1064
1065 <ButtonGroup className={ 'widthButtons' }>
1066 <Button isPrimary={ !! autoWidthMobile } disabled={ hideWidthMobile } onClick={ () => {
1067 if ( autoWidthMobile ) {
1068 setAttributes( { autoWidthMobile: false } );
1069 } else {
1070 setAttributes( { autoWidthMobile: true } );
1071 }
1072 } }>
1073 { __( 'Auto', 'generateblocks' ) }
1074 </Button>
1075
1076 <Button isPrimary={ widthMobile === 25 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 25, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>25</Button>
1077 <Button isPrimary={ widthMobile === 33.33 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 33.33, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>33</Button>
1078 <Button isPrimary={ widthMobile === 50 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 50, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>50</Button>
1079 <Button isPrimary={ widthMobile === 66.66 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 66.66, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>66</Button>
1080 <Button isPrimary={ widthMobile === 75 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 75, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>75</Button>
1081 <Button isPrimary={ widthMobile === 100 && ! autoWidthMobile } onClick={ () => setAttributes( { widthMobile: 100, autoWidthMobile: false } ) } disabled={ hideWidthMobile }>100</Button>
1082 </ButtonGroup>
1083
1084 { ! autoWidthMobile &&
1085 <RangeControlInput
1086 value={ hasNumericValue( widthMobile ) ? widthMobile : '' }
1087 onChange={ ( value ) => {
1088 // No zero value or values that start with zero.
1089 if ( String( value ).startsWith( 0 ) ) {
1090 value = '';
1091 }
1092
1093 setAttributes( {
1094 widthMobile: value,
1095 autoWidthMobile: false,
1096 } );
1097 } }
1098 rangeMin={ 10 }
1099 rangeMax={ 100 }
1100 step={ 5 }
1101 initialPosition={ generateBlocksDefaults.container.widthMobile }
1102 disabled={ hideWidthMobile }
1103 />
1104 }
1105 </BaseControl>
1106
1107 <BaseControl
1108 className="gblocks-flex-controls"
1109 >
1110 <div className="gblocks-utility-label">
1111 <label
1112 htmlFor="gblocks-flex-grow-mobile"
1113 className="components-base-control__label"
1114 >
1115 { __( 'Flex', 'generateblocks' ) }
1116 </label>
1117
1118 <Tooltip text={ __( 'Reset', 'generateblocks' ) } position="top">
1119 <Button
1120 className="gblocks-reset-button"
1121 icon={ getIcon( 'reset' ) }
1122 onClick={ () => {
1123 setAttributes( {
1124 flexGrowMobile: '',
1125 flexShrinkMobile: '',
1126 flexBasisMobile: '',
1127 } );
1128 } }
1129 />
1130 </Tooltip>
1131 </div>
1132
1133 <div className="gblocks-flex-controls-inner">
1134 <TextControl
1135 help={ __( 'Grow', 'generateblocks' ) }
1136 id="gblocks-flex-grow-mobile"
1137 type={ 'number' }
1138 value={ flexGrowMobile }
1139 min="0"
1140 step="1"
1141 placeholder={ getResponsivePlaceholder( 'flexGrow', attributes, 'Mobile', '0' ) }
1142 onChange={ ( value ) => {
1143 setAttributes( {
1144 flexGrowMobile: value,
1145 } );
1146 } }
1147 onBlur={ () => {
1148 if ( '' !== flexGrowMobile ) {
1149 setAttributes( {
1150 flexGrowMobile: parseFloat( flexGrowMobile ),
1151 } );
1152 }
1153 } }
1154 onClick={ ( e ) => {
1155 // Make sure onBlur fires in Firefox.
1156 e.currentTarget.focus();
1157 } }
1158 />
1159
1160 <TextControl
1161 help={ __( 'Shrink', 'generateblocks' ) }
1162 type={ 'number' }
1163 value={ flexShrinkMobile }
1164 min="0"
1165 step="1"
1166 placeholder={ getResponsivePlaceholder( 'flexShrink', attributes, 'Mobile', '1' ) }
1167 onChange={ ( value ) => {
1168 setAttributes( {
1169 flexShrinkMobile: value,
1170 } );
1171 } }
1172 onBlur={ () => {
1173 if ( '' !== flexShrinkMobile ) {
1174 setAttributes( {
1175 flexShrinkMobile: parseFloat( flexShrinkMobile ),
1176 } );
1177 }
1178 } }
1179 onClick={ ( e ) => {
1180 // Make sure onBlur fires in Firefox.
1181 e.currentTarget.focus();
1182 } }
1183 />
1184
1185 <div className="gblocks-flex-basis-wrapper">
1186 { ! isNaN( flexBasisMobile ) &&
1187 <UnitPicker
1188 value={ flexBasisUnit }
1189 units={ [ 'px', '%' ] }
1190 onClick={ ( value ) => {
1191 setAttributes( {
1192 flexBasisUnit: value,
1193 } );
1194 } }
1195 />
1196 }
1197
1198 <TextControl
1199 help={ __( 'Basis', 'generateblocks' ) }
1200 type={ 'text' }
1201 value={ flexBasisMobile }
1202 placeholder={ getResponsivePlaceholder( 'flexBasis', attributes, 'Mobile', 'auto' ) }
1203 onChange={ ( value ) => {
1204 setAttributes( {
1205 flexBasisMobile: value,
1206 } );
1207 } }
1208 onBlur={ () => {
1209 if ( ! flexBasisMobile.match( /(auto|fill|max-content|min-content|fit-content|content|inherit|initial|revert|unset|[0-9.]+)/g ) ) {
1210 setAttributes( {
1211 flexBasisMobile: '',
1212 } );
1213 }
1214 } }
1215 />
1216 </div>
1217 </div>
1218 </BaseControl>
1219
1220 <SelectControl
1221 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1222 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
1223 value={ verticalAlignmentMobile }
1224 options={ [
1225 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1226 { label: __( 'Default', 'generateblocks' ), value: '' },
1227 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1228 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1229 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1230 ] }
1231 onChange={ ( value ) => {
1232 setAttributes( {
1233 verticalAlignmentMobile: value,
1234 } );
1235 } }
1236 />
1237
1238 <ToggleControl
1239 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
1240 checked={ !! removeVerticalGapMobile }
1241 onChange={ ( value ) => {
1242 setAttributes( {
1243 removeVerticalGapMobile: value,
1244 } );
1245 } }
1246 />
1247
1248 <TextControl
1249 type={ 'number' }
1250 label={ __( 'Order', 'generateblocks' ) }
1251 value={ orderMobile || 0 === orderMobile ? orderMobile : '' }
1252 onChange={ ( value ) => {
1253 setAttributes( {
1254 orderMobile: parseFloat( value ),
1255 } );
1256 } }
1257 />
1258 </Fragment>
1259 ) }
1260
1261 { applyFilters( 'generateblocks.editor.controls', '', 'containerGridLayout', this.props, this.state ) }
1262 </PanelArea>
1263 ) }
1264
1265 <PanelArea { ...this.props }
1266 title={ __( 'Typography', 'generateblocks' ) }
1267 initialOpen={ false }
1268 icon={ getIcon( 'typography' ) }
1269 className={ 'gblocks-panel-label' }
1270 id={ 'containerTypography' }
1271 state={ this.state }
1272 >
1273
1274 { 'Desktop' === this.getDeviceType() && (
1275 <Fragment>
1276 <TypographyControls { ...this.props }
1277 showFontFamily={ true }
1278 showFontWeight={ true }
1279 showTextTransform={ true }
1280 showFontSize={ true }
1281 defaultFontSize={ generateBlocksDefaults.container.fontSize }
1282 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
1283 defaultLineHeight={ generateBlocksDefaults.container.lineHeight }
1284 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
1285 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacing }
1286 />
1287 </Fragment>
1288 ) }
1289
1290 { 'Tablet' === this.getDeviceType() && (
1291 <Fragment>
1292 <TypographyControls { ...this.props }
1293 device={ 'Tablet' }
1294 showFontSize={ true }
1295 disableAdvancedToggle={ true }
1296 defaultFontSize={ generateBlocksDefaults.container.fontSizeTablet }
1297 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
1298 defaultLineHeight={ generateBlocksDefaults.container.lineHeightTablet }
1299 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
1300 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacingTablet }
1301 />
1302 </Fragment>
1303 ) }
1304
1305 { 'Mobile' === this.getDeviceType() && (
1306 <Fragment>
1307 <TypographyControls { ...this.props }
1308 device={ 'Mobile' }
1309 showFontSize={ true }
1310 disableAdvancedToggle={ true }
1311 defaultFontSize={ generateBlocksDefaults.container.fontSizeMobile }
1312 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
1313 defaultLineHeight={ generateBlocksDefaults.container.lineHeightMobile }
1314 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
1315 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacingMobile }
1316 />
1317 </Fragment>
1318 ) }
1319
1320 { applyFilters( 'generateblocks.editor.controls', '', 'containerTypography', this.props, this.state ) }
1321 </PanelArea>
1322
1323 <PanelArea { ...this.props }
1324 title={ __( 'Spacing', 'generateblocks' ) }
1325 initialOpen={ false }
1326 icon={ getIcon( 'spacing' ) }
1327 className={ 'gblocks-panel-label' }
1328 id={ 'containerSpacing' }
1329 state={ this.state }
1330 >
1331
1332 { 'Desktop' === this.getDeviceType() && (
1333 <Fragment>
1334 <UnitPicker
1335 label={ __( 'Minimum Height', 'generateblocks' ) }
1336 value={ minHeightUnit }
1337 units={ [ 'px', 'vh', 'vw' ] }
1338 onClick={ ( value ) => {
1339 setAttributes( {
1340 minHeightUnit: value,
1341 } );
1342 } }
1343 />
1344
1345 <TextControl
1346 type={ 'number' }
1347 value={ minHeight ? minHeight : '' }
1348 onChange={ ( value ) => {
1349 setAttributes( {
1350 minHeight: parseFloat( value ),
1351 } );
1352 } }
1353 />
1354
1355 { !! minHeight && ! isGrid &&
1356 <SelectControl
1357 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1358 value={ verticalAlignment }
1359 options={ [
1360 { label: __( 'Default', 'generateblocks' ), value: '' },
1361 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1362 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1363 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1364 ] }
1365 onChange={ ( value ) => {
1366 setAttributes( {
1367 verticalAlignment: value,
1368 } );
1369 } }
1370 />
1371 }
1372
1373 <DimensionsControl { ...this.props }
1374 device={ this.getDeviceType() }
1375 type={ 'padding' }
1376 label={ __( 'Padding', 'generateblocks' ) }
1377 attrTop={ 'paddingTop' }
1378 attrRight={ 'paddingRight' }
1379 attrBottom={ 'paddingBottom' }
1380 attrLeft={ 'paddingLeft' }
1381 attrUnit={ 'paddingUnit' }
1382 attrSyncUnits={ 'paddingSyncUnits' }
1383 defaults={ generateBlocksDefaults.container }
1384 units={ [ 'px', 'em', '%' ] }
1385 />
1386
1387 <DimensionsControl { ...this.props }
1388 device={ this.getDeviceType() }
1389 type={ 'margin' }
1390 label={ __( 'Margin', 'generateblocks' ) }
1391 attrTop={ 'marginTop' }
1392 attrRight={ 'marginRight' }
1393 attrBottom={ 'marginBottom' }
1394 attrLeft={ 'marginLeft' }
1395 attrUnit={ 'marginUnit' }
1396 attrSyncUnits={ 'marginSyncUnits' }
1397 defaults={ generateBlocksDefaults.container }
1398 units={ [ 'px', 'em', '%' ] }
1399 />
1400
1401 <DimensionsControl { ...this.props }
1402 device={ this.getDeviceType() }
1403 type={ 'padding' }
1404 label={ __( 'Border Size', 'generateblocks' ) }
1405 attrTop={ 'borderSizeTop' }
1406 attrRight={ 'borderSizeRight' }
1407 attrBottom={ 'borderSizeBottom' }
1408 attrLeft={ 'borderSizeLeft' }
1409 attrSyncUnits={ 'borderSizeSyncUnits' }
1410 defaults={ generateBlocksDefaults.container }
1411 units={ [ 'px' ] }
1412 />
1413
1414 <DimensionsControl { ...this.props }
1415 device={ this.getDeviceType() }
1416 type={ 'padding' }
1417 label={ __( 'Border Radius', 'generateblocks' ) }
1418 attrTop={ 'borderRadiusTopLeft' }
1419 attrRight={ 'borderRadiusTopRight' }
1420 attrBottom={ 'borderRadiusBottomRight' }
1421 attrLeft={ 'borderRadiusBottomLeft' }
1422 attrUnit={ 'borderRadiusUnit' }
1423 attrSyncUnits={ 'borderRadiusSyncUnits' }
1424 labelTop={ __( 'T-Left', 'generateblocks' ) }
1425 labelRight={ __( 'T-Right', 'generateblocks' ) }
1426 labelBottom={ __( 'B-Right', 'generateblocks' ) }
1427 labelLeft={ __( 'B-Left', 'generateblocks' ) }
1428 defaults={ generateBlocksDefaults.container }
1429 units={ [ 'px', 'em', '%' ] }
1430 />
1431
1432 <TextControl
1433 label={ __( 'Outer z-index', 'generateblocks' ) }
1434 type={ 'number' }
1435 value={ zindex || 0 === zindex ? zindex : '' }
1436 onChange={ ( value ) => {
1437 setAttributes( {
1438 zindex: value,
1439 } );
1440 } }
1441 onBlur={ () => {
1442 setAttributes( {
1443 zindex: parseFloat( zindex ),
1444 } );
1445 } }
1446 onClick={ ( e ) => {
1447 // Make sure onBlur fires in Firefox.
1448 e.currentTarget.focus();
1449 } }
1450 />
1451
1452 <TextControl
1453 label={ __( 'Inner z-index', 'generateblocks' ) }
1454 type={ 'number' }
1455 value={ innerZindex || 0 === innerZindex ? innerZindex : '' }
1456 onChange={ ( value ) => {
1457 setAttributes( {
1458 innerZindex: value,
1459 } );
1460 } }
1461 onBlur={ () => {
1462 setAttributes( {
1463 innerZindex: parseFloat( innerZindex ),
1464 } );
1465 } }
1466 onClick={ ( e ) => {
1467 // Make sure onBlur fires in Firefox.
1468 e.currentTarget.focus();
1469 } }
1470 />
1471 </Fragment>
1472 ) }
1473
1474 { 'Tablet' === this.getDeviceType() && (
1475 <Fragment>
1476 <UnitPicker
1477 label={ __( 'Minimum Height', 'generateblocks' ) }
1478 value={ minHeightUnitTablet }
1479 units={ [ 'px', 'vh', 'vw' ] }
1480 onClick={ ( value ) => {
1481 setAttributes( {
1482 minHeightUnitTablet: value,
1483 } );
1484 } }
1485 />
1486
1487 <TextControl
1488 type={ 'number' }
1489 value={ minHeightTablet || 0 === minHeightTablet ? minHeightTablet : '' }
1490 onChange={ ( value ) => {
1491 setAttributes( {
1492 minHeightTablet: parseFloat( value ),
1493 } );
1494 } }
1495 />
1496
1497 { ( !! minHeight || !! minHeightTablet ) && ! isGrid &&
1498 <SelectControl
1499 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1500 value={ verticalAlignmentTablet }
1501 options={ [
1502 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1503 { label: __( 'Default', 'generateblocks' ), value: '' },
1504 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1505 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1506 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1507 ] }
1508 onChange={ ( value ) => {
1509 setAttributes( {
1510 verticalAlignmentTablet: value,
1511 } );
1512 } }
1513 />
1514 }
1515
1516 <DimensionsControl { ...this.props }
1517 device={ this.getDeviceType() }
1518 type={ 'padding' }
1519 label={ __( 'Padding', 'generateblocks' ) }
1520 attrTop={ 'paddingTopTablet' }
1521 attrRight={ 'paddingRightTablet' }
1522 attrBottom={ 'paddingBottomTablet' }
1523 attrLeft={ 'paddingLeftTablet' }
1524 attrUnit={ 'paddingUnit' }
1525 attrSyncUnits={ 'paddingSyncUnits' }
1526 defaults={ generateBlocksDefaults.container }
1527 units={ [ 'px', 'em', '%' ] }
1528 />
1529
1530 <DimensionsControl { ...this.props }
1531 device={ this.getDeviceType() }
1532 type={ 'margin' }
1533 label={ __( 'Margin', 'generateblocks' ) }
1534 attrTop={ 'marginTopTablet' }
1535 attrRight={ 'marginRightTablet' }
1536 attrBottom={ 'marginBottomTablet' }
1537 attrLeft={ 'marginLeftTablet' }
1538 attrUnit={ 'marginUnit' }
1539 attrSyncUnits={ 'marginSyncUnits' }
1540 defaults={ generateBlocksDefaults.container }
1541 units={ [ 'px', 'em', '%' ] }
1542 />
1543
1544 <DimensionsControl { ...this.props }
1545 device={ this.getDeviceType() }
1546 type={ 'padding' }
1547 label={ __( 'Border Size', 'generateblocks' ) }
1548 attrTop={ 'borderSizeTopTablet' }
1549 attrRight={ 'borderSizeRightTablet' }
1550 attrBottom={ 'borderSizeBottomTablet' }
1551 attrLeft={ 'borderSizeLeftTablet' }
1552 attrSyncUnits={ 'borderSizeSyncUnits' }
1553 defaults={ generateBlocksDefaults.container }
1554 units={ [ 'px' ] }
1555 />
1556
1557 <DimensionsControl { ...this.props }
1558 device={ this.getDeviceType() }
1559 type={ 'padding' }
1560 label={ __( 'Border Radius', 'generateblocks' ) }
1561 attrTop={ 'borderRadiusTopLeftTablet' }
1562 attrRight={ 'borderRadiusTopRightTablet' }
1563 attrBottom={ 'borderRadiusBottomRightTablet' }
1564 attrLeft={ 'borderRadiusBottomLeftTablet' }
1565 attrUnit={ 'borderRadiusUnit' }
1566 attrSyncUnits={ 'borderRadiusSyncUnits' }
1567 labelTop={ __( 'T-Left', 'generateblocks' ) }
1568 labelRight={ __( 'T-Right', 'generateblocks' ) }
1569 labelBottom={ __( 'B-Right', 'generateblocks' ) }
1570 labelLeft={ __( 'B-Left', 'generateblocks' ) }
1571 defaults={ generateBlocksDefaults.container }
1572 units={ [ 'px', 'em', '%' ] }
1573 />
1574 </Fragment>
1575 ) }
1576
1577 { 'Mobile' === this.getDeviceType() && (
1578 <Fragment>
1579 <UnitPicker
1580 label={ __( 'Minimum Height', 'generateblocks' ) }
1581 value={ minHeightUnitMobile }
1582 units={ [ 'px', 'vh', 'vw' ] }
1583 onClick={ ( value ) => {
1584 setAttributes( {
1585 minHeightUnitMobile: value,
1586 } );
1587 } }
1588 />
1589
1590 <TextControl
1591 type={ 'number' }
1592 value={ minHeightMobile || 0 === minHeightMobile ? minHeightMobile : '' }
1593 onChange={ ( value ) => {
1594 setAttributes( {
1595 minHeightMobile: parseFloat( value ),
1596 } );
1597 } }
1598 />
1599
1600 { ( !! minHeight || !! minHeightTablet || !! minHeightMobile ) && ! isGrid &&
1601 <SelectControl
1602 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1603 value={ verticalAlignmentMobile }
1604 options={ [
1605 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1606 { label: __( 'Default', 'generateblocks' ), value: '' },
1607 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1608 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1609 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1610 ] }
1611 onChange={ ( value ) => {
1612 setAttributes( {
1613 verticalAlignmentMobile: value,
1614 } );
1615 } }
1616 />
1617 }
1618
1619 <DimensionsControl { ...this.props }
1620 device={ this.getDeviceType() }
1621 type={ 'padding' }
1622 label={ __( 'Padding', 'generateblocks' ) }
1623 attrTop={ 'paddingTopMobile' }
1624 attrRight={ 'paddingRightMobile' }
1625 attrBottom={ 'paddingBottomMobile' }
1626 attrLeft={ 'paddingLeftMobile' }
1627 attrUnit={ 'paddingUnit' }
1628 attrSyncUnits={ 'paddingSyncUnits' }
1629 defaults={ generateBlocksDefaults.container }
1630 units={ [ 'px', 'em', '%' ] }
1631 />
1632
1633 <DimensionsControl { ...this.props }
1634 device={ this.getDeviceType() }
1635 type={ 'margin' }
1636 label={ __( 'Margin', 'generateblocks' ) }
1637 attrTop={ 'marginTopMobile' }
1638 attrRight={ 'marginRightMobile' }
1639 attrBottom={ 'marginBottomMobile' }
1640 attrLeft={ 'marginLeftMobile' }
1641 attrUnit={ 'marginUnit' }
1642 attrSyncUnits={ 'marginSyncUnits' }
1643 defaults={ generateBlocksDefaults.container }
1644 units={ [ 'px', 'em', '%' ] }
1645 />
1646
1647 <DimensionsControl { ...this.props }
1648 device={ this.getDeviceType() }
1649 type={ 'padding' }
1650 label={ __( 'Border Size', 'generateblocks' ) }
1651 attrTop={ 'borderSizeTopMobile' }
1652 attrRight={ 'borderSizeRightMobile' }
1653 attrBottom={ 'borderSizeBottomMobile' }
1654 attrLeft={ 'borderSizeLeftMobile' }
1655 attrSyncUnits={ 'borderSizeSyncUnits' }
1656 defaults={ generateBlocksDefaults.container }
1657 units={ [ 'px' ] }
1658 />
1659
1660 <DimensionsControl { ...this.props }
1661 device={ this.getDeviceType() }
1662 type={ 'padding' }
1663 label={ __( 'Border Radius', 'generateblocks' ) }
1664 attrTop={ 'borderRadiusTopLeftMobile' }
1665 attrRight={ 'borderRadiusTopRightMobile' }
1666 attrBottom={ 'borderRadiusBottomRightMobile' }
1667 attrLeft={ 'borderRadiusBottomLeftMobile' }
1668 attrUnit={ 'borderRadiusUnit' }
1669 attrSyncUnits={ 'borderRadiusSyncUnits' }
1670 labelTop={ __( 'T-Left', 'generateblocks' ) }
1671 labelRight={ __( 'T-Right', 'generateblocks' ) }
1672 labelBottom={ __( 'B-Right', 'generateblocks' ) }
1673 labelLeft={ __( 'B-Left', 'generateblocks' ) }
1674 defaults={ generateBlocksDefaults.container }
1675 units={ [ 'px', 'em', '%' ] }
1676 />
1677 </Fragment>
1678 ) }
1679
1680 { applyFilters( 'generateblocks.editor.controls', '', 'containerSpacing', this.props, this.state ) }
1681 </PanelArea>
1682
1683 <PanelArea { ...this.props }
1684 title={ __( 'Colors', 'generateblocks' ) }
1685 initialOpen={ false }
1686 icon={ getIcon( 'colors' ) }
1687 className={ 'gblocks-panel-label' }
1688 id={ 'containerColors' }
1689 state={ this.state }
1690 >
1691 { 'Desktop' === this.getDeviceType() &&
1692 <Fragment>
1693 <ColorPicker
1694 label={ __( 'Background Color', 'generateblocks' ) }
1695 value={ backgroundColor }
1696 alpha={ true }
1697 valueOpacity={ backgroundColorOpacity }
1698 attrOpacity={ 'backgroundColorOpacity' }
1699 onChange={ ( nextBackgroundColor ) =>
1700 setAttributes( {
1701 backgroundColor: nextBackgroundColor,
1702 } )
1703 }
1704 onOpacityChange={ ( value ) =>
1705 setAttributes( {
1706 backgroundColorOpacity: value,
1707 } )
1708 }
1709 />
1710
1711 <ColorPicker
1712 label={ __( 'Text Color', 'generateblocks' ) }
1713 value={ textColor }
1714 alpha={ false }
1715 onChange={ ( nextTextColor ) =>
1716 setAttributes( {
1717 textColor: nextTextColor,
1718 } )
1719 }
1720 />
1721
1722 <ColorPicker
1723 label={ __( 'Link Color', 'generateblocks' ) }
1724 value={ linkColor }
1725 alpha={ false }
1726 onChange={ ( nextLinkColor ) =>
1727 setAttributes( {
1728 linkColor: nextLinkColor,
1729 } )
1730 }
1731 />
1732
1733 <ColorPicker
1734 label={ __( 'Link Color Hover', 'generateblocks' ) }
1735 value={ linkColorHover }
1736 alpha={ false }
1737 onChange={ ( nextLinkColorHover ) =>
1738 setAttributes( {
1739 linkColorHover: nextLinkColorHover,
1740 } )
1741 }
1742 />
1743
1744 <ColorPicker
1745 label={ __( 'Border Color', 'generateblocks' ) }
1746 value={ borderColor }
1747 alpha={ true }
1748 valueOpacity={ borderColorOpacity }
1749 attrOpacity={ 'borderColorOpacity' }
1750 onChange={ ( value ) =>
1751 setAttributes( {
1752 borderColor: value,
1753 } )
1754 }
1755 onOpacityChange={ ( value ) =>
1756 setAttributes( {
1757 borderColorOpacity: value,
1758 } )
1759 }
1760 />
1761 </Fragment>
1762 }
1763
1764 { applyFilters( 'generateblocks.editor.controls', '', 'containerColors', this.props, this.state ) }
1765 </PanelArea>
1766
1767 <PanelArea { ...this.props }
1768 title={ __( 'Backgrounds', 'generateblocks' ) }
1769 initialOpen={ false }
1770 icon={ getIcon( 'gradients' ) }
1771 className={ 'gblocks-panel-label' }
1772 id={ 'containerBackground' }
1773 state={ this.state }
1774 >
1775 <Fragment>
1776 <BaseControl
1777 id="gblocks-background-image-upload"
1778 label={ __( 'Image URL', 'generateblocks' ) }
1779 >
1780 <div className="gblocks-bg-image-wrapper">
1781 <TextControl
1782 type={ 'text' }
1783 value={ !! bgImage ? bgImage.image.url : '' }
1784 onChange={ ( value ) => {
1785 if ( ! value ) {
1786 setAttributes( {
1787 bgImage: null,
1788 } );
1789 } else {
1790 setAttributes( {
1791 bgImage: {
1792 id: '',
1793 image: {
1794 url: value,
1795 },
1796 },
1797 } );
1798 }
1799 } }
1800 />
1801
1802 <div className="gblocks-background-image-action-buttons">
1803 <MediaUpload
1804 title={ __( 'Set background image', 'generateblocks' ) }
1805 onSelect={ ( media ) => {
1806 let size = generateBlocksDefaults.container.bgImageSize;
1807
1808 if ( 'undefined' === typeof media.sizes[ size ] ) {
1809 size = 'full';
1810 }
1811
1812 setAttributes( {
1813 bgImage: {
1814 id: media.id,
1815 image: media.sizes[ size ],
1816 },
1817 } );
1818 } }
1819 onClose={ () => {
1820 document.querySelector( '.gblocks-bg-image-wrapper input' ).focus();
1821 } }
1822 allowedTypes={ [ 'image' ] }
1823 value={ !! bgImage ? bgImage.id : '' }
1824 modalClass="editor-gb-container-background__media-modal"
1825 render={ ( { open } ) => (
1826 <Tooltip text={ __( 'Open the Media Library', 'generateblocks' ) }>
1827 <Button
1828 onClick={ open }
1829 className="is-secondary is-small"
1830 >
1831 { __( 'Browse', 'generateblocks' ) }
1832 </Button>
1833 </Tooltip>
1834 ) }
1835 />
1836
1837 { applyFilters( 'generateblocks.editor.backgroundImageActions', '', this.props, this.state ) }
1838 </div>
1839 </div>
1840 </BaseControl>
1841
1842 { !! bgImage && (
1843 <Fragment>
1844 { !! bgOptions.overlay ? ( // This option is deprecated, so only show it if it's in use.
1845 <Fragment>
1846 <ToggleControl
1847 label={ __( 'Background Color Overlay', 'generateblocks' ) }
1848 checked={ !! bgOptions.overlay }
1849 onChange={ ( nextOverlay ) => {
1850 setAttributes( {
1851 bgOptions: {
1852 ...bgOptions,
1853 overlay: nextOverlay,
1854 },
1855 } );
1856 } }
1857 />
1858
1859 <Notice
1860 className="gblocks-option-notice"
1861 status="info"
1862 isDismissible={ false }
1863 >
1864 { __( 'The background color overlay option is deprecated. Toggle this option to use the new method.', 'generateblocks' ) }
1865 </Notice>
1866 </Fragment>
1867 ) : ( // These options is only for people not using the deprecated overlay option.
1868 <Fragment>
1869 { 'undefined' !== typeof bgImage.id && bgImage.id &&
1870 <SelectControl
1871 label={ __( 'Image Size', 'generateblocks' ) }
1872 value={ bgImageSize }
1873 options={ bgImageSizes }
1874 onChange={ ( value ) => {
1875 setAttributes( {
1876 bgImageSize: value,
1877 } );
1878 } }
1879 />
1880 }
1881
1882 <SelectControl
1883 label={ __( 'Selector', 'generateblocks' ) }
1884 value={ bgOptions.selector }
1885 options={ [
1886 { label: __( 'Element', 'generateblocks' ), value: 'element' },
1887 { label: __( 'Pseudo Element', 'generateblocks' ), value: 'pseudo-element' },
1888 ] }
1889 onChange={ ( value ) => {
1890 setAttributes( {
1891 bgOptions: {
1892 ...bgOptions,
1893 selector: value,
1894 },
1895 } );
1896
1897 if ( 'pseudo-element' === value && ! innerZindex && 0 !== innerZindex ) {
1898 setAttributes( {
1899 innerZindex: 1,
1900 } );
1901 }
1902 } }
1903 />
1904
1905 <RangeControl
1906 label={ __( 'Image Opacity', 'generateblocks' ) }
1907 value={ bgOptions.opacity }
1908 onChange={ ( value ) => {
1909 setAttributes( {
1910 bgOptions: {
1911 ...bgOptions,
1912 opacity: value,
1913 selector: 'pseudo-element',
1914 },
1915 } );
1916
1917 if ( ! innerZindex && 0 !== innerZindex ) {
1918 setAttributes( {
1919 innerZindex: 1,
1920 } );
1921 }
1922 } }
1923 min={ 0 }
1924 max={ 1 }
1925 step={ 0.1 }
1926 initialPosition={ generateBlocksDefaults.container.bgOptions.opacity }
1927 />
1928
1929 { 1 !== bgOptions.opacity && 'pseudo-element' !== bgOptions.selector &&
1930 <Notice
1931 className="gblocks-option-notice"
1932 status="info"
1933 isDismissible={ false }
1934 >
1935 { __( 'Your selector must be set to Pseudo Element to use opacity.', 'generateblocks' ) }
1936 </Notice>
1937 }
1938 </Fragment>
1939 ) }
1940
1941 <TextControl
1942 label={ __( 'Size', 'generateblocks' ) }
1943 value={ bgOptions.size }
1944 onChange={ ( nextSize ) => {
1945 setAttributes( {
1946 bgOptions: {
1947 ...bgOptions,
1948 size: nextSize,
1949 },
1950 } );
1951 } }
1952 />
1953
1954 <TextControl
1955 label={ __( 'Position', 'generateblocks' ) }
1956 value={ bgOptions.position }
1957 onChange={ ( nextPosition ) => {
1958 setAttributes( {
1959 bgOptions: {
1960 ...bgOptions,
1961 position: nextPosition,
1962 },
1963 } );
1964 } }
1965 />
1966
1967 <SelectControl
1968 label={ __( 'Repeat', 'generateblocks' ) }
1969 value={ bgOptions.repeat }
1970 options={ [
1971 { label: 'no-repeat', value: 'no-repeat' },
1972 { label: 'repeat', value: 'repeat' },
1973 { label: 'repeat-x', value: 'repeat-x' },
1974 { label: 'repeat-y', value: 'repeat-y' },
1975 ] }
1976 onChange={ ( nextRepeat ) => {
1977 setAttributes( {
1978 bgOptions: {
1979 ...bgOptions,
1980 repeat: nextRepeat,
1981 },
1982 } );
1983 } }
1984 />
1985
1986 <SelectControl
1987 label={ __( 'Attachment', 'generateblocks' ) }
1988 value={ bgOptions.attachment }
1989 options={ [
1990 { label: 'scroll', value: '' },
1991 { label: 'fixed', value: 'fixed' },
1992 { label: 'local', value: 'local' },
1993 ] }
1994 onChange={ ( nextAttachment ) => {
1995 setAttributes( {
1996 bgOptions: {
1997 ...bgOptions,
1998 attachment: nextAttachment,
1999 },
2000 } );
2001 } }
2002 />
2003 </Fragment>
2004 ) }
2005
2006 <GradientControl { ...this.props }
2007 attrGradient={ 'gradient' }
2008 attrGradientDirection={ 'gradientDirection' }
2009 attrGradientColorOne={ 'gradientColorOne' }
2010 attrGradientColorStopOne={ 'gradientColorStopOne' }
2011 attrGradientColorTwo={ 'gradientColorTwo' }
2012 attrGradientColorStopTwo={ 'gradientColorStopTwo' }
2013 attrGradientColorOneOpacity={ 'gradientColorOneOpacity' }
2014 attrGradientColorTwoOpacity={ 'gradientColorTwoOpacity' }
2015 defaultColorOne={ generateBlocksDefaults.container.gradientColorOne }
2016 defaultColorTwo={ generateBlocksDefaults.container.gradientColorTwo }
2017 />
2018
2019 { applyFilters( 'generateblocks.editor.controls', '', 'containerBackground', this.props, this.state ) }
2020 </Fragment>
2021 </PanelArea>
2022
2023 <PanelArea { ...this.props }
2024 title={ __( 'Shapes', 'generateblocks' ) }
2025 initialOpen={ false }
2026 icon={ getIcon( 'shapes' ) }
2027 className={ 'gblocks-panel-label' }
2028 id={ 'containerShapes' }
2029 state={ this.state }
2030 showPanel={ 'Desktop' === this.getDeviceType() || attributes.shapeDividers.length ? true : false }
2031 >
2032 <BaseControl className="gb-icon-chooser gb-shape-chooser">
2033 {
2034 shapeDividers.map( ( location, index ) => {
2035 const shapeNumber = index + 1;
2036
2037 return <Fragment key={ index }>
2038 <div className="gblocks-shape-container">
2039 <div
2040 className={ classnames( {
2041 'gblocks-shape-toggle-preview': true,
2042 [ `gblocks-shape-toggle-preview-${ shapeNumber }` ]: true,
2043 } ) }
2044 style={ { backgroundColor } }
2045 >
2046 { 'undefined' !== typeof allShapes[ shapeDividers[ index ].shape ] &&
2047 <div
2048 className="gblocks-shape-divider-preview"
2049 style={ { color: shapeDividers[ index ].color } }
2050 dangerouslySetInnerHTML={ { __html: sanitizeSVG( allShapes[ shapeDividers[ index ].shape ].icon ) } }
2051 />
2052 }
2053 </div>
2054
2055 {
2056 /* translators: Shape number */
2057 sprintf( __( 'Shape %s', 'generateblocks' ), shapeNumber )
2058 }
2059
2060 <Fragment>
2061 <Dropdown
2062 contentClassName="gblocks-shapes-dropdown"
2063 renderToggle={ ( { isOpen, onToggle } ) => (
2064 <Tooltip text={ __( 'Edit Shape', 'generateblocks' ) }>
2065 <Button
2066 className="gblocks-shape-dropdown"
2067 isSecondary={ isOpen ? undefined : true }
2068 isPrimary={ isOpen ? true : undefined }
2069 icon={ getIcon( 'wrench' ) }
2070 onClick={ onToggle }
2071 aria-expanded={ isOpen }
2072 />
2073 </Tooltip>
2074 ) }
2075 renderContent={ () => (
2076 <div className="gblocks-shape-controls">
2077 { 'Desktop' === this.getDeviceType() &&
2078 <Fragment>
2079 <BaseControl className="gb-icon-chooser">
2080 {
2081 Object.keys( generateBlocksInfo.svgShapes ).map( ( svg, i ) => {
2082 const svgItems = generateBlocksInfo.svgShapes[ svg ].svgs;
2083
2084 return (
2085 <PanelBody
2086 title={ generateBlocksInfo.svgShapes[ svg ].group }
2087 initialOpen={ svgItems.hasOwnProperty( shapeDividers[ index ].shape ) }
2088 key={ i }
2089 >
2090 <PanelRow>
2091 <BaseControl>
2092 <ul className="gblocks-icon-chooser gblocks-shape-chooser">
2093 {
2094 Object.keys( svgItems ).map( ( svgItem, iconIndex ) => {
2095 return (
2096 <li key={ `editor-pblock-types-list-item-${ iconIndex }` }>
2097 <Tooltip text={ ( svgItems[ svgItem ].label ) }>
2098 <Button
2099 className={ classnames( {
2100 'editor-block-list-item-button': true,
2101 'gblocks-shape-is-active': shapeDividers[ index ].shape === svgItem,
2102 } ) }
2103 onClick={ () => {
2104 const shapes = [ ...shapeDividers ];
2105
2106 shapes[ index ] = {
2107 ...shapes[ index ],
2108 shape: svgItem,
2109 };
2110
2111 setAttributes( {
2112 shapeDividers: shapes,
2113 } );
2114 } }
2115 >
2116 { 'string' === typeof svgItems[ svgItem ].icon ? (
2117 <Fragment>
2118 <span
2119 className="editor-block-types-list__item-icon"
2120 dangerouslySetInnerHTML={ { __html: sanitizeSVG( svgItems[ svgItem ].icon ) } }
2121 />
2122 </Fragment>
2123 ) : (
2124 <Fragment>
2125 <span className="editor-block-types-list__item-icon">
2126 { svgItems[ svgItem ].icon }
2127 </span>
2128 </Fragment>
2129 ) }
2130 </Button>
2131 </Tooltip>
2132 </li>
2133 );
2134 } )
2135 }
2136 </ul>
2137 </BaseControl>
2138 </PanelRow>
2139 </PanelBody>
2140 );
2141 } )
2142 }
2143 </BaseControl>
2144
2145 <ColorPicker
2146 label={ __( 'Color', 'generateblocks' ) }
2147 value={ shapeDividers[ index ].color }
2148 alpha={ true }
2149 valueOpacity={ shapeDividers[ index ].colorOpacity }
2150 onChange={ ( value ) => {
2151 const shapes = [ ...shapeDividers ];
2152
2153 shapes[ index ] = {
2154 ...shapes[ index ],
2155 color: value,
2156 };
2157
2158 setAttributes( {
2159 shapeDividers: shapes,
2160 } );
2161 } }
2162 onOpacityChange={ ( value ) => {
2163 const shapes = [ ...shapeDividers ];
2164
2165 shapes[ index ] = {
2166 ...shapes[ index ],
2167 colorOpacity: value,
2168 };
2169
2170 setAttributes( {
2171 shapeDividers: shapes,
2172 } );
2173 } }
2174 />
2175
2176 <SelectControl
2177 label={ __( 'Location', 'generateblocks' ) }
2178 value={ shapeDividers[ index ].location }
2179 options={ [
2180 { label: __( 'Top', 'generateblocks' ), value: 'top' },
2181 { label: __( 'Bottom', 'generateblocks' ), value: 'bottom' },
2182 ] }
2183 onChange={ ( value ) => {
2184 const shapes = [ ...shapeDividers ];
2185
2186 shapes[ index ] = {
2187 ...shapes[ index ],
2188 location: value,
2189 };
2190
2191 setAttributes( {
2192 shapeDividers: shapes,
2193 } );
2194 } }
2195 />
2196
2197 <UnitPicker
2198 label={ __( 'Height', 'generateblocks' ) }
2199 value={ 'px' }
2200 units={ [ 'px' ] }
2201 onClick={ () => {
2202 return false;
2203 } }
2204 />
2205
2206 <TextControl
2207 type={ 'number' }
2208 value={ shapeDividers[ index ].height ? shapeDividers[ index ].height : '' }
2209 onChange={ ( value ) => {
2210 const shapes = [ ...shapeDividers ];
2211
2212 shapes[ index ] = {
2213 ...shapes[ index ],
2214 height: parseFloat( value ),
2215 };
2216
2217 setAttributes( {
2218 shapeDividers: shapes,
2219 } );
2220 } }
2221 />
2222
2223 <UnitPicker
2224 label={ __( 'Width', 'generateblocks' ) }
2225 value={ '%' }
2226 units={ [ '%' ] }
2227 onClick={ () => {
2228 return false;
2229 } }
2230 />
2231
2232 <TextControl
2233 type={ 'number' }
2234 value={ shapeDividers[ index ].width ? shapeDividers[ index ].width : '' }
2235 min="100"
2236 onChange={ ( value ) => {
2237 const shapes = [ ...shapeDividers ];
2238
2239 shapes[ index ] = {
2240 ...shapes[ index ],
2241 width: parseFloat( value ),
2242 };
2243
2244 setAttributes( {
2245 shapeDividers: shapes,
2246 } );
2247 } }
2248 />
2249
2250 <ToggleControl
2251 label={ __( 'Flip Horizontally', 'generateblocks' ) }
2252 checked={ !! shapeDividers[ index ].flipHorizontally }
2253 onChange={ ( value ) => {
2254 const shapes = [ ...shapeDividers ];
2255
2256 shapes[ index ] = {
2257 ...shapes[ index ],
2258 flipHorizontally: value,
2259 };
2260
2261 setAttributes( {
2262 shapeDividers: shapes,
2263 } );
2264 } }
2265 />
2266
2267 <TextControl
2268 label={ __( 'z-index', 'generateblocks' ) }
2269 type={ 'number' }
2270 min="0"
2271 value={ shapeDividers[ index ].zindex || 0 === shapeDividers[ index ].zindex ? shapeDividers[ index ].zindex : '' }
2272 onChange={ ( value ) => {
2273 const shapes = [ ...shapeDividers ];
2274
2275 shapes[ index ] = {
2276 ...shapes[ index ],
2277 zindex: value,
2278 };
2279
2280 setAttributes( {
2281 shapeDividers: shapes,
2282 } );
2283 } }
2284 onBlur={ () => {
2285 const shapes = [ ...shapeDividers ];
2286
2287 shapes[ index ] = {
2288 ...shapes[ index ],
2289 zindex: parseFloat( shapeDividers[ index ].zindex ),
2290 };
2291
2292 setAttributes( {
2293 shapeDividers: shapes,
2294 } );
2295 } }
2296 onClick={ ( e ) => {
2297 // Make sure onBlur fires in Firefox.
2298 e.currentTarget.focus();
2299 } }
2300 />
2301 </Fragment>
2302 }
2303
2304 { 'Tablet' === this.getDeviceType() &&
2305 <Fragment>
2306 <UnitPicker
2307 label={ __( 'Height', 'generateblocks' ) }
2308 value={ 'px' }
2309 units={ [ 'px' ] }
2310 onClick={ () => {
2311 return false;
2312 } }
2313 />
2314
2315 <TextControl
2316 type={ 'number' }
2317 value={ shapeDividers[ index ].heightTablet ? shapeDividers[ index ].heightTablet : '' }
2318 onChange={ ( value ) => {
2319 const shapes = [ ...shapeDividers ];
2320
2321 shapes[ index ] = {
2322 ...shapes[ index ],
2323 heightTablet: parseFloat( value ),
2324 };
2325
2326 setAttributes( {
2327 shapeDividers: shapes,
2328 } );
2329 } }
2330 />
2331
2332 <UnitPicker
2333 label={ __( 'Width', 'generateblocks' ) }
2334 value={ '%' }
2335 units={ [ '%' ] }
2336 onClick={ () => {
2337 return false;
2338 } }
2339 />
2340
2341 <TextControl
2342 type={ 'number' }
2343 value={ shapeDividers[ index ].widthTablet ? shapeDividers[ index ].widthTablet : '' }
2344 min="100"
2345 onChange={ ( value ) => {
2346 const shapes = [ ...shapeDividers ];
2347
2348 shapes[ index ] = {
2349 ...shapes[ index ],
2350 widthTablet: parseFloat( value ),
2351 };
2352
2353 setAttributes( {
2354 shapeDividers: shapes,
2355 } );
2356 } }
2357 />
2358 </Fragment>
2359 }
2360
2361 { 'Mobile' === this.getDeviceType() &&
2362 <Fragment>
2363 <UnitPicker
2364 label={ __( 'Height', 'generateblocks' ) }
2365 value={ 'px' }
2366 units={ [ 'px' ] }
2367 onClick={ () => {
2368 return false;
2369 } }
2370 />
2371
2372 <TextControl
2373 type={ 'number' }
2374 value={ shapeDividers[ index ].heightMobile ? shapeDividers[ index ].heightMobile : '' }
2375 onChange={ ( value ) => {
2376 const shapes = [ ...shapeDividers ];
2377
2378 shapes[ index ] = {
2379 ...shapes[ index ],
2380 heightMobile: parseFloat( value ),
2381 };
2382
2383 setAttributes( {
2384 shapeDividers: shapes,
2385 } );
2386 } }
2387 />
2388
2389 <UnitPicker
2390 label={ __( 'Width', 'generateblocks' ) }
2391 value={ '%' }
2392 units={ [ '%' ] }
2393 onClick={ () => {
2394 return false;
2395 } }
2396 />
2397
2398 <TextControl
2399 type={ 'number' }
2400 value={ shapeDividers[ index ].widthMobile ? shapeDividers[ index ].widthMobile : '' }
2401 min="100"
2402 onChange={ ( value ) => {
2403 const shapes = [ ...shapeDividers ];
2404
2405 shapes[ index ] = {
2406 ...shapes[ index ],
2407 widthMobile: parseFloat( value ),
2408 };
2409
2410 setAttributes( {
2411 shapeDividers: shapes,
2412 } );
2413 } }
2414 />
2415 </Fragment>
2416 }
2417 </div>
2418 ) }
2419 />
2420 </Fragment>
2421
2422 { 'Desktop' === this.getDeviceType() &&
2423 <Tooltip text={ __( 'Delete Shape', 'generateblocks' ) }>
2424 <Button
2425 className="gblocks-remove-shape"
2426 onClick={ () => {
2427 // eslint-disable-next-line
2428 if ( window.confirm( __( 'This will permanently delete this shape.', 'generateblocks' ) ) ) {
2429 handleRemoveShape( index );
2430 }
2431 } }
2432 icon={ getIcon( 'x' ) }
2433 />
2434 </Tooltip>
2435 }
2436 </div>
2437 </Fragment>;
2438 } )
2439 }
2440
2441 <div className="gblocks-add-new-shape">
2442 <Button
2443 isSecondary
2444 onClick={ handleAddShape.bind( this ) }
2445 >
2446 { __( 'Add Shape', 'generateblocks' ) }
2447 </Button>
2448 </div>
2449 </BaseControl>
2450
2451 { applyFilters( 'generateblocks.editor.controls', '', 'containerShapeDivider', this.props, this.state ) }
2452 </PanelArea>
2453
2454 <PanelArea { ...this.props }
2455 title={ __( 'Documentation', 'generateblocks' ) }
2456 initialOpen={ false }
2457 icon={ getIcon( 'documentation' ) }
2458 className={ 'gblocks-panel-label' }
2459 id={ 'containerDocumentation' }
2460 state={ this.state }
2461 >
2462 <p>{ __( 'Need help with this block?', 'generateblocks' ) }</p>
2463 <a href="https://docs.generateblocks.com/collection/container/" target="_blank" rel="noreferrer noopener">{ __( 'Visit our documentation', 'generateblocks' ) }</a>
2464
2465 { applyFilters( 'generateblocks.editor.controls', '', 'containerDocumentation', this.props, this.state ) }
2466 </PanelArea>
2467 </InspectorControls>
2468
2469 <InspectorAdvancedControls>
2470 <TextControl
2471 label={ __( 'HTML Anchor', 'generateblocks' ) }
2472 help={ __( 'Anchors lets you link directly to a section on a page.', 'generateblocks' ) }
2473 value={ anchor || '' }
2474 onChange={ ( nextValue ) => {
2475 nextValue = nextValue.replace( ANCHOR_REGEX, '-' );
2476 setAttributes( {
2477 anchor: nextValue,
2478 } );
2479 } } />
2480 </InspectorAdvancedControls>
2481
2482 <MainCSS { ...this.props } />
2483
2484 { this.props.deviceType &&
2485 <Fragment>
2486 { 'Desktop' === this.props.deviceType &&
2487 <DesktopCSS { ...this.props } />
2488 }
2489
2490 { ( 'Tablet' === this.props.deviceType || 'Mobile' === this.props.deviceType ) &&
2491 <TabletCSS { ...this.props } />
2492 }
2493
2494 { 'Tablet' === this.props.deviceType &&
2495 <TabletOnlyCSS { ...this.props } />
2496 }
2497
2498 { 'Mobile' === this.props.deviceType &&
2499 <MobileCSS { ...this.props } />
2500 }
2501 </Fragment>
2502 }
2503
2504 { fontFamily && googleFont &&
2505 <link
2506 rel="stylesheet"
2507 href={ 'https://fonts.googleapis.com/css?family=' + fontFamily.replace( / /g, '+' ) + googleFontsAttr }
2508 />
2509 }
2510
2511 <Element
2512 tagName={ filterTagName( applyFilters( 'generateblocks.frontend.containerTagName', tagName, attributes ) ) }
2513 htmlAttrs={ htmlAttributes }
2514 >
2515 { applyFilters( 'generateblocks.frontend.afterContainerOpen', '', attributes ) }
2516 <div
2517 className={ classnames( {
2518 'gb-inside-container': true,
2519 } ) }
2520 >
2521 { applyFilters( 'generateblocks.frontend.insideContainer', '', attributes ) }
2522 <InnerBlocks
2523 templateLock={ false }
2524 renderAppender={ () => {
2525 // Selected Container.
2526 if ( this.props.isSelected ) {
2527 return <InnerBlocks.ButtonBlockAppender />;
2528 }
2529
2530 // Empty non-selected Container.
2531 if ( ! hasChildBlocks && ! this.props.isSelected ) {
2532 return <Button
2533 className="gblocks-container-selector"
2534 onClick={ () => wp.data.dispatch( 'core/block-editor' ).selectBlock( clientId ) }
2535 aria-label={ __( 'Select Container', 'generateblocks' ) }
2536 >
2537 <span className="gblocks-container-selector__icon">
2538 { getIcon( 'container' ) }
2539 </span>
2540 </Button>;
2541 }
2542
2543 return false;
2544 } }
2545 />
2546 </div>
2547
2548 { allShapeDividers() }
2549
2550 { applyFilters( 'generateblocks.frontend.beforeContainerClose', '', attributes ) }
2551 </Element>
2552 </Fragment>
2553 );
2554 }
2555 }
2556
2557 export default compose( [
2558 withDispatch( ( dispatch ) => ( {
2559 setDeviceType( type ) {
2560 const {
2561 __experimentalSetPreviewDeviceType: setPreviewDeviceType,
2562 } = dispatch( 'core/edit-post' ) || false;
2563
2564 if ( ! setPreviewDeviceType ) {
2565 return;
2566 }
2567
2568 setPreviewDeviceType( type );
2569 },
2570 } ) ),
2571 withSelect( ( select, props ) => {
2572 const { clientId } = props;
2573 const blockEditor = select( 'core/block-editor' );
2574
2575 if ( ! select( 'core/edit-post' ) ) {
2576 return {
2577 media: null,
2578 deviceType: null,
2579 hasChildBlocks: blockEditor ? 0 < blockEditor.getBlockOrder( clientId ).length : false,
2580 };
2581 }
2582
2583 const {
2584 __experimentalGetPreviewDeviceType: getPreviewDeviceType,
2585 } = select( 'core/edit-post' );
2586
2587 const {
2588 getMedia,
2589 } = select( 'core' );
2590
2591 const {
2592 getEditedPostAttribute,
2593 } = select( 'core/editor' );
2594
2595 const featuredImageId = getEditedPostAttribute( 'featured_media' );
2596
2597 if ( ! getPreviewDeviceType ) {
2598 return {
2599 media: featuredImageId ? getMedia( featuredImageId ) : null,
2600 deviceType: null,
2601 hasChildBlocks: blockEditor ? 0 < blockEditor.getBlockOrder( clientId ).length : false,
2602 };
2603 }
2604
2605 return {
2606 media: featuredImageId ? getMedia( featuredImageId ) : null,
2607 deviceType: getPreviewDeviceType(),
2608 hasChildBlocks: blockEditor ? 0 < blockEditor.getBlockOrder( clientId ).length : false,
2609 };
2610 } ),
2611 ] )( GenerateBlockContainer );
2612