UNPKG

5.66 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 *
9 * @emails oncall+draft_js
10 */
11'use strict';
12
13var _assign = require("object-assign");
14
15function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
16
17function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
18
19function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
20
21var DraftEditorTextNode = require("./DraftEditorTextNode.react");
22
23var React = require("react");
24
25var invariant = require("fbjs/lib/invariant");
26
27var isHTMLBRElement = require("./isHTMLBRElement");
28
29var setDraftEditorSelection = require("./setDraftEditorSelection").setDraftEditorSelection;
30
31/**
32 * All leaf nodes in the editor are spans with single text nodes. Leaf
33 * elements are styled based on the merging of an optional custom style map
34 * and a default style map.
35 *
36 * `DraftEditorLeaf` also provides a wrapper for calling into the imperative
37 * DOM Selection API. In this way, top-level components can declaratively
38 * maintain the selection state.
39 */
40var DraftEditorLeaf = /*#__PURE__*/function (_React$Component) {
41 _inheritsLoose(DraftEditorLeaf, _React$Component);
42
43 function DraftEditorLeaf() {
44 var _this;
45
46 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
47 args[_key] = arguments[_key];
48 }
49
50 _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
51
52 _defineProperty(_assertThisInitialized(_this), "leaf", void 0);
53
54 return _this;
55 }
56
57 var _proto = DraftEditorLeaf.prototype;
58
59 _proto._setSelection = function _setSelection() {
60 var selection = this.props.selection; // If selection state is irrelevant to the parent block, no-op.
61
62 if (selection == null || !selection.getHasFocus()) {
63 return;
64 }
65
66 var _this$props = this.props,
67 block = _this$props.block,
68 start = _this$props.start,
69 text = _this$props.text;
70 var blockKey = block.getKey();
71 var end = start + text.length;
72
73 if (!selection.hasEdgeWithin(blockKey, start, end)) {
74 return;
75 } // Determine the appropriate target node for selection. If the child
76 // is not a text node, it is a <br /> spacer. In this case, use the
77 // <span> itself as the selection target.
78
79
80 var node = this.leaf;
81 !node ? process.env.NODE_ENV !== "production" ? invariant(false, 'Missing node') : invariant(false) : void 0;
82 var child = node.firstChild;
83 !child ? process.env.NODE_ENV !== "production" ? invariant(false, 'Missing child') : invariant(false) : void 0;
84 var targetNode;
85
86 if (child.nodeType === Node.TEXT_NODE) {
87 targetNode = child;
88 } else if (isHTMLBRElement(child)) {
89 targetNode = node;
90 } else {
91 targetNode = child.firstChild;
92 !targetNode ? process.env.NODE_ENV !== "production" ? invariant(false, 'Missing targetNode') : invariant(false) : void 0;
93 }
94
95 setDraftEditorSelection(selection, targetNode, blockKey, start, end);
96 };
97
98 _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
99 var leafNode = this.leaf;
100 !leafNode ? process.env.NODE_ENV !== "production" ? invariant(false, 'Missing leafNode') : invariant(false) : void 0;
101 var shouldUpdate = leafNode.textContent !== nextProps.text || nextProps.styleSet !== this.props.styleSet || nextProps.forceSelection;
102 return shouldUpdate;
103 };
104
105 _proto.componentDidUpdate = function componentDidUpdate() {
106 this._setSelection();
107 };
108
109 _proto.componentDidMount = function componentDidMount() {
110 this._setSelection();
111 };
112
113 _proto.render = function render() {
114 var _this2 = this;
115
116 var block = this.props.block;
117 var text = this.props.text; // If the leaf is at the end of its block and ends in a soft newline, append
118 // an extra line feed character. Browsers collapse trailing newline
119 // characters, which leaves the cursor in the wrong place after a
120 // shift+enter. The extra character repairs this.
121
122 if (text.endsWith('\n') && this.props.isLast) {
123 text += '\n';
124 }
125
126 var _this$props2 = this.props,
127 customStyleMap = _this$props2.customStyleMap,
128 customStyleFn = _this$props2.customStyleFn,
129 offsetKey = _this$props2.offsetKey,
130 styleSet = _this$props2.styleSet;
131 var styleObj = styleSet.reduce(function (map, styleName) {
132 var mergedStyles = {};
133 var style = customStyleMap[styleName];
134
135 if (style !== undefined && map.textDecoration !== style.textDecoration) {
136 // .trim() is necessary for IE9/10/11 and Edge
137 mergedStyles.textDecoration = [map.textDecoration, style.textDecoration].join(' ').trim();
138 }
139
140 return _assign(map, style, mergedStyles);
141 }, {});
142
143 if (customStyleFn) {
144 var newStyles = customStyleFn(styleSet, block);
145 styleObj = _assign(styleObj, newStyles);
146 }
147
148 return React.createElement("span", {
149 "data-offset-key": offsetKey,
150 ref: function ref(_ref) {
151 return _this2.leaf = _ref;
152 },
153 style: styleObj
154 }, React.createElement(DraftEditorTextNode, null, text));
155 };
156
157 return DraftEditorLeaf;
158}(React.Component);
159
160module.exports = DraftEditorLeaf;
\No newline at end of file