slate
Version:
A completely customizable framework for building rich text editors.
1,337 lines (1,317 loc) • 232 kB
JavaScript
// eslint-disable-next-line no-redeclare
var PathRef = {
transform(ref, op) {
var {
current,
affinity
} = ref;
if (current == null) {
return;
}
var path = Path.transform(current, op, {
affinity
});
ref.current = path;
if (path == null) {
ref.unref();
}
}
};
// eslint-disable-next-line no-redeclare
var PointRef = {
transform(ref, op) {
var {
current,
affinity
} = ref;
if (current == null) {
return;
}
var point = Point.transform(current, op, {
affinity
});
ref.current = point;
if (point == null) {
ref.unref();
}
}
};
// eslint-disable-next-line no-redeclare
var RangeRef = {
transform(ref, op) {
var {
current,
affinity
} = ref;
if (current == null) {
return;
}
var path = Range.transform(current, op, {
affinity
});
ref.current = path;
if (path == null) {
ref.unref();
}
}
};
var DIRTY_PATHS = new WeakMap();
var DIRTY_PATH_KEYS = new WeakMap();
var FLUSHING = new WeakMap();
var NORMALIZING = new WeakMap();
var PATH_REFS = new WeakMap();
var POINT_REFS = new WeakMap();
var RANGE_REFS = new WeakMap();
// eslint-disable-next-line no-redeclare
var Path = {
ancestors(path) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var {
reverse = false
} = options;
var paths = Path.levels(path, options);
if (reverse) {
paths = paths.slice(1);
} else {
paths = paths.slice(0, -1);
}
return paths;
},
common(path, another) {
var common = [];
for (var i = 0; i < path.length && i < another.length; i++) {
var av = path[i];
var bv = another[i];
if (typeof av !== 'number' || typeof bv !== 'number') {
throw new Error('Got non-numeric path index');
}
if (av !== bv) {
break;
}
common.push(av);
}
return common;
},
compare(path, another) {
var min = Math.min(path.length, another.length);
for (var i = 0; i < min; i++) {
if (path[i] < another[i]) return -1;
if (path[i] > another[i]) return 1;
}
return 0;
},
endsAfter(path, another) {
var i = path.length - 1;
var as = path.slice(0, i);
var bs = another.slice(0, i);
var av = path[i];
var bv = another[i];
return Path.equals(as, bs) && av > bv;
},
endsAt(path, another) {
var i = path.length;
var as = path.slice(0, i);
var bs = another.slice(0, i);
return Path.equals(as, bs);
},
endsBefore(path, another) {
var i = path.length - 1;
var as = path.slice(0, i);
var bs = another.slice(0, i);
var av = path[i];
var bv = another[i];
return Path.equals(as, bs) && av < bv;
},
equals(path, another) {
return path.length === another.length && path.every((n, i) => n === another[i]);
},
hasPrevious(path) {
return path[path.length - 1] > 0;
},
isAfter(path, another) {
return Path.compare(path, another) === 1;
},
isAncestor(path, another) {
return path.length < another.length && Path.compare(path, another) === 0;
},
isBefore(path, another) {
return Path.compare(path, another) === -1;
},
isChild(path, another) {
return path.length === another.length + 1 && Path.compare(path, another) === 0;
},
isCommon(path, another) {
return path.length <= another.length && Path.compare(path, another) === 0;
},
isDescendant(path, another) {
return path.length > another.length && Path.compare(path, another) === 0;
},
isParent(path, another) {
return path.length + 1 === another.length && Path.compare(path, another) === 0;
},
isPath(value) {
return Array.isArray(value) && value.every(n => typeof n === 'number');
},
isSibling(path, another) {
if (path.length !== another.length) {
return false;
}
var as = path.slice(0, -1);
var bs = another.slice(0, -1);
var al = path[path.length - 1];
var bl = another[another.length - 1];
return al !== bl && Path.equals(as, bs);
},
levels(path) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var {
reverse = false
} = options;
var list = [];
for (var i = 0; i <= path.length; i++) {
list.push(path.slice(0, i));
}
if (reverse) {
list.reverse();
}
return list;
},
next(path) {
if (path.length === 0) {
throw new Error("Cannot get the next path of a root path [".concat(path, "], because it has no next index."));
}
var last = path[path.length - 1];
return path.slice(0, -1).concat(last + 1);
},
operationCanTransformPath(operation) {
switch (operation.type) {
case 'insert_node':
case 'remove_node':
case 'merge_node':
case 'split_node':
case 'move_node':
return true;
default:
return false;
}
},
parent(path) {
if (path.length === 0) {
throw new Error("Cannot get the parent path of the root path [".concat(path, "]."));
}
return path.slice(0, -1);
},
previous(path) {
if (path.length === 0) {
throw new Error("Cannot get the previous path of a root path [".concat(path, "], because it has no previous index."));
}
var last = path[path.length - 1];
if (last <= 0) {
throw new Error("Cannot get the previous path of a first child path [".concat(path, "] because it would result in a negative index."));
}
return path.slice(0, -1).concat(last - 1);
},
relative(path, ancestor) {
if (!Path.isAncestor(ancestor, path) && !Path.equals(path, ancestor)) {
throw new Error("Cannot get the relative path of [".concat(path, "] inside ancestor [").concat(ancestor, "], because it is not above or equal to the path."));
}
return path.slice(ancestor.length);
},
transform(path, operation) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
if (!path) return null;
// PERF: use destructing instead of immer
var p = [...path];
var {
affinity = 'forward'
} = options;
// PERF: Exit early if the operation is guaranteed not to have an effect.
if (path.length === 0) {
return p;
}
switch (operation.type) {
case 'insert_node':
{
var {
path: op
} = operation;
if (Path.equals(op, p) || Path.endsBefore(op, p) || Path.isAncestor(op, p)) {
p[op.length - 1] += 1;
}
break;
}
case 'remove_node':
{
var {
path: _op
} = operation;
if (Path.equals(_op, p) || Path.isAncestor(_op, p)) {
return null;
} else if (Path.endsBefore(_op, p)) {
p[_op.length - 1] -= 1;
}
break;
}
case 'merge_node':
{
var {
path: _op2,
position
} = operation;
if (Path.equals(_op2, p) || Path.endsBefore(_op2, p)) {
p[_op2.length - 1] -= 1;
} else if (Path.isAncestor(_op2, p)) {
p[_op2.length - 1] -= 1;
p[_op2.length] += position;
}
break;
}
case 'split_node':
{
var {
path: _op3,
position: _position
} = operation;
if (Path.equals(_op3, p)) {
if (affinity === 'forward') {
p[p.length - 1] += 1;
} else if (affinity === 'backward') ; else {
return null;
}
} else if (Path.endsBefore(_op3, p)) {
p[_op3.length - 1] += 1;
} else if (Path.isAncestor(_op3, p) && path[_op3.length] >= _position) {
p[_op3.length - 1] += 1;
p[_op3.length] -= _position;
}
break;
}
case 'move_node':
{
var {
path: _op4,
newPath: onp
} = operation;
// If the old and new path are the same, it's a no-op.
if (Path.equals(_op4, onp)) {
return p;
}
if (Path.isAncestor(_op4, p) || Path.equals(_op4, p)) {
var copy = onp.slice();
if (Path.endsBefore(_op4, onp) && _op4.length < onp.length) {
copy[_op4.length - 1] -= 1;
}
return copy.concat(p.slice(_op4.length));
} else if (Path.isSibling(_op4, onp) && (Path.isAncestor(onp, p) || Path.equals(onp, p))) {
if (Path.endsBefore(_op4, p)) {
p[_op4.length - 1] -= 1;
} else {
p[_op4.length - 1] += 1;
}
} else if (Path.endsBefore(onp, p) || Path.equals(onp, p) || Path.isAncestor(onp, p)) {
if (Path.endsBefore(_op4, p)) {
p[_op4.length - 1] -= 1;
}
p[onp.length - 1] += 1;
} else if (Path.endsBefore(_op4, p)) {
if (Path.equals(onp, p)) {
p[onp.length - 1] += 1;
}
p[_op4.length - 1] -= 1;
}
break;
}
}
return p;
}
};
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _toPrimitive(input, hint) {
if (_typeof(input) !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint);
if (_typeof(res) !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return _typeof(key) === "symbol" ? key : String(key);
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
var _excluded$4 = ["anchor", "focus"];
function ownKeys$g(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$g(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$g(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$g(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// eslint-disable-next-line no-redeclare
var Range = {
edges(range) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var {
reverse = false
} = options;
var {
anchor,
focus
} = range;
return Range.isBackward(range) === reverse ? [anchor, focus] : [focus, anchor];
},
end(range) {
var [, end] = Range.edges(range);
return end;
},
equals(range, another) {
return Point.equals(range.anchor, another.anchor) && Point.equals(range.focus, another.focus);
},
surrounds(range, target) {
var intersectionRange = Range.intersection(range, target);
if (!intersectionRange) {
return false;
}
return Range.equals(intersectionRange, target);
},
includes(range, target) {
if (Location.isRange(target)) {
if (Range.includes(range, target.anchor) || Range.includes(range, target.focus)) {
return true;
}
var [rs, re] = Range.edges(range);
var [ts, te] = Range.edges(target);
return Point.isBefore(rs, ts) && Point.isAfter(re, te);
}
var [start, end] = Range.edges(range);
var isAfterStart = false;
var isBeforeEnd = false;
if (Location.isPoint(target)) {
isAfterStart = Point.compare(target, start) >= 0;
isBeforeEnd = Point.compare(target, end) <= 0;
} else {
isAfterStart = Path.compare(target, start.path) >= 0;
isBeforeEnd = Path.compare(target, end.path) <= 0;
}
return isAfterStart && isBeforeEnd;
},
intersection(range, another) {
var {
anchor,
focus
} = range,
rest = _objectWithoutProperties(range, _excluded$4);
var [s1, e1] = Range.edges(range);
var [s2, e2] = Range.edges(another);
var start = Point.isBefore(s1, s2) ? s2 : s1;
var end = Point.isBefore(e1, e2) ? e1 : e2;
if (Point.isBefore(end, start)) {
return null;
} else {
return _objectSpread$g({
anchor: start,
focus: end
}, rest);
}
},
isBackward(range) {
var {
anchor,
focus
} = range;
return Point.isAfter(anchor, focus);
},
isCollapsed(range) {
var {
anchor,
focus
} = range;
return Point.equals(anchor, focus);
},
isExpanded(range) {
return !Range.isCollapsed(range);
},
isForward(range) {
return !Range.isBackward(range);
},
isRange(value) {
return isObject(value) && Point.isPoint(value.anchor) && Point.isPoint(value.focus);
},
*points(range) {
yield [range.anchor, 'anchor'];
yield [range.focus, 'focus'];
},
start(range) {
var [start] = Range.edges(range);
return start;
},
transform(range, op) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
if (range === null) {
return null;
}
var {
affinity = 'inward'
} = options;
var affinityAnchor;
var affinityFocus;
if (affinity === 'inward') {
// If the range is collapsed, make sure to use the same affinity to
// avoid the two points passing each other and expanding in the opposite
// direction
var isCollapsed = Range.isCollapsed(range);
if (Range.isForward(range)) {
affinityAnchor = 'forward';
affinityFocus = isCollapsed ? affinityAnchor : 'backward';
} else {
affinityAnchor = 'backward';
affinityFocus = isCollapsed ? affinityAnchor : 'forward';
}
} else if (affinity === 'outward') {
if (Range.isForward(range)) {
affinityAnchor = 'backward';
affinityFocus = 'forward';
} else {
affinityAnchor = 'forward';
affinityFocus = 'backward';
}
} else {
affinityAnchor = affinity;
affinityFocus = affinity;
}
var anchor = Point.transform(range.anchor, op, {
affinity: affinityAnchor
});
var focus = Point.transform(range.focus, op, {
affinity: affinityFocus
});
if (!anchor || !focus) {
return null;
}
return {
anchor,
focus
};
}
};
/**
* Shared the function with isElementType utility
*/
var isElement = function isElement(value) {
var {
deep = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!isObject(value)) return false;
// PERF: No need to use the full Editor.isEditor here
var isEditor = typeof value.apply === 'function';
if (isEditor) return false;
var isChildrenValid = deep ? Node.isNodeList(value.children) : Array.isArray(value.children);
return isChildrenValid;
};
// eslint-disable-next-line no-redeclare
var Element = {
isAncestor(value) {
var {
deep = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return isObject(value) && Node.isNodeList(value.children, {
deep
});
},
isElement,
isElementList(value) {
var {
deep = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return Array.isArray(value) && value.every(val => Element.isElement(val, {
deep
}));
},
isElementProps(props) {
return props.children !== undefined;
},
isElementType: function isElementType(value, elementVal) {
var elementKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'type';
return isElement(value) && value[elementKey] === elementVal;
},
matches(element, props) {
for (var key in props) {
if (key === 'children') {
continue;
}
if (element[key] !== props[key]) {
return false;
}
}
return true;
}
};
var _excluded$3 = ["text"],
_excluded2$3 = ["children"];
function ownKeys$f(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$f(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$f(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// eslint-disable-next-line no-redeclare
var Node = {
ancestor(root, path) {
var node = Node.get(root, path);
if (Node.isText(node)) {
throw new Error("Cannot get the ancestor node at path [".concat(path, "] because it refers to a text node instead: ").concat(Scrubber.stringify(node)));
}
return node;
},
ancestors(root, path) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return function* () {
for (var p of Path.ancestors(path, options)) {
var n = Node.ancestor(root, p);
var entry = [n, p];
yield entry;
}
}();
},
child(root, index) {
if (Node.isText(root)) {
throw new Error("Cannot get the child of a text node: ".concat(Scrubber.stringify(root)));
}
if (typeof index !== 'number') {
throw new Error('Expected index to be a number');
}
var c = root.children[index];
if (c == null) {
throw new Error("Cannot get child at index `".concat(index, "` in node: ").concat(Scrubber.stringify(root)));
}
return c;
},
children(root, path) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return function* () {
var {
reverse = false
} = options;
var ancestor = Node.ancestor(root, path);
var {
children
} = ancestor;
var index = reverse ? children.length - 1 : 0;
while (reverse ? index >= 0 : index < children.length) {
var child = Node.child(ancestor, index);
var childPath = path.concat(index);
yield [child, childPath];
index = reverse ? index - 1 : index + 1;
}
}();
},
common(root, path, another) {
var p = Path.common(path, another);
var n = Node.get(root, p);
return [n, p];
},
descendant(root, path) {
var node = Node.get(root, path);
if (Node.isEditor(node)) {
throw new Error("Cannot get the descendant node at path [".concat(path, "] because it refers to the root editor node instead: ").concat(Scrubber.stringify(node)));
}
return node;
},
descendants(root) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return function* () {
for (var [node, path] of Node.nodes(root, options)) {
if (path.length !== 0) {
// NOTE: we have to coerce here because checking the path's length does
// guarantee that `node` is not a `Editor`, but TypeScript doesn't know.
yield [node, path];
}
}
}();
},
elements(root) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return function* () {
for (var [node, path] of Node.nodes(root, options)) {
if (Node.isElement(node)) {
yield [node, path];
}
}
}();
},
extractProps(node) {
if (Node.isText(node)) {
var {
text
} = node,
properties = _objectWithoutProperties(node, _excluded$3);
return properties;
} else {
var {
children
} = node,
properties = _objectWithoutProperties(node, _excluded2$3);
return properties;
}
},
first(root, path) {
var p = path.slice();
var n = Node.get(root, p);
while (n) {
if (Node.isText(n) || n.children.length === 0) {
break;
} else {
n = n.children[0];
p.push(0);
}
}
return [n, p];
},
fragment(root, range) {
var newRoot = {
children: root.children
};
var [start, end] = Range.edges(range);
var nodeEntries = Node.nodes(newRoot, {
reverse: true,
pass: _ref => {
var [, path] = _ref;
return !Range.includes(range, path);
}
});
var _loop = function _loop() {
if (!Range.includes(range, path)) {
var index = path[path.length - 1];
modifyChildren(newRoot, Path.parent(path), children => removeChildren(children, index, 1));
}
if (Path.equals(path, end.path)) {
modifyLeaf(newRoot, path, node => {
var before = node.text.slice(0, end.offset);
return _objectSpread$f(_objectSpread$f({}, node), {}, {
text: before
});
});
}
if (Path.equals(path, start.path)) {
modifyLeaf(newRoot, path, node => {
var before = node.text.slice(start.offset);
return _objectSpread$f(_objectSpread$f({}, node), {}, {
text: before
});
});
}
};
for (var [, path] of nodeEntries) {
_loop();
}
return newRoot.children;
},
get(root, path) {
var node = Node.getIf(root, path);
if (node === undefined) {
throw new Error("Cannot find a descendant at path [".concat(path, "] in node: ").concat(Scrubber.stringify(root)));
}
return node;
},
getIf(root, path) {
var node = root;
for (var i = 0; i < path.length; i++) {
var p = path[i];
if (typeof p !== 'number') {
throw new Error('Got non-numeric path index');
}
if (Node.isText(node) || !node.children[p]) {
return;
}
node = node.children[p];
}
return node;
},
has(root, path) {
var node = root;
for (var i = 0; i < path.length; i++) {
var p = path[i];
if (typeof p !== 'number') {
throw new Error('Got non-numeric path index');
}
if (Node.isText(node) || !node.children[p]) {
return false;
}
node = node.children[p];
}
return true;
},
isAncestor(node) {
return !Node.isText(node);
},
isEditor(node) {
return typeof node.apply === 'function';
},
isElement(node) {
return Array.isArray(node.children) && typeof node.apply !== 'function';
},
isNode(value) {
var {
deep = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return Text.isText(value) || Element.isElement(value, {
deep
}) || Editor.isEditor(value, {
deep
});
},
isNodeList(value) {
var {
deep = false
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return Array.isArray(value) && value.every(val => Node.isNode(val, {
deep
}));
},
isText(node) {
return typeof node.text === 'string';
},
last(root, path) {
var p = path.slice();
var n = Node.get(root, p);
while (n) {
if (Node.isText(n) || n.children.length === 0) {
break;
} else {
var i = n.children.length - 1;
n = n.children[i];
p.push(i);
}
}
return [n, p];
},
leaf(root, path) {
var node = Node.get(root, path);
if (!Node.isText(node)) {
throw new Error("Cannot get the leaf node at path [".concat(path, "] because it refers to a non-leaf node: ").concat(Scrubber.stringify(node)));
}
return node;
},
levels(root, path) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return function* () {
for (var p of Path.levels(path, options)) {
var n = Node.get(root, p);
yield [n, p];
}
}();
},
matches(node, props) {
return Node.isElement(node) && Element.isElementProps(props) && Element.matches(node, props) || Node.isText(node) && Text.isTextProps(props) && Text.matches(node, props);
},
nodes(root) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return function* () {
var {
pass,
reverse = false
} = options;
var {
from = [],
to
} = options;
var visited = new Set();
var p = [];
var n = root;
while (true) {
if (to && (reverse ? Path.isBefore(p, to) : Path.isAfter(p, to))) {
break;
}
if (!visited.has(n)) {
yield [n, p];
}
// If we're allowed to go downward and we haven't descended yet, do.
if (!visited.has(n) && !Node.isText(n) && n.children.length !== 0 && (pass == null || pass([n, p]) === false)) {
visited.add(n);
var nextIndex = reverse ? n.children.length - 1 : 0;
if (Path.isAncestor(p, from)) {
nextIndex = from[p.length];
}
p = p.concat(nextIndex);
n = Node.get(root, p);
continue;
}
// If we're at the root and we can't go down, we're done.
if (p.length === 0) {
break;
}
// If we're going forward...
if (!reverse) {
var newPath = Path.next(p);
if (Node.has(root, newPath)) {
p = newPath;
n = Node.get(root, p);
continue;
}
}
// If we're going backward...
if (reverse && p[p.length - 1] !== 0) {
var _newPath = Path.previous(p);
p = _newPath;
n = Node.get(root, p);
continue;
}
// Otherwise we're going upward...
p = Path.parent(p);
n = Node.get(root, p);
visited.add(n);
}
}();
},
parent(root, path) {
var parentPath = Path.parent(path);
var node = Node.get(root, parentPath);
if (Node.isText(node)) {
// this can happen if `path` points somewhere that doesnt exist and it's where a child of a text node would be
throw new Error("Cannot get the parent of path [".concat(path, "] because it does not exist in the root."));
}
return node;
},
string(node) {
if (Node.isText(node)) {
return node.text;
} else {
return node.children.map(Node.string).join('');
}
},
texts(root) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return function* () {
for (var [node, path] of Node.nodes(root, options)) {
if (Node.isText(node)) {
yield [node, path];
}
}
}();
}
};
function ownKeys$e(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread$e(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$e(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$e(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// eslint-disable-next-line no-redeclare
var Operation = {
isNodeOperation(value) {
return Operation.isOperation(value) && value.type.endsWith('_node');
},
isOperation(value) {
if (!isObject(value)) {
return false;
}
switch (value.type) {
case 'insert_node':
return Path.isPath(value.path) && Node.isNode(value.node);
case 'insert_text':
return typeof value.offset === 'number' && typeof value.text === 'string' && Path.isPath(value.path);
case 'merge_node':
return typeof value.position === 'number' && Path.isPath(value.path) && isObject(value.properties);
case 'move_node':
return Path.isPath(value.path) && Path.isPath(value.newPath);
case 'remove_node':
return Path.isPath(value.path) && Node.isNode(value.node);
case 'remove_text':
return typeof value.offset === 'number' && typeof value.text === 'string' && Path.isPath(value.path);
case 'set_node':
return Path.isPath(value.path) && isObject(value.properties) && isObject(value.newProperties);
case 'set_selection':
return value.properties === null && Range.isRange(value.newProperties) || value.newProperties === null && Range.isRange(value.properties) || isObject(value.properties) && isObject(value.newProperties);
case 'split_node':
return Path.isPath(value.path) && typeof value.position === 'number' && isObject(value.properties);
default:
return false;
}
},
isOperationList(value) {
return Array.isArray(value) && value.every(val => Operation.isOperation(val));
},
isSelectionOperation(value) {
return Operation.isOperation(value) && value.type.endsWith('_selection');
},
isTextOperation(value) {
return Operation.isOperation(value) && value.type.endsWith('_text');
},
inverse(op) {
switch (op.type) {
case 'insert_node':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'remove_node'
});
}
case 'insert_text':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'remove_text'
});
}
case 'merge_node':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'split_node',
path: Path.previous(op.path)
});
}
case 'move_node':
{
var {
newPath,
path
} = op;
// PERF: in this case the move operation is a no-op anyways.
if (Path.equals(newPath, path)) {
return op;
}
// If the move happens completely within a single parent the path and
// newPath are stable with respect to each other.
if (Path.isSibling(path, newPath)) {
return _objectSpread$e(_objectSpread$e({}, op), {}, {
path: newPath,
newPath: path
});
}
// If the move does not happen within a single parent it is possible
// for the move to impact the true path to the location where the node
// was removed from and where it was inserted. We have to adjust for this
// and find the original path. We can accomplish this (only in non-sibling)
// moves by looking at the impact of the move operation on the node
// after the original move path.
var inversePath = Path.transform(path, op);
var inverseNewPath = Path.transform(Path.next(path), op);
return _objectSpread$e(_objectSpread$e({}, op), {}, {
path: inversePath,
newPath: inverseNewPath
});
}
case 'remove_node':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'insert_node'
});
}
case 'remove_text':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'insert_text'
});
}
case 'set_node':
{
var {
properties,
newProperties
} = op;
return _objectSpread$e(_objectSpread$e({}, op), {}, {
properties: newProperties,
newProperties: properties
});
}
case 'set_selection':
{
var {
properties: _properties,
newProperties: _newProperties
} = op;
if (_properties == null) {
return _objectSpread$e(_objectSpread$e({}, op), {}, {
properties: _newProperties,
newProperties: null
});
} else if (_newProperties == null) {
return _objectSpread$e(_objectSpread$e({}, op), {}, {
properties: null,
newProperties: _properties
});
} else {
return _objectSpread$e(_objectSpread$e({}, op), {}, {
properties: _newProperties,
newProperties: _properties
});
}
}
case 'split_node':
{
return _objectSpread$e(_objectSpread$e({}, op), {}, {
type: 'merge_node',
path: Path.next(op.path)
});
}
}
}
};
var isObject = value => typeof value === 'object' && value !== null;
/**
* Custom deep equal comparison for Slate nodes. Since Slate only supports plain
* values, arrays and nested objects, we don't need a general purpose deep
* equality check.
*
* Slate objects are designed to be serialised, so missing keys are deliberately
* normalised to undefined.
*/
var isDeepEqual = (a, b) => {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) {
if (!isDeepEqual(a[i], b[i])) return false;
}
return true;
}
if (isObject(a) && isObject(b)) {
for (var key in a) {
var valueA = Object.hasOwn(a, key) ? a[key] : undefined;
var valueB = Object.hasOwn(b, key) ? b[key] : undefined;
if (!isDeepEqual(valueA, valueB)) return false;
}
// Deep object equality is only necessary in one direction; in the reverse
// direction we are only looking for keys that are missing. As above,
// undefined keys treated the same as missing keys.
for (var _key in b) {
if (a[_key] === undefined && b[_key] !== undefined) return false;
}
return true;
}
return a === b;
};
/**
* Get the default location to insert content into the editor.
* By default, use the selection as the target location. But if there is
* no selection, insert at the end of the document since that is such a
* common use case when inserting from a non-selected state.
*/
var getDefaultInsertLocation = editor => {
if (editor.selection) {
return editor.selection;
} else if (editor.children.length > 0) {
return Editor.end(editor, []);
} else {
return [0];
}
};
var matchPath = (editor, path) => {
var [node] = Editor.node(editor, path);
return n => n === node;
};
// Character (grapheme cluster) boundaries are determined according to
// the default grapheme cluster boundary specification, extended grapheme clusters variant[1].
//
// References:
//
// [1] https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table
// [2] https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
// [3] https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.html
// [4] https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt
/**
* Get the distance to the end of the first character in a string of text.
*/
var getCharacterDistance = function getCharacterDistance(str) {
var isRTL = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isLTR = !isRTL;
var codepoints = isRTL ? codepointsIteratorRTL(str) : str;
var left = CodepointType.None;
var right = CodepointType.None;
var distance = 0;
// Evaluation of these conditions are deferred.
var gb11 = null; // Is GB11 applicable?
var gb12Or13 = null; // Is GB12 or GB13 applicable?
var gb9c = null; // Is GB9c applicable?
for (var char of codepoints) {
var code = char.codePointAt(0);
if (!code) break;
var type = getCodepointType(char, code);
[left, right] = isLTR ? [right, type] : [type, left];
if (intersects(left, CodepointType.ZWJ) && intersects(right, CodepointType.ExtPict)) {
if (isLTR) {
gb11 = endsWithEmojiZWJ(str.substring(0, distance));
} else {
gb11 = endsWithEmojiZWJ(str.substring(0, str.length - distance));
}
if (!gb11) break;
}
if (intersects(left, CodepointType.RI) && intersects(right, CodepointType.RI)) {
if (gb12Or13 !== null) {
gb12Or13 = !gb12Or13;
} else {
if (isLTR) {
gb12Or13 = true;
} else {
gb12Or13 = endsWithOddNumberOfRIs(str.substring(0, str.length - distance));
}
}
if (!gb12Or13) break;
}
if (intersects(left, CodepointType.InCBLinker | CodepointType.InCBExtend) && intersects(right, CodepointType.InCBConsonant)) {
if (isLTR) {
gb9c = endsWithConjunctLinker(str.substring(0, distance));
} else {
gb9c = endsWithConjunctLinker(str.substring(0, str.length - distance));
}
if (!gb9c) break;
}
if (left !== CodepointType.None && right !== CodepointType.None && isBoundaryPair(left, right)) {
break;
}
distance += char.length;
}
return distance || 1;
};
var SPACE = /\s/;
var PUNCTUATION = /[\u002B\u0021-\u0023\u0025-\u002A\u002C-\u002F\u003A\u003B\u003F\u0040\u005B-\u005D\u005F\u007B\u007D\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E3B\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/;
var CHAMELEON = /['\u2018\u2019]/;
/**
* Get the distance to the end of the first word in a string of text.
*/
var getWordDistance = function getWordDistance(text) {
var isRTL = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var dist = 0;
var started = false;
while (text.length > 0) {
var charDist = getCharacterDistance(text, isRTL);
var [char, remaining] = splitByCharacterDistance(text, charDist, isRTL);
if (isWordCharacter(char, remaining, isRTL)) {
started = true;
dist += charDist;
} else if (!started) {
dist += charDist;
} else {
break;
}
text = remaining;
}
return dist;
};
/**
* Split a string in two parts at a given distance starting from the end when
* `isRTL` is set to `true`.
*/
var splitByCharacterDistance = (str, dist, isRTL) => {
if (isRTL) {
var at = str.length - dist;
return [str.slice(at, str.length), str.slice(0, at)];
}
return [str.slice(0, dist), str.slice(dist)];
};
/**
* Check if a character is a word character. The `remaining` argument is used
* because sometimes you must read subsequent characters to truly determine it.
*/
var isWordCharacter = function isWordCharacter(char, remaining) {
var isRTL = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (SPACE.test(char)) {
return false;
}
// Chameleons count as word characters as long as they're in a word, so
// recurse to see if the next one is a word character or not.
if (CHAMELEON.test(char)) {
var charDist = getCharacterDistance(remaining, isRTL);
var [nextChar, nextRemaining] = splitByCharacterDistance(remaining, charDist, isRTL);
if (isWordCharacter(nextChar, nextRemaining, isRTL)) {
return true;
}
}
if (PUNCTUATION.test(char)) {
return false;
}
return true;
};
/**
* Iterate on codepoints from right to left.
*/
var codepointsIteratorRTL = function* codepointsIteratorRTL(str) {
var end = str.length - 1;
for (var i = 0; i < str.length; i++) {
var char1 = str.charAt(end - i);
if (isLowSurrogate(char1.charCodeAt(0))) {
var char2 = str.charAt(end - i - 1);
if (isHighSurrogate(char2.charCodeAt(0))) {
yield char2 + char1;
i++;
continue;
}
}
yield char1;
}
};
/**
* Is `charCode` a high surrogate.
*
* https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates
*/
var isHighSurrogate = charCode => {
return charCode >= 0xd800 && charCode <= 0xdbff;
};
/**
* Is `charCode` a low surrogate.
*
* https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates
*/
var isLowSurrogate = charCode => {
return charCode >= 0xdc00 && charCode <= 0xdfff;
};
var CodepointType;
(function (CodepointType) {
CodepointType[CodepointType["None"] = 0] = "None";
CodepointType[CodepointType["Extend"] = 1] = "Extend";
CodepointType[CodepointType["ZWJ"] = 2] = "ZWJ";
CodepointType[CodepointType["RI"] = 4] = "RI";
CodepointType[CodepointType["Prepend"] = 8] = "Prepend";
CodepointType[CodepointType["SpacingMark"] = 16] = "SpacingMark";
CodepointType[CodepointType["L"] = 32] = "L";
CodepointType[CodepointType["V"] = 64] = "V";
CodepointType[CodepointType["T"] = 128] = "T";
CodepointType[CodepointType["LV"] = 256] = "LV";
CodepointType[CodepointType["LVT"] = 512] = "LVT";
CodepointType[CodepointType["ExtPict"] = 1024] = "ExtPict";
CodepointType[CodepointType["Any"] = 2048] = "Any";
CodepointType[CodepointType["InCBConsonant"] = 4096] = "InCBConsonant";
CodepointType[CodepointType["InCBExtend"] = 8192] = "InCBExtend";
CodepointType[CodepointType["InCBLinker"] = 16384] = "InCBLinker";
})(CodepointType || (CodepointType = {}));
var reExtend = /^(?:[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0898-\u089F\u08CA-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09BE\u09C1-\u09C4\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3E\u0B3F\u0B41-\u0B44\u0B4D\u0B55-\u0B57\u0B62\u0B63\u0B82\u0BBE\u0BC0\u0BCD\u0BD7\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CBF\u0CC2\u0CC6\u0CCC\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D3E\u0D41-\u0D44\u0D4D\u0D57\u0D62\u0D63\u0D81\u0DCA\u0DCF\u0DD2-\u0DD4\u0DD6\u0DDF\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1ACE\u1B00-\u1B03\u1B34-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u200C\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFF9E\uFF9F]|\uD800[\uDDFD\uDEE0\uDF76-\uDF7A]|\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD24-\uDD27\uDEAB\uDEAC\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC01\uDC38-\uDC46\uDC70\uDC73\uDC74\uDC7F-\uDC81\uDCB3-\uDCB6\uDCB9\uDCBA\uDCC2\uDD00-\uDD02\uDD27-\uDD2B\uDD2D-\uDD34\uDD73\uDD80\uDD81\uDDB6-\uDDBE\uDDC9-\uDDCC\uDDCF\uDE2F-\uDE31\uDE34\uDE36\uDE37\uDE3E\uDE41\uDEDF\uDEE3-\uDEEA\uDF00\uDF01\uDF3B\uDF3C\uDF3E\uDF40\uDF57\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC38-\uDC3F\uDC42-\uDC44\uDC46\uDC5E\uDCB0\uDCB3-\uDCB8\uDCBA\uDCBD\uDCBF\uDCC0\uDCC2\uDCC3\uDDAF\uDDB2-\uDDB5\uDDBC\uDDBD\uDDBF\uDDC0\uDDDC\uDDDD\uDE33-\uDE3A\uDE3D\uDE3F\uDE40\uDEAB\uDEAD\uDEB0-\uDEB5\uDEB7\uDF1D-\uDF1F\uDF22-\uDF25\uDF27-\uDF2B]|\uD806[\uDC2F-\uDC37\uDC39\uDC3A\uDD30\uDD3B\uDD3C\uDD3E\uDD43\uDDD4-\uDDD7\uDDDA\uDDDB\uDDE0\uDE01-\uDE0A\uDE33-\uDE38\uDE3B-\uDE3E\uDE47\uDE51-\uDE56\uDE59-\uDE5B\uDE8A-\uDE96\uDE98\uDE99]|\uD807[\uDC30-\uDC36\uDC38-\uDC3D\uDC3F\uDC92-\uDCA7\uDCAA-\uDCB0\uDCB2\uDCB3\uDCB5\uDCB6\uDD31-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD45\uDD47\uDD90\uDD91\uDD95\uDD97\uDEF3\uDEF4\uDF00\uDF01\uDF36-\uDF3A\uDF40\uDF42]|\uD80D[\uDC40\uDC47-\uDC55]|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDF4F\uDF8F-\uDF92\uDFE4]|\uD82F[\uDC9D\uDC9E]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD65\uDD67-\uDD69\uDD6E-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A\uDC8F\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDCEC-\uDCEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD4A]|\uD83C[\uDFFB-\uDFFF]|\uDB40[\uDC20-\uDC7F\uDD00-\uDDEF])$/;
var rePrepend = /^(?:[\u0600-\u0605\u06DD\u070F\u0890\u0891\u08E2\u0D4E]|\uD804[\uDCBD\uDCCD\uDDC2\uDDC3]|\uD806[\uDD3F\uDD41\uDE3A\uDE84-\uDE89]|\uD807\uDD46)$/;
var reSpacingMark = /^(?:[\u0903\u093B\u093E-\u0940\u0949-\u094C\u094E\u094F\u0982\u0983\u09BF\u09C0\u09C7\u09C8\u09CB\u09CC\u0A03\u0A3E-\u0A40\u0A83\u0ABE-\u0AC0\u0AC9\u0ACB\u0ACC\u0B02\u0B03\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0C01-\u0C03\u0C41-\u0C44\u0C82\u0C83\u0CBE\u0CC0\u0CC1\u0CC3\u0CC4\u0CC7\u0CC8\u0CCA\u0CCB\u0D02\u0D03\u0D3F\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D82\u0D83\u0DD0\u0DD1\u0DD8-\u0DDE\u0DF2\u0DF3\u0E33\u0EB3\u0F3E\u0F3F\u0F7F\u1031\u103B\u103C\u1056\u1057\u1084\u1715\u1734\u17B6\u17BE-\u17C5\u17C7\u17C8\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u1A19\u1A1A\u1A55\u1A57\u1A6D-\u1A72\u1B04\u1B3B\u1B3D-\u1B41\u1B43\u1B44\u1B82\u1BA1\u1BA6\u1BA7\u1BAA\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1C24-\u1C2B\u1C34\u1C35\u1CE1\u1CF7\uA823\uA824\uA827\uA880\uA881\uA8B4-\uA8C3\uA952\uA953\uA983\uA9B4\uA9B5\uA9BA\uA9BB\uA9BE-\uA9C0\uAA2F\uAA30\uAA33\uAA34\uAA4D\uAAEB\uAAEE\uAAEF\uAAF5\uABE3\uABE4\uABE6\uABE7\uABE9\uABEA\uABEC]|\uD804[\uDC00\uDC02\uDC82\uDCB0-\uDCB2\uDCB7\uDCB8\uDD2C\uDD45\uDD46\uDD82\uDDB3-\uDDB5\uDDBF\uDDC0\uDDCE\uDE2C-\uDE2E\uDE32\uDE33\uDE35\uDEE0-\uDEE2\uDF02\uDF03\uDF3F\uDF41-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF62\uDF63]|\uD805[\uDC35-\uDC37\uDC40\uDC41\uDC45\uDCB1\uDCB2\uDCB9\uDCBB\uDCBC\uDCBE\uDCC1\uDDB0\uDDB1\uDDB8-\uDDBB\uDDBE\uDE30-\uDE32\uDE3B\uDE3C\uDE3E\uDEAC\uDEAE\uDEAF\uDEB6\uDF26]|\uD806[\uDC2C-\uDC2E\uDC38\uDD31-\uDD35\uDD37\uDD38\uDD3D\uDD40\uDD42\uDDD1-\uDDD3\uDDDC-\uDDDF\uDDE4\uDE39\uDE57\uDE58\uDE97]|\uD807[\uDC2F\uDC3E\uDCA9\uDCB1\uDCB4\uDD8A-\uDD8E\uDD93\uDD94\uDD96\uDEF5\uDEF6]|\uD81B[\uDF51-\uDF87\uDFF0\uDFF1]|\uD834[\uDD66\uDD6D])$/;
var reL = /^[\u1100-\u115F\uA960-\uA97C]$/;
var reV = /^[\u1160-\u11A7\uD7B0-\uD7C6]$/;
var reT = /^[\u11A8-\u11FF\uD7CB-\uD7FB]$/;
var reLV = /^[\uAC00\uAC1C\uAC38\uAC54\uAC70\uAC8C\uACA8\uACC4\uACE0\uACFC\uAD18\uAD34\uAD50\uAD6C\uAD88\uADA4\uADC0\uADDC\uADF8\uAE14\uAE30\uAE4C\uAE68\uAE84\uAEA0\uAEBC\uAED8\uAEF4\uAF10\uAF2C\uAF48\uAF64\uAF80\uAF9C\uAFB8\uAFD4\uAFF0\uB00C\uB028\uB044\uB060\uB07C\uB098\uB0B4\uB0D0\uB0EC\uB108\uB124\uB140\uB15C\uB178\uB194\uB1B0\uB1CC\uB1E8\uB204\uB220\uB23C\uB258\uB274\uB290\uB2AC\uB2C8\uB2E4\uB300\uB31C\uB338\uB354\uB37