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