PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.3.4
GenerateBlocks v1.3.4
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 5 years ago attributes.js 5 years ago block-controls.js 5 years ago block.js 5 years ago deprecated.js 5 years ago edit.js 5 years ago editor.scss 5 years ago
edit.js
2107 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 MainCSS from './css/main.js';
17 import DesktopCSS from './css/desktop.js';
18 import TabletCSS from './css/tablet.js';
19 import TabletOnlyCSS from './css/tablet-only.js';
20 import MobileCSS from './css/mobile.js';
21
22 import {
23 __,
24 sprintf,
25 } from '@wordpress/i18n';
26
27 import {
28 RangeControl,
29 Button,
30 ButtonGroup,
31 ToggleControl,
32 SelectControl,
33 TextControl,
34 BaseControl,
35 Notice,
36 PanelBody,
37 PanelRow,
38 Tooltip,
39 Dropdown,
40 } from '@wordpress/components';
41
42 import {
43 Fragment,
44 Component,
45 } from '@wordpress/element';
46
47 import {
48 InspectorControls,
49 InnerBlocks,
50 MediaUpload,
51 AlignmentToolbar,
52 InspectorAdvancedControls,
53 BlockControls,
54 } from '@wordpress/block-editor';
55
56 import {
57 applyFilters,
58 } from '@wordpress/hooks';
59
60 import {
61 withSelect,
62 withDispatch,
63 } from '@wordpress/data';
64
65 import {
66 compose,
67 } from '@wordpress/compose';
68
69 /**
70 * Regular expression matching invalid anchor characters for replacement.
71 *
72 * @type {RegExp}
73 */
74 const ANCHOR_REGEX = /[\s#]/g;
75
76 const gbContainerIds = [];
77
78 class GenerateBlockContainer extends Component {
79 constructor() {
80 super( ...arguments );
81
82 this.state = {
83 selectedDevice: 'Desktop',
84 };
85
86 this.getDeviceType = this.getDeviceType.bind( this );
87 this.setDeviceType = this.setDeviceType.bind( this );
88 }
89
90 componentDidMount() {
91 const id = this.props.clientId.substr( 2, 9 ).replace( '-', '' );
92
93 // We don't want to ever regenerate unique IDs if they're a global style.
94 const isGlobalStyle = 'undefined' !== typeof this.props.attributes.isGlobalStyle && this.props.attributes.isGlobalStyle;
95
96 if ( ! this.props.attributes.uniqueId ) {
97 this.props.setAttributes( {
98 uniqueId: id,
99 } );
100
101 gbContainerIds.push( id );
102 } else if ( gbContainerIds.includes( this.props.attributes.uniqueId ) && ! isGlobalStyle ) {
103 this.props.setAttributes( {
104 uniqueId: id,
105 } );
106
107 gbContainerIds.push( id );
108 } else {
109 gbContainerIds.push( this.props.attributes.uniqueId );
110 }
111
112 const thisBlock = document.getElementById( 'block-' + this.props.clientId );
113
114 if ( thisBlock && 'full' === this.props.attributes.align ) {
115 thisBlock.setAttribute( 'data-align', 'full' );
116 }
117
118 // This block used to be static. Set it to dynamic by default from now on.
119 if ( 'undefined' === typeof this.props.attributes.isDynamic || ! this.props.attributes.isDynamic ) {
120 this.props.setAttributes( {
121 isDynamic: true,
122 } );
123 }
124 }
125
126 componentDidUpdate() {
127 const thisBlock = document.getElementById( 'block-' + this.props.clientId );
128
129 if ( thisBlock ) {
130 const alignValue = this.props.attributes.align;
131 let currentDataAlign = '';
132
133 if ( thisBlock.getAttribute( 'data-align' ) ) {
134 currentDataAlign = thisBlock.getAttribute( 'data-align' );
135 }
136
137 if ( alignValue !== currentDataAlign ) {
138 if ( ( '' === alignValue || undefined === alignValue ) && '' !== currentDataAlign ) {
139 thisBlock.removeAttribute( 'data-align' );
140 } else {
141 thisBlock.setAttribute( 'data-align', alignValue );
142 }
143 }
144 }
145 }
146
147 getDeviceType() {
148 let deviceType = this.props.deviceType ? this.props.deviceType : this.state.selectedDevice;
149
150 if ( ! generateBlocksInfo.syncResponsivePreviews ) {
151 deviceType = this.state.selectedDevice;
152 }
153
154 return deviceType;
155 }
156
157 setDeviceType( deviceType ) {
158 if ( generateBlocksInfo.syncResponsivePreviews && this.props.deviceType ) {
159 this.props.setDeviceType( deviceType );
160 this.setState( { selectedDevice: deviceType } );
161 } else {
162 this.setState( { selectedDevice: deviceType } );
163 }
164 }
165
166 render() {
167 const {
168 attributes,
169 setAttributes,
170 hasChildBlocks,
171 clientId,
172 } = this.props;
173
174 const {
175 uniqueId,
176 className,
177 anchor,
178 tagName,
179 isGrid,
180 width,
181 widthTablet,
182 widthMobile,
183 outerContainer,
184 innerContainer,
185 containerWidth,
186 minHeight,
187 minHeightUnit,
188 minHeightTablet,
189 minHeightUnitTablet,
190 minHeightMobile,
191 minHeightUnitMobile,
192 borderColor,
193 borderColorOpacity,
194 backgroundColor,
195 backgroundColorOpacity,
196 textColor,
197 linkColor,
198 linkColorHover,
199 bgImage,
200 bgOptions,
201 bgImageSize,
202 verticalAlignment,
203 verticalAlignmentTablet,
204 verticalAlignmentMobile,
205 zindex,
206 innerZindex,
207 removeVerticalGap,
208 removeVerticalGapTablet,
209 removeVerticalGapMobile,
210 orderTablet,
211 orderMobile,
212 alignment,
213 alignmentTablet,
214 alignmentMobile,
215 fontFamily,
216 googleFont,
217 googleFontVariants,
218 fullWidthContent,
219 align,
220 shapeDividers,
221 } = attributes;
222
223 // Attribute defaults added to an object late don't get defaults.
224 if ( 'undefined' === typeof attributes.bgOptions.selector ) {
225 attributes.bgOptions.selector = 'element';
226 }
227
228 if ( 'undefined' === typeof attributes.bgOptions.opacity ) {
229 attributes.bgOptions.opacity = 1;
230 }
231
232 const tagNames = [
233 { label: 'div', value: 'div' },
234 { label: 'section', value: 'section' },
235 { label: 'header', value: 'header' },
236 { label: 'footer', value: 'footer' },
237 { label: 'aside', value: 'aside' },
238 ];
239
240 const pageBuilderContainerOption = document.getElementById( '_generate-full-width-content' );
241 const changeEvent = new Event( 'change' ); // eslint-disable-line no-undef
242 const getRootId = wp.data.select( 'core/block-editor' ).getBlockHierarchyRootClientId( clientId );
243 const isRootContainer = getRootId === clientId;
244
245 const fullWidthContentOptions = () => {
246 return (
247 <Fragment>
248 { generateBlocksInfo.isGeneratePress && isRootContainer && pageBuilderContainerOption &&
249 <BaseControl
250 id="gblocks-gp-full-width-page"
251 label={ __( 'If you want to build a full width page, use the option below to remove the page width, margin and padding.', 'generateblocks' ) }
252 className="gblocks-gpress-full-width"
253 >
254 <ToggleControl
255 label={ __( 'Make page full-width', 'generateblocks' ) }
256 checked={ fullWidthContent ? true : false }
257 onChange={ ( value ) => {
258 if ( value ) {
259 if ( 'select' === pageBuilderContainerOption.tagName.toLowerCase() ) {
260 pageBuilderContainerOption.value = 'true';
261 pageBuilderContainerOption.dispatchEvent( changeEvent );
262 } else {
263 pageBuilderContainerOption.checked = true;
264 pageBuilderContainerOption.setAttribute( 'value', 'true' );
265 pageBuilderContainerOption.dispatchEvent( changeEvent );
266 }
267
268 setAttributes( {
269 fullWidthContent: 'true',
270 align: '',
271 } );
272 } else {
273 if ( 'select' === pageBuilderContainerOption.tagName.toLowerCase() ) {
274 pageBuilderContainerOption.value = '';
275 pageBuilderContainerOption.dispatchEvent( changeEvent );
276 } else {
277 pageBuilderContainerOption.checked = false;
278 pageBuilderContainerOption.setAttribute( 'value', '' );
279 document.querySelector( 'input[name="_generate-full-width-content"]#default-content' ).checked = true;
280 pageBuilderContainerOption.dispatchEvent( changeEvent );
281 }
282
283 setAttributes( {
284 fullWidthContent: '',
285 } );
286 }
287 } }
288 />
289 </BaseControl>
290 }
291 </Fragment>
292 );
293 };
294
295 let googleFontsAttr = '';
296
297 if ( googleFontVariants ) {
298 googleFontsAttr = ':' + googleFontVariants;
299 }
300
301 let parentBlockId = false,
302 parentBlock = false,
303 hasGridContainer = false,
304 gridContainerId = '';
305
306 if ( typeof wp.data.select( 'core/block-editor' ).getBlockParents === 'function' ) {
307 parentBlockId = wp.data.select( 'core/block-editor' ).getBlockParents( clientId, true )[ 0 ];
308
309 if ( parentBlockId ) {
310 parentBlock = wp.data.select( 'core/block-editor' ).getBlocksByClientId( parentBlockId );
311
312 if ( parentBlock && 'generateblocks/grid' === parentBlock[ 0 ].name ) {
313 hasGridContainer = true;
314 gridContainerId = parentBlock[ 0 ].attributes.uniqueId;
315 }
316 }
317 }
318
319 const handleAddShape = () => {
320 const shapeDividersValues = [ ...shapeDividers ];
321
322 shapeDividersValues.push( {
323 shape: generateBlocksStyling.container.shapeDividers.shape,
324 color: generateBlocksStyling.container.shapeDividers.color,
325 colorOpacity: generateBlocksStyling.container.shapeDividers.colorOpacity,
326 location: generateBlocksStyling.container.shapeDividers.location,
327 height: generateBlocksStyling.container.shapeDividers.height,
328 heightTablet: generateBlocksStyling.container.shapeDividers.heightTablet,
329 heightMobile: generateBlocksStyling.container.shapeDividers.heightMobile,
330 width: generateBlocksStyling.container.shapeDividers.width,
331 widthTablet: generateBlocksStyling.container.shapeDividers.widthTablet,
332 widthMobile: generateBlocksStyling.container.shapeDividers.widthMobile,
333 flipHorizontally: generateBlocksStyling.container.shapeDividers.flipHorizontally,
334 zindex: generateBlocksStyling.container.shapeDividers.zindex,
335 } );
336
337 setAttributes( { shapeDividers: shapeDividersValues } );
338 };
339
340 const handleRemoveShape = ( index ) => {
341 const shapeDividersValues = [ ...shapeDividers ];
342
343 shapeDividersValues.splice( index, 1 );
344 setAttributes( { shapeDividers: shapeDividersValues } );
345 };
346
347 const allShapes = [];
348
349 Object.keys( generateBlocksInfo.svgShapes ).forEach( ( key ) => {
350 const shapes = generateBlocksInfo.svgShapes[ key ].svgs;
351
352 Object.keys( shapes ).forEach( ( name ) => {
353 allShapes[ name ] = {
354 label: shapes[ name ].label,
355 icon: shapes[ name ].icon,
356 };
357 } );
358 } );
359
360 const allShapeDividers = () => {
361 return (
362 <Fragment>
363 { !! attributes.shapeDividers.length &&
364 <div className="gb-shapes">
365 {
366 attributes.shapeDividers.map( ( location, index ) => {
367 const shapeNumber = index + 1;
368
369 return <Fragment key={ index }>
370 { 'undefined' !== typeof allShapes[ shapeDividers[ index ].shape ] &&
371 <div
372 className={ classnames( {
373 'gb-shape': true,
374 [ `gb-shape-${ shapeNumber }` ]: true,
375 } ) }
376 dangerouslySetInnerHTML={ { __html: sanitizeSVG( allShapes[ shapeDividers[ index ].shape ].icon ) } }
377 />
378 }
379 </Fragment>;
380 } )
381 }
382 </div>
383 }
384 </Fragment>
385 );
386 };
387
388 const bgImageSizes = [];
389
390 Object.keys( generateBlocksInfo.imageSizes ).forEach( ( size ) => {
391 bgImageSizes.push( {
392 label: generateBlocksInfo.imageSizes[ size ],
393 value: generateBlocksInfo.imageSizes[ size ],
394 } );
395 } );
396
397 let htmlAttributes = {
398 className: classnames( {
399 'gb-container': true,
400 [ `gb-container-${ uniqueId }` ]: true,
401 [ `${ className }` ]: undefined !== className,
402 } ),
403 id: anchor ? anchor : null,
404 };
405
406 htmlAttributes = applyFilters( 'generateblocks.frontend.htmlAttributes', htmlAttributes, 'generateblocks/container', attributes );
407
408 return (
409 <Fragment>
410 <BlockControls>
411 { 'Desktop' === this.getDeviceType() && (
412 <AlignmentToolbar
413 value={ alignment }
414 onChange={ ( value ) => {
415 setAttributes( { alignment: value } );
416 } }
417 />
418 ) }
419
420 { 'Tablet' === this.getDeviceType() && (
421 <AlignmentToolbar
422 value={ alignmentTablet }
423 onChange={ ( value ) => {
424 setAttributes( { alignmentTablet: value } );
425 } }
426 />
427 ) }
428
429 { 'Mobile' === this.getDeviceType() && (
430 <AlignmentToolbar
431 value={ alignmentMobile }
432 onChange={ ( value ) => {
433 setAttributes( { alignmentMobile: value } );
434 } }
435 />
436 ) }
437 </BlockControls>
438
439 <InspectorControls>
440 <ResponsiveTabs { ...this.props }
441 selectedDevice={ this.getDeviceType() }
442 onClick={ ( device ) => {
443 this.setDeviceType( device );
444 } }
445 />
446
447 { ! isGrid && (
448 <PanelArea { ...this.props }
449 title={ __( 'Layout', 'generateblocks' ) }
450 initialOpen={ true }
451 icon={ getIcon( 'layout' ) }
452 className={ 'gblocks-panel-label' }
453 id={ 'containerLayout' }
454 state={ this.state }
455 >
456 { 'Desktop' === this.getDeviceType() &&
457 <Fragment>
458 { hasGridContainer &&
459 <ToggleControl
460 label={ __( 'Grid Item', 'generateblocks' ) }
461 help={ __( 'This Container is inside a Grid Block but is not set as a grid item. Enable this option for optimal results.', 'generateblocks' ) }
462 checked={ !! isGrid }
463 onChange={ ( value ) => {
464 setAttributes( {
465 isGrid: value,
466 gridId: gridContainerId,
467 } );
468 } }
469 />
470 }
471
472 <SelectControl
473 label={ __( 'Container', 'generateblocks' ) }
474 value={ outerContainer }
475 options={ [
476 { label: __( 'Full width', 'generateblocks' ), value: 'full' },
477 { label: __( 'Contained width', 'generateblocks' ), value: 'contained' },
478 ] }
479 onChange={ ( value ) => {
480 setAttributes( {
481 outerContainer: value,
482 } );
483
484 if ( 'contained' === value && 'full' === align ) {
485 setAttributes( {
486 align: '',
487 } );
488 }
489 } }
490 />
491
492 { 'full' === outerContainer &&
493 <SelectControl
494 label={ __( 'Inner Container', 'generateblocks' ) }
495 value={ innerContainer }
496 options={ [
497 { label: __( 'Full width', 'generateblocks' ), value: 'full' },
498 { label: __( 'Contained width', 'generateblocks' ), value: 'contained' },
499 ] }
500 onChange={ ( value ) => {
501 setAttributes( {
502 innerContainer: value,
503 } );
504 } }
505 />
506 }
507
508 { ( 'contained' === outerContainer || 'contained' === innerContainer ) &&
509 <Fragment>
510 <UnitPicker
511 label={ __( 'Container Width', 'generateblocks' ) }
512 value={ 'px' }
513 units={ [ 'px' ] }
514 onClick={ () => {
515 return false;
516 } }
517 />
518
519 <TextControl
520 type={ 'number' }
521 className="gblocks-container-width"
522 value={ parseFloat( containerWidth ) || '' }
523 placeholder={ generateBlocksDefaults.container.containerWidth }
524 onChange={ ( value ) => {
525 setAttributes( {
526 containerWidth: '' !== value ? parseFloat( value ) : undefined,
527 } );
528 } }
529 />
530 </Fragment>
531 }
532
533 <SelectControl
534 label={ __( 'Tag Name', 'generateblocks' ) }
535 value={ tagName }
536 options={ applyFilters( 'generateblocks.editor.containerTagNames', tagNames, this.props, this.state ) }
537 onChange={ ( value ) => {
538 setAttributes( {
539 tagName: value,
540 } );
541 } }
542 />
543
544 { applyFilters( 'generateblocks.editor.controls', '', 'containerAfterElementTag', this.props, this.state ) }
545
546 { fullWidthContentOptions() }
547 </Fragment>
548 }
549
550 { applyFilters( 'generateblocks.editor.controls', '', 'containerLayout', this.props, this.state ) }
551 </PanelArea>
552 ) }
553
554 { isGrid && (
555 <PanelArea { ...this.props }
556 title={ __( 'Layout', 'generateblocks' ) }
557 initialOpen={ true }
558 icon={ getIcon( 'layout' ) }
559 className={ 'gblocks-panel-label' }
560 id={ 'containerGridLayout' }
561 state={ this.state }
562 >
563 { ! hasGridContainer &&
564 <ToggleControl
565 label={ __( 'Grid Item', 'generateblocks' ) }
566 help={ __( 'This container is set as a grid item but is not inside a grid block. Deactivate this option for optimal results.', 'generateblocks' ) }
567 checked={ !! isGrid }
568 onChange={ ( value ) => {
569 setAttributes( {
570 isGrid: value,
571 gridId: '',
572 } );
573 } }
574 />
575 }
576
577 { 'Desktop' === this.getDeviceType() && (
578 <Fragment>
579 <UnitPicker
580 label={ __( 'Container Width', 'generateblocks' ) }
581 value={ '%' }
582 units={ [ '%' ] }
583 onClick={ () => {
584 return false;
585 } }
586 />
587
588 <ButtonGroup className={ 'widthButtons' }>
589 <Button isPrimary={ width === 25 } onClick={ () => setAttributes( { width: 25 } ) }>25</Button>
590 <Button isPrimary={ width === 33.33 } onClick={ () => setAttributes( { width: 33.33 } ) }>33</Button>
591 <Button isPrimary={ width === 50 } onClick={ () => setAttributes( { width: 50 } ) }>50</Button>
592 <Button isPrimary={ width === 66.66 } onClick={ () => setAttributes( { width: 66.66 } ) }>66</Button>
593 <Button isPrimary={ width === 75 } onClick={ () => setAttributes( { width: 75 } ) }>75</Button>
594 <Button isPrimary={ width === 100 } onClick={ () => setAttributes( { width: 100 } ) }>100</Button>
595 </ButtonGroup>
596
597 <RangeControl
598 className={ 'gblocks-column-width-control' }
599 value={ width || '' }
600 onChange={ ( value ) => {
601 setAttributes( {
602 width: value,
603 } );
604 } }
605 min={ 0 }
606 max={ 100 }
607 step={ 0.01 }
608 initialPosition={ generateBlocksDefaults.container.width }
609 />
610
611 <SelectControl
612 label={ __( 'Vertical Alignment', 'generateblocks' ) }
613 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
614 value={ verticalAlignment }
615 options={ [
616 { label: __( 'Default', 'generateblocks' ), value: '' },
617 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
618 { label: __( 'Center', 'generateblocks' ), value: 'center' },
619 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
620 ] }
621 onChange={ ( value ) => {
622 setAttributes( {
623 verticalAlignment: value,
624 } );
625 } }
626 />
627
628 <ToggleControl
629 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
630 checked={ !! removeVerticalGap }
631 onChange={ ( value ) => {
632 setAttributes( {
633 removeVerticalGap: value,
634 } );
635 } }
636 />
637
638 <SelectControl
639 label={ __( 'Tag Name', 'generateblocks' ) }
640 value={ tagName }
641 options={ applyFilters( 'generateblocks.editor.containerTagNames', tagNames, this.props, this.state ) }
642 onChange={ ( value ) => {
643 setAttributes( {
644 tagName: value,
645 } );
646 } }
647 />
648
649 { applyFilters( 'generateblocks.editor.controls', '', 'containerAfterElementTag', this.props, this.state ) }
650 </Fragment>
651 ) }
652
653 { 'Tablet' === this.getDeviceType() && (
654 <Fragment>
655 <UnitPicker
656 label={ __( 'Container Width', 'generateblocks' ) }
657 value={ '%' }
658 units={ [ '%' ] }
659 onClick={ () => {
660 return false;
661 } }
662 />
663
664 <ButtonGroup className={ 'widthButtons' }>
665 <Button isPrimary={ widthTablet === 25 } onClick={ () => setAttributes( { widthTablet: 25 } ) }>25</Button>
666 <Button isPrimary={ widthTablet === 33.33 } onClick={ () => setAttributes( { widthTablet: 33.33 } ) }>33</Button>
667 <Button isPrimary={ widthTablet === 50 } onClick={ () => setAttributes( { widthTablet: 50 } ) }>50</Button>
668 <Button isPrimary={ widthTablet === 66.66 } onClick={ () => setAttributes( { widthTablet: 66.66 } ) }>66</Button>
669 <Button isPrimary={ widthTablet === 75 } onClick={ () => setAttributes( { widthTablet: 75 } ) }>75</Button>
670 <Button isPrimary={ widthTablet === 100 } onClick={ () => setAttributes( { widthTablet: 100 } ) }>100</Button>
671 </ButtonGroup>
672
673 <RangeControl
674 className={ 'gblocks-column-width-control' }
675 value={ widthTablet || '' }
676 onChange={ ( value ) => {
677 setAttributes( {
678 widthTablet: value,
679 } );
680 } }
681 min={ 0 }
682 max={ 100 }
683 step={ 0.01 }
684 initialPosition={ generateBlocksDefaults.container.widthTablet }
685 />
686
687 <SelectControl
688 label={ __( 'Vertical Alignment', 'generateblocks' ) }
689 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
690 value={ verticalAlignmentTablet }
691 options={ [
692 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
693 { label: __( 'Default', 'generateblocks' ), value: '' },
694 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
695 { label: __( 'Center', 'generateblocks' ), value: 'center' },
696 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
697 ] }
698 onChange={ ( value ) => {
699 setAttributes( {
700 verticalAlignmentTablet: value,
701 } );
702 } }
703 />
704
705 <ToggleControl
706 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
707 checked={ !! removeVerticalGapTablet }
708 onChange={ ( value ) => {
709 setAttributes( {
710 removeVerticalGapTablet: value,
711 } );
712 } }
713 />
714
715 <TextControl
716 type={ 'number' }
717 label={ __( 'Order', 'generateblocks' ) }
718 value={ orderTablet || 0 === orderTablet ? orderTablet : '' }
719 onChange={ ( value ) => {
720 setAttributes( {
721 orderTablet: parseFloat( value ),
722 } );
723 } }
724 />
725 </Fragment>
726 ) }
727
728 { 'Mobile' === this.getDeviceType() && (
729 <Fragment>
730 <UnitPicker
731 label={ __( 'Container Width', 'generateblocks' ) }
732 value={ '%' }
733 units={ [ '%' ] }
734 onClick={ () => {
735 return false;
736 } }
737 />
738
739 <ButtonGroup className={ 'widthButtons' }>
740 <Button isPrimary={ widthMobile === 25 } onClick={ () => setAttributes( { widthMobile: 25 } ) }>25</Button>
741 <Button isPrimary={ widthMobile === 33.33 } onClick={ () => setAttributes( { widthMobile: 33.33 } ) }>33</Button>
742 <Button isPrimary={ widthMobile === 50 } onClick={ () => setAttributes( { widthMobile: 50 } ) }>50</Button>
743 <Button isPrimary={ widthMobile === 66.66 } onClick={ () => setAttributes( { widthMobile: 66.66 } ) }>66</Button>
744 <Button isPrimary={ widthMobile === 75 } onClick={ () => setAttributes( { widthMobile: 75 } ) }>75</Button>
745 <Button isPrimary={ widthMobile === 100 } onClick={ () => setAttributes( { widthMobile: 100 } ) }>100</Button>
746 </ButtonGroup>
747
748 <RangeControl
749 className={ 'gblocks-column-width-control' }
750 value={ widthMobile || '' }
751 onChange={ ( value ) => {
752 setAttributes( {
753 widthMobile: value,
754 } );
755 } }
756 min={ 0 }
757 max={ 100 }
758 step={ 0.01 }
759 initialPosition={ generateBlocksDefaults.container.widthMobile }
760 />
761
762 <SelectControl
763 label={ __( 'Vertical Alignment', 'generateblocks' ) }
764 help={ __( 'Align grid item content. Does not apply if vertical alignment is set in the grid.', 'generateblocks' ) }
765 value={ verticalAlignmentMobile }
766 options={ [
767 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
768 { label: __( 'Default', 'generateblocks' ), value: '' },
769 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
770 { label: __( 'Center', 'generateblocks' ), value: 'center' },
771 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
772 ] }
773 onChange={ ( value ) => {
774 setAttributes( {
775 verticalAlignmentMobile: value,
776 } );
777 } }
778 />
779
780 <ToggleControl
781 label={ __( 'Remove Vertical Gap', 'generateblocks' ) }
782 checked={ !! removeVerticalGapMobile }
783 onChange={ ( value ) => {
784 setAttributes( {
785 removeVerticalGapMobile: value,
786 } );
787 } }
788 />
789
790 <TextControl
791 type={ 'number' }
792 label={ __( 'Order', 'generateblocks' ) }
793 value={ orderMobile || 0 === orderMobile ? orderMobile : '' }
794 onChange={ ( value ) => {
795 setAttributes( {
796 orderMobile: parseFloat( value ),
797 } );
798 } }
799 />
800 </Fragment>
801 ) }
802
803 { applyFilters( 'generateblocks.editor.controls', '', 'containerGridLayout', this.props, this.state ) }
804 </PanelArea>
805 ) }
806
807 <PanelArea { ...this.props }
808 title={ __( 'Typography', 'generateblocks' ) }
809 initialOpen={ false }
810 icon={ getIcon( 'typography' ) }
811 className={ 'gblocks-panel-label' }
812 id={ 'containerTypography' }
813 state={ this.state }
814 >
815
816 { 'Desktop' === this.getDeviceType() && (
817 <Fragment>
818 <TypographyControls { ...this.props }
819 showFontFamily={ true }
820 showFontWeight={ true }
821 showTextTransform={ true }
822 showFontSize={ true }
823 defaultFontSize={ generateBlocksDefaults.container.fontSize }
824 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
825 defaultLineHeight={ generateBlocksDefaults.container.lineHeight }
826 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
827 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacing }
828 />
829 </Fragment>
830 ) }
831
832 { 'Tablet' === this.getDeviceType() && (
833 <Fragment>
834 <TypographyControls { ...this.props }
835 device={ 'Tablet' }
836 showFontSize={ true }
837 defaultFontSize={ generateBlocksDefaults.container.fontSizeTablet }
838 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
839 defaultLineHeight={ generateBlocksDefaults.container.lineHeightTablet }
840 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
841 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacingTablet }
842 />
843 </Fragment>
844 ) }
845
846 { 'Mobile' === this.getDeviceType() && (
847 <Fragment>
848 <TypographyControls { ...this.props }
849 device={ 'Mobile' }
850 showFontSize={ true }
851 defaultFontSize={ generateBlocksDefaults.container.fontSizeMobile }
852 defaultFontSizeUnit={ generateBlocksDefaults.container.fontSizeUnit }
853 defaultLineHeight={ generateBlocksDefaults.container.lineHeightMobile }
854 defaultLineHeightUnit={ generateBlocksDefaults.container.lineHeightUnit }
855 defaultLetterSpacing={ generateBlocksDefaults.container.letterSpacingMobile }
856 />
857 </Fragment>
858 ) }
859
860 { applyFilters( 'generateblocks.editor.controls', '', 'containerTypography', this.props, this.state ) }
861 </PanelArea>
862
863 <PanelArea { ...this.props }
864 title={ __( 'Spacing', 'generateblocks' ) }
865 initialOpen={ false }
866 icon={ getIcon( 'spacing' ) }
867 className={ 'gblocks-panel-label' }
868 id={ 'containerSpacing' }
869 state={ this.state }
870 >
871
872 { 'Desktop' === this.getDeviceType() && (
873 <Fragment>
874 <UnitPicker
875 label={ __( 'Minimum Height', 'generateblocks' ) }
876 value={ minHeightUnit }
877 units={ [ 'px', 'vh', 'vw' ] }
878 onClick={ ( value ) => {
879 setAttributes( {
880 minHeightUnit: value,
881 } );
882 } }
883 />
884
885 <TextControl
886 type={ 'number' }
887 value={ minHeight ? minHeight : '' }
888 onChange={ ( value ) => {
889 setAttributes( {
890 minHeight: parseFloat( value ),
891 } );
892 } }
893 />
894
895 { !! minHeight && ! isGrid &&
896 <SelectControl
897 label={ __( 'Vertical Alignment', 'generateblocks' ) }
898 value={ verticalAlignment }
899 options={ [
900 { label: __( 'Default', 'generateblocks' ), value: '' },
901 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
902 { label: __( 'Center', 'generateblocks' ), value: 'center' },
903 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
904 ] }
905 onChange={ ( value ) => {
906 setAttributes( {
907 verticalAlignment: value,
908 } );
909 } }
910 />
911 }
912
913 <DimensionsControl { ...this.props }
914 device={ this.getDeviceType() }
915 type={ 'padding' }
916 label={ __( 'Padding', 'generateblocks' ) }
917 attrTop={ 'paddingTop' }
918 attrRight={ 'paddingRight' }
919 attrBottom={ 'paddingBottom' }
920 attrLeft={ 'paddingLeft' }
921 attrUnit={ 'paddingUnit' }
922 attrSyncUnits={ 'paddingSyncUnits' }
923 defaults={ generateBlocksDefaults.container }
924 units={ [ 'px', 'em', '%' ] }
925 />
926
927 <DimensionsControl { ...this.props }
928 device={ this.getDeviceType() }
929 type={ 'margin' }
930 label={ __( 'Margin', 'generateblocks' ) }
931 attrTop={ 'marginTop' }
932 attrRight={ 'marginRight' }
933 attrBottom={ 'marginBottom' }
934 attrLeft={ 'marginLeft' }
935 attrUnit={ 'marginUnit' }
936 attrSyncUnits={ 'marginSyncUnits' }
937 defaults={ generateBlocksDefaults.container }
938 units={ [ 'px', 'em', '%' ] }
939 />
940
941 <DimensionsControl { ...this.props }
942 device={ this.getDeviceType() }
943 type={ 'padding' }
944 label={ __( 'Border Size', 'generateblocks' ) }
945 attrTop={ 'borderSizeTop' }
946 attrRight={ 'borderSizeRight' }
947 attrBottom={ 'borderSizeBottom' }
948 attrLeft={ 'borderSizeLeft' }
949 attrSyncUnits={ 'borderSizeSyncUnits' }
950 defaults={ generateBlocksDefaults.container }
951 units={ [ 'px' ] }
952 />
953
954 <DimensionsControl { ...this.props }
955 device={ this.getDeviceType() }
956 type={ 'padding' }
957 label={ __( 'Border Radius', 'generateblocks' ) }
958 attrTop={ 'borderRadiusTopLeft' }
959 attrRight={ 'borderRadiusTopRight' }
960 attrBottom={ 'borderRadiusBottomRight' }
961 attrLeft={ 'borderRadiusBottomLeft' }
962 attrUnit={ 'borderRadiusUnit' }
963 attrSyncUnits={ 'borderRadiusSyncUnits' }
964 labelTop={ __( 'T-Left', 'generateblocks' ) }
965 labelRight={ __( 'T-Right', 'generateblocks' ) }
966 labelBottom={ __( 'B-Right', 'generateblocks' ) }
967 labelLeft={ __( 'B-Left', 'generateblocks' ) }
968 defaults={ generateBlocksDefaults.container }
969 units={ [ 'px', 'em', '%' ] }
970 />
971
972 <TextControl
973 label={ __( 'Outer z-index', 'generateblocks' ) }
974 type={ 'number' }
975 value={ zindex || 0 === zindex ? zindex : '' }
976 onChange={ ( value ) => {
977 setAttributes( {
978 zindex: value,
979 } );
980 } }
981 onBlur={ () => {
982 setAttributes( {
983 zindex: parseFloat( zindex ),
984 } );
985 } }
986 onClick={ ( e ) => {
987 // Make sure onBlur fires in Firefox.
988 e.currentTarget.focus();
989 } }
990 />
991
992 <TextControl
993 label={ __( 'Inner z-index', 'generateblocks' ) }
994 type={ 'number' }
995 value={ innerZindex || 0 === innerZindex ? innerZindex : '' }
996 onChange={ ( value ) => {
997 setAttributes( {
998 innerZindex: value,
999 } );
1000 } }
1001 onBlur={ () => {
1002 setAttributes( {
1003 innerZindex: parseFloat( innerZindex ),
1004 } );
1005 } }
1006 onClick={ ( e ) => {
1007 // Make sure onBlur fires in Firefox.
1008 e.currentTarget.focus();
1009 } }
1010 />
1011 </Fragment>
1012 ) }
1013
1014 { 'Tablet' === this.getDeviceType() && (
1015 <Fragment>
1016 <UnitPicker
1017 label={ __( 'Minimum Height', 'generateblocks' ) }
1018 value={ minHeightUnitTablet }
1019 units={ [ 'px', 'vh', 'vw' ] }
1020 onClick={ ( value ) => {
1021 setAttributes( {
1022 minHeightUnitTablet: value,
1023 } );
1024 } }
1025 />
1026
1027 <TextControl
1028 type={ 'number' }
1029 value={ minHeightTablet ? minHeightTablet : '' }
1030 onChange={ ( value ) => {
1031 setAttributes( {
1032 minHeightTablet: parseFloat( value ),
1033 } );
1034 } }
1035 />
1036
1037 { ( !! minHeight || !! minHeightTablet ) && ! isGrid &&
1038 <SelectControl
1039 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1040 value={ verticalAlignmentTablet }
1041 options={ [
1042 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1043 { label: __( 'Default', 'generateblocks' ), value: '' },
1044 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1045 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1046 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1047 ] }
1048 onChange={ ( value ) => {
1049 setAttributes( {
1050 verticalAlignmentTablet: value,
1051 } );
1052 } }
1053 />
1054 }
1055
1056 <DimensionsControl { ...this.props }
1057 device={ this.getDeviceType() }
1058 type={ 'padding' }
1059 label={ __( 'Padding', 'generateblocks' ) }
1060 attrTop={ 'paddingTopTablet' }
1061 attrRight={ 'paddingRightTablet' }
1062 attrBottom={ 'paddingBottomTablet' }
1063 attrLeft={ 'paddingLeftTablet' }
1064 attrUnit={ 'paddingUnit' }
1065 attrSyncUnits={ 'paddingSyncUnits' }
1066 defaults={ generateBlocksDefaults.container }
1067 units={ [ 'px', 'em', '%' ] }
1068 />
1069
1070 <DimensionsControl { ...this.props }
1071 device={ this.getDeviceType() }
1072 type={ 'margin' }
1073 label={ __( 'Margin', 'generateblocks' ) }
1074 attrTop={ 'marginTopTablet' }
1075 attrRight={ 'marginRightTablet' }
1076 attrBottom={ 'marginBottomTablet' }
1077 attrLeft={ 'marginLeftTablet' }
1078 attrUnit={ 'marginUnit' }
1079 attrSyncUnits={ 'marginSyncUnits' }
1080 defaults={ generateBlocksDefaults.container }
1081 units={ [ 'px', 'em', '%' ] }
1082 />
1083
1084 <DimensionsControl { ...this.props }
1085 device={ this.getDeviceType() }
1086 type={ 'padding' }
1087 label={ __( 'Border Size', 'generateblocks' ) }
1088 attrTop={ 'borderSizeTopTablet' }
1089 attrRight={ 'borderSizeRightTablet' }
1090 attrBottom={ 'borderSizeBottomTablet' }
1091 attrLeft={ 'borderSizeLeftTablet' }
1092 attrSyncUnits={ 'borderSizeSyncUnits' }
1093 defaults={ generateBlocksDefaults.container }
1094 units={ [ 'px' ] }
1095 />
1096
1097 <DimensionsControl { ...this.props }
1098 device={ this.getDeviceType() }
1099 type={ 'padding' }
1100 label={ __( 'Border Radius', 'generateblocks' ) }
1101 attrTop={ 'borderRadiusTopLeftTablet' }
1102 attrRight={ 'borderRadiusTopRightTablet' }
1103 attrBottom={ 'borderRadiusBottomRightTablet' }
1104 attrLeft={ 'borderRadiusBottomLeftTablet' }
1105 attrUnit={ 'borderRadiusUnit' }
1106 attrSyncUnits={ 'borderRadiusSyncUnits' }
1107 labelTop={ __( 'T-Left', 'generateblocks' ) }
1108 labelRight={ __( 'T-Right', 'generateblocks' ) }
1109 labelBottom={ __( 'B-Right', 'generateblocks' ) }
1110 labelLeft={ __( 'B-Left', 'generateblocks' ) }
1111 defaults={ generateBlocksDefaults.container }
1112 units={ [ 'px', 'em', '%' ] }
1113 />
1114 </Fragment>
1115 ) }
1116
1117 { 'Mobile' === this.getDeviceType() && (
1118 <Fragment>
1119 <UnitPicker
1120 label={ __( 'Minimum Height', 'generateblocks' ) }
1121 value={ minHeightUnitMobile }
1122 units={ [ 'px', 'vh', 'vw' ] }
1123 onClick={ ( value ) => {
1124 setAttributes( {
1125 minHeightUnitMobile: value,
1126 } );
1127 } }
1128 />
1129
1130 <TextControl
1131 type={ 'number' }
1132 value={ minHeightMobile ? minHeightMobile : '' }
1133 onChange={ ( value ) => {
1134 setAttributes( {
1135 minHeightMobile: parseFloat( value ),
1136 } );
1137 } }
1138 />
1139
1140 { ( !! minHeight || !! minHeightTablet || !! minHeightMobile ) && ! isGrid &&
1141 <SelectControl
1142 label={ __( 'Vertical Alignment', 'generateblocks' ) }
1143 value={ verticalAlignmentMobile }
1144 options={ [
1145 { label: __( 'Inherit', 'generateblocks' ), value: 'inherit' },
1146 { label: __( 'Default', 'generateblocks' ), value: '' },
1147 { label: __( 'Top', 'generateblocks' ), value: 'flex-start' },
1148 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1149 { label: __( 'Bottom', 'generateblocks' ), value: 'flex-end' },
1150 ] }
1151 onChange={ ( value ) => {
1152 setAttributes( {
1153 verticalAlignmentMobile: value,
1154 } );
1155 } }
1156 />
1157 }
1158
1159 <DimensionsControl { ...this.props }
1160 device={ this.getDeviceType() }
1161 type={ 'padding' }
1162 label={ __( 'Padding', 'generateblocks' ) }
1163 attrTop={ 'paddingTopMobile' }
1164 attrRight={ 'paddingRightMobile' }
1165 attrBottom={ 'paddingBottomMobile' }
1166 attrLeft={ 'paddingLeftMobile' }
1167 attrUnit={ 'paddingUnit' }
1168 attrSyncUnits={ 'paddingSyncUnits' }
1169 defaults={ generateBlocksDefaults.container }
1170 units={ [ 'px', 'em', '%' ] }
1171 />
1172
1173 <DimensionsControl { ...this.props }
1174 device={ this.getDeviceType() }
1175 type={ 'margin' }
1176 label={ __( 'Margin', 'generateblocks' ) }
1177 attrTop={ 'marginTopMobile' }
1178 attrRight={ 'marginRightMobile' }
1179 attrBottom={ 'marginBottomMobile' }
1180 attrLeft={ 'marginLeftMobile' }
1181 attrUnit={ 'marginUnit' }
1182 attrSyncUnits={ 'marginSyncUnits' }
1183 defaults={ generateBlocksDefaults.container }
1184 units={ [ 'px', 'em', '%' ] }
1185 />
1186
1187 <DimensionsControl { ...this.props }
1188 device={ this.getDeviceType() }
1189 type={ 'padding' }
1190 label={ __( 'Border Size', 'generateblocks' ) }
1191 attrTop={ 'borderSizeTopMobile' }
1192 attrRight={ 'borderSizeRightMobile' }
1193 attrBottom={ 'borderSizeBottomMobile' }
1194 attrLeft={ 'borderSizeLeftMobile' }
1195 attrSyncUnits={ 'borderSizeSyncUnits' }
1196 defaults={ generateBlocksDefaults.container }
1197 units={ [ 'px' ] }
1198 />
1199
1200 <DimensionsControl { ...this.props }
1201 device={ this.getDeviceType() }
1202 type={ 'padding' }
1203 label={ __( 'Border Radius', 'generateblocks' ) }
1204 attrTop={ 'borderRadiusTopLeftMobile' }
1205 attrRight={ 'borderRadiusTopRightMobile' }
1206 attrBottom={ 'borderRadiusBottomRightMobile' }
1207 attrLeft={ 'borderRadiusBottomLeftMobile' }
1208 attrUnit={ 'borderRadiusUnit' }
1209 attrSyncUnits={ 'borderRadiusSyncUnits' }
1210 labelTop={ __( 'T-Left', 'generateblocks' ) }
1211 labelRight={ __( 'T-Right', 'generateblocks' ) }
1212 labelBottom={ __( 'B-Right', 'generateblocks' ) }
1213 labelLeft={ __( 'B-Left', 'generateblocks' ) }
1214 defaults={ generateBlocksDefaults.container }
1215 units={ [ 'px', 'em', '%' ] }
1216 />
1217 </Fragment>
1218 ) }
1219
1220 { applyFilters( 'generateblocks.editor.controls', '', 'containerSpacing', this.props, this.state ) }
1221 </PanelArea>
1222
1223 <PanelArea { ...this.props }
1224 title={ __( 'Colors', 'generateblocks' ) }
1225 initialOpen={ false }
1226 icon={ getIcon( 'colors' ) }
1227 className={ 'gblocks-panel-label' }
1228 id={ 'containerColors' }
1229 state={ this.state }
1230 >
1231 { 'Desktop' === this.getDeviceType() &&
1232 <Fragment>
1233 <ColorPicker
1234 label={ __( 'Background Color', 'generateblocks' ) }
1235 value={ backgroundColor }
1236 alpha={ true }
1237 valueOpacity={ backgroundColorOpacity }
1238 attrOpacity={ 'backgroundColorOpacity' }
1239 onChange={ ( nextBackgroundColor ) =>
1240 setAttributes( {
1241 backgroundColor: nextBackgroundColor,
1242 } )
1243 }
1244 onOpacityChange={ ( value ) =>
1245 setAttributes( {
1246 backgroundColorOpacity: value,
1247 } )
1248 }
1249 />
1250
1251 <ColorPicker
1252 label={ __( 'Text Color', 'generateblocks' ) }
1253 value={ textColor }
1254 alpha={ false }
1255 onChange={ ( nextTextColor ) =>
1256 setAttributes( {
1257 textColor: nextTextColor,
1258 } )
1259 }
1260 />
1261
1262 <ColorPicker
1263 label={ __( 'Link Color', 'generateblocks' ) }
1264 value={ linkColor }
1265 alpha={ false }
1266 onChange={ ( nextLinkColor ) =>
1267 setAttributes( {
1268 linkColor: nextLinkColor,
1269 } )
1270 }
1271 />
1272
1273 <ColorPicker
1274 label={ __( 'Link Color Hover', 'generateblocks' ) }
1275 value={ linkColorHover }
1276 alpha={ false }
1277 onChange={ ( nextLinkColorHover ) =>
1278 setAttributes( {
1279 linkColorHover: nextLinkColorHover,
1280 } )
1281 }
1282 />
1283
1284 <ColorPicker
1285 label={ __( 'Border Color', 'generateblocks' ) }
1286 value={ borderColor }
1287 alpha={ true }
1288 valueOpacity={ borderColorOpacity }
1289 attrOpacity={ 'borderColorOpacity' }
1290 onChange={ ( value ) =>
1291 setAttributes( {
1292 borderColor: value,
1293 } )
1294 }
1295 onOpacityChange={ ( value ) =>
1296 setAttributes( {
1297 borderColorOpacity: value,
1298 } )
1299 }
1300 />
1301 </Fragment>
1302 }
1303
1304 { applyFilters( 'generateblocks.editor.controls', '', 'containerColors', this.props, this.state ) }
1305 </PanelArea>
1306
1307 <PanelArea { ...this.props }
1308 title={ __( 'Backgrounds', 'generateblocks' ) }
1309 initialOpen={ false }
1310 icon={ getIcon( 'gradients' ) }
1311 className={ 'gblocks-panel-label' }
1312 id={ 'containerBackground' }
1313 state={ this.state }
1314 >
1315 <Fragment>
1316 <BaseControl
1317 id="gblocks-background-image-upload"
1318 label={ __( 'Image URL', 'generateblocks' ) }
1319 >
1320 <div className="gblocks-bg-image-wrapper">
1321 <TextControl
1322 type={ 'text' }
1323 value={ !! bgImage ? bgImage.image.url : '' }
1324 onChange={ ( value ) => {
1325 if ( ! value ) {
1326 setAttributes( {
1327 bgImage: null,
1328 } );
1329 } else {
1330 setAttributes( {
1331 bgImage: {
1332 id: '',
1333 image: {
1334 url: value,
1335 },
1336 },
1337 } );
1338 }
1339 } }
1340 />
1341
1342 <div className="gblocks-background-image-action-buttons">
1343 <MediaUpload
1344 title={ __( 'Set background image', 'generateblocks' ) }
1345 onSelect={ ( media ) => {
1346 let size = generateBlocksDefaults.container.bgImageSize;
1347
1348 if ( 'undefined' === typeof media.sizes[ size ] ) {
1349 size = 'full';
1350 }
1351
1352 setAttributes( {
1353 bgImage: {
1354 id: media.id,
1355 image: media.sizes[ size ],
1356 },
1357 } );
1358 } }
1359 onClose={ () => {
1360 document.querySelector( '.gblocks-bg-image-wrapper input' ).focus();
1361 } }
1362 allowedTypes={ [ 'image' ] }
1363 value={ !! bgImage ? bgImage.id : '' }
1364 modalClass="editor-gb-container-background__media-modal"
1365 render={ ( { open } ) => (
1366 <Tooltip text={ __( 'Open the Media Library', 'generateblocks' ) }>
1367 <Button
1368 onClick={ open }
1369 className="is-secondary is-small"
1370 >
1371 { __( 'Browse', 'generateblocks' ) }
1372 </Button>
1373 </Tooltip>
1374 ) }
1375 />
1376
1377 { applyFilters( 'generateblocks.editor.backgroundImageActions', '', this.props, this.state ) }
1378 </div>
1379 </div>
1380 </BaseControl>
1381
1382 { !! bgImage && (
1383 <Fragment>
1384 { !! bgOptions.overlay ? ( // This option is deprecated, so only show it if it's in use.
1385 <Fragment>
1386 <ToggleControl
1387 label={ __( 'Background Color Overlay', 'generateblocks' ) }
1388 checked={ !! bgOptions.overlay }
1389 onChange={ ( nextOverlay ) => {
1390 setAttributes( {
1391 bgOptions: {
1392 ...bgOptions,
1393 overlay: nextOverlay,
1394 },
1395 } );
1396 } }
1397 />
1398
1399 <Notice
1400 className="gblocks-option-notice"
1401 status="info"
1402 isDismissible={ false }
1403 >
1404 { __( 'The background color overlay option is deprecated. Toggle this option to use the new method.', 'generateblocks' ) }
1405 </Notice>
1406 </Fragment>
1407 ) : ( // These options is only for people not using the deprecated overlay option.
1408 <Fragment>
1409 { 'undefined' !== typeof bgImage.id && bgImage.id &&
1410 <SelectControl
1411 label={ __( 'Image Size', 'generateblocks' ) }
1412 value={ bgImageSize }
1413 options={ bgImageSizes }
1414 onChange={ ( value ) => {
1415 setAttributes( {
1416 bgImageSize: value,
1417 } );
1418 } }
1419 />
1420 }
1421
1422 <SelectControl
1423 label={ __( 'Selector', 'generateblocks' ) }
1424 value={ bgOptions.selector }
1425 options={ [
1426 { label: __( 'Element', 'generateblocks' ), value: 'element' },
1427 { label: __( 'Pseudo Element', 'generateblocks' ), value: 'pseudo-element' },
1428 ] }
1429 onChange={ ( value ) => {
1430 setAttributes( {
1431 bgOptions: {
1432 ...bgOptions,
1433 selector: value,
1434 },
1435 } );
1436 } }
1437 />
1438
1439 <RangeControl
1440 label={ __( 'Image Opacity', 'generateblocks' ) }
1441 value={ bgOptions.opacity }
1442 onChange={ ( value ) => {
1443 setAttributes( {
1444 bgOptions: {
1445 ...bgOptions,
1446 opacity: value,
1447 selector: 'pseudo-element',
1448 },
1449 } );
1450 } }
1451 min={ 0 }
1452 max={ 1 }
1453 step={ 0.1 }
1454 initialPosition={ generateBlocksDefaults.container.bgOptions.opacity }
1455 />
1456
1457 { 1 !== bgOptions.opacity && 'pseudo-element' !== bgOptions.selector &&
1458 <Notice
1459 className="gblocks-option-notice"
1460 status="info"
1461 isDismissible={ false }
1462 >
1463 { __( 'Your selector must be set to Pseudo Element to use opacity.', 'generateblocks' ) }
1464 </Notice>
1465 }
1466 </Fragment>
1467 ) }
1468
1469 <TextControl
1470 label={ __( 'Size', 'generateblocks' ) }
1471 value={ bgOptions.size }
1472 onChange={ ( nextSize ) => {
1473 setAttributes( {
1474 bgOptions: {
1475 ...bgOptions,
1476 size: nextSize,
1477 },
1478 } );
1479 } }
1480 />
1481
1482 <TextControl
1483 label={ __( 'Position', 'generateblocks' ) }
1484 value={ bgOptions.position }
1485 onChange={ ( nextPosition ) => {
1486 setAttributes( {
1487 bgOptions: {
1488 ...bgOptions,
1489 position: nextPosition,
1490 },
1491 } );
1492 } }
1493 />
1494
1495 <SelectControl
1496 label={ __( 'Repeat', 'generateblocks' ) }
1497 value={ bgOptions.repeat }
1498 options={ [
1499 { label: 'no-repeat', value: 'no-repeat' },
1500 { label: 'repeat', value: 'repeat' },
1501 { label: 'repeat-x', value: 'repeat-x' },
1502 { label: 'repeat-y', value: 'repeat-y' },
1503 ] }
1504 onChange={ ( nextRepeat ) => {
1505 setAttributes( {
1506 bgOptions: {
1507 ...bgOptions,
1508 repeat: nextRepeat,
1509 },
1510 } );
1511 } }
1512 />
1513
1514 <SelectControl
1515 label={ __( 'Attachment', 'generateblocks' ) }
1516 value={ bgOptions.attachment }
1517 options={ [
1518 { label: 'scroll', value: '' },
1519 { label: 'fixed', value: 'fixed' },
1520 { label: 'local', value: 'local' },
1521 ] }
1522 onChange={ ( nextAttachment ) => {
1523 setAttributes( {
1524 bgOptions: {
1525 ...bgOptions,
1526 attachment: nextAttachment,
1527 },
1528 } );
1529 } }
1530 />
1531 </Fragment>
1532 ) }
1533
1534 <GradientControl { ...this.props }
1535 attrGradient={ 'gradient' }
1536 attrGradientDirection={ 'gradientDirection' }
1537 attrGradientColorOne={ 'gradientColorOne' }
1538 attrGradientColorStopOne={ 'gradientColorStopOne' }
1539 attrGradientColorTwo={ 'gradientColorTwo' }
1540 attrGradientColorStopTwo={ 'gradientColorStopTwo' }
1541 attrGradientColorOneOpacity={ 'gradientColorOneOpacity' }
1542 attrGradientColorTwoOpacity={ 'gradientColorTwoOpacity' }
1543 defaultColorOne={ generateBlocksDefaults.container.gradientColorOne }
1544 defaultColorTwo={ generateBlocksDefaults.container.gradientColorTwo }
1545 />
1546
1547 { applyFilters( 'generateblocks.editor.controls', '', 'containerBackground', this.props, this.state ) }
1548 </Fragment>
1549 </PanelArea>
1550
1551 <PanelArea { ...this.props }
1552 title={ __( 'Shapes', 'generateblocks' ) }
1553 initialOpen={ false }
1554 icon={ getIcon( 'shapes' ) }
1555 className={ 'gblocks-panel-label' }
1556 id={ 'containerShapes' }
1557 state={ this.state }
1558 showPanel={ 'Desktop' === this.getDeviceType() || attributes.shapeDividers.length ? true : false }
1559 >
1560 <BaseControl className="gb-icon-chooser gb-shape-chooser">
1561 {
1562 shapeDividers.map( ( location, index ) => {
1563 const shapeNumber = index + 1;
1564
1565 return <Fragment key={ index }>
1566 <div className="gblocks-shape-container">
1567 <div
1568 className={ classnames( {
1569 'gblocks-shape-toggle-preview': true,
1570 [ `gblocks-shape-toggle-preview-${ shapeNumber }` ]: true,
1571 } ) }
1572 style={ { backgroundColor } }
1573 >
1574 { 'undefined' !== typeof allShapes[ shapeDividers[ index ].shape ] &&
1575 <div
1576 className="gblocks-shape-divider-preview"
1577 style={ { color: shapeDividers[ index ].color } }
1578 dangerouslySetInnerHTML={ { __html: sanitizeSVG( allShapes[ shapeDividers[ index ].shape ].icon ) } }
1579 />
1580 }
1581 </div>
1582
1583 {
1584 /* translators: Shape number */
1585 sprintf( __( 'Shape %s', 'generateblocks' ), shapeNumber )
1586 }
1587
1588 <Fragment>
1589 <Dropdown
1590 contentClassName="gblocks-shapes-dropdown"
1591 renderToggle={ ( { isOpen, onToggle } ) => (
1592 <Tooltip text={ __( 'Edit Shape', 'generateblocks' ) }>
1593 <Button
1594 className="gblocks-shape-dropdown"
1595 isSecondary={ isOpen ? undefined : true }
1596 isPrimary={ isOpen ? true : undefined }
1597 icon={ getIcon( 'wrench' ) }
1598 onClick={ onToggle }
1599 aria-expanded={ isOpen }
1600 />
1601 </Tooltip>
1602 ) }
1603 renderContent={ () => (
1604 <div className="gblocks-shape-controls">
1605 { 'Desktop' === this.getDeviceType() &&
1606 <Fragment>
1607 <BaseControl className="gb-icon-chooser">
1608 {
1609 Object.keys( generateBlocksInfo.svgShapes ).map( ( svg, i ) => {
1610 const svgItems = generateBlocksInfo.svgShapes[ svg ].svgs;
1611
1612 return (
1613 <PanelBody
1614 title={ generateBlocksInfo.svgShapes[ svg ].group }
1615 initialOpen={ svgItems.hasOwnProperty( shapeDividers[ index ].shape ) }
1616 key={ i }
1617 >
1618 <PanelRow>
1619 <BaseControl>
1620 <ul className="gblocks-icon-chooser gblocks-shape-chooser">
1621 {
1622 Object.keys( svgItems ).map( ( svgItem, iconIndex ) => {
1623 return (
1624 <li key={ `editor-pblock-types-list-item-${ iconIndex }` }>
1625 <Tooltip text={ ( svgItems[ svgItem ].label ) }>
1626 <Button
1627 className={ classnames( {
1628 'editor-block-list-item-button': true,
1629 'gblocks-shape-is-active': shapeDividers[ index ].shape === svgItem,
1630 } ) }
1631 onClick={ () => {
1632 const shapes = [ ...shapeDividers ];
1633
1634 shapes[ index ] = {
1635 ...shapes[ index ],
1636 shape: svgItem,
1637 };
1638
1639 setAttributes( {
1640 shapeDividers: shapes,
1641 } );
1642 } }
1643 >
1644 { 'string' === typeof svgItems[ svgItem ].icon ? (
1645 <Fragment>
1646 <span
1647 className="editor-block-types-list__item-icon"
1648 dangerouslySetInnerHTML={ { __html: sanitizeSVG( svgItems[ svgItem ].icon ) } }
1649 />
1650 </Fragment>
1651 ) : (
1652 <Fragment>
1653 <span className="editor-block-types-list__item-icon">
1654 { svgItems[ svgItem ].icon }
1655 </span>
1656 </Fragment>
1657 ) }
1658 </Button>
1659 </Tooltip>
1660 </li>
1661 );
1662 } )
1663 }
1664 </ul>
1665 </BaseControl>
1666 </PanelRow>
1667 </PanelBody>
1668 );
1669 } )
1670 }
1671 </BaseControl>
1672
1673 <ColorPicker
1674 label={ __( 'Color', 'generateblocks' ) }
1675 value={ shapeDividers[ index ].color }
1676 alpha={ true }
1677 valueOpacity={ shapeDividers[ index ].colorOpacity }
1678 onChange={ ( value ) => {
1679 const shapes = [ ...shapeDividers ];
1680
1681 shapes[ index ] = {
1682 ...shapes[ index ],
1683 color: value,
1684 };
1685
1686 setAttributes( {
1687 shapeDividers: shapes,
1688 } );
1689 } }
1690 onOpacityChange={ ( value ) => {
1691 const shapes = [ ...shapeDividers ];
1692
1693 shapes[ index ] = {
1694 ...shapes[ index ],
1695 colorOpacity: value,
1696 };
1697
1698 setAttributes( {
1699 shapeDividers: shapes,
1700 } );
1701 } }
1702 />
1703
1704 <SelectControl
1705 label={ __( 'Location', 'generateblocks' ) }
1706 value={ shapeDividers[ index ].location }
1707 options={ [
1708 { label: __( 'Top', 'generateblocks' ), value: 'top' },
1709 { label: __( 'Bottom', 'generateblocks' ), value: 'bottom' },
1710 ] }
1711 onChange={ ( value ) => {
1712 const shapes = [ ...shapeDividers ];
1713
1714 shapes[ index ] = {
1715 ...shapes[ index ],
1716 location: value,
1717 };
1718
1719 setAttributes( {
1720 shapeDividers: shapes,
1721 } );
1722 } }
1723 />
1724
1725 <UnitPicker
1726 label={ __( 'Height', 'generateblocks' ) }
1727 value={ 'px' }
1728 units={ [ 'px' ] }
1729 onClick={ () => {
1730 return false;
1731 } }
1732 />
1733
1734 <TextControl
1735 type={ 'number' }
1736 value={ shapeDividers[ index ].height ? shapeDividers[ index ].height : '' }
1737 onChange={ ( value ) => {
1738 const shapes = [ ...shapeDividers ];
1739
1740 shapes[ index ] = {
1741 ...shapes[ index ],
1742 height: parseFloat( value ),
1743 };
1744
1745 setAttributes( {
1746 shapeDividers: shapes,
1747 } );
1748 } }
1749 />
1750
1751 <UnitPicker
1752 label={ __( 'Width', 'generateblocks' ) }
1753 value={ '%' }
1754 units={ [ '%' ] }
1755 onClick={ () => {
1756 return false;
1757 } }
1758 />
1759
1760 <TextControl
1761 type={ 'number' }
1762 value={ shapeDividers[ index ].width ? shapeDividers[ index ].width : '' }
1763 min="100"
1764 onChange={ ( value ) => {
1765 const shapes = [ ...shapeDividers ];
1766
1767 shapes[ index ] = {
1768 ...shapes[ index ],
1769 width: parseFloat( value ),
1770 };
1771
1772 setAttributes( {
1773 shapeDividers: shapes,
1774 } );
1775 } }
1776 />
1777
1778 <ToggleControl
1779 label={ __( 'Flip Horizontally', 'generateblocks' ) }
1780 checked={ !! shapeDividers[ index ].flipHorizontally }
1781 onChange={ ( value ) => {
1782 const shapes = [ ...shapeDividers ];
1783
1784 shapes[ index ] = {
1785 ...shapes[ index ],
1786 flipHorizontally: value,
1787 };
1788
1789 setAttributes( {
1790 shapeDividers: shapes,
1791 } );
1792 } }
1793 />
1794
1795 <TextControl
1796 label={ __( 'z-index', 'generateblocks' ) }
1797 type={ 'number' }
1798 min="0"
1799 value={ shapeDividers[ index ].zindex || 0 === shapeDividers[ index ].zindex ? shapeDividers[ index ].zindex : '' }
1800 onChange={ ( value ) => {
1801 const shapes = [ ...shapeDividers ];
1802
1803 shapes[ index ] = {
1804 ...shapes[ index ],
1805 zindex: value,
1806 };
1807
1808 setAttributes( {
1809 shapeDividers: shapes,
1810 } );
1811 } }
1812 onBlur={ () => {
1813 const shapes = [ ...shapeDividers ];
1814
1815 shapes[ index ] = {
1816 ...shapes[ index ],
1817 zindex: parseFloat( shapeDividers[ index ].zindex ),
1818 };
1819
1820 setAttributes( {
1821 shapeDividers: shapes,
1822 } );
1823 } }
1824 onClick={ ( e ) => {
1825 // Make sure onBlur fires in Firefox.
1826 e.currentTarget.focus();
1827 } }
1828 />
1829 </Fragment>
1830 }
1831
1832 { 'Tablet' === this.getDeviceType() &&
1833 <Fragment>
1834 <UnitPicker
1835 label={ __( 'Height', 'generateblocks' ) }
1836 value={ 'px' }
1837 units={ [ 'px' ] }
1838 onClick={ () => {
1839 return false;
1840 } }
1841 />
1842
1843 <TextControl
1844 type={ 'number' }
1845 value={ shapeDividers[ index ].heightTablet ? shapeDividers[ index ].heightTablet : '' }
1846 onChange={ ( value ) => {
1847 const shapes = [ ...shapeDividers ];
1848
1849 shapes[ index ] = {
1850 ...shapes[ index ],
1851 heightTablet: parseFloat( value ),
1852 };
1853
1854 setAttributes( {
1855 shapeDividers: shapes,
1856 } );
1857 } }
1858 />
1859
1860 <UnitPicker
1861 label={ __( 'Width', 'generateblocks' ) }
1862 value={ '%' }
1863 units={ [ '%' ] }
1864 onClick={ () => {
1865 return false;
1866 } }
1867 />
1868
1869 <TextControl
1870 type={ 'number' }
1871 value={ shapeDividers[ index ].widthTablet ? shapeDividers[ index ].widthTablet : '' }
1872 min="100"
1873 onChange={ ( value ) => {
1874 const shapes = [ ...shapeDividers ];
1875
1876 shapes[ index ] = {
1877 ...shapes[ index ],
1878 widthTablet: parseFloat( value ),
1879 };
1880
1881 setAttributes( {
1882 shapeDividers: shapes,
1883 } );
1884 } }
1885 />
1886 </Fragment>
1887 }
1888
1889 { 'Mobile' === this.getDeviceType() &&
1890 <Fragment>
1891 <UnitPicker
1892 label={ __( 'Height', 'generateblocks' ) }
1893 value={ 'px' }
1894 units={ [ 'px' ] }
1895 onClick={ () => {
1896 return false;
1897 } }
1898 />
1899
1900 <TextControl
1901 type={ 'number' }
1902 value={ shapeDividers[ index ].heightMobile ? shapeDividers[ index ].heightMobile : '' }
1903 onChange={ ( value ) => {
1904 const shapes = [ ...shapeDividers ];
1905
1906 shapes[ index ] = {
1907 ...shapes[ index ],
1908 heightMobile: parseFloat( value ),
1909 };
1910
1911 setAttributes( {
1912 shapeDividers: shapes,
1913 } );
1914 } }
1915 />
1916
1917 <UnitPicker
1918 label={ __( 'Width', 'generateblocks' ) }
1919 value={ '%' }
1920 units={ [ '%' ] }
1921 onClick={ () => {
1922 return false;
1923 } }
1924 />
1925
1926 <TextControl
1927 type={ 'number' }
1928 value={ shapeDividers[ index ].widthMobile ? shapeDividers[ index ].widthMobile : '' }
1929 min="100"
1930 onChange={ ( value ) => {
1931 const shapes = [ ...shapeDividers ];
1932
1933 shapes[ index ] = {
1934 ...shapes[ index ],
1935 widthMobile: parseFloat( value ),
1936 };
1937
1938 setAttributes( {
1939 shapeDividers: shapes,
1940 } );
1941 } }
1942 />
1943 </Fragment>
1944 }
1945 </div>
1946 ) }
1947 />
1948 </Fragment>
1949
1950 { 'Desktop' === this.getDeviceType() &&
1951 <Tooltip text={ __( 'Delete Shape', 'generateblocks' ) }>
1952 <Button
1953 className="gblocks-remove-shape"
1954 onClick={ () => {
1955 // eslint-disable-next-line
1956 if ( window.confirm( __( 'This will permanently delete this shape.', 'generateblocks' ) ) ) {
1957 handleRemoveShape( index );
1958 }
1959 } }
1960 icon={ getIcon( 'x' ) }
1961 />
1962 </Tooltip>
1963 }
1964 </div>
1965 </Fragment>;
1966 } )
1967 }
1968
1969 <div className="gblocks-add-new-shape">
1970 <Button
1971 isSecondary
1972 onClick={ handleAddShape.bind( this ) }
1973 >
1974 { __( 'Add Shape', 'generateblocks' ) }
1975 </Button>
1976 </div>
1977 </BaseControl>
1978
1979 { applyFilters( 'generateblocks.editor.controls', '', 'containerShapeDivider', this.props, this.state ) }
1980 </PanelArea>
1981
1982 <PanelArea { ...this.props }
1983 title={ __( 'Documentation', 'generateblocks' ) }
1984 initialOpen={ false }
1985 icon={ getIcon( 'documentation' ) }
1986 className={ 'gblocks-panel-label' }
1987 id={ 'containerDocumentation' }
1988 state={ this.state }
1989 >
1990 <p>{ __( 'Need help with this block?', 'generateblocks' ) }</p>
1991 <a href="https://docs.generateblocks.com/collection/container/" target="_blank" rel="noreferrer noopener">{ __( 'Visit our documentation', 'generateblocks' ) }</a>
1992
1993 { applyFilters( 'generateblocks.editor.controls', '', 'containerDocumentation', this.props, this.state ) }
1994 </PanelArea>
1995 </InspectorControls>
1996
1997 <InspectorAdvancedControls>
1998 <TextControl
1999 label={ __( 'HTML Anchor', 'generateblocks' ) }
2000 help={ __( 'Anchors lets you link directly to a section on a page.', 'generateblocks' ) }
2001 value={ anchor || '' }
2002 onChange={ ( nextValue ) => {
2003 nextValue = nextValue.replace( ANCHOR_REGEX, '-' );
2004 setAttributes( {
2005 anchor: nextValue,
2006 } );
2007 } } />
2008 </InspectorAdvancedControls>
2009
2010 <MainCSS { ...this.props } />
2011
2012 { this.props.deviceType &&
2013 <Fragment>
2014 { 'Desktop' === this.props.deviceType &&
2015 <DesktopCSS { ...this.props } />
2016 }
2017
2018 { ( 'Tablet' === this.props.deviceType || 'Mobile' === this.props.deviceType ) &&
2019 <TabletCSS { ...this.props } />
2020 }
2021
2022 { 'Tablet' === this.props.deviceType &&
2023 <TabletOnlyCSS { ...this.props } />
2024 }
2025
2026 { 'Mobile' === this.props.deviceType &&
2027 <MobileCSS { ...this.props } />
2028 }
2029 </Fragment>
2030 }
2031
2032 { fontFamily && googleFont &&
2033 <link
2034 rel="stylesheet"
2035 href={ 'https://fonts.googleapis.com/css?family=' + fontFamily.replace( / /g, '+' ) + googleFontsAttr }
2036 />
2037 }
2038
2039 <Element
2040 tagName={ applyFilters( 'generateblocks.frontend.containerTagName', tagName, attributes ) }
2041 htmlAttrs={ htmlAttributes }
2042 >
2043 { applyFilters( 'generateblocks.frontend.afterContainerOpen', '', attributes ) }
2044 <div
2045 className={ classnames( {
2046 'gb-inside-container': true,
2047 } ) }
2048 >
2049 { applyFilters( 'generateblocks.frontend.insideContainer', '', attributes ) }
2050 <InnerBlocks
2051 templateLock={ false }
2052 renderAppender={ ( hasChildBlocks ? undefined : () => <InnerBlocks.ButtonBlockAppender /> ) }
2053 />
2054 </div>
2055
2056 { allShapeDividers() }
2057
2058 { applyFilters( 'generateblocks.frontend.beforeContainerClose', '', attributes ) }
2059 </Element>
2060 </Fragment>
2061 );
2062 }
2063 }
2064
2065 export default compose( [
2066 withDispatch( ( dispatch ) => ( {
2067 setDeviceType( type ) {
2068 const {
2069 __experimentalSetPreviewDeviceType: setPreviewDeviceType,
2070 } = dispatch( 'core/edit-post' );
2071
2072 if ( ! setPreviewDeviceType ) {
2073 return;
2074 }
2075
2076 setPreviewDeviceType( type );
2077 },
2078 } ) ),
2079 withSelect( ( select ) => {
2080 const {
2081 __experimentalGetPreviewDeviceType: getPreviewDeviceType,
2082 } = select( 'core/edit-post' );
2083
2084 const {
2085 getMedia,
2086 } = select( 'core' );
2087
2088 const {
2089 getEditedPostAttribute,
2090 } = select( 'core/editor' );
2091
2092 const featuredImageId = getEditedPostAttribute( 'featured_media' );
2093
2094 if ( ! getPreviewDeviceType ) {
2095 return {
2096 media: featuredImageId ? getMedia( featuredImageId ) : null,
2097 deviceType: null,
2098 };
2099 }
2100
2101 return {
2102 media: featuredImageId ? getMedia( featuredImageId ) : null,
2103 deviceType: getPreviewDeviceType(),
2104 };
2105 } ),
2106 ] )( GenerateBlockContainer );
2107