-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add title to gutenberg mobile (#13199)
* temporarily disable link formatting * Make sure RichText resigns focus when unmounted (#13048) * Implements a native version of post-title. * Removes some unnecessary log calls. * Submits a few lint fixes. * Fixes a linting issue. * When focusing the title, any focused block loses its focus. * FocusOut is now wired for post-title for mobile. * Removes unused some code. * Added a file I failed to commit. * Fixes a linting issue.
- Loading branch information
1 parent
72c0c7b
commit a1b2ec9
Showing
4 changed files
with
225 additions
and
0 deletions.
There are no files selected for viewing
139 changes: 139 additions & 0 deletions
139
packages/components/src/higher-order/with-focus-outside/index.native.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { includes } from 'lodash'; | ||
import { View } from 'react-native'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { createHigherOrderComponent } from '@wordpress/compose'; | ||
|
||
/** | ||
* Input types which are classified as button types, for use in considering | ||
* whether element is a (focus-normalized) button. | ||
* | ||
* @type {string[]} | ||
*/ | ||
const INPUT_BUTTON_TYPES = [ | ||
'button', | ||
'submit', | ||
]; | ||
|
||
/** | ||
* Returns true if the given element is a button element subject to focus | ||
* normalization, or false otherwise. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus | ||
* | ||
* @param {Element} element Element to test. | ||
* | ||
* @return {boolean} Whether element is a button. | ||
*/ | ||
function isFocusNormalizedButton( element ) { | ||
switch ( element.nodeName ) { | ||
case 'A': | ||
case 'BUTTON': | ||
return true; | ||
|
||
case 'INPUT': | ||
return includes( INPUT_BUTTON_TYPES, element.type ); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
export default createHigherOrderComponent( | ||
( WrappedComponent ) => { | ||
return class extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.bindNode = this.bindNode.bind( this ); | ||
this.cancelBlurCheck = this.cancelBlurCheck.bind( this ); | ||
this.queueBlurCheck = this.queueBlurCheck.bind( this ); | ||
this.normalizeButtonFocus = this.normalizeButtonFocus.bind( this ); | ||
} | ||
|
||
componentWillUnmount() { | ||
this.cancelBlurCheck(); | ||
} | ||
|
||
bindNode( node ) { | ||
if ( node ) { | ||
this.node = node; | ||
} else { | ||
delete this.node; | ||
this.cancelBlurCheck(); | ||
} | ||
} | ||
|
||
queueBlurCheck( event ) { | ||
// React does not allow using an event reference asynchronously | ||
// due to recycling behavior, except when explicitly persisted. | ||
event.persist(); | ||
|
||
// Skip blur check if clicking button. See `normalizeButtonFocus`. | ||
if ( this.preventBlurCheck ) { | ||
return; | ||
} | ||
|
||
this.blurCheckTimeout = setTimeout( () => { | ||
if ( 'function' === typeof this.node.handleFocusOutside ) { | ||
this.node.handleFocusOutside( event ); | ||
} | ||
}, 0 ); | ||
} | ||
|
||
cancelBlurCheck() { | ||
clearTimeout( this.blurCheckTimeout ); | ||
} | ||
|
||
/** | ||
* Handles a mousedown or mouseup event to respectively assign and | ||
* unassign a flag for preventing blur check on button elements. Some | ||
* browsers, namely Firefox and Safari, do not emit a focus event on | ||
* button elements when clicked, while others do. The logic here | ||
* intends to normalize this as treating click on buttons as focus. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus | ||
* | ||
* @param {MouseEvent} event Event for mousedown or mouseup. | ||
*/ | ||
normalizeButtonFocus( event ) { | ||
const { type, target } = event; | ||
|
||
const isInteractionEnd = includes( [ 'mouseup', 'touchend' ], type ); | ||
|
||
if ( isInteractionEnd ) { | ||
this.preventBlurCheck = false; | ||
} else if ( isFocusNormalizedButton( target ) ) { | ||
this.preventBlurCheck = true; | ||
} | ||
} | ||
|
||
render() { | ||
// Disable reason: See `normalizeButtonFocus` for browser-specific | ||
// focus event normalization. | ||
|
||
/* eslint-disable jsx-a11y/no-static-element-interactions */ | ||
return ( | ||
<View | ||
onFocus={ this.cancelBlurCheck } | ||
onMouseDown={ this.normalizeButtonFocus } | ||
onMouseUp={ this.normalizeButtonFocus } | ||
onTouchStart={ this.normalizeButtonFocus } | ||
onTouchEnd={ this.normalizeButtonFocus } | ||
onBlur={ this.queueBlurCheck } | ||
> | ||
<WrappedComponent | ||
ref={ this.bindNode } | ||
{ ...this.props } /> | ||
</View> | ||
); | ||
/* eslint-enable jsx-a11y/no-static-element-interactions */ | ||
} | ||
}; | ||
}, 'withFocusOutside' | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { TextInput } from 'react-native'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { decodeEntities } from '@wordpress/html-entities'; | ||
import { withDispatch } from '@wordpress/data'; | ||
import { withFocusOutside } from '@wordpress/components'; | ||
import { withInstanceId, compose } from '@wordpress/compose'; | ||
|
||
class PostTitle extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.onChange = this.onChange.bind( this ); | ||
this.onSelect = this.onSelect.bind( this ); | ||
this.onUnselect = this.onUnselect.bind( this ); | ||
|
||
this.state = { | ||
isSelected: false, | ||
}; | ||
} | ||
|
||
handleFocusOutside() { | ||
this.onUnselect(); | ||
} | ||
|
||
onSelect() { | ||
this.setState( { isSelected: true } ); | ||
this.props.clearSelectedBlock(); | ||
} | ||
|
||
onUnselect() { | ||
this.setState( { isSelected: false } ); | ||
} | ||
|
||
onChange( title ) { | ||
this.props.onUpdate( title ); | ||
} | ||
|
||
render() { | ||
const { | ||
placeholder, | ||
style, | ||
title, | ||
} = this.props; | ||
|
||
const decodedPlaceholder = decodeEntities( placeholder ); | ||
|
||
return ( | ||
<TextInput | ||
blurOnSubmit={ true } | ||
textAlignVertical="top" | ||
multiline | ||
numberOfLines={ 0 } | ||
onChangeText={ this.onChange } | ||
onFocus={ this.onSelect } | ||
placeholder={ decodedPlaceholder } | ||
style={ style } | ||
value={ title }> | ||
</TextInput> | ||
); | ||
} | ||
} | ||
|
||
const applyWithDispatch = withDispatch( ( dispatch ) => { | ||
const { | ||
clearSelectedBlock, | ||
} = dispatch( 'core/editor' ); | ||
|
||
return { | ||
clearSelectedBlock, | ||
}; | ||
} ); | ||
|
||
export default compose( | ||
applyWithDispatch, | ||
withInstanceId, | ||
withFocusOutside | ||
)( PostTitle ); |