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