diff --git a/components/clipboard-button/index.js b/components/clipboard-button/index.js index e52ef576afc4bb..80a96920e5cbd1 100644 --- a/components/clipboard-button/index.js +++ b/components/clipboard-button/index.js @@ -3,12 +3,11 @@ */ import Clipboard from 'clipboard'; import classnames from 'classnames'; -import { noop } from 'lodash'; /** * WordPress dependencies */ -import { findDOMNode, Component } from '@wordpress/element'; +import { Component } from '@wordpress/element'; /** * Internal dependencies @@ -16,12 +15,23 @@ import { findDOMNode, Component } from '@wordpress/element'; import { Button } from '../'; class ClipboardButton extends Component { + constructor() { + super( ...arguments ); + + this.bindContainer = this.bindContainer.bind( this ); + this.onCopy = this.onCopy.bind( this ); + this.getText = this.getText.bind( this ); + } + componentDidMount() { - const { text, onCopy = noop } = this.props; - const button = findDOMNode( this.button ); - this.clipboard = new Clipboard( button, { - text: () => text, + const { container, getText, onCopy } = this; + const button = container.firstChild; + + this.clipboard = new Clipboard( button, { + text: getText, + container, } ); + this.clipboard.on( 'success', onCopy ); } @@ -30,17 +40,36 @@ class ClipboardButton extends Component { delete this.clipboard; } + bindContainer( container ) { + this.container = container; + } + + onCopy( args ) { + // Clearing selection will move focus back to the triggering button, + // ensuring that it is not reset to the body, and further that it is + // kept within the rendered node. + args.clearSelection(); + + const { onCopy } = this.props; + if ( onCopy ) { + onCopy(); + } + } + + getText() { + return this.props.text; + } + render() { const { className, children } = this.props; const classes = classnames( 'components-clipboard-button', className ); return ( - +
+ +
); } } diff --git a/editor/post-permalink/index.js b/editor/post-permalink/index.js index 2f7fc86277e431..a53295c6399696 100644 --- a/editor/post-permalink/index.js +++ b/editor/post-permalink/index.js @@ -25,7 +25,7 @@ class PostPermalink extends Component { this.onCopy = this.onCopy.bind( this ); } - componentWillUnmout() { + componentWillUnmount() { clearTimeout( this.dismissCopyConfirmation ); } diff --git a/editor/post-title/index.js b/editor/post-title/index.js index bdbb042f47ba39..4c01f36bd5e687 100644 --- a/editor/post-title/index.js +++ b/editor/post-title/index.js @@ -3,7 +3,6 @@ */ import { connect } from 'react-redux'; import Textarea from 'react-autosize-textarea'; -import clickOutside from 'react-click-outside'; import classnames from 'classnames'; /** @@ -32,12 +31,16 @@ class PostTitle extends Component { constructor() { super( ...arguments ); - this.bindTextarea = this.bindTextarea.bind( this ); + this.bindContainer = this.bindNode.bind( this, 'container' ); + this.bindTextarea = this.bindNode.bind( this, 'textarea' ); this.onChange = this.onChange.bind( this ); this.onSelect = this.onSelect.bind( this ); this.onUnselect = this.onUnselect.bind( this ); this.onSelectionChange = this.onSelectionChange.bind( this ); this.onKeyDown = this.onKeyDown.bind( this ); + this.blurIfOutside = this.blurIfOutside.bind( this ); + + this.nodes = {}; this.state = { isSelected: false, @@ -52,12 +55,12 @@ class PostTitle extends Component { document.removeEventListener( 'selectionchange', this.onSelectionChange ); } - bindTextarea( ref ) { - this.textareaContainer = ref; + bindNode( name, node ) { + this.nodes[ name ] = node; } onSelectionChange() { - const textarea = this.textareaContainer.textarea; + const textarea = this.nodes.textarea.textarea; if ( document.activeElement === textarea && textarea.selectionStart !== textarea.selectionEnd @@ -80,8 +83,10 @@ class PostTitle extends Component { this.setState( { isSelected: false } ); } - handleClickOutside() { - this.setState( { isSelected: false } ); + blurIfOutside( event ) { + if ( ! this.nodes.container.contains( event.relatedTarget ) ) { + this.onUnselect(); + } } onKeyDown( event ) { @@ -97,7 +102,13 @@ class PostTitle extends Component { const className = classnames( 'editor-post-title', { 'is-selected': isSelected } ); return ( -
+
{ isSelected && }