1 |
|
2 |
|
3 |
|
4 | import classnames from 'classnames';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | import { __, _x } from '@wordpress/i18n';
|
10 | import {
|
11 | Component,
|
12 | Fragment,
|
13 | } from '@wordpress/element';
|
14 | import {
|
15 | PanelBody,
|
16 | ToggleControl,
|
17 | Toolbar,
|
18 | withFallbackStyles,
|
19 | } from '@wordpress/components';
|
20 | import {
|
21 | withColors,
|
22 | AlignmentToolbar,
|
23 | BlockControls,
|
24 | ContrastChecker,
|
25 | FontSizePicker,
|
26 | InspectorControls,
|
27 | PanelColorSettings,
|
28 | RichText,
|
29 | withFontSizes,
|
30 | } from '@wordpress/block-editor';
|
31 | import { createBlock } from '@wordpress/blocks';
|
32 | import { compose } from '@wordpress/compose';
|
33 | import { withSelect } from '@wordpress/data';
|
34 |
|
35 | const { getComputedStyle } = window;
|
36 |
|
37 | const name = 'core/paragraph';
|
38 |
|
39 | const applyFallbackStyles = withFallbackStyles( ( node, ownProps ) => {
|
40 | const { textColor, backgroundColor, fontSize, customFontSize } = ownProps.attributes;
|
41 | const editableNode = node.querySelector( '[contenteditable="true"]' );
|
42 |
|
43 | const computedStyles = editableNode ? getComputedStyle( editableNode ) : null;
|
44 | return {
|
45 | fallbackBackgroundColor: backgroundColor || ! computedStyles ? undefined : computedStyles.backgroundColor,
|
46 | fallbackTextColor: textColor || ! computedStyles ? undefined : computedStyles.color,
|
47 | fallbackFontSize: fontSize || customFontSize || ! computedStyles ? undefined : parseInt( computedStyles.fontSize ) || undefined,
|
48 | };
|
49 | } );
|
50 |
|
51 | class ParagraphBlock extends Component {
|
52 | constructor() {
|
53 | super( ...arguments );
|
54 |
|
55 | this.onReplace = this.onReplace.bind( this );
|
56 | this.toggleDropCap = this.toggleDropCap.bind( this );
|
57 | this.splitBlock = this.splitBlock.bind( this );
|
58 | }
|
59 |
|
60 | onReplace( blocks ) {
|
61 | const { attributes, onReplace } = this.props;
|
62 | onReplace( blocks.map( ( block, index ) => (
|
63 | index === 0 && block.name === name ?
|
64 | { ...block,
|
65 | attributes: {
|
66 | ...attributes,
|
67 | ...block.attributes,
|
68 | },
|
69 | } :
|
70 | block
|
71 | ) ) );
|
72 | }
|
73 |
|
74 | toggleDropCap() {
|
75 | const { attributes, setAttributes } = this.props;
|
76 | setAttributes( { dropCap: ! attributes.dropCap } );
|
77 | }
|
78 |
|
79 | getDropCapHelp( checked ) {
|
80 | return checked ? __( 'Showing large initial letter.' ) : __( 'Toggle to show a large initial letter.' );
|
81 | }
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | splitBlock( before, after, ...blocks ) {
|
97 | const {
|
98 | attributes,
|
99 | insertBlocksAfter,
|
100 | setAttributes,
|
101 | onReplace,
|
102 | } = this.props;
|
103 |
|
104 | if ( after !== null ) {
|
105 |
|
106 |
|
107 | blocks.push( createBlock( name, { content: after } ) );
|
108 | }
|
109 |
|
110 | if ( blocks.length && insertBlocksAfter ) {
|
111 | insertBlocksAfter( blocks );
|
112 | }
|
113 |
|
114 | const { content } = attributes;
|
115 | if ( before === null ) {
|
116 |
|
117 | onReplace( [] );
|
118 | } else if ( content !== before ) {
|
119 |
|
120 |
|
121 |
|
122 | setAttributes( { content: before } );
|
123 | }
|
124 | }
|
125 |
|
126 | render() {
|
127 | const {
|
128 | attributes,
|
129 | setAttributes,
|
130 | mergeBlocks,
|
131 | onReplace,
|
132 | className,
|
133 | backgroundColor,
|
134 | textColor,
|
135 | setBackgroundColor,
|
136 | setTextColor,
|
137 | fallbackBackgroundColor,
|
138 | fallbackTextColor,
|
139 | fallbackFontSize,
|
140 | fontSize,
|
141 | setFontSize,
|
142 | isRTL,
|
143 | } = this.props;
|
144 |
|
145 | const {
|
146 | align,
|
147 | content,
|
148 | dropCap,
|
149 | placeholder,
|
150 | direction,
|
151 | } = attributes;
|
152 |
|
153 | return (
|
154 | <Fragment>
|
155 | <BlockControls>
|
156 | <AlignmentToolbar
|
157 | value={ align }
|
158 | onChange={ ( nextAlign ) => {
|
159 | setAttributes( { align: nextAlign } );
|
160 | } }
|
161 | />
|
162 | { isRTL && (
|
163 | <Toolbar
|
164 | controls={ [
|
165 | {
|
166 | icon: 'editor-ltr',
|
167 | title: _x( 'Left to right', 'editor button' ),
|
168 | isActive: direction === 'ltr',
|
169 | onClick() {
|
170 | const nextDirection = direction === 'ltr' ? undefined : 'ltr';
|
171 | setAttributes( {
|
172 | direction: nextDirection,
|
173 | } );
|
174 | },
|
175 | },
|
176 | ] }
|
177 | />
|
178 | ) }
|
179 | </BlockControls>
|
180 | <InspectorControls>
|
181 | <PanelBody title={ __( 'Text Settings' ) } className="blocks-font-size">
|
182 | <FontSizePicker
|
183 | fallbackFontSize={ fallbackFontSize }
|
184 | value={ fontSize.size }
|
185 | onChange={ setFontSize }
|
186 | />
|
187 | <ToggleControl
|
188 | label={ __( 'Drop Cap' ) }
|
189 | checked={ !! dropCap }
|
190 | onChange={ this.toggleDropCap }
|
191 | help={ this.getDropCapHelp }
|
192 | />
|
193 | </PanelBody>
|
194 | <PanelColorSettings
|
195 | title={ __( 'Color Settings' ) }
|
196 | initialOpen={ false }
|
197 | colorSettings={ [
|
198 | {
|
199 | value: backgroundColor.color,
|
200 | onChange: setBackgroundColor,
|
201 | label: __( 'Background Color' ),
|
202 | },
|
203 | {
|
204 | value: textColor.color,
|
205 | onChange: setTextColor,
|
206 | label: __( 'Text Color' ),
|
207 | },
|
208 | ] }
|
209 | >
|
210 | <ContrastChecker
|
211 | { ...{
|
212 | textColor: textColor.color,
|
213 | backgroundColor: backgroundColor.color,
|
214 | fallbackTextColor,
|
215 | fallbackBackgroundColor,
|
216 | } }
|
217 | fontSize={ fontSize.size }
|
218 | />
|
219 | </PanelColorSettings>
|
220 | </InspectorControls>
|
221 | <RichText
|
222 | identifier="content"
|
223 | tagName="p"
|
224 | className={ classnames( 'wp-block-paragraph', className, {
|
225 | 'has-text-color': textColor.color,
|
226 | 'has-background': backgroundColor.color,
|
227 | 'has-drop-cap': dropCap,
|
228 | [ backgroundColor.class ]: backgroundColor.class,
|
229 | [ textColor.class ]: textColor.class,
|
230 | [ fontSize.class ]: fontSize.class,
|
231 | } ) }
|
232 | style={ {
|
233 | backgroundColor: backgroundColor.color,
|
234 | color: textColor.color,
|
235 | fontSize: fontSize.size ? fontSize.size + 'px' : undefined,
|
236 | textAlign: align,
|
237 | direction,
|
238 | } }
|
239 | value={ content }
|
240 | onChange={ ( nextContent ) => {
|
241 | setAttributes( {
|
242 | content: nextContent,
|
243 | } );
|
244 | } }
|
245 | unstableOnSplit={ this.splitBlock }
|
246 | onMerge={ mergeBlocks }
|
247 | onReplace={ this.onReplace }
|
248 | onRemove={ () => onReplace( [] ) }
|
249 | aria-label={ content ? __( 'Paragraph block' ) : __( 'Empty block; start writing or type forward slash to choose a block' ) }
|
250 | placeholder={ placeholder || __( 'Start writing or type / to choose a block' ) }
|
251 | />
|
252 | </Fragment>
|
253 | );
|
254 | }
|
255 | }
|
256 |
|
257 | const ParagraphEdit = compose( [
|
258 | withColors( 'backgroundColor', { textColor: 'color' } ),
|
259 | withFontSizes( 'fontSize' ),
|
260 | applyFallbackStyles,
|
261 | withSelect( ( select ) => {
|
262 | const { getSettings } = select( 'core/block-editor' );
|
263 |
|
264 | return {
|
265 | isRTL: getSettings().isRTL,
|
266 | };
|
267 | } ),
|
268 | ] )( ParagraphBlock );
|
269 |
|
270 | export default ParagraphEdit;
|