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