slate-react 0.115.0 → 0.116.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/chunking/children-helper.d.ts +61 -0
  2. package/dist/chunking/children-helper.d.ts.map +1 -0
  3. package/dist/chunking/chunk-tree-helper.d.ts +160 -0
  4. package/dist/chunking/chunk-tree-helper.d.ts.map +1 -0
  5. package/dist/chunking/get-chunk-tree-for-node.d.ts +16 -0
  6. package/dist/chunking/get-chunk-tree-for-node.d.ts.map +1 -0
  7. package/dist/chunking/index.d.ts +3 -0
  8. package/dist/chunking/index.d.ts.map +1 -0
  9. package/dist/chunking/reconcile-children.d.ts +19 -0
  10. package/dist/chunking/reconcile-children.d.ts.map +1 -0
  11. package/dist/chunking/types.d.ts +44 -0
  12. package/dist/chunking/types.d.ts.map +1 -0
  13. package/dist/components/chunk-tree.d.ts +13 -0
  14. package/dist/components/chunk-tree.d.ts.map +1 -0
  15. package/dist/components/editable.d.ts +13 -0
  16. package/dist/components/editable.d.ts.map +1 -1
  17. package/dist/components/element.d.ts +4 -4
  18. package/dist/components/element.d.ts.map +1 -1
  19. package/dist/components/leaf.d.ts.map +1 -1
  20. package/dist/components/slate.d.ts.map +1 -1
  21. package/dist/components/text.d.ts +1 -1
  22. package/dist/components/text.d.ts.map +1 -1
  23. package/dist/hooks/use-children.d.ts +4 -4
  24. package/dist/hooks/use-children.d.ts.map +1 -1
  25. package/dist/hooks/use-decorations.d.ts +18 -0
  26. package/dist/hooks/use-decorations.d.ts.map +1 -0
  27. package/dist/hooks/use-element.d.ts +12 -0
  28. package/dist/hooks/use-element.d.ts.map +1 -0
  29. package/dist/hooks/use-generic-selector.d.ts +20 -0
  30. package/dist/hooks/use-generic-selector.d.ts.map +1 -0
  31. package/dist/hooks/use-selected.d.ts +0 -5
  32. package/dist/hooks/use-selected.d.ts.map +1 -1
  33. package/dist/hooks/use-slate-selector.d.ts +30 -15
  34. package/dist/hooks/use-slate-selector.d.ts.map +1 -1
  35. package/dist/hooks/use-slate.d.ts +7 -14
  36. package/dist/hooks/use-slate.d.ts.map +1 -1
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.es.js +1154 -232
  40. package/dist/index.es.js.map +1 -1
  41. package/dist/index.js +1328 -343
  42. package/dist/index.js.map +1 -1
  43. package/dist/plugin/react-editor.d.ts +7 -0
  44. package/dist/plugin/react-editor.d.ts.map +1 -1
  45. package/dist/plugin/with-react.d.ts.map +1 -1
  46. package/dist/slate-react.js +1385 -346
  47. package/dist/slate-react.min.js +1 -1
  48. package/package.json +5 -4
  49. package/dist/hooks/use-decorate.d.ts +0 -11
  50. package/dist/hooks/use-decorate.d.ts.map +0 -1
package/dist/index.es.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import getDirection from 'direction';
2
2
  import debounce from 'lodash/debounce';
3
3
  import throttle from 'lodash/throttle';
4
- import React, { createContext, useContext, useRef, useEffect, useLayoutEffect, useState, memo, forwardRef, useCallback, Component, useReducer, useMemo } from 'react';
4
+ import React, { createContext, useContext, useRef, useEffect, useLayoutEffect, useState, memo, forwardRef, useCallback, useReducer, useMemo, Fragment, Component } from 'react';
5
5
  import scrollIntoView from 'scroll-into-view-if-needed';
6
6
  import { Editor, Range, Transforms, Node, Text as Text$1, Path, Point, Element as Element$1, Scrubber } from 'slate';
7
- import { DOMEditor, EDITOR_TO_USER_MARKS, EDITOR_TO_PENDING_DIFFS, EDITOR_TO_PENDING_ACTION, EDITOR_TO_PENDING_INSERTION_MARKS, targetRange, verifyDiffState, EDITOR_TO_PENDING_SELECTION, IS_COMPOSING, IS_NODE_MAP_DIRTY, applyStringDiff, isDOMSelection, isTrackedMutation, EDITOR_TO_FORCE_RENDER, normalizeRange, normalizePoint, EDITOR_TO_PLACEHOLDER_ELEMENT, normalizeStringDiff, mergeStringDiffs, CAN_USE_DOM, IS_ANDROID, EDITOR_TO_SCHEDULE_FLUSH, MARK_PLACEHOLDER_SYMBOL, PLACEHOLDER_SYMBOL, IS_WEBKIT, isTextDecorationsEqual, EDITOR_TO_KEY_TO_ELEMENT, NODE_TO_ELEMENT, ELEMENT_TO_NODE, isElementDecorationsEqual, NODE_TO_INDEX, NODE_TO_PARENT, IS_READ_ONLY, getActiveElement, getSelection, IS_FOCUSED, getDefaultView, EDITOR_TO_WINDOW, EDITOR_TO_ELEMENT, IS_FIREFOX, EDITOR_TO_USER_SELECTION, HAS_BEFORE_INPUT_SUPPORT, isDOMElement, isDOMNode, TRIPLE_CLICK, IS_FIREFOX_LEGACY, IS_IOS, IS_WECHATBROWSER, IS_UC_MOBILE, Hotkeys, IS_CHROME, isPlainTextOnlyPaste, EDITOR_TO_ON_CHANGE, withDOM } from 'slate-dom';
7
+ import { DOMEditor, EDITOR_TO_USER_MARKS, EDITOR_TO_PENDING_DIFFS, EDITOR_TO_PENDING_ACTION, EDITOR_TO_PENDING_INSERTION_MARKS, targetRange, verifyDiffState, EDITOR_TO_PENDING_SELECTION, IS_COMPOSING, IS_NODE_MAP_DIRTY, applyStringDiff, isDOMSelection, isTrackedMutation, EDITOR_TO_FORCE_RENDER, normalizeRange, normalizePoint, EDITOR_TO_PLACEHOLDER_ELEMENT, normalizeStringDiff, mergeStringDiffs, CAN_USE_DOM, IS_ANDROID, EDITOR_TO_SCHEDULE_FLUSH, MARK_PLACEHOLDER_SYMBOL, PLACEHOLDER_SYMBOL, IS_WEBKIT, isTextDecorationsEqual, isElementDecorationsEqual, EDITOR_TO_KEY_TO_ELEMENT, NODE_TO_ELEMENT, ELEMENT_TO_NODE, NODE_TO_INDEX, NODE_TO_PARENT, Key, splitDecorationsByChild, IS_READ_ONLY, getActiveElement, getSelection, IS_FOCUSED, getDefaultView, EDITOR_TO_WINDOW, EDITOR_TO_ELEMENT, IS_FIREFOX, EDITOR_TO_USER_SELECTION, HAS_BEFORE_INPUT_SUPPORT, isDOMElement, isDOMNode, TRIPLE_CLICK, IS_FIREFOX_LEGACY, IS_IOS, IS_WECHATBROWSER, IS_UC_MOBILE, Hotkeys, IS_CHROME, isPlainTextOnlyPaste, EDITOR_TO_ON_CHANGE, withDOM } from 'slate-dom';
8
8
  export { NODE_TO_INDEX, NODE_TO_PARENT } from 'slate-dom';
9
9
  import { ResizeObserver } from '@juggle/resize-observer';
10
10
  import ReactDOM from 'react-dom';
@@ -97,8 +97,8 @@ var useSlateStatic = () => {
97
97
  // eslint-disable-next-line no-redeclare
98
98
  var ReactEditor = DOMEditor;
99
99
 
100
- function ownKeys$6(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; }
101
- function _objectSpread$6(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$6(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
100
+ function ownKeys$7(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; }
101
+ function _objectSpread$7(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$7(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$7(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
102
102
  // https://github.com/facebook/draft-js/blob/main/src/component/handlers/composition/DraftEditorCompositionHandler.js#L41
103
103
  // When using keyboard English association function, conpositionEnd triggered too fast, resulting in after `insertText` still maintain association state.
104
104
  var RESOLVE_DELAY = 25;
@@ -294,7 +294,7 @@ function createAndroidInputManager(_ref) {
294
294
  updatePlaceholderVisibility();
295
295
  return;
296
296
  }
297
- pendingDiffs[idx] = _objectSpread$6(_objectSpread$6({}, pendingDiffs[idx]), {}, {
297
+ pendingDiffs[idx] = _objectSpread$7(_objectSpread$7({}, pendingDiffs[idx]), {}, {
298
298
  diff: merged
299
299
  });
300
300
  };
@@ -612,7 +612,7 @@ function createAndroidInputManager(_ref) {
612
612
  if (insertPositionHint === null) {
613
613
  insertPositionHint = _diff;
614
614
  } else if (insertPositionHint && Range.isCollapsed(targetRange) && insertPositionHint.end + insertPositionHint.text.length === _start2.offset) {
615
- insertPositionHint = _objectSpread$6(_objectSpread$6({}, insertPositionHint), {}, {
615
+ insertPositionHint = _objectSpread$7(_objectSpread$7({}, insertPositionHint), {}, {
616
616
  text: insertPositionHint.text + _text
617
617
  });
618
618
  } else {
@@ -748,8 +748,8 @@ function useMutationObserver(node, callback, options) {
748
748
  }
749
749
 
750
750
  var _excluded$2 = ["node"];
751
- function ownKeys$5(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; }
752
- function _objectSpread$5(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$5(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$5(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
751
+ function ownKeys$6(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; }
752
+ function _objectSpread$6(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$6(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$6(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
753
753
  var MUTATION_OBSERVER_CONFIG$1 = {
754
754
  subtree: true,
755
755
  childList: true,
@@ -765,7 +765,7 @@ var useAndroidInputManager = !IS_ANDROID ? () => null : _ref => {
765
765
  }
766
766
  var editor = useSlateStatic();
767
767
  var isMounted = useIsMounted();
768
- var [inputManager] = useState(() => createAndroidInputManager(_objectSpread$5({
768
+ var [inputManager] = useState(() => createAndroidInputManager(_objectSpread$6({
769
769
  editor
770
770
  }, options)));
771
771
  useMutationObserver(node, inputManager.handleDomMutations, MUTATION_OBSERVER_CONFIG$1);
@@ -776,8 +776,8 @@ var useAndroidInputManager = !IS_ANDROID ? () => null : _ref => {
776
776
  return inputManager;
777
777
  };
778
778
 
779
- function ownKeys$4(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; }
780
- function _objectSpread$4(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$4(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$4(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
779
+ function ownKeys$5(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; }
780
+ function _objectSpread$5(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$5(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$5(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
781
781
  /**
782
782
  * Leaf content strings.
783
783
  */
@@ -894,11 +894,11 @@ var ZeroWidthString = props => {
894
894
  // be because accepting an IME suggestion when at the start of a block (no
895
895
  // preceding \uFEFF) removes one or more DOM elements that `toSlateRange`
896
896
  // depends on. (https://github.com/ianstormtaylor/slate/issues/5703)
897
- return /*#__PURE__*/React.createElement("span", _objectSpread$4({}, attributes), !IS_ANDROID || !isLineBreak ? '\uFEFF' : null, isLineBreak ? /*#__PURE__*/React.createElement("br", null) : null);
897
+ return /*#__PURE__*/React.createElement("span", _objectSpread$5({}, attributes), !IS_ANDROID || !isLineBreak ? '\uFEFF' : null, isLineBreak ? /*#__PURE__*/React.createElement("br", null) : null);
898
898
  };
899
899
 
900
- function ownKeys$3(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; }
901
- function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$3(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$3(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
900
+ function ownKeys$4(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; }
901
+ function _objectSpread$4(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$4(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$4(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
902
902
  // Delay the placeholder on Android to prevent the keyboard from closing.
903
903
  // (https://github.com/ianstormtaylor/slate/pull/5368)
904
904
  var PLACEHOLDER_DELAY = IS_ANDROID ? 300 : 0;
@@ -916,6 +916,7 @@ function clearTimeoutRef(timeoutRef) {
916
916
  timeoutRef.current = null;
917
917
  }
918
918
  }
919
+ var defaultRenderLeaf = props => /*#__PURE__*/React.createElement(DefaultLeaf, _objectSpread$4({}, props));
919
920
  /**
920
921
  * Individual leaves in a text node with unique formatting.
921
922
  */
@@ -926,7 +927,7 @@ var Leaf = props => {
926
927
  text,
927
928
  parent,
928
929
  renderPlaceholder,
929
- renderLeaf = props => /*#__PURE__*/React.createElement(DefaultLeaf, _objectSpread$3({}, props)),
930
+ renderLeaf = defaultRenderLeaf,
930
931
  leafPosition
931
932
  } = props;
932
933
  var editor = useSlateStatic();
@@ -1022,26 +1023,145 @@ var DefaultLeaf = props => {
1022
1023
  attributes,
1023
1024
  children
1024
1025
  } = props;
1025
- return /*#__PURE__*/React.createElement("span", _objectSpread$3({}, attributes), children);
1026
+ return /*#__PURE__*/React.createElement("span", _objectSpread$4({}, attributes), children);
1026
1027
  };
1027
1028
 
1028
- function ownKeys$2(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; }
1029
- function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1029
+ /**
1030
+ * Create a selector that updates when an `update` function is called, and
1031
+ * which only causes the component to render when the result of `selector`
1032
+ * differs from the previous result according to `equalityFn`.
1033
+ *
1034
+ * If `selector` is memoized using `useCallback`, then it will only be called
1035
+ * when it changes or when `update` is called. Otherwise, `selector` will be
1036
+ * called every time the component renders.
1037
+ *
1038
+ * @example
1039
+ * const [state, update] = useGenericSelector(selector, equalityFn)
1040
+ *
1041
+ * useIsomorphicLayoutEffect(() => {
1042
+ * return addEventListener(update)
1043
+ * }, [addEventListener, update])
1044
+ *
1045
+ * return state
1046
+ */
1047
+ function useGenericSelector(selector, equalityFn) {
1048
+ var [, forceRender] = useReducer(s => s + 1, 0);
1049
+ var latestSubscriptionCallbackError = useRef();
1050
+ var latestSelector = useRef(() => null);
1051
+ var latestSelectedState = useRef(null);
1052
+ var selectedState;
1053
+ try {
1054
+ if (selector !== latestSelector.current || latestSubscriptionCallbackError.current) {
1055
+ var selectorResult = selector();
1056
+ if (equalityFn(latestSelectedState.current, selectorResult)) {
1057
+ selectedState = latestSelectedState.current;
1058
+ } else {
1059
+ selectedState = selectorResult;
1060
+ }
1061
+ } else {
1062
+ selectedState = latestSelectedState.current;
1063
+ }
1064
+ } catch (err) {
1065
+ if (latestSubscriptionCallbackError.current && isError(err)) {
1066
+ err.message += "\nThe error may be correlated with this previous error:\n".concat(latestSubscriptionCallbackError.current.stack, "\n\n");
1067
+ }
1068
+ throw err;
1069
+ }
1070
+ latestSelector.current = selector;
1071
+ latestSelectedState.current = selectedState;
1072
+ latestSubscriptionCallbackError.current = undefined;
1073
+ var update = useCallback(() => {
1074
+ try {
1075
+ var newSelectedState = latestSelector.current();
1076
+ if (equalityFn(latestSelectedState.current, newSelectedState)) {
1077
+ return;
1078
+ }
1079
+ latestSelectedState.current = newSelectedState;
1080
+ } catch (err) {
1081
+ // we ignore all errors here, since when the component
1082
+ // is re-rendered, the selectors are called again, and
1083
+ // will throw again, if neither props nor store state
1084
+ // changed
1085
+ if (err instanceof Error) {
1086
+ latestSubscriptionCallbackError.current = err;
1087
+ } else {
1088
+ latestSubscriptionCallbackError.current = new Error(String(err));
1089
+ }
1090
+ }
1091
+ forceRender();
1092
+ // don't rerender on equalityFn change since we want to be able to define it inline
1093
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1094
+ }, []);
1095
+ return [selectedState, update];
1096
+ }
1097
+ function isError(error) {
1098
+ return error instanceof Error;
1099
+ }
1100
+
1101
+ /**
1102
+ * A React context for sharing the `decorate` prop of the editable and
1103
+ * subscribing to changes on this prop.
1104
+ */
1105
+ var DecorateContext = /*#__PURE__*/createContext({});
1106
+ var useDecorations = (node, parentDecorations) => {
1107
+ var editor = useSlateStatic();
1108
+ var {
1109
+ decorate,
1110
+ addEventListener
1111
+ } = useContext(DecorateContext);
1112
+ // Not memoized since we want nodes to be decorated on each render
1113
+ var selector = () => {
1114
+ var path = ReactEditor.findPath(editor, node);
1115
+ return decorate([node, path]);
1116
+ };
1117
+ var equalityFn = Text$1.isText(node) ? isTextDecorationsEqual : isElementDecorationsEqual;
1118
+ var [decorations, update] = useGenericSelector(selector, equalityFn);
1119
+ useIsomorphicLayoutEffect(() => {
1120
+ var unsubscribe = addEventListener(update);
1121
+ update();
1122
+ return unsubscribe;
1123
+ }, [addEventListener, update]);
1124
+ return useMemo(() => [...decorations, ...parentDecorations], [decorations, parentDecorations]);
1125
+ };
1126
+ var useDecorateContext = decorateProp => {
1127
+ var eventListeners = useRef(new Set());
1128
+ var latestDecorate = useRef(decorateProp);
1129
+ useIsomorphicLayoutEffect(() => {
1130
+ latestDecorate.current = decorateProp;
1131
+ eventListeners.current.forEach(listener => listener());
1132
+ }, [decorateProp]);
1133
+ var decorate = useCallback(entry => latestDecorate.current(entry), []);
1134
+ var addEventListener = useCallback(callback => {
1135
+ eventListeners.current.add(callback);
1136
+ return () => {
1137
+ eventListeners.current.delete(callback);
1138
+ };
1139
+ }, []);
1140
+ return useMemo(() => ({
1141
+ decorate,
1142
+ addEventListener
1143
+ }), [decorate, addEventListener]);
1144
+ };
1145
+
1146
+ function ownKeys$3(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; }
1147
+ function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$3(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$3(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1148
+ var defaultRenderText = props => /*#__PURE__*/React.createElement(DefaultText, _objectSpread$3({}, props));
1030
1149
  /**
1031
1150
  * Text.
1032
1151
  */
1033
1152
  var Text = props => {
1034
1153
  var {
1035
- decorations,
1154
+ decorations: parentDecorations,
1036
1155
  isLast,
1037
1156
  parent,
1038
1157
  renderPlaceholder,
1039
1158
  renderLeaf,
1040
- renderText = props => /*#__PURE__*/React.createElement(DefaultText, _objectSpread$2({}, props)),
1159
+ renderText = defaultRenderText,
1041
1160
  text
1042
1161
  } = props;
1043
1162
  var editor = useSlateStatic();
1044
1163
  var ref = useRef(null);
1164
+ var decorations = useDecorations(text, parentDecorations);
1045
1165
  var decoratedLeaves = Text$1.decorations(text, decorations);
1046
1166
  var key = ReactEditor.findKey(editor, text);
1047
1167
  var children = [];
@@ -1095,27 +1215,29 @@ var DefaultText = props => {
1095
1215
  attributes,
1096
1216
  children
1097
1217
  } = props;
1098
- return /*#__PURE__*/React.createElement("span", _objectSpread$2({}, attributes), children);
1218
+ return /*#__PURE__*/React.createElement("span", _objectSpread$3({}, attributes), children);
1099
1219
  };
1100
1220
 
1101
- function ownKeys$1(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; }
1102
- function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1221
+ function ownKeys$2(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; }
1222
+ function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1223
+ var defaultRenderElement = props => /*#__PURE__*/React.createElement(DefaultElement, _objectSpread$2({}, props));
1103
1224
  /**
1104
1225
  * Element.
1105
1226
  */
1106
1227
  var Element = props => {
1107
1228
  var {
1108
- decorations,
1229
+ decorations: parentDecorations,
1109
1230
  element,
1110
- renderElement = p => /*#__PURE__*/React.createElement(DefaultElement, _objectSpread$1({}, p)),
1231
+ renderElement = defaultRenderElement,
1232
+ renderChunk,
1111
1233
  renderPlaceholder,
1112
1234
  renderLeaf,
1113
- renderText,
1114
- selection
1235
+ renderText
1115
1236
  } = props;
1116
1237
  var editor = useSlateStatic();
1117
1238
  var readOnly = useReadOnly();
1118
1239
  var isInline = editor.isInline(element);
1240
+ var decorations = useDecorations(element, parentDecorations);
1119
1241
  var key = ReactEditor.findKey(editor, element);
1120
1242
  var ref = useCallback(ref => {
1121
1243
  // Update element-related weak maps with the DOM element ref.
@@ -1133,10 +1255,10 @@ var Element = props => {
1133
1255
  decorations,
1134
1256
  node: element,
1135
1257
  renderElement,
1258
+ renderChunk,
1136
1259
  renderPlaceholder,
1137
1260
  renderLeaf,
1138
- renderText,
1139
- selection
1261
+ renderText
1140
1262
  });
1141
1263
  // Attributes that the developer must mix into the element in their
1142
1264
  // custom node renderer component.
@@ -1189,7 +1311,7 @@ var Element = props => {
1189
1311
  });
1190
1312
  };
1191
1313
  var MemoizedElement = /*#__PURE__*/React.memo(Element, (prev, next) => {
1192
- return prev.element === next.element && prev.renderElement === next.renderElement && prev.renderText === next.renderText && prev.renderLeaf === next.renderLeaf && prev.renderPlaceholder === next.renderPlaceholder && isElementDecorationsEqual(prev.decorations, next.decorations) && (prev.selection === next.selection || !!prev.selection && !!next.selection && Range.equals(prev.selection, next.selection));
1314
+ return prev.element === next.element && prev.renderElement === next.renderElement && prev.renderChunk === next.renderChunk && prev.renderText === next.renderText && prev.renderLeaf === next.renderLeaf && prev.renderPlaceholder === next.renderPlaceholder && isElementDecorationsEqual(prev.decorations, next.decorations);
1193
1315
  });
1194
1316
  /**
1195
1317
  * The default element renderer.
@@ -1202,7 +1324,7 @@ var DefaultElement = props => {
1202
1324
  } = props;
1203
1325
  var editor = useSlateStatic();
1204
1326
  var Tag = editor.isInline(element) ? 'span' : 'div';
1205
- return /*#__PURE__*/React.createElement(Tag, _objectSpread$1(_objectSpread$1({}, attributes), {}, {
1327
+ return /*#__PURE__*/React.createElement(Tag, _objectSpread$2(_objectSpread$2({}, attributes), {}, {
1206
1328
  style: {
1207
1329
  position: 'relative'
1208
1330
  }
@@ -1210,26 +1332,732 @@ var DefaultElement = props => {
1210
1332
  };
1211
1333
 
1212
1334
  /**
1213
- * A React context for sharing the `decorate` prop of the editable.
1335
+ * Traverse and modify a chunk tree
1336
+ */
1337
+ class ChunkTreeHelper {
1338
+ constructor(chunkTree, _ref) {
1339
+ var {
1340
+ chunkSize,
1341
+ debug
1342
+ } = _ref;
1343
+ /**
1344
+ * The root of the chunk tree
1345
+ */
1346
+ _defineProperty(this, "root", void 0);
1347
+ /**
1348
+ * The ideal size of a chunk
1349
+ */
1350
+ _defineProperty(this, "chunkSize", void 0);
1351
+ /**
1352
+ * Whether debug mode is enabled
1353
+ *
1354
+ * If enabled, the pointer state will be checked for internal consistency
1355
+ * after each mutating operation.
1356
+ */
1357
+ _defineProperty(this, "debug", void 0);
1358
+ /**
1359
+ * Whether the traversal has reached the end of the chunk tree
1360
+ *
1361
+ * When this is true, the pointerChunk and pointerIndex point to the last
1362
+ * top-level node in the chunk tree, although pointerNode returns null.
1363
+ */
1364
+ _defineProperty(this, "reachedEnd", void 0);
1365
+ /**
1366
+ * The chunk containing the current node
1367
+ */
1368
+ _defineProperty(this, "pointerChunk", void 0);
1369
+ /**
1370
+ * The index of the current node within pointerChunk
1371
+ *
1372
+ * Can be -1 to indicate that the pointer is before the start of the tree.
1373
+ */
1374
+ _defineProperty(this, "pointerIndex", void 0);
1375
+ /**
1376
+ * Similar to a Slate path; tracks the path of pointerChunk relative to the
1377
+ * root.
1378
+ *
1379
+ * Used to move the pointer from the current chunk to the parent chunk more
1380
+ * efficiently.
1381
+ */
1382
+ _defineProperty(this, "pointerIndexStack", void 0);
1383
+ /**
1384
+ * Indexing the current chunk's children has a slight time cost, which adds up
1385
+ * when traversing very large trees, so the current node is cached.
1386
+ *
1387
+ * A value of undefined means that the current node is not cached. This
1388
+ * property must be set to undefined whenever the pointer is moved, unless
1389
+ * the pointer is guaranteed to point to the same node that it did previously.
1390
+ */
1391
+ _defineProperty(this, "cachedPointerNode", void 0);
1392
+ this.root = chunkTree;
1393
+ this.chunkSize = chunkSize;
1394
+ // istanbul ignore next
1395
+ this.debug = debug !== null && debug !== void 0 ? debug : false;
1396
+ this.pointerChunk = chunkTree;
1397
+ this.pointerIndex = -1;
1398
+ this.pointerIndexStack = [];
1399
+ this.reachedEnd = false;
1400
+ this.validateState();
1401
+ }
1402
+ /**
1403
+ * Move the pointer to the next leaf in the chunk tree
1404
+ */
1405
+ readLeaf() {
1406
+ // istanbul ignore next
1407
+ if (this.reachedEnd) return null;
1408
+ // Get the next sibling or aunt node
1409
+ while (true) {
1410
+ if (this.pointerIndex + 1 < this.pointerSiblings.length) {
1411
+ this.pointerIndex++;
1412
+ this.cachedPointerNode = undefined;
1413
+ break;
1414
+ } else if (this.pointerChunk.type === 'root') {
1415
+ this.reachedEnd = true;
1416
+ return null;
1417
+ } else {
1418
+ this.exitChunk();
1419
+ }
1420
+ }
1421
+ this.validateState();
1422
+ // If the next sibling or aunt is a chunk, descend into it
1423
+ this.enterChunkUntilLeaf(false);
1424
+ return this.pointerNode;
1425
+ }
1426
+ /**
1427
+ * Move the pointer to the previous leaf in the chunk tree
1428
+ */
1429
+ returnToPreviousLeaf() {
1430
+ // If we were at the end of the tree, descend into the end of the last
1431
+ // chunk in the tree
1432
+ if (this.reachedEnd) {
1433
+ this.reachedEnd = false;
1434
+ this.enterChunkUntilLeaf(true);
1435
+ return;
1436
+ }
1437
+ // Get the previous sibling or aunt node
1438
+ while (true) {
1439
+ if (this.pointerIndex >= 1) {
1440
+ this.pointerIndex--;
1441
+ this.cachedPointerNode = undefined;
1442
+ break;
1443
+ } else if (this.pointerChunk.type === 'root') {
1444
+ this.pointerIndex = -1;
1445
+ return;
1446
+ } else {
1447
+ this.exitChunk();
1448
+ }
1449
+ }
1450
+ this.validateState();
1451
+ // If the previous sibling or aunt is a chunk, descend into it
1452
+ this.enterChunkUntilLeaf(true);
1453
+ }
1454
+ /**
1455
+ * Insert leaves before the current leaf, leaving the pointer unchanged
1456
+ */
1457
+ insertBefore(leaves) {
1458
+ this.returnToPreviousLeaf();
1459
+ this.insertAfter(leaves);
1460
+ this.readLeaf();
1461
+ }
1462
+ /**
1463
+ * Insert leaves after the current leaf, leaving the pointer on the last
1464
+ * inserted leaf
1465
+ *
1466
+ * The insertion algorithm first checks for any chunk we're currently at the
1467
+ * end of that can receive additional leaves. Next, it tries to insert leaves
1468
+ * at the starts of any subsequent chunks.
1469
+ *
1470
+ * Any remaining leaves are passed to rawInsertAfter to be chunked and
1471
+ * inserted at the highest possible level.
1472
+ */
1473
+ insertAfter(leaves) {
1474
+ // istanbul ignore next
1475
+ if (leaves.length === 0) return;
1476
+ var beforeDepth = 0;
1477
+ var afterDepth = 0;
1478
+ // While at the end of a chunk, insert any leaves that will fit, and then
1479
+ // exit the chunk
1480
+ while (this.pointerChunk.type === 'chunk' && this.pointerIndex === this.pointerSiblings.length - 1) {
1481
+ var remainingCapacity = this.chunkSize - this.pointerSiblings.length;
1482
+ var toInsertCount = Math.min(remainingCapacity, leaves.length);
1483
+ if (toInsertCount > 0) {
1484
+ var leavesToInsert = leaves.splice(0, toInsertCount);
1485
+ this.rawInsertAfter(leavesToInsert, beforeDepth);
1486
+ }
1487
+ this.exitChunk();
1488
+ beforeDepth++;
1489
+ }
1490
+ if (leaves.length === 0) return;
1491
+ // Save the pointer so that we can come back here after inserting leaves
1492
+ // into the starts of subsequent blocks
1493
+ var rawInsertPointer = this.savePointer();
1494
+ // If leaves are inserted into the start of a subsequent block, then we
1495
+ // eventually need to restore the pointer to the last such inserted leaf
1496
+ var finalPointer = null;
1497
+ // Move the pointer into the chunk containing the next leaf, if it exists
1498
+ if (this.readLeaf()) {
1499
+ // While at the start of a chunk, insert any leaves that will fit, and
1500
+ // then exit the chunk
1501
+ while (this.pointerChunk.type === 'chunk' && this.pointerIndex === 0) {
1502
+ var _remainingCapacity = this.chunkSize - this.pointerSiblings.length;
1503
+ var _toInsertCount = Math.min(_remainingCapacity, leaves.length);
1504
+ if (_toInsertCount > 0) {
1505
+ var _leavesToInsert = leaves.splice(-_toInsertCount, _toInsertCount);
1506
+ // Insert the leaves at the start of the chunk
1507
+ this.pointerIndex = -1;
1508
+ this.cachedPointerNode = undefined;
1509
+ this.rawInsertAfter(_leavesToInsert, afterDepth);
1510
+ // If this is the first batch of insertions at the start of a
1511
+ // subsequent chunk, set the final pointer to the last inserted leaf
1512
+ if (!finalPointer) {
1513
+ finalPointer = this.savePointer();
1514
+ }
1515
+ }
1516
+ this.exitChunk();
1517
+ afterDepth++;
1518
+ }
1519
+ }
1520
+ this.restorePointer(rawInsertPointer);
1521
+ // If there are leaves left to insert, insert them between the end of the
1522
+ // previous chunk and the start of the first subsequent chunk, or wherever
1523
+ // the pointer ended up after the first batch of insertions
1524
+ var minDepth = Math.max(beforeDepth, afterDepth);
1525
+ this.rawInsertAfter(leaves, minDepth);
1526
+ if (finalPointer) {
1527
+ this.restorePointer(finalPointer);
1528
+ }
1529
+ this.validateState();
1530
+ }
1531
+ /**
1532
+ * Remove the current node and decrement the pointer, deleting any ancestor
1533
+ * chunk that becomes empty as a result
1534
+ */
1535
+ remove() {
1536
+ this.pointerSiblings.splice(this.pointerIndex--, 1);
1537
+ this.cachedPointerNode = undefined;
1538
+ if (this.pointerSiblings.length === 0 && this.pointerChunk.type === 'chunk') {
1539
+ this.exitChunk();
1540
+ this.remove();
1541
+ } else {
1542
+ this.invalidateChunk();
1543
+ }
1544
+ this.validateState();
1545
+ }
1546
+ /**
1547
+ * Add the current chunk and all ancestor chunks to the list of modified
1548
+ * chunks
1549
+ */
1550
+ invalidateChunk() {
1551
+ for (var c = this.pointerChunk; c.type === 'chunk'; c = c.parent) {
1552
+ this.root.modifiedChunks.add(c);
1553
+ }
1554
+ }
1555
+ /**
1556
+ * Whether the pointer is at the start of the tree
1557
+ */
1558
+ get atStart() {
1559
+ return this.pointerChunk.type === 'root' && this.pointerIndex === -1;
1560
+ }
1561
+ /**
1562
+ * The siblings of the current node
1563
+ */
1564
+ get pointerSiblings() {
1565
+ return this.pointerChunk.children;
1566
+ }
1567
+ /**
1568
+ * Get the current node (uncached)
1569
+ *
1570
+ * If the pointer is at the start or end of the document, returns null.
1571
+ *
1572
+ * Usually, the current node is a chunk leaf, although it can be a chunk
1573
+ * while insertions are in progress.
1574
+ */
1575
+ getPointerNode() {
1576
+ if (this.reachedEnd || this.pointerIndex === -1) {
1577
+ return null;
1578
+ }
1579
+ return this.pointerSiblings[this.pointerIndex];
1580
+ }
1581
+ /**
1582
+ * Cached getter for the current node
1583
+ */
1584
+ get pointerNode() {
1585
+ if (this.cachedPointerNode !== undefined) return this.cachedPointerNode;
1586
+ var pointerNode = this.getPointerNode();
1587
+ this.cachedPointerNode = pointerNode;
1588
+ return pointerNode;
1589
+ }
1590
+ /**
1591
+ * Get the path of a chunk relative to the root, returning null if the chunk
1592
+ * is not connected to the root
1593
+ */
1594
+ getChunkPath(chunk) {
1595
+ var path = [];
1596
+ for (var c = chunk; c.type === 'chunk'; c = c.parent) {
1597
+ var index = c.parent.children.indexOf(c);
1598
+ // istanbul ignore next
1599
+ if (index === -1) {
1600
+ return null;
1601
+ }
1602
+ path.unshift(index);
1603
+ }
1604
+ return path;
1605
+ }
1606
+ /**
1607
+ * Save the current pointer to be restored later
1608
+ */
1609
+ savePointer() {
1610
+ if (this.atStart) return 'start';
1611
+ // istanbul ignore next
1612
+ if (!this.pointerNode) {
1613
+ throw new Error('Cannot save pointer when pointerNode is null');
1614
+ }
1615
+ return {
1616
+ chunk: this.pointerChunk,
1617
+ node: this.pointerNode
1618
+ };
1619
+ }
1620
+ /**
1621
+ * Restore the pointer to a previous state
1622
+ */
1623
+ restorePointer(savedPointer) {
1624
+ if (savedPointer === 'start') {
1625
+ this.pointerChunk = this.root;
1626
+ this.pointerIndex = -1;
1627
+ this.pointerIndexStack = [];
1628
+ this.reachedEnd = false;
1629
+ this.cachedPointerNode = undefined;
1630
+ return;
1631
+ }
1632
+ // Since nodes may have been inserted or removed prior to the saved
1633
+ // pointer since it was saved, the index and index stack must be
1634
+ // recomputed. This is slow, but this is fine since restoring a pointer is
1635
+ // not a frequent operation.
1636
+ var {
1637
+ chunk,
1638
+ node
1639
+ } = savedPointer;
1640
+ var index = chunk.children.indexOf(node);
1641
+ // istanbul ignore next
1642
+ if (index === -1) {
1643
+ throw new Error('Cannot restore point because saved node is no longer in saved chunk');
1644
+ }
1645
+ var indexStack = this.getChunkPath(chunk);
1646
+ // istanbul ignore next
1647
+ if (!indexStack) {
1648
+ throw new Error('Cannot restore point because saved chunk is no longer connected to root');
1649
+ }
1650
+ this.pointerChunk = chunk;
1651
+ this.pointerIndex = index;
1652
+ this.pointerIndexStack = indexStack;
1653
+ this.reachedEnd = false;
1654
+ this.cachedPointerNode = node;
1655
+ this.validateState();
1656
+ }
1657
+ /**
1658
+ * Assuming the current node is a chunk, move the pointer into that chunk
1659
+ *
1660
+ * @param end If true, place the pointer on the last node of the chunk.
1661
+ * Otherwise, place the pointer on the first node.
1662
+ */
1663
+ enterChunk(end) {
1664
+ var _this$pointerNode;
1665
+ // istanbul ignore next
1666
+ if (((_this$pointerNode = this.pointerNode) === null || _this$pointerNode === void 0 ? void 0 : _this$pointerNode.type) !== 'chunk') {
1667
+ throw new Error('Cannot enter non-chunk');
1668
+ }
1669
+ this.pointerIndexStack.push(this.pointerIndex);
1670
+ this.pointerChunk = this.pointerNode;
1671
+ this.pointerIndex = end ? this.pointerSiblings.length - 1 : 0;
1672
+ this.cachedPointerNode = undefined;
1673
+ this.validateState();
1674
+ // istanbul ignore next
1675
+ if (this.pointerChunk.children.length === 0) {
1676
+ throw new Error('Cannot enter empty chunk');
1677
+ }
1678
+ }
1679
+ /**
1680
+ * Assuming the current node is a chunk, move the pointer into that chunk
1681
+ * repeatedly until the current node is a leaf
1682
+ *
1683
+ * @param end If true, place the pointer on the last node of the chunk.
1684
+ * Otherwise, place the pointer on the first node.
1685
+ */
1686
+ enterChunkUntilLeaf(end) {
1687
+ while (((_this$pointerNode2 = this.pointerNode) === null || _this$pointerNode2 === void 0 ? void 0 : _this$pointerNode2.type) === 'chunk') {
1688
+ var _this$pointerNode2;
1689
+ this.enterChunk(end);
1690
+ }
1691
+ }
1692
+ /**
1693
+ * Move the pointer to the parent chunk
1694
+ */
1695
+ exitChunk() {
1696
+ // istanbul ignore next
1697
+ if (this.pointerChunk.type === 'root') {
1698
+ throw new Error('Cannot exit root');
1699
+ }
1700
+ var previousPointerChunk = this.pointerChunk;
1701
+ this.pointerChunk = previousPointerChunk.parent;
1702
+ this.pointerIndex = this.pointerIndexStack.pop();
1703
+ this.cachedPointerNode = undefined;
1704
+ this.validateState();
1705
+ }
1706
+ /**
1707
+ * Insert leaves immediately after the current node, leaving the pointer on
1708
+ * the last inserted leaf
1709
+ *
1710
+ * Leaves are chunked according to the number of nodes already in the parent
1711
+ * plus the number of nodes being inserted, or the minimum depth if larger
1712
+ */
1713
+ rawInsertAfter(leaves, minDepth) {
1714
+ if (leaves.length === 0) return;
1715
+ var groupIntoChunks = (leaves, parent, perChunk) => {
1716
+ if (perChunk === 1) return leaves;
1717
+ var chunks = [];
1718
+ for (var i = 0; i < this.chunkSize; i++) {
1719
+ var chunkNodes = leaves.slice(i * perChunk, (i + 1) * perChunk);
1720
+ if (chunkNodes.length === 0) break;
1721
+ var chunk = {
1722
+ type: 'chunk',
1723
+ key: new Key(),
1724
+ parent,
1725
+ children: []
1726
+ };
1727
+ chunk.children = groupIntoChunks(chunkNodes, chunk, perChunk / this.chunkSize);
1728
+ chunks.push(chunk);
1729
+ }
1730
+ return chunks;
1731
+ };
1732
+ // Determine the chunking depth based on the number of existing nodes in
1733
+ // the chunk and the number of nodes being inserted
1734
+ var newTotal = this.pointerSiblings.length + leaves.length;
1735
+ var depthForTotal = 0;
1736
+ for (var i = this.chunkSize; i < newTotal; i *= this.chunkSize) {
1737
+ depthForTotal++;
1738
+ }
1739
+ // A depth of 0 means no chunking
1740
+ var depth = Math.max(depthForTotal, minDepth);
1741
+ var perTopLevelChunk = Math.pow(this.chunkSize, depth);
1742
+ var chunks = groupIntoChunks(leaves, this.pointerChunk, perTopLevelChunk);
1743
+ this.pointerSiblings.splice(this.pointerIndex + 1, 0, ...chunks);
1744
+ this.pointerIndex += chunks.length;
1745
+ this.cachedPointerNode = undefined;
1746
+ this.invalidateChunk();
1747
+ this.validateState();
1748
+ }
1749
+ /**
1750
+ * If debug mode is enabled, ensure that the state is internally consistent
1751
+ */
1752
+ // istanbul ignore next
1753
+ validateState() {
1754
+ if (!this.debug) return;
1755
+ var validateDescendant = node => {
1756
+ if (node.type === 'chunk') {
1757
+ var {
1758
+ parent,
1759
+ children
1760
+ } = node;
1761
+ if (!parent.children.includes(node)) {
1762
+ throw new Error("Debug: Chunk ".concat(node.key.id, " has an incorrect parent property"));
1763
+ }
1764
+ children.forEach(validateDescendant);
1765
+ }
1766
+ };
1767
+ this.root.children.forEach(validateDescendant);
1768
+ if (this.cachedPointerNode !== undefined && this.cachedPointerNode !== this.getPointerNode()) {
1769
+ throw new Error('Debug: The cached pointer is incorrect and has not been invalidated');
1770
+ }
1771
+ var actualIndexStack = this.getChunkPath(this.pointerChunk);
1772
+ if (!actualIndexStack) {
1773
+ throw new Error('Debug: The pointer chunk is not connected to the root');
1774
+ }
1775
+ if (!Path.equals(this.pointerIndexStack, actualIndexStack)) {
1776
+ throw new Error("Debug: The cached index stack [".concat(this.pointerIndexStack.join(', '), "] does not match the path of the pointer chunk [").concat(actualIndexStack.join(', '), "]"));
1777
+ }
1778
+ }
1779
+ }
1780
+
1781
+ /**
1782
+ * Traverse an array of children, providing helpers useful for reconciling the
1783
+ * children array with a chunk tree
1214
1784
  */
1215
- var DecorateContext = /*#__PURE__*/createContext(() => []);
1785
+ class ChildrenHelper {
1786
+ constructor(editor, children) {
1787
+ _defineProperty(this, "editor", void 0);
1788
+ _defineProperty(this, "children", void 0);
1789
+ /**
1790
+ * Sparse array of Slate node keys, each index corresponding to an index in
1791
+ * the children array
1792
+ *
1793
+ * Fetching the key for a Slate node is expensive, so we cache them here.
1794
+ */
1795
+ _defineProperty(this, "cachedKeys", void 0);
1796
+ /**
1797
+ * The index of the next node to be read in the children array
1798
+ */
1799
+ _defineProperty(this, "pointerIndex", void 0);
1800
+ this.editor = editor;
1801
+ this.children = children;
1802
+ this.cachedKeys = new Array(children.length);
1803
+ this.pointerIndex = 0;
1804
+ }
1805
+ /**
1806
+ * Read a given number of nodes, advancing the pointer by that amount
1807
+ */
1808
+ read(n) {
1809
+ // PERF: If only one child was requested (the most common case), use array
1810
+ // indexing instead of slice
1811
+ if (n === 1) {
1812
+ return [this.children[this.pointerIndex++]];
1813
+ }
1814
+ var slicedChildren = this.remaining(n);
1815
+ this.pointerIndex += n;
1816
+ return slicedChildren;
1817
+ }
1818
+ /**
1819
+ * Get the remaining children without advancing the pointer
1820
+ *
1821
+ * @param [maxChildren] Limit the number of children returned.
1822
+ */
1823
+ remaining(maxChildren) {
1824
+ if (maxChildren === undefined) {
1825
+ return this.children.slice(this.pointerIndex);
1826
+ }
1827
+ return this.children.slice(this.pointerIndex, this.pointerIndex + maxChildren);
1828
+ }
1829
+ /**
1830
+ * Whether all children have been read
1831
+ */
1832
+ get reachedEnd() {
1833
+ return this.pointerIndex >= this.children.length;
1834
+ }
1835
+ /**
1836
+ * Determine whether a node with a given key appears in the unread part of the
1837
+ * children array, and return its index relative to the current pointer if so
1838
+ *
1839
+ * Searching for the node object itself using indexOf is most efficient, but
1840
+ * will fail to locate nodes that have been modified. In this case, nodes
1841
+ * should be identified by their keys instead.
1842
+ *
1843
+ * Searching an array of keys using indexOf is very inefficient since fetching
1844
+ * the keys for all children in advance is very slow. Insead, if the node
1845
+ * search fails to return a value, fetch the keys of each remaining child one
1846
+ * by one and compare it to the known key.
1847
+ */
1848
+ lookAhead(node, key) {
1849
+ var elementResult = this.children.indexOf(node, this.pointerIndex);
1850
+ if (elementResult > -1) return elementResult - this.pointerIndex;
1851
+ for (var i = this.pointerIndex; i < this.children.length; i++) {
1852
+ var candidateNode = this.children[i];
1853
+ var candidateKey = this.findKey(candidateNode, i);
1854
+ if (candidateKey === key) return i - this.pointerIndex;
1855
+ }
1856
+ return -1;
1857
+ }
1858
+ /**
1859
+ * Convert an array of Slate nodes to an array of chunk leaves, each
1860
+ * containing the node and its key
1861
+ */
1862
+ toChunkLeaves(nodes, startIndex) {
1863
+ return nodes.map((node, i) => ({
1864
+ type: 'leaf',
1865
+ node,
1866
+ key: this.findKey(node, startIndex + i),
1867
+ index: startIndex + i
1868
+ }));
1869
+ }
1870
+ /**
1871
+ * Get the key for a Slate node, cached using the node's index
1872
+ */
1873
+ findKey(node, index) {
1874
+ var cachedKey = this.cachedKeys[index];
1875
+ if (cachedKey) return cachedKey;
1876
+ var key = ReactEditor.findKey(this.editor, node);
1877
+ this.cachedKeys[index] = key;
1878
+ return key;
1879
+ }
1880
+ }
1881
+
1216
1882
  /**
1217
- * Get the current `decorate` prop of the editable.
1883
+ * Update the chunk tree to match the children array, inserting, removing and
1884
+ * updating differing nodes
1218
1885
  */
1219
- var useDecorate = () => {
1220
- return useContext(DecorateContext);
1886
+ var reconcileChildren = (editor, _ref) => {
1887
+ var {
1888
+ chunkTree,
1889
+ children,
1890
+ chunkSize,
1891
+ rerenderChildren = [],
1892
+ onInsert,
1893
+ onUpdate,
1894
+ onIndexChange,
1895
+ debug
1896
+ } = _ref;
1897
+ chunkTree.modifiedChunks.clear();
1898
+ var chunkTreeHelper = new ChunkTreeHelper(chunkTree, {
1899
+ chunkSize,
1900
+ debug
1901
+ });
1902
+ var childrenHelper = new ChildrenHelper(editor, children);
1903
+ var treeLeaf;
1904
+ // Read leaves from the tree one by one, each one representing a single Slate
1905
+ // node. Each leaf from the tree is compared to the current node in the
1906
+ // children array to determine whether nodes have been inserted, removed or
1907
+ // updated.
1908
+ var _loop = function _loop() {
1909
+ // Check where the tree node appears in the children array. In the most
1910
+ // common case (where no insertions or removals have occurred), this will be
1911
+ // 0. If the node has been removed, this will be -1. If new nodes have been
1912
+ // inserted before the node, or if the node has been moved to a later
1913
+ // position in the same children array, this will be a positive number.
1914
+ var lookAhead = childrenHelper.lookAhead(treeLeaf.node, treeLeaf.key);
1915
+ // If the node was moved, we want to remove it and insert it later, rather
1916
+ // then re-inserting all intermediate nodes before it.
1917
+ var wasMoved = lookAhead > 0 && chunkTree.movedNodeKeys.has(treeLeaf.key);
1918
+ // If the tree leaf was moved or removed, remove it
1919
+ if (lookAhead === -1 || wasMoved) {
1920
+ chunkTreeHelper.remove();
1921
+ return 1; // continue
1922
+ }
1923
+ // Get the matching Slate node and any nodes that may have been inserted
1924
+ // prior to it. Insert these into the chunk tree.
1925
+ var insertedChildrenStartIndex = childrenHelper.pointerIndex;
1926
+ var insertedChildren = childrenHelper.read(lookAhead + 1);
1927
+ var matchingChild = insertedChildren.pop();
1928
+ if (insertedChildren.length) {
1929
+ var _leavesToInsert = childrenHelper.toChunkLeaves(insertedChildren, insertedChildrenStartIndex);
1930
+ chunkTreeHelper.insertBefore(_leavesToInsert);
1931
+ insertedChildren.forEach((node, relativeIndex) => {
1932
+ onInsert === null || onInsert === void 0 || onInsert(node, insertedChildrenStartIndex + relativeIndex);
1933
+ });
1934
+ }
1935
+ var matchingChildIndex = childrenHelper.pointerIndex - 1;
1936
+ // Make sure the chunk tree contains the most recent version of the Slate
1937
+ // node
1938
+ if (treeLeaf.node !== matchingChild) {
1939
+ treeLeaf.node = matchingChild;
1940
+ chunkTreeHelper.invalidateChunk();
1941
+ onUpdate === null || onUpdate === void 0 || onUpdate(matchingChild, matchingChildIndex);
1942
+ }
1943
+ // Update the index if it has changed
1944
+ if (treeLeaf.index !== matchingChildIndex) {
1945
+ treeLeaf.index = matchingChildIndex;
1946
+ onIndexChange === null || onIndexChange === void 0 || onIndexChange(matchingChild, matchingChildIndex);
1947
+ }
1948
+ // Manually invalidate chunks containing specific children that we want to
1949
+ // re-render
1950
+ if (rerenderChildren.includes(matchingChildIndex)) {
1951
+ chunkTreeHelper.invalidateChunk();
1952
+ }
1953
+ };
1954
+ while (treeLeaf = chunkTreeHelper.readLeaf()) {
1955
+ if (_loop()) continue;
1956
+ }
1957
+ // If there are still Slate nodes remaining from the children array that were
1958
+ // not matched to nodes in the tree, insert them at the end of the tree
1959
+ if (!childrenHelper.reachedEnd) {
1960
+ var remainingChildren = childrenHelper.remaining();
1961
+ var leavesToInsert = childrenHelper.toChunkLeaves(remainingChildren, childrenHelper.pointerIndex);
1962
+ // Move the pointer back to the final leaf in the tree, or the start of the
1963
+ // tree if the tree is currently empty
1964
+ chunkTreeHelper.returnToPreviousLeaf();
1965
+ chunkTreeHelper.insertAfter(leavesToInsert);
1966
+ remainingChildren.forEach((node, relativeIndex) => {
1967
+ onInsert === null || onInsert === void 0 || onInsert(node, childrenHelper.pointerIndex + relativeIndex);
1968
+ });
1969
+ }
1970
+ chunkTree.movedNodeKeys.clear();
1221
1971
  };
1222
1972
 
1973
+ function ownKeys$1(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; }
1974
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1975
+ var KEY_TO_CHUNK_TREE = new WeakMap();
1223
1976
  /**
1224
- * A React context for sharing the `selected` state of an element.
1977
+ * Get or create the chunk tree for a Slate node
1978
+ *
1979
+ * If the reconcile option is provided, the chunk tree will be updated to
1980
+ * match the current children of the node. The children are chunked
1981
+ * automatically using the given chunk size.
1225
1982
  */
1226
- var SelectedContext = /*#__PURE__*/createContext(false);
1983
+ var getChunkTreeForNode = function getChunkTreeForNode(editor, node) {
1984
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1985
+ var key = ReactEditor.findKey(editor, node);
1986
+ var chunkTree = KEY_TO_CHUNK_TREE.get(key);
1987
+ if (!chunkTree) {
1988
+ chunkTree = {
1989
+ type: 'root',
1990
+ movedNodeKeys: new Set(),
1991
+ modifiedChunks: new Set(),
1992
+ children: []
1993
+ };
1994
+ KEY_TO_CHUNK_TREE.set(key, chunkTree);
1995
+ }
1996
+ if (options.reconcile) {
1997
+ reconcileChildren(editor, _objectSpread$1({
1998
+ chunkTree,
1999
+ children: node.children
2000
+ }, options.reconcile));
2001
+ }
2002
+ return chunkTree;
2003
+ };
2004
+
2005
+ var defaultRenderChunk = _ref => {
2006
+ var {
2007
+ children
2008
+ } = _ref;
2009
+ return children;
2010
+ };
2011
+ var ChunkAncestor = props => {
2012
+ var {
2013
+ root,
2014
+ ancestor,
2015
+ renderElement,
2016
+ renderChunk = defaultRenderChunk
2017
+ } = props;
2018
+ return ancestor.children.map(chunkNode => {
2019
+ if (chunkNode.type === 'chunk') {
2020
+ var key = chunkNode.key.id;
2021
+ var renderedChunk = renderChunk({
2022
+ highest: ancestor === root,
2023
+ lowest: chunkNode.children.some(c => c.type === 'leaf'),
2024
+ attributes: {
2025
+ 'data-slate-chunk': true
2026
+ },
2027
+ children: /*#__PURE__*/React.createElement(MemoizedChunk, {
2028
+ root: root,
2029
+ ancestor: chunkNode,
2030
+ renderElement: renderElement,
2031
+ renderChunk: renderChunk
2032
+ })
2033
+ });
2034
+ return /*#__PURE__*/React.createElement(Fragment, {
2035
+ key: key
2036
+ }, renderedChunk);
2037
+ }
2038
+ // Only blocks containing no inlines are chunked
2039
+ var element = chunkNode.node;
2040
+ return renderElement(element, chunkNode.index, chunkNode.key);
2041
+ });
2042
+ };
2043
+ var ChunkTree = ChunkAncestor;
2044
+ var MemoizedChunk = /*#__PURE__*/React.memo(ChunkAncestor, (prev, next) => prev.root === next.root && prev.renderElement === next.renderElement && prev.renderChunk === next.renderChunk && !next.root.modifiedChunks.has(next.ancestor));
2045
+
2046
+ var ElementContext = /*#__PURE__*/createContext(null);
1227
2047
  /**
1228
- * Get the current `selected` state of an element.
2048
+ * Get the current element.
1229
2049
  */
1230
- var useSelected = () => {
1231
- return useContext(SelectedContext);
2050
+ var useElement = () => {
2051
+ var context = useContext(ElementContext);
2052
+ if (!context) {
2053
+ throw new Error('The `useElement` hook must be used inside `renderElement`.');
2054
+ }
2055
+ return context;
1232
2056
  };
2057
+ /**
2058
+ * Get the current element, or return null if not inside `renderElement`.
2059
+ */
2060
+ var useElementIf = () => useContext(ElementContext);
1233
2061
 
1234
2062
  /**
1235
2063
  * Children.
@@ -1239,60 +2067,113 @@ var useChildren = props => {
1239
2067
  decorations,
1240
2068
  node,
1241
2069
  renderElement,
2070
+ renderChunk,
1242
2071
  renderPlaceholder,
1243
2072
  renderText,
1244
- renderLeaf,
1245
- selection
2073
+ renderLeaf
1246
2074
  } = props;
1247
- var decorate = useDecorate();
1248
2075
  var editor = useSlateStatic();
1249
2076
  IS_NODE_MAP_DIRTY.set(editor, false);
1250
- var path = ReactEditor.findPath(editor, node);
1251
- var children = [];
1252
- var isLeafBlock = Element$1.isElement(node) && !editor.isInline(node) && Editor.hasInlines(editor, node);
1253
- for (var i = 0; i < node.children.length; i++) {
1254
- var p = path.concat(i);
1255
- var n = node.children[i];
2077
+ var isEditor = Editor.isEditor(node);
2078
+ var isBlock = !isEditor && Element$1.isElement(node) && !editor.isInline(node);
2079
+ var isLeafBlock = isBlock && Editor.hasInlines(editor, node);
2080
+ var chunkSize = isLeafBlock ? null : editor.getChunkSize(node);
2081
+ var chunking = !!chunkSize;
2082
+ var {
2083
+ decorationsByChild,
2084
+ childrenToRedecorate
2085
+ } = useDecorationsByChild(editor, node, decorations);
2086
+ // Update the index and parent of each child.
2087
+ // PERF: If chunking is enabled, this is done while traversing the chunk tree
2088
+ // instead to eliminate unnecessary weak map operations.
2089
+ if (!chunking) {
2090
+ node.children.forEach((n, i) => {
2091
+ NODE_TO_INDEX.set(n, i);
2092
+ NODE_TO_PARENT.set(n, node);
2093
+ });
2094
+ }
2095
+ var renderElementComponent = useCallback((n, i, cachedKey) => {
2096
+ var key = cachedKey !== null && cachedKey !== void 0 ? cachedKey : ReactEditor.findKey(editor, n);
2097
+ return /*#__PURE__*/React.createElement(ElementContext.Provider, {
2098
+ key: "provider-".concat(key.id),
2099
+ value: n
2100
+ }, /*#__PURE__*/React.createElement(MemoizedElement, {
2101
+ decorations: decorationsByChild[i],
2102
+ element: n,
2103
+ key: key.id,
2104
+ renderElement: renderElement,
2105
+ renderChunk: renderChunk,
2106
+ renderPlaceholder: renderPlaceholder,
2107
+ renderLeaf: renderLeaf,
2108
+ renderText: renderText
2109
+ }));
2110
+ }, [editor, decorationsByChild, renderElement, renderChunk, renderPlaceholder, renderLeaf, renderText]);
2111
+ var renderTextComponent = (n, i) => {
1256
2112
  var key = ReactEditor.findKey(editor, n);
1257
- var range = Editor.range(editor, p);
1258
- var sel = selection && Range.intersection(range, selection);
1259
- var ds = decorate([n, p]);
1260
- for (var dec of decorations) {
1261
- var d = Range.intersection(dec, range);
1262
- if (d) {
1263
- ds.push(d);
1264
- }
1265
- }
1266
- if (Element$1.isElement(n)) {
1267
- children.push( /*#__PURE__*/React.createElement(SelectedContext.Provider, {
1268
- key: "provider-".concat(key.id),
1269
- value: !!sel
1270
- }, /*#__PURE__*/React.createElement(MemoizedElement, {
1271
- decorations: ds,
1272
- element: n,
1273
- key: key.id,
1274
- renderElement: renderElement,
1275
- renderPlaceholder: renderPlaceholder,
1276
- renderLeaf: renderLeaf,
1277
- renderText: renderText,
1278
- selection: sel
1279
- })));
1280
- } else {
1281
- children.push( /*#__PURE__*/React.createElement(MemoizedText, {
1282
- decorations: ds,
1283
- key: key.id,
1284
- isLast: isLeafBlock && i === node.children.length - 1,
1285
- parent: node,
1286
- renderPlaceholder: renderPlaceholder,
1287
- renderLeaf: renderLeaf,
1288
- renderText: renderText,
1289
- text: n
1290
- }));
2113
+ return /*#__PURE__*/React.createElement(MemoizedText, {
2114
+ decorations: decorationsByChild[i],
2115
+ key: key.id,
2116
+ isLast: i === node.children.length - 1,
2117
+ parent: node,
2118
+ renderPlaceholder: renderPlaceholder,
2119
+ renderLeaf: renderLeaf,
2120
+ renderText: renderText,
2121
+ text: n
2122
+ });
2123
+ };
2124
+ if (!chunking) {
2125
+ return node.children.map((n, i) => Text$1.isText(n) ? renderTextComponent(n, i) : renderElementComponent(n, i));
2126
+ }
2127
+ var chunkTree = getChunkTreeForNode(editor, node, {
2128
+ reconcile: {
2129
+ chunkSize,
2130
+ rerenderChildren: childrenToRedecorate,
2131
+ onInsert: (n, i) => {
2132
+ NODE_TO_INDEX.set(n, i);
2133
+ NODE_TO_PARENT.set(n, node);
2134
+ },
2135
+ onUpdate: (n, i) => {
2136
+ NODE_TO_INDEX.set(n, i);
2137
+ NODE_TO_PARENT.set(n, node);
2138
+ },
2139
+ onIndexChange: (n, i) => {
2140
+ NODE_TO_INDEX.set(n, i);
2141
+ }
2142
+ }
2143
+ });
2144
+ return /*#__PURE__*/React.createElement(ChunkTree, {
2145
+ root: chunkTree,
2146
+ ancestor: chunkTree,
2147
+ renderElement: renderElementComponent,
2148
+ renderChunk: renderChunk
2149
+ });
2150
+ };
2151
+ var useDecorationsByChild = (editor, node, decorations) => {
2152
+ var decorationsByChild = splitDecorationsByChild(editor, node, decorations);
2153
+ // The value we return is a mutable array of `DecoratedRange[]` arrays. This
2154
+ // lets us avoid passing an immutable array of decorations for each child into
2155
+ // `ChunkTree` using props. Each `DecoratedRange[]` is only updated if the
2156
+ // decorations at that index have changed, which speeds up the equality check
2157
+ // for the `decorations` prop in the memoized `Element` and `Text` components.
2158
+ var mutableDecorationsByChild = useRef(decorationsByChild).current;
2159
+ // Track the list of child indices whose decorations have changed, so that we
2160
+ // can tell the chunk tree to re-render these children.
2161
+ var childrenToRedecorate = [];
2162
+ // Resize the mutable array to match the latest result
2163
+ mutableDecorationsByChild.length = decorationsByChild.length;
2164
+ for (var i = 0; i < decorationsByChild.length; i++) {
2165
+ var _mutableDecorationsBy;
2166
+ var _decorations = decorationsByChild[i];
2167
+ var previousDecorations = (_mutableDecorationsBy = mutableDecorationsByChild[i]) !== null && _mutableDecorationsBy !== void 0 ? _mutableDecorationsBy : null;
2168
+ if (!isElementDecorationsEqual(previousDecorations, _decorations)) {
2169
+ mutableDecorationsByChild[i] = _decorations;
2170
+ childrenToRedecorate.push(i);
1291
2171
  }
1292
- NODE_TO_INDEX.set(n, i);
1293
- NODE_TO_PARENT.set(n, node);
1294
2172
  }
1295
- return children;
2173
+ return {
2174
+ decorationsByChild: mutableDecorationsByChild,
2175
+ childrenToRedecorate
2176
+ };
1296
2177
  };
1297
2178
 
1298
2179
  /**
@@ -1306,26 +2187,137 @@ var useReadOnly = () => {
1306
2187
  return useContext(ReadOnlyContext);
1307
2188
  };
1308
2189
 
1309
- var SlateContext = /*#__PURE__*/createContext(null);
1310
2190
  /**
1311
- * Get the current editor object from the React context.
2191
+ * A React context for sharing the editor selector context in a way to control
2192
+ * re-renders.
1312
2193
  */
1313
- var useSlate = () => {
1314
- var context = useContext(SlateContext);
2194
+ var SlateSelectorContext = /*#__PURE__*/createContext({});
2195
+ var refEquality = (a, b) => a === b;
2196
+ /**
2197
+ * Use redux style selectors to prevent re-rendering on every keystroke.
2198
+ *
2199
+ * Bear in mind re-rendering can only prevented if the returned value is a value
2200
+ * type or for reference types (e.g. objects and arrays) add a custom equality
2201
+ * function.
2202
+ *
2203
+ * If `selector` is memoized using `useCallback`, then it will only be called
2204
+ * when it or the editor state changes. Otherwise, `selector` will be called
2205
+ * every time the component renders.
2206
+ *
2207
+ * @example
2208
+ * const isSelectionActive = useSlateSelector(editor => Boolean(editor.selection))
2209
+ */
2210
+ function useSlateSelector(selector) {
2211
+ var equalityFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : refEquality;
2212
+ var {
2213
+ deferred
2214
+ } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2215
+ var context = useContext(SlateSelectorContext);
1315
2216
  if (!context) {
1316
- throw new Error("The `useSlate` hook must be used inside the <Slate> component's context.");
2217
+ throw new Error("The `useSlateSelector` hook must be used inside the <Slate> component's context.");
1317
2218
  }
1318
2219
  var {
1319
- editor
2220
+ addEventListener
1320
2221
  } = context;
1321
- return editor;
1322
- };
1323
- var useSlateWithV = () => {
1324
- var context = useContext(SlateContext);
1325
- if (!context) {
2222
+ var editor = useSlateStatic();
2223
+ var genericSelector = useCallback(() => selector(editor), [editor, selector]);
2224
+ var [selectedState, update] = useGenericSelector(genericSelector, equalityFn);
2225
+ useIsomorphicLayoutEffect(() => {
2226
+ var unsubscribe = addEventListener(update, {
2227
+ deferred
2228
+ });
2229
+ update();
2230
+ return unsubscribe;
2231
+ }, [addEventListener, update, deferred]);
2232
+ return selectedState;
2233
+ }
2234
+ /**
2235
+ * Create selector context with editor updating on every editor change
2236
+ */
2237
+ function useSelectorContext() {
2238
+ var eventListeners = useRef(new Set());
2239
+ var deferredEventListeners = useRef(new Set());
2240
+ var onChange = useCallback(() => {
2241
+ eventListeners.current.forEach(listener => listener());
2242
+ }, []);
2243
+ var flushDeferred = useCallback(() => {
2244
+ deferredEventListeners.current.forEach(listener => listener());
2245
+ deferredEventListeners.current.clear();
2246
+ }, []);
2247
+ var addEventListener = useCallback(function (callbackProp) {
2248
+ var {
2249
+ deferred = false
2250
+ } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2251
+ var callback = deferred ? () => deferredEventListeners.current.add(callbackProp) : callbackProp;
2252
+ eventListeners.current.add(callback);
2253
+ return () => {
2254
+ eventListeners.current.delete(callback);
2255
+ };
2256
+ }, []);
2257
+ var selectorContext = useMemo(() => ({
2258
+ addEventListener,
2259
+ flushDeferred
2260
+ }), [addEventListener, flushDeferred]);
2261
+ return {
2262
+ selectorContext,
2263
+ onChange
2264
+ };
2265
+ }
2266
+ function useFlushDeferredSelectorsOnRender() {
2267
+ var {
2268
+ flushDeferred
2269
+ } = useContext(SlateSelectorContext);
2270
+ useIsomorphicLayoutEffect(flushDeferred);
2271
+ }
2272
+
2273
+ /**
2274
+ * Get the current editor object and re-render whenever it changes.
2275
+ */
2276
+ var useSlate = () => {
2277
+ var {
2278
+ addEventListener
2279
+ } = useContext(SlateSelectorContext);
2280
+ var [, forceRender] = useReducer(s => s + 1, 0);
2281
+ if (!addEventListener) {
1326
2282
  throw new Error("The `useSlate` hook must be used inside the <Slate> component's context.");
1327
2283
  }
1328
- return context;
2284
+ useIsomorphicLayoutEffect(() => addEventListener(forceRender), [addEventListener]);
2285
+ return useSlateStatic();
2286
+ };
2287
+ var EDITOR_TO_V = new WeakMap();
2288
+ var getEditorVersionRef = editor => {
2289
+ var v = EDITOR_TO_V.get(editor);
2290
+ if (v) {
2291
+ return v;
2292
+ }
2293
+ v = {
2294
+ current: 0
2295
+ };
2296
+ EDITOR_TO_V.set(editor, v);
2297
+ // Register the `onChange` handler exactly once per editor
2298
+ var {
2299
+ onChange
2300
+ } = editor;
2301
+ editor.onChange = options => {
2302
+ v.current++;
2303
+ onChange(options);
2304
+ };
2305
+ return v;
2306
+ };
2307
+ /**
2308
+ * Get the current editor object and its version, which increments on every
2309
+ * change.
2310
+ *
2311
+ * @deprecated The `v` counter is no longer used except for this hook, and may
2312
+ * be removed in a future version.
2313
+ */
2314
+ var useSlateWithV = () => {
2315
+ var editor = useSlate();
2316
+ var vRef = useMemo(() => getEditorVersionRef(editor), [editor]);
2317
+ return {
2318
+ editor,
2319
+ v: vRef.current
2320
+ };
1329
2321
  };
1330
2322
 
1331
2323
  function useTrackUserInput() {
@@ -1465,7 +2457,7 @@ var useComposing = () => {
1465
2457
  return useContext(ComposingContext);
1466
2458
  };
1467
2459
 
1468
- var _excluded$1 = ["autoFocus", "decorate", "onDOMBeforeInput", "placeholder", "readOnly", "renderElement", "renderLeaf", "renderText", "renderPlaceholder", "scrollSelectionIntoView", "style", "as", "disableDefaultStyles"],
2460
+ var _excluded$1 = ["autoFocus", "decorate", "onDOMBeforeInput", "placeholder", "readOnly", "renderElement", "renderChunk", "renderLeaf", "renderText", "renderPlaceholder", "scrollSelectionIntoView", "style", "as", "disableDefaultStyles"],
1469
2461
  _excluded2 = ["text"];
1470
2462
  function ownKeys(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; }
1471
2463
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -1482,6 +2474,7 @@ var Editable = /*#__PURE__*/forwardRef((props, forwardedRef) => {
1482
2474
  placeholder,
1483
2475
  readOnly = false,
1484
2476
  renderElement,
2477
+ renderChunk,
1485
2478
  renderLeaf,
1486
2479
  renderText,
1487
2480
  renderPlaceholder = defaultRenderPlaceholder,
@@ -1515,6 +2508,11 @@ var Editable = /*#__PURE__*/forwardRef((props, forwardedRef) => {
1515
2508
  }), []);
1516
2509
  // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it
1517
2510
  // needs to be manually focused.
2511
+ //
2512
+ // If this stops working in Firefox, make sure nothing is causing this
2513
+ // component to re-render during the initial mount. If the DOM selection is
2514
+ // set by `useIsomorphicLayoutEffect` before `onDOMSelectionChange` updates
2515
+ // `editor.selection`, the DOM selection can be removed accidentally.
1518
2516
  useEffect(() => {
1519
2517
  if (ref.current && autoFocus) {
1520
2518
  ref.current.focus();
@@ -2067,6 +3065,7 @@ var Editable = /*#__PURE__*/forwardRef((props, forwardedRef) => {
2067
3065
  };
2068
3066
  }, [scheduleOnDOMSelectionChange, state]);
2069
3067
  var decorations = decorate([editor, []]);
3068
+ var decorateContext = useDecorateContext(decorate);
2070
3069
  var showPlaceholder = placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '' && !isComposing;
2071
3070
  var placeHolderResizeHandler = useCallback(placeholderEl => {
2072
3071
  if (placeholderEl && showPlaceholder) {
@@ -2135,12 +3134,13 @@ var Editable = /*#__PURE__*/forwardRef((props, forwardedRef) => {
2135
3134
  EDITOR_TO_PENDING_INSERTION_MARKS.delete(editor);
2136
3135
  });
2137
3136
  });
3137
+ useFlushDeferredSelectorsOnRender();
2138
3138
  return /*#__PURE__*/React.createElement(ReadOnlyContext.Provider, {
2139
3139
  value: readOnly
2140
3140
  }, /*#__PURE__*/React.createElement(ComposingContext.Provider, {
2141
3141
  value: isComposing
2142
3142
  }, /*#__PURE__*/React.createElement(DecorateContext.Provider, {
2143
- value: decorate
3143
+ value: decorateContext
2144
3144
  }, /*#__PURE__*/React.createElement(RestoreDOM, {
2145
3145
  node: ref,
2146
3146
  receivedUserInput: receivedUserInput
@@ -2725,10 +3725,10 @@ var Editable = /*#__PURE__*/forwardRef((props, forwardedRef) => {
2725
3725
  decorations: decorations,
2726
3726
  node: editor,
2727
3727
  renderElement: renderElement,
3728
+ renderChunk: renderChunk,
2728
3729
  renderPlaceholder: renderPlaceholder,
2729
3730
  renderLeaf: renderLeaf,
2730
- renderText: renderText,
2731
- selection: editor.selection
3731
+ renderText: renderText
2732
3732
  }))))));
2733
3733
  });
2734
3734
  /**
@@ -2825,118 +3825,6 @@ var useFocused = () => {
2825
3825
  return useContext(FocusedContext);
2826
3826
  };
2827
3827
 
2828
- function isError(error) {
2829
- return error instanceof Error;
2830
- }
2831
- /**
2832
- * A React context for sharing the editor selector context in a way to control rerenders
2833
- */
2834
- var SlateSelectorContext = /*#__PURE__*/createContext({});
2835
- var refEquality = (a, b) => a === b;
2836
- /**
2837
- * use redux style selectors to prevent rerendering on every keystroke.
2838
- * Bear in mind rerendering can only prevented if the returned value is a value type or for reference types (e.g. objects and arrays) add a custom equality function.
2839
- *
2840
- * Example:
2841
- * ```
2842
- * const isSelectionActive = useSlateSelector(editor => Boolean(editor.selection));
2843
- * ```
2844
- */
2845
- function useSlateSelector(selector) {
2846
- var equalityFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : refEquality;
2847
- var [, forceRender] = useReducer(s => s + 1, 0);
2848
- var context = useContext(SlateSelectorContext);
2849
- if (!context) {
2850
- throw new Error("The `useSlateSelector` hook must be used inside the <Slate> component's context.");
2851
- }
2852
- var {
2853
- getSlate,
2854
- addEventListener
2855
- } = context;
2856
- var latestSubscriptionCallbackError = useRef();
2857
- var latestSelector = useRef(() => null);
2858
- var latestSelectedState = useRef(null);
2859
- var selectedState;
2860
- try {
2861
- if (selector !== latestSelector.current || latestSubscriptionCallbackError.current) {
2862
- var selectorResult = selector(getSlate());
2863
- if (equalityFn(latestSelectedState.current, selectorResult)) {
2864
- selectedState = latestSelectedState.current;
2865
- } else {
2866
- selectedState = selectorResult;
2867
- }
2868
- } else {
2869
- selectedState = latestSelectedState.current;
2870
- }
2871
- } catch (err) {
2872
- if (latestSubscriptionCallbackError.current && isError(err)) {
2873
- err.message += "\nThe error may be correlated with this previous error:\n".concat(latestSubscriptionCallbackError.current.stack, "\n\n");
2874
- }
2875
- throw err;
2876
- }
2877
- useIsomorphicLayoutEffect(() => {
2878
- latestSelector.current = selector;
2879
- latestSelectedState.current = selectedState;
2880
- latestSubscriptionCallbackError.current = undefined;
2881
- });
2882
- useIsomorphicLayoutEffect(() => {
2883
- function checkForUpdates() {
2884
- try {
2885
- var newSelectedState = latestSelector.current(getSlate());
2886
- if (equalityFn(newSelectedState, latestSelectedState.current)) {
2887
- return;
2888
- }
2889
- latestSelectedState.current = newSelectedState;
2890
- } catch (err) {
2891
- // we ignore all errors here, since when the component
2892
- // is re-rendered, the selectors are called again, and
2893
- // will throw again, if neither props nor store state
2894
- // changed
2895
- if (err instanceof Error) {
2896
- latestSubscriptionCallbackError.current = err;
2897
- } else {
2898
- latestSubscriptionCallbackError.current = new Error(String(err));
2899
- }
2900
- }
2901
- forceRender();
2902
- }
2903
- var unsubscribe = addEventListener(checkForUpdates);
2904
- checkForUpdates();
2905
- return () => unsubscribe();
2906
- },
2907
- // don't rerender on equalityFn change since we want to be able to define it inline
2908
- [addEventListener, getSlate]);
2909
- return selectedState;
2910
- }
2911
- /**
2912
- * Create selector context with editor updating on every editor change
2913
- */
2914
- function useSelectorContext(editor) {
2915
- var eventListeners = useRef([]).current;
2916
- var slateRef = useRef({
2917
- editor
2918
- }).current;
2919
- var onChange = useCallback(editor => {
2920
- slateRef.editor = editor;
2921
- eventListeners.forEach(listener => listener(editor));
2922
- }, [eventListeners, slateRef]);
2923
- var selectorContext = useMemo(() => {
2924
- return {
2925
- getSlate: () => slateRef.editor,
2926
- addEventListener: callback => {
2927
- eventListeners.push(callback);
2928
- return () => {
2929
- eventListeners.splice(eventListeners.indexOf(callback), 1);
2930
- };
2931
- }
2932
- };
2933
- }, [eventListeners, slateRef]);
2934
- return {
2935
- selectorContext,
2936
- onChange
2937
- };
2938
- }
2939
-
2940
3828
  var REACT_MAJOR_VERSION = parseInt(React.version.split('.')[0], 10);
2941
3829
 
2942
3830
  var _excluded = ["editor", "children", "onChange", "onSelectionChange", "onValueChange", "initialValue"];
@@ -2954,7 +3842,8 @@ var Slate = props => {
2954
3842
  initialValue
2955
3843
  } = props,
2956
3844
  rest = _objectWithoutProperties(props, _excluded);
2957
- var [context, setContext] = React.useState(() => {
3845
+ // Run once on first mount, but before `useEffect` or render
3846
+ React.useState(() => {
2958
3847
  if (!Node.isNodeList(initialValue)) {
2959
3848
  throw new Error("[Slate] initialValue is invalid! Expected a list of elements but got: ".concat(Scrubber.stringify(initialValue)));
2960
3849
  }
@@ -2963,15 +3852,11 @@ var Slate = props => {
2963
3852
  }
2964
3853
  editor.children = initialValue;
2965
3854
  Object.assign(editor, rest);
2966
- return {
2967
- v: 0,
2968
- editor
2969
- };
2970
3855
  });
2971
3856
  var {
2972
3857
  selectorContext,
2973
3858
  onChange: handleSelectorChange
2974
- } = useSelectorContext(editor);
3859
+ } = useSelectorContext();
2975
3860
  var onContextChange = useCallback(options => {
2976
3861
  var _options$operation;
2977
3862
  if (onChange) {
@@ -2984,11 +3869,7 @@ var Slate = props => {
2984
3869
  default:
2985
3870
  onValueChange === null || onValueChange === void 0 || onValueChange(editor.children);
2986
3871
  }
2987
- setContext(prevContext => ({
2988
- v: prevContext.v + 1,
2989
- editor
2990
- }));
2991
- handleSelectorChange(editor);
3872
+ handleSelectorChange();
2992
3873
  }, [editor, handleSelectorChange, onChange, onSelectionChange, onValueChange]);
2993
3874
  useEffect(() => {
2994
3875
  EDITOR_TO_ON_CHANGE.set(editor, onContextChange);
@@ -3023,13 +3904,11 @@ var Slate = props => {
3023
3904
  }, []);
3024
3905
  return /*#__PURE__*/React.createElement(SlateSelectorContext.Provider, {
3025
3906
  value: selectorContext
3026
- }, /*#__PURE__*/React.createElement(SlateContext.Provider, {
3027
- value: context
3028
3907
  }, /*#__PURE__*/React.createElement(EditorContext.Provider, {
3029
- value: context.editor
3908
+ value: editor
3030
3909
  }, /*#__PURE__*/React.createElement(FocusedContext.Provider, {
3031
3910
  value: isFocused
3032
- }, children))));
3911
+ }, children)));
3033
3912
  };
3034
3913
 
3035
3914
  /**
@@ -3044,6 +3923,31 @@ var useEditor = () => {
3044
3923
  return editor;
3045
3924
  };
3046
3925
 
3926
+ /**
3927
+ * Get the current `selected` state of an element.
3928
+ */
3929
+ var useSelected = () => {
3930
+ var element = useElementIf();
3931
+ // Breaking the rules of hooks is fine here since `!element` will remain true
3932
+ // or false for the entire lifetime of the component this hook is called from.
3933
+ // TODO: Decide if we want to throw an error instead when calling
3934
+ // `useSelected` outside of an element (potentially a breaking change).
3935
+ if (!element) return false;
3936
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3937
+ var selector = useCallback(editor => {
3938
+ if (!editor.selection) return false;
3939
+ var path = ReactEditor.findPath(editor, element);
3940
+ var range = Editor.range(editor, path);
3941
+ return !!Range.intersection(range, editor.selection);
3942
+ }, [element]);
3943
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3944
+ return useSlateSelector(selector, undefined, {
3945
+ // Defer the selector until after `Editable` has rendered so that the path
3946
+ // will be accurate.
3947
+ deferred: true
3948
+ });
3949
+ };
3950
+
3047
3951
  /**
3048
3952
  * Get the current slate selection.
3049
3953
  * Only triggers a rerender when the selection actually changes
@@ -3070,8 +3974,10 @@ var withReact = function withReact(editor) {
3070
3974
  var e = editor;
3071
3975
  e = withDOM(e, clipboardFormatKey);
3072
3976
  var {
3073
- onChange
3977
+ onChange,
3978
+ apply
3074
3979
  } = e;
3980
+ e.getChunkSize = () => null;
3075
3981
  e.onChange = options => {
3076
3982
  // COMPAT: React < 18 doesn't batch `setState` hook calls, which means
3077
3983
  // that the children and selection can get out of sync for one render
@@ -3083,8 +3989,24 @@ var withReact = function withReact(editor) {
3083
3989
  onChange(options);
3084
3990
  });
3085
3991
  };
3992
+ // On move_node, if the chunking optimization is enabled for the parent of the
3993
+ // node being moved, add the moved node to the movedNodeKeys set of the
3994
+ // parent's chunk tree.
3995
+ e.apply = operation => {
3996
+ if (operation.type === 'move_node') {
3997
+ var parent = Node.parent(e, operation.path);
3998
+ var chunking = !!e.getChunkSize(parent);
3999
+ if (chunking) {
4000
+ var node = Node.get(e, operation.path);
4001
+ var chunkTree = getChunkTreeForNode(e, parent);
4002
+ var key = ReactEditor.findKey(e, node);
4003
+ chunkTree.movedNodeKeys.add(key);
4004
+ }
4005
+ }
4006
+ apply(operation);
4007
+ };
3086
4008
  return e;
3087
4009
  };
3088
4010
 
3089
- export { DefaultElement, DefaultLeaf, DefaultPlaceholder, DefaultText, Editable, ReactEditor, Slate, useComposing, useEditor, useFocused, useReadOnly, useSelected, useSlate, useSlateSelection, useSlateSelector, useSlateStatic, useSlateWithV, withReact };
4011
+ export { DefaultElement, DefaultLeaf, DefaultPlaceholder, DefaultText, Editable, ReactEditor, Slate, useComposing, useEditor, useElement, useElementIf, useFocused, useReadOnly, useSelected, useSlate, useSlateSelection, useSlateSelector, useSlateStatic, useSlateWithV, withReact };
3090
4012
  //# sourceMappingURL=index.es.js.map