PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.3.4
GenerateBlocks v1.3.4
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / src / blocks / headline / edit.js
generateblocks / src / blocks / headline 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 element-icons.js 5 years ago markformat.js 5 years ago save.js 5 years ago transforms.js 5 years ago
edit.js
1324 lines
1 /**
2 * Block: Headline
3 */
4
5 import classnames from 'classnames';
6 import ColorPicker from '../../components/color-picker';
7 import IconPicker from '../../components/icon-picker';
8 import UnitPicker from '../../components/unit-picker';
9 import TypographyControls from '../../components/typography';
10 import DimensionsControl from '../../components/dimensions/';
11 import ResponsiveTabs from '../../components/responsive-tabs';
12 import getIcon from '../../utils/get-icon';
13 import MainCSS from './css/main.js';
14 import DesktopCSS from './css/desktop.js';
15 import TabletCSS from './css/tablet.js';
16 import TabletOnlyCSS from './css/tablet-only.js';
17 import MobileCSS from './css/mobile.js';
18 import PanelArea from '../../components/panel-area/';
19 import Element from '../../components/element';
20 import './markformat';
21 import HeadingLevelIcon from './element-icons';
22
23 import {
24 __,
25 sprintf,
26 } from '@wordpress/i18n';
27
28 import {
29 TextControl,
30 ToolbarGroup,
31 SelectControl,
32 ToggleControl,
33 Button,
34 } from '@wordpress/components';
35
36 import {
37 Fragment,
38 Component,
39 } from '@wordpress/element';
40
41 import {
42 InspectorControls,
43 RichText,
44 BlockControls,
45 AlignmentToolbar,
46 InspectorAdvancedControls,
47 } from '@wordpress/block-editor';
48
49 import {
50 applyFilters,
51 } from '@wordpress/hooks';
52
53 import {
54 withSelect,
55 withDispatch,
56 } from '@wordpress/data';
57
58 import {
59 compose,
60 } from '@wordpress/compose';
61
62 /**
63 * Regular expression matching invalid anchor characters for replacement.
64 *
65 * @type {RegExp}
66 */
67 const ANCHOR_REGEX = /[\s#]/g;
68
69 const gbHeadlineIds = [];
70
71 class GenerateBlockHeadline extends Component {
72 constructor() {
73 super( ...arguments );
74
75 this.getFontSizePlaceholder = this.getFontSizePlaceholder.bind( this );
76 this.getDeviceType = this.getDeviceType.bind( this );
77 this.setDeviceType = this.setDeviceType.bind( this );
78
79 this.state = {
80 selectedDevice: 'Desktop',
81 fontSizePlaceholder: '17',
82 };
83 }
84
85 componentDidMount() {
86 const id = this.props.clientId.substr( 2, 9 ).replace( '-', '' );
87
88 // We don't want to ever regenerate unique IDs if they're a global style.
89 const isGlobalStyle = 'undefined' !== typeof this.props.attributes.isGlobalStyle && this.props.attributes.isGlobalStyle;
90
91 if ( ! this.props.attributes.uniqueId ) {
92 this.props.setAttributes( {
93 uniqueId: id,
94 } );
95
96 gbHeadlineIds.push( id );
97 } else if ( gbHeadlineIds.includes( this.props.attributes.uniqueId ) && ! isGlobalStyle ) {
98 this.props.setAttributes( {
99 uniqueId: id,
100 } );
101
102 gbHeadlineIds.push( id );
103 } else {
104 gbHeadlineIds.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
123 componentDidUpdate() {
124 const tempFontSizePlaceholder = this.getFontSizePlaceholder();
125
126 if ( tempFontSizePlaceholder !== this.state.fontSizePlaceholder ) {
127 this.setState( {
128 fontSizePlaceholder: tempFontSizePlaceholder,
129 } );
130 }
131 }
132
133 getFontSizePlaceholder() {
134 let placeholder = '25';
135
136 if ( 'em' === this.props.attributes.fontSizeUnit ) {
137 placeholder = '1';
138 } else if ( '%' === this.props.attributes.fontSizeUnit ) {
139 placeholder = '100';
140 } else {
141 const headlineId = document.querySelector( '.gb-headline-' + this.props.attributes.uniqueId );
142
143 if ( headlineId ) {
144 placeholder = parseFloat( window.getComputedStyle( headlineId ).fontSize );
145 }
146 }
147
148 return placeholder;
149 }
150
151 getDeviceType() {
152 let deviceType = this.props.deviceType ? this.props.deviceType : this.state.selectedDevice;
153
154 if ( ! generateBlocksInfo.syncResponsivePreviews ) {
155 deviceType = this.state.selectedDevice;
156 }
157
158 return deviceType;
159 }
160
161 setDeviceType( deviceType ) {
162 if ( generateBlocksInfo.syncResponsivePreviews && this.props.deviceType ) {
163 this.props.setDeviceType( deviceType );
164 this.setState( { selectedDevice: deviceType } );
165 } else {
166 this.setState( { selectedDevice: deviceType } );
167 }
168 }
169
170 render() {
171 const {
172 attributes,
173 setAttributes,
174 } = this.props;
175
176 const {
177 fontSizePlaceholder,
178 } = this.state;
179
180 const {
181 uniqueId,
182 anchor,
183 className,
184 content,
185 element,
186 alignment,
187 alignmentTablet,
188 alignmentMobile,
189 backgroundColor,
190 backgroundColorOpacity,
191 textColor,
192 linkColor,
193 linkColorHover,
194 borderColor,
195 borderColorOpacity,
196 highlightTextColor,
197 fontFamily,
198 googleFont,
199 googleFontVariants,
200 marginTop,
201 marginRight,
202 marginBottom,
203 marginLeft,
204 icon,
205 hasIcon,
206 iconColor,
207 iconColorOpacity,
208 iconLocation,
209 iconLocationTablet,
210 iconLocationMobile,
211 iconVerticalAlignment,
212 iconVerticalAlignmentTablet,
213 iconVerticalAlignmentMobile,
214 iconSize,
215 iconSizeTablet,
216 iconSizeMobile,
217 iconSizeUnit,
218 inlineWidth,
219 inlineWidthTablet,
220 inlineWidthMobile,
221 removeText,
222 ariaLabel,
223 } = attributes;
224
225 let googleFontsAttr = '';
226
227 if ( googleFontVariants ) {
228 googleFontsAttr = ':' + googleFontVariants;
229 }
230
231 let iconSizePlaceholderMobile = '';
232
233 if ( iconSizeTablet || 0 === iconSizeTablet ) {
234 iconSizePlaceholderMobile = iconSizeTablet;
235 } else if ( iconSize || 0 === iconSize ) {
236 iconSizePlaceholderMobile = iconSize;
237 } else {
238 iconSizePlaceholderMobile = '';
239 }
240
241 let htmlAttributes = {
242 className: classnames( {
243 'gb-headline': true,
244 [ `gb-headline-${ uniqueId }` ]: true,
245 'gb-headline-text': ! hasIcon,
246 [ className ]: undefined !== className,
247 } ),
248 id: anchor ? anchor : null,
249 };
250
251 htmlAttributes = applyFilters( 'generateblocks.frontend.htmlAttributes', htmlAttributes, 'generateblocks/headline', attributes );
252
253 return (
254 <Fragment>
255 <BlockControls>
256 <ToolbarGroup
257 isCollapsed={ true }
258 icon={ <HeadingLevelIcon level={ element } /> }
259 label={ __( 'Change Headline Element', 'generateblocks' ) }
260 controls={ [
261 {
262 isActive: 'h1' === element,
263 icon: (
264 <HeadingLevelIcon
265 level={ 'h1' }
266 />
267 ),
268 title: sprintf(
269 // translators: %s: heading level e.g: "1", "2", "3"
270 __( 'Heading %s', 'generateblocks' ),
271 '1'
272 ),
273 onClick: () => {
274 setAttributes( { element: 'h1' } );
275 },
276 },
277 {
278 isActive: 'h2' === element,
279 icon: (
280 <HeadingLevelIcon
281 level={ 'h2' }
282 />
283 ),
284 title: sprintf(
285 // translators: %s: heading level e.g: "1", "2", "3"
286 __( 'Heading %s', 'generateblocks' ),
287 '2'
288 ),
289 onClick: () => {
290 setAttributes( { element: 'h2' } );
291 },
292 },
293 {
294 isActive: 'h3' === element,
295 icon: (
296 <HeadingLevelIcon
297 level={ 'h3' }
298 />
299 ),
300 title: sprintf(
301 // translators: %s: heading level e.g: "1", "2", "3"
302 __( 'Heading %s', 'generateblocks' ),
303 '3'
304 ),
305 onClick: () => {
306 setAttributes( { element: 'h3' } );
307 },
308 },
309 {
310 isActive: 'h4' === element,
311 icon: (
312 <HeadingLevelIcon
313 level={ 'h4' }
314 />
315 ),
316 title: sprintf(
317 // translators: %s: heading level e.g: "1", "2", "3"
318 __( 'Heading %s', 'generateblocks' ),
319 '4'
320 ),
321 onClick: () => {
322 setAttributes( { element: 'h4' } );
323 },
324 },
325 {
326 isActive: 'h5' === element,
327 icon: (
328 <HeadingLevelIcon
329 level={ 'h5' }
330 />
331 ),
332 title: sprintf(
333 // translators: %s: heading level e.g: "1", "2", "3"
334 __( 'Heading %s', 'generateblocks' ),
335 '5'
336 ),
337 onClick: () => {
338 setAttributes( { element: 'h5' } );
339 },
340 },
341 {
342 isActive: 'h6' === element,
343 icon: (
344 <HeadingLevelIcon
345 level={ 'h6' }
346 />
347 ),
348 title: sprintf(
349 // translators: %s: heading level e.g: "1", "2", "3"
350 __( 'Heading %s', 'generateblocks' ),
351 '6'
352 ),
353 onClick: () => {
354 setAttributes( { element: 'h6' } );
355 },
356 },
357 {
358 isActive: 'p' === element,
359 icon: (
360 <HeadingLevelIcon
361 level={ 'p' }
362 />
363 ),
364 title: __( 'Paragraph', 'generateblocks' ),
365 onClick: () => {
366 setAttributes( { element: 'p' } );
367 },
368 },
369 {
370 isActive: 'div' === element,
371 icon: (
372 <HeadingLevelIcon
373 level={ 'div' }
374 />
375 ),
376 title: __( 'Div', 'generateblocks' ),
377 onClick: () => {
378 setAttributes( { element: 'div' } );
379 },
380 },
381 ] }
382 />
383
384 { 'Desktop' === this.getDeviceType() && ! inlineWidth &&
385 <AlignmentToolbar
386 value={ alignment }
387 onChange={ ( value ) => {
388 setAttributes( { alignment: value } );
389 } }
390 />
391 }
392
393 { 'Tablet' === this.getDeviceType() && ! inlineWidthTablet &&
394 <AlignmentToolbar
395 value={ alignmentTablet }
396 onChange={ ( value ) => {
397 setAttributes( { alignmentTablet: value } );
398 } }
399 />
400 }
401
402 { 'Mobile' === this.getDeviceType() && ! inlineWidthMobile &&
403 <AlignmentToolbar
404 value={ alignmentMobile }
405 onChange={ ( value ) => {
406 setAttributes( { alignmentMobile: value } );
407 } }
408 />
409 }
410 </BlockControls>
411
412 <InspectorControls>
413 <ResponsiveTabs { ...this.props }
414 selectedDevice={ this.getDeviceType() }
415 onClick={ ( device ) => {
416 this.setDeviceType( device );
417 } }
418 />
419
420 <PanelArea { ...this.props }
421 id={ 'headlineElement' }
422 state={ this.state }
423 showPanel={ 'Desktop' === this.getDeviceType() ? true : false }
424 >
425 <SelectControl
426 label={ __( 'Tag Name', 'generateblocks' ) }
427 value={ element }
428 options={ [
429 { label: 'h1', value: 'h1' },
430 { label: 'h2', value: 'h2' },
431 { label: 'h3', value: 'h3' },
432 { label: 'h4', value: 'h4' },
433 { label: 'h5', value: 'h5' },
434 { label: 'h6', value: 'h6' },
435 { label: 'paragraph', value: 'p' },
436 { label: 'div', value: 'div' },
437 ] }
438 onChange={ ( value ) => {
439 setAttributes( {
440 element: value,
441 } );
442
443 if ( ! marginTop && ! marginRight && ! marginBottom && ! marginLeft ) {
444 if ( 'p' === value ) {
445 setAttributes( { marginUnit: 'em' } );
446 } else {
447 setAttributes( { marginUnit: generateBlocksDefaults.headline.marginUnit } );
448 }
449 }
450 } }
451 />
452
453 { applyFilters( 'generateblocks.editor.controls', '', 'headlineElement', this.props, this.state ) }
454 </PanelArea>
455
456 <PanelArea { ...this.props }
457 title={ __( 'Typography', 'generateblocks' ) }
458 initialOpen={ false }
459 icon={ getIcon( 'typography' ) }
460 className={ 'gblocks-panel-label' }
461 id={ 'headlineTypography' }
462 state={ this.state }
463 showPanel={ ! removeText || false }
464 >
465 { 'Desktop' === this.getDeviceType() && (
466 <Fragment>
467 <TypographyControls { ...this.props }
468 showFontFamily={ true }
469 showFontWeight={ true }
470 showTextTransform={ true }
471 showFontSize={ true }
472 showLineHeight={ true }
473 showLetterSpacing={ true }
474 fontSizePlaceholder={ fontSizePlaceholder }
475 defaultFontSize={ generateBlocksDefaults.headline.fontSize }
476 defaultFontSizeUnit={ generateBlocksDefaults.headline.fontSizeUnit }
477 defaultLineHeight={ generateBlocksDefaults.headline.lineHeight }
478 defaultLineHeightUnit={ generateBlocksDefaults.headline.lineHeightUnit }
479 defaultLetterSpacing={ generateBlocksDefaults.headline.letterSpacing }
480 />
481 </Fragment>
482 ) }
483
484 { 'Tablet' === this.getDeviceType() && (
485 <Fragment>
486 <TypographyControls { ...this.props }
487 device={ 'Tablet' }
488 showFontSize={ true }
489 showLineHeight={ true }
490 showLetterSpacing={ true }
491 defaultFontSize={ generateBlocksDefaults.headline.fontSizeTablet }
492 defaultFontSizeUnit={ generateBlocksDefaults.headline.fontSizeUnit }
493 defaultLineHeight={ generateBlocksDefaults.headline.lineHeightTablet }
494 defaultLineHeightUnit={ generateBlocksDefaults.headline.lineHeightUnit }
495 defaultLetterSpacing={ generateBlocksDefaults.headline.letterSpacingTablet }
496 />
497 </Fragment>
498 ) }
499
500 { 'Mobile' === this.getDeviceType() && (
501 <Fragment>
502 <TypographyControls { ...this.props }
503 device={ 'Mobile' }
504 showFontSize={ true }
505 showLineHeight={ true }
506 showLetterSpacing={ true }
507 defaultFontSize={ generateBlocksDefaults.headline.fontSizeMobile }
508 defaultFontSizeUnit={ generateBlocksDefaults.headline.fontSizeUnit }
509 defaultLineHeight={ generateBlocksDefaults.headline.lineHeightMobile }
510 defaultLineHeightUnit={ generateBlocksDefaults.headline.lineHeightUnit }
511 defaultLetterSpacing={ generateBlocksDefaults.headline.letterSpacingMobile }
512 />
513 </Fragment>
514 ) }
515
516 { applyFilters( 'generateblocks.editor.controls', '', 'headlineTypography', this.props, this.state ) }
517 </PanelArea>
518
519 <PanelArea { ...this.props }
520 title={ __( 'Spacing', 'generateblocks' ) }
521 initialOpen={ false }
522 icon={ getIcon( 'spacing' ) }
523 className={ 'gblocks-panel-label' }
524 id={ 'headlineSpacing' }
525 state={ this.state }
526 >
527 { 'Desktop' === this.getDeviceType() && (
528 <Fragment>
529 <ToggleControl
530 label={ __( 'Inline Width', 'generateblocks' ) }
531 checked={ !! inlineWidth }
532 onChange={ ( value ) => {
533 setAttributes( {
534 inlineWidth: value,
535 } );
536 } }
537 />
538
539 <DimensionsControl { ...this.props }
540 device={ this.getDeviceType() }
541 type={ 'padding' }
542 label={ __( 'Padding', 'generateblocks' ) }
543 attrTop={ 'paddingTop' }
544 attrRight={ 'paddingRight' }
545 attrBottom={ 'paddingBottom' }
546 attrLeft={ 'paddingLeft' }
547 attrUnit={ 'paddingUnit' }
548 attrSyncUnits={ 'paddingSyncUnits' }
549 defaults={ generateBlocksDefaults.headline }
550 units={ [ 'px', 'em', '%' ] }
551 />
552
553 <DimensionsControl { ...this.props }
554 device={ this.getDeviceType() }
555 type={ 'margin' }
556 block={ 'headline' }
557 label={ __( 'Margin', 'generateblocks' ) }
558 attrTop={ 'marginTop' }
559 attrRight={ 'marginRight' }
560 attrBottom={ 'marginBottom' }
561 attrLeft={ 'marginLeft' }
562 attrUnit={ 'marginUnit' }
563 attrSyncUnits={ 'marginSyncUnits' }
564 defaults={ generateBlocksDefaults.headline }
565 units={ [ 'px', 'em', '%' ] }
566 />
567
568 <DimensionsControl { ...this.props }
569 device={ this.getDeviceType() }
570 type={ 'padding' }
571 label={ __( 'Border Size', 'generateblocks' ) }
572 attrTop={ 'borderSizeTop' }
573 attrRight={ 'borderSizeRight' }
574 attrBottom={ 'borderSizeBottom' }
575 attrLeft={ 'borderSizeLeft' }
576 attrSyncUnits={ 'borderSizeSyncUnits' }
577 defaults={ generateBlocksDefaults.headline }
578 units={ [ 'px' ] }
579 />
580
581 <DimensionsControl { ...this.props }
582 device={ this.getDeviceType() }
583 type={ 'padding' }
584 label={ __( 'Border Radius', 'generateblocks' ) }
585 attrTop={ 'borderRadiusTopLeft' }
586 attrRight={ 'borderRadiusTopRight' }
587 attrBottom={ 'borderRadiusBottomRight' }
588 attrLeft={ 'borderRadiusBottomLeft' }
589 attrUnit={ 'borderRadiusUnit' }
590 attrSyncUnits={ 'borderRadiusSyncUnits' }
591 labelTop={ __( 'T-Left', 'generateblocks' ) }
592 labelRight={ __( 'T-Right', 'generateblocks' ) }
593 labelBottom={ __( 'B-Right', 'generateblocks' ) }
594 labelLeft={ __( 'B-Left', 'generateblocks' ) }
595 defaults={ generateBlocksDefaults.headline }
596 units={ [ 'px', 'em', '%' ] }
597 />
598 </Fragment>
599 ) }
600
601 { 'Tablet' === this.getDeviceType() && (
602 <Fragment>
603 <ToggleControl
604 label={ __( 'Inline Width', 'generateblocks' ) }
605 checked={ !! inlineWidthTablet }
606 onChange={ ( value ) => {
607 setAttributes( {
608 inlineWidthTablet: value,
609 } );
610 } }
611 />
612
613 <DimensionsControl { ...this.props }
614 device={ this.getDeviceType() }
615 type={ 'padding' }
616 label={ __( 'Padding', 'generateblocks' ) }
617 attrTop={ 'paddingTopTablet' }
618 attrRight={ 'paddingRightTablet' }
619 attrBottom={ 'paddingBottomTablet' }
620 attrLeft={ 'paddingLeftTablet' }
621 attrUnit={ 'paddingUnit' }
622 attrSyncUnits={ 'paddingSyncUnits' }
623 defaults={ generateBlocksDefaults.headline }
624 units={ [ 'px', 'em', '%' ] }
625 />
626
627 <DimensionsControl { ...this.props }
628 device={ this.getDeviceType() }
629 type={ 'margin' }
630 block={ 'headline' }
631 label={ __( 'Margin', 'generateblocks' ) }
632 attrTop={ 'marginTopTablet' }
633 attrRight={ 'marginRightTablet' }
634 attrBottom={ 'marginBottomTablet' }
635 attrLeft={ 'marginLeftTablet' }
636 attrUnit={ 'marginUnit' }
637 attrSyncUnits={ 'marginSyncUnits' }
638 defaults={ generateBlocksDefaults.headline }
639 units={ [ 'px', 'em', '%' ] }
640 />
641
642 <DimensionsControl { ...this.props }
643 device={ this.getDeviceType() }
644 type={ 'padding' }
645 label={ __( 'Border Size', 'generateblocks' ) }
646 attrTop={ 'borderSizeTopTablet' }
647 attrRight={ 'borderSizeRightTablet' }
648 attrBottom={ 'borderSizeBottomTablet' }
649 attrLeft={ 'borderSizeLeftTablet' }
650 attrSyncUnits={ 'borderSizeSyncUnits' }
651 defaults={ generateBlocksDefaults.headline }
652 units={ [ 'px' ] }
653 />
654
655 <DimensionsControl { ...this.props }
656 device={ this.getDeviceType() }
657 type={ 'padding' }
658 label={ __( 'Border Radius', 'generateblocks' ) }
659 attrTop={ 'borderRadiusTopLeftTablet' }
660 attrRight={ 'borderRadiusTopRightTablet' }
661 attrBottom={ 'borderRadiusBottomRightTablet' }
662 attrLeft={ 'borderRadiusBottomLeftTablet' }
663 attrUnit={ 'borderRadiusUnit' }
664 attrSyncUnits={ 'borderRadiusSyncUnits' }
665 labelTop={ __( 'T-Left', 'generateblocks' ) }
666 labelRight={ __( 'T-Right', 'generateblocks' ) }
667 labelBottom={ __( 'B-Right', 'generateblocks' ) }
668 labelLeft={ __( 'B-Left', 'generateblocks' ) }
669 defaults={ generateBlocksDefaults.headline }
670 units={ [ 'px', 'em', '%' ] }
671 />
672 </Fragment>
673 ) }
674
675 { 'Mobile' === this.getDeviceType() && (
676 <Fragment>
677 <ToggleControl
678 label={ __( 'Inline Width', 'generateblocks' ) }
679 checked={ !! inlineWidthMobile }
680 onChange={ ( value ) => {
681 setAttributes( {
682 inlineWidthMobile: value,
683 } );
684 } }
685 />
686
687 <DimensionsControl { ...this.props }
688 device={ this.getDeviceType() }
689 type={ 'padding' }
690 label={ __( 'Padding', 'generateblocks' ) }
691 attrTop={ 'paddingTopMobile' }
692 attrRight={ 'paddingRightMobile' }
693 attrBottom={ 'paddingBottomMobile' }
694 attrLeft={ 'paddingLeftMobile' }
695 attrUnit={ 'paddingUnit' }
696 attrSyncUnits={ 'paddingSyncUnits' }
697 defaults={ generateBlocksDefaults.headline }
698 units={ [ 'px', 'em', '%' ] }
699 />
700
701 <DimensionsControl { ...this.props }
702 device={ this.getDeviceType() }
703 type={ 'margin' }
704 block={ 'headline' }
705 label={ __( 'Margin', 'generateblocks' ) }
706 attrTop={ 'marginTopMobile' }
707 attrRight={ 'marginRightMobile' }
708 attrBottom={ 'marginBottomMobile' }
709 attrLeft={ 'marginLeftMobile' }
710 attrUnit={ 'marginUnit' }
711 attrSyncUnits={ 'marginSyncUnits' }
712 defaults={ generateBlocksDefaults.headline }
713 units={ [ 'px', 'em', '%' ] }
714 />
715
716 <DimensionsControl { ...this.props }
717 device={ this.getDeviceType() }
718 type={ 'padding' }
719 label={ __( 'Border Size', 'generateblocks' ) }
720 attrTop={ 'borderSizeTopMobile' }
721 attrRight={ 'borderSizeRightMobile' }
722 attrBottom={ 'borderSizeBottomMobile' }
723 attrLeft={ 'borderSizeLeftMobile' }
724 attrSyncUnits={ 'borderSizeSyncUnits' }
725 defaults={ generateBlocksDefaults.headline }
726 units={ [ 'px' ] }
727 />
728
729 <DimensionsControl { ...this.props }
730 device={ this.getDeviceType() }
731 type={ 'padding' }
732 label={ __( 'Border Radius', 'generateblocks' ) }
733 attrTop={ 'borderRadiusTopLeftMobile' }
734 attrRight={ 'borderRadiusTopRightMobile' }
735 attrBottom={ 'borderRadiusBottomRightMobile' }
736 attrLeft={ 'borderRadiusBottomLeftMobile' }
737 attrUnit={ 'borderRadiusUnit' }
738 attrSyncUnits={ 'borderRadiusSyncUnits' }
739 labelTop={ __( 'T-Left', 'generateblocks' ) }
740 labelRight={ __( 'T-Right', 'generateblocks' ) }
741 labelBottom={ __( 'B-Right', 'generateblocks' ) }
742 labelLeft={ __( 'B-Left', 'generateblocks' ) }
743 defaults={ generateBlocksDefaults.headline }
744 units={ [ 'px', 'em', '%' ] }
745 />
746 </Fragment>
747 ) }
748
749 { applyFilters( 'generateblocks.editor.controls', '', 'headlineSpacing', this.props, this.state ) }
750 </PanelArea>
751
752 <PanelArea { ...this.props }
753 title={ __( 'Colors', 'generateblocks' ) }
754 initialOpen={ false }
755 icon={ getIcon( 'colors' ) }
756 className={ 'gblocks-panel-label' }
757 id={ 'headlineColors' }
758 state={ this.state }
759 showPanel={ 'Desktop' === this.getDeviceType() || false }
760 >
761 <ColorPicker
762 label={ __( 'Background Color', 'generateblocks' ) }
763 value={ backgroundColor }
764 alpha={ true }
765 valueOpacity={ backgroundColorOpacity }
766 attrOpacity={ 'backgroundColorOpacity' }
767 onChange={ ( value ) =>
768 setAttributes( {
769 backgroundColor: value,
770 } )
771 }
772 onOpacityChange={ ( value ) =>
773 setAttributes( {
774 backgroundColorOpacity: value,
775 } )
776 }
777 />
778
779 <ColorPicker
780 label={ __( 'Text Color', 'generateblocks' ) }
781 value={ textColor }
782 alpha={ false }
783 onChange={ ( value ) =>
784 setAttributes( {
785 textColor: value,
786 } )
787 }
788 />
789
790 <ColorPicker
791 label={ __( 'Link Color', 'generateblocks' ) }
792 value={ linkColor }
793 alpha={ false }
794 onChange={ ( value ) =>
795 setAttributes( {
796 linkColor: value,
797 } )
798 }
799 />
800
801 <ColorPicker
802 label={ __( 'Link Color Hover', 'generateblocks' ) }
803 value={ linkColorHover }
804 alpha={ false }
805 onChange={ ( value ) =>
806 setAttributes( {
807 linkColorHover: value,
808 } )
809 }
810 />
811
812 <ColorPicker
813 label={ __( 'Border Color', 'generateblocks' ) }
814 value={ borderColor }
815 alpha={ true }
816 valueOpacity={ borderColorOpacity }
817 attrOpacity={ 'borderColorOpacity' }
818 onChange={ ( value ) =>
819 setAttributes( {
820 borderColor: value,
821 } )
822 }
823 onOpacityChange={ ( value ) =>
824 setAttributes( {
825 borderColorOpacity: value,
826 } )
827 }
828 />
829
830 { icon &&
831 <ColorPicker
832 label={ __( 'Icon Color', 'generateblocks' ) }
833 value={ iconColor }
834 alpha={ true }
835 valueOpacity={ iconColorOpacity }
836 attrOpacity={ 'iconColorOpacity' }
837 onChange={ ( value ) =>
838 setAttributes( {
839 iconColor: value,
840 } )
841 }
842 onOpacityChange={ ( value ) =>
843 setAttributes( {
844 iconColorOpacity: value,
845 } )
846 }
847 />
848 }
849
850 <ColorPicker
851 label={ __( 'Highlight Text', 'generateblocks' ) }
852 value={ highlightTextColor }
853 alpha={ false }
854 onChange={ ( value ) =>
855 setAttributes( {
856 highlightTextColor: value,
857 } )
858 }
859 />
860 </PanelArea>
861
862 <PanelArea { ...this.props }
863 title={ __( 'Icon', 'generateblocks' ) }
864 initialOpen={ false }
865 icon={ getIcon( 'icons' ) }
866 className={ 'gblocks-panel-label' }
867 id={ 'headlineIcon' }
868 state={ this.state }
869 showPanel={ 'Desktop' === this.getDeviceType() || !! icon ? true : false }
870 >
871
872 { 'Desktop' === this.getDeviceType() &&
873 <IconPicker { ...this.props }
874 attrIcon={ 'icon' }
875 attrRemoveText={ 'removeText' }
876 attrAriaLabel={ 'ariaLabel' }
877 />
878 }
879
880 { 'Desktop' === this.getDeviceType() && !! icon &&
881 <Fragment>
882 { ! removeText &&
883 <Fragment>
884 <SelectControl
885 label={ __( 'Icon Location', 'generateblocks' ) }
886 value={ iconLocation }
887 options={ [
888 { label: __( 'Inline', 'generateblocks' ), value: 'inline' },
889 { label: __( 'Above', 'generateblocks' ), value: 'above' },
890 ] }
891 onChange={ ( value ) => {
892 setAttributes( {
893 iconLocation: value,
894 iconPaddingRight: 'inline' === value ? '0.5' : '',
895 iconPaddingBottom: 'above' === value ? '0.5' : '',
896 } );
897 } }
898 />
899
900 { 'inline' === iconLocation &&
901 <SelectControl
902 label={ __( 'Icon Alignment', 'generateblocks' ) }
903 value={ iconVerticalAlignment }
904 options={ [
905 { label: __( 'Top', 'generateblocks' ), value: 'top' },
906 { label: __( 'Center', 'generateblocks' ), value: 'center' },
907 { label: __( 'Bottom', 'generateblocks' ), value: 'bottom' },
908 ] }
909 onChange={ ( value ) => {
910 setAttributes( {
911 iconVerticalAlignment: value,
912 } );
913 } }
914 />
915 }
916
917 <DimensionsControl { ...this.props }
918 device={ this.getDeviceType() }
919 type={ 'padding' }
920 label={ __( 'Padding', 'generateblocks' ) }
921 attrTop={ 'iconPaddingTop' }
922 attrRight={ 'iconPaddingRight' }
923 attrBottom={ 'iconPaddingBottom' }
924 attrLeft={ 'iconPaddingLeft' }
925 attrUnit={ 'iconPaddingUnit' }
926 attrSyncUnits={ 'iconPaddingSyncUnits' }
927 defaults={ generateBlocksDefaults.headline }
928 units={ [ 'px', 'em', '%' ] }
929 />
930 </Fragment>
931 }
932
933 <UnitPicker
934 label={ __( 'Icon Size', 'generateblocks' ) }
935 value={ iconSizeUnit }
936 units={ [ 'px', 'em' ] }
937 onClick={ ( value ) => {
938 setAttributes( {
939 iconSizeUnit: value,
940 } );
941 } }
942 />
943
944 <div className="components-base-control components-gblocks-typography-control__inputs">
945 <TextControl
946 type={ 'number' }
947 value={ iconSize || 0 === iconSize ? iconSize : '' }
948 step={ 'em' === iconSizeUnit ? .1 : 1 }
949 onChange={ ( value ) => {
950 setAttributes( {
951 iconSize: value,
952 } );
953 } }
954 onBlur={ () => {
955 setAttributes( {
956 iconSize: parseFloat( iconSize ),
957 } );
958 } }
959 onClick={ ( e ) => {
960 // Make sure onBlur fires in Firefox.
961 e.currentTarget.focus();
962 } }
963 />
964
965 <Button
966 isSmall
967 isSecondary
968 className="components-gblocks-default-number"
969 onClick={ () => {
970 setAttributes( {
971 iconSize: generateBlocksDefaults.headline.iconSize,
972 } );
973 } }
974 >
975 { __( 'Reset', 'generateblocks' ) }
976 </Button>
977 </div>
978 </Fragment>
979 }
980
981 { 'Tablet' === this.getDeviceType() && !! icon &&
982 <Fragment>
983 { ! removeText &&
984 <Fragment>
985 <SelectControl
986 label={ __( 'Icon Location', 'generateblocks' ) }
987 value={ iconLocationTablet }
988 options={ [
989 { label: __( 'Inherit', 'generateblocks' ), value: '' },
990 { label: __( 'Inline', 'generateblocks' ), value: 'inline' },
991 { label: __( 'Above', 'generateblocks' ), value: 'above' },
992 ] }
993 onChange={ ( value ) => {
994 setAttributes( {
995 iconLocationTablet: value,
996 iconPaddingRightTablet: 'inline' === value ? '0.5' : '',
997 iconPaddingBottomTablet: 'above' === value ? '0.5' : '',
998 } );
999 } }
1000 />
1001
1002 { 'inline' === iconLocationTablet &&
1003 <SelectControl
1004 label={ __( 'Icon Alignment', 'generateblocks' ) }
1005 value={ iconVerticalAlignmentTablet }
1006 options={ [
1007 { label: __( 'Inherit', 'generateblocks' ), value: '' },
1008 { label: __( 'Top', 'generateblocks' ), value: 'top' },
1009 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1010 { label: __( 'Bottom', 'generateblocks' ), value: 'bottom' },
1011 ] }
1012 onChange={ ( value ) => {
1013 setAttributes( {
1014 iconVerticalAlignmentTablet: value,
1015 } );
1016 } }
1017 />
1018 }
1019
1020 <DimensionsControl { ...this.props }
1021 device={ this.getDeviceType() }
1022 type={ 'padding' }
1023 label={ __( 'Padding', 'generateblocks' ) }
1024 attrTop={ 'iconPaddingTopTablet' }
1025 attrRight={ 'iconPaddingRightTablet' }
1026 attrBottom={ 'iconPaddingBottomTablet' }
1027 attrLeft={ 'iconPaddingLeftTablet' }
1028 attrUnit={ 'iconPaddingUnit' }
1029 attrSyncUnits={ 'iconPaddingSyncUnits' }
1030 defaults={ generateBlocksDefaults.headline }
1031 units={ [ 'px', 'em', '%' ] }
1032 />
1033 </Fragment>
1034 }
1035
1036 <UnitPicker
1037 label={ __( 'Icon Size', 'generateblocks' ) }
1038 value={ iconSizeUnit }
1039 units={ [ 'px', 'em' ] }
1040 onClick={ ( value ) => {
1041 setAttributes( {
1042 iconSizeUnit: value,
1043 } );
1044 } }
1045 />
1046
1047 <div className="components-base-control components-gblocks-typography-control__inputs">
1048 <TextControl
1049 type={ 'number' }
1050 value={ iconSizeTablet || 0 === iconSizeTablet ? iconSizeTablet : '' }
1051 step={ 'em' === iconSizeUnit ? .1 : 1 }
1052 placeholder={ iconSize || 0 === iconSize ? iconSize : '' }
1053 onChange={ ( value ) => {
1054 setAttributes( {
1055 iconSizeTablet: value,
1056 } );
1057 } }
1058 onBlur={ () => {
1059 setAttributes( {
1060 iconSizeTablet: parseFloat( iconSizeTablet ),
1061 } );
1062 } }
1063 onClick={ ( e ) => {
1064 // Make sure onBlur fires in Firefox.
1065 e.currentTarget.focus();
1066 } }
1067 />
1068
1069 <Button
1070 isSmall
1071 isSecondary
1072 className="components-gblocks-default-number"
1073 onClick={ () => {
1074 setAttributes( {
1075 iconSizeTablet: generateBlocksDefaults.headline.iconSizeTablet,
1076 } );
1077 } }
1078 >
1079 { __( 'Reset', 'generateblocks' ) }
1080 </Button>
1081 </div>
1082 </Fragment>
1083 }
1084
1085 { 'Mobile' === this.getDeviceType() && !! icon &&
1086 <Fragment>
1087 { ! removeText &&
1088 <Fragment>
1089 <SelectControl
1090 label={ __( 'Icon Location', 'generateblocks' ) }
1091 value={ iconLocationMobile }
1092 options={ [
1093 { label: __( 'Inherit', 'generateblocks' ), value: '' },
1094 { label: __( 'Inline', 'generateblocks' ), value: 'inline' },
1095 { label: __( 'Above', 'generateblocks' ), value: 'above' },
1096 ] }
1097 onChange={ ( value ) => {
1098 setAttributes( {
1099 iconLocationMobile: value,
1100 iconPaddingRightMobile: 'inline' === value ? '0.5' : '',
1101 iconPaddingBottomMobile: 'above' === value ? '0.5' : '',
1102 } );
1103 } }
1104 />
1105
1106 { 'inline' === iconLocationMobile &&
1107 <SelectControl
1108 label={ __( 'Icon Alignment', 'generateblocks' ) }
1109 value={ iconVerticalAlignmentMobile }
1110 options={ [
1111 { label: __( 'Inherit', 'generateblocks' ), value: '' },
1112 { label: __( 'Top', 'generateblocks' ), value: 'top' },
1113 { label: __( 'Center', 'generateblocks' ), value: 'center' },
1114 { label: __( 'Bottom', 'generateblocks' ), value: 'bottom' },
1115 ] }
1116 onChange={ ( value ) => {
1117 setAttributes( {
1118 iconVerticalAlignmentMobile: value,
1119 } );
1120 } }
1121 />
1122 }
1123
1124 <DimensionsControl { ...this.props }
1125 device={ this.getDeviceType() }
1126 type={ 'padding' }
1127 label={ __( 'Padding', 'generateblocks' ) }
1128 attrTop={ 'iconPaddingTopMobile' }
1129 attrRight={ 'iconPaddingRightMobile' }
1130 attrBottom={ 'iconPaddingBottomMobile' }
1131 attrLeft={ 'iconPaddingLeftMobile' }
1132 attrUnit={ 'iconPaddingUnit' }
1133 attrSyncUnits={ 'iconPaddingSyncUnits' }
1134 defaults={ generateBlocksDefaults.headline }
1135 units={ [ 'px', 'em', '%' ] }
1136 />
1137 </Fragment>
1138 }
1139
1140 <UnitPicker
1141 label={ __( 'Icon Size', 'generateblocks' ) }
1142 value={ iconSizeUnit }
1143 units={ [ 'px', 'em' ] }
1144 onClick={ ( value ) => {
1145 setAttributes( {
1146 iconSizeUnit: value,
1147 } );
1148 } }
1149 />
1150
1151 <div className="components-base-control components-gblocks-typography-control__inputs">
1152 <TextControl
1153 type={ 'number' }
1154 value={ iconSizeMobile || 0 === iconSizeMobile ? iconSizeMobile : '' }
1155 step={ 'em' === iconSizeUnit ? .1 : 1 }
1156 placeholder={ iconSizePlaceholderMobile }
1157 onChange={ ( value ) => {
1158 setAttributes( {
1159 iconSizeMobile: value,
1160 } );
1161 } }
1162 onBlur={ () => {
1163 setAttributes( {
1164 iconSizeMobile: parseFloat( iconSizeMobile ),
1165 } );
1166 } }
1167 onClick={ ( e ) => {
1168 // Make sure onBlur fires in Firefox.
1169 e.currentTarget.focus();
1170 } }
1171 />
1172
1173 <Button
1174 isSmall
1175 isSecondary
1176 className="components-gblocks-default-number"
1177 onClick={ () => {
1178 setAttributes( {
1179 iconSizeMobile: generateBlocksDefaults.headline.iconSizeMobile,
1180 } );
1181 } }
1182 >
1183 { __( 'Reset', 'generateblocks' ) }
1184 </Button>
1185 </div>
1186 </Fragment>
1187 }
1188
1189 { applyFilters( 'generateblocks.editor.controls', '', 'headlineIcon', this.props, this.state ) }
1190 </PanelArea>
1191
1192 <PanelArea { ...this.props }
1193 title={ __( 'Documentation', 'generateblocks' ) }
1194 icon={ getIcon( 'documentation' ) }
1195 initialOpen={ false }
1196 className={ 'gblocks-panel-label' }
1197 id={ 'headlineDocumentation' }
1198 state={ this.state }
1199 >
1200 <p>{ __( 'Need help with this block?', 'generateblocks' ) }</p>
1201 <a href="https://docs.generateblocks.com/collection/headline/" target="_blank" rel="noreferrer noopener">{ __( 'Visit our documentation', 'generateblocks' ) }</a>
1202
1203 { applyFilters( 'generateblocks.editor.controls', '', 'headlineDocumentation', this.props, this.state ) }
1204 </PanelArea>
1205 </InspectorControls>
1206
1207 <InspectorAdvancedControls>
1208 <TextControl
1209 label={ __( 'HTML Anchor', 'generateblocks' ) }
1210 help={ __( 'Anchors lets you link directly to a section on a page.', 'generateblocks' ) }
1211 value={ anchor || '' }
1212 onChange={ ( nextValue ) => {
1213 nextValue = nextValue.replace( ANCHOR_REGEX, '-' );
1214 setAttributes( {
1215 anchor: nextValue,
1216 } );
1217 } } />
1218 </InspectorAdvancedControls>
1219
1220 <MainCSS { ...this.props } />
1221
1222 { this.props.deviceType &&
1223 <Fragment>
1224 { 'Desktop' === this.props.deviceType &&
1225 <DesktopCSS { ...this.props } />
1226 }
1227
1228 { ( 'Tablet' === this.props.deviceType || 'Mobile' === this.props.deviceType ) &&
1229 <TabletCSS { ...this.props } />
1230 }
1231
1232 { 'Tablet' === this.props.deviceType &&
1233 <TabletOnlyCSS { ...this.props } />
1234 }
1235
1236 { 'Mobile' === this.props.deviceType &&
1237 <MobileCSS { ...this.props } />
1238 }
1239 </Fragment>
1240 }
1241
1242 { fontFamily && googleFont &&
1243 <link
1244 rel="stylesheet"
1245 href={ 'https://fonts.googleapis.com/css?family=' + fontFamily.replace( / /g, '+' ) + googleFontsAttr }
1246 />
1247 }
1248
1249 { applyFilters( 'generateblocks.editor.beforeHeadlineElement', '', this.props ) }
1250
1251 <Element
1252 tagName={ element }
1253 htmlAttrs={ htmlAttributes }
1254 >
1255 { hasIcon &&
1256 <Fragment>
1257 <span
1258 className="gb-icon"
1259 aria-label={ !! removeText && !! ariaLabel ? ariaLabel : undefined }
1260 dangerouslySetInnerHTML={ { __html: icon } }
1261 />
1262
1263 { ! removeText &&
1264 <span className="gb-headline-text">
1265 <RichText
1266 tagName="span"
1267 value={ content }
1268 onChange={ ( value ) => setAttributes( { content: value } ) }
1269 placeholder={ __( 'Headline', 'generateblocks' ) }
1270 keepPlaceholderOnFocus={ true }
1271 allowedFormats={ applyFilters( 'generateblocks.editor.headlineDisableFormatting', false, this.props ) ? [] : null }
1272 />
1273 </span>
1274 }
1275 </Fragment>
1276 }
1277
1278 { ! hasIcon && ! removeText &&
1279 <RichText
1280 tagName="span"
1281 value={ content }
1282 onChange={ ( value ) => setAttributes( { content: value } ) }
1283 placeholder={ __( 'Headline', 'generateblocks' ) }
1284 keepPlaceholderOnFocus={ true }
1285 allowedFormats={ applyFilters( 'generateblocks.editor.headlineDisableFormatting', false, this.props ) ? [] : null }
1286 />
1287 }
1288 </Element>
1289 </Fragment>
1290 );
1291 }
1292 }
1293
1294 export default compose( [
1295 withDispatch( ( dispatch ) => ( {
1296 setDeviceType( type ) {
1297 const {
1298 __experimentalSetPreviewDeviceType: setPreviewDeviceType,
1299 } = dispatch( 'core/edit-post' );
1300
1301 if ( ! setPreviewDeviceType ) {
1302 return;
1303 }
1304
1305 setPreviewDeviceType( type );
1306 },
1307 } ) ),
1308 withSelect( ( select ) => {
1309 const {
1310 __experimentalGetPreviewDeviceType: getPreviewDeviceType,
1311 } = select( 'core/edit-post' );
1312
1313 if ( ! getPreviewDeviceType ) {
1314 return {
1315 deviceType: null,
1316 };
1317 }
1318
1319 return {
1320 deviceType: getPreviewDeviceType(),
1321 };
1322 } ),
1323 ] )( GenerateBlockHeadline );
1324