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