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