/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule DraftEditorTextNode.react
* @format
* @flow
*/
'use strict';
const React = require('react');
const ReactDOM = require('react-dom');
const UserAgent = require('fbjs/lib/UserAgent');
const invariant = require('fbjs/lib/invariant');
// In IE, spans with
tags render as two newlines. By rendering a span
// with only a newline character, we can be sure to render a single line.
const useNewlineChar = UserAgent.isBrowser('IE <= 11');
/**
* Check whether the node should be considered a newline.
*/
function isNewline(node: Element): boolean {
return useNewlineChar ? node.textContent === '\n' : node.tagName === 'BR';
}
/**
* Placeholder elements for empty text content.
*
* What is this `data-text` attribute, anyway? It turns out that we need to
* put an attribute on the lowest-level text node in order to preserve correct
* spellcheck handling. If the is naked, Chrome and Safari may do
* bizarre things to do the DOM -- split text nodes, create extra spans, etc.
* If the has an attribute, this appears not to happen.
* See http://jsfiddle.net/9khdavod/ for the failure case, and
* http://jsfiddle.net/7pg143f7/ for the fixed case.
*/
const NEWLINE_A = useNewlineChar ?
{'\n'}
:
;
const NEWLINE_B = useNewlineChar ?
{'\n'}
:
;
type Props = {
children: string
};
/**
* The lowest-level component in a `DraftEditor`, the text node component
* replaces the default React text node implementation. This allows us to
* perform custom handling of newline behavior and avoid re-rendering text
* nodes with DOM state that already matches the expectations of our immutable
* editor state.
*/
class DraftEditorTextNode extends React.Component {
_forceFlag: boolean;
constructor(props: Props) {
super(props);
// By flipping this flag, we also keep flipping keys which forces
// React to remount this node every time it rerenders.
this._forceFlag = false;
}
shouldComponentUpdate(nextProps: Props): boolean {
const node = ReactDOM.findDOMNode(this);
const shouldBeNewline = nextProps.children === '';
invariant(node instanceof Element, 'node is not an Element');
if (shouldBeNewline) {
return !isNewline(node);
}
return node.textContent !== nextProps.children;
}
componentDidMount(): void {
this._forceFlag = !this._forceFlag;
}
componentDidUpdate(): void {
this._forceFlag = !this._forceFlag;
}
render(): React.Node {
if (this.props.children === '') {
return this._forceFlag ? NEWLINE_A : NEWLINE_B;
}
return
{this.props.children}
;
}
}
module.exports = DraftEditorTextNode;