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