@@ -7,18 +7,12 @@ import classnames from 'classnames';
77 * WordPress dependencies
88 */
99import { __ } from '@wordpress/i18n' ;
10- import {
11- forwardRef ,
12- useEffect ,
13- useImperativeHandle ,
14- useRef ,
15- useState ,
16- } from '@wordpress/element' ;
10+ import { forwardRef , useState } from '@wordpress/element' ;
1711import { decodeEntities } from '@wordpress/html-entities' ;
18- import { ENTER } from '@wordpress/keycodes' ;
1912import { useSelect , useDispatch } from '@wordpress/data' ;
20- import { pasteHandler } from '@wordpress/blocks' ;
2113import { store as blockEditorStore } from '@wordpress/block-editor' ;
14+ import { ENTER } from '@wordpress/keycodes' ;
15+ import { pasteHandler } from '@wordpress/blocks' ;
2216import {
2317 __unstableUseRichText as useRichText ,
2418 create ,
@@ -31,78 +25,45 @@ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
3125/**
3226 * Internal dependencies
3327 */
34- import PostTypeSupportCheck from '../post-type-support-check' ;
3528import { store as editorStore } from '../../store' ;
36-
37- /**
38- * Constants
39- */
40- const REGEXP_NEWLINES = / [ \r \n ] + / g;
29+ import { DEFAULT_CLASSNAMES , REGEXP_NEWLINES } from './constants' ;
30+ import usePostTitleFocus from './use-post-title-focus' ;
31+ import usePostTitle from './use-post-title' ;
32+ import PostTypeSupportCheck from '../post-type-support-check' ;
4133
4234function PostTitle ( _ , forwardedRef ) {
43- const ref = useRef ( ) ;
35+ const { placeholder, hasFixedToolbar } = useSelect ( ( select ) => {
36+ const { getEditedPostAttribute } = select ( editorStore ) ;
37+ const { getSettings } = select ( blockEditorStore ) ;
38+ const { titlePlaceholder, hasFixedToolbar : _hasFixedToolbar } =
39+ getSettings ( ) ;
40+
41+ return {
42+ title : getEditedPostAttribute ( 'title' ) ,
43+ placeholder : titlePlaceholder ,
44+ hasFixedToolbar : _hasFixedToolbar ,
45+ } ;
46+ } , [ ] ) ;
47+
4448 const [ isSelected , setIsSelected ] = useState ( false ) ;
45- const { editPost } = useDispatch ( editorStore ) ;
46- const { insertDefaultBlock, clearSelectedBlock, insertBlocks } =
47- useDispatch ( blockEditorStore ) ;
48- const { isCleanNewPost, title, placeholder, hasFixedToolbar } = useSelect (
49- ( select ) => {
50- const { getEditedPostAttribute, isCleanNewPost : _isCleanNewPost } =
51- select ( editorStore ) ;
52- const { getSettings } = select ( blockEditorStore ) ;
53- const { titlePlaceholder, hasFixedToolbar : _hasFixedToolbar } =
54- getSettings ( ) ;
55-
56- return {
57- isCleanNewPost : _isCleanNewPost ( ) ,
58- title : getEditedPostAttribute ( 'title' ) ,
59- placeholder : titlePlaceholder ,
60- hasFixedToolbar : _hasFixedToolbar ,
61- } ;
62- } ,
63- [ ]
64- ) ;
6549
66- useImperativeHandle ( forwardedRef , ( ) => ( {
67- focus : ( ) => {
68- ref ?. current ?. focus ( ) ;
69- } ,
70- } ) ) ;
50+ const { ref : focusRef } = usePostTitleFocus ( forwardedRef ) ;
7151
72- useEffect ( ( ) => {
73- if ( ! ref . current ) {
74- return ;
75- }
52+ const { title, setTitle : onUpdate } = usePostTitle ( ) ;
7653
77- const { defaultView } = ref . current . ownerDocument ;
78- const { name, parent } = defaultView ;
79- const ownerDocument =
80- name === 'editor-canvas' ? parent . document : defaultView . document ;
81- const { activeElement, body } = ownerDocument ;
82-
83- // Only autofocus the title when the post is entirely empty. This should
84- // only happen for a new post, which means we focus the title on new
85- // post so the author can start typing right away, without needing to
86- // click anything.
87- if ( isCleanNewPost && ( ! activeElement || body === activeElement ) ) {
88- ref . current . focus ( ) ;
89- }
90- } , [ isCleanNewPost ] ) ;
54+ const [ selection , setSelection ] = useState ( { } ) ;
9155
92- function onEnterPress ( ) {
93- insertDefaultBlock ( undefined , undefined , 0 ) ;
56+ const { clearSelectedBlock, insertBlocks, insertDefaultBlock } =
57+ useDispatch ( blockEditorStore ) ;
58+
59+ function onChange ( value ) {
60+ onUpdate ( value . replace ( REGEXP_NEWLINES , ' ' ) ) ;
9461 }
9562
9663 function onInsertBlockAfter ( blocks ) {
9764 insertBlocks ( blocks , 0 ) ;
9865 }
9966
100- function onUpdate ( newTitle ) {
101- editPost ( { title : newTitle } ) ;
102- }
103-
104- const [ selection , setSelection ] = useState ( { } ) ;
105-
10667 function onSelect ( ) {
10768 setIsSelected ( true ) ;
10869 clearSelectedBlock ( ) ;
@@ -113,8 +74,8 @@ function PostTitle( _, forwardedRef ) {
11374 setSelection ( { } ) ;
11475 }
11576
116- function onChange ( value ) {
117- onUpdate ( value . replace ( REGEXP_NEWLINES , ' ' ) ) ;
77+ function onEnterPress ( ) {
78+ insertDefaultBlock ( undefined , undefined , 0 ) ;
11879 }
11980
12081 function onKeyDown ( event ) {
@@ -170,7 +131,13 @@ function PostTitle( _, forwardedRef ) {
170131 ( firstBlock . name === 'core/heading' ||
171132 firstBlock . name === 'core/paragraph' )
172133 ) {
173- onUpdate ( stripHTML ( firstBlock . attributes . content ) ) ;
134+ // Strip HTML to avoid unwanted HTML being added to the title.
135+ // In the majority of cases it is assumed that HTML in the title
136+ // is undesirable.
137+ const contentNoHTML = stripHTML (
138+ firstBlock . attributes . content
139+ ) ;
140+ onUpdate ( contentNoHTML ) ;
174141 onInsertBlockAfter ( content . slice ( 1 ) ) ;
175142 } else {
176143 onInsertBlockAfter ( content ) ;
@@ -180,10 +147,13 @@ function PostTitle( _, forwardedRef ) {
180147 ...create ( { html : title } ) ,
181148 ...selection ,
182149 } ;
183- const newValue = insert (
184- value ,
185- create ( { html : stripHTML ( content ) } )
186- ) ;
150+
151+ // Strip HTML to avoid unwanted HTML being added to the title.
152+ // In the majority of cases it is assumed that HTML in the title
153+ // is undesirable.
154+ const contentNoHTML = stripHTML ( content ) ;
155+
156+ const newValue = insert ( value , create ( { html : contentNoHTML } ) ) ;
187157 onUpdate ( toHTMLString ( { value : newValue } ) ) ;
188158 setSelection ( {
189159 start : newValue . start ,
@@ -192,21 +162,13 @@ function PostTitle( _, forwardedRef ) {
192162 }
193163 }
194164
195- // The wp-block className is important for editor styles.
196- // This same block is used in both the visual and the code editor.
197- const className = classnames (
198- 'wp-block wp-block-post-title block-editor-block-list__block editor-post-title editor-post-title__input rich-text' ,
199- {
200- 'is-selected' : isSelected ,
201- 'has-fixed-toolbar' : hasFixedToolbar ,
202- }
203- ) ;
204165 const decodedPlaceholder =
205166 decodeEntities ( placeholder ) || __ ( 'Add title' ) ;
167+
206168 const { ref : richTextRef } = useRichText ( {
207169 value : title ,
208170 onChange,
209- placeholder : decodedPlaceholder ,
171+ decodedPlaceholder,
210172 selectionStart : selection . start ,
211173 selectionEnd : selection . end ,
212174 onSelectionChange ( newStart , newEnd ) {
@@ -221,14 +183,21 @@ function PostTitle( _, forwardedRef ) {
221183 } ;
222184 } ) ;
223185 } ,
224- __unstableDisableFormats : true ,
186+ __unstableDisableFormats : false ,
187+ } ) ;
188+
189+ // The wp-block className is important for editor styles.
190+ // This same block is used in both the visual and the code editor.
191+ const className = classnames ( DEFAULT_CLASSNAMES , {
192+ 'is-selected' : isSelected ,
193+ 'has-fixed-toolbar' : hasFixedToolbar ,
225194 } ) ;
226195
227- /* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
228196 return (
197+ /* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
229198 < PostTypeSupportCheck supportKeys = "title" >
230199 < h1
231- ref = { useMergeRefs ( [ richTextRef , ref ] ) }
200+ ref = { useMergeRefs ( [ richTextRef , focusRef ] ) }
232201 contentEditable
233202 className = { className }
234203 aria-label = { decodedPlaceholder }
@@ -241,8 +210,8 @@ function PostTitle( _, forwardedRef ) {
241210 onPaste = { onPaste }
242211 />
243212 </ PostTypeSupportCheck >
213+ /* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
244214 ) ;
245- /* eslint-enable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */
246215}
247216
248217export default forwardRef ( PostTitle ) ;
0 commit comments