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 / button / edit.js
generateblocks / src / blocks / button Last commit date
css 5 years ago attributes.js 5 years ago block.js 5 years ago deprecated.js 5 years ago edit.js 5 years ago editor.scss 5 years ago save.js 5 years ago
edit.js
1140 lines
1 /**
2 * Block: Buttons
3 */
4
5 import classnames from 'classnames';
6 import ColorPicker from '../../components/color-picker';
7 import UnitPicker from '../../components/unit-picker';
8 import IconPicker from '../../components/icon-picker';
9 import URLInput from '../../components/url-input';
10 import DimensionsControl from '../../components/dimensions/';
11 import TypographyControls from '../../components/typography';
12 import GradientControl from '../../components/gradient/';
13 import ResponsiveTabs from '../../components/responsive-tabs';
14 import PanelArea from '../../components/panel-area/';
15 import getIcon from '../../utils/get-icon';
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 import sanitizeSVG from '../../utils/sanitize-svg';
22 import Element from '../../components/element';
23
24 import {
25 __,
26 } from '@wordpress/i18n';
27
28 import {
29 TabPanel,
30 TextControl,
31 ToolbarGroup,
32 ToolbarButton,
33 Button,
34 } from '@wordpress/components';
35
36 import {
37 Fragment,
38 Component,
39 } from '@wordpress/element';
40
41 import {
42 InspectorControls,
43 InspectorAdvancedControls,
44 RichText,
45 BlockControls,
46 } from '@wordpress/block-editor';
47
48 import {
49 cloneBlock,
50 } from '@wordpress/blocks';
51
52 import {
53 applyFilters,
54 } from '@wordpress/hooks';
55
56 import {
57 withSelect,
58 withDispatch,
59 } from '@wordpress/data';
60
61 import {
62 compose,
63 } from '@wordpress/compose';
64
65 /**
66 * Regular expression matching invalid anchor characters for replacement.
67 *
68 * @type {RegExp}
69 */
70 const ANCHOR_REGEX = /[\s#]/g;
71
72 const gbButtonIds = [];
73
74 class GenerateBlockButton extends Component {
75 constructor() {
76 super( ...arguments );
77
78 this.state = {
79 selectedDevice: 'Desktop',
80 fontSizePlaceholder: '17',
81 };
82
83 this.getFontSizePlaceholder = this.getFontSizePlaceholder.bind( this );
84 this.getDeviceType = this.getDeviceType.bind( this );
85 this.setDeviceType = this.setDeviceType.bind( this );
86 }
87
88 componentDidMount() {
89 const id = this.props.clientId.substr( 2, 9 ).replace( '-', '' );
90
91 if ( ! this.props.attributes.uniqueId ) {
92 this.props.setAttributes( {
93 uniqueId: id,
94 } );
95
96 gbButtonIds.push( id );
97 } else if ( gbButtonIds.includes( this.props.attributes.uniqueId ) ) {
98 this.props.setAttributes( {
99 uniqueId: id,
100 } );
101
102 gbButtonIds.push( id );
103 } else {
104 gbButtonIds.push( this.props.attributes.uniqueId );
105 }
106
107 const tempFontSizePlaceholder = this.getFontSizePlaceholder();
108
109 if ( tempFontSizePlaceholder !== this.state.fontSizePlaceholder ) {
110 this.setState( {
111 fontSizePlaceholder: tempFontSizePlaceholder,
112 } );
113 }
114
115 // hasIcon came late, so let's set it on mount if we have an icon.
116 if ( ! this.props.attributes.hasIcon && this.props.attributes.icon ) {
117 this.props.setAttributes( {
118 hasIcon: true,
119 } );
120 }
121
122 // hasUrl came late, so let's set it if it doesn't exist.
123 if ( 'undefined' === typeof this.props.attributes.hasUrl ) {
124 if ( ! this.props.attributes.url ) {
125 this.props.setAttributes( {
126 hasUrl: false,
127 } );
128 } else {
129 this.props.setAttributes( {
130 hasUrl: true,
131 } );
132 }
133 }
134 }
135
136 componentDidUpdate() {
137 const tempFontSizePlaceholder = this.getFontSizePlaceholder();
138
139 if ( tempFontSizePlaceholder !== this.state.fontSizePlaceholder ) {
140 this.setState( {
141 fontSizePlaceholder: tempFontSizePlaceholder,
142 } );
143 }
144 }
145
146 getFontSizePlaceholder() {
147 let placeholder = '17';
148 const buttonId = document.querySelector( '.gb-button-' + this.props.attributes.uniqueId );
149
150 if ( buttonId ) {
151 placeholder = parseFloat( window.getComputedStyle( buttonId ).fontSize );
152 }
153
154 return placeholder;
155 }
156
157 getDeviceType() {
158 let deviceType = this.props.deviceType ? this.props.deviceType : this.state.selectedDevice;
159
160 if ( ! generateBlocksInfo.syncResponsivePreviews ) {
161 deviceType = this.state.selectedDevice;
162 }
163
164 return deviceType;
165 }
166
167 setDeviceType( deviceType ) {
168 if ( generateBlocksInfo.syncResponsivePreviews && this.props.deviceType ) {
169 this.props.setDeviceType( deviceType );
170 this.setState( { selectedDevice: deviceType } );
171 } else {
172 this.setState( { selectedDevice: deviceType } );
173 }
174 }
175
176 render() {
177 const {
178 attributes,
179 setAttributes,
180 isSelected,
181 clientId,
182 } = this.props;
183
184 const {
185 fontSizePlaceholder,
186 } = this.state;
187
188 const {
189 uniqueId,
190 className,
191 anchor,
192 text,
193 url,
194 target,
195 relNoFollow,
196 relSponsored,
197 icon,
198 iconLocation,
199 removeText,
200 ariaLabel,
201 backgroundColor,
202 backgroundColorOpacity,
203 textColor,
204 backgroundColorHover,
205 backgroundColorHoverOpacity,
206 textColorHover,
207 fontFamily,
208 googleFont,
209 googleFontVariants,
210 borderColor,
211 borderColorOpacity,
212 borderColorHover,
213 borderColorHoverOpacity,
214 iconSize,
215 iconSizeTablet,
216 iconSizeMobile,
217 iconSizeUnit,
218 } = attributes;
219
220 // Stop the buttons from doing anything in the editor.
221 const links = document.querySelectorAll( 'a.gb-button' );
222
223 for ( let i = 0; i < links.length; i++ ) {
224 links[ i ].addEventListener( 'click', function( e ) {
225 if ( links[ i ].getAttribute( 'href' ) ) {
226 links[ i ].removeAttribute( 'href' );
227 e.preventDefault();
228 }
229 }, false );
230 }
231
232 const relAttributes = [];
233
234 if ( relNoFollow ) {
235 relAttributes.push( 'nofollow' );
236 }
237
238 if ( target ) {
239 relAttributes.push( 'noopener', 'noreferrer' );
240 }
241
242 if ( relSponsored ) {
243 relAttributes.push( 'sponsored' );
244 }
245
246 let googleFontsAttr = '';
247
248 if ( googleFontVariants ) {
249 googleFontsAttr = ':' + googleFontVariants;
250 }
251
252 let htmlAttributes = {
253 className: classnames( {
254 'gb-button': true,
255 [ `gb-button-${ uniqueId }` ]: true,
256 'gb-button-text': ! icon,
257 [ `${ className }` ]: undefined !== className,
258 } ),
259 href: !! url ? url : null,
260 target: !! target ? '_blank' : null,
261 rel: relAttributes && relAttributes.length > 0 ? relAttributes.join( ' ' ) : null,
262 'aria-label': !! ariaLabel ? ariaLabel : null,
263 id: anchor ? anchor : null,
264 };
265
266 htmlAttributes = applyFilters( 'generateblocks.frontend.htmlAttributes', htmlAttributes, 'generateblocks/button', attributes );
267
268 return (
269 <Fragment>
270 <BlockControls>
271 <ToolbarGroup>
272 <ToolbarButton
273 className="gblocks-add-new-button"
274 icon={ 'insert' }
275 label={ __( 'Add Button', 'generateblocks' ) }
276 onClick={ () => {
277 let parentBlockId = false;
278
279 if ( typeof wp.data.select( 'core/block-editor' ).getBlockParentsByBlockName === 'function' ) {
280 parentBlockId = wp.data.select( 'core/block-editor' ).getBlockParentsByBlockName( clientId, 'generateblocks/button-container', true )[ 0 ];
281 } else {
282 parentBlockId = wp.data.select( 'core/block-editor' ).getBlockRootClientId( clientId );
283 }
284
285 const thisBlock = wp.data.select( 'core/block-editor' ).getBlocksByClientId( clientId )[ 0 ];
286 const clonedBlock = cloneBlock( thisBlock );
287
288 wp.data.dispatch( 'core/block-editor' ).insertBlocks( clonedBlock, undefined, parentBlockId );
289 } }
290 showTooltip
291 />
292 </ToolbarGroup>
293 </BlockControls>
294
295 <InspectorControls>
296 <ResponsiveTabs { ...this.props }
297 selectedDevice={ this.getDeviceType() }
298 onClick={ ( device ) => {
299 this.setDeviceType( device );
300 } }
301 />
302
303 <PanelArea { ...this.props }
304 title={ __( 'Typography', 'generateblocks' ) }
305 initialOpen={ false }
306 icon={ getIcon( 'typography' ) }
307 className={ 'gblocks-panel-label' }
308 id={ 'buttonTypography' }
309 state={ this.state }
310 showPanel={ ! removeText || false }
311 >
312
313 { 'Desktop' === this.getDeviceType() && (
314 <Fragment>
315 <TypographyControls { ...this.props }
316 showFontFamily={ true }
317 showFontWeight={ true }
318 showTextTransform={ true }
319 showFontSize={ true }
320 showLetterSpacing={ true }
321 fontSizePlaceholder={ fontSizePlaceholder }
322 defaultFontSize={ generateBlocksDefaults.button.fontSize }
323 defaultFontSizeUnit={ generateBlocksDefaults.button.fontSizeUnit }
324 defaultLetterSpacing={ generateBlocksDefaults.button.letterSpacing }
325 />
326 </Fragment>
327 ) }
328
329 { 'Tablet' === this.getDeviceType() && (
330 <Fragment>
331 <TypographyControls { ...this.props }
332 device={ 'Tablet' }
333 showFontSize={ true }
334 showLetterSpacing={ true }
335 disableAdvancedToggle={ true }
336 defaultFontSize={ generateBlocksDefaults.button.fontSizeTablet }
337 defaultFontSizeUnit={ generateBlocksDefaults.button.fontSizeUnit }
338 defaultLetterSpacing={ generateBlocksDefaults.button.letterSpacingTablet }
339 />
340 </Fragment>
341 ) }
342
343 { 'Mobile' === this.getDeviceType() && (
344 <Fragment>
345 <TypographyControls { ...this.props }
346 device={ 'Mobile' }
347 showFontSize={ true }
348 showLetterSpacing={ true }
349 disableAdvancedToggle={ true }
350 defaultFontSize={ generateBlocksDefaults.button.fontSizeMobile }
351 defaultFontSizeUnit={ generateBlocksDefaults.button.fontSizeUnit }
352 defaultLetterSpacing={ generateBlocksDefaults.button.letterSpacingMobile }
353 />
354 </Fragment>
355 ) }
356
357 { applyFilters( 'generateblocks.editor.controls', '', 'buttonTypography', this.props, this.state ) }
358 </PanelArea>
359
360 <PanelArea { ...this.props }
361 title={ __( 'Spacing', 'generateblocks' ) }
362 initialOpen={ false }
363 icon={ getIcon( 'spacing' ) }
364 className={ 'gblocks-panel-label' }
365 id={ 'buttonSpacing' }
366 state={ this.state }
367 >
368
369 { 'Desktop' === this.getDeviceType() && (
370 <Fragment>
371 <DimensionsControl { ...this.props }
372 device={ this.getDeviceType() }
373 type={ 'padding' }
374 label={ __( 'Padding', 'generateblocks' ) }
375 attrTop={ 'paddingTop' }
376 attrRight={ 'paddingRight' }
377 attrBottom={ 'paddingBottom' }
378 attrLeft={ 'paddingLeft' }
379 attrUnit={ 'paddingUnit' }
380 attrSyncUnits={ 'paddingSyncUnits' }
381 defaults={ generateBlocksDefaults.button }
382 units={ [ 'px', 'em', '%' ] }
383 />
384
385 <DimensionsControl { ...this.props }
386 device={ this.getDeviceType() }
387 type={ 'margin' }
388 label={ __( 'Margin', 'generateblocks' ) }
389 attrTop={ 'marginTop' }
390 attrRight={ 'marginRight' }
391 attrBottom={ 'marginBottom' }
392 attrLeft={ 'marginLeft' }
393 attrUnit={ 'marginUnit' }
394 attrSyncUnits={ 'marginSyncUnits' }
395 defaults={ generateBlocksDefaults.button }
396 units={ [ 'px', 'em', '%' ] }
397 />
398
399 <DimensionsControl { ...this.props }
400 device={ this.getDeviceType() }
401 type={ 'padding' }
402 label={ __( 'Border Size', 'generateblocks' ) }
403 attrTop={ 'borderSizeTop' }
404 attrRight={ 'borderSizeRight' }
405 attrBottom={ 'borderSizeBottom' }
406 attrLeft={ 'borderSizeLeft' }
407 attrSyncUnits={ 'borderSizeSyncUnits' }
408 defaults={ generateBlocksDefaults.button }
409 units={ [ 'px' ] }
410 />
411
412 <DimensionsControl { ...this.props }
413 device={ this.getDeviceType() }
414 type={ 'padding' }
415 label={ __( 'Border Radius', 'generateblocks' ) }
416 attrTop={ 'borderRadiusTopLeft' }
417 attrRight={ 'borderRadiusTopRight' }
418 attrBottom={ 'borderRadiusBottomRight' }
419 attrLeft={ 'borderRadiusBottomLeft' }
420 attrUnit={ 'borderRadiusUnit' }
421 attrSyncUnits={ 'borderRadiusSyncUnits' }
422 labelTop={ __( 'T-Left', 'generateblocks' ) }
423 labelRight={ __( 'T-Right', 'generateblocks' ) }
424 labelBottom={ __( 'B-Right', 'generateblocks' ) }
425 labelLeft={ __( 'B-Left', 'generateblocks' ) }
426 defaults={ generateBlocksDefaults.button }
427 units={ [ 'px', 'em', '%' ] }
428 />
429 </Fragment>
430 ) }
431
432 { 'Tablet' === this.getDeviceType() && (
433 <Fragment>
434 <DimensionsControl { ...this.props }
435 device={ this.getDeviceType() }
436 type={ 'padding' }
437 label={ __( 'Padding', 'generateblocks' ) }
438 attrTop={ 'paddingTopTablet' }
439 attrRight={ 'paddingRightTablet' }
440 attrBottom={ 'paddingBottomTablet' }
441 attrLeft={ 'paddingLeftTablet' }
442 attrUnit={ 'paddingUnit' }
443 attrSyncUnits={ 'paddingSyncUnits' }
444 defaults={ generateBlocksDefaults.button }
445 units={ [ 'px', 'em', '%' ] }
446 />
447
448 <DimensionsControl { ...this.props }
449 device={ this.getDeviceType() }
450 type={ 'margin' }
451 label={ __( 'Margin', 'generateblocks' ) }
452 attrTop={ 'marginTopTablet' }
453 attrRight={ 'marginRightTablet' }
454 attrBottom={ 'marginBottomTablet' }
455 attrLeft={ 'marginLeftTablet' }
456 attrUnit={ 'marginUnit' }
457 attrSyncUnits={ 'marginSyncUnits' }
458 defaults={ generateBlocksDefaults.button }
459 units={ [ 'px', 'em', '%' ] }
460 />
461
462 <DimensionsControl { ...this.props }
463 device={ this.getDeviceType() }
464 type={ 'padding' }
465 label={ __( 'Border Size', 'generateblocks' ) }
466 attrTop={ 'borderSizeTopTablet' }
467 attrRight={ 'borderSizeRightTablet' }
468 attrBottom={ 'borderSizeBottomTablet' }
469 attrLeft={ 'borderSizeLeftTablet' }
470 attrSyncUnits={ 'borderSizeSyncUnits' }
471 defaults={ generateBlocksDefaults.button }
472 units={ [ 'px' ] }
473 />
474
475 <DimensionsControl { ...this.props }
476 device={ this.getDeviceType() }
477 type={ 'padding' }
478 label={ __( 'Border Radius', 'generateblocks' ) }
479 attrTop={ 'borderRadiusTopLeftTablet' }
480 attrRight={ 'borderRadiusTopRightTablet' }
481 attrBottom={ 'borderRadiusBottomRightTablet' }
482 attrLeft={ 'borderRadiusBottomLeftTablet' }
483 attrUnit={ 'borderRadiusUnit' }
484 attrSyncUnits={ 'borderRadiusSyncUnits' }
485 labelTop={ __( 'T-Left', 'generateblocks' ) }
486 labelRight={ __( 'T-Right', 'generateblocks' ) }
487 labelBottom={ __( 'B-Right', 'generateblocks' ) }
488 labelLeft={ __( 'B-Left', 'generateblocks' ) }
489 defaults={ generateBlocksDefaults.button }
490 units={ [ 'px', 'em', '%' ] }
491 />
492 </Fragment>
493 ) }
494
495 { 'Mobile' === this.getDeviceType() && (
496 <Fragment>
497 <DimensionsControl { ...this.props }
498 device={ this.getDeviceType() }
499 type={ 'padding' }
500 label={ __( 'Padding', 'generateblocks' ) }
501 attrTop={ 'paddingTopMobile' }
502 attrRight={ 'paddingRightMobile' }
503 attrBottom={ 'paddingBottomMobile' }
504 attrLeft={ 'paddingLeftMobile' }
505 attrUnit={ 'paddingUnit' }
506 attrSyncUnits={ 'paddingSyncUnits' }
507 defaults={ generateBlocksDefaults.button }
508 units={ [ 'px', 'em', '%' ] }
509 />
510
511 <DimensionsControl { ...this.props }
512 device={ this.getDeviceType() }
513 type={ 'padding' }
514 label={ __( 'Margin', 'generateblocks' ) }
515 attrTop={ 'marginTopMobile' }
516 attrRight={ 'marginRightMobile' }
517 attrBottom={ 'marginBottomMobile' }
518 attrLeft={ 'marginLeftMobile' }
519 attrUnit={ 'marginUnit' }
520 attrSyncUnits={ 'marginSyncUnits' }
521 defaults={ generateBlocksDefaults.button }
522 units={ [ 'px', 'em', '%' ] }
523 />
524
525 <DimensionsControl { ...this.props }
526 device={ this.getDeviceType() }
527 type={ 'padding' }
528 label={ __( 'Border Size', 'generateblocks' ) }
529 attrTop={ 'borderSizeTopMobile' }
530 attrRight={ 'borderSizeRightMobile' }
531 attrBottom={ 'borderSizeBottomMobile' }
532 attrLeft={ 'borderSizeLeftMobile' }
533 attrSyncUnits={ 'borderSizeSyncUnits' }
534 defaults={ generateBlocksDefaults.button }
535 units={ [ 'px' ] }
536 />
537
538 <DimensionsControl { ...this.props }
539 device={ this.getDeviceType() }
540 type={ 'padding' }
541 label={ __( 'Border Radius', 'generateblocks' ) }
542 attrTop={ 'borderRadiusTopLeftMobile' }
543 attrRight={ 'borderRadiusTopRightMobile' }
544 attrBottom={ 'borderRadiusBottomRightMobile' }
545 attrLeft={ 'borderRadiusBottomLeftMobile' }
546 attrUnit={ 'borderRadiusUnit' }
547 attrSyncUnits={ 'borderRadiusSyncUnits' }
548 labelTop={ __( 'T-Left', 'generateblocks' ) }
549 labelRight={ __( 'T-Right', 'generateblocks' ) }
550 labelBottom={ __( 'B-Right', 'generateblocks' ) }
551 labelLeft={ __( 'B-Left', 'generateblocks' ) }
552 defaults={ generateBlocksDefaults.button }
553 units={ [ 'px', 'em', '%' ] }
554 />
555 </Fragment>
556 ) }
557
558 { applyFilters( 'generateblocks.editor.controls', '', 'buttonSpacing', this.props, this.state ) }
559 </PanelArea>
560
561 <PanelArea { ...this.props }
562 title={ __( 'Colors', 'generateblocks' ) }
563 initialOpen={ false }
564 icon={ getIcon( 'colors' ) }
565 className={ 'gblocks-panel-label' }
566 id={ 'buttonColors' }
567 state={ this.state }
568 >
569 { 'Desktop' === this.getDeviceType() &&
570 <TabPanel className="layout-tab-panel gblocks-control-tabs"
571 activeClass="active-tab"
572 tabs={ [
573 {
574 name: 'button-colors',
575 title: __( 'Normal', 'generateblocks' ),
576 className: 'button-colors',
577 },
578 {
579 name: 'button-colors-hover',
580 title: __( 'Hover', 'generateblocks' ),
581 className: 'button-colors-hover',
582 },
583 ] }>
584 {
585 ( tab ) => {
586 const isNormal = tab.name === 'button-colors';
587
588 return (
589 <div>
590 { isNormal ? (
591 <Fragment>
592 <ColorPicker
593 label={ __( 'Background Color', 'generateblocks' ) }
594 value={ backgroundColor }
595 alpha={ true }
596 valueOpacity={ backgroundColorOpacity }
597 attrOpacity={ 'backgroundColorOpacity' }
598 key={ 'buttonBackgroundColor' }
599 onChange={ ( nextBackgroundColor ) =>
600 setAttributes( {
601 backgroundColor: nextBackgroundColor,
602 } )
603 }
604 onOpacityChange={ ( value ) =>
605 setAttributes( {
606 backgroundColorOpacity: value,
607 } )
608 }
609 />
610
611 <ColorPicker
612 label={ __( 'Text Color', 'generateblocks' ) }
613 value={ textColor }
614 alpha={ false }
615 key={ 'buttonTextColor' }
616 onChange={ ( nextTextColor ) =>
617 setAttributes( {
618 textColor: nextTextColor,
619 } )
620 }
621 />
622
623 <ColorPicker
624 label={ __( 'Border Color', 'generateblocks' ) }
625 value={ borderColor }
626 alpha={ true }
627 valueOpacity={ borderColorOpacity }
628 attrOpacity={ 'borderColorOpacity' }
629 key={ 'buttonBorderColor' }
630 onChange={ ( value ) =>
631 setAttributes( {
632 borderColor: value,
633 } )
634 }
635 onOpacityChange={ ( value ) =>
636 setAttributes( {
637 borderColorOpacity: value,
638 } )
639 }
640 />
641
642 { applyFilters( 'generateblocks.editor.controls', '', 'buttonColorsNormal', this.props, this.state ) }
643 </Fragment>
644
645 ) : (
646
647 <Fragment>
648 <ColorPicker
649 label={ __( 'Background Color', 'generateblocks' ) }
650 value={ backgroundColorHover }
651 alpha={ true }
652 valueOpacity={ backgroundColorHoverOpacity }
653 attrOpacity={ 'backgroundColorHoverOpacity' }
654 key={ 'buttonBackgroundColorHover' }
655 onChange={ ( nextBackgroundColorHover ) =>
656 setAttributes( {
657 backgroundColorHover: nextBackgroundColorHover,
658 } )
659 }
660 onOpacityChange={ ( value ) =>
661 setAttributes( {
662 backgroundColorHoverOpacity: value,
663 } )
664 }
665 />
666
667 <ColorPicker
668 label={ __( 'Text Color', 'generateblocks' ) }
669 value={ textColorHover }
670 alpha={ false }
671 key={ 'buttonTextColorHover' }
672 onChange={ ( nextTextColorHover ) =>
673 setAttributes( {
674 textColorHover: nextTextColorHover,
675 } )
676 }
677 />
678
679 <ColorPicker
680 label={ __( 'Border Color', 'generateblocks' ) }
681 value={ borderColorHover }
682 alpha={ true }
683 valueOpacity={ borderColorHoverOpacity }
684 attrOpacity={ 'borderColorHoverOpacity' }
685 key={ 'buttonBorderColorHover' }
686 onChange={ ( value ) =>
687 setAttributes( {
688 borderColorHover: value,
689 } )
690 }
691 onOpacityChange={ ( value ) =>
692 setAttributes( {
693 borderColorHoverOpacity: value,
694 } )
695 }
696 />
697
698 { applyFilters( 'generateblocks.editor.controls', '', 'buttonColorsHover', this.props, this.state ) }
699 </Fragment>
700 ) }
701 </div>
702 );
703 }
704 }
705 </TabPanel>
706 }
707
708 { applyFilters( 'generateblocks.editor.controls', '', 'buttonColors', this.props, this.state ) }
709 </PanelArea>
710
711 <PanelArea { ...this.props }
712 title={ __( 'Background Gradient', 'generateblocks' ) }
713 initialOpen={ false }
714 icon={ getIcon( 'gradients' ) }
715 className={ 'gblocks-panel-label' }
716 id={ 'buttonBackgroundGradient' }
717 state={ this.state }
718 >
719 { 'Desktop' === this.getDeviceType() &&
720 <GradientControl { ...this.props }
721 attrGradient={ 'gradient' }
722 attrGradientDirection={ 'gradientDirection' }
723 attrGradientColorOne={ 'gradientColorOne' }
724 attrGradientColorOneOpacity={ 'gradientColorOneOpacity' }
725 attrGradientColorStopOne={ 'gradientColorStopOne' }
726 attrGradientColorTwo={ 'gradientColorTwo' }
727 attrGradientColorTwoOpacity={ 'gradientColorTwoOpacity' }
728 attrGradientColorStopTwo={ 'gradientColorStopTwo' }
729 defaultColorOne={ generateBlocksDefaults.button.gradientColorOne }
730 defaultColorTwo={ generateBlocksDefaults.button.gradientColorTwo }
731 />
732 }
733
734 { applyFilters( 'generateblocks.editor.controls', '', 'buttonBackgroundGradient', this.props, this.state ) }
735 </PanelArea>
736
737 <PanelArea { ...this.props }
738 title={ __( 'Icon', 'generateblocks' ) }
739 initialOpen={ false }
740 icon={ getIcon( 'icons' ) }
741 className={ 'gblocks-panel-label' }
742 id={ 'buttonIcon' }
743 state={ this.state }
744 showPanel={ 'Desktop' === this.getDeviceType() || !! icon ? true : false }
745 >
746
747 { 'Desktop' === this.getDeviceType() &&
748 <IconPicker { ...this.props }
749 attrIcon={ 'icon' }
750 attrIconLocation={ 'iconLocation' }
751 attrRemoveText={ 'removeText' }
752 locationOptions={ [
753 { label: __( 'Left', 'generateblocks' ), value: 'left' },
754 { label: __( 'Right', 'generateblocks' ), value: 'right' },
755 ] }
756 />
757 }
758
759 { 'Desktop' === this.getDeviceType() && !! icon && (
760 <Fragment>
761 { ! removeText &&
762 <Fragment>
763 <DimensionsControl { ...this.props }
764 device={ this.getDeviceType() }
765 type={ 'padding' }
766 label={ __( 'Padding', 'generateblocks' ) }
767 attrTop={ 'iconPaddingTop' }
768 attrRight={ 'iconPaddingRight' }
769 attrBottom={ 'iconPaddingBottom' }
770 attrLeft={ 'iconPaddingLeft' }
771 attrUnit={ 'iconPaddingUnit' }
772 attrSyncUnits={ 'iconPaddingSyncUnits' }
773 defaults={ generateBlocksDefaults.button }
774 units={ [ 'px', 'em', '%' ] }
775 />
776 </Fragment>
777 }
778
779 <UnitPicker
780 label={ __( 'Icon Size', 'generateblocks' ) }
781 value={ iconSizeUnit }
782 units={ [ 'px', 'em' ] }
783 onClick={ ( value ) => {
784 setAttributes( {
785 iconSizeUnit: value,
786 } );
787 } }
788 />
789
790 <div className="components-base-control components-gblocks-typography-control__inputs">
791 <TextControl
792 type={ 'number' }
793 value={ iconSize || '' }
794 step={ 'em' === iconSizeUnit ? .1 : 1 }
795 onChange={ ( value ) => {
796 setAttributes( {
797 iconSize: value,
798 } );
799 } }
800 onBlur={ () => {
801 setAttributes( {
802 iconSize: parseFloat( iconSize ),
803 } );
804 } }
805 onClick={ ( e ) => {
806 // Make sure onBlur fires in Firefox.
807 e.currentTarget.focus();
808 } }
809 />
810
811 <Button
812 isSmall
813 isSecondary
814 className="components-gblocks-default-number"
815 onClick={ () => {
816 setAttributes( {
817 iconSize: generateBlocksDefaults.button.iconSize,
818 } );
819 } }
820 >
821 { __( 'Reset', 'generateblocks' ) }
822 </Button>
823 </div>
824 </Fragment>
825 ) }
826
827 { 'Tablet' === this.getDeviceType() && !! icon &&
828 <Fragment>
829 { ! removeText &&
830 <Fragment>
831 <DimensionsControl { ...this.props }
832 device={ this.getDeviceType() }
833 type={ 'padding' }
834 label={ __( 'Padding', 'generateblocks' ) }
835 attrTop={ 'iconPaddingTopTablet' }
836 attrRight={ 'iconPaddingRightTablet' }
837 attrBottom={ 'iconPaddingBottomTablet' }
838 attrLeft={ 'iconPaddingLeftTablet' }
839 attrUnit={ 'iconPaddingUnit' }
840 attrSyncUnits={ 'iconPaddingSyncUnits' }
841 defaults={ generateBlocksDefaults.button }
842 units={ [ 'px', 'em', '%' ] }
843 />
844 </Fragment>
845 }
846
847 <UnitPicker
848 label={ __( 'Icon Size', 'generateblocks' ) }
849 value={ iconSizeUnit }
850 units={ [ 'px', 'em' ] }
851 onClick={ ( value ) => {
852 setAttributes( {
853 iconSizeUnit: value,
854 } );
855 } }
856 />
857
858 <div className="components-base-control components-gblocks-typography-control__inputs">
859 <TextControl
860 type={ 'number' }
861 value={ iconSizeTablet || '' }
862 step={ 'em' === iconSizeUnit ? .1 : 1 }
863 placeholder="1"
864 onChange={ ( value ) => {
865 setAttributes( {
866 iconSizeTablet: value,
867 } );
868 } }
869 onBlur={ () => {
870 setAttributes( {
871 iconSizeTablet: parseFloat( iconSizeTablet ),
872 } );
873 } }
874 onClick={ ( e ) => {
875 // Make sure onBlur fires in Firefox.
876 e.currentTarget.focus();
877 } }
878 />
879
880 <Button
881 isSmall
882 isSecondary
883 className="components-gblocks-default-number"
884 onClick={ () => {
885 setAttributes( {
886 iconSizeTablet: generateBlocksDefaults.button.iconSizeTablet,
887 } );
888 } }
889 >
890 { __( 'Reset', 'generateblocks' ) }
891 </Button>
892 </div>
893 </Fragment>
894 }
895
896 { 'Mobile' === this.getDeviceType() && !! icon && (
897 <Fragment>
898 { ! removeText &&
899 <Fragment>
900 <DimensionsControl { ...this.props }
901 device={ this.getDeviceType() }
902 type={ 'padding' }
903 label={ __( 'Padding', 'generateblocks' ) }
904 attrTop={ 'iconPaddingTopMobile' }
905 attrRight={ 'iconPaddingRightMobile' }
906 attrBottom={ 'iconPaddingBottomMobile' }
907 attrLeft={ 'iconPaddingLeftMobile' }
908 attrUnit={ 'iconPaddingUnit' }
909 attrSyncUnits={ 'iconPaddingSyncUnits' }
910 defaults={ generateBlocksDefaults.button }
911 units={ [ 'px', 'em', '%' ] }
912 />
913 </Fragment>
914 }
915
916 <UnitPicker
917 label={ __( 'Icon Size', 'generateblocks' ) }
918 value={ iconSizeUnit }
919 units={ [ 'px', 'em' ] }
920 onClick={ ( value ) => {
921 setAttributes( {
922 iconSizeUnit: value,
923 } );
924 } }
925 />
926
927 <div className="components-base-control components-gblocks-typography-control__inputs">
928 <TextControl
929 type={ 'number' }
930 value={ iconSizeMobile || '' }
931 step={ 'em' === iconSizeUnit ? .1 : 1 }
932 placeholder="1"
933 onChange={ ( value ) => {
934 setAttributes( {
935 iconSizeMobile: value,
936 } );
937 } }
938 onBlur={ () => {
939 setAttributes( {
940 iconSizeMobile: parseFloat( iconSizeMobile ),
941 } );
942 } }
943 onClick={ ( e ) => {
944 // Make sure onBlur fires in Firefox.
945 e.currentTarget.focus();
946 } }
947 />
948
949 <Button
950 isSmall
951 isSecondary
952 className="components-gblocks-default-number"
953 onClick={ () => {
954 setAttributes( {
955 iconSizeMobile: generateBlocksDefaults.button.iconSizeMobile,
956 } );
957 } }
958 >
959 { __( 'Reset', 'generateblocks' ) }
960 </Button>
961 </div>
962 </Fragment>
963 ) }
964
965 { applyFilters( 'generateblocks.editor.controls', '', 'buttonIcon', this.props, this.state ) }
966 </PanelArea>
967
968 <PanelArea { ...this.props }
969 title={ __( 'Documentation', 'generateblocks' ) }
970 icon={ getIcon( 'documentation' ) }
971 initialOpen={ false }
972 className={ 'gblocks-panel-label' }
973 id={ 'buttonDocumentation' }
974 state={ this.state }
975 >
976 <p>{ __( 'Need help with this block?', 'generateblocks' ) }</p>
977 <a href="https://docs.generateblocks.com/collection/buttons/" target="_blank" rel="noreferrer noopener">{ __( 'Visit our documentation', 'generateblocks' ) }</a>
978
979 { applyFilters( 'generateblocks.editor.controls', '', 'buttonDocumentation', this.props, this.state ) }
980 </PanelArea>
981 </InspectorControls>
982
983 <InspectorAdvancedControls>
984 <TextControl
985 label={ __( 'HTML Anchor' ) }
986 help={ __( 'Anchors lets you link directly to a section on a page.', 'generateblocks' ) }
987 value={ anchor || '' }
988 onChange={ ( nextValue ) => {
989 nextValue = nextValue.replace( ANCHOR_REGEX, '-' );
990 setAttributes( {
991 anchor: nextValue,
992 } );
993 } } />
994
995 <TextControl
996 label={ __( 'ARIA Label', 'generateblocks' ) }
997 help={ __( 'Helpful to people using screen readers.', 'generateblocks' ) }
998 value={ ariaLabel }
999 onChange={ ( value ) => {
1000 setAttributes( {
1001 ariaLabel: value,
1002 } );
1003 } }
1004 />
1005 </InspectorAdvancedControls>
1006
1007 <MainCSS { ...this.props } />
1008
1009 { this.props.deviceType &&
1010 <Fragment>
1011 { 'Desktop' === this.props.deviceType &&
1012 <DesktopCSS { ...this.props } />
1013 }
1014
1015 { ( 'Tablet' === this.props.deviceType || 'Mobile' === this.props.deviceType ) &&
1016 <TabletCSS { ...this.props } />
1017 }
1018
1019 { 'Tablet' === this.props.deviceType &&
1020 <TabletOnlyCSS { ...this.props } />
1021 }
1022
1023 { 'Mobile' === this.props.deviceType &&
1024 <MobileCSS { ...this.props } />
1025 }
1026 </Fragment>
1027 }
1028
1029 { fontFamily && googleFont &&
1030 <link
1031 rel="stylesheet"
1032 href={ 'https://fonts.googleapis.com/css?family=' + fontFamily.replace( / /g, '+' ) + googleFontsAttr }
1033 />
1034 }
1035
1036 <Element
1037 tagName={ url ? 'a' : 'span' }
1038 htmlAttrs={ htmlAttributes }
1039 >
1040 { !! icon &&
1041 <Fragment>
1042 { 'left' === iconLocation &&
1043 <span
1044 className="gb-icon"
1045 dangerouslySetInnerHTML={ { __html: sanitizeSVG( icon ) } }
1046 />
1047 }
1048
1049 { ! removeText &&
1050 <span className={ 'gb-button-text' }>
1051 <RichText
1052 placeholder={ __( 'Add text…', 'generateblocks' ) }
1053 value={ text }
1054 onChange={ ( value ) => setAttributes( { text: value } ) }
1055 allowedFormats={ [ 'core/bold', 'core/italic', 'core/strikethrough' ] }
1056 isSelected={ isSelected }
1057 keepPlaceholderOnFocus
1058 />
1059 </span>
1060 }
1061
1062 { 'right' === iconLocation &&
1063 <span
1064 className="gb-icon"
1065 dangerouslySetInnerHTML={ { __html: sanitizeSVG( icon ) } }
1066 />
1067 }
1068 </Fragment>
1069 }
1070
1071 { ! icon && ! removeText &&
1072 <RichText
1073 placeholder={ __( 'Add text…', 'generateblocks' ) }
1074 value={ text }
1075 onChange={ ( value ) => setAttributes( { text: value } ) }
1076 allowedFormats={ [ 'core/bold', 'core/italic', 'core/strikethrough' ] }
1077 isSelected={ isSelected }
1078 keepPlaceholderOnFocus
1079 />
1080 }
1081 </Element>
1082 { isSelected &&
1083 <URLInput
1084 url={ url }
1085 target={ target }
1086 relNoFollow={ relNoFollow }
1087 relSponsored={ relSponsored }
1088 onChange={ ( data ) => {
1089 setAttributes( data );
1090
1091 if ( '' !== data.url ) {
1092 setAttributes( {
1093 hasUrl: true,
1094 } );
1095 } else {
1096 setAttributes( {
1097 hasUrl: false,
1098 } );
1099 }
1100 } }
1101 autoFocus={ false } // eslint-disable-line jsx-a11y/no-autofocus
1102 className="gblocks-component-url-input-float"
1103 />
1104 }
1105 </Fragment>
1106 );
1107 }
1108 }
1109
1110 export default compose( [
1111 withDispatch( ( dispatch ) => ( {
1112 setDeviceType( type ) {
1113 const {
1114 __experimentalSetPreviewDeviceType: setPreviewDeviceType,
1115 } = dispatch( 'core/edit-post' );
1116
1117 if ( ! setPreviewDeviceType ) {
1118 return;
1119 }
1120
1121 setPreviewDeviceType( type );
1122 },
1123 } ) ),
1124 withSelect( ( select ) => {
1125 const {
1126 __experimentalGetPreviewDeviceType: getPreviewDeviceType,
1127 } = select( 'core/edit-post' );
1128
1129 if ( ! getPreviewDeviceType ) {
1130 return {
1131 deviceType: null,
1132 };
1133 }
1134
1135 return {
1136 deviceType: getPreviewDeviceType(),
1137 };
1138 } ),
1139 ] )( GenerateBlockButton );
1140