From c9d1424599461c15299f91e36af42071955dca7c Mon Sep 17 00:00:00 2001 From: Bernat Felip Date: Tue, 8 Jul 2025 10:54:34 +0200 Subject: [PATCH] feat: copy all new code --- CHANGELOG.md | 1096 +++++++ Readme.md | 18 +- dist/components/children.d.ts | 18 - dist/components/children.d.ts.map | 1 - dist/components/editable.d.ts | 48 - dist/components/editable.d.ts.map | 1 - dist/components/element.d.ts | 18 - dist/components/element.d.ts.map | 1 - dist/components/leaf.d.ts | 16 - dist/components/leaf.d.ts.map | 1 - dist/components/slate.d.ts | 15 - dist/components/slate.d.ts.map | 1 - dist/components/string.d.ts | 12 - dist/components/string.d.ts.map | 1 - dist/components/text.d.ts | 12 - dist/components/text.d.ts.map | 1 - dist/hooks/use-editor.d.ts | 11 - dist/hooks/use-editor.d.ts.map | 1 - dist/hooks/use-focused.d.ts | 10 - dist/hooks/use-focused.d.ts.map | 1 - dist/hooks/use-isomorphic-layout-effect.d.ts | 6 - .../use-isomorphic-layout-effect.d.ts.map | 1 - dist/hooks/use-read-only.d.ts | 10 - dist/hooks/use-read-only.d.ts.map | 1 - dist/hooks/use-selected.d.ts | 10 - dist/hooks/use-selected.d.ts.map | 1 - dist/hooks/use-slate.d.ts | 12 - dist/hooks/use-slate.d.ts.map | 1 - dist/index.d.ts | 12 - dist/index.d.ts.map | 1 - dist/index.es.js | 1915 ------------ dist/index.es.js.map | 1 - dist/index.js | 1932 ------------ dist/index.js.map | 1 - dist/plugin/react-editor.d.ts | 78 - dist/plugin/react-editor.d.ts.map | 1 - dist/plugin/with-react.d.ts | 7 - dist/plugin/with-react.d.ts.map | 1 - dist/utils/dom.d.ts | 38 - dist/utils/dom.d.ts.map | 1 - dist/utils/environment.d.ts | 5 - dist/utils/environment.d.ts.map | 1 - dist/utils/hotkeys.d.ts | 30 - dist/utils/hotkeys.d.ts.map | 1 - dist/utils/key.d.ts | 12 - dist/utils/key.d.ts.map | 1 - dist/utils/weak-maps.d.ts | 34 - dist/utils/weak-maps.d.ts.map | 1 - node_modules/.bin/direction | 1 - package.json | 42 +- src/chunking/children-helper.ts | 122 + src/chunking/chunk-tree-helper.ts | 574 ++++ src/chunking/get-chunk-tree-for-node.ts | 47 + src/chunking/index.ts | 2 + src/chunking/reconcile-children.ts | 127 + src/chunking/types.ts | 52 + src/components/children.tsx | 108 - src/components/chunk-tree.tsx | 65 + src/components/editable.tsx | 2744 +++++++++++------ src/components/element.tsx | 159 +- src/components/leaf.tsx | 158 +- .../restore-dom/restore-dom-manager.ts | 61 + src/components/restore-dom/restore-dom.tsx | 84 + src/components/slate.tsx | 126 +- src/components/string.tsx | 98 +- src/components/text.tsx | 112 +- src/custom-types.ts | 45 + .../android-input-manager.ts | 827 +++++ .../use-android-input-manager.ts | 54 + src/hooks/use-children.tsx | 190 ++ src/hooks/use-composing.ts | 15 + src/hooks/use-decorations.ts | 81 + src/hooks/use-editor.tsx | 11 +- src/hooks/use-element.ts | 25 + src/hooks/use-generic-selector.tsx | 92 + src/hooks/use-is-mounted.tsx | 14 + src/hooks/use-isomorphic-layout-effect.ts | 9 +- src/hooks/use-mutation-observer.ts | 25 + src/hooks/use-selected.ts | 38 +- src/hooks/use-slate-selection.tsx | 17 + src/hooks/use-slate-selector.tsx | 128 + src/hooks/use-slate-static.tsx | 25 + src/hooks/use-slate.tsx | 71 +- src/hooks/use-track-user-input.ts | 32 + src/index.ts | 17 +- src/plugin/react-editor.ts | 493 +-- src/plugin/with-react.ts | 135 +- src/utils/dom.ts | 135 - src/utils/environment.ts | 17 +- src/utils/hotkeys.ts | 95 - src/utils/key.ts | 18 - src/utils/weak-maps.ts | 44 - test/chunking.spec.ts | 953 ++++++ test/decorations.spec.tsx | 672 ++++ test/editable.spec.tsx | 204 ++ test/index.js | 1 - test/react-editor.spec.tsx | 127 + test/tsconfig.json | 7 + test/use-selected.spec.tsx | 183 ++ test/use-slate-selector.spec.tsx | 60 + test/use-slate.spec.tsx | 59 + tsconfig.json | 9 +- 102 files changed, 8567 insertions(+), 6441 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 dist/components/children.d.ts delete mode 100644 dist/components/children.d.ts.map delete mode 100644 dist/components/editable.d.ts delete mode 100644 dist/components/editable.d.ts.map delete mode 100644 dist/components/element.d.ts delete mode 100644 dist/components/element.d.ts.map delete mode 100644 dist/components/leaf.d.ts delete mode 100644 dist/components/leaf.d.ts.map delete mode 100644 dist/components/slate.d.ts delete mode 100644 dist/components/slate.d.ts.map delete mode 100644 dist/components/string.d.ts delete mode 100644 dist/components/string.d.ts.map delete mode 100644 dist/components/text.d.ts delete mode 100644 dist/components/text.d.ts.map delete mode 100644 dist/hooks/use-editor.d.ts delete mode 100644 dist/hooks/use-editor.d.ts.map delete mode 100644 dist/hooks/use-focused.d.ts delete mode 100644 dist/hooks/use-focused.d.ts.map delete mode 100644 dist/hooks/use-isomorphic-layout-effect.d.ts delete mode 100644 dist/hooks/use-isomorphic-layout-effect.d.ts.map delete mode 100644 dist/hooks/use-read-only.d.ts delete mode 100644 dist/hooks/use-read-only.d.ts.map delete mode 100644 dist/hooks/use-selected.d.ts delete mode 100644 dist/hooks/use-selected.d.ts.map delete mode 100644 dist/hooks/use-slate.d.ts delete mode 100644 dist/hooks/use-slate.d.ts.map delete mode 100644 dist/index.d.ts delete mode 100644 dist/index.d.ts.map delete mode 100644 dist/index.es.js delete mode 100644 dist/index.es.js.map delete mode 100644 dist/index.js delete mode 100644 dist/index.js.map delete mode 100644 dist/plugin/react-editor.d.ts delete mode 100644 dist/plugin/react-editor.d.ts.map delete mode 100644 dist/plugin/with-react.d.ts delete mode 100644 dist/plugin/with-react.d.ts.map delete mode 100644 dist/utils/dom.d.ts delete mode 100644 dist/utils/dom.d.ts.map delete mode 100644 dist/utils/environment.d.ts delete mode 100644 dist/utils/environment.d.ts.map delete mode 100644 dist/utils/hotkeys.d.ts delete mode 100644 dist/utils/hotkeys.d.ts.map delete mode 100644 dist/utils/key.d.ts delete mode 100644 dist/utils/key.d.ts.map delete mode 100644 dist/utils/weak-maps.d.ts delete mode 100644 dist/utils/weak-maps.d.ts.map delete mode 120000 node_modules/.bin/direction create mode 100644 src/chunking/children-helper.ts create mode 100644 src/chunking/chunk-tree-helper.ts create mode 100644 src/chunking/get-chunk-tree-for-node.ts create mode 100644 src/chunking/index.ts create mode 100644 src/chunking/reconcile-children.ts create mode 100644 src/chunking/types.ts delete mode 100644 src/components/children.tsx create mode 100644 src/components/chunk-tree.tsx create mode 100644 src/components/restore-dom/restore-dom-manager.ts create mode 100644 src/components/restore-dom/restore-dom.tsx create mode 100644 src/custom-types.ts create mode 100644 src/hooks/android-input-manager/android-input-manager.ts create mode 100644 src/hooks/android-input-manager/use-android-input-manager.ts create mode 100644 src/hooks/use-children.tsx create mode 100644 src/hooks/use-composing.ts create mode 100644 src/hooks/use-decorations.ts create mode 100644 src/hooks/use-element.ts create mode 100644 src/hooks/use-generic-selector.tsx create mode 100644 src/hooks/use-is-mounted.tsx create mode 100644 src/hooks/use-mutation-observer.ts create mode 100644 src/hooks/use-slate-selection.tsx create mode 100644 src/hooks/use-slate-selector.tsx create mode 100644 src/hooks/use-slate-static.tsx create mode 100644 src/hooks/use-track-user-input.ts delete mode 100644 src/utils/dom.ts delete mode 100644 src/utils/hotkeys.ts delete mode 100644 src/utils/key.ts delete mode 100644 src/utils/weak-maps.ts create mode 100644 test/chunking.spec.ts create mode 100644 test/decorations.spec.tsx create mode 100644 test/editable.spec.tsx delete mode 100644 test/index.js create mode 100644 test/react-editor.spec.tsx create mode 100644 test/tsconfig.json create mode 100644 test/use-selected.spec.tsx create mode 100644 test/use-slate-selector.spec.tsx create mode 100644 test/use-slate.spec.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8854c2a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1096 @@ +# slate-react + +## 0.117.3 + +### Patch Changes + +- [#5901](https://github.com/ianstormtaylor/slate/pull/5901) [`5a20ea3a`](https://github.com/ianstormtaylor/slate/commit/5a20ea3ad8f725b6072b6512f68d48e440da8901) Thanks [@bibixx](https://github.com/bibixx)! - Fix Android cursor jumping to word start after autocorrect + +## 0.117.2 + +### Patch Changes + +- [#5908](https://github.com/ianstormtaylor/slate/pull/5908) [`06b21fdc`](https://github.com/ianstormtaylor/slate/commit/06b21fdca39705c4686c2d3afb9649d63f9ddde5) Thanks [@nabbydude](https://github.com/nabbydude)! - Fixed issue on android where deleting forward at the end of a block would delete the first character in the next block instead of the linebreak + +## 0.117.1 + +### Patch Changes + +- [#5902](https://github.com/ianstormtaylor/slate/pull/5902) [`47da9bf4`](https://github.com/ianstormtaylor/slate/commit/47da9bf45599c81359cb6bc86aa59d01c77bba52) Thanks [@zbeyens](https://github.com/zbeyens)! - Fixes #5900 + +## 0.116.0 + +### Minor Changes + +- [#5871](https://github.com/ianstormtaylor/slate/pull/5871) [`fb87646e`](https://github.com/ianstormtaylor/slate/commit/fb87646e8643e1d0547134cea9d1f57912f06a92) Thanks [@12joan](https://github.com/12joan)! - - Implement experimental chunking optimization (disabled by default, see https://docs.slatejs.org/walkthroughs/09-performance). + - Add `useElement` and `useElementIf` hooks to get the current element. + - **BREAKING CHANGE:** Decorations are no longer recomputed when a node's parent re-renders, only when the node itself re-renders or when the `decorate` function is changed. + - Ensure that `decorate` is a pure function of the node passed into it. Depending on the node's parent may result in decorations not being recomputed when you expect them to be. + - If this change impacts you, consider changing your `decorate` function to work on the node's parent instead. + - For example, if your `decorate` function decorates a `code-line` based on the parent `code-block`'s language, decorate the `code-block` instead. + - This is unlikely to result in any performance detriment, since in previous versions of `slate-react`, the decorations of all siblings were recomputed when one sibling was modified. + - **BREAKING CHANGE:** Elements no longer re-render due to selection changes. + - To re-render whenever an element becomes selected or deselected, subscribe to `useSelected`. + - To re-render whenever the selection changes anywhere in the editor, subscribe to `useSlateSelection`. + - To re-render whenever the intersection of the selection with an element changes (the previous behaviour), use `useSlateSelector` to compute this intersection using `Range.intersection`. Ensure you provide a suitable equality function using `Range.equals`. + - Increase minimum `slate-dom` version to `0.116.0`. + - Deprecate the `useSlateWithV` hook + - PERF: Use subscribable pattern for `useSlate`, `useSelected` and decorations to reduce re-renders. + +## 0.115.0 + +### Patch Changes + +- [#5881](https://github.com/ianstormtaylor/slate/pull/5881) [`05263b54`](https://github.com/ianstormtaylor/slate/commit/05263b544c32b4c704d141dc5142190f18c056e1) Thanks [@12joan](https://github.com/12joan)! - Fix IME issues in Firefox caused by placeholder + +- [#5877](https://github.com/ianstormtaylor/slate/pull/5877) [`747ebfda`](https://github.com/ianstormtaylor/slate/commit/747ebfda0a06b29fc31720f9172c67222fbeae07) Thanks [@12joan](https://github.com/12joan)! - Fix a crash on iOS when composing text using an IME at the start of a block, at the cost of breaking capitalization on iOS in an empty editor. + +- [#5859](https://github.com/ianstormtaylor/slate/pull/5859) [`72532fd2`](https://github.com/ianstormtaylor/slate/commit/72532fd2d7be594251ea26fefb5c1ce8337b76ed) Thanks [@12joan](https://github.com/12joan)! - Optimize `isElement`, `isText`, `isNodeList` and `isEditor` by removing dependency on `is-plain-object` and by performing shallow checks by default. To perform a full check, including all descendants, pass the `{ deep: true }` option to `isElement`, `isNodeList` or `isEditor`. + +## 0.114.2 + +### Patch Changes + +- [#5855](https://github.com/ianstormtaylor/slate/pull/5855) [`ec367fb0`](https://github.com/ianstormtaylor/slate/commit/ec367fb04f018c8fd0daf8b0d09f87c89a8c155b) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix `renderText` prop not applied + +## 0.114.1 + +### Patch Changes + +- [#5853](https://github.com/ianstormtaylor/slate/pull/5853) [`9fe6184c`](https://github.com/ianstormtaylor/slate/commit/9fe6184ca26c518a1114b66df319504f31a07cbb) Thanks [@12joan](https://github.com/12joan)! - Increase minimum `slate` version to 0.114.0 due to https://github.com/ianstormtaylor/slate/issues/5852 + +## 0.114.0 + +### Minor Changes + +- [#5850](https://github.com/ianstormtaylor/slate/pull/5850) [`22a3dda3`](https://github.com/ianstormtaylor/slate/commit/22a3dda36d4362d5dfdb9a75836297dae8cd7f9e) Thanks [@zbeyens](https://github.com/zbeyens)! - - Update `RenderLeafProps` interface to add `leafPosition` property containing `start`, `end`, `isFirst`, and `isLast` when a text node is split by decorations. + + - Add optional `renderText` prop to `` component for customizing text node rendering. + +- [#5848](https://github.com/ianstormtaylor/slate/pull/5848) [`2c62e017`](https://github.com/ianstormtaylor/slate/commit/2c62e0179734871369ac23d38ebfc1378ec9ad68) Thanks [@dpolugic](https://github.com/dpolugic)! - Use equalityFn in useSlateSelector during render as well + +## 0.113.0 + +### Patch Changes + +- [#5822](https://github.com/ianstormtaylor/slate/pull/5822) [`68915e8c`](https://github.com/ianstormtaylor/slate/commit/68915e8cfadd9d8dd545dbcd8c33b6b69827a287) Thanks [@RavenColEvol](https://github.com/RavenColEvol)! - add context menu undo support + +## 0.112.1 + +### Patch Changes + +- [#5795](https://github.com/ianstormtaylor/slate/pull/5795) [`f456dfbf`](https://github.com/ianstormtaylor/slate/commit/f456dfbf133f93fabe683849adb7952b8b04fc60) Thanks [@12joan](https://github.com/12joan)! - Ignore selectionchange events originating from input and textarea elements (addresses Chrome bug https://issues.chromium.org/issues/389368412) + +## 0.112.0 + +### Patch Changes + +- [#5763](https://github.com/ianstormtaylor/slate/pull/5763) [`644ebdc8`](https://github.com/ianstormtaylor/slate/commit/644ebdc8f5f30878fb87dc8685f62e0636c23491) Thanks [@TyMick](https://github.com/TyMick)! - Use extended `Editor` type in `useSlateWithV` return type + +- [#5741](https://github.com/ianstormtaylor/slate/pull/5741) [`90fbcdef`](https://github.com/ianstormtaylor/slate/commit/90fbcdeff58d9b1f5de13102a1198f1c7244ae0c) Thanks [@AdrienPoupa](https://github.com/AdrienPoupa)! - Fix ReactEditor.toDOMRange crash in setDomSelection + +## 0.111.0 + +### Minor Changes + +- [#5734](https://github.com/ianstormtaylor/slate/pull/5734) [`9a212512`](https://github.com/ianstormtaylor/slate/commit/9a2125127064f35332d5c06df2dfa3768f745185) Thanks [@bmingles](https://github.com/bmingles)! - Split out slate-dom package + +## 0.110.3 + +### Patch Changes + +- [#5746](https://github.com/ianstormtaylor/slate/pull/5746) [`e97a9f88`](https://github.com/ianstormtaylor/slate/commit/e97a9f8857b24d57c1386b2d01e9922360f98599) Thanks [@DustinMackintosh](https://github.com/DustinMackintosh)! - Invalidate node maps when nodes change until next react paint + +## 0.110.2 + +### Patch Changes + +- [#5737](https://github.com/ianstormtaylor/slate/pull/5737) [`cd21bb1f`](https://github.com/ianstormtaylor/slate/commit/cd21bb1f80cfaa824253849b407781c9471dcd9a) Thanks [@WindRunnerMax](https://github.com/WindRunnerMax)! - fix: sync built-in state on undo when editor is unfocused + +- [#5727](https://github.com/ianstormtaylor/slate/pull/5727) [`335c5418`](https://github.com/ianstormtaylor/slate/commit/335c54188ff1e2985cc584dd9fa3117508208dd3) Thanks [@hernansartorio](https://github.com/hernansartorio)! - Call unref on pathRefs created for move_node to remove memory leak + +## 0.110.1 + +### Patch Changes + +- [#5716](https://github.com/ianstormtaylor/slate/pull/5716) [`10abeff8`](https://github.com/ianstormtaylor/slate/commit/10abeff84fd856f9fd72240f8ee1631466f98d02) Thanks [@TyMick](https://github.com/TyMick)! - Fix selections with non-void non-editable focus + +## 0.110.0 + +### Minor Changes + +- [#5706](https://github.com/ianstormtaylor/slate/pull/5706) [`f9e83b80`](https://github.com/ianstormtaylor/slate/commit/f9e83b807f4b2ae717814af5943f53f366a48fd2) Thanks [@yf-yang](https://github.com/yf-yang)! - Expose useComposing hook + +## 0.109.0 + +### Minor Changes + +- [#5695](https://github.com/ianstormtaylor/slate/pull/5695) [`6cb38e37`](https://github.com/ianstormtaylor/slate/commit/6cb38e37a4bd3a43ee02652c514288df62da1c21) Thanks [@yf-yang](https://github.com/yf-yang)! - feat: Add useComposing hook" + +## 0.108.0 + +### Minor Changes + +- [#5681](https://github.com/ianstormtaylor/slate/pull/5681) [`b8bf92dc`](https://github.com/ianstormtaylor/slate/commit/b8bf92dc7e42f7547128fcfe1c63e89dffb29032) Thanks [@yf-yang](https://github.com/yf-yang)! - Forward ref from Editable component + +## 0.107.1 + +### Patch Changes + +- [#5677](https://github.com/ianstormtaylor/slate/pull/5677) [`a9a70405`](https://github.com/ianstormtaylor/slate/commit/a9a7040583ffe6a5ddf623acbaa91dee8fc76904) Thanks [@WindrunnerMax](https://github.com/WindrunnerMax)! - fix unexpected event triggered when using `ReactEditor.focus` + +## 0.107.0 + +### Minor Changes + +- [#5676](https://github.com/ianstormtaylor/slate/pull/5676) [`ec9e5f0a`](https://github.com/ianstormtaylor/slate/commit/ec9e5f0a366dda80f826e90042ff8a49b1cf3933) Thanks [@ivan-sysoi](https://github.com/ivan-sysoi)! - Changed behaviour of ReactEditor.findDocumentOrShadowRoot. It returns shadow root or document without checking for the existence of the getSelection method. + +## 0.106.0 + +### Minor Changes + +- [#5659](https://github.com/ianstormtaylor/slate/pull/5659) [`e6254f70`](https://github.com/ianstormtaylor/slate/commit/e6254f706a47d0e451d3d40485bf96f819eaa9ab) Thanks [@MahmoudElsayad](https://github.com/MahmoudElsayad)! - Enable Shadow DOM fix for all Safari versions. + +### Patch Changes + +- [#5664](https://github.com/ianstormtaylor/slate/pull/5664) [`0016f984`](https://github.com/ianstormtaylor/slate/commit/0016f9843f76fee1fe7d26330dd00cd1307915ec) Thanks [@12joan](https://github.com/12joan)! - Fix: `state.isDraggingInternally` is stale if a drop handler outside the editor causes the dragged DOM element to unmount + +## 0.105.0 + +### Minor Changes + +- [#5654](https://github.com/ianstormtaylor/slate/pull/5654) [`2a8b4e95`](https://github.com/ianstormtaylor/slate/commit/2a8b4e958bd02f3b70da51c3880fd764270424ad) Thanks [@alex-starostin](https://github.com/alex-starostin)! - Make capitalizing work for iOS + +## 0.104.0 + +### Minor Changes + +- [#5648](https://github.com/ianstormtaylor/slate/pull/5648) [`0bb7be54`](https://github.com/ianstormtaylor/slate/commit/0bb7be5496db4c31042667a17f9ff95c3f3d42b0) Thanks [@MahmoudElsayad](https://github.com/MahmoudElsayad)! - Fix Safari selection inside Shadow DOM. + +## 0.102.0 + +### Patch Changes + +- [#5541](https://github.com/ianstormtaylor/slate/pull/5541) [`c2ae1eda`](https://github.com/ianstormtaylor/slate/commit/c2ae1eda91d0aae1cd63bd46af759c542c292a8a) Thanks [@12joan](https://github.com/12joan)! - Do not move selection outside inline node when composition starts + +## 0.101.6 + +### Patch Changes + +- [#5593](https://github.com/ianstormtaylor/slate/pull/5593) [`54594d0f`](https://github.com/ianstormtaylor/slate/commit/54594d0f81627166d72c97256203c4b5642a82ff) Thanks [@12joan](https://github.com/12joan)! - Fix: Calling `ReactEditor.focus` doesn't update `useFocused` when running in @testing-library/react + +## 0.101.5 + +### Patch Changes + +- [#5584](https://github.com/ianstormtaylor/slate/pull/5584) [`884ab424`](https://github.com/ianstormtaylor/slate/commit/884ab4249485e5930f1f79abb939bf375ffd47c0) Thanks [@Elvin7CF](https://github.com/Elvin7CF)! - Fix onCompositionEnd not updating isComposing + +## 0.101.3 + +### Patch Changes + +- [#5576](https://github.com/ianstormtaylor/slate/pull/5576) [`8ce52fd4`](https://github.com/ianstormtaylor/slate/commit/8ce52fd494c5156c8f08841b972bc5eda2817c03) Thanks [@qirong77](https://github.com/qirong77)! - fix onCompositionEnd update error. + +## 0.101.2 + +### Patch Changes + +- [#5567](https://github.com/ianstormtaylor/slate/pull/5567) [`07f59e36`](https://github.com/ianstormtaylor/slate/commit/07f59e36071bae2b9c09b787f1dd514c6bf859a4) Thanks [@timagixe](https://github.com/timagixe)! - Fix cursor position on selection collapse for RTL direction + +## 0.101.1 + +### Patch Changes + +- [#5564](https://github.com/ianstormtaylor/slate/pull/5564) [`9aa573e9`](https://github.com/ianstormtaylor/slate/commit/9aa573e9b8b2aff0c702fc6efa622e71db7759f1) Thanks [@12joan](https://github.com/12joan)! - Apply 300ms placeholder delay only on Android devices + +## 0.101.0 + +### Minor Changes + +- [#5527](https://github.com/ianstormtaylor/slate/pull/5527) [`fc081816`](https://github.com/ianstormtaylor/slate/commit/fc081816e08ade6838d05a96f84088de9f2734ce) Thanks [@skogsmaskin](https://github.com/skogsmaskin)! - Fixes a bug with `ReactEditor.focus` where it would throw an error if the editor was in the middle of applying pending operations. + With this change, setting focus will be retried until the editor no longer has any pending operations. + Calling `ReactEditor.focus` on a editor without a current selection, will now make a selection in the top of the document. + +### Patch Changes + +- [#5549](https://github.com/ianstormtaylor/slate/pull/5549) [`f9cca97f`](https://github.com/ianstormtaylor/slate/commit/f9cca97f00e4b7827f7056cd7f1644345a4be953) Thanks [@12joan](https://github.com/12joan)! - Firefox compat: Fix incorrect focus.offset when text node ends with \n + +- [#5556](https://github.com/ianstormtaylor/slate/pull/5556) [`22495e14`](https://github.com/ianstormtaylor/slate/commit/22495e143d81fd602ff3efa0b5f6339a4b05b6c0) Thanks [@dylans](https://github.com/dylans)! - Revert #5542 + +## 0.100.1 + +### Patch Changes + +- [#5542](https://github.com/ianstormtaylor/slate/pull/5542) [`8688ed5c`](https://github.com/ianstormtaylor/slate/commit/8688ed5c680069c4277d8b575b79fe525737935d) Thanks [@hellsan631](https://github.com/hellsan631)! - Fix Memory Leak when switching between focused editables + +## 0.100.0 + +### Minor Changes + +- [#5526](https://github.com/ianstormtaylor/slate/pull/5526) [`623f4452`](https://github.com/ianstormtaylor/slate/commit/623f44521ee95be38c53b6def456ed8c5f16e14b) Thanks [@jkcs](https://github.com/jkcs)! - Add `onSelectionChange` and `onValueChange` in Slate React component + +- [#5528](https://github.com/ianstormtaylor/slate/pull/5528) [`c4c14882`](https://github.com/ianstormtaylor/slate/commit/c4c14882edf13828f6583a88e50754ce63583bd7) Thanks [@dylans](https://github.com/dylans)! - Update dependencies to React 18, Node 20, TS 5.2, etc. + +## 0.99.0 + +### Minor Changes + +- [#5516](https://github.com/ianstormtaylor/slate/pull/5516) [`300dc57a`](https://github.com/ianstormtaylor/slate/commit/300dc57a00c6437519ae0044384811efec653758) Thanks [@josephmr](https://github.com/josephmr)! - Retain editor selection when using ReactEditor.focus() + +### Patch Changes + +- [#5514](https://github.com/ianstormtaylor/slate/pull/5514) [`ff7db221`](https://github.com/ianstormtaylor/slate/commit/ff7db221205014605464628d18e41f1310bcead9) Thanks [@YaoKaiLun](https://github.com/YaoKaiLun)! - Fix move_node triggers nodes re-render + +## 0.98.4 + +### Patch Changes + +- [#5510](https://github.com/ianstormtaylor/slate/pull/5510) [`13c7d271`](https://github.com/ianstormtaylor/slate/commit/13c7d271e35406a2497e78ef114417ad17796c65) Thanks [@e1himself](https://github.com/e1himself)! - Remove an unused React ref + +## 0.98.3 + +### Patch Changes + +- [#5503](https://github.com/ianstormtaylor/slate/pull/5503) [`e308cd66`](https://github.com/ianstormtaylor/slate/commit/e308cd664d381ba1cd37f423445f189b9b5e4d1d) Thanks [@janpaepke](https://github.com/janpaepke)! - bugfix: slate breaks on load on safari < 16.4 + +## 0.98.2 + +### Patch Changes + +- [#5497](https://github.com/ianstormtaylor/slate/pull/5497) [`76ba3759`](https://github.com/ianstormtaylor/slate/commit/76ba3759838fd538587fda2f4027f7c74ff09589) Thanks [@Dimitri-WEI-Lingfeng](https://github.com/Dimitri-WEI-Lingfeng)! - fix the bug that user cannot input chinese on mac wechat browser. + +## 0.98.1 + +### Patch Changes + +- [#5491](https://github.com/ianstormtaylor/slate/pull/5491) [`a5576e56`](https://github.com/ianstormtaylor/slate/commit/a5576e56a73f061972775953f270b34081a5cad8) Thanks [@WcaleNieWolny](https://github.com/WcaleNieWolny)! - Fix firefox table selection if table is contentedtiable + +## 0.98.0 + +### Minor Changes + +- [#5486](https://github.com/ianstormtaylor/slate/pull/5486) [`8b548fb5`](https://github.com/ianstormtaylor/slate/commit/8b548fb53af861e1f391f2d5c052e3279f0a0b6c) Thanks [@WcaleNieWolny](https://github.com/WcaleNieWolny)! - Fix invalid usage of the selection API in firefox + +## 0.97.2 + +### Patch Changes + +- [#5462](https://github.com/ianstormtaylor/slate/pull/5462) [`a6b606d8`](https://github.com/ianstormtaylor/slate/commit/a6b606d804795d9b134784a35e3b00ac77f3ebbc) Thanks [@Ben-Wormald](https://github.com/Ben-Wormald)! - Update hotkeys util to use isHotkey for better support for non-latin keyboards + +* [#5470](https://github.com/ianstormtaylor/slate/pull/5470) [`4bd15ed3`](https://github.com/ianstormtaylor/slate/commit/4bd15ed3950e3a0871f5d0ecb391bb637c05e59d) Thanks [@josephmr](https://github.com/josephmr)! - Fix Android caret placement regression when inputting into empty editor + +## 0.97.1 + +### Patch Changes + +- [#5460](https://github.com/ianstormtaylor/slate/pull/5460) [`53395449`](https://github.com/ianstormtaylor/slate/commit/53395449e5b03fde5c0521203ef044064f3c159e) Thanks [@12joan](https://github.com/12joan)! - Do not attempt to batch updates manually in React >= 18 + +## 0.97.0 + +### Minor Changes + +- [#5451](https://github.com/ianstormtaylor/slate/pull/5451) [`12ff246e`](https://github.com/ianstormtaylor/slate/commit/12ff246e101bb7ae51248066c07c378ee4be9220) Thanks [@gtluszcz](https://github.com/gtluszcz)! - Fixed occasional crashes when selecting void elements in Chrome + +### Patch Changes + +- [#5453](https://github.com/ianstormtaylor/slate/pull/5453) [`cde0a155`](https://github.com/ianstormtaylor/slate/commit/cde0a155e23d015d4ee72f9f10f63b67e878668e) Thanks [@Shiba-ligo](https://github.com/Shiba-ligo)! - fix regular expression for testing Webkit based browser. + +## 0.96.0 + +### Minor Changes + +- [#5437](https://github.com/ianstormtaylor/slate/pull/5437) [`3ad13d60`](https://github.com/ianstormtaylor/slate/commit/3ad13d601550341688cc75466a75b616d8232154) Thanks [@josephmr](https://github.com/josephmr)! - Detect all WebKit based browsers for COMPAT behavior + +### Patch Changes + +- [#5443](https://github.com/ianstormtaylor/slate/pull/5443) [`eb7f5987`](https://github.com/ianstormtaylor/slate/commit/eb7f598707ab9a4f1bd62fd195719049e9536be0) Thanks [@OldDream](https://github.com/OldDream)! - fix wrong caret position during composition. + +## 0.95.0 + +### Minor Changes + +- [#5422](https://github.com/ianstormtaylor/slate/pull/5422) [`0b179909`](https://github.com/ianstormtaylor/slate/commit/0b1799091a6800c7e868d5a6148b82648cbe8270) Thanks [@Chudesnov](https://github.com/Chudesnov)! - Prevents default focus styles from being removed in Editable + +* [#5421](https://github.com/ianstormtaylor/slate/pull/5421) [`91e388ec`](https://github.com/ianstormtaylor/slate/commit/91e388ecd9e6a540b4a651978436f196f38f667d) Thanks [@e1himself](https://github.com/e1himself)! - Rename `` component prop from `value` to `initialValue` to emphasize uncontrolled nature of it + +## 0.94.2 + +### Patch Changes + +- [#5423](https://github.com/ianstormtaylor/slate/pull/5423) [`042bca16`](https://github.com/ianstormtaylor/slate/commit/042bca167ac810acccae229bc905a49098aee546) Thanks [@horacioh](https://github.com/horacioh)! - fix placeholder position in Safari 16.x + +## 0.94.0 + +### Patch Changes + +- [#5307](https://github.com/ianstormtaylor/slate/pull/5307) [`3243c7e3`](https://github.com/ianstormtaylor/slate/commit/3243c7e34ac2602618c67c88b1b7df07fde1c2ec) Thanks [@zbeyens](https://github.com/zbeyens)! - Interface methods JSDoc should now work on IDEs. + +## 0.93.0 + +### Patch Changes + +- [#5383](https://github.com/ianstormtaylor/slate/pull/5383) [`3c3ea29a`](https://github.com/ianstormtaylor/slate/commit/3c3ea29a2d7c70bab3629f0f78ea28dca4058b53) Thanks [@12joan](https://github.com/12joan)! - Fix issue when tabbing into editor in Safari (https://github.com/udecode/plate/issues/2315) + +* [#5368](https://github.com/ianstormtaylor/slate/pull/5368) [`5a0d3974`](https://github.com/ianstormtaylor/slate/commit/5a0d3974d6cb2c099dff4c0976e9390d24c345ad) Thanks [@edhager](https://github.com/edhager)! - Delay rendering of placeholder to avoid IME hiding + +## 0.92.0 + +### Minor Changes + +- [#5363](https://github.com/ianstormtaylor/slate/pull/5363) [`d42cd005`](https://github.com/ianstormtaylor/slate/commit/d42cd005db862165f5ac63fba4d35f36d92864f6) Thanks [@aciccarello](https://github.com/aciccarello)! - update dependencies on react hooks to be more senstive to changes + + The code should now meet eslint react hook standards + + This could result in more renders + + closes #3886 + +### Patch Changes + +- [#5369](https://github.com/ianstormtaylor/slate/pull/5369) [`556a4565`](https://github.com/ianstormtaylor/slate/commit/556a4565d2bb4a611d34bb30ecd9bac324664066) Thanks [@alex-vladut](https://github.com/alex-vladut)! - Allow copying from editable void input + +## 0.91.11 + +### Patch Changes + +- [#5362](https://github.com/ianstormtaylor/slate/pull/5362) [`43999356`](https://github.com/ianstormtaylor/slate/commit/439993569001f8c5dc9e68194c198d430a4ef4bc) Thanks [@jason0x43](https://github.com/jason0x43)! - Fix an issue where pastes in Safari wouldn't include application/x-slate-fragment data + +* [#5359](https://github.com/ianstormtaylor/slate/pull/5359) [`9825d29b`](https://github.com/ianstormtaylor/slate/commit/9825d29b87ffff96b4cdfd7339028cc1a92c6f68) Thanks [@jason0x43](https://github.com/jason0x43)! - Fix an issue on Android where content containing a newline wouldn't be pasted properly + +## 0.91.10 + +### Patch Changes + +- [#5346](https://github.com/ianstormtaylor/slate/pull/5346) [`a5e833f6`](https://github.com/ianstormtaylor/slate/commit/a5e833f6550a823689e593317f4579127d8a7fd7) Thanks [@edhager](https://github.com/edhager)! - Fix a problem with Editable not calling the decorate function passed as a prop when it should. + +* [#5343](https://github.com/ianstormtaylor/slate/pull/5343) [`f7f02a8b`](https://github.com/ianstormtaylor/slate/commit/f7f02a8b23f16a3f3103302343e3326549917892) Thanks [@12joan](https://github.com/12joan)! - Fix error when triple-clicking a word preceding a `contenteditable="false"` DOM node in Chrome + +## 0.91.9 + +### Patch Changes + +- [#5339](https://github.com/ianstormtaylor/slate/pull/5339) [`62f8ddd9`](https://github.com/ianstormtaylor/slate/commit/62f8ddd9713617bf474968a10b69c24b71074b41) Thanks [@12joan](https://github.com/12joan)! - Fixes #5335. To prevent performance issues, make sure to wrap custom `renderPlaceholder` values in `useCallback`. + +## 0.91.8 + +### Patch Changes + +- [#5325](https://github.com/ianstormtaylor/slate/pull/5325) [`af3f828b`](https://github.com/ianstormtaylor/slate/commit/af3f828b1206409951708b823fb32965b67c798f) Thanks [@clauderic](https://github.com/clauderic)! - Fix edge-cases in the Android input manager when text leaf nodes are deleted, such as when deleting text leaf nodes adjacent to inline void nodes. + +* [#5327](https://github.com/ianstormtaylor/slate/pull/5327) [`4205e0f0`](https://github.com/ianstormtaylor/slate/commit/4205e0f002929f575f34ef8bb5d3bf9d2670d9d7) Thanks [@YasinChan](https://github.com/YasinChan)! - Fix the issue of composition API and beforeinput event triggering between Chrome versions 60-75 on the Android platform. + +## 0.91.7 + +### Patch Changes + +- [#5322](https://github.com/ianstormtaylor/slate/pull/5322) [`836f6600`](https://github.com/ianstormtaylor/slate/commit/836f660054c6fd4ced793cfa28349543b8db9890) Thanks [@edhager](https://github.com/edhager)! - Add checks to Editable selection change handler to avoid errors + +## 0.91.6 + +### Patch Changes + +- [#5315](https://github.com/ianstormtaylor/slate/pull/5315) [`5784a38b`](https://github.com/ianstormtaylor/slate/commit/5784a38b6bd0f7de50efc890a4d6ceb8fafe191b) Thanks [@clauderic](https://github.com/clauderic)! - The `RestoreDOM` manager that is used Android no longer restores the DOM to its previous state for text mutations. This allows the editor state to be reconciled during a composition without interrupting the composition, as programatically updating the `textContent` of a text node ends the current composition. + +* [#5315](https://github.com/ianstormtaylor/slate/pull/5315) [`5784a38b`](https://github.com/ianstormtaylor/slate/commit/5784a38b6bd0f7de50efc890a4d6ceb8fafe191b) Thanks [@clauderic](https://github.com/clauderic)! - Fixed consumer defined `onInput` event handler not being invoked when passed to the `` component. + +## 0.91.5 + +### Patch Changes + +- [#5313](https://github.com/ianstormtaylor/slate/pull/5313) [`3bf568ed`](https://github.com/ianstormtaylor/slate/commit/3bf568ede2a1df91ff4f88402e0cdd848848f2fb) Thanks [@edhager](https://github.com/edhager)! - Some code clean-up in Editable. + +* [#5306](https://github.com/ianstormtaylor/slate/pull/5306) [`213edbbf`](https://github.com/ianstormtaylor/slate/commit/213edbbf3abc407532aeda72e40d6f01d368c33c) Thanks [@clauderic](https://github.com/clauderic)! - Use memoization to avoid unnecessary `textContent` updates in `` component. + +## 0.91.4 + +### Patch Changes + +- [#5310](https://github.com/ianstormtaylor/slate/pull/5310) [`b94254d6`](https://github.com/ianstormtaylor/slate/commit/b94254d694c6ea6c88cacd661e7bd77165cd2607) Thanks [@etrepum](https://github.com/etrepum)! - Fix to ensure that the latest versions of onChange and renderPlaceholder are used + +## 0.91.3 + +### Patch Changes + +- [#5305](https://github.com/ianstormtaylor/slate/pull/5305) [`11adbf96`](https://github.com/ianstormtaylor/slate/commit/11adbf966c764ffde866be38ada2d32e00105e48) Thanks [@alex-vladut](https://github.com/alex-vladut)! - Allow pasting plain text into editable voids + +## 0.91.2 + +### Patch Changes + +- [#5297](https://github.com/ianstormtaylor/slate/pull/5297) [`967d99eb`](https://github.com/ianstormtaylor/slate/commit/967d99eb36df798ac3163c7d15a01e64fee0668c) Thanks [@edhager](https://github.com/edhager)! - Fix memory leaks by adding clean-up code that looks for ref resets in Editable and Text. + +## 0.91.1 + +### Patch Changes + +- [#5251](https://github.com/ianstormtaylor/slate/pull/5251) [`6fa4b954`](https://github.com/ianstormtaylor/slate/commit/6fa4b954a5e4c67cff87d00b1253b2a838c0db94) Thanks [@YaoKaiLun](https://github.com/YaoKaiLun)! - Fix the cursor jump to an unexpected position after deleting in android + +## 0.91.0 + +### Minor Changes + +- [#5267](https://github.com/ianstormtaylor/slate/pull/5267) [`463edbd2`](https://github.com/ianstormtaylor/slate/commit/463edbd27ed78a4b4a3d38886da4d9e3e8b8efd5) Thanks [@ilya2204](https://github.com/ilya2204)! - Allow to change clipboard fragment format name + +* [#5271](https://github.com/ianstormtaylor/slate/pull/5271) [`9635b992`](https://github.com/ianstormtaylor/slate/commit/9635b992a0d91cecd45e3b6a883a860f14bcaaea) Thanks [@dsvgit](https://github.com/dsvgit)! - If TextComponent decorations keep the same offsets and only paths are changed, prevent re-rendering because only decoration offsets matter when leaves are calculated. + +## 0.90.0 + +### Minor Changes + +- [#5278](https://github.com/ianstormtaylor/slate/pull/5278) [`9c4097a2`](https://github.com/ianstormtaylor/slate/commit/9c4097a26fa92718e6f4fc1f984a70fb5af42ca2) Thanks [@kylemclean](https://github.com/kylemclean)! - Revert to using inline styles for default editor styles + +## 0.89.0 + +### Minor Changes + +- [#5275](https://github.com/ianstormtaylor/slate/pull/5275) [`5bc69d8d`](https://github.com/ianstormtaylor/slate/commit/5bc69d8d657c57eef06aeaa1fa198840d36939c7) Thanks [@12joan](https://github.com/12joan)! - Firefox: fix wrong text highlighting with double-click + +### Patch Changes + +- [#5265](https://github.com/ianstormtaylor/slate/pull/5265) [`3cf51f4d`](https://github.com/ianstormtaylor/slate/commit/3cf51f4d88e8e91faa6ab5d1f2c5f8c8e505ae89) Thanks [@kylemclean](https://github.com/kylemclean)! - Improve compatibility for browsers that do not support ResizeObserver or :where selector + +## 0.88.2 + +### Patch Changes + +- [#5259](https://github.com/ianstormtaylor/slate/pull/5259) [`d7de564d`](https://github.com/ianstormtaylor/slate/commit/d7de564d62848dd8e14535993083c5e9aa1bfacc) Thanks [@Jacfem](https://github.com/Jacfem)! - Updates the selection correctly in readonly shadowdom + +* [#5252](https://github.com/ianstormtaylor/slate/pull/5252) [`179d5c92`](https://github.com/ianstormtaylor/slate/commit/179d5c926eecfdb2b3d8a75c07cb89181c348ad1) Thanks [@frellica](https://github.com/frellica)! - remove qq browser from `beforeinput` compat list because it had updated its chromium core to version 94 + +## 0.88.0 + +### Minor Changes + +- [#5226](https://github.com/ianstormtaylor/slate/pull/5226) [`0141f683`](https://github.com/ianstormtaylor/slate/commit/0141f683659025c7e851c11274cf200da05fd31e) Thanks [@laufeyrut](https://github.com/laufeyrut)! - Check if getBoundingClientRect exist before trying to call bind on it. Makes unit testing experience agains Editable nicer + +## 0.87.1 + +### Patch Changes + +- [#5223](https://github.com/ianstormtaylor/slate/pull/5223) [`120437d6`](https://github.com/ianstormtaylor/slate/commit/120437d61237eeb8df4ed0db92af31698e910eda) Thanks [@alex-vladut](https://github.com/alex-vladut)! - Fix issue preventing editing and copy/paste into editable voids + +## 0.87.0 + +### Minor Changes + +- [#5206](https://github.com/ianstormtaylor/slate/pull/5206) [`96b7fcdb`](https://github.com/ianstormtaylor/slate/commit/96b7fcdbf98a7c8908f5d9613d9898cb24a8ae47) Thanks [@kylemclean](https://github.com/kylemclean)! - Use stylesheet for default styles on Editable components + +## 0.86.0 + +### Minor Changes + +- [#5121](https://github.com/ianstormtaylor/slate/pull/5121) [`06942c6d`](https://github.com/ianstormtaylor/slate/commit/06942c6d7e4b8418a467f022750b010491dbdbe7) Thanks [@laufeyrut](https://github.com/laufeyrut)! - Make it possible to copy/paste void elements + +## 0.83.2 + +### Patch Changes + +- [#5148](https://github.com/ianstormtaylor/slate/pull/5148) [`a2b6786d`](https://github.com/ianstormtaylor/slate/commit/a2b6786d19f8bd5f779c526742a4dc3da971f696) Thanks [@ksimons](https://github.com/ksimons)! - Ensure the min-height for placeholders is set on the correct editor +- [#5155](https://github.com/ianstormtaylor/slate/pull/5154) [`1b14de5`](https://github.com/ianstormtaylor/slate/commit/1b14de5f8e5961ac36eced229abea9abb5be71f9) Thanks [@jameshfisher](https://github.com/jameshfisher) - Revert insertText breaking change that deletes fragment + +## 0.83.1 + +### Patch Changes + +- [#5143](https://github.com/ianstormtaylor/slate/pull/5143) [`347865ca`](https://github.com/ianstormtaylor/slate/commit/347865cafc1f2f3b0fc3d74d8758e082480df6ca) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix scrollIntoView when selection is collapsed inside mark placeholder + +## 0.83.0 + +### Minor Changes + +- [#5123](https://github.com/ianstormtaylor/slate/pull/5123) [`0eb37e79`](https://github.com/ianstormtaylor/slate/commit/0eb37e79150275d3535f1694d8972751a83d826f) Thanks [@laufeyrut](https://github.com/laufeyrut)! - Make it possible to delete block elements with backspace in Chrome and Safari + +### Patch Changes + +- [#5127](https://github.com/ianstormtaylor/slate/pull/5127) [`341041f0`](https://github.com/ianstormtaylor/slate/commit/341041f0b721926cca3f9dee98dc4589f2c96797) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Cleanup and fix insertion placeholder mark compare + +## 0.82.2 + +### Patch Changes + +- [#5120](https://github.com/ianstormtaylor/slate/pull/5120) [`9815bdab`](https://github.com/ianstormtaylor/slate/commit/9815bdabdd34221ed86f68b556cfa43d845e2db0) Thanks [@hueyhe](https://github.com/hueyhe)! - Fix editor selection out of sync in readonly mode + +* [#5100](https://github.com/ianstormtaylor/slate/pull/5100) [`8eb1972b`](https://github.com/ianstormtaylor/slate/commit/8eb1972b5b2f9489936b1759afb76574040af5a0) Thanks [@KittyGiraudel](https://github.com/KittyGiraudel)! - Add `aria-multiline` attribute to textbox editor + +- [#5105](https://github.com/ianstormtaylor/slate/pull/5105) [`55b95740`](https://github.com/ianstormtaylor/slate/commit/55b9574097f6008bda7ed8e3cb7aa9dd607d9f49) Thanks [@yume-chan](https://github.com/yume-chan)! - Change `Element` component to use callback-style ref to reliably track DOM node of rendered custom elements + +## 0.82.1 + +### Patch Changes + +- [#5084](https://github.com/ianstormtaylor/slate/pull/5084) [`50de780b`](https://github.com/ianstormtaylor/slate/commit/50de780b1c32fa2c52ad88d42031748f9d3944e9) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix selection handling with slow flush in mark placeholders on android, fix auto-capitalize after placeholder + +* [#5091](https://github.com/ianstormtaylor/slate/pull/5091) [`e18879e7`](https://github.com/ianstormtaylor/slate/commit/e18879e728077b09580b29e9a6683aaa66629bc5) Thanks [@e1himself](https://github.com/e1himself)! - Fix `withReact()` function type definition + +## 0.82.0 + +### Minor Changes + +- [#5041](https://github.com/ianstormtaylor/slate/pull/5041) [`9bc0b613`](https://github.com/ianstormtaylor/slate/commit/9bc0b6132aa288a37ae9a85d0e59a9d5a75ebdd7) Thanks [@bryanph](https://github.com/bryanph)! - - Introduces a `useSlateSelection` hook that triggers whenever the selection changes. + - This also changes the implementation of SlateContext to use an incrementing value instead of an array replace to trigger updates + - Introduces a `useSlateWithV` hook that includes the version counter which can be used to prevent re-renders + +* [#4988](https://github.com/ianstormtaylor/slate/pull/4988) [`fbab6331`](https://github.com/ianstormtaylor/slate/commit/fbab6331a5ecebd9e98c6c8c87d6f4b3b7c43bd0) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Android input handling rewrite, replace composition insert prefixes with decoration based mark placeholders + +## 0.81.3 + +### Patch Changes + +- [#5054](https://github.com/ianstormtaylor/slate/pull/5054) [`1cc0797f`](https://github.com/ianstormtaylor/slate/commit/1cc0797f53f22e650198c83192ba5fc35c525a15) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix toSlatePoint in void nodes with nested editors if children are rendered as the last child + +* [#5042](https://github.com/ianstormtaylor/slate/pull/5042) [`11a93e65`](https://github.com/ianstormtaylor/slate/commit/11a93e65de4b197a43777e575caf13d7a05d5dc9) Thanks [@bryanph](https://github.com/bryanph)! - Upgrade next.js and source-map-loader packages + +## 0.81.2 + +### Patch Changes + +- [#5045](https://github.com/ianstormtaylor/slate/pull/5045) [`0b2e6c79`](https://github.com/ianstormtaylor/slate/commit/0b2e6c79c08fc4eba32be7a424da758ba74573c3) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Don't native insert inside blocks with whitespace="pre" containing tab chars to work around https://bugs.chromium.org/p/chromium/issues/detail?id=1219139 + +* [#5046](https://github.com/ianstormtaylor/slate/pull/5046) [`f96b6597`](https://github.com/ianstormtaylor/slate/commit/f96b659755673375ef1b6a1cc925c73ce4934a03) Thanks [@BitPhinix](https://github.com/BitPhinix)! - fix macos accent menu when using arrow keys + +## 0.81.0 + +### Minor Changes + +- [#4999](https://github.com/ianstormtaylor/slate/pull/4999) [`fe13a8f9`](https://github.com/ianstormtaylor/slate/commit/fe13a8f9e750569342ee004951e34233ab6614bf) Thanks [@alexandercampbell](https://github.com/alexandercampbell)! - Add new Slate.Scrubber interface to allow scrubbing end user data from exception + text. The default behavior remains unchanged. + +## 0.80.0 + +### Patch Changes + +- [#5007](https://github.com/ianstormtaylor/slate/pull/5007) [`92c5730a`](https://github.com/ianstormtaylor/slate/commit/92c5730a96223a683b3c95651eb4c90a5caca21a) Thanks [@jasonphillips](https://github.com/jasonphillips)! - Revert #4876 & #4910 to restore original decorations behavior + +## 0.79.0 + +### Minor Changes + +- [#4981](https://github.com/ianstormtaylor/slate/pull/4981) [`cb8a5515`](https://github.com/ianstormtaylor/slate/commit/cb8a551508c023346fd3aa0af1a5a80ffd6a37cd) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Add `ReactEditor.isComposing(editor)` to get the current `isComposing` state + +## 0.78.1 + +### Patch Changes + +- [#4979](https://github.com/ianstormtaylor/slate/pull/4979) [`6afa9f6a`](https://github.com/ianstormtaylor/slate/commit/6afa9f6a719092368b92dc3342e21e44d457d77e) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Unset isComposing on keydown with isCompsing false + +## 0.77.4 + +### Patch Changes + +- [#4965](https://github.com/ianstormtaylor/slate/pull/4965) [`a4536e2a`](https://github.com/ianstormtaylor/slate/commit/a4536e2aa2703d4c4460a54f87997ce76a722689) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix triple click handling in nested blocks + +## 0.77.3 + +### Patch Changes + +- [#4957](https://github.com/ianstormtaylor/slate/pull/4957) [`c1e3fbaa`](https://github.com/ianstormtaylor/slate/commit/c1e3fbaab969f2e78303f9ba00f26b88c575cdd1) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Don't treat events with non-selection target range as native + +## 0.77.2 + +### Patch Changes + +- [#4951](https://github.com/ianstormtaylor/slate/pull/4951) [`5b51e87d`](https://github.com/ianstormtaylor/slate/commit/5b51e87d511e3a8c05a679903650cb256f3bf044) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix double insert in anchor element decorations + +## 0.77.1 + +### Patch Changes + +- [#4948](https://github.com/ianstormtaylor/slate/pull/4948) [`9957c214`](https://github.com/ianstormtaylor/slate/commit/9957c214357dbbd5492ec4761fd6e1c7b14310f5) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Prevent native insert at the end of anchor elements + +## 0.77.0 + +### Minor Changes + +- [#4926](https://github.com/ianstormtaylor/slate/pull/4926) [`076ab9a6`](https://github.com/ianstormtaylor/slate/commit/076ab9a67a5d7bf54062e551e6c29b1464da7e99) Thanks [@Auralytical](https://github.com/Auralytical)! - Fix firefox three digit version check + +### Patch Changes + +- [#4944](https://github.com/ianstormtaylor/slate/pull/4944) [`486c385b`](https://github.com/ianstormtaylor/slate/commit/486c385bc52ae76890f67ee9e8965955a6de3f61) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Fix crash when tripple clicking editor root + +## 0.76.1 + +### Patch Changes + +- [#4923](https://github.com/ianstormtaylor/slate/pull/4923) [`08d5a12c`](https://github.com/ianstormtaylor/slate/commit/08d5a12c9131c715ba75d3cc6f87108f8e6a8f59) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Call keyDown handler while composing + +* [#4920](https://github.com/ianstormtaylor/slate/pull/4920) [`f6b7ca1f`](https://github.com/ianstormtaylor/slate/commit/f6b7ca1f97bcc9e6136ab6ba6c7e9bcb1c4fd9bb) Thanks [@adri1wald](https://github.com/adri1wald)! - fix useFocused hook in react >= 17 + +- [#4914](https://github.com/ianstormtaylor/slate/pull/4914) [`aff67312`](https://github.com/ianstormtaylor/slate/commit/aff67312cbfa7e45df5cf6abcaec9f4f7d5f1a89) Thanks [@sennpang](https://github.com/sennpang)! - Fixed Triple click selection and copy&paste in read-only mode + +* [#4919](https://github.com/ianstormtaylor/slate/pull/4919) [`7de7cdcf`](https://github.com/ianstormtaylor/slate/commit/7de7cdcf5625d44dbb2dc9faf52675374e51499f) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Restore user selection after applying beforeinput with target range + +- [#4922](https://github.com/ianstormtaylor/slate/pull/4922) [`9892cf0f`](https://github.com/ianstormtaylor/slate/commit/9892cf0ffbd741cc2880d1f0bd0d7c1b36145bbd) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Make Slate component onChange optional + +## 0.76.0 + +### Minor Changes + +- [#4873](https://github.com/ianstormtaylor/slate/pull/4873) [`20acca4b`](https://github.com/ianstormtaylor/slate/commit/20acca4bc8f31bd1aa6fbca2c49aaae5f31cadfe) Thanks [@bryanph](https://github.com/bryanph)! - A different behavior for inserting a soft break with shift+enter is quite common in rich text editors. Right now you have to do this in onKeyDown which is not so nice. This adds a separate insertSoftBreak method on the editor instance that gets called when a soft break is inserted. This maintains the current default behavior for backwards compatibility (it just splits the block). But at least you can easily overwrite it now. + + If you rely on overwriting editor.insertBreak for extra behavior for soft breaks this might be a breaking change for you and you should overwrite editor.insertSoftBreak instead. + +### Patch Changes + +- [#4901](https://github.com/ianstormtaylor/slate/pull/4901) [`5ef346fe`](https://github.com/ianstormtaylor/slate/commit/5ef346feb9e6430b3b6af66f196e5445a9ee3ff2) Thanks [@bryanph](https://github.com/bryanph)! - Fixes a bug where nodes remounted on split_node and merge_node + +* [#4885](https://github.com/ianstormtaylor/slate/pull/4885) [`07669dca`](https://github.com/ianstormtaylor/slate/commit/07669dca4b0641506ca857bd781c460dae7606a9) Thanks [@ryanmitts](https://github.com/ryanmitts)! - toSlatePoint should not consider a selection within a void node if the void node isn't in the editor itself. + + Prior to this fix, a nested Slate editor inside a void node in a parent editor would not allow you to start typing text in a blank editor state correctly. After the first character insertion, the selection would jump back to the start of the nested editor. + +- [#4910](https://github.com/ianstormtaylor/slate/pull/4910) [`2a8d86f1`](https://github.com/ianstormtaylor/slate/commit/2a8d86f1a40bcc806422e6fe3658ddd810ce73a5) Thanks [@jasonphillips](https://github.com/jasonphillips)! - Fix decorations applied across nested elements + +## 0.75.0 + +### Minor Changes + +- [#4883](https://github.com/ianstormtaylor/slate/pull/4883) [`3b3b0e32`](https://github.com/ianstormtaylor/slate/commit/3b3b0e32df4df9fb4cf1d82c0c09b7242c708169) Thanks [@always-maap](https://github.com/always-maap)! - Fix chrome and edge three digit version check + +## 0.74.2 + +### Patch Changes + +- [#4876](https://github.com/ianstormtaylor/slate/pull/4876) [`1b205c08`](https://github.com/ianstormtaylor/slate/commit/1b205c087bef2f2360679c46801804d6d30a8139) Thanks [@nemanja-tosic](https://github.com/nemanja-tosic)! - Fix decorations not getting applied for children unless parent changes +- [#4874](https://github.com/ianstormtaylor/slate/pull/4874) [`4d28948`](https://github.com/ianstormtaylor/slate/commit/4d28948b901b1724493dd0a782e3001149546533) Thanks [@bryanph](https://github.com/bryanph)! - Revert #4755 + +## 0.74.1 + +### Patch Changes + +- [#4868](https://github.com/ianstormtaylor/slate/pull/4868) [`7499d4b4`](https://github.com/ianstormtaylor/slate/commit/7499d4b4c01a089906a96f30f6c04256204ca65e) Thanks [@sennpang](https://github.com/sennpang)! - fixed cursor when triple clicking on text and type over it, fixes #4862 + +## 0.74.0 + +### Minor Changes + +- [#4841](https://github.com/ianstormtaylor/slate/pull/4841) [`47f2403e`](https://github.com/ianstormtaylor/slate/commit/47f2403e3a46d84b8d8f99c6e2bf41f2699e30df) Thanks [@Fibs7000](https://github.com/Fibs7000)! - Added redux-style useSlateSelector to improve and prevent unneccessary rerendering with the useSlate hook + +## 0.73.0 + +### Patch Changes + +- [#4840](https://github.com/ianstormtaylor/slate/pull/4840) [`100448d5`](https://github.com/ianstormtaylor/slate/commit/100448d55c018351d5a5ffbe18efa207e668f1fb) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Render void spacer in readonly mode + +## 0.72.9 + +### Patch Changes + +- [#4828](https://github.com/ianstormtaylor/slate/pull/4828) [`d5ac8237`](https://github.com/ianstormtaylor/slate/commit/d5ac82373b97e389528688ec6dbc7c72715cc360) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Reset isDraggingInternally onDragEnd and onDrop even if the event is handled by the editable handler + +* [#4819](https://github.com/ianstormtaylor/slate/pull/4819) [`80661509`](https://github.com/ianstormtaylor/slate/commit/80661509ecf39b5d8256fa387c7eff15f60bf612) Thanks [@ugaya40](https://github.com/ugaya40)! - Fix a possible update of react state after Slate component is unmounted + +## 0.72.8 + +### Patch Changes + +- [#4816](https://github.com/ianstormtaylor/slate/pull/4816) [`6d62abc1`](https://github.com/ianstormtaylor/slate/commit/6d62abc1039cf93ce90bd9332a505471df8118ba) Thanks [@dylans](https://github.com/dylans)! - - Revert #4749, DOM & Slate selection are mismatching + +## 0.72.7 + +### Patch Changes + +- [#4813](https://github.com/ianstormtaylor/slate/pull/4813) [`a5fd62dd`](https://github.com/ianstormtaylor/slate/commit/a5fd62ddd646553841a54616f7a5528e310bfd22) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Don't throw in toSlatePoint while using supressThrow if leaf has no text node + +* [#4798](https://github.com/ianstormtaylor/slate/pull/4798) [`3796c514`](https://github.com/ianstormtaylor/slate/commit/3796c514d6da0db8656486151147d92e73a2350a) Thanks [@hueyhe](https://github.com/hueyhe)! - Fix text not rendered on ssr + +- [#4809](https://github.com/ianstormtaylor/slate/pull/4809) [`e9987529`](https://github.com/ianstormtaylor/slate/commit/e9987529895d3ef2740f8f466a9ef9ce4c3e37c2) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Flush onDOMSelectionChange on onDOMBeforeInput + +## 0.72.6 + +### Patch Changes + +- [#4796](https://github.com/ianstormtaylor/slate/pull/4796) [`5d8a1606`](https://github.com/ianstormtaylor/slate/commit/5d8a16066949981ead34466af26bcb8e4ffa994b) Thanks [@hueyhe](https://github.com/hueyhe)! - Fix text not rendered on server-side rendering + +## 0.72.5 + +### Patch Changes + +- [#4749](https://github.com/ianstormtaylor/slate/pull/4749) [`a3dfb151`](https://github.com/ianstormtaylor/slate/commit/a3dfb151d432ec67f10847997fc71b009bcf5c00) Thanks [@Jabher](https://github.com/Jabher)! - Fix "cannot resolve DOM point" error when switching between multiple errors + +## 0.72.4 + +### Patch Changes + +- [#4753](https://github.com/ianstormtaylor/slate/pull/4753) [`e9a46ad2`](https://github.com/ianstormtaylor/slate/commit/e9a46ad29e0376a45051c4a8100c5678784b785c) Thanks [@alessiogaldy](https://github.com/alessiogaldy)! - Fix "editor.insertText never gets called inside plugins on android" + +* [#4779](https://github.com/ianstormtaylor/slate/pull/4779) [`345b8fc9`](https://github.com/ianstormtaylor/slate/commit/345b8fc9e8f073674c006098bd843823309db2e2) Thanks [@alessiogaldy](https://github.com/alessiogaldy)! - Android editable updates + + - Remove logic to delay handling of text insertion + - Call Transforms.setSelection before Editor.insertText to adjust position + +- [#4786](https://github.com/ianstormtaylor/slate/pull/4786) [`67aa1f10`](https://github.com/ianstormtaylor/slate/commit/67aa1f10106e15486031b4103285c7fae4373056) Thanks [@alessiogaldy](https://github.com/alessiogaldy)! - - Restore logic to delay text insertion on android + - Always call Trasform.setSelection before calling Editor.insertText + +* [#4755](https://github.com/ianstormtaylor/slate/pull/4755) [`8daa77e9`](https://github.com/ianstormtaylor/slate/commit/8daa77e9fab6b222ad796b420b86f3ec88999a39) Thanks [@jhurwitz](https://github.com/jhurwitz)! - fix useFocused hook + +- [#4788](https://github.com/ianstormtaylor/slate/pull/4788) [`a8c08a4e`](https://github.com/ianstormtaylor/slate/commit/a8c08a4e0107bccfe972149a512643fbbfcfb9bf) Thanks [@YasinChan](https://github.com/YasinChan)! - Android merge `Editor.insertText` logic. + +## 0.72.2 + +### Patch Changes + +- [#4734](https://github.com/ianstormtaylor/slate/pull/4734) [`3c07a870`](https://github.com/ianstormtaylor/slate/commit/3c07a8706ef152fe35c5363a2316aa291c12c2f0) Thanks [@YasinChan](https://github.com/YasinChan)! - [AndroidEditor] Solve input association problems and add click events. +- [#4733](https://github.com/ianstormtaylor/slate/pull/4733) [`ccafb69`](https://github.com/ianstormtaylor/slate/commit/ccafb6982f56364becc8ca39ed6c1953a5febac3) Thanks [@Schipy](https://github.com/Schipy)! - Optimize TextString rendering to support browser/OS text features, e.g. fix native spellcheck. + +## 0.72.1 + +### Patch Changes + +- [#4720](https://github.com/ianstormtaylor/slate/pull/4720) [`1217021a`](https://github.com/ianstormtaylor/slate/commit/1217021a9a42563c9ee951ab670255c209863452) Thanks [@bryanph](https://github.com/bryanph)! - Add origin event type to setFragmentData to be able to distinguish copy, cut and drag + +* [#4727](https://github.com/ianstormtaylor/slate/pull/4727) [`0334851c`](https://github.com/ianstormtaylor/slate/commit/0334851cb1da3fd194278e48985166eb658eaf24) Thanks [@ahoisl](https://github.com/ahoisl)! - Fix "Cannot resolve from DOM point" error on onDomSelectionChange for readonly void elements + +## 0.72.0 + +### Minor Changes + +- [#4702](https://github.com/ianstormtaylor/slate/pull/4702) [`8bc6a464`](https://github.com/ianstormtaylor/slate/commit/8bc6a464600d6820d85f55fdaf71e9ea01702eb5) Thanks [@ttitoo](https://github.com/ttitoo)! - Fix CJK IME (e.g. Chinese or Japanese) double input + +### Patch Changes + +- [#4706](https://github.com/ianstormtaylor/slate/pull/4706) [`6d194077`](https://github.com/ianstormtaylor/slate/commit/6d194077763ec0a9d5642be5cafef20e65dbce8e) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Update android restoreDOM to use partial dom restoring + +* [#4707](https://github.com/ianstormtaylor/slate/pull/4707) [`c020ca23`](https://github.com/ianstormtaylor/slate/commit/c020ca23b6f5d2307eb62630566ec711def89fcf) Thanks [@ahoisl](https://github.com/ahoisl)! - fix: add 'readonly' dependency for onDragStart callback + +## 0.71.0 + +### Minor Changes + +- [#4682](https://github.com/ianstormtaylor/slate/pull/4682) [`e5380655`](https://github.com/ianstormtaylor/slate/commit/e53806557217b08bce6217b7d871cd5ae7dad31c) Thanks [@matthewkeil](https://github.com/matthewkeil)! - Support SSR for autoCorrect, spellCheck and autoCapitalize. + Fixes prop mismatch between server and client. + Removes the need to add + + +## 0.70.2 + +### Patch Changes + +- [#4669](https://github.com/ianstormtaylor/slate/pull/4669) [`807716d7`](https://github.com/ianstormtaylor/slate/commit/807716d7dfb0fa5791cdcdfeaf4ac027a003127b) Thanks [@BitPhinix](https://github.com/BitPhinix)! - Flush scheduleOnDOMSelectionChange on beforeinput + +* [#4661](https://github.com/ianstormtaylor/slate/pull/4661) [`0f194a86`](https://github.com/ianstormtaylor/slate/commit/0f194a86a08d5de07e58e20fb95c9dc760e9d52d) Thanks [@leoc4e](https://github.com/leoc4e)! - use ownerDocument to create element + +## 0.70.1 + +### Patch Changes + +- [#4654](https://github.com/ianstormtaylor/slate/pull/4654) [`2c7750ca`](https://github.com/ianstormtaylor/slate/commit/2c7750cac5949a935a570a9590a82187673b9a44) Thanks [@anho](https://github.com/anho)! - weak guard on DataTransfer to not rely on current window + +* [#4652](https://github.com/ianstormtaylor/slate/pull/4652) [`95389ed7`](https://github.com/ianstormtaylor/slate/commit/95389ed7b03487aa066af277afcccba440c32f24) Thanks [@karthikcodes6](https://github.com/karthikcodes6)! - Disabled the auto scroll behaviour when the editor has any active selection + +- [#4650](https://github.com/ianstormtaylor/slate/pull/4650) [`b6643132`](https://github.com/ianstormtaylor/slate/commit/b6643132f1f3b64f019a601ee2f44a521c122ad3) Thanks [@e1himself](https://github.com/e1himself)! - Do not disable Grammarly extension in Slate editors + +## 0.70.0 + +### Patch Changes + +- [#4636](https://github.com/ianstormtaylor/slate/pull/4636) [`9e8d5e2b`](https://github.com/ianstormtaylor/slate/commit/9e8d5e2b9bbff1ec7161e292635a074ba3538774) Thanks [@cmmartin](https://github.com/cmmartin)! - Fixes drop actions in editors rendered in iFrames. + +## 0.69.0 + +### Minor Changes + +- [#4625](https://github.com/ianstormtaylor/slate/pull/4625) [`e54f2a0e`](https://github.com/ianstormtaylor/slate/commit/e54f2a0ea01ddc94f3ad14e812602b0ed824aeb3) Thanks [@echarles](https://github.com/echarles)! - insertTextData and insertFragmentData return a boolean (true if some content has been effectively inserted) + +## 0.68.1 + +### Patch Changes + +- [#4627](https://github.com/ianstormtaylor/slate/pull/4627) [`ec01e75f`](https://github.com/ianstormtaylor/slate/commit/ec01e75fff29b3e7b710b59a6ba8106d9aa9ca5e) Thanks [@jameshfisher](https://github.com/jameshfisher)! - Fixed issues where cursor jumps to wrong location + +## 0.68.0 + +### Minor Changes + +- [#4620](https://github.com/ianstormtaylor/slate/pull/4620) [`0b59ad54`](https://github.com/ianstormtaylor/slate/commit/0b59ad5414f682b510453696b6f45d5a46cb66bb) Thanks [@NicklasAndersson](https://github.com/NicklasAndersson)! - Support selection in readOnly=true editors. + +## 0.67.1 + +### Patch Changes + +- [#4616](https://github.com/ianstormtaylor/slate/pull/4616) [`77d9f60a`](https://github.com/ianstormtaylor/slate/commit/77d9f60ab5e497aadf2d0c9564b1e79525984734) Thanks [@jameshfisher](https://github.com/jameshfisher)! - Fixed crash on self-deleting void node + +* [#4617](https://github.com/ianstormtaylor/slate/pull/4617) [`b186d3ea`](https://github.com/ianstormtaylor/slate/commit/b186d3ea12ce59c024a56fcbad4604c919757d36) Thanks [@imdbsd](https://github.com/imdbsd)! - Fix crash on drag and drop image on readOnly editable + +- [#4614](https://github.com/ianstormtaylor/slate/pull/4614) [`72160fac`](https://github.com/ianstormtaylor/slate/commit/72160fac08fde98d223c9dd2b4263897d23454f6) Thanks [@echarles](https://github.com/echarles)! - Add insertFragmentData and insertTextData to the ReactEditor API + +## 0.67.0 + +### Minor Changes + +- [#4540](https://github.com/ianstormtaylor/slate/pull/4540) [`11ef83b4`](https://github.com/ianstormtaylor/slate/commit/11ef83b47fca84d1f908b5c9eeefada516fe9fed) Thanks [@bryanph](https://github.com/bryanph)! - The Slate Provider's "value" prop is now only used as initial state for editor.children as was intended before. If your code relies on replacing editor.children you should do so by replacing it directly instead of relying on the "value" prop to do this for you. + +### Patch Changes + +- [#4577](https://github.com/ianstormtaylor/slate/pull/4577) [`4b2e4000`](https://github.com/ianstormtaylor/slate/commit/4b2e4000d6253bd86fab237b6f2c70e9f8d30f09) Thanks [@jameshfisher](https://github.com/jameshfisher)! - Fixed a bug that removed the selection when hovering over a non-selectable DOM element + +* [#4605](https://github.com/ianstormtaylor/slate/pull/4605) [`87ab2efa`](https://github.com/ianstormtaylor/slate/commit/87ab2efa41a5b7a1324b3fc97117a1cdd3b41d66) Thanks [@jaked](https://github.com/jaked)! - defer native events within Editable to avoid bugs with Editor + +- [#4584](https://github.com/ianstormtaylor/slate/pull/4584) [`f40e515d`](https://github.com/ianstormtaylor/slate/commit/f40e515dc7f956b7fd859688c0170f2c1763fecf) Thanks [@jameshfisher](https://github.com/jameshfisher)! - Fixed bug: setting selection from `contentEditable:false` element causes crash + +## 0.66.7 + +### Patch Changes + +- [#4588](https://github.com/ianstormtaylor/slate/pull/4588) [`ae65ae5f`](https://github.com/ianstormtaylor/slate/commit/ae65ae5f717c877eee0e3f839b76fc18d8b44999) Thanks [@jaked](https://github.com/jaked)! - revert #4455 / #4512; fix triple-click by unhanging range with void + +## 0.66.6 + +### Patch Changes + +- [#4556](https://github.com/ianstormtaylor/slate/pull/4556) [`b1084918`](https://github.com/ianstormtaylor/slate/commit/b10849182086699d4bb18209a37ea6247f712bd0) Thanks [@jaked](https://github.com/jaked)! - fix forced update in TextString in case of double render + +## 0.66.4 + +### Patch Changes + +- [#4304](https://github.com/ianstormtaylor/slate/pull/4304) [`7ba486aa`](https://github.com/ianstormtaylor/slate/commit/7ba486aa397411a3e83ab636b0982167d95319c0) Thanks [@davidruisinger](https://github.com/davidruisinger)! - Fixed a bug where text was typed backwards within nested editor + +## 0.66.3 + +### Patch Changes + +- [#4547](https://github.com/ianstormtaylor/slate/pull/4547) [`677da0ca`](https://github.com/ianstormtaylor/slate/commit/677da0ca87ffefb36676200fee5cf5cf0136b22e) Thanks [@clauderic](https://github.com/clauderic)! - Fixed a bug that caused the editor to be unable to resolve a Slate point from a DOM point when selecting an entire document that ended in a new line in Firefox. + +* [#4526](https://github.com/ianstormtaylor/slate/pull/4526) [`bc85497d`](https://github.com/ianstormtaylor/slate/commit/bc85497d58dc2eddb0918eed4c7d25d040fa653f) Thanks [@VictorBaron](https://github.com/VictorBaron)! - Fix - delete selected inline void in chrome + +- [#4549](https://github.com/ianstormtaylor/slate/pull/4549) [`f9c41a56`](https://github.com/ianstormtaylor/slate/commit/f9c41a569cab2000bd14df5f516c80089b3bf0ac) Thanks [@nemanja-tosic](https://github.com/nemanja-tosic)! - Fix deletion of expanded range (#4546) + +## 0.66.2 + +### Patch Changes + +- [#4529](https://github.com/ianstormtaylor/slate/pull/4529) [`bd80a0b8`](https://github.com/ianstormtaylor/slate/commit/bd80a0b8dc108a05addb6e599b7f6272acc8aa57) Thanks [@nemanja-tosic](https://github.com/nemanja-tosic)! - Fix erroneous text after native insert + +## 0.66.1 + +### Patch Changes + +- [#4514](https://github.com/ianstormtaylor/slate/pull/4514) [`8b5dbc3d`](https://github.com/ianstormtaylor/slate/commit/8b5dbc3dc7716b51b74a3b7a3dbe2609642f2f6c) Thanks [@dylans](https://github.com/dylans)! - fix(react-editor): reset focus offset when triple clicking + +## 0.66.0 + +### Minor Changes + +- [#3888](https://github.com/ianstormtaylor/slate/pull/3888) [`25afbd43`](https://github.com/ianstormtaylor/slate/commit/25afbd43001cdee852af6386d2b701d943b788da) Thanks [@bkrausz](https://github.com/bkrausz)! - Use native character insertion to fix browser/OS text features + +### Patch Changes + +- [#4475](https://github.com/ianstormtaylor/slate/pull/4475) [`c1433f56`](https://github.com/ianstormtaylor/slate/commit/c1433f56cfe13feb826264989bb4f68a0eefab62) Thanks [@skogsmaskin](https://github.com/skogsmaskin)! - [slate-react]: fix selection bugs when multiple editors share value + +* [#4132](https://github.com/ianstormtaylor/slate/pull/4132) [`48b71294`](https://github.com/ianstormtaylor/slate/commit/48b7129447347c9cf7a0535026287896ef59779b) Thanks [@ulion](https://github.com/ulion)! - Make onDomSelectionChange trigger after onClick. + +- [#4493](https://github.com/ianstormtaylor/slate/pull/4493) [`3dd74dd5`](https://github.com/ianstormtaylor/slate/commit/3dd74dd58daa907bfa1fb44bc5655ae2fc8ddb35) Thanks [@dylans](https://github.com/dylans)! - Update error message for useSlate + +* [#4450](https://github.com/ianstormtaylor/slate/pull/4450) [`220f2d2c`](https://github.com/ianstormtaylor/slate/commit/220f2d2ce6dffcc1a0f2ea1e8725601b8ea1949b) Thanks [@neko-neko](https://github.com/neko-neko)! - Changed so that the onKeyDown event do not fired while IME converting. + +- [#4452](https://github.com/ianstormtaylor/slate/pull/4452) [`935b3a79`](https://github.com/ianstormtaylor/slate/commit/935b3a79d6ec7d7e8f20804b2703e984e9c396e0) Thanks [@dylans](https://github.com/dylans)! - double ime fix for qq browser + +* [#4500](https://github.com/ianstormtaylor/slate/pull/4500) [`50bb3d7e`](https://github.com/ianstormtaylor/slate/commit/50bb3d7e32d640957018831526235ca656963f1d) Thanks [@tubbo](https://github.com/tubbo)! - Upgrade `is-plain-object` to v5.0.0 + +- [#4480](https://github.com/ianstormtaylor/slate/pull/4480) [`e51566ad`](https://github.com/ianstormtaylor/slate/commit/e51566ada84cfa107c445cc6f3908e78c18656b6) Thanks [@imdbsd](https://github.com/imdbsd)! - Add key for Children SelectedContext.Provider + +* [#4454](https://github.com/ianstormtaylor/slate/pull/4454) [`d06706c9`](https://github.com/ianstormtaylor/slate/commit/d06706c9e15bbbdd7cdd9a1bbb38c87d37c85ea1) Thanks [@imdbsd](https://github.com/imdbsd)! - Fix to read fragment from data-slate-fragment when application/x-slate-fragment is missing + +- [#4460](https://github.com/ianstormtaylor/slate/pull/4460) [`ace397f9`](https://github.com/ianstormtaylor/slate/commit/ace397f96602d93ab9216e3d3434f55eef981e4d) Thanks [@dylans](https://github.com/dylans)! - fix double character insertion regression due to unnecessary memo + +* [#4451](https://github.com/ianstormtaylor/slate/pull/4451) [`8e4120ae`](https://github.com/ianstormtaylor/slate/commit/8e4120ae315151705152e62944737ca4f62ad446) Thanks [@githoniel](https://github.com/githoniel)! - fix IME double input with editor mark + +- [#4503](https://github.com/ianstormtaylor/slate/pull/4503) [`2065c5bd`](https://github.com/ianstormtaylor/slate/commit/2065c5bdfd0de9f7d5ea049b23cd22b71bb80225) Thanks [@bytrangle](https://github.com/bytrangle)! - Fix incorrect selection when triple clicking blocks in Editable component + +* [#4433](https://github.com/ianstormtaylor/slate/pull/4433) [`a1f925bd`](https://github.com/ianstormtaylor/slate/commit/a1f925bddfb8e4507977b3449972d4521d05b148) Thanks [@imdbsd](https://github.com/imdbsd)! - Fix copy-paste a slate fragment on android editable + +- [#4365](https://github.com/ianstormtaylor/slate/pull/4365) [`906e5af1`](https://github.com/ianstormtaylor/slate/commit/906e5af1b1af07454da0a93490fca70b58fd9986) Thanks [@samarsault](https://github.com/samarsault)! - fix a bug where element selections were not captured by useSelected + +* [#4342](https://github.com/ianstormtaylor/slate/pull/4342) [`834ce348`](https://github.com/ianstormtaylor/slate/commit/834ce3483dc407a6293ba29cac8f192c13f57b01) Thanks [@imdbsd](https://github.com/imdbsd)! - Fix editor mark is not inserted on android + +## 0.65.3 + +### Patch Changes + +- [#4175](https://github.com/ianstormtaylor/slate/pull/4175) [`bde6e804`](https://github.com/ianstormtaylor/slate/commit/bde6e80476ee0ba7a14c8c7625b51de9e58bb170) Thanks [@gyh9457](https://github.com/gyh9457)! - Fixed a bug in the memoization logic for the leaves of text nodes. + +* [#4394](https://github.com/ianstormtaylor/slate/pull/4394) [`01889807`](https://github.com/ianstormtaylor/slate/commit/0188980796b7a4b23ef2ee9e7e468532c1f5c8c4) Thanks [@jaked](https://github.com/jaked)! - fix bug where decorate is not called on immediate children of editor + +- [#4049](https://github.com/ianstormtaylor/slate/pull/4049) [`6c844227`](https://github.com/ianstormtaylor/slate/commit/6c8442272105ec78b88d38efecb7aab9bb4e41de) Thanks [@ulion](https://github.com/ulion)! - Fix ios chrome ime double input issue. + +* [#4427](https://github.com/ianstormtaylor/slate/pull/4427) [`3f69a9f3`](https://github.com/ianstormtaylor/slate/commit/3f69a9f3951b5beca77b065aaa5eba0737e68a8e) Thanks [@ben10code](https://github.com/ben10code)! - Fix crash when unmounting an editor rendered within a React portal. The issue was arising at unmount time, because `getRootNode` returned the dettached portal node and it is not an instance of `Document` or `ShadowRoot`. As a fix, `getDocumentOrShadowRoot` has been refactored to return a root node instead of throwing. In sum, this patch fixes a regression bug introduced by https://github.com/ianstormtaylor/slate/pull/3749/ + +- [#4369](https://github.com/ianstormtaylor/slate/pull/4369) [`c217dbb5`](https://github.com/ianstormtaylor/slate/commit/c217dbb5b9190753298bbc117a49af940a3a0d53) Thanks [@thesunny](https://github.com/thesunny)! - Scroll when inserting new text will now scroll parent scrollables + +* [#4333](https://github.com/ianstormtaylor/slate/pull/4333) [`e0776c5c`](https://github.com/ianstormtaylor/slate/commit/e0776c5c923f1fb33a130599e558e6dffdde40f4) Thanks [@dylans](https://github.com/dylans)! - Allow setFragmentData to work without copy/paste or DnD data structure + +- [#4421](https://github.com/ianstormtaylor/slate/pull/4421) [`237edc6e`](https://github.com/ianstormtaylor/slate/commit/237edc6ea616c9171611e632e146872a245bdb0e) Thanks [@jaked](https://github.com/jaked)! - fix decorate bug (#4277) without adding extra layers of render tree + +* [#4347](https://github.com/ianstormtaylor/slate/pull/4347) [`46c8871c`](https://github.com/ianstormtaylor/slate/commit/46c8871c9cafd3017b2c9afff9b36f0527c2205f) Thanks [@aiwenar](https://github.com/aiwenar)! - Re-render leaf when new properties were added to it + +- [#4352](https://github.com/ianstormtaylor/slate/pull/4352) [`4b373dc2`](https://github.com/ianstormtaylor/slate/commit/4b373dc29055a6fb3e2cdb26dd4cd023787603a5) Thanks [@hueyhe](https://github.com/hueyhe)! - Do not display placeholder when composing + +## 0.65.2 + +### Patch Changes + +- [#4331](https://github.com/ianstormtaylor/slate/pull/4331) [`a3bc97af`](https://github.com/ianstormtaylor/slate/commit/a3bc97af3e3bc88ccf9ab7eadb1a56c0bc92f436) Thanks [@golota60](https://github.com/golota60)! - Fix deletion of selected inline void nodes in Safari when presssing `backspace` or `delete`. This is a bug that [was originally fixed only for Google Chrome](https://github.com/ianstormtaylor/slate/issues/3456), but the fix also needs to be applied in Safari. + +## 0.65.1 + +### Patch Changes + +- [#4324](https://github.com/ianstormtaylor/slate/pull/4324) [`61171a23`](https://github.com/ianstormtaylor/slate/commit/61171a23821b882116deabceec15f7e2649d271c) Thanks [@clauderic](https://github.com/clauderic)! - Fix backward typing bug in Safari by ensuring the selection is always removed on blur. + Safari doesn't always remove the selection, even if the contenteditable element no longer has focus. + In this scenario, we need to forcefully remove the selection on blur. + Refer to https://stackoverflow.com/questions/12353247/force-contenteditable-div-to-stop-accepting-input-after-it-loses-focus-under-web + +## 0.65.0 + +### Minor Changes + +- [#4299](https://github.com/ianstormtaylor/slate/pull/4299) [`2c17e2b7`](https://github.com/ianstormtaylor/slate/commit/2c17e2b7f9dbfa4a821b05668bd00f465da175ad) Thanks [@georgberecz](https://github.com/georgberecz)! - Allow custom event handlers on Editable component to return boolean flag to specify whether the event can be treated as being handled. + + By default, the `Editable` component comes with a set of event handlers that handle typical rich-text editing behaviors (for example, it implements its own `onCopy`, `onPaste`, `onDrop`, and `onKeyDown` handlers). + + In some cases you may want to extend or override Slate's default behavior, which can be done by passing your own event handler(s) to the `Editable` component. + + Your custom event handler can control whether or not Slate should execute its own event handling for a given event after your handler runs depending on the return value of your event handler as described below. + + ```jsx + import {Editable} from 'slate-react'; + + function MyEditor() { + const onClick = event => { + // Implement custom event logic... + + // When no value is returned, Slate will execute its own event handler when + // neither isDefaultPrevented nor isPropagationStopped was set on the event + }; + + const onDrop = event => { + // Implement custom event logic... + + // No matter the state of the event, treat it as being handled by returning + // true here, Slate will skip its own event handler + return true; + }; + + const onDragStart = event => { + // Implement custom event logic... + + // No matter the status of the event, treat event as *not* being handled by + // returning false, Slate will exectue its own event handler afterward + return false; + }; + + return ( + + ) + } + ``` + +### Patch Changes + +- [#4266](https://github.com/ianstormtaylor/slate/pull/4266) [`411e5a19`](https://github.com/ianstormtaylor/slate/commit/411e5a193bd639fb743c2253a5f5e43a5949b100) Thanks [@TheSpyder](https://github.com/TheSpyder)! - Removed accidental bundling of `slate-history` inside `slate-react` + +* [#4307](https://github.com/ianstormtaylor/slate/pull/4307) [`a7e3a181`](https://github.com/ianstormtaylor/slate/commit/a7e3a18187d1c29744d78875542abd035220ebdc) Thanks [@clauderic](https://github.com/clauderic)! - Fix deletion of selected inline void nodes in Chrome. Chrome does not fire a `beforeinput` event when deleting backwards within an inline void node, so we need to add special logic to handle this edge-case for Chrome only. + +- [#4272](https://github.com/ianstormtaylor/slate/pull/4272) [`294d5120`](https://github.com/ianstormtaylor/slate/commit/294d5120aed89f4e1c7a818e0d1339f4fa1cbaf5) Thanks [@clauderic](https://github.com/clauderic)! - Fix errors accessing `globalThis` in browsers that do not implement it + +* [#4295](https://github.com/ianstormtaylor/slate/pull/4295) [`dfc03960`](https://github.com/ianstormtaylor/slate/commit/dfc039601f7b4d74592dfe39c31b67c0f0619bca) Thanks [@dubzzz](https://github.com/dubzzz)! - Fix React warnings related to `autoCorrect` and `autoCapitalize` attributes being passed as a boolean instead of a string. + +- [#4271](https://github.com/ianstormtaylor/slate/pull/4271) [`ff267767`](https://github.com/ianstormtaylor/slate/commit/ff267767f61577fdbd68119a1c978e9856e3bb31) Thanks [@omerg](https://github.com/omerg)! - Fixed typo: Renamed `toSlatePoint` argument `extractMatch` to `exactMatch` + +## 0.64.0 + +### Minor Changes + +- [#4257](https://github.com/ianstormtaylor/slate/pull/4257) [`4f0d1120`](https://github.com/ianstormtaylor/slate/commit/4f0d1120d46d1024d94e3c2742026f6c54357e1f) Thanks [@clauderic](https://github.com/clauderic)! - Added support for Android devices using a `MutationObserver` based reconciliation layer. + + Bugs should be expected; translating mutations into a set of operations that need to be reconciled onto the Slate model is not an absolute science, and requires a lot of guesswork and handling of edge cases. There are still edge cases that aren't being handled. + + This reconciliation layer aims to support Android 10 and 11. Earlier versions of Android work to a certain extent, but have more bugs and edge cases that currently aren't well supported. + +## 0.63.0 + +### Patch Changes + +- [#4238](https://github.com/ianstormtaylor/slate/pull/4238) [`c14e1fbc`](https://github.com/ianstormtaylor/slate/commit/c14e1fbc77c51f7928ba8ab089c76f3e3438fb97) Thanks [@clauderic](https://github.com/clauderic)! - Fix duplicated content and other bugs related to drag and drop handling + +* [#4237](https://github.com/ianstormtaylor/slate/pull/4237) [`623960a7`](https://github.com/ianstormtaylor/slate/commit/623960a7d14103b8cebe667019b4de5f8ad1fd61) Thanks [@dylans](https://github.com/dylans)! - Fixed text insertion logic to prevent crashing in newer Firefox versions. + +## 0.62.1 + +### Patch Changes + +- [#4118](https://github.com/ianstormtaylor/slate/pull/4118) [`6a137633`](https://github.com/ianstormtaylor/slate/commit/6a1376332bbd2567336c444c57c1e64fdf706feb) Thanks [@kamilkazmierczak](https://github.com/kamilkazmierczak)! - Improved detection of legacy browsers that don't have proper `beforeinput` support. + +* [#4190](https://github.com/ianstormtaylor/slate/pull/4190) [`ea2eefef`](https://github.com/ianstormtaylor/slate/commit/ea2eefefb84365eb969e91151afc861e0dbefefd) Thanks [@juliankrispel](https://github.com/juliankrispel)! - Added a `renderPlaceholder` prop to the `` component for customizing how placeholders are rendered. + +- [#4157](https://github.com/ianstormtaylor/slate/pull/4157) [`de5cc7e5`](https://github.com/ianstormtaylor/slate/commit/de5cc7e5ed97fdca9e3766a8d947ab6391e6ccb2) Thanks [@githoniel](https://github.com/githoniel)! - Fixed a bug when syncing the selection for IME-based editing. + +* [#4158](https://github.com/ianstormtaylor/slate/pull/4158) [`ea6dc089`](https://github.com/ianstormtaylor/slate/commit/ea6dc08913d9dd671eeb05796dca522a4a35904e) Thanks [@githoniel](https://github.com/githoniel)! - Fixed a bug that resulted in doubly-input characters when using an IME. + +- [#4211](https://github.com/ianstormtaylor/slate/pull/4211) [`1c32b97d`](https://github.com/ianstormtaylor/slate/commit/1c32b97d23138d301e9ecb567263e3001cc4dbfa) Thanks [@clauderic](https://github.com/clauderic)! - Collapse expanded selection before handling `moveWordBackward` (`alt + left`) and `moveWordForward` (`alt + right`) hotkeys. + +* [#4219](https://github.com/ianstormtaylor/slate/pull/4219) [`737aaa9c`](https://github.com/ianstormtaylor/slate/commit/737aaa9cde2d4a2d6d64b83256aa5d9d1b5ce720) Thanks [@juliankrispel](https://github.com/juliankrispel)! - Fixes error that occurs when Editor is rendered inside iframe + +## 0.62.0 + +### Minor Changes + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - **Add directional awareness to `Editor.deleteFragment`.** This is an obscure change, but is a required distinction when implementing features that need to "fake delete" content (like Google Docs's suggestions). Previously deleting always collapsed to the end of a range, but now it can collapse forwards as well. + +* [#4154](https://github.com/ianstormtaylor/slate/pull/4154) [`7283c51f`](https://github.com/ianstormtaylor/slate/commit/7283c51feb83cb8522bc16efce09bb01c29400b9) Thanks [@ianstormtaylor](https://github.com/ianstormtaylor)! - **Start using [🦋 Changesets](https://github.com/atlassian/changesets) to manage releases.** Going forward, whenever a pull request is made that fixes or adds functionality to Slate, it will need to be accompanied by a changset Markdown file describing the change. These files will be automatically used in the release process when bump the versions of Slate and compiling the changelog. + +### Patch Changes + +- [#4150](https://github.com/ianstormtaylor/slate/pull/4150) [`bbd7d9c3`](https://github.com/ianstormtaylor/slate/commit/bbd7d9c33023add223ef9f1a33b657a468552caf) Thanks [@nivekithan](https://github.com/nivekithan)! - Added support for using the new `beforeInput` events in the latest Firefox. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed spellcheck disabling logic to always work in older versions of Firefox. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed browser-detection behavior to work with Deno. + +* [`d5589279`](https://github.com/ianstormtaylor/slate/commit/d5589279e8792185c1082af720a73f55b16797dd) - Updated placeholder styles to allow for wrapping long placeholder text. + +- [#3698](https://github.com/ianstormtaylor/slate/pull/3698) [`bf83f333`](https://github.com/ianstormtaylor/slate/commit/bf83f333e689bc17b96504b497bb7fcdf6dc7fc1) Thanks [@pubuzhixing8](https://github.com/pubuzhixing8)! - Fixed selection updating with IME inputs in browsers that support `beforeinput`. + +* [#3652](https://github.com/ianstormtaylor/slate/pull/3652) [`f3fb40cc`](https://github.com/ianstormtaylor/slate/commit/f3fb40cce044b73b6da13013f90bd7018f2f5d8a) Thanks [@Andarist](https://github.com/Andarist)! - Fixed selection logic when a controlled editor's nodes change out from under it. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed a bug where memoization logic would prevent placeholders from re-rendering properly. + +* [#3326](https://github.com/ianstormtaylor/slate/pull/3326) [`d5b2d7f5`](https://github.com/ianstormtaylor/slate/commit/d5b2d7f55e2982019b246fdea1e9eb845d0e2fc2) Thanks [@rockettomatooo](https://github.com/rockettomatooo)! - Added invariants when passing invalud `value` or `editor` props to ``. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed cursor movement in RTL text. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed a bug in the conversion of DOM points to Slate points. + +- [#3746](https://github.com/ianstormtaylor/slate/pull/3746) [`f8be509e`](https://github.com/ianstormtaylor/slate/commit/f8be509e4d0b5c13bb791e0fd5702242319d114f) Thanks [@gztomas](https://github.com/gztomas)! - Fixed auto-scrolling behavior when a block is bigger than the viewport. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed a bug that occurred when using Babel's `loose` mode. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed deleting void elements when using cut-and-paste. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed a bug that crashed the editor when using IME input. + +- [#3396](https://github.com/ianstormtaylor/slate/pull/3396) [`469e6b26`](https://github.com/ianstormtaylor/slate/commit/469e6b26f50857ef0d68cdf5a54793f8fe9033fd) Thanks [@cvlmtg](https://github.com/cvlmtg)! - Fixed allowing the `onPaste` handler to be overridden in all browsers. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed internal decoration logic to be faster and require fewer re-renders. + +- [#3894](https://github.com/ianstormtaylor/slate/pull/3894) [`7fe41f15`](https://github.com/ianstormtaylor/slate/commit/7fe41f156614453479cb9ea649fe5665b616d3a7) Thanks [@msc117](https://github.com/msc117)! - Fixed an error that happened when selecting void nodes in a read-only editor. + +* [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed `move_node` operations to not always require a full re-render. + +- [`d5589279`](https://github.com/ianstormtaylor/slate/commit/d5589279e8792185c1082af720a73f55b16797dd) - Fixed normalization of DOM points to be more accurate when triple-clicking. + +* [`d5589279`](https://github.com/ianstormtaylor/slate/commit/d5589279e8792185c1082af720a73f55b16797dd) - Fixed a bug that prevented `isFocused` from updating on certain focus changes. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed IME input to not insert repeated characters. + +* [#3749](https://github.com/ianstormtaylor/slate/pull/3749) [`0473d0bf`](https://github.com/ianstormtaylor/slate/commit/0473d0bf93808b0e4e98abe833b7f7f4f5aff3b1) Thanks [@davidruisinger](https://github.com/davidruisinger)! - Fixes Slate to work with the Shadow DOM. + +- [`c6002024`](https://github.com/ianstormtaylor/slate/commit/c60020244b9d25094edb0ffcca8b49dead9b31dc) - Fixed deleting by line to account for the line breaks in the browser. diff --git a/Readme.md b/Readme.md index fdc81fb..8117839 100644 --- a/Readme.md +++ b/Readme.md @@ -1,12 +1,8 @@ -To run locally: -1. Clone the version v0.57.1 of the slate repo: https://github.com/ianstormtaylor/slate/commit/22d9095c39a0e201878e1df04ef5e35d4d86a596 -2. cd slate/packages and remove slate-react -3. Pull this repo in slate/packages -4. cd slate && yarn start +This package contains the React-specific logic for Slate. It's separated further into a series of directories: -To deploy: -1. cd slate && yarn build -2. cd packages/slate-react -3. npm version [patch | minor ...] && git push -4. Update the commit hash in hs-editor/package.json -5. cd hs-monorepo && yarn +- [**Components**](./src/components) — containing the React components for rendering Slate editors. +- [**Hooks**](./src/hooks) — containing a few React hooks for Slate editors. +- [**Plugins**](./src/plugin) — containing the React-specific plugins for Slate editors. +- [**Utils**](./src/utils) — containing a few private convenience modules. + +Feel free to poke around in each of them to learn more! diff --git a/dist/components/children.d.ts b/dist/components/children.d.ts deleted file mode 100644 index 138e762..0000000 --- a/dist/components/children.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { Range, NodeEntry, Ancestor } from 'slate'; -import { RenderElementProps, RenderLeafProps } from './editable'; -/** - * Children. - */ -declare const Children: (props: { - decorate: (entry: NodeEntry) => Range[]; - decorations: Range[]; - node: Ancestor; - renderElement?: ((props: RenderElementProps) => JSX.Element) | undefined; - renderLeaf?: ((props: RenderLeafProps) => JSX.Element) | undefined; - selection: Range | null; - ReactHappyWindow: React.Component<{}, {}, any> | undefined; - reactHappyWindowProps: Object | undefined; -}) => JSX.Element; -export default Children; -//# sourceMappingURL=children.d.ts.map \ No newline at end of file diff --git a/dist/components/children.d.ts.map b/dist/components/children.d.ts.map deleted file mode 100644 index 74a23aa..0000000 --- a/dist/components/children.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"children.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/children.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAU,KAAK,EAAW,SAAS,EAAE,QAAQ,EAAc,MAAM,OAAO,CAAA;AAO/E,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEhE;;GAEG;AAEH,QAAA,MAAM,QAAQ;;;;;;;;;iBA2Fb,CAAA;AAED,eAAe,QAAQ,CAAA"} \ No newline at end of file diff --git a/dist/components/editable.d.ts b/dist/components/editable.d.ts deleted file mode 100644 index 75b00b2..0000000 --- a/dist/components/editable.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import { Element, NodeEntry, Range, Text } from 'slate'; -/** - * `RenderElementProps` are passed to the `renderElement` handler. - */ -export interface RenderElementProps { - children: any; - element: Element; - attributes: { - 'data-slate-node': 'element'; - 'data-slate-inline'?: true; - 'data-slate-void'?: true; - dir?: 'rtl'; - ref: any; - }; -} -/** - * `RenderLeafProps` are passed to the `renderLeaf` handler. - */ -export interface RenderLeafProps { - children: any; - leaf: Text; - text: Text; - attributes: { - 'data-slate-leaf': true; - }; -} -/** - * `EditableProps` are passed to the `` component. - */ -export declare type EditableProps = { - decorate?: (entry: NodeEntry) => Range[]; - onDOMBeforeInput?: (event: Event) => void; - placeholder?: string; - readOnly?: boolean; - role?: string; - style?: React.CSSProperties; - renderElement?: (props: RenderElementProps) => JSX.Element; - renderLeaf?: (props: RenderLeafProps) => JSX.Element; - as?: React.ElementType; - ReactHappyWindow?: React.Component; - reactHappyWindowProps?: object; -} & React.TextareaHTMLAttributes; -/** - * Editable. - */ -export declare const Editable: (props: EditableProps) => JSX.Element; -//# sourceMappingURL=editable.d.ts.map \ No newline at end of file diff --git a/dist/components/editable.d.ts.map b/dist/components/editable.d.ts.map deleted file mode 100644 index 6c6d319..0000000 --- a/dist/components/editable.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"editable.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/editable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAA;AACtE,OAAO,EAEL,OAAO,EACP,SAAS,EAET,KAAK,EACL,IAAI,EAEL,MAAM,OAAO,CAAA;AA8Bd;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,GAAG,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE;QACV,iBAAiB,EAAE,SAAS,CAAA;QAC5B,mBAAmB,CAAC,EAAE,IAAI,CAAA;QAC1B,iBAAiB,CAAC,EAAE,IAAI,CAAA;QACxB,GAAG,CAAC,EAAE,KAAK,CAAA;QACX,GAAG,EAAE,GAAG,CAAA;KACT,CAAA;CACF;AAED;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,GAAG,CAAA;IACb,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,IAAI,CAAA;IACV,UAAU,EAAE;QACV,iBAAiB,EAAE,IAAI,CAAA;KACxB,CAAA;CACF;AAED;;GAEG;AAEH,oBAAY,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,KAAK,EAAE,CAAA;IACxC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACzC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,GAAG,CAAC,OAAO,CAAA;IAC1D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,GAAG,CAAC,OAAO,CAAA;IACpD,EAAE,CAAC,EAAE,KAAK,CAAC,WAAW,CAAA;IACtB,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,GAAG,KAAK,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAA;AAEhD;;GAEG;AAEH,eAAO,MAAM,QAAQ,uCA+0BpB,CAAA"} \ No newline at end of file diff --git a/dist/components/element.d.ts b/dist/components/element.d.ts deleted file mode 100644 index a93c33f..0000000 --- a/dist/components/element.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { Node, Range, NodeEntry, Element as SlateElement } from 'slate'; -import { RenderElementProps, RenderLeafProps } from './editable'; -declare const MemoizedElement: React.MemoExoticComponent<(props: { - decorate: (entry: NodeEntry) => Range[]; - decorations: Range[]; - element: SlateElement; - renderElement?: ((props: RenderElementProps) => JSX.Element) | undefined; - renderLeaf?: ((props: RenderLeafProps) => JSX.Element) | undefined; - selection: Range | null; - elementIndex: Number; -}) => JSX.Element>; -/** - * The default element renderer. - */ -export declare const DefaultElement: (props: RenderElementProps) => JSX.Element; -export default MemoizedElement; -//# sourceMappingURL=element.d.ts.map \ No newline at end of file diff --git a/dist/components/element.d.ts.map b/dist/components/element.d.ts.map deleted file mode 100644 index c56bac1..0000000 --- a/dist/components/element.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/element.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiB,MAAM,OAAO,CAAA;AAErC,OAAO,EAAU,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,CAAA;AAc/E,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAwHhE,QAAA,MAAM,eAAe;;;;;;;;kBAYnB,CAAA;AAEF;;GAEG;AAEH,eAAO,MAAM,cAAc,4CAS1B,CAAA;AA2BD,eAAe,eAAe,CAAA"} \ No newline at end of file diff --git a/dist/components/leaf.d.ts b/dist/components/leaf.d.ts deleted file mode 100644 index 751e354..0000000 --- a/dist/components/leaf.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { Text, Element } from 'slate'; -import { RenderLeafProps } from './editable'; -declare const MemoizedLeaf: React.MemoExoticComponent<(props: { - isLast: boolean; - leaf: Text; - parent: Element; - renderLeaf?: ((props: RenderLeafProps) => JSX.Element) | undefined; - text: Text; -}) => JSX.Element>; -/** - * The default custom leaf renderer. - */ -export declare const DefaultLeaf: (props: RenderLeafProps) => JSX.Element; -export default MemoizedLeaf; -//# sourceMappingURL=leaf.d.ts.map \ No newline at end of file diff --git a/dist/components/leaf.d.ts.map b/dist/components/leaf.d.ts.map deleted file mode 100644 index e52bc2c..0000000 --- a/dist/components/leaf.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"leaf.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/leaf.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAIrC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA2D5C,QAAA,MAAM,YAAY;;;;;;kBAQhB,CAAA;AAEF;;GAEG;AAEH,eAAO,MAAM,WAAW,yCAGvB,CAAA;AAED,eAAe,YAAY,CAAA"} \ No newline at end of file diff --git a/dist/components/slate.d.ts b/dist/components/slate.d.ts deleted file mode 100644 index d55cee8..0000000 --- a/dist/components/slate.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { Node } from 'slate'; -import { ReactEditor } from '../plugin/react-editor'; -/** - * A wrapper around the provider to handle `onChange` events, because the editor - * is a mutable singleton so it won't ever register as "changed" otherwise. - */ -export declare const Slate: (props: { - [key: string]: any; - editor: ReactEditor; - value: Node[]; - children: React.ReactNode; - onChange: (value: Node[]) => void; -}) => JSX.Element; -//# sourceMappingURL=slate.d.ts.map \ No newline at end of file diff --git a/dist/components/slate.d.ts.map b/dist/components/slate.d.ts.map deleted file mode 100644 index 5264bc6..0000000 --- a/dist/components/slate.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"slate.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/slate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAE5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAMpD;;;GAGG;AAEH,eAAO,MAAM,KAAK;;;;;;iBA+BjB,CAAA"} \ No newline at end of file diff --git a/dist/components/string.d.ts b/dist/components/string.d.ts deleted file mode 100644 index 33d29ea..0000000 --- a/dist/components/string.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Text, Element } from 'slate'; -/** - * Leaf content strings. - */ -declare const String: (props: { - isLast: boolean; - leaf: Text; - parent: Element; - text: Text; -}) => JSX.Element; -export default String; -//# sourceMappingURL=string.d.ts.map \ No newline at end of file diff --git a/dist/components/string.d.ts.map b/dist/components/string.d.ts.map deleted file mode 100644 index 05092be..0000000 --- a/dist/components/string.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/string.tsx"],"names":[],"mappings":"AACA,OAAO,EAAU,IAAI,EAAQ,OAAO,EAAQ,MAAM,OAAO,CAAA;AAIzD;;GAEG;AAEH,QAAA,MAAM,MAAM;;;;;iBA2CX,CAAA;AAiCD,eAAe,MAAM,CAAA"} \ No newline at end of file diff --git a/dist/components/text.d.ts b/dist/components/text.d.ts deleted file mode 100644 index 90acace..0000000 --- a/dist/components/text.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { Range, Element, Text as SlateText } from 'slate'; -import { RenderLeafProps } from './editable'; -declare const MemoizedText: React.MemoExoticComponent<(props: { - decorations: Range[]; - isLast: boolean; - parent: Element; - renderLeaf?: ((props: RenderLeafProps) => JSX.Element) | undefined; - text: SlateText; -}) => JSX.Element>; -export default MemoizedText; -//# sourceMappingURL=text.d.ts.map \ No newline at end of file diff --git a/dist/components/text.d.ts.map b/dist/components/text.d.ts.map deleted file mode 100644 index 475884f..0000000 --- a/dist/components/text.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/components/text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiB,MAAM,OAAO,CAAA;AACrC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,OAAO,CAAA;AAIzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA4D5C,QAAA,MAAM,YAAY;;;;;;kBAOhB,CAAA;AAEF,eAAe,YAAY,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-editor.d.ts b/dist/hooks/use-editor.d.ts deleted file mode 100644 index d0a0c73..0000000 --- a/dist/hooks/use-editor.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// -import { ReactEditor } from '../plugin/react-editor'; -/** - * A React context for sharing the editor object. - */ -export declare const EditorContext: import("react").Context; -/** - * Get the current editor object from the React context. - */ -export declare const useEditor: () => ReactEditor; -//# sourceMappingURL=use-editor.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-editor.d.ts.map b/dist/hooks/use-editor.d.ts.map deleted file mode 100644 index 91f7978..0000000 --- a/dist/hooks/use-editor.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-editor.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-editor.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;GAEG;AAEH,eAAO,MAAM,aAAa,6CAA0C,CAAA;AAEpE;;GAEG;AAEH,eAAO,MAAM,SAAS,mBAUrB,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-focused.d.ts b/dist/hooks/use-focused.d.ts deleted file mode 100644 index 1972f76..0000000 --- a/dist/hooks/use-focused.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -/** - * A React context for sharing the `focused` state of the editor. - */ -export declare const FocusedContext: import("react").Context; -/** - * Get the current `focused` state of the editor. - */ -export declare const useFocused: () => boolean; -//# sourceMappingURL=use-focused.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-focused.d.ts.map b/dist/hooks/use-focused.d.ts.map deleted file mode 100644 index 15ae1f9..0000000 --- a/dist/hooks/use-focused.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-focused.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-focused.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,eAAO,MAAM,cAAc,kCAAuB,CAAA;AAElD;;GAEG;AAEH,eAAO,MAAM,UAAU,eAEtB,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-isomorphic-layout-effect.d.ts b/dist/hooks/use-isomorphic-layout-effect.d.ts deleted file mode 100644 index 0ec130b..0000000 --- a/dist/hooks/use-isomorphic-layout-effect.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useLayoutEffect } from 'react'; -/** - * Prevent warning on SSR by falling back to useEffect when window is not defined - */ -export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect; -//# sourceMappingURL=use-isomorphic-layout-effect.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-isomorphic-layout-effect.d.ts.map b/dist/hooks/use-isomorphic-layout-effect.d.ts.map deleted file mode 100644 index 15061dd..0000000 --- a/dist/hooks/use-isomorphic-layout-effect.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-isomorphic-layout-effect.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-isomorphic-layout-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAa,MAAM,OAAO,CAAA;AAElD;;GAEG;AACH,eAAO,MAAM,yBAAyB,wBACuB,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-read-only.d.ts b/dist/hooks/use-read-only.d.ts deleted file mode 100644 index 993116c..0000000 --- a/dist/hooks/use-read-only.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -/** - * A React context for sharing the `readOnly` state of the editor. - */ -export declare const ReadOnlyContext: import("react").Context; -/** - * Get the current `readOnly` state of the editor. - */ -export declare const useReadOnly: () => boolean; -//# sourceMappingURL=use-read-only.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-read-only.d.ts.map b/dist/hooks/use-read-only.d.ts.map deleted file mode 100644 index 82fadd4..0000000 --- a/dist/hooks/use-read-only.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-read-only.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-read-only.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,eAAO,MAAM,eAAe,kCAAuB,CAAA;AAEnD;;GAEG;AAEH,eAAO,MAAM,WAAW,eAEvB,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-selected.d.ts b/dist/hooks/use-selected.d.ts deleted file mode 100644 index ad1e941..0000000 --- a/dist/hooks/use-selected.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// -/** - * A React context for sharing the `selected` state of an element. - */ -export declare const SelectedContext: import("react").Context; -/** - * Get the current `selected` state of an element. - */ -export declare const useSelected: () => boolean; -//# sourceMappingURL=use-selected.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-selected.d.ts.map b/dist/hooks/use-selected.d.ts.map deleted file mode 100644 index 49e6aa4..0000000 --- a/dist/hooks/use-selected.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-selected.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-selected.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,eAAO,MAAM,eAAe,kCAAuB,CAAA;AAEnD;;GAEG;AAEH,eAAO,MAAM,WAAW,eAEvB,CAAA"} \ No newline at end of file diff --git a/dist/hooks/use-slate.d.ts b/dist/hooks/use-slate.d.ts deleted file mode 100644 index 5bd990f..0000000 --- a/dist/hooks/use-slate.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// -import { ReactEditor } from '../plugin/react-editor'; -/** - * A React context for sharing the editor object, in a way that re-renders the - * context whenever changes occur. - */ -export declare const SlateContext: import("react").Context<[ReactEditor] | null>; -/** - * Get the current editor object from the React context. - */ -export declare const useSlate: () => ReactEditor; -//# sourceMappingURL=use-slate.d.ts.map \ No newline at end of file diff --git a/dist/hooks/use-slate.d.ts.map b/dist/hooks/use-slate.d.ts.map deleted file mode 100644 index f0a0664..0000000 --- a/dist/hooks/use-slate.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"use-slate.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/hooks/use-slate.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;;GAGG;AAEH,eAAO,MAAM,YAAY,+CAA4C,CAAA;AAErE;;GAEG;AAEH,eAAO,MAAM,QAAQ,mBAWpB,CAAA"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index 171b544..0000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { RenderElementProps, RenderLeafProps, Editable, } from './components/editable'; -export { DefaultElement } from './components/element'; -export { DefaultLeaf } from './components/leaf'; -export { Slate } from './components/slate'; -export { useEditor } from './hooks/use-editor'; -export { useFocused } from './hooks/use-focused'; -export { useReadOnly } from './hooks/use-read-only'; -export { useSelected } from './hooks/use-selected'; -export { useSlate } from './hooks/use-slate'; -export { ReactEditor } from './plugin/react-editor'; -export { withReact } from './plugin/with-react'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map deleted file mode 100644 index dcaab91..0000000 --- a/dist/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["packages/slate-react/src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,QAAQ,GACT,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAG1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA"} \ No newline at end of file diff --git a/dist/index.es.js b/dist/index.es.js deleted file mode 100644 index 4aff277..0000000 --- a/dist/index.es.js +++ /dev/null @@ -1,1915 +0,0 @@ -import React, { useLayoutEffect, useEffect, useRef, createContext, useContext, useMemo, useCallback, useState } from 'react'; -import { Path, Node as Node$1, Editor, Text as Text$1, Range, Element as Element$1, Transforms } from 'slate'; -import getDirection from 'direction'; -import debounce from 'debounce'; -import scrollIntoView from 'scroll-into-view-if-needed'; -import { isKeyHotkey } from 'is-hotkey'; -import ReactDOM from 'react-dom'; - -/** - * Leaf content strings. - */ -const String = (props) => { - const { isLast, leaf, parent, text } = props; - const editor = useEditor(); - const path = ReactEditor.findPath(editor, text); - const parentPath = Path.parent(path); - // COMPAT: Render text inside void nodes with a zero-width space. - // So the node can contain selection but the text is not visible. - if (editor.isVoid(parent)) { - return React.createElement(ZeroWidthString, { length: Node$1.string(parent).length }); - } - // COMPAT: If this is the last text node in an empty block, render a zero- - // width space that will convert into a line break when copying and pasting - // to support expected plain text. - if (leaf.text === '' && - parent.children[parent.children.length - 1] === text && - !editor.isInline(parent) && - Editor.string(editor, parentPath) === '') { - return React.createElement(ZeroWidthString, { isLineBreak: true }); - } - // COMPAT: If the text is empty, it's because it's on the edge of an inline - // node, so we render a zero-width space so that the selection can be - // inserted next to it still. - if (leaf.text === '') { - return React.createElement(ZeroWidthString, null); - } - // COMPAT: Browsers will collapse trailing new lines at the end of blocks, - // so we need to add an extra trailing new lines to prevent that. - if (isLast && leaf.text.slice(-1) === '\n') { - return React.createElement(TextString, { isTrailing: true, text: leaf.text }); - } - return React.createElement(TextString, { text: leaf.text }); -}; -/** - * Leaf strings with text in them. - */ -const TextString = (props) => { - const { text, isTrailing = false } = props; - return (React.createElement("span", { "data-slate-string": true }, - text, - isTrailing ? '\n' : null)); -}; -/** - * Leaf strings without text, render as zero-width strings. - */ -const ZeroWidthString = (props) => { - const { length = 0, isLineBreak = false } = props; - return (React.createElement("span", { "data-slate-zero-width": isLineBreak ? 'n' : 'z', "data-slate-length": length }, - '\uFEFF', - isLineBreak ? React.createElement("br", null) : null)); -}; - -/** - * Two weak maps that allow us rebuild a path given a node. They are populated - * at render time such that after a render occurs we can always backtrack. - */ -var NODE_TO_INDEX = new WeakMap(); -var NODE_TO_PARENT = new WeakMap(); -/** - * Weak maps that allow us to go between Slate nodes and DOM nodes. These - * are used to resolve DOM event-related logic into Slate actions. - */ - -var EDITOR_TO_ELEMENT = new WeakMap(); -var ELEMENT_TO_NODE = new WeakMap(); -var KEY_TO_ELEMENT = new WeakMap(); -var NODE_TO_ELEMENT = new WeakMap(); -var NODE_TO_KEY = new WeakMap(); -/** - * Weak maps for storing editor-related state. - */ - -var IS_READ_ONLY = new WeakMap(); -var IS_FOCUSED = new WeakMap(); -/** - * Weak map for associating the context `onChange` context with the plugin. - */ - -var EDITOR_TO_ON_CHANGE = new WeakMap(); -/** - * Symbols. - */ - -var PLACEHOLDER_SYMBOL = Symbol('placeholder'); - -/** - * Individual leaves in a text node with unique formatting. - */ -const Leaf = (props) => { - const { leaf, isLast, text, parent, renderLeaf = (props) => React.createElement(DefaultLeaf, Object.assign({}, props)), } = props; - let children = (React.createElement(String, { isLast: isLast, leaf: leaf, parent: parent, text: text })); - if (leaf[PLACEHOLDER_SYMBOL]) { - children = (React.createElement(React.Fragment, null, - React.createElement("span", { contentEditable: false, style: { - pointerEvents: 'none', - display: 'inline-block', - verticalAlign: 'text-top', - width: '0', - maxWidth: '100%', - whiteSpace: 'nowrap', - opacity: '0.333', - } }, leaf.placeholder), - children)); - } - // COMPAT: Having the `data-` attributes on these leaf elements ensures that - // in certain misbehaving browsers they aren't weirdly cloned/destroyed by - // contenteditable behaviors. (2019/05/08) - const attributes = { - 'data-slate-leaf': true, - }; - return renderLeaf({ attributes, children, leaf, text }); -}; -const MemoizedLeaf = React.memo(Leaf, (prev, next) => { - return (next.parent === prev.parent && - next.isLast === prev.isLast && - next.renderLeaf === prev.renderLeaf && - next.text === prev.text && - Text$1.matches(next.leaf, prev.leaf)); -}); -/** - * The default custom leaf renderer. - */ -const DefaultLeaf = (props) => { - const { attributes, children } = props; - return React.createElement("span", Object.assign({}, attributes), children); -}; - -/** - * Prevent warning on SSR by falling back to useEffect when window is not defined - */ - -var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; - -/** - * Text. - */ -const Text = (props) => { - const { decorations, isLast, parent, renderLeaf, text } = props; - const editor = useEditor(); - const ref = useRef(null); - const leaves = Text$1.decorations(text, decorations); - const key = ReactEditor.findKey(editor, text); - const children = []; - for (let i = 0; i < leaves.length; i++) { - const leaf = leaves[i]; - children.push(React.createElement(MemoizedLeaf, { isLast: isLast && i === leaves.length - 1, key: `${key.id}-${i}`, leaf: leaf, text: text, parent: parent, renderLeaf: renderLeaf })); - } - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - KEY_TO_ELEMENT.set(key, ref.current); - NODE_TO_ELEMENT.set(text, ref.current); - ELEMENT_TO_NODE.set(ref.current, text); - } - else { - KEY_TO_ELEMENT.delete(key); - NODE_TO_ELEMENT.delete(text); - } - }); - return (React.createElement("span", { "data-slate-node": "text", ref: ref }, children)); -}; -const MemoizedText = React.memo(Text, (prev, next) => { - return (next.parent === prev.parent && - next.isLast === prev.isLast && - next.renderLeaf === prev.renderLeaf && - next.text === prev.text); -}); - -/** - * A React context for sharing the `selected` state of an element. - */ - -var SelectedContext = createContext(false); -/** - * Get the current `selected` state of an element. - */ - -var useSelected = () => { - return useContext(SelectedContext); -}; - -/** - * Element. - */ -const Element = (props) => { - const { decorate, decorations, element, renderElement = (p) => React.createElement(DefaultElement, Object.assign({}, p)), renderLeaf, selection, elementIndex, } = props; - const ref = useRef(null); - const editor = useEditor(); - const readOnly = useReadOnly(); - const isInline = editor.isInline(element); - const key = ReactEditor.findKey(editor, element); - let children = (React.createElement(Children, { decorate: decorate, decorations: decorations, node: element, renderElement: renderElement, renderLeaf: renderLeaf, selection: selection })); - // Attributes that the developer must mix into the element in their - // custom node renderer component. - const attributes = { - 'data-slate-node': 'element', - ref, - elementIndex, - }; - if (isInline) { - attributes['data-slate-inline'] = true; - } - // If it's a block node with inline children, add the proper `dir` attribute - // for text direction. - if (!isInline && Editor.hasInlines(editor, element)) { - const text = Node$1.string(element); - const dir = getDirection(text); - if (dir === 'rtl') { - attributes.dir = dir; - } - } - // If it's a void node, wrap the children in extra void-specific elements. - if (Editor.isVoid(editor, element)) { - attributes['data-slate-void'] = true; - if (!readOnly && isInline) { - attributes.contentEditable = false; - } - const Tag = isInline ? 'span' : 'div'; - const [[text]] = Node$1.texts(element); - children = readOnly ? null : (React.createElement(Tag, { "data-slate-spacer": true, style: { - height: '0', - color: 'transparent', - outline: 'none', - position: 'absolute', - } }, - React.createElement(MemoizedText, { decorations: [], isLast: false, parent: element, text: text }))); - NODE_TO_INDEX.set(text, 0); - NODE_TO_PARENT.set(text, element); - } - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - KEY_TO_ELEMENT.set(key, ref.current); - NODE_TO_ELEMENT.set(element, ref.current); - ELEMENT_TO_NODE.set(ref.current, element); - } - else { - KEY_TO_ELEMENT.delete(key); - NODE_TO_ELEMENT.delete(element); - } - }); - return (React.createElement(SelectedContext.Provider, { value: !!selection }, renderElement({ attributes, children, element }))); -}; -const MemoizedElement = React.memo(Element, (prev, next) => { - return (prev.decorate === next.decorate && - prev.element === next.element && - prev.renderElement === next.renderElement && - prev.renderLeaf === next.renderLeaf && - isRangeListEqual(prev.decorations, next.decorations) && - (prev.selection === next.selection || - (!!prev.selection && - !!next.selection && - Range.equals(prev.selection, next.selection)))); -}); -/** - * The default element renderer. - */ -const DefaultElement = (props) => { - const { attributes, children, element } = props; - const editor = useEditor(); - const Tag = editor.isInline(element) ? 'span' : 'div'; - return (React.createElement(Tag, Object.assign({}, attributes, { style: { position: 'relative' } }), children)); -}; -/** - * Check if a list of ranges is equal to another. - * - * PERF: this requires the two lists to also have the ranges inside them in the - * same order, but this is an okay constraint for us since decorations are - * kept in order, and the odd case where they aren't is okay to re-render for. - */ -const isRangeListEqual = (list, another) => { - if (list.length !== another.length) { - return false; - } - for (let i = 0; i < list.length; i++) { - const range = list[i]; - const other = another[i]; - if (!Range.equals(range, other)) { - return false; - } - } - return true; -}; - -/** - * A React context for sharing the editor object. - */ -const EditorContext = createContext(null); -/** - * Get the current editor object from the React context. - */ -const useEditor = () => { - const editor = useContext(EditorContext); - if (!editor) { - throw new Error(`The \`useEditor\` hook must be used inside the component's context.`); - } - return editor; -}; - -/** - * Children. - */ -const Children = (props) => { - const { decorate, decorations, node, renderElement, renderLeaf, selection, ReactHappyWindow, reactHappyWindowProps = {}, } = props; - const editor = useEditor(); - const path = ReactEditor.findPath(editor, node); - const children = []; - const isLeafBlock = Element$1.isElement(node) && - !editor.isInline(node) && - Editor.hasInlines(editor, node); - const renderChild = (i) => { - const p = path.concat(i); - const n = node.children[i]; - const key = ReactEditor.findKey(editor, n); - const range = Editor.range(editor, p); - const sel = selection && Range.intersection(range, selection); - // Commented out to improve performance. We don't use decorations - // const ds = decorate([n, p]) - const ds = []; - // for (const dec of decorations) { - // const d = Range.intersection(dec, range) - // if (d) { - // ds.push(d) - // } - // } - NODE_TO_INDEX.set(n, i); - NODE_TO_PARENT.set(n, node); - if (Element$1.isElement(n)) { - return (React.createElement(MemoizedElement, { decorate: decorate, decorations: ds, element: n, key: key.id, renderElement: renderElement, renderLeaf: renderLeaf, selection: sel, elementIndex: i })); - } - else { - return (React.createElement(MemoizedText, { decorations: ds, key: key.id, isLast: isLeafBlock && i === node.children.length - 1, parent: node, renderLeaf: renderLeaf, text: n })); - } - }; - if (ReactHappyWindow) { - return (React.createElement(ReactHappyWindow, Object.assign({ itemCount: node.children.length, renderItem: renderChild }, reactHappyWindowProps))); - } - for (let i = 0; i < node.children.length; i++) { - children.push(renderChild(i)); - } - return React.createElement(React.Fragment, null, children); -}; - -var IS_IOS = typeof navigator !== 'undefined' && typeof window !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; -var IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent); -var IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); -var IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent); - -/** - * Hotkey mappings for each platform. - */ - -var HOTKEYS = { - bold: 'mod+b', - compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'], - moveBackward: 'left', - moveForward: 'right', - moveWordBackward: 'ctrl+left', - moveWordForward: 'ctrl+right', - deleteBackward: 'shift?+backspace', - deleteForward: 'shift?+delete', - extendBackward: 'shift+left', - extendForward: 'shift+right', - italic: 'mod+i', - splitBlock: 'shift?+enter', - undo: 'mod+z' -}; -var APPLE_HOTKEYS = { - moveLineBackward: 'opt+up', - moveLineForward: 'opt+down', - moveWordBackward: 'opt+left', - moveWordForward: 'opt+right', - deleteBackward: ['ctrl+backspace', 'ctrl+h'], - deleteForward: ['ctrl+delete', 'ctrl+d'], - deleteLineBackward: 'cmd+shift?+backspace', - deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'], - deleteWordBackward: 'opt+shift?+backspace', - deleteWordForward: 'opt+shift?+delete', - extendLineBackward: 'opt+shift+up', - extendLineForward: 'opt+shift+down', - redo: 'cmd+shift+z', - transposeCharacter: 'ctrl+t' -}; -var WINDOWS_HOTKEYS = { - deleteWordBackward: 'ctrl+shift?+backspace', - deleteWordForward: 'ctrl+shift?+delete', - redo: ['ctrl+y', 'ctrl+shift+z'] -}; -/** - * Create a platform-aware hotkey checker. - */ - -var create = key => { - var generic = HOTKEYS[key]; - var apple = APPLE_HOTKEYS[key]; - var windows = WINDOWS_HOTKEYS[key]; - var isGeneric = generic && isKeyHotkey(generic); - var isApple = apple && isKeyHotkey(apple); - var isWindows = windows && isKeyHotkey(windows); - return event => { - if (isGeneric && isGeneric(event)) return true; - if (IS_APPLE && isApple && isApple(event)) return true; - if (!IS_APPLE && isWindows && isWindows(event)) return true; - return false; - }; -}; -/** - * Hotkeys. - */ - - -var Hotkeys = { - isBold: create('bold'), - isCompose: create('compose'), - isMoveBackward: create('moveBackward'), - isMoveForward: create('moveForward'), - isDeleteBackward: create('deleteBackward'), - isDeleteForward: create('deleteForward'), - isDeleteLineBackward: create('deleteLineBackward'), - isDeleteLineForward: create('deleteLineForward'), - isDeleteWordBackward: create('deleteWordBackward'), - isDeleteWordForward: create('deleteWordForward'), - isExtendBackward: create('extendBackward'), - isExtendForward: create('extendForward'), - isExtendLineBackward: create('extendLineBackward'), - isExtendLineForward: create('extendLineForward'), - isItalic: create('italic'), - isMoveLineBackward: create('moveLineBackward'), - isMoveLineForward: create('moveLineForward'), - isMoveWordBackward: create('moveWordBackward'), - isMoveWordForward: create('moveWordForward'), - isRedo: create('redo'), - isSplitBlock: create('splitBlock'), - isTransposeCharacter: create('transposeCharacter'), - isUndo: create('undo') -}; - -/** - * A React context for sharing the `readOnly` state of the editor. - */ - -var ReadOnlyContext = createContext(false); -/** - * Get the current `readOnly` state of the editor. - */ - -var useReadOnly = () => { - return useContext(ReadOnlyContext); -}; - -/** - * A React context for sharing the editor object, in a way that re-renders the - * context whenever changes occur. - */ -const SlateContext = createContext(null); -/** - * Get the current editor object from the React context. - */ -const useSlate = () => { - const context = useContext(SlateContext); - if (!context) { - throw new Error(`The \`useSlate\` hook must be used inside the component's context.`); - } - const [editor] = context; - return editor; -}; - -/** - * Types. - */ -/** - * Check if a DOM node is a comment node. - */ - -var isDOMComment = value => { - return isDOMNode(value) && value.nodeType === 8; -}; -/** - * Check if a DOM node is an element node. - */ - -var isDOMElement = value => { - return isDOMNode(value) && value.nodeType === 1; -}; -/** - * Check if a value is a DOM node. - */ - -var isDOMNode = value => { - return value instanceof Node; -}; -/** - * Check if a DOM node is an element node. - */ - -var isDOMText = value => { - return isDOMNode(value) && value.nodeType === 3; -}; -/** - * Normalize a DOM point so that it always refers to a text node. - */ - -var normalizeDOMPoint = domPoint => { - var [node, offset] = domPoint; // If it's an element node, its offset refers to the index of its children - // including comment nodes, so try to find the right text child node. - - if (isDOMElement(node) && node.childNodes.length) { - var isLast = offset === node.childNodes.length; - var direction = isLast ? 'backward' : 'forward'; - var index = isLast ? offset - 1 : offset; - node = getEditableChild(node, index, direction); // If the node has children, traverse until we have a leaf node. Leaf nodes - // can be either text nodes, or other void DOM nodes. - - while (isDOMElement(node) && node.childNodes.length) { - var i = isLast ? node.childNodes.length - 1 : 0; - node = getEditableChild(node, i, direction); - } // Determine the new offset inside the text node. - - - offset = isLast && node.textContent != null ? node.textContent.length : 0; - } // Return the node and offset. - - - return [node, offset]; -}; -/** - * Get the nearest editable child at `index` in a `parent`, preferring - * `direction`. - */ - -var getEditableChild = (parent, index, direction) => { - var { - childNodes - } = parent; - var child = childNodes[index]; - var i = index; - var triedForward = false; - var triedBackward = false; // While the child is a comment node, or an element node with no children, - // keep iterating to find a sibling non-void, non-comment node. - - while (isDOMComment(child) || isDOMElement(child) && child.childNodes.length === 0 || isDOMElement(child) && child.getAttribute('contenteditable') === 'false') { - if (triedForward && triedBackward) { - break; - } - - if (i >= childNodes.length) { - triedForward = true; - i = index - 1; - direction = 'backward'; - continue; - } - - if (i < 0) { - triedBackward = true; - i = index + 1; - direction = 'forward'; - continue; - } - - child = childNodes[i]; - i += direction === 'forward' ? 1 : -1; - } - - return child; -}; - -/** - * Editable. - */ -const Editable = (props) => { - const { autoFocus, decorate = defaultDecorate, onDOMBeforeInput: propsOnDOMBeforeInput, placeholder, readOnly = false, renderElement, renderLeaf, style = {}, as: Component = 'div', ReactHappyWindow, reactHappyWindowProps, happyWindowRef, ...attributes } = props; - const editor = useSlate(); - const ref = useRef(null); - // Update internal state on each render. - IS_READ_ONLY.set(editor, readOnly); - // Keep track of some state for the event handler logic. - const state = useMemo(() => ({ - isComposing: false, - isUpdatingSelection: false, - latestElement: null, - }), []); - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - EDITOR_TO_ELEMENT.set(editor, ref.current); - NODE_TO_ELEMENT.set(editor, ref.current); - ELEMENT_TO_NODE.set(ref.current, editor); - } - else { - NODE_TO_ELEMENT.delete(editor); - } - }); - // Attach a native DOM event handler for `selectionchange`, because React's - // built-in `onSelect` handler doesn't fire for all selection changes. It's a - // leaky polyfill that only fires on keypresses or clicks. Instead, we want to - // fire for any change to the selection inside the editor. (2019/11/04) - // https://github.com/facebook/react/issues/5785 - useIsomorphicLayoutEffect(() => { - window.document.addEventListener('selectionchange', onDOMSelectionChange); - return () => { - window.document.removeEventListener('selectionchange', onDOMSelectionChange); - }; - }, []); - // Attach a native DOM event handler for `beforeinput` events, because React's - // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose - // real `beforeinput` events sadly... (2019/11/04) - // https://github.com/facebook/react/issues/11211 - useIsomorphicLayoutEffect(() => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.addEventListener('beforeinput', onDOMBeforeInput); - } - return () => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.removeEventListener('beforeinput', onDOMBeforeInput); - } - }; - }, []); - // Whenever the editor updates, make sure the DOM selection state is in sync. - useIsomorphicLayoutEffect(() => { - const { selection } = editor; - const domSelection = window.getSelection(); - if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) { - return; - } - const hasDomSelection = domSelection.type !== 'None'; - // If the DOM selection is properly unset, we're done. - if (!selection && !hasDomSelection) { - return; - } - const newDomRange = selection && ReactEditor.toDOMRange(editor, selection); - // If the DOM selection is already correct, we're done. - if (hasDomSelection && - newDomRange && - isRangeEqual(domSelection.getRangeAt(0), newDomRange)) { - return; - } - // Otherwise the DOM selection is out of sync, so update it. - const el = ReactEditor.toDOMNode(editor, editor); - state.isUpdatingSelection = true; - domSelection.removeAllRanges(); - if (newDomRange) { - domSelection.addRange(newDomRange); - const leafEl = newDomRange.startContainer.parentElement; - scrollIntoView(leafEl, { scrollMode: 'if-needed' }); - } - setTimeout(() => { - // COMPAT: In Firefox, it's not enough to create a range, you also need - // to focus the contenteditable element too. (2016/11/16) - if (newDomRange && IS_FIREFOX) { - el.focus(); - } - state.isUpdatingSelection = false; - }); - }); - // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it - // needs to be manually focused. - useEffect(() => { - if (ref.current && autoFocus) { - ref.current.focus(); - } - }, [autoFocus]); - // Listen on the native `beforeinput` event to get real "Level 2" events. This - // is required because React's `beforeinput` is fake and never really attaches - // to the real event sadly. (2019/11/01) - // https://github.com/facebook/react/issues/11211 - const onDOMBeforeInput = useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isDOMEventHandled(event, propsOnDOMBeforeInput)) { - const { selection } = editor; - const { inputType: type } = event; - const data = event.dataTransfer || event.data || undefined; - // These two types occur while a user is composing text and can't be - // cancelled. Let them through and wait for the composition to end. - if (type === 'insertCompositionText' || - type === 'deleteCompositionText') { - return; - } - event.preventDefault(); - // COMPAT: For the deleting forward/backward input types we don't want - // to change the selection because it is the range that will be deleted, - // and those commands determine that for themselves. - if (!type.startsWith('delete') || type.startsWith('deleteBy')) { - const [targetRange] = event.getTargetRanges(); - if (targetRange) { - const range = ReactEditor.toSlateRange(editor, targetRange); - if (!range) { - return; - } - if (!selection || !Range.equals(selection, range)) { - Transforms.select(editor, range); - } - } - } - // COMPAT: If the selection is expanded, even if the command seems like - // a delete forward/backward command it should delete the selection. - if (selection && - Range.isExpanded(selection) && - type.startsWith('delete')) { - Editor.deleteFragment(editor); - return; - } - switch (type) { - case 'deleteByComposition': - case 'deleteByCut': - case 'deleteByDrag': { - Editor.deleteFragment(editor); - break; - } - case 'deleteContent': - case 'deleteContentForward': { - Editor.deleteForward(editor); - break; - } - case 'deleteContentBackward': { - Editor.deleteBackward(editor); - break; - } - case 'deleteEntireSoftLine': { - Editor.deleteBackward(editor, { unit: 'line' }); - Editor.deleteForward(editor, { unit: 'line' }); - break; - } - case 'deleteHardLineBackward': { - Editor.deleteBackward(editor, { unit: 'block' }); - break; - } - case 'deleteSoftLineBackward': { - Editor.deleteBackward(editor, { unit: 'line' }); - break; - } - case 'deleteHardLineForward': { - Editor.deleteForward(editor, { unit: 'block' }); - break; - } - case 'deleteSoftLineForward': { - Editor.deleteForward(editor, { unit: 'line' }); - break; - } - case 'deleteWordBackward': { - Editor.deleteBackward(editor, { unit: 'word' }); - break; - } - case 'deleteWordForward': { - Editor.deleteForward(editor, { unit: 'word' }); - break; - } - case 'insertLineBreak': - case 'insertParagraph': { - Editor.insertBreak(editor); - break; - } - case 'insertFromComposition': - case 'insertFromDrop': - case 'insertFromPaste': - case 'insertFromYank': - case 'insertReplacementText': - case 'insertText': { - if (data instanceof DataTransfer) { - ReactEditor.insertData(editor, data); - } - else if (typeof data === 'string') { - Editor.insertText(editor, data); - } - break; - } - } - } - }, []); - // Listen on the native `selectionchange` event to be able to update any time - // the selection changes. This is required because React's `onSelect` is leaky - // and non-standard so it doesn't fire until after a selection has been - // released. This causes issues in situations where another change happens - // while a selection is being dragged. - const onDOMSelectionChange = useCallback(debounce(() => { - if (!readOnly && !state.isComposing && !state.isUpdatingSelection) { - const { activeElement } = window.document; - const el = ReactEditor.toDOMNode(editor, editor); - const domSelection = window.getSelection(); - const domRange = domSelection && - domSelection.rangeCount > 0 && - domSelection.getRangeAt(0); - if (activeElement === el) { - state.latestElement = activeElement; - IS_FOCUSED.set(editor, true); - } - else { - IS_FOCUSED.delete(editor); - } - if (domRange && - hasEditableTarget(editor, domRange.startContainer) && - hasEditableTarget(editor, domRange.endContainer)) { - const range = ReactEditor.toSlateRange(editor, domRange); - Transforms.select(editor, range); - } - else { - Transforms.deselect(editor); - } - } - }, 100), []); - const decorations = decorate([editor, []]); - if (placeholder && - editor.children.length === 1 && - Array.from(Node$1.texts(editor)).length === 1 && - Node$1.string(editor) === '') { - const start = Editor.start(editor, []); - decorations.push({ - [PLACEHOLDER_SYMBOL]: true, - placeholder, - anchor: start, - focus: start, - }); - } - return (React.createElement(ReadOnlyContext.Provider, { value: readOnly }, - React.createElement(Component - // COMPAT: The Grammarly Chrome extension works by changing the DOM - // out from under `contenteditable` elements, which leads to weird - // behaviors so we have to disable it like editor. (2017/04/24) - , Object.assign({ "data-gramm": false, role: readOnly ? undefined : 'textbox' }, attributes, { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we'd - // have to use hacks to make these replacement-based features work. - spellCheck: IS_FIREFOX ? undefined : attributes.spellCheck, autoCorrect: IS_FIREFOX ? undefined : attributes.autoCorrect, autoCapitalize: IS_FIREFOX ? undefined : attributes.autoCapitalize, "data-slate-editor": true, "data-slate-node": "value", contentEditable: readOnly ? undefined : true, suppressContentEditableWarning: true, ref: ref, style: { - // Prevent the default outline styles. - outline: 'none', - // Preserve adjacent whitespace and new lines. - whiteSpace: 'pre-wrap', - // Allow words to break if they are too long. - wordWrap: 'break-word', - // Allow for passed-in styles to override anything. - ...style, - }, onBeforeInput: useCallback((event) => { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to React's leaky polyfill instead just for it. It - // only works for the `insertText` input type. - if (IS_FIREFOX && !readOnly && ReactEditor.isFocused(editor)) { - event.preventDefault(); - const text = event.data; - Editor.insertText(editor, text); - } - }, [readOnly]), onBlur: useCallback((event) => { - if (readOnly || - state.isUpdatingSelection || - !hasEditableTarget(editor, event.target) || - isEventHandled(event, attributes.onBlur)) { - return; - } - // COMPAT: If the current `activeElement` is still the previous - // one, this is due to the window being blurred when the tab - // itself becomes unfocused, so we want to abort early to allow to - // editor to stay focused when the tab becomes focused again. - if (state.latestElement === window.document.activeElement) { - return; - } - const { relatedTarget } = event; - const el = ReactEditor.toDOMNode(editor, editor); - // COMPAT: The event should be ignored if the focus is returning - // to the editor from an embedded editable element (eg. an - // element inside a void node). - if (relatedTarget === el) { - return; - } - // COMPAT: The event should be ignored if the focus is moving from - // the editor to inside a void node's spacer element. - if (isDOMElement(relatedTarget) && - relatedTarget.hasAttribute('data-slate-spacer')) { - return; - } - // COMPAT: The event should be ignored if the focus is moving to a - // non- editable section of an element that isn't a void node (eg. - // a list item of the check list example). - if (relatedTarget != null && - isDOMNode(relatedTarget) && - ReactEditor.hasDOMNode(editor, relatedTarget)) { - const node = ReactEditor.toSlateNode(editor, relatedTarget); - if (Element$1.isElement(node) && !editor.isVoid(node)) { - return; - } - } - IS_FOCUSED.delete(editor); - }, [readOnly, attributes.onBlur]), onClick: useCallback((event) => { - if (!readOnly && - hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onClick) && - isDOMNode(event.target)) { - const node = ReactEditor.toSlateNode(editor, event.target); - const path = ReactEditor.findPath(editor, node); - const start = Editor.start(editor, path); - if (Editor.void(editor, { at: start })) { - const range = Editor.range(editor, start); - Transforms.select(editor, range); - } - } - }, [readOnly, attributes.onClick]), onCompositionEnd: useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionEnd)) { - state.isComposing = false; - // COMPAT: In Chrome, `beforeinput` events for compositions - // aren't correct and never fire the "insertFromComposition" - // type that we need. So instead, insert whenever a composition - // ends since it will already have been committed to the DOM. - if (!IS_SAFARI && !IS_FIREFOX && event.data) { - Editor.insertText(editor, event.data); - } - } - }, [attributes.onCompositionEnd]), onCompositionStart: useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionStart)) { - state.isComposing = true; - } - }, [attributes.onCompositionStart]), onCopy: useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCopy)) { - event.preventDefault(); - setFragmentData(event.clipboardData, editor); - } - }, [attributes.onCopy]), onCut: useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCut)) { - event.preventDefault(); - setFragmentData(event.clipboardData, editor); - const { selection } = editor; - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - } - }, [readOnly, attributes.onCut]), onDragOver: useCallback((event) => { - if (hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragOver)) { - // Only when the target is void, call `preventDefault` to signal - // that drops are allowed. Editable content is droppable by - // default, and calling `preventDefault` hides the cursor. - const node = ReactEditor.toSlateNode(editor, event.target); - if (Editor.isVoid(editor, node)) { - event.preventDefault(); - } - } - }, [attributes.onDragOver]), onDragStart: useCallback((event) => { - if (hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragStart)) { - const node = ReactEditor.toSlateNode(editor, event.target); - const path = ReactEditor.findPath(editor, node); - const voidMatch = Editor.void(editor, { at: path }); - // If starting a drag on a void node, make sure it is selected - // so that it shows up in the selection's fragment. - if (voidMatch) { - const range = Editor.range(editor, path); - Transforms.select(editor, range); - } - setFragmentData(event.dataTransfer, editor); - } - }, [attributes.onDragStart]), onDrop: useCallback((event) => { - if (hasTarget(editor, event.target) && - !readOnly && - !isEventHandled(event, attributes.onDrop)) { - // COMPAT: Firefox doesn't fire `beforeinput` events at all, and - // Chromium browsers don't properly fire them for files being - // dropped into a `contenteditable`. (2019/11/26) - // https://bugs.chromium.org/p/chromium/issues/detail?id=1028668 - if (IS_FIREFOX || - (!IS_SAFARI && event.dataTransfer.files.length > 0)) { - event.preventDefault(); - const range = ReactEditor.findEventRange(editor, event); - const data = event.dataTransfer; - Transforms.select(editor, range); - ReactEditor.insertData(editor, data); - } - } - }, [readOnly, attributes.onDrop]), onFocus: useCallback((event) => { - if (!readOnly && - !state.isUpdatingSelection && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onFocus)) { - const el = ReactEditor.toDOMNode(editor, editor); - state.latestElement = window.document.activeElement; - // COMPAT: If the editor has nested editable elements, the focus - // can go to them. In Firefox, this must be prevented because it - // results in issues with keyboard navigation. (2017/03/30) - if (IS_FIREFOX && event.target !== el) { - el.focus(); - return; - } - IS_FOCUSED.set(editor, true); - } - }, [readOnly, attributes.onFocus]), onKeyDown: useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onKeyDown)) { - const { nativeEvent } = event; - const { selection } = editor; - const element = editor.children[selection !== null ? selection.focus.path[0] : 0]; - const isRTL = getDirection(Node$1.string(element)) === 'rtl'; - // COMPAT: Since we prevent the default behavior on - // `beforeinput` events, the browser doesn't think there's ever - // any history stack to undo or redo, so we have to manage these - // hotkeys ourselves. (2019/11/06) - if (Hotkeys.isRedo(nativeEvent)) { - event.preventDefault(); - if (editor.redo) { - editor.redo(); - } - return; - } - if (Hotkeys.isUndo(nativeEvent)) { - event.preventDefault(); - if (editor.undo) { - editor.undo(); - } - return; - } - // COMPAT: Certain browsers don't handle the selection updates - // properly. In Chrome, the selection isn't properly extended. - // And in Firefox, the selection isn't properly collapsed. - // (2017/10/17) - if (Hotkeys.isMoveLineBackward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { unit: 'line', reverse: true }); - return; - } - if (Hotkeys.isMoveLineForward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { unit: 'line' }); - return; - } - if (Hotkeys.isExtendLineBackward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { - unit: 'line', - edge: 'focus', - reverse: true, - }); - return; - } - if (Hotkeys.isExtendLineForward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { unit: 'line', edge: 'focus' }); - return; - } - // COMPAT: If a void node is selected, or a zero-width text node - // adjacent to an inline is selected, we need to handle these - // hotkeys manually because browsers won't be able to skip over - // the void node with the zero-width space not being an empty - // string. - if (Hotkeys.isMoveBackward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isCollapsed(selection)) { - const { anchor } = selection; - if (anchor.offset === 1 && anchor.path[1] > 0) { - // Hack to position the cursor at the end of the previous text node - Transforms.move(editor, { reverse: !isRTL, distance: 2 }); - Transforms.move(editor, { reverse: isRTL }); - } - else { - Transforms.move(editor, { reverse: !isRTL }); - } - } - else { - Transforms.collapse(editor, { edge: 'start' }); - } - return; - } - if (Hotkeys.isMoveForward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isCollapsed(selection)) { - Transforms.move(editor, { reverse: isRTL }); - } - else { - Transforms.collapse(editor, { edge: 'end' }); - } - return; - } - if (Hotkeys.isMoveWordBackward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { unit: 'word', reverse: !isRTL }); - return; - } - if (Hotkeys.isMoveWordForward(nativeEvent)) { - event.preventDefault(); - Transforms.move(editor, { unit: 'word', reverse: isRTL }); - return; - } - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to guessing at the input intention for hotkeys. - // COMPAT: In iOS, some of these hotkeys are handled in the - if (IS_FIREFOX) { - // We don't have a core behavior for these, but they change the - // DOM if we don't prevent them, so we have to. - if (Hotkeys.isBold(nativeEvent) || - Hotkeys.isItalic(nativeEvent) || - Hotkeys.isTransposeCharacter(nativeEvent)) { - event.preventDefault(); - return; - } - if (Hotkeys.isSplitBlock(nativeEvent)) { - event.preventDefault(); - Editor.insertBreak(editor); - return; - } - if (Hotkeys.isDeleteBackward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteBackward(editor); - } - return; - } - if (Hotkeys.isDeleteForward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteForward(editor); - } - return; - } - if (Hotkeys.isDeleteLineBackward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteBackward(editor, { unit: 'line' }); - } - return; - } - if (Hotkeys.isDeleteLineForward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteForward(editor, { unit: 'line' }); - } - return; - } - if (Hotkeys.isDeleteWordBackward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteBackward(editor, { unit: 'word' }); - } - return; - } - if (Hotkeys.isDeleteWordForward(nativeEvent)) { - event.preventDefault(); - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor); - } - else { - Editor.deleteForward(editor, { unit: 'word' }); - } - return; - } - } - } - }, [readOnly, attributes.onKeyDown]), onPaste: useCallback((event) => { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to React's `onPaste` here instead. - if (IS_FIREFOX && - !readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onPaste)) { - event.preventDefault(); - ReactEditor.insertData(editor, event.clipboardData); - } - }, [readOnly, attributes.onPaste]) }), - React.createElement(Children, { decorate: decorate, decorations: decorations, node: editor, renderElement: renderElement, renderLeaf: renderLeaf, selection: editor.selection, ReactHappyWindow: ReactHappyWindow, reactHappyWindowProps: reactHappyWindowProps })))); -}; -/** - * A default memoized decorate function. - */ -const defaultDecorate = () => []; -/** - * Check if two DOM range objects are equal. - */ -const isRangeEqual = (a, b) => { - return ((a.startContainer === b.startContainer && - a.startOffset === b.startOffset && - a.endContainer === b.endContainer && - a.endOffset === b.endOffset) || - (a.startContainer === b.endContainer && - a.startOffset === b.endOffset && - a.endContainer === b.startContainer && - a.endOffset === b.startOffset)); -}; -/** - * Check if the target is in the editor. - */ -const hasTarget = (editor, target) => { - return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target); -}; -/** - * Check if the target is editable and in the editor. - */ -const hasEditableTarget = (editor, target) => { - return (isDOMNode(target) && - ReactEditor.hasDOMNode(editor, target, { editable: true })); -}; -/** - * Check if an event is overrided by a handler. - */ -const isEventHandled = (event, handler) => { - if (!handler) { - return false; - } - handler(event); - return event.isDefaultPrevented() || event.isPropagationStopped(); -}; -/** - * Check if a DOM event is overrided by a handler. - */ -const isDOMEventHandled = (event, handler) => { - if (!handler) { - return false; - } - handler(event); - return event.defaultPrevented; -}; -/** - * Set the currently selected fragment to the clipboard. - */ -const setFragmentData = (dataTransfer, editor) => { - const { selection } = editor; - if (!selection) { - return; - } - const [start, end] = Range.edges(selection); - const startVoid = Editor.void(editor, { at: start.path }); - const endVoid = Editor.void(editor, { at: end.path }); - if (Range.isCollapsed(selection) && !startVoid) { - return; - } - // Create a fake selection so that we can add a Base64-encoded copy of the - // fragment to the HTML, to decode on future pastes. - const domRange = ReactEditor.toDOMRange(editor, selection); - let contents = domRange.cloneContents(); - let attach = contents.childNodes[0]; - // Make sure attach is non-empty, since empty nodes will not get copied. - contents.childNodes.forEach(node => { - if (node.textContent && node.textContent.trim() !== '') { - attach = node; - } - }); - // COMPAT: If the end node is a void node, we need to move the end of the - // range from the void node's spacer span, to the end of the void node's - // content, since the spacer is before void's content in the DOM. - if (endVoid) { - const [voidNode] = endVoid; - const r = domRange.cloneRange(); - const domNode = ReactEditor.toDOMNode(editor, voidNode); - r.setEndAfter(domNode); - contents = r.cloneContents(); - } - // COMPAT: If the start node is a void node, we need to attach the encoded - // fragment to the void node's content node instead of the spacer, because - // attaching it to empty `
/` nodes will end up having it erased by - // most browsers. (2018/04/27) - if (startVoid) { - attach = contents.querySelector('[data-slate-spacer]'); - } - // Remove any zero-width space spans from the cloned DOM so that they don't - // show up elsewhere when pasted. - Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(zw => { - const isNewline = zw.getAttribute('data-slate-zero-width') === 'n'; - zw.textContent = isNewline ? '\n' : ''; - }); - // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up - // in the HTML, and can be used for intra-Slate pasting. If it's a text - // node, wrap it in a `` so we have something to set an attribute on. - if (isDOMText(attach)) { - const span = document.createElement('span'); - // COMPAT: In Chrome and Safari, if we don't add the `white-space` style - // then leading and trailing spaces will be ignored. (2017/09/21) - span.style.whiteSpace = 'pre'; - span.appendChild(attach); - contents.appendChild(span); - attach = span; - } - const fragment = Node$1.fragment(editor, selection); - const string = JSON.stringify(fragment); - const encoded = window.btoa(encodeURIComponent(string)); - attach.setAttribute('data-slate-fragment', encoded); - // Overwriting the default functionality - const { getFormattedSelection, getHTMLFormattedSelection } = editor; - if (typeof getFormattedSelection === 'function' && - typeof getHTMLFormattedSelection === 'function') { - try { - const plainText = getFormattedSelection(); - const htmlText = getHTMLFormattedSelection(); - dataTransfer.setData('text/plain', plainText); - dataTransfer.setData('text/html', htmlText); - return; - } - catch (e) { - // eslint-disable-next-line no-console - console.log('Error in slate-react/src/components/editable.tsx: ', e); - // Only setData application/x-slate-fragment as a fallback because - // we don't want to copy the timestamps of words - dataTransfer.setData('application/x-slate-fragment', encoded); - } - } - // Add the content to a
so that we can get its inner HTML. - const div = document.createElement('div'); - div.appendChild(contents); - dataTransfer.setData('text/html', div.innerHTML); - dataTransfer.setData('text/plain', getPlainText(div)); -}; -/** - * Get a plaintext representation of the content of a node, accounting for block - * elements which get a newline appended. - */ -const getPlainText = (domNode) => { - let text = ''; - if (isDOMText(domNode) && domNode.nodeValue) { - return domNode.nodeValue; - } - if (isDOMElement(domNode)) { - for (const childNode of Array.from(domNode.childNodes)) { - text += getPlainText(childNode); - } - const display = getComputedStyle(domNode).getPropertyValue('display'); - if (display === 'block' || display === 'list' || domNode.tagName === 'BR') { - text += '\n'; - } - } - return text; -}; - -/** - * An auto-incrementing identifier for keys. - */ -var n = 0; -/** - * A class that keeps track of a key string. We use a full class here because we - * want to be able to use them as keys in `WeakMap` objects. - */ - -class Key { - constructor() { - this.id = "".concat(n++); - } - -} - -var ReactEditor = { - /** - * Find a key for a Slate node. - */ - findKey(editor, node) { - var key = NODE_TO_KEY.get(node); - - if (!key) { - key = new Key(); - NODE_TO_KEY.set(node, key); - } - - return key; - }, - - /** - * Find the path of Slate node. - */ - findPath(editor, node) { - var path = []; - var child = node; - - while (true) { - var parent = NODE_TO_PARENT.get(child); - - if (parent == null) { - if (Editor.isEditor(child)) { - return path; - } else { - break; - } - } - - var i = NODE_TO_INDEX.get(child); - - if (i == null) { - break; - } - - path.unshift(i); - child = parent; - } - - throw new Error("Unable to find the path for Slate node: ".concat(JSON.stringify(node))); - }, - - /** - * Check if the editor is focused. - */ - isFocused(editor) { - return !!IS_FOCUSED.get(editor); - }, - - /** - * Check if the editor is in read-only mode. - */ - isReadOnly(editor) { - return !!IS_READ_ONLY.get(editor); - }, - - /** - * Blur the editor. - */ - blur(editor) { - var el = ReactEditor.toDOMNode(editor, editor); - IS_FOCUSED.set(editor, false); - - if (window.document.activeElement === el) { - el.blur(); - } - }, - - /** - * Focus the editor. - */ - focus(editor) { - var el = ReactEditor.toDOMNode(editor, editor); - IS_FOCUSED.set(editor, true); - - if (window.document.activeElement !== el) { - el.focus({ - preventScroll: true - }); - } - }, - - /** - * Deselect the editor. - */ - deselect(editor) { - var { - selection - } = editor; - var domSelection = window.getSelection(); - - if (domSelection && domSelection.rangeCount > 0) { - domSelection.removeAllRanges(); - } - - if (selection) { - Transforms.deselect(editor); - } - }, - - /** - * Check if a DOM node is within the editor. - */ - hasDOMNode(editor, target) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var { - editable = false - } = options; - var el = ReactEditor.toDOMNode(editor, editor); - var element; // COMPAT: In Firefox, reading `target.nodeType` will throw an error if - // target is originating from an internal "restricted" element (e.g. a - // stepper arrow on a number input). (2018/05/04) - // https://github.com/ianstormtaylor/slate/issues/1819 - - try { - element = isDOMElement(target) ? target : target.parentElement; - } catch (err) { - if (!err.message.includes('Permission denied to access property "nodeType"')) { - throw err; - } - } - - if (!element) { - return false; - } - - return element.closest("[data-slate-editor]") === el && (!editable || el.isContentEditable); - }, - - /** - * Insert data from a `DataTransfer` into the editor. - */ - insertData(editor, data) { - editor.insertData(data); - }, - - /** - * Find the native DOM element from a Slate node. - */ - toDOMNode(editor, node) { - var domNode = Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node)); - - if (!domNode) { - throw new Error("Cannot resolve a DOM node from Slate node: ".concat(JSON.stringify(node))); - } - - return domNode; - }, - - /** - * Find a native DOM selection point from a Slate point. - */ - toDOMPoint(editor, point) { - var [node] = Editor.node(editor, point.path); - var el = ReactEditor.toDOMNode(editor, node); - var domPoint; // If we're inside a void node, force the offset to 0, otherwise the zero - // width spacing character will result in an incorrect offset of 1 - - if (Editor.void(editor, { - at: point - })) { - point = { - path: point.path, - offset: 0 - }; - } // For each leaf, we need to isolate its content, which means filtering - // to its direct text and zero-width spans. (We have to filter out any - // other siblings that may have been rendered alongside them.) - - - var selector = "[data-slate-string], [data-slate-zero-width]"; - var texts = Array.from(el.querySelectorAll(selector)); - var start = 0; - - for (var text of texts) { - var domNode = text.childNodes[0]; - - if (domNode == null || domNode.textContent == null) { - continue; - } - - var { - length - } = domNode.textContent; - var attr = text.getAttribute('data-slate-length'); - var trueLength = attr == null ? length : parseInt(attr, 10); - var end = start + trueLength; - - if (point.offset <= end) { - var offset = Math.min(length, Math.max(0, point.offset - start)); - domPoint = [domNode, offset]; - break; - } - - start = end; - } - - if (!domPoint) { - throw new Error("Cannot resolve a DOM point from Slate point: ".concat(JSON.stringify(point))); - } - - return domPoint; - }, - - /** - * Find a native DOM range from a Slate `range`. - */ - toDOMRange(editor, range) { - var { - anchor, - focus - } = range; - var domAnchor = ReactEditor.toDOMPoint(editor, anchor); - var domFocus = Range.isCollapsed(range) ? domAnchor : ReactEditor.toDOMPoint(editor, focus); - var domRange = window.document.createRange(); - var start = Range.isBackward(range) ? domFocus : domAnchor; - var end = Range.isBackward(range) ? domAnchor : domFocus; - domRange.setStart(start[0], start[1]); - domRange.setEnd(end[0], end[1]); - return domRange; - }, - - /** - * Find a Slate node from a native DOM `element`. - */ - toSlateNode(editor, domNode) { - var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement; - - if (domEl && !domEl.hasAttribute('data-slate-node')) { - domEl = domEl.closest("[data-slate-node]"); - } - - var node = domEl ? ELEMENT_TO_NODE.get(domEl) : null; - - if (!node) { - throw new Error("Cannot resolve a Slate node from DOM node: ".concat(domEl)); - } - - return node; - }, - - /** - * Get the target range from a DOM `event`. - */ - findEventRange(editor, event) { - if ('nativeEvent' in event) { - event = event.nativeEvent; - } - - var { - clientX: x, - clientY: y, - target - } = event; - - if (x == null || y == null) { - throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event)); - } - - var node = ReactEditor.toSlateNode(editor, event.target); - var path = ReactEditor.findPath(editor, node); // If the drop target is inside a void node, move it into either the - // next or previous node, depending on which side the `x` and `y` - // coordinates are closest to. - - if (Editor.isVoid(editor, node)) { - var rect = target.getBoundingClientRect(); - var isPrev = editor.isInline(node) ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y; - var edge = Editor.point(editor, path, { - edge: isPrev ? 'start' : 'end' - }); - var point = isPrev ? Editor.before(editor, edge) : Editor.after(editor, edge); - - if (point) { - var _range = Editor.range(editor, point); - - return _range; - } - } // Else resolve a range from the caret position where the drop occured. - - - var domRange; - var { - document - } = window; // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25) - - if (document.caretRangeFromPoint) { - domRange = document.caretRangeFromPoint(x, y); - } else { - var position = document.caretPositionFromPoint(x, y); - - if (position) { - domRange = document.createRange(); - domRange.setStart(position.offsetNode, position.offset); - domRange.setEnd(position.offsetNode, position.offset); - } - } - - if (!domRange) { - throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event)); - } // Resolve a Slate range from the DOM range. - - - var range = ReactEditor.toSlateRange(editor, domRange); - return range; - }, - - /** - * Find a Slate point from a DOM selection's `domNode` and `domOffset`. - */ - toSlatePoint(editor, domPoint) { - var [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint); - var parentNode = nearestNode.parentNode; - var textNode = null; - var offset = 0; - - if (parentNode) { - var voidNode = parentNode.closest('[data-slate-void="true"]'); - var leafNode = parentNode.closest('[data-slate-leaf]'); - var domNode = null; // Calculate how far into the text node the `nearestNode` is, so that we - // can determine what the offset relative to the text node is. - - if (leafNode) { - textNode = leafNode.closest('[data-slate-node="text"]'); - var range = window.document.createRange(); - range.setStart(textNode, 0); - range.setEnd(nearestNode, nearestOffset); - var contents = range.cloneContents(); - var removals = [...contents.querySelectorAll('[data-slate-zero-width]'), ...contents.querySelectorAll('[contenteditable=false]')]; - removals.forEach(el => { - el.parentNode.removeChild(el); - }); // COMPAT: Edge has a bug where Range.prototype.toString() will - // convert \n into \r\n. The bug causes a loop when slate-react - // attempts to reposition its cursor to match the native position. Use - // textContent.length instead. - // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/ - - offset = contents.textContent.length; - domNode = textNode; - } else if (voidNode) { - // For void nodes, the element with the offset key will be a cousin, not an - // ancestor, so find it by going down from the nearest void parent. - leafNode = voidNode.querySelector('[data-slate-leaf]'); - textNode = leafNode.closest('[data-slate-node="text"]'); - domNode = leafNode; - offset = domNode.textContent.length; - } // COMPAT: If the parent node is a Slate zero-width space, editor is - // because the text node should have no characters. However, during IME - // composition the ASCII characters will be prepended to the zero-width - // space, so subtract 1 from the offset to account for the zero-width - // space character. - - - if (domNode && offset === domNode.textContent.length && parentNode.hasAttribute('data-slate-zero-width')) { - offset--; - } - } - - if (!textNode) { - throw new Error("Cannot resolve a Slate point from DOM point: ".concat(domPoint)); - } // COMPAT: If someone is clicking from one Slate editor into another, - // the select event fires twice, once for the old editor's `element` - // first, and then afterwards for the correct `element`. (2017/03/03) - - - var slateNode = ReactEditor.toSlateNode(editor, textNode); - var path = ReactEditor.findPath(editor, slateNode); - return { - path, - offset - }; - }, - - /** - * Find a Slate range from a DOM range or selection. - */ - toSlateRange(editor, domRange) { - var el = domRange instanceof Selection ? domRange.anchorNode : domRange.startContainer; - var anchorNode; - var anchorOffset; - var focusNode; - var focusOffset; - var isCollapsed; - - if (el) { - if (domRange instanceof Selection) { - anchorNode = domRange.anchorNode; - anchorOffset = domRange.anchorOffset; - focusNode = domRange.focusNode; - focusOffset = domRange.focusOffset; - isCollapsed = domRange.isCollapsed; - } else { - anchorNode = domRange.startContainer; - anchorOffset = domRange.startOffset; - focusNode = domRange.endContainer; - focusOffset = domRange.endOffset; - isCollapsed = domRange.collapsed; - } - } - - if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) { - throw new Error("Cannot resolve a Slate range from DOM range: ".concat(domRange)); - } - - var anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset]); - var focus = isCollapsed ? anchor : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset]); - return { - anchor, - focus - }; - } - -}; - -/** - * A React context for sharing the `focused` state of the editor. - */ - -var FocusedContext = createContext(false); -/** - * Get the current `focused` state of the editor. - */ - -var useFocused = () => { - return useContext(FocusedContext); -}; - -/** - * A wrapper around the provider to handle `onChange` events, because the editor - * is a mutable singleton so it won't ever register as "changed" otherwise. - */ -const Slate = (props) => { - const { editor, children, onChange, value, ...rest } = props; - const [key, setKey] = useState(0); - const context = useMemo(() => { - editor.children = value; - Object.assign(editor, rest); - return [editor]; - }, [key, value, ...Object.values(rest)]); - const onContextChange = useCallback(() => { - onChange(editor.children); - setKey(key + 1); - }, [key, onChange]); - EDITOR_TO_ON_CHANGE.set(editor, onContextChange); - return (React.createElement(SlateContext.Provider, { value: context }, - React.createElement(EditorContext.Provider, { value: editor }, - React.createElement(FocusedContext.Provider, { value: ReactEditor.isFocused(editor) }, children)))); -}; - -/** - * `withReact` adds React and DOM specific behaviors to the editor. - */ - -var withReact = editor => { - var e = editor; - var { - apply, - onChange - } = e; - - e.apply = op => { - var matches = []; - - switch (op.type) { - case 'insert_text': - case 'remove_text': - case 'set_node': - { - for (var [node, path] of Editor.levels(e, { - at: op.path - })) { - var key = ReactEditor.findKey(e, node); - matches.push([path, key]); - } - - break; - } - - case 'insert_node': - case 'remove_node': - case 'merge_node': - case 'split_node': - { - for (var [_node, _path] of Editor.levels(e, { - at: Path.parent(op.path) - })) { - var _key = ReactEditor.findKey(e, _node); - - matches.push([_path, _key]); - } - - break; - } - } - - apply(op); - - for (var [_path2, _key2] of matches) { - var [_node2] = Editor.node(e, _path2); - NODE_TO_KEY.set(_node2, _key2); - } - }; - - e.insertData = data => { - var fragment = data.getData('application/x-slate-fragment'); - - if (fragment) { - var decoded = decodeURIComponent(window.atob(fragment)); - var parsed = JSON.parse(decoded); - Transforms.insertFragment(e, parsed); - return; - } - - var text = data.getData('text/plain'); - - if (text) { - var lines = text.split('\n'); - var split = false; - - for (var line of lines) { - if (split) { - Transforms.splitNodes(e); - } - - Transforms.insertText(e, line); - split = true; - } - } - }; - - e.onChange = () => { - // COMPAT: React doesn't batch `setState` hook calls, which means that the - // children and selection can get out of sync for one render pass. So we - // have to use this unstable API to ensure it batches them. (2019/12/03) - // https://github.com/facebook/react/issues/14259#issuecomment-439702367 - ReactDOM.unstable_batchedUpdates(() => { - var onContextChange = EDITOR_TO_ON_CHANGE.get(e); - - if (onContextChange) { - onContextChange(); - } - - onChange(); - }); - }; - - return e; -}; - -export { DefaultElement, DefaultLeaf, Editable, ReactEditor, Slate, useEditor, useFocused, useReadOnly, useSelected, useSlate, withReact }; -//# sourceMappingURL=index.es.js.map diff --git a/dist/index.es.js.map b/dist/index.es.js.map deleted file mode 100644 index ce5d572..0000000 --- a/dist/index.es.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.es.js","sources":["../src/components/string.tsx","../src/utils/weak-maps.ts","../src/components/leaf.tsx","../src/hooks/use-isomorphic-layout-effect.ts","../src/components/text.tsx","../src/hooks/use-selected.ts","../src/components/element.tsx","../src/hooks/use-editor.tsx","../src/components/children.tsx","../src/utils/environment.ts","../src/utils/hotkeys.ts","../src/hooks/use-read-only.ts","../src/hooks/use-slate.tsx","../src/utils/dom.ts","../src/components/editable.tsx","../src/utils/key.ts","../src/plugin/react-editor.ts","../src/hooks/use-focused.ts","../src/components/slate.tsx","../src/plugin/with-react.ts"],"sourcesContent":["import React from 'react'\nimport { Editor, Text, Path, Element, Node } from 'slate'\n\nimport { ReactEditor, useEditor } from '..'\n\n/**\n * Leaf content strings.\n */\n\nconst String = (props: {\n isLast: boolean\n leaf: Text\n parent: Element\n text: Text\n}) => {\n const { isLast, leaf, parent, text } = props\n const editor = useEditor()\n const path = ReactEditor.findPath(editor, text)\n const parentPath = Path.parent(path)\n\n // COMPAT: Render text inside void nodes with a zero-width space.\n // So the node can contain selection but the text is not visible.\n if (editor.isVoid(parent)) {\n return \n }\n\n // COMPAT: If this is the last text node in an empty block, render a zero-\n // width space that will convert into a line break when copying and pasting\n // to support expected plain text.\n if (\n leaf.text === '' &&\n parent.children[parent.children.length - 1] === text &&\n !editor.isInline(parent) &&\n Editor.string(editor, parentPath) === ''\n ) {\n return \n }\n\n // COMPAT: If the text is empty, it's because it's on the edge of an inline\n // node, so we render a zero-width space so that the selection can be\n // inserted next to it still.\n if (leaf.text === '') {\n return \n }\n\n // COMPAT: Browsers will collapse trailing new lines at the end of blocks,\n // so we need to add an extra trailing new lines to prevent that.\n if (isLast && leaf.text.slice(-1) === '\\n') {\n return \n }\n\n return \n}\n\n/**\n * Leaf strings with text in them.\n */\n\nconst TextString = (props: { text: string; isTrailing?: boolean }) => {\n const { text, isTrailing = false } = props\n return (\n \n {text}\n {isTrailing ? '\\n' : null}\n \n )\n}\n\n/**\n * Leaf strings without text, render as zero-width strings.\n */\n\nconst ZeroWidthString = (props: { length?: number; isLineBreak?: boolean }) => {\n const { length = 0, isLineBreak = false } = props\n return (\n \n {'\\uFEFF'}\n {isLineBreak ?
: null}\n \n )\n}\n\nexport default String\n","import { Node, Ancestor, Editor, Range } from 'slate'\n\nimport { Key } from './key'\n\n/**\n * Two weak maps that allow us rebuild a path given a node. They are populated\n * at render time such that after a render occurs we can always backtrack.\n */\n\nexport const NODE_TO_INDEX: WeakMap = new WeakMap()\nexport const NODE_TO_PARENT: WeakMap = new WeakMap()\n\n/**\n * Weak maps that allow us to go between Slate nodes and DOM nodes. These\n * are used to resolve DOM event-related logic into Slate actions.\n */\n\nexport const EDITOR_TO_ELEMENT: WeakMap = new WeakMap()\nexport const EDITOR_TO_PLACEHOLDER: WeakMap = new WeakMap()\nexport const ELEMENT_TO_NODE: WeakMap = new WeakMap()\nexport const KEY_TO_ELEMENT: WeakMap = new WeakMap()\nexport const NODE_TO_ELEMENT: WeakMap = new WeakMap()\nexport const NODE_TO_KEY: WeakMap = new WeakMap()\n\n/**\n * Weak maps for storing editor-related state.\n */\n\nexport const IS_READ_ONLY: WeakMap = new WeakMap()\nexport const IS_FOCUSED: WeakMap = new WeakMap()\nexport const IS_DRAGGING: WeakMap = new WeakMap()\nexport const IS_CLICKING: WeakMap = new WeakMap()\n\n/**\n * Weak map for associating the context `onChange` context with the plugin.\n */\n\nexport const EDITOR_TO_ON_CHANGE = new WeakMap void>()\n\n/**\n * Symbols.\n */\n\nexport const PLACEHOLDER_SYMBOL = (Symbol('placeholder') as unknown) as string\n","import React from 'react'\nimport { Text, Element } from 'slate'\n\nimport String from './string'\nimport { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'\nimport { RenderLeafProps } from './editable'\n\n/**\n * Individual leaves in a text node with unique formatting.\n */\n\nconst Leaf = (props: {\n isLast: boolean\n leaf: Text\n parent: Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n text: Text\n}) => {\n const {\n leaf,\n isLast,\n text,\n parent,\n renderLeaf = (props: RenderLeafProps) => ,\n } = props\n\n let children = (\n \n )\n\n if (leaf[PLACEHOLDER_SYMBOL]) {\n children = (\n \n \n {leaf.placeholder}\n \n {children}\n \n )\n }\n\n // COMPAT: Having the `data-` attributes on these leaf elements ensures that\n // in certain misbehaving browsers they aren't weirdly cloned/destroyed by\n // contenteditable behaviors. (2019/05/08)\n const attributes: {\n 'data-slate-leaf': true\n } = {\n 'data-slate-leaf': true,\n }\n\n return renderLeaf({ attributes, children, leaf, text })\n}\n\nconst MemoizedLeaf = React.memo(Leaf, (prev, next) => {\n return (\n next.parent === prev.parent &&\n next.isLast === prev.isLast &&\n next.renderLeaf === prev.renderLeaf &&\n next.text === prev.text &&\n Text.matches(next.leaf, prev.leaf)\n )\n})\n\n/**\n * The default custom leaf renderer.\n */\n\nexport const DefaultLeaf = (props: RenderLeafProps) => {\n const { attributes, children } = props\n return {children}\n}\n\nexport default MemoizedLeaf\n","import { useLayoutEffect, useEffect } from 'react'\n\n/**\n * Prevent warning on SSR by falling back to useEffect when window is not defined\n */\nexport const useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect\n","import React, { useRef } from 'react'\nimport { Range, Element, Text as SlateText } from 'slate'\n\nimport Leaf from './leaf'\nimport { ReactEditor, useEditor } from '..'\nimport { RenderLeafProps } from './editable'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n KEY_TO_ELEMENT,\n NODE_TO_ELEMENT,\n ELEMENT_TO_NODE,\n} from '../utils/weak-maps'\n\n/**\n * Text.\n */\n\nconst Text = (props: {\n decorations: Range[]\n isLast: boolean\n parent: Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n text: SlateText\n}) => {\n const { decorations, isLast, parent, renderLeaf, text } = props\n const editor = useEditor()\n const ref = useRef(null)\n const leaves = SlateText.decorations(text, decorations)\n const key = ReactEditor.findKey(editor, text)\n const children = []\n\n for (let i = 0; i < leaves.length; i++) {\n const leaf = leaves[i]\n\n children.push(\n \n )\n }\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n KEY_TO_ELEMENT.set(key, ref.current)\n NODE_TO_ELEMENT.set(text, ref.current)\n ELEMENT_TO_NODE.set(ref.current, text)\n } else {\n KEY_TO_ELEMENT.delete(key)\n NODE_TO_ELEMENT.delete(text)\n }\n })\n\n return (\n \n {children}\n \n )\n}\n\nconst MemoizedText = React.memo(Text, (prev, next) => {\n return (\n next.parent === prev.parent &&\n next.isLast === prev.isLast &&\n next.renderLeaf === prev.renderLeaf &&\n next.text === prev.text\n )\n})\n\nexport default MemoizedText\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `selected` state of an element.\n */\n\nexport const SelectedContext = createContext(false)\n\n/**\n * Get the current `selected` state of an element.\n */\n\nexport const useSelected = (): boolean => {\n return useContext(SelectedContext)\n}\n","import React, { useRef } from 'react'\nimport getDirection from 'direction'\nimport { Editor, Node, Range, NodeEntry, Element as SlateElement } from 'slate'\n\nimport Text from './text'\nimport Children from './children'\nimport { ReactEditor, useEditor, useReadOnly } from '..'\nimport { SelectedContext } from '../hooks/use-selected'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n NODE_TO_ELEMENT,\n ELEMENT_TO_NODE,\n NODE_TO_PARENT,\n NODE_TO_INDEX,\n KEY_TO_ELEMENT,\n} from '../utils/weak-maps'\nimport { RenderElementProps, RenderLeafProps } from './editable'\n\n/**\n * Element.\n */\n\nconst Element = (props: {\n decorate: (entry: NodeEntry) => Range[]\n decorations: Range[]\n element: SlateElement\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n selection: Range | null\n elementIndex: Number\n}) => {\n const {\n decorate,\n decorations,\n element,\n renderElement = (p: RenderElementProps) => ,\n renderLeaf,\n selection,\n elementIndex,\n } = props\n const ref = useRef(null)\n const editor = useEditor()\n const readOnly = useReadOnly()\n const isInline = editor.isInline(element)\n const key = ReactEditor.findKey(editor, element)\n\n let children: JSX.Element | null = (\n \n )\n\n // Attributes that the developer must mix into the element in their\n // custom node renderer component.\n const attributes: {\n 'data-slate-node': 'element'\n 'data-slate-void'?: true\n 'data-slate-inline'?: true\n contentEditable?: false\n dir?: 'rtl'\n ref: any\n elementIndex: Number\n } = {\n 'data-slate-node': 'element',\n ref,\n elementIndex,\n }\n\n if (isInline) {\n attributes['data-slate-inline'] = true\n }\n\n // If it's a block node with inline children, add the proper `dir` attribute\n // for text direction.\n if (!isInline && Editor.hasInlines(editor, element)) {\n const text = Node.string(element)\n const dir = getDirection(text)\n\n if (dir === 'rtl') {\n attributes.dir = dir\n }\n }\n\n // If it's a void node, wrap the children in extra void-specific elements.\n if (Editor.isVoid(editor, element)) {\n attributes['data-slate-void'] = true\n\n if (!readOnly && isInline) {\n attributes.contentEditable = false\n }\n\n const Tag = isInline ? 'span' : 'div'\n const [[text]] = Node.texts(element)\n\n children = readOnly ? null : (\n \n \n \n )\n\n NODE_TO_INDEX.set(text, 0)\n NODE_TO_PARENT.set(text, element)\n }\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n KEY_TO_ELEMENT.set(key, ref.current)\n NODE_TO_ELEMENT.set(element, ref.current)\n ELEMENT_TO_NODE.set(ref.current, element)\n } else {\n KEY_TO_ELEMENT.delete(key)\n NODE_TO_ELEMENT.delete(element)\n }\n })\n\n return (\n \n {renderElement({ attributes, children, element })}\n \n )\n}\n\nconst MemoizedElement = React.memo(Element, (prev, next) => {\n return (\n prev.decorate === next.decorate &&\n prev.element === next.element &&\n prev.renderElement === next.renderElement &&\n prev.renderLeaf === next.renderLeaf &&\n isRangeListEqual(prev.decorations, next.decorations) &&\n (prev.selection === next.selection ||\n (!!prev.selection &&\n !!next.selection &&\n Range.equals(prev.selection, next.selection)))\n )\n})\n\n/**\n * The default element renderer.\n */\n\nexport const DefaultElement = (props: RenderElementProps) => {\n const { attributes, children, element } = props\n const editor = useEditor()\n const Tag = editor.isInline(element) ? 'span' : 'div'\n return (\n \n {children}\n \n )\n}\n\n/**\n * Check if a list of ranges is equal to another.\n *\n * PERF: this requires the two lists to also have the ranges inside them in the\n * same order, but this is an okay constraint for us since decorations are\n * kept in order, and the odd case where they aren't is okay to re-render for.\n */\n\nconst isRangeListEqual = (list: Range[], another: Range[]): boolean => {\n if (list.length !== another.length) {\n return false\n }\n\n for (let i = 0; i < list.length; i++) {\n const range = list[i]\n const other = another[i]\n\n if (!Range.equals(range, other)) {\n return false\n }\n }\n\n return true\n}\n\nexport default MemoizedElement\n","import { createContext, useContext } from 'react'\n\nimport { ReactEditor } from '../plugin/react-editor'\n\n/**\n * A React context for sharing the editor object.\n */\n\nexport const EditorContext = createContext(null)\n\n/**\n * Get the current editor object from the React context.\n */\n\nexport const useEditor = () => {\n const editor = useContext(EditorContext)\n\n if (!editor) {\n throw new Error(\n `The \\`useEditor\\` hook must be used inside the component's context.`\n )\n }\n\n return editor\n}\n","import React from 'react'\nimport { Editor, Range, Element, NodeEntry, Ancestor, Descendant } from 'slate'\n\nimport ElementComponent from './element'\nimport TextComponent from './text'\nimport { ReactEditor } from '..'\nimport { useEditor } from '../hooks/use-editor'\nimport { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps'\nimport { RenderElementProps, RenderLeafProps } from './editable'\n\n/**\n * Children.\n */\n\nconst Children = (props: {\n decorate: (entry: NodeEntry) => Range[]\n decorations: Range[]\n node: Ancestor\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n selection: Range | null\n ReactHappyWindow: React.Component | undefined\n reactHappyWindowProps: Object | undefined\n}) => {\n const {\n decorate,\n decorations,\n node,\n renderElement,\n renderLeaf,\n selection,\n ReactHappyWindow,\n reactHappyWindowProps = {},\n } = props\n const editor = useEditor()\n const path = ReactEditor.findPath(editor, node)\n const children = []\n const isLeafBlock =\n Element.isElement(node) &&\n !editor.isInline(node) &&\n Editor.hasInlines(editor, node)\n\n const renderChild = (i: number) => {\n const p = path.concat(i)\n const n = node.children[i] as Descendant\n const key = ReactEditor.findKey(editor, n)\n const range = Editor.range(editor, p)\n const sel = selection && Range.intersection(range, selection)\n\n // Commented out to improve performance. We don't use decorations\n // const ds = decorate([n, p])\n const ds = [] as Range[]\n // for (const dec of decorations) {\n // const d = Range.intersection(dec, range)\n\n // if (d) {\n // ds.push(d)\n // }\n // }\n\n NODE_TO_INDEX.set(n, i)\n NODE_TO_PARENT.set(n, node)\n\n if (Element.isElement(n)) {\n return (\n \n )\n } else {\n return (\n \n )\n }\n }\n\n if (ReactHappyWindow) {\n return (\n \n )\n }\n\n for (let i = 0; i < node.children.length; i++) {\n children.push(renderChild(i))\n }\n\n return {children}\n}\n\nexport default Children\n","export const IS_IOS =\n typeof navigator !== 'undefined' &&\n typeof window !== 'undefined' &&\n /iPad|iPhone|iPod/.test(navigator.userAgent) &&\n !window.MSStream\n\nexport const IS_APPLE =\n typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent)\n\nexport const IS_FIREFOX =\n typeof navigator !== 'undefined' &&\n /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent)\n\nexport const IS_SAFARI =\n typeof navigator !== 'undefined' &&\n /Version\\/[\\d\\.]+.*Safari/.test(navigator.userAgent)\n","import { isKeyHotkey } from 'is-hotkey'\nimport { IS_APPLE } from './environment'\n\n/**\n * Hotkey mappings for each platform.\n */\n\nconst HOTKEYS = {\n bold: 'mod+b',\n compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],\n moveBackward: 'left',\n moveForward: 'right',\n moveWordBackward: 'ctrl+left',\n moveWordForward: 'ctrl+right',\n deleteBackward: 'shift?+backspace',\n deleteForward: 'shift?+delete',\n extendBackward: 'shift+left',\n extendForward: 'shift+right',\n italic: 'mod+i',\n splitBlock: 'shift?+enter',\n undo: 'mod+z',\n}\n\nconst APPLE_HOTKEYS = {\n moveLineBackward: 'opt+up',\n moveLineForward: 'opt+down',\n moveWordBackward: 'opt+left',\n moveWordForward: 'opt+right',\n deleteBackward: ['ctrl+backspace', 'ctrl+h'],\n deleteForward: ['ctrl+delete', 'ctrl+d'],\n deleteLineBackward: 'cmd+shift?+backspace',\n deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],\n deleteWordBackward: 'opt+shift?+backspace',\n deleteWordForward: 'opt+shift?+delete',\n extendLineBackward: 'opt+shift+up',\n extendLineForward: 'opt+shift+down',\n redo: 'cmd+shift+z',\n transposeCharacter: 'ctrl+t',\n}\n\nconst WINDOWS_HOTKEYS = {\n deleteWordBackward: 'ctrl+shift?+backspace',\n deleteWordForward: 'ctrl+shift?+delete',\n redo: ['ctrl+y', 'ctrl+shift+z'],\n}\n\n/**\n * Create a platform-aware hotkey checker.\n */\n\nconst create = (key: string) => {\n const generic = HOTKEYS[key]\n const apple = APPLE_HOTKEYS[key]\n const windows = WINDOWS_HOTKEYS[key]\n const isGeneric = generic && isKeyHotkey(generic)\n const isApple = apple && isKeyHotkey(apple)\n const isWindows = windows && isKeyHotkey(windows)\n\n return (event: KeyboardEvent) => {\n if (isGeneric && isGeneric(event)) return true\n if (IS_APPLE && isApple && isApple(event)) return true\n if (!IS_APPLE && isWindows && isWindows(event)) return true\n return false\n }\n}\n\n/**\n * Hotkeys.\n */\n\nexport default {\n isBold: create('bold'),\n isCompose: create('compose'),\n isMoveBackward: create('moveBackward'),\n isMoveForward: create('moveForward'),\n isDeleteBackward: create('deleteBackward'),\n isDeleteForward: create('deleteForward'),\n isDeleteLineBackward: create('deleteLineBackward'),\n isDeleteLineForward: create('deleteLineForward'),\n isDeleteWordBackward: create('deleteWordBackward'),\n isDeleteWordForward: create('deleteWordForward'),\n isExtendBackward: create('extendBackward'),\n isExtendForward: create('extendForward'),\n isExtendLineBackward: create('extendLineBackward'),\n isExtendLineForward: create('extendLineForward'),\n isItalic: create('italic'),\n isMoveLineBackward: create('moveLineBackward'),\n isMoveLineForward: create('moveLineForward'),\n isMoveWordBackward: create('moveWordBackward'),\n isMoveWordForward: create('moveWordForward'),\n isRedo: create('redo'),\n isSplitBlock: create('splitBlock'),\n isTransposeCharacter: create('transposeCharacter'),\n isUndo: create('undo'),\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `readOnly` state of the editor.\n */\n\nexport const ReadOnlyContext = createContext(false)\n\n/**\n * Get the current `readOnly` state of the editor.\n */\n\nexport const useReadOnly = (): boolean => {\n return useContext(ReadOnlyContext)\n}\n","import { createContext, useContext } from 'react'\n\nimport { ReactEditor } from '../plugin/react-editor'\n\n/**\n * A React context for sharing the editor object, in a way that re-renders the\n * context whenever changes occur.\n */\n\nexport const SlateContext = createContext<[ReactEditor] | null>(null)\n\n/**\n * Get the current editor object from the React context.\n */\n\nexport const useSlate = () => {\n const context = useContext(SlateContext)\n\n if (!context) {\n throw new Error(\n `The \\`useSlate\\` hook must be used inside the component's context.`\n )\n }\n\n const [editor] = context\n return editor\n}\n","/**\n * Types.\n */\n\n// COMPAT: This is required to prevent TypeScript aliases from doing some very\n// weird things for Slate's types with the same name as globals. (2019/11/27)\n// https://github.com/microsoft/TypeScript/issues/35002\nimport DOMNode = globalThis.Node\nimport DOMComment = globalThis.Comment\nimport DOMElement = globalThis.Element\nimport DOMText = globalThis.Text\nimport DOMRange = globalThis.Range\nimport DOMSelection = globalThis.Selection\nimport DOMStaticRange = globalThis.StaticRange\nexport {\n DOMNode,\n DOMComment,\n DOMElement,\n DOMText,\n DOMRange,\n DOMSelection,\n DOMStaticRange,\n}\n\nexport type DOMPoint = [Node, number]\n\n/**\n * Check if a DOM node is a comment node.\n */\n\nexport const isDOMComment = (value: any): value is DOMComment => {\n return isDOMNode(value) && value.nodeType === 8\n}\n\n/**\n * Check if a DOM node is an element node.\n */\n\nexport const isDOMElement = (value: any): value is DOMElement => {\n return isDOMNode(value) && value.nodeType === 1\n}\n\n/**\n * Check if a value is a DOM node.\n */\n\nexport const isDOMNode = (value: any): value is DOMNode => {\n return value instanceof Node\n}\n\n/**\n * Check if a DOM node is an element node.\n */\n\nexport const isDOMText = (value: any): value is DOMText => {\n return isDOMNode(value) && value.nodeType === 3\n}\n\n/**\n * Normalize a DOM point so that it always refers to a text node.\n */\n\nexport const normalizeDOMPoint = (domPoint: DOMPoint): DOMPoint => {\n let [node, offset] = domPoint\n\n // If it's an element node, its offset refers to the index of its children\n // including comment nodes, so try to find the right text child node.\n if (isDOMElement(node) && node.childNodes.length) {\n const isLast = offset === node.childNodes.length\n const direction = isLast ? 'backward' : 'forward'\n const index = isLast ? offset - 1 : offset\n node = getEditableChild(node, index, direction)\n\n // If the node has children, traverse until we have a leaf node. Leaf nodes\n // can be either text nodes, or other void DOM nodes.\n while (isDOMElement(node) && node.childNodes.length) {\n const i = isLast ? node.childNodes.length - 1 : 0\n node = getEditableChild(node, i, direction)\n }\n\n // Determine the new offset inside the text node.\n offset = isLast && node.textContent != null ? node.textContent.length : 0\n }\n\n // Return the node and offset.\n return [node, offset]\n}\n\n/**\n * Get the nearest editable child at `index` in a `parent`, preferring\n * `direction`.\n */\n\nexport const getEditableChild = (\n parent: DOMElement,\n index: number,\n direction: 'forward' | 'backward'\n): DOMNode => {\n const { childNodes } = parent\n let child = childNodes[index]\n let i = index\n let triedForward = false\n let triedBackward = false\n\n // While the child is a comment node, or an element node with no children,\n // keep iterating to find a sibling non-void, non-comment node.\n while (\n isDOMComment(child) ||\n (isDOMElement(child) && child.childNodes.length === 0) ||\n (isDOMElement(child) && child.getAttribute('contenteditable') === 'false')\n ) {\n if (triedForward && triedBackward) {\n break\n }\n\n if (i >= childNodes.length) {\n triedForward = true\n i = index - 1\n direction = 'backward'\n continue\n }\n\n if (i < 0) {\n triedBackward = true\n i = index + 1\n direction = 'forward'\n continue\n }\n\n child = childNodes[i]\n i += direction === 'forward' ? 1 : -1\n }\n\n return child\n}\n","import React, { useEffect, useRef, useMemo, useCallback } from 'react'\nimport {\n Editor,\n Element,\n NodeEntry,\n Node,\n Range,\n Text,\n Transforms,\n} from 'slate'\nimport getDirection from 'direction'\nimport debounce from 'debounce'\nimport scrollIntoView from 'scroll-into-view-if-needed'\n\nimport Children from './children'\nimport Hotkeys from '../utils/hotkeys'\nimport { IS_FIREFOX, IS_SAFARI } from '../utils/environment'\nimport { ReactEditor } from '..'\nimport { ReadOnlyContext } from '../hooks/use-read-only'\nimport { useSlate } from '../hooks/use-slate'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n DOMElement,\n DOMNode,\n DOMRange,\n isDOMElement,\n isDOMNode,\n isDOMText,\n DOMStaticRange,\n} from '../utils/dom'\nimport {\n EDITOR_TO_ELEMENT,\n ELEMENT_TO_NODE,\n IS_READ_ONLY,\n NODE_TO_ELEMENT,\n IS_FOCUSED,\n PLACEHOLDER_SYMBOL,\n} from '../utils/weak-maps'\n\n/**\n * `RenderElementProps` are passed to the `renderElement` handler.\n */\n\nexport interface RenderElementProps {\n children: any\n element: Element\n attributes: {\n 'data-slate-node': 'element'\n 'data-slate-inline'?: true\n 'data-slate-void'?: true\n dir?: 'rtl'\n ref: any\n }\n}\n\n/**\n * `RenderLeafProps` are passed to the `renderLeaf` handler.\n */\n\nexport interface RenderLeafProps {\n children: any\n leaf: Text\n text: Text\n attributes: {\n 'data-slate-leaf': true\n }\n}\n\n/**\n * `EditableProps` are passed to the `` component.\n */\n\nexport type EditableProps = {\n decorate?: (entry: NodeEntry) => Range[]\n onDOMBeforeInput?: (event: Event) => void\n placeholder?: string\n readOnly?: boolean\n role?: string\n style?: React.CSSProperties\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n as?: React.ElementType\n ReactHappyWindow?: React.Component\n reactHappyWindowProps?: object\n} & React.TextareaHTMLAttributes\n\n/**\n * Editable.\n */\n\nexport const Editable = (props: EditableProps) => {\n const {\n autoFocus,\n decorate = defaultDecorate,\n onDOMBeforeInput: propsOnDOMBeforeInput,\n placeholder,\n readOnly = false,\n renderElement,\n renderLeaf,\n style = {},\n as: Component = 'div',\n ReactHappyWindow,\n reactHappyWindowProps,\n happyWindowRef,\n ...attributes\n } = props\n const editor = useSlate()\n const ref = useRef(null)\n\n // Update internal state on each render.\n IS_READ_ONLY.set(editor, readOnly)\n\n // Keep track of some state for the event handler logic.\n const state = useMemo(\n () => ({\n isComposing: false,\n isUpdatingSelection: false,\n latestElement: null as DOMElement | null,\n }),\n []\n )\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n EDITOR_TO_ELEMENT.set(editor, ref.current)\n NODE_TO_ELEMENT.set(editor, ref.current)\n ELEMENT_TO_NODE.set(ref.current, editor)\n } else {\n NODE_TO_ELEMENT.delete(editor)\n }\n })\n\n // Attach a native DOM event handler for `selectionchange`, because React's\n // built-in `onSelect` handler doesn't fire for all selection changes. It's a\n // leaky polyfill that only fires on keypresses or clicks. Instead, we want to\n // fire for any change to the selection inside the editor. (2019/11/04)\n // https://github.com/facebook/react/issues/5785\n useIsomorphicLayoutEffect(() => {\n window.document.addEventListener('selectionchange', onDOMSelectionChange)\n\n return () => {\n window.document.removeEventListener(\n 'selectionchange',\n onDOMSelectionChange\n )\n }\n }, [])\n\n // Attach a native DOM event handler for `beforeinput` events, because React's\n // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose\n // real `beforeinput` events sadly... (2019/11/04)\n // https://github.com/facebook/react/issues/11211\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n // @ts-ignore The `beforeinput` event isn't recognized.\n ref.current.addEventListener('beforeinput', onDOMBeforeInput)\n }\n\n return () => {\n if (ref.current) {\n // @ts-ignore The `beforeinput` event isn't recognized.\n ref.current.removeEventListener('beforeinput', onDOMBeforeInput)\n }\n }\n }, [])\n\n // Whenever the editor updates, make sure the DOM selection state is in sync.\n useIsomorphicLayoutEffect(() => {\n const { selection } = editor\n const domSelection = window.getSelection()\n\n if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {\n return\n }\n\n const hasDomSelection = domSelection.type !== 'None'\n\n // If the DOM selection is properly unset, we're done.\n if (!selection && !hasDomSelection) {\n return\n }\n\n const newDomRange = selection && ReactEditor.toDOMRange(editor, selection)\n\n // If the DOM selection is already correct, we're done.\n if (\n hasDomSelection &&\n newDomRange &&\n isRangeEqual(domSelection.getRangeAt(0), newDomRange)\n ) {\n return\n }\n\n // Otherwise the DOM selection is out of sync, so update it.\n const el = ReactEditor.toDOMNode(editor, editor)\n state.isUpdatingSelection = true\n domSelection.removeAllRanges()\n\n if (newDomRange) {\n domSelection.addRange(newDomRange!)\n const leafEl = newDomRange.startContainer.parentElement!\n scrollIntoView(leafEl, { scrollMode: 'if-needed' })\n }\n\n setTimeout(() => {\n // COMPAT: In Firefox, it's not enough to create a range, you also need\n // to focus the contenteditable element too. (2016/11/16)\n if (newDomRange && IS_FIREFOX) {\n el.focus()\n }\n\n state.isUpdatingSelection = false\n })\n })\n\n // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it\n // needs to be manually focused.\n useEffect(() => {\n if (ref.current && autoFocus) {\n ref.current.focus()\n }\n }, [autoFocus])\n\n // Listen on the native `beforeinput` event to get real \"Level 2\" events. This\n // is required because React's `beforeinput` is fake and never really attaches\n // to the real event sadly. (2019/11/01)\n // https://github.com/facebook/react/issues/11211\n const onDOMBeforeInput = useCallback(\n (\n event: Event & {\n data: string | null\n dataTransfer: DataTransfer | null\n getTargetRanges(): DOMStaticRange[]\n inputType: string\n isComposing: boolean\n }\n ) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isDOMEventHandled(event, propsOnDOMBeforeInput)\n ) {\n const { selection } = editor\n const { inputType: type } = event\n const data = event.dataTransfer || event.data || undefined\n\n // These two types occur while a user is composing text and can't be\n // cancelled. Let them through and wait for the composition to end.\n if (\n type === 'insertCompositionText' ||\n type === 'deleteCompositionText'\n ) {\n return\n }\n\n event.preventDefault()\n\n // COMPAT: For the deleting forward/backward input types we don't want\n // to change the selection because it is the range that will be deleted,\n // and those commands determine that for themselves.\n if (!type.startsWith('delete') || type.startsWith('deleteBy')) {\n const [targetRange] = event.getTargetRanges()\n\n if (targetRange) {\n const range = ReactEditor.toSlateRange(editor, targetRange)\n if (!range) {\n return\n }\n if (!selection || !Range.equals(selection, range)) {\n Transforms.select(editor, range)\n }\n }\n }\n\n // COMPAT: If the selection is expanded, even if the command seems like\n // a delete forward/backward command it should delete the selection.\n if (\n selection &&\n Range.isExpanded(selection) &&\n type.startsWith('delete')\n ) {\n Editor.deleteFragment(editor)\n return\n }\n\n switch (type) {\n case 'deleteByComposition':\n case 'deleteByCut':\n case 'deleteByDrag': {\n Editor.deleteFragment(editor)\n break\n }\n\n case 'deleteContent':\n case 'deleteContentForward': {\n Editor.deleteForward(editor)\n break\n }\n\n case 'deleteContentBackward': {\n Editor.deleteBackward(editor)\n break\n }\n\n case 'deleteEntireSoftLine': {\n Editor.deleteBackward(editor, { unit: 'line' })\n Editor.deleteForward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteHardLineBackward': {\n Editor.deleteBackward(editor, { unit: 'block' })\n break\n }\n\n case 'deleteSoftLineBackward': {\n Editor.deleteBackward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteHardLineForward': {\n Editor.deleteForward(editor, { unit: 'block' })\n break\n }\n\n case 'deleteSoftLineForward': {\n Editor.deleteForward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteWordBackward': {\n Editor.deleteBackward(editor, { unit: 'word' })\n break\n }\n\n case 'deleteWordForward': {\n Editor.deleteForward(editor, { unit: 'word' })\n break\n }\n\n case 'insertLineBreak':\n case 'insertParagraph': {\n Editor.insertBreak(editor)\n break\n }\n\n case 'insertFromComposition':\n case 'insertFromDrop':\n case 'insertFromPaste':\n case 'insertFromYank':\n case 'insertReplacementText':\n case 'insertText': {\n if (data instanceof DataTransfer) {\n ReactEditor.insertData(editor, data)\n } else if (typeof data === 'string') {\n Editor.insertText(editor, data)\n }\n\n break\n }\n }\n }\n },\n []\n )\n\n // Listen on the native `selectionchange` event to be able to update any time\n // the selection changes. This is required because React's `onSelect` is leaky\n // and non-standard so it doesn't fire until after a selection has been\n // released. This causes issues in situations where another change happens\n // while a selection is being dragged.\n const onDOMSelectionChange = useCallback(\n debounce(() => {\n if (!readOnly && !state.isComposing && !state.isUpdatingSelection) {\n const { activeElement } = window.document\n const el = ReactEditor.toDOMNode(editor, editor)\n const domSelection = window.getSelection()\n const domRange =\n domSelection &&\n domSelection.rangeCount > 0 &&\n domSelection.getRangeAt(0)\n\n if (activeElement === el) {\n state.latestElement = activeElement\n IS_FOCUSED.set(editor, true)\n } else {\n IS_FOCUSED.delete(editor)\n }\n\n if (\n domRange &&\n hasEditableTarget(editor, domRange.startContainer) &&\n hasEditableTarget(editor, domRange.endContainer)\n ) {\n const range = ReactEditor.toSlateRange(editor, domRange)\n Transforms.select(editor, range)\n } else {\n Transforms.deselect(editor)\n }\n }\n }, 100),\n []\n )\n\n const decorations = decorate([editor, []])\n\n if (\n placeholder &&\n editor.children.length === 1 &&\n Array.from(Node.texts(editor)).length === 1 &&\n Node.string(editor) === ''\n ) {\n const start = Editor.start(editor, [])\n decorations.push({\n [PLACEHOLDER_SYMBOL]: true,\n placeholder,\n anchor: start,\n focus: start,\n })\n }\n\n return (\n \n {\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to React's leaky polyfill instead just for it. It\n // only works for the `insertText` input type.\n if (IS_FIREFOX && !readOnly && ReactEditor.isFocused(editor)) {\n event.preventDefault()\n const text = (event as any).data as string\n Editor.insertText(editor, text)\n }\n },\n [readOnly]\n )}\n onBlur={useCallback(\n (event: React.FocusEvent) => {\n if (\n readOnly ||\n state.isUpdatingSelection ||\n !hasEditableTarget(editor, event.target) ||\n isEventHandled(event, attributes.onBlur)\n ) {\n return\n }\n\n // COMPAT: If the current `activeElement` is still the previous\n // one, this is due to the window being blurred when the tab\n // itself becomes unfocused, so we want to abort early to allow to\n // editor to stay focused when the tab becomes focused again.\n if (state.latestElement === window.document.activeElement) {\n return\n }\n\n const { relatedTarget } = event\n const el = ReactEditor.toDOMNode(editor, editor)\n\n // COMPAT: The event should be ignored if the focus is returning\n // to the editor from an embedded editable element (eg. an \n // element inside a void node).\n if (relatedTarget === el) {\n return\n }\n\n // COMPAT: The event should be ignored if the focus is moving from\n // the editor to inside a void node's spacer element.\n if (\n isDOMElement(relatedTarget) &&\n relatedTarget.hasAttribute('data-slate-spacer')\n ) {\n return\n }\n\n // COMPAT: The event should be ignored if the focus is moving to a\n // non- editable section of an element that isn't a void node (eg.\n // a list item of the check list example).\n if (\n relatedTarget != null &&\n isDOMNode(relatedTarget) &&\n ReactEditor.hasDOMNode(editor, relatedTarget)\n ) {\n const node = ReactEditor.toSlateNode(editor, relatedTarget)\n\n if (Element.isElement(node) && !editor.isVoid(node)) {\n return\n }\n }\n\n IS_FOCUSED.delete(editor)\n },\n [readOnly, attributes.onBlur]\n )}\n onClick={useCallback(\n (event: React.MouseEvent) => {\n if (\n !readOnly &&\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onClick) &&\n isDOMNode(event.target)\n ) {\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n const start = Editor.start(editor, path)\n\n if (Editor.void(editor, { at: start })) {\n const range = Editor.range(editor, start)\n Transforms.select(editor, range)\n }\n }\n },\n [readOnly, attributes.onClick]\n )}\n onCompositionEnd={useCallback(\n (event: React.CompositionEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCompositionEnd)\n ) {\n state.isComposing = false\n\n // COMPAT: In Chrome, `beforeinput` events for compositions\n // aren't correct and never fire the \"insertFromComposition\"\n // type that we need. So instead, insert whenever a composition\n // ends since it will already have been committed to the DOM.\n if (!IS_SAFARI && !IS_FIREFOX && event.data) {\n Editor.insertText(editor, event.data)\n }\n }\n },\n [attributes.onCompositionEnd]\n )}\n onCompositionStart={useCallback(\n (event: React.CompositionEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCompositionStart)\n ) {\n state.isComposing = true\n }\n },\n [attributes.onCompositionStart]\n )}\n onCopy={useCallback(\n (event: React.ClipboardEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCopy)\n ) {\n event.preventDefault()\n setFragmentData(event.clipboardData, editor)\n }\n },\n [attributes.onCopy]\n )}\n onCut={useCallback(\n (event: React.ClipboardEvent) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCut)\n ) {\n event.preventDefault()\n setFragmentData(event.clipboardData, editor)\n const { selection } = editor\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n }\n }\n },\n [readOnly, attributes.onCut]\n )}\n onDragOver={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onDragOver)\n ) {\n // Only when the target is void, call `preventDefault` to signal\n // that drops are allowed. Editable content is droppable by\n // default, and calling `preventDefault` hides the cursor.\n const node = ReactEditor.toSlateNode(editor, event.target)\n\n if (Editor.isVoid(editor, node)) {\n event.preventDefault()\n }\n }\n },\n [attributes.onDragOver]\n )}\n onDragStart={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onDragStart)\n ) {\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n const voidMatch = Editor.void(editor, { at: path })\n\n // If starting a drag on a void node, make sure it is selected\n // so that it shows up in the selection's fragment.\n if (voidMatch) {\n const range = Editor.range(editor, path)\n Transforms.select(editor, range)\n }\n\n setFragmentData(event.dataTransfer, editor)\n }\n },\n [attributes.onDragStart]\n )}\n onDrop={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !readOnly &&\n !isEventHandled(event, attributes.onDrop)\n ) {\n // COMPAT: Firefox doesn't fire `beforeinput` events at all, and\n // Chromium browsers don't properly fire them for files being\n // dropped into a `contenteditable`. (2019/11/26)\n // https://bugs.chromium.org/p/chromium/issues/detail?id=1028668\n if (\n IS_FIREFOX ||\n (!IS_SAFARI && event.dataTransfer.files.length > 0)\n ) {\n event.preventDefault()\n const range = ReactEditor.findEventRange(editor, event)\n const data = event.dataTransfer\n Transforms.select(editor, range)\n ReactEditor.insertData(editor, data)\n }\n }\n },\n [readOnly, attributes.onDrop]\n )}\n onFocus={useCallback(\n (event: React.FocusEvent) => {\n if (\n !readOnly &&\n !state.isUpdatingSelection &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onFocus)\n ) {\n const el = ReactEditor.toDOMNode(editor, editor)\n state.latestElement = window.document.activeElement\n\n // COMPAT: If the editor has nested editable elements, the focus\n // can go to them. In Firefox, this must be prevented because it\n // results in issues with keyboard navigation. (2017/03/30)\n if (IS_FIREFOX && event.target !== el) {\n el.focus()\n return\n }\n\n IS_FOCUSED.set(editor, true)\n }\n },\n [readOnly, attributes.onFocus]\n )}\n onKeyDown={useCallback(\n (event: React.KeyboardEvent) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onKeyDown)\n ) {\n const { nativeEvent } = event\n const { selection } = editor\n\n const element =\n editor.children[\n selection !== null ? selection.focus.path[0] : 0\n ]\n const isRTL = getDirection(Node.string(element)) === 'rtl'\n\n // COMPAT: Since we prevent the default behavior on\n // `beforeinput` events, the browser doesn't think there's ever\n // any history stack to undo or redo, so we have to manage these\n // hotkeys ourselves. (2019/11/06)\n if (Hotkeys.isRedo(nativeEvent)) {\n event.preventDefault()\n\n if (editor.redo) {\n editor.redo()\n }\n\n return\n }\n\n if (Hotkeys.isUndo(nativeEvent)) {\n event.preventDefault()\n\n if (editor.undo) {\n editor.undo()\n }\n\n return\n }\n\n // COMPAT: Certain browsers don't handle the selection updates\n // properly. In Chrome, the selection isn't properly extended.\n // And in Firefox, the selection isn't properly collapsed.\n // (2017/10/17)\n if (Hotkeys.isMoveLineBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line', reverse: true })\n return\n }\n\n if (Hotkeys.isMoveLineForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line' })\n return\n }\n\n if (Hotkeys.isExtendLineBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, {\n unit: 'line',\n edge: 'focus',\n reverse: true,\n })\n return\n }\n\n if (Hotkeys.isExtendLineForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line', edge: 'focus' })\n return\n }\n\n // COMPAT: If a void node is selected, or a zero-width text node\n // adjacent to an inline is selected, we need to handle these\n // hotkeys manually because browsers won't be able to skip over\n // the void node with the zero-width space not being an empty\n // string.\n if (Hotkeys.isMoveBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isCollapsed(selection)) {\n const { anchor } = selection\n if (anchor.offset === 1 && anchor.path[1] > 0) {\n // Hack to position the cursor at the end of the previous text node\n Transforms.move(editor, { reverse: !isRTL, distance: 2 })\n Transforms.move(editor, { reverse: isRTL })\n } else {\n Transforms.move(editor, { reverse: !isRTL })\n }\n } else {\n Transforms.collapse(editor, { edge: 'start' })\n }\n\n return\n }\n\n if (Hotkeys.isMoveForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isCollapsed(selection)) {\n Transforms.move(editor, { reverse: isRTL })\n } else {\n Transforms.collapse(editor, { edge: 'end' })\n }\n\n return\n }\n\n if (Hotkeys.isMoveWordBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'word', reverse: !isRTL })\n return\n }\n\n if (Hotkeys.isMoveWordForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'word', reverse: isRTL })\n return\n }\n\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to guessing at the input intention for hotkeys.\n // COMPAT: In iOS, some of these hotkeys are handled in the\n if (IS_FIREFOX) {\n // We don't have a core behavior for these, but they change the\n // DOM if we don't prevent them, so we have to.\n if (\n Hotkeys.isBold(nativeEvent) ||\n Hotkeys.isItalic(nativeEvent) ||\n Hotkeys.isTransposeCharacter(nativeEvent)\n ) {\n event.preventDefault()\n return\n }\n\n if (Hotkeys.isSplitBlock(nativeEvent)) {\n event.preventDefault()\n Editor.insertBreak(editor)\n return\n }\n\n if (Hotkeys.isDeleteBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor)\n }\n\n return\n }\n\n if (Hotkeys.isDeleteForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor)\n }\n\n return\n }\n\n if (Hotkeys.isDeleteLineBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor, { unit: 'line' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteLineForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor, { unit: 'line' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteWordBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor, { unit: 'word' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteWordForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor, { unit: 'word' })\n }\n\n return\n }\n }\n }\n },\n [readOnly, attributes.onKeyDown]\n )}\n onPaste={useCallback(\n (event: React.ClipboardEvent) => {\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to React's `onPaste` here instead.\n if (\n IS_FIREFOX &&\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onPaste)\n ) {\n event.preventDefault()\n ReactEditor.insertData(editor, event.clipboardData)\n }\n },\n [readOnly, attributes.onPaste]\n )}\n >\n \n \n \n )\n}\n\n/**\n * A default memoized decorate function.\n */\n\nconst defaultDecorate = () => []\n\n/**\n * Check if two DOM range objects are equal.\n */\n\nconst isRangeEqual = (a: DOMRange, b: DOMRange) => {\n return (\n (a.startContainer === b.startContainer &&\n a.startOffset === b.startOffset &&\n a.endContainer === b.endContainer &&\n a.endOffset === b.endOffset) ||\n (a.startContainer === b.endContainer &&\n a.startOffset === b.endOffset &&\n a.endContainer === b.startContainer &&\n a.endOffset === b.startOffset)\n )\n}\n\n/**\n * Check if the target is in the editor.\n */\n\nconst hasTarget = (\n editor: ReactEditor,\n target: EventTarget | null\n): target is DOMNode => {\n return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target)\n}\n\n/**\n * Check if the target is editable and in the editor.\n */\n\nconst hasEditableTarget = (\n editor: ReactEditor,\n target: EventTarget | null\n): target is DOMNode => {\n return (\n isDOMNode(target) &&\n ReactEditor.hasDOMNode(editor, target, { editable: true })\n )\n}\n\n/**\n * Check if an event is overrided by a handler.\n */\n\nconst isEventHandled = <\n EventType extends React.SyntheticEvent\n>(\n event: EventType,\n handler?: (event: EventType) => void\n) => {\n if (!handler) {\n return false\n }\n\n handler(event)\n return event.isDefaultPrevented() || event.isPropagationStopped()\n}\n\n/**\n * Check if a DOM event is overrided by a handler.\n */\n\nconst isDOMEventHandled = (event: Event, handler?: (event: Event) => void) => {\n if (!handler) {\n return false\n }\n\n handler(event)\n return event.defaultPrevented\n}\n\n/**\n * Set the currently selected fragment to the clipboard.\n */\n\nconst setFragmentData = (\n dataTransfer: DataTransfer,\n editor: ReactEditor\n): void => {\n const { selection } = editor\n\n if (!selection) {\n return\n }\n\n const [start, end] = Range.edges(selection)\n const startVoid = Editor.void(editor, { at: start.path })\n const endVoid = Editor.void(editor, { at: end.path })\n\n if (Range.isCollapsed(selection) && !startVoid) {\n return\n }\n\n // Create a fake selection so that we can add a Base64-encoded copy of the\n // fragment to the HTML, to decode on future pastes.\n const domRange = ReactEditor.toDOMRange(editor, selection)\n let contents = domRange.cloneContents()\n let attach = contents.childNodes[0] as HTMLElement\n\n // Make sure attach is non-empty, since empty nodes will not get copied.\n contents.childNodes.forEach(node => {\n if (node.textContent && node.textContent.trim() !== '') {\n attach = node as HTMLElement\n }\n })\n\n // COMPAT: If the end node is a void node, we need to move the end of the\n // range from the void node's spacer span, to the end of the void node's\n // content, since the spacer is before void's content in the DOM.\n if (endVoid) {\n const [voidNode] = endVoid\n const r = domRange.cloneRange()\n const domNode = ReactEditor.toDOMNode(editor, voidNode)\n r.setEndAfter(domNode)\n contents = r.cloneContents()\n }\n\n // COMPAT: If the start node is a void node, we need to attach the encoded\n // fragment to the void node's content node instead of the spacer, because\n // attaching it to empty `
/` nodes will end up having it erased by\n // most browsers. (2018/04/27)\n if (startVoid) {\n attach = contents.querySelector('[data-slate-spacer]')! as HTMLElement\n }\n\n // Remove any zero-width space spans from the cloned DOM so that they don't\n // show up elsewhere when pasted.\n Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(\n zw => {\n const isNewline = zw.getAttribute('data-slate-zero-width') === 'n'\n zw.textContent = isNewline ? '\\n' : ''\n }\n )\n\n // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up\n // in the HTML, and can be used for intra-Slate pasting. If it's a text\n // node, wrap it in a `` so we have something to set an attribute on.\n if (isDOMText(attach)) {\n const span = document.createElement('span')\n // COMPAT: In Chrome and Safari, if we don't add the `white-space` style\n // then leading and trailing spaces will be ignored. (2017/09/21)\n span.style.whiteSpace = 'pre'\n span.appendChild(attach)\n contents.appendChild(span)\n attach = span\n }\n\n const fragment = Node.fragment(editor, selection)\n const string = JSON.stringify(fragment)\n const encoded = window.btoa(encodeURIComponent(string))\n attach.setAttribute('data-slate-fragment', encoded)\n\n // Overwriting the default functionality\n const { getFormattedSelection, getHTMLFormattedSelection } = editor\n if (\n typeof getFormattedSelection === 'function' &&\n typeof getHTMLFormattedSelection === 'function'\n ) {\n try {\n const plainText = getFormattedSelection()\n const htmlText = getHTMLFormattedSelection()\n dataTransfer.setData('text/plain', plainText)\n dataTransfer.setData('text/html', htmlText)\n return\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Error in slate-react/src/components/editable.tsx: ', e)\n // Only setData application/x-slate-fragment as a fallback because\n // we don't want to copy the timestamps of words\n dataTransfer.setData('application/x-slate-fragment', encoded)\n }\n }\n\n // Add the content to a
so that we can get its inner HTML.\n const div = document.createElement('div')\n div.appendChild(contents)\n dataTransfer.setData('text/html', div.innerHTML)\n dataTransfer.setData('text/plain', getPlainText(div))\n}\n\n/**\n * Get a plaintext representation of the content of a node, accounting for block\n * elements which get a newline appended.\n */\n\nconst getPlainText = (domNode: DOMNode) => {\n let text = ''\n\n if (isDOMText(domNode) && domNode.nodeValue) {\n return domNode.nodeValue\n }\n\n if (isDOMElement(domNode)) {\n for (const childNode of Array.from(domNode.childNodes)) {\n text += getPlainText(childNode)\n }\n\n const display = getComputedStyle(domNode).getPropertyValue('display')\n\n if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {\n text += '\\n'\n }\n }\n\n return text\n}\n","/**\n * An auto-incrementing identifier for keys.\n */\n\nlet n = 0\n\n/**\n * A class that keeps track of a key string. We use a full class here because we\n * want to be able to use them as keys in `WeakMap` objects.\n */\n\nexport class Key {\n id: string\n\n constructor() {\n this.id = `${n++}`\n }\n}\n","import { Editor, Node, Path, Point, Range, Transforms } from 'slate'\n\nimport { Key } from '../utils/key'\nimport {\n EDITOR_TO_ELEMENT,\n ELEMENT_TO_NODE,\n IS_FOCUSED,\n IS_READ_ONLY,\n KEY_TO_ELEMENT,\n NODE_TO_INDEX,\n NODE_TO_KEY,\n NODE_TO_PARENT,\n} from '../utils/weak-maps'\nimport {\n DOMElement,\n DOMNode,\n DOMPoint,\n DOMRange,\n DOMSelection,\n DOMStaticRange,\n isDOMElement,\n normalizeDOMPoint,\n} from '../utils/dom'\n\n/**\n * A React and DOM-specific version of the `Editor` interface.\n */\n\nexport interface ReactEditor extends Editor {\n insertData: (data: DataTransfer) => void\n}\n\nexport const ReactEditor = {\n /**\n * Find a key for a Slate node.\n */\n\n findKey(editor: ReactEditor, node: Node): Key {\n let key = NODE_TO_KEY.get(node)\n\n if (!key) {\n key = new Key()\n NODE_TO_KEY.set(node, key)\n }\n\n return key\n },\n\n /**\n * Find the path of Slate node.\n */\n\n findPath(editor: ReactEditor, node: Node): Path {\n const path: Path = []\n let child = node\n\n while (true) {\n const parent = NODE_TO_PARENT.get(child)\n\n if (parent == null) {\n if (Editor.isEditor(child)) {\n return path\n } else {\n break\n }\n }\n\n const i = NODE_TO_INDEX.get(child)\n\n if (i == null) {\n break\n }\n\n path.unshift(i)\n child = parent\n }\n\n throw new Error(\n `Unable to find the path for Slate node: ${JSON.stringify(node)}`\n )\n },\n\n /**\n * Check if the editor is focused.\n */\n\n isFocused(editor: ReactEditor): boolean {\n return !!IS_FOCUSED.get(editor)\n },\n\n /**\n * Check if the editor is in read-only mode.\n */\n\n isReadOnly(editor: ReactEditor): boolean {\n return !!IS_READ_ONLY.get(editor)\n },\n\n /**\n * Blur the editor.\n */\n\n blur(editor: ReactEditor): void {\n const el = ReactEditor.toDOMNode(editor, editor)\n IS_FOCUSED.set(editor, false)\n\n if (window.document.activeElement === el) {\n el.blur()\n }\n },\n\n /**\n * Focus the editor.\n */\n\n focus(editor: ReactEditor): void {\n const el = ReactEditor.toDOMNode(editor, editor)\n IS_FOCUSED.set(editor, true)\n\n if (window.document.activeElement !== el) {\n el.focus({ preventScroll: true })\n }\n },\n\n /**\n * Deselect the editor.\n */\n\n deselect(editor: ReactEditor): void {\n const { selection } = editor\n const domSelection = window.getSelection()\n\n if (domSelection && domSelection.rangeCount > 0) {\n domSelection.removeAllRanges()\n }\n\n if (selection) {\n Transforms.deselect(editor)\n }\n },\n\n /**\n * Check if a DOM node is within the editor.\n */\n\n hasDOMNode(\n editor: ReactEditor,\n target: DOMNode,\n options: { editable?: boolean } = {}\n ): boolean {\n const { editable = false } = options\n const el = ReactEditor.toDOMNode(editor, editor)\n let element\n\n // COMPAT: In Firefox, reading `target.nodeType` will throw an error if\n // target is originating from an internal \"restricted\" element (e.g. a\n // stepper arrow on a number input). (2018/05/04)\n // https://github.com/ianstormtaylor/slate/issues/1819\n try {\n element = isDOMElement(target) ? target : target.parentElement\n } catch (err) {\n if (\n !err.message.includes('Permission denied to access property \"nodeType\"')\n ) {\n throw err\n }\n }\n\n if (!element) {\n return false\n }\n\n return (\n element.closest(`[data-slate-editor]`) === el &&\n (!editable || el.isContentEditable)\n )\n },\n\n /**\n * Insert data from a `DataTransfer` into the editor.\n */\n\n insertData(editor: ReactEditor, data: DataTransfer): void {\n editor.insertData(data)\n },\n\n /**\n * Find the native DOM element from a Slate node.\n */\n\n toDOMNode(editor: ReactEditor, node: Node): HTMLElement {\n const domNode = Editor.isEditor(node)\n ? EDITOR_TO_ELEMENT.get(editor)\n : KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node))\n\n if (!domNode) {\n throw new Error(\n `Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`\n )\n }\n\n return domNode\n },\n\n /**\n * Find a native DOM selection point from a Slate point.\n */\n\n toDOMPoint(editor: ReactEditor, point: Point): DOMPoint {\n const [node] = Editor.node(editor, point.path)\n const el = ReactEditor.toDOMNode(editor, node)\n let domPoint: DOMPoint | undefined\n\n // If we're inside a void node, force the offset to 0, otherwise the zero\n // width spacing character will result in an incorrect offset of 1\n if (Editor.void(editor, { at: point })) {\n point = { path: point.path, offset: 0 }\n }\n\n // For each leaf, we need to isolate its content, which means filtering\n // to its direct text and zero-width spans. (We have to filter out any\n // other siblings that may have been rendered alongside them.)\n const selector = `[data-slate-string], [data-slate-zero-width]`\n const texts = Array.from(el.querySelectorAll(selector))\n let start = 0\n\n for (const text of texts) {\n const domNode = text.childNodes[0] as HTMLElement\n\n if (domNode == null || domNode.textContent == null) {\n continue\n }\n\n const { length } = domNode.textContent\n const attr = text.getAttribute('data-slate-length')\n const trueLength = attr == null ? length : parseInt(attr, 10)\n const end = start + trueLength\n\n if (point.offset <= end) {\n const offset = Math.min(length, Math.max(0, point.offset - start))\n domPoint = [domNode, offset]\n break\n }\n\n start = end\n }\n\n if (!domPoint) {\n throw new Error(\n `Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`\n )\n }\n\n return domPoint\n },\n\n /**\n * Find a native DOM range from a Slate `range`.\n */\n\n toDOMRange(editor: ReactEditor, range: Range): DOMRange {\n const { anchor, focus } = range\n const domAnchor = ReactEditor.toDOMPoint(editor, anchor)\n const domFocus = Range.isCollapsed(range)\n ? domAnchor\n : ReactEditor.toDOMPoint(editor, focus)\n\n const domRange = window.document.createRange()\n const start = Range.isBackward(range) ? domFocus : domAnchor\n const end = Range.isBackward(range) ? domAnchor : domFocus\n domRange.setStart(start[0], start[1])\n domRange.setEnd(end[0], end[1])\n return domRange\n },\n\n /**\n * Find a Slate node from a native DOM `element`.\n */\n\n toSlateNode(editor: ReactEditor, domNode: DOMNode): Node {\n let domEl = isDOMElement(domNode) ? domNode : domNode.parentElement\n\n if (domEl && !domEl.hasAttribute('data-slate-node')) {\n domEl = domEl.closest(`[data-slate-node]`)\n }\n\n const node = domEl ? ELEMENT_TO_NODE.get(domEl as HTMLElement) : null\n\n if (!node) {\n throw new Error(`Cannot resolve a Slate node from DOM node: ${domEl}`)\n }\n\n return node\n },\n\n /**\n * Get the target range from a DOM `event`.\n */\n\n findEventRange(editor: ReactEditor, event: any): Range {\n if ('nativeEvent' in event) {\n event = event.nativeEvent\n }\n\n const { clientX: x, clientY: y, target } = event\n\n if (x == null || y == null) {\n throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`)\n }\n\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n\n // If the drop target is inside a void node, move it into either the\n // next or previous node, depending on which side the `x` and `y`\n // coordinates are closest to.\n if (Editor.isVoid(editor, node)) {\n const rect = target.getBoundingClientRect()\n const isPrev = editor.isInline(node)\n ? x - rect.left < rect.left + rect.width - x\n : y - rect.top < rect.top + rect.height - y\n\n const edge = Editor.point(editor, path, {\n edge: isPrev ? 'start' : 'end',\n })\n const point = isPrev\n ? Editor.before(editor, edge)\n : Editor.after(editor, edge)\n\n if (point) {\n const range = Editor.range(editor, point)\n return range\n }\n }\n\n // Else resolve a range from the caret position where the drop occured.\n let domRange\n const { document } = window\n\n // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)\n if (document.caretRangeFromPoint) {\n domRange = document.caretRangeFromPoint(x, y)\n } else {\n const position = document.caretPositionFromPoint(x, y)\n\n if (position) {\n domRange = document.createRange()\n domRange.setStart(position.offsetNode, position.offset)\n domRange.setEnd(position.offsetNode, position.offset)\n }\n }\n\n if (!domRange) {\n throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`)\n }\n\n // Resolve a Slate range from the DOM range.\n const range = ReactEditor.toSlateRange(editor, domRange)\n return range\n },\n\n /**\n * Find a Slate point from a DOM selection's `domNode` and `domOffset`.\n */\n\n toSlatePoint(editor: ReactEditor, domPoint: DOMPoint): Point {\n const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint)\n const parentNode = nearestNode.parentNode as DOMElement\n let textNode: DOMElement | null = null\n let offset = 0\n\n if (parentNode) {\n const voidNode = parentNode.closest('[data-slate-void=\"true\"]')\n let leafNode = parentNode.closest('[data-slate-leaf]')\n let domNode: DOMElement | null = null\n\n // Calculate how far into the text node the `nearestNode` is, so that we\n // can determine what the offset relative to the text node is.\n if (leafNode) {\n textNode = leafNode.closest('[data-slate-node=\"text\"]')!\n const range = window.document.createRange()\n range.setStart(textNode, 0)\n range.setEnd(nearestNode, nearestOffset)\n const contents = range.cloneContents()\n const removals = [\n ...contents.querySelectorAll('[data-slate-zero-width]'),\n ...contents.querySelectorAll('[contenteditable=false]'),\n ]\n\n removals.forEach(el => {\n el!.parentNode!.removeChild(el)\n })\n\n // COMPAT: Edge has a bug where Range.prototype.toString() will\n // convert \\n into \\r\\n. The bug causes a loop when slate-react\n // attempts to reposition its cursor to match the native position. Use\n // textContent.length instead.\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/\n offset = contents.textContent!.length\n domNode = textNode\n } else if (voidNode) {\n // For void nodes, the element with the offset key will be a cousin, not an\n // ancestor, so find it by going down from the nearest void parent.\n\n leafNode = voidNode.querySelector('[data-slate-leaf]')!\n textNode = leafNode.closest('[data-slate-node=\"text\"]')!\n domNode = leafNode\n offset = domNode.textContent!.length\n }\n\n // COMPAT: If the parent node is a Slate zero-width space, editor is\n // because the text node should have no characters. However, during IME\n // composition the ASCII characters will be prepended to the zero-width\n // space, so subtract 1 from the offset to account for the zero-width\n // space character.\n if (\n domNode &&\n offset === domNode.textContent!.length &&\n parentNode.hasAttribute('data-slate-zero-width')\n ) {\n offset--\n }\n }\n\n if (!textNode) {\n throw new Error(\n `Cannot resolve a Slate point from DOM point: ${domPoint}`\n )\n }\n\n // COMPAT: If someone is clicking from one Slate editor into another,\n // the select event fires twice, once for the old editor's `element`\n // first, and then afterwards for the correct `element`. (2017/03/03)\n const slateNode = ReactEditor.toSlateNode(editor, textNode!)\n const path = ReactEditor.findPath(editor, slateNode)\n return { path, offset }\n },\n\n /**\n * Find a Slate range from a DOM range or selection.\n */\n\n toSlateRange(\n editor: ReactEditor,\n domRange: DOMRange | DOMStaticRange | DOMSelection\n ): Range {\n const el =\n domRange instanceof Selection\n ? domRange.anchorNode\n : domRange.startContainer\n let anchorNode\n let anchorOffset\n let focusNode\n let focusOffset\n let isCollapsed\n\n if (el) {\n if (domRange instanceof Selection) {\n anchorNode = domRange.anchorNode\n anchorOffset = domRange.anchorOffset\n focusNode = domRange.focusNode\n focusOffset = domRange.focusOffset\n isCollapsed = domRange.isCollapsed\n } else {\n anchorNode = domRange.startContainer\n anchorOffset = domRange.startOffset\n focusNode = domRange.endContainer\n focusOffset = domRange.endOffset\n isCollapsed = domRange.collapsed\n }\n }\n\n if (\n anchorNode == null ||\n focusNode == null ||\n anchorOffset == null ||\n focusOffset == null\n ) {\n throw new Error(\n `Cannot resolve a Slate range from DOM range: ${domRange}`\n )\n }\n\n const anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset])\n const focus = isCollapsed\n ? anchor\n : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset])\n\n return { anchor, focus }\n },\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `focused` state of the editor.\n */\n\nexport const FocusedContext = createContext(false)\n\n/**\n * Get the current `focused` state of the editor.\n */\n\nexport const useFocused = (): boolean => {\n return useContext(FocusedContext)\n}\n","import React, { useMemo, useState, useCallback } from 'react'\nimport { Node } from 'slate'\n\nimport { ReactEditor } from '../plugin/react-editor'\nimport { FocusedContext } from '../hooks/use-focused'\nimport { EditorContext } from '../hooks/use-editor'\nimport { SlateContext } from '../hooks/use-slate'\nimport { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'\n\n/**\n * A wrapper around the provider to handle `onChange` events, because the editor\n * is a mutable singleton so it won't ever register as \"changed\" otherwise.\n */\n\nexport const Slate = (props: {\n editor: ReactEditor\n value: Node[]\n children: React.ReactNode\n onChange: (value: Node[]) => void\n [key: string]: any\n}) => {\n const { editor, children, onChange, value, ...rest } = props\n const [key, setKey] = useState(0)\n const context: [ReactEditor] = useMemo(() => {\n editor.children = value\n Object.assign(editor, rest)\n return [editor]\n }, [key, value, ...Object.values(rest)])\n\n const onContextChange = useCallback(() => {\n onChange(editor.children)\n setKey(key + 1)\n }, [key, onChange])\n\n EDITOR_TO_ON_CHANGE.set(editor, onContextChange)\n\n return (\n \n \n \n {children}\n \n \n \n )\n}\n","import ReactDOM from 'react-dom'\nimport { Editor, Node, Path, Operation, Transforms } from 'slate'\n\nimport { ReactEditor } from './react-editor'\nimport { Key } from '../utils/key'\nimport { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'\n\n/**\n * `withReact` adds React and DOM specific behaviors to the editor.\n */\n\nexport const withReact = (editor: T) => {\n const e = editor as T & ReactEditor\n const { apply, onChange } = e\n\n e.apply = (op: Operation) => {\n const matches: [Path, Key][] = []\n\n switch (op.type) {\n case 'insert_text':\n case 'remove_text':\n case 'set_node': {\n for (const [node, path] of Editor.levels(e, { at: op.path })) {\n const key = ReactEditor.findKey(e, node)\n matches.push([path, key])\n }\n\n break\n }\n\n case 'insert_node':\n case 'remove_node':\n case 'merge_node':\n case 'split_node': {\n for (const [node, path] of Editor.levels(e, {\n at: Path.parent(op.path),\n })) {\n const key = ReactEditor.findKey(e, node)\n matches.push([path, key])\n }\n\n break\n }\n\n case 'move_node': {\n // TODO\n break\n }\n }\n\n apply(op)\n\n for (const [path, key] of matches) {\n const [node] = Editor.node(e, path)\n NODE_TO_KEY.set(node, key)\n }\n }\n\n e.insertData = (data: DataTransfer) => {\n const fragment = data.getData('application/x-slate-fragment')\n\n if (fragment) {\n const decoded = decodeURIComponent(window.atob(fragment))\n const parsed = JSON.parse(decoded) as Node[]\n Transforms.insertFragment(e, parsed)\n return\n }\n\n const text = data.getData('text/plain')\n\n if (text) {\n const lines = text.split('\\n')\n let split = false\n\n for (const line of lines) {\n if (split) {\n Transforms.splitNodes(e)\n }\n\n Transforms.insertText(e, line)\n split = true\n }\n }\n }\n\n e.onChange = () => {\n // COMPAT: React doesn't batch `setState` hook calls, which means that the\n // children and selection can get out of sync for one render pass. So we\n // have to use this unstable API to ensure it batches them. (2019/12/03)\n // https://github.com/facebook/react/issues/14259#issuecomment-439702367\n ReactDOM.unstable_batchedUpdates(() => {\n const onContextChange = EDITOR_TO_ON_CHANGE.get(e)\n\n if (onContextChange) {\n onContextChange()\n }\n\n onChange()\n })\n }\n\n return e\n}\n"],"names":["Node","NODE_TO_INDEX","WeakMap","NODE_TO_PARENT","EDITOR_TO_ELEMENT","ELEMENT_TO_NODE","KEY_TO_ELEMENT","NODE_TO_ELEMENT","NODE_TO_KEY","IS_READ_ONLY","IS_FOCUSED","EDITOR_TO_ON_CHANGE","PLACEHOLDER_SYMBOL","Symbol","Text","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","SlateText","Leaf","SelectedContext","createContext","useSelected","useContext","Element","ElementComponent","TextComponent","IS_IOS","navigator","test","userAgent","MSStream","IS_APPLE","IS_FIREFOX","IS_SAFARI","HOTKEYS","bold","compose","moveBackward","moveForward","moveWordBackward","moveWordForward","deleteBackward","deleteForward","extendBackward","extendForward","italic","splitBlock","undo","APPLE_HOTKEYS","moveLineBackward","moveLineForward","deleteLineBackward","deleteLineForward","deleteWordBackward","deleteWordForward","extendLineBackward","extendLineForward","redo","transposeCharacter","WINDOWS_HOTKEYS","create","key","generic","apple","windows","isGeneric","isKeyHotkey","isApple","isWindows","event","isBold","isCompose","isMoveBackward","isMoveForward","isDeleteBackward","isDeleteForward","isDeleteLineBackward","isDeleteLineForward","isDeleteWordBackward","isDeleteWordForward","isExtendBackward","isExtendForward","isExtendLineBackward","isExtendLineForward","isItalic","isMoveLineBackward","isMoveLineForward","isMoveWordBackward","isMoveWordForward","isRedo","isSplitBlock","isTransposeCharacter","isUndo","ReadOnlyContext","useReadOnly","isDOMComment","value","isDOMNode","nodeType","isDOMElement","isDOMText","normalizeDOMPoint","domPoint","node","offset","childNodes","length","isLast","direction","index","getEditableChild","i","textContent","parent","child","triedForward","triedBackward","getAttribute","n","Key","constructor","id","ReactEditor","findKey","editor","get","set","findPath","path","Editor","isEditor","unshift","Error","JSON","stringify","isFocused","isReadOnly","blur","el","toDOMNode","document","activeElement","focus","preventScroll","deselect","selection","domSelection","getSelection","rangeCount","removeAllRanges","Transforms","hasDOMNode","target","options","editable","element","parentElement","err","message","includes","closest","isContentEditable","insertData","data","domNode","toDOMPoint","point","void","at","selector","texts","Array","from","querySelectorAll","start","text","attr","trueLength","parseInt","end","Math","min","max","toDOMRange","range","anchor","domAnchor","domFocus","Range","isCollapsed","domRange","createRange","isBackward","setStart","setEnd","toSlateNode","domEl","hasAttribute","findEventRange","nativeEvent","clientX","x","clientY","y","isVoid","rect","getBoundingClientRect","isPrev","isInline","left","width","top","height","edge","before","after","caretRangeFromPoint","position","caretPositionFromPoint","offsetNode","toSlateRange","toSlatePoint","nearestNode","nearestOffset","parentNode","textNode","voidNode","leafNode","contents","cloneContents","removals","forEach","removeChild","querySelector","slateNode","Selection","anchorNode","startContainer","anchorOffset","focusNode","focusOffset","startOffset","endContainer","endOffset","collapsed","FocusedContext","useFocused","withReact","e","apply","onChange","op","matches","type","levels","push","Path","fragment","getData","decoded","decodeURIComponent","atob","parsed","parse","insertFragment","lines","split","line","splitNodes","insertText","ReactDOM","unstable_batchedUpdates","onContextChange"],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index 03955d1..0000000 --- a/dist/index.js +++ /dev/null @@ -1,1932 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } - -var React = require('react'); -var React__default = _interopDefault(React); -var slate = require('slate'); -var getDirection = _interopDefault(require('direction')); -var debounce = _interopDefault(require('debounce')); -var scrollIntoView = _interopDefault(require('scroll-into-view-if-needed')); -var isHotkey = require('is-hotkey'); -var ReactDOM = _interopDefault(require('react-dom')); - -/** - * Leaf content strings. - */ -const String = (props) => { - const { isLast, leaf, parent, text } = props; - const editor = useEditor(); - const path = ReactEditor.findPath(editor, text); - const parentPath = slate.Path.parent(path); - // COMPAT: Render text inside void nodes with a zero-width space. - // So the node can contain selection but the text is not visible. - if (editor.isVoid(parent)) { - return React__default.createElement(ZeroWidthString, { length: slate.Node.string(parent).length }); - } - // COMPAT: If this is the last text node in an empty block, render a zero- - // width space that will convert into a line break when copying and pasting - // to support expected plain text. - if (leaf.text === '' && - parent.children[parent.children.length - 1] === text && - !editor.isInline(parent) && - slate.Editor.string(editor, parentPath) === '') { - return React__default.createElement(ZeroWidthString, { isLineBreak: true }); - } - // COMPAT: If the text is empty, it's because it's on the edge of an inline - // node, so we render a zero-width space so that the selection can be - // inserted next to it still. - if (leaf.text === '') { - return React__default.createElement(ZeroWidthString, null); - } - // COMPAT: Browsers will collapse trailing new lines at the end of blocks, - // so we need to add an extra trailing new lines to prevent that. - if (isLast && leaf.text.slice(-1) === '\n') { - return React__default.createElement(TextString, { isTrailing: true, text: leaf.text }); - } - return React__default.createElement(TextString, { text: leaf.text }); -}; -/** - * Leaf strings with text in them. - */ -const TextString = (props) => { - const { text, isTrailing = false } = props; - return (React__default.createElement("span", { "data-slate-string": true }, - text, - isTrailing ? '\n' : null)); -}; -/** - * Leaf strings without text, render as zero-width strings. - */ -const ZeroWidthString = (props) => { - const { length = 0, isLineBreak = false } = props; - return (React__default.createElement("span", { "data-slate-zero-width": isLineBreak ? 'n' : 'z', "data-slate-length": length }, - '\uFEFF', - isLineBreak ? React__default.createElement("br", null) : null)); -}; - -/** - * Two weak maps that allow us rebuild a path given a node. They are populated - * at render time such that after a render occurs we can always backtrack. - */ -var NODE_TO_INDEX = new WeakMap(); -var NODE_TO_PARENT = new WeakMap(); -/** - * Weak maps that allow us to go between Slate nodes and DOM nodes. These - * are used to resolve DOM event-related logic into Slate actions. - */ - -var EDITOR_TO_ELEMENT = new WeakMap(); -var ELEMENT_TO_NODE = new WeakMap(); -var KEY_TO_ELEMENT = new WeakMap(); -var NODE_TO_ELEMENT = new WeakMap(); -var NODE_TO_KEY = new WeakMap(); -/** - * Weak maps for storing editor-related state. - */ - -var IS_READ_ONLY = new WeakMap(); -var IS_FOCUSED = new WeakMap(); -/** - * Weak map for associating the context `onChange` context with the plugin. - */ - -var EDITOR_TO_ON_CHANGE = new WeakMap(); -/** - * Symbols. - */ - -var PLACEHOLDER_SYMBOL = Symbol('placeholder'); - -/** - * Individual leaves in a text node with unique formatting. - */ -const Leaf = (props) => { - const { leaf, isLast, text, parent, renderLeaf = (props) => React__default.createElement(DefaultLeaf, Object.assign({}, props)), } = props; - let children = (React__default.createElement(String, { isLast: isLast, leaf: leaf, parent: parent, text: text })); - if (leaf[PLACEHOLDER_SYMBOL]) { - children = (React__default.createElement(React__default.Fragment, null, - React__default.createElement("span", { contentEditable: false, style: { - pointerEvents: 'none', - display: 'inline-block', - verticalAlign: 'text-top', - width: '0', - maxWidth: '100%', - whiteSpace: 'nowrap', - opacity: '0.333', - } }, leaf.placeholder), - children)); - } - // COMPAT: Having the `data-` attributes on these leaf elements ensures that - // in certain misbehaving browsers they aren't weirdly cloned/destroyed by - // contenteditable behaviors. (2019/05/08) - const attributes = { - 'data-slate-leaf': true, - }; - return renderLeaf({ attributes, children, leaf, text }); -}; -const MemoizedLeaf = React__default.memo(Leaf, (prev, next) => { - return (next.parent === prev.parent && - next.isLast === prev.isLast && - next.renderLeaf === prev.renderLeaf && - next.text === prev.text && - slate.Text.matches(next.leaf, prev.leaf)); -}); -/** - * The default custom leaf renderer. - */ -const DefaultLeaf = (props) => { - const { attributes, children } = props; - return React__default.createElement("span", Object.assign({}, attributes), children); -}; - -/** - * Prevent warning on SSR by falling back to useEffect when window is not defined - */ - -var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect; - -/** - * Text. - */ -const Text = (props) => { - const { decorations, isLast, parent, renderLeaf, text } = props; - const editor = useEditor(); - const ref = React.useRef(null); - const leaves = slate.Text.decorations(text, decorations); - const key = ReactEditor.findKey(editor, text); - const children = []; - for (let i = 0; i < leaves.length; i++) { - const leaf = leaves[i]; - children.push(React__default.createElement(MemoizedLeaf, { isLast: isLast && i === leaves.length - 1, key: `${key.id}-${i}`, leaf: leaf, text: text, parent: parent, renderLeaf: renderLeaf })); - } - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - KEY_TO_ELEMENT.set(key, ref.current); - NODE_TO_ELEMENT.set(text, ref.current); - ELEMENT_TO_NODE.set(ref.current, text); - } - else { - KEY_TO_ELEMENT.delete(key); - NODE_TO_ELEMENT.delete(text); - } - }); - return (React__default.createElement("span", { "data-slate-node": "text", ref: ref }, children)); -}; -const MemoizedText = React__default.memo(Text, (prev, next) => { - return (next.parent === prev.parent && - next.isLast === prev.isLast && - next.renderLeaf === prev.renderLeaf && - next.text === prev.text); -}); - -/** - * A React context for sharing the `selected` state of an element. - */ - -var SelectedContext = React.createContext(false); -/** - * Get the current `selected` state of an element. - */ - -var useSelected = () => { - return React.useContext(SelectedContext); -}; - -/** - * Element. - */ -const Element = (props) => { - const { decorate, decorations, element, renderElement = (p) => React__default.createElement(DefaultElement, Object.assign({}, p)), renderLeaf, selection, elementIndex, } = props; - const ref = React.useRef(null); - const editor = useEditor(); - const readOnly = useReadOnly(); - const isInline = editor.isInline(element); - const key = ReactEditor.findKey(editor, element); - let children = (React__default.createElement(Children, { decorate: decorate, decorations: decorations, node: element, renderElement: renderElement, renderLeaf: renderLeaf, selection: selection })); - // Attributes that the developer must mix into the element in their - // custom node renderer component. - const attributes = { - 'data-slate-node': 'element', - ref, - elementIndex, - }; - if (isInline) { - attributes['data-slate-inline'] = true; - } - // If it's a block node with inline children, add the proper `dir` attribute - // for text direction. - if (!isInline && slate.Editor.hasInlines(editor, element)) { - const text = slate.Node.string(element); - const dir = getDirection(text); - if (dir === 'rtl') { - attributes.dir = dir; - } - } - // If it's a void node, wrap the children in extra void-specific elements. - if (slate.Editor.isVoid(editor, element)) { - attributes['data-slate-void'] = true; - if (!readOnly && isInline) { - attributes.contentEditable = false; - } - const Tag = isInline ? 'span' : 'div'; - const [[text]] = slate.Node.texts(element); - children = readOnly ? null : (React__default.createElement(Tag, { "data-slate-spacer": true, style: { - height: '0', - color: 'transparent', - outline: 'none', - position: 'absolute', - } }, - React__default.createElement(MemoizedText, { decorations: [], isLast: false, parent: element, text: text }))); - NODE_TO_INDEX.set(text, 0); - NODE_TO_PARENT.set(text, element); - } - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - KEY_TO_ELEMENT.set(key, ref.current); - NODE_TO_ELEMENT.set(element, ref.current); - ELEMENT_TO_NODE.set(ref.current, element); - } - else { - KEY_TO_ELEMENT.delete(key); - NODE_TO_ELEMENT.delete(element); - } - }); - return (React__default.createElement(SelectedContext.Provider, { value: !!selection }, renderElement({ attributes, children, element }))); -}; -const MemoizedElement = React__default.memo(Element, (prev, next) => { - return (prev.decorate === next.decorate && - prev.element === next.element && - prev.renderElement === next.renderElement && - prev.renderLeaf === next.renderLeaf && - isRangeListEqual(prev.decorations, next.decorations) && - (prev.selection === next.selection || - (!!prev.selection && - !!next.selection && - slate.Range.equals(prev.selection, next.selection)))); -}); -/** - * The default element renderer. - */ -const DefaultElement = (props) => { - const { attributes, children, element } = props; - const editor = useEditor(); - const Tag = editor.isInline(element) ? 'span' : 'div'; - return (React__default.createElement(Tag, Object.assign({}, attributes, { style: { position: 'relative' } }), children)); -}; -/** - * Check if a list of ranges is equal to another. - * - * PERF: this requires the two lists to also have the ranges inside them in the - * same order, but this is an okay constraint for us since decorations are - * kept in order, and the odd case where they aren't is okay to re-render for. - */ -const isRangeListEqual = (list, another) => { - if (list.length !== another.length) { - return false; - } - for (let i = 0; i < list.length; i++) { - const range = list[i]; - const other = another[i]; - if (!slate.Range.equals(range, other)) { - return false; - } - } - return true; -}; - -/** - * A React context for sharing the editor object. - */ -const EditorContext = React.createContext(null); -/** - * Get the current editor object from the React context. - */ -const useEditor = () => { - const editor = React.useContext(EditorContext); - if (!editor) { - throw new Error(`The \`useEditor\` hook must be used inside the component's context.`); - } - return editor; -}; - -/** - * Children. - */ -const Children = (props) => { - const { decorate, decorations, node, renderElement, renderLeaf, selection, ReactHappyWindow, reactHappyWindowProps = {}, } = props; - const editor = useEditor(); - const path = ReactEditor.findPath(editor, node); - const children = []; - const isLeafBlock = slate.Element.isElement(node) && - !editor.isInline(node) && - slate.Editor.hasInlines(editor, node); - const renderChild = (i) => { - const p = path.concat(i); - const n = node.children[i]; - const key = ReactEditor.findKey(editor, n); - const range = slate.Editor.range(editor, p); - const sel = selection && slate.Range.intersection(range, selection); - // Commented out to improve performance. We don't use decorations - // const ds = decorate([n, p]) - const ds = []; - // for (const dec of decorations) { - // const d = Range.intersection(dec, range) - // if (d) { - // ds.push(d) - // } - // } - NODE_TO_INDEX.set(n, i); - NODE_TO_PARENT.set(n, node); - if (slate.Element.isElement(n)) { - return (React__default.createElement(MemoizedElement, { decorate: decorate, decorations: ds, element: n, key: key.id, renderElement: renderElement, renderLeaf: renderLeaf, selection: sel, elementIndex: i })); - } - else { - return (React__default.createElement(MemoizedText, { decorations: ds, key: key.id, isLast: isLeafBlock && i === node.children.length - 1, parent: node, renderLeaf: renderLeaf, text: n })); - } - }; - if (ReactHappyWindow) { - return (React__default.createElement(ReactHappyWindow, Object.assign({ itemCount: node.children.length, renderItem: renderChild }, reactHappyWindowProps))); - } - for (let i = 0; i < node.children.length; i++) { - children.push(renderChild(i)); - } - return React__default.createElement(React__default.Fragment, null, children); -}; - -var IS_IOS = typeof navigator !== 'undefined' && typeof window !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; -var IS_APPLE = typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent); -var IS_FIREFOX = typeof navigator !== 'undefined' && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); -var IS_SAFARI = typeof navigator !== 'undefined' && /Version\/[\d\.]+.*Safari/.test(navigator.userAgent); - -/** - * Hotkey mappings for each platform. - */ - -var HOTKEYS = { - bold: 'mod+b', - compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'], - moveBackward: 'left', - moveForward: 'right', - moveWordBackward: 'ctrl+left', - moveWordForward: 'ctrl+right', - deleteBackward: 'shift?+backspace', - deleteForward: 'shift?+delete', - extendBackward: 'shift+left', - extendForward: 'shift+right', - italic: 'mod+i', - splitBlock: 'shift?+enter', - undo: 'mod+z' -}; -var APPLE_HOTKEYS = { - moveLineBackward: 'opt+up', - moveLineForward: 'opt+down', - moveWordBackward: 'opt+left', - moveWordForward: 'opt+right', - deleteBackward: ['ctrl+backspace', 'ctrl+h'], - deleteForward: ['ctrl+delete', 'ctrl+d'], - deleteLineBackward: 'cmd+shift?+backspace', - deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'], - deleteWordBackward: 'opt+shift?+backspace', - deleteWordForward: 'opt+shift?+delete', - extendLineBackward: 'opt+shift+up', - extendLineForward: 'opt+shift+down', - redo: 'cmd+shift+z', - transposeCharacter: 'ctrl+t' -}; -var WINDOWS_HOTKEYS = { - deleteWordBackward: 'ctrl+shift?+backspace', - deleteWordForward: 'ctrl+shift?+delete', - redo: ['ctrl+y', 'ctrl+shift+z'] -}; -/** - * Create a platform-aware hotkey checker. - */ - -var create = key => { - var generic = HOTKEYS[key]; - var apple = APPLE_HOTKEYS[key]; - var windows = WINDOWS_HOTKEYS[key]; - var isGeneric = generic && isHotkey.isKeyHotkey(generic); - var isApple = apple && isHotkey.isKeyHotkey(apple); - var isWindows = windows && isHotkey.isKeyHotkey(windows); - return event => { - if (isGeneric && isGeneric(event)) return true; - if (IS_APPLE && isApple && isApple(event)) return true; - if (!IS_APPLE && isWindows && isWindows(event)) return true; - return false; - }; -}; -/** - * Hotkeys. - */ - - -var Hotkeys = { - isBold: create('bold'), - isCompose: create('compose'), - isMoveBackward: create('moveBackward'), - isMoveForward: create('moveForward'), - isDeleteBackward: create('deleteBackward'), - isDeleteForward: create('deleteForward'), - isDeleteLineBackward: create('deleteLineBackward'), - isDeleteLineForward: create('deleteLineForward'), - isDeleteWordBackward: create('deleteWordBackward'), - isDeleteWordForward: create('deleteWordForward'), - isExtendBackward: create('extendBackward'), - isExtendForward: create('extendForward'), - isExtendLineBackward: create('extendLineBackward'), - isExtendLineForward: create('extendLineForward'), - isItalic: create('italic'), - isMoveLineBackward: create('moveLineBackward'), - isMoveLineForward: create('moveLineForward'), - isMoveWordBackward: create('moveWordBackward'), - isMoveWordForward: create('moveWordForward'), - isRedo: create('redo'), - isSplitBlock: create('splitBlock'), - isTransposeCharacter: create('transposeCharacter'), - isUndo: create('undo') -}; - -/** - * A React context for sharing the `readOnly` state of the editor. - */ - -var ReadOnlyContext = React.createContext(false); -/** - * Get the current `readOnly` state of the editor. - */ - -var useReadOnly = () => { - return React.useContext(ReadOnlyContext); -}; - -/** - * A React context for sharing the editor object, in a way that re-renders the - * context whenever changes occur. - */ -const SlateContext = React.createContext(null); -/** - * Get the current editor object from the React context. - */ -const useSlate = () => { - const context = React.useContext(SlateContext); - if (!context) { - throw new Error(`The \`useSlate\` hook must be used inside the component's context.`); - } - const [editor] = context; - return editor; -}; - -/** - * Types. - */ -/** - * Check if a DOM node is a comment node. - */ - -var isDOMComment = value => { - return isDOMNode(value) && value.nodeType === 8; -}; -/** - * Check if a DOM node is an element node. - */ - -var isDOMElement = value => { - return isDOMNode(value) && value.nodeType === 1; -}; -/** - * Check if a value is a DOM node. - */ - -var isDOMNode = value => { - return value instanceof Node; -}; -/** - * Check if a DOM node is an element node. - */ - -var isDOMText = value => { - return isDOMNode(value) && value.nodeType === 3; -}; -/** - * Normalize a DOM point so that it always refers to a text node. - */ - -var normalizeDOMPoint = domPoint => { - var [node, offset] = domPoint; // If it's an element node, its offset refers to the index of its children - // including comment nodes, so try to find the right text child node. - - if (isDOMElement(node) && node.childNodes.length) { - var isLast = offset === node.childNodes.length; - var direction = isLast ? 'backward' : 'forward'; - var index = isLast ? offset - 1 : offset; - node = getEditableChild(node, index, direction); // If the node has children, traverse until we have a leaf node. Leaf nodes - // can be either text nodes, or other void DOM nodes. - - while (isDOMElement(node) && node.childNodes.length) { - var i = isLast ? node.childNodes.length - 1 : 0; - node = getEditableChild(node, i, direction); - } // Determine the new offset inside the text node. - - - offset = isLast && node.textContent != null ? node.textContent.length : 0; - } // Return the node and offset. - - - return [node, offset]; -}; -/** - * Get the nearest editable child at `index` in a `parent`, preferring - * `direction`. - */ - -var getEditableChild = (parent, index, direction) => { - var { - childNodes - } = parent; - var child = childNodes[index]; - var i = index; - var triedForward = false; - var triedBackward = false; // While the child is a comment node, or an element node with no children, - // keep iterating to find a sibling non-void, non-comment node. - - while (isDOMComment(child) || isDOMElement(child) && child.childNodes.length === 0 || isDOMElement(child) && child.getAttribute('contenteditable') === 'false') { - if (triedForward && triedBackward) { - break; - } - - if (i >= childNodes.length) { - triedForward = true; - i = index - 1; - direction = 'backward'; - continue; - } - - if (i < 0) { - triedBackward = true; - i = index + 1; - direction = 'forward'; - continue; - } - - child = childNodes[i]; - i += direction === 'forward' ? 1 : -1; - } - - return child; -}; - -/** - * Editable. - */ -const Editable = (props) => { - const { autoFocus, decorate = defaultDecorate, onDOMBeforeInput: propsOnDOMBeforeInput, placeholder, readOnly = false, renderElement, renderLeaf, style = {}, as: Component = 'div', ReactHappyWindow, reactHappyWindowProps, happyWindowRef, ...attributes } = props; - const editor = useSlate(); - const ref = React.useRef(null); - // Update internal state on each render. - IS_READ_ONLY.set(editor, readOnly); - // Keep track of some state for the event handler logic. - const state = React.useMemo(() => ({ - isComposing: false, - isUpdatingSelection: false, - latestElement: null, - }), []); - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - EDITOR_TO_ELEMENT.set(editor, ref.current); - NODE_TO_ELEMENT.set(editor, ref.current); - ELEMENT_TO_NODE.set(ref.current, editor); - } - else { - NODE_TO_ELEMENT.delete(editor); - } - }); - // Attach a native DOM event handler for `selectionchange`, because React's - // built-in `onSelect` handler doesn't fire for all selection changes. It's a - // leaky polyfill that only fires on keypresses or clicks. Instead, we want to - // fire for any change to the selection inside the editor. (2019/11/04) - // https://github.com/facebook/react/issues/5785 - useIsomorphicLayoutEffect(() => { - window.document.addEventListener('selectionchange', onDOMSelectionChange); - return () => { - window.document.removeEventListener('selectionchange', onDOMSelectionChange); - }; - }, []); - // Attach a native DOM event handler for `beforeinput` events, because React's - // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose - // real `beforeinput` events sadly... (2019/11/04) - // https://github.com/facebook/react/issues/11211 - useIsomorphicLayoutEffect(() => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.addEventListener('beforeinput', onDOMBeforeInput); - } - return () => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.removeEventListener('beforeinput', onDOMBeforeInput); - } - }; - }, []); - // Whenever the editor updates, make sure the DOM selection state is in sync. - useIsomorphicLayoutEffect(() => { - const { selection } = editor; - const domSelection = window.getSelection(); - if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) { - return; - } - const hasDomSelection = domSelection.type !== 'None'; - // If the DOM selection is properly unset, we're done. - if (!selection && !hasDomSelection) { - return; - } - const newDomRange = selection && ReactEditor.toDOMRange(editor, selection); - // If the DOM selection is already correct, we're done. - if (hasDomSelection && - newDomRange && - isRangeEqual(domSelection.getRangeAt(0), newDomRange)) { - return; - } - // Otherwise the DOM selection is out of sync, so update it. - const el = ReactEditor.toDOMNode(editor, editor); - state.isUpdatingSelection = true; - domSelection.removeAllRanges(); - if (newDomRange) { - domSelection.addRange(newDomRange); - const leafEl = newDomRange.startContainer.parentElement; - scrollIntoView(leafEl, { scrollMode: 'if-needed' }); - } - setTimeout(() => { - // COMPAT: In Firefox, it's not enough to create a range, you also need - // to focus the contenteditable element too. (2016/11/16) - if (newDomRange && IS_FIREFOX) { - el.focus(); - } - state.isUpdatingSelection = false; - }); - }); - // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it - // needs to be manually focused. - React.useEffect(() => { - if (ref.current && autoFocus) { - ref.current.focus(); - } - }, [autoFocus]); - // Listen on the native `beforeinput` event to get real "Level 2" events. This - // is required because React's `beforeinput` is fake and never really attaches - // to the real event sadly. (2019/11/01) - // https://github.com/facebook/react/issues/11211 - const onDOMBeforeInput = React.useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isDOMEventHandled(event, propsOnDOMBeforeInput)) { - const { selection } = editor; - const { inputType: type } = event; - const data = event.dataTransfer || event.data || undefined; - // These two types occur while a user is composing text and can't be - // cancelled. Let them through and wait for the composition to end. - if (type === 'insertCompositionText' || - type === 'deleteCompositionText') { - return; - } - event.preventDefault(); - // COMPAT: For the deleting forward/backward input types we don't want - // to change the selection because it is the range that will be deleted, - // and those commands determine that for themselves. - if (!type.startsWith('delete') || type.startsWith('deleteBy')) { - const [targetRange] = event.getTargetRanges(); - if (targetRange) { - const range = ReactEditor.toSlateRange(editor, targetRange); - if (!range) { - return; - } - if (!selection || !slate.Range.equals(selection, range)) { - slate.Transforms.select(editor, range); - } - } - } - // COMPAT: If the selection is expanded, even if the command seems like - // a delete forward/backward command it should delete the selection. - if (selection && - slate.Range.isExpanded(selection) && - type.startsWith('delete')) { - slate.Editor.deleteFragment(editor); - return; - } - switch (type) { - case 'deleteByComposition': - case 'deleteByCut': - case 'deleteByDrag': { - slate.Editor.deleteFragment(editor); - break; - } - case 'deleteContent': - case 'deleteContentForward': { - slate.Editor.deleteForward(editor); - break; - } - case 'deleteContentBackward': { - slate.Editor.deleteBackward(editor); - break; - } - case 'deleteEntireSoftLine': { - slate.Editor.deleteBackward(editor, { unit: 'line' }); - slate.Editor.deleteForward(editor, { unit: 'line' }); - break; - } - case 'deleteHardLineBackward': { - slate.Editor.deleteBackward(editor, { unit: 'block' }); - break; - } - case 'deleteSoftLineBackward': { - slate.Editor.deleteBackward(editor, { unit: 'line' }); - break; - } - case 'deleteHardLineForward': { - slate.Editor.deleteForward(editor, { unit: 'block' }); - break; - } - case 'deleteSoftLineForward': { - slate.Editor.deleteForward(editor, { unit: 'line' }); - break; - } - case 'deleteWordBackward': { - slate.Editor.deleteBackward(editor, { unit: 'word' }); - break; - } - case 'deleteWordForward': { - slate.Editor.deleteForward(editor, { unit: 'word' }); - break; - } - case 'insertLineBreak': - case 'insertParagraph': { - slate.Editor.insertBreak(editor); - break; - } - case 'insertFromComposition': - case 'insertFromDrop': - case 'insertFromPaste': - case 'insertFromYank': - case 'insertReplacementText': - case 'insertText': { - if (data instanceof DataTransfer) { - ReactEditor.insertData(editor, data); - } - else if (typeof data === 'string') { - slate.Editor.insertText(editor, data); - } - break; - } - } - } - }, []); - // Listen on the native `selectionchange` event to be able to update any time - // the selection changes. This is required because React's `onSelect` is leaky - // and non-standard so it doesn't fire until after a selection has been - // released. This causes issues in situations where another change happens - // while a selection is being dragged. - const onDOMSelectionChange = React.useCallback(debounce(() => { - if (!readOnly && !state.isComposing && !state.isUpdatingSelection) { - const { activeElement } = window.document; - const el = ReactEditor.toDOMNode(editor, editor); - const domSelection = window.getSelection(); - const domRange = domSelection && - domSelection.rangeCount > 0 && - domSelection.getRangeAt(0); - if (activeElement === el) { - state.latestElement = activeElement; - IS_FOCUSED.set(editor, true); - } - else { - IS_FOCUSED.delete(editor); - } - if (domRange && - hasEditableTarget(editor, domRange.startContainer) && - hasEditableTarget(editor, domRange.endContainer)) { - const range = ReactEditor.toSlateRange(editor, domRange); - slate.Transforms.select(editor, range); - } - else { - slate.Transforms.deselect(editor); - } - } - }, 100), []); - const decorations = decorate([editor, []]); - if (placeholder && - editor.children.length === 1 && - Array.from(slate.Node.texts(editor)).length === 1 && - slate.Node.string(editor) === '') { - const start = slate.Editor.start(editor, []); - decorations.push({ - [PLACEHOLDER_SYMBOL]: true, - placeholder, - anchor: start, - focus: start, - }); - } - return (React__default.createElement(ReadOnlyContext.Provider, { value: readOnly }, - React__default.createElement(Component - // COMPAT: The Grammarly Chrome extension works by changing the DOM - // out from under `contenteditable` elements, which leads to weird - // behaviors so we have to disable it like editor. (2017/04/24) - , Object.assign({ "data-gramm": false, role: readOnly ? undefined : 'textbox' }, attributes, { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we'd - // have to use hacks to make these replacement-based features work. - spellCheck: IS_FIREFOX ? undefined : attributes.spellCheck, autoCorrect: IS_FIREFOX ? undefined : attributes.autoCorrect, autoCapitalize: IS_FIREFOX ? undefined : attributes.autoCapitalize, "data-slate-editor": true, "data-slate-node": "value", contentEditable: readOnly ? undefined : true, suppressContentEditableWarning: true, ref: ref, style: { - // Prevent the default outline styles. - outline: 'none', - // Preserve adjacent whitespace and new lines. - whiteSpace: 'pre-wrap', - // Allow words to break if they are too long. - wordWrap: 'break-word', - // Allow for passed-in styles to override anything. - ...style, - }, onBeforeInput: React.useCallback((event) => { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to React's leaky polyfill instead just for it. It - // only works for the `insertText` input type. - if (IS_FIREFOX && !readOnly && ReactEditor.isFocused(editor)) { - event.preventDefault(); - const text = event.data; - slate.Editor.insertText(editor, text); - } - }, [readOnly]), onBlur: React.useCallback((event) => { - if (readOnly || - state.isUpdatingSelection || - !hasEditableTarget(editor, event.target) || - isEventHandled(event, attributes.onBlur)) { - return; - } - // COMPAT: If the current `activeElement` is still the previous - // one, this is due to the window being blurred when the tab - // itself becomes unfocused, so we want to abort early to allow to - // editor to stay focused when the tab becomes focused again. - if (state.latestElement === window.document.activeElement) { - return; - } - const { relatedTarget } = event; - const el = ReactEditor.toDOMNode(editor, editor); - // COMPAT: The event should be ignored if the focus is returning - // to the editor from an embedded editable element (eg. an - // element inside a void node). - if (relatedTarget === el) { - return; - } - // COMPAT: The event should be ignored if the focus is moving from - // the editor to inside a void node's spacer element. - if (isDOMElement(relatedTarget) && - relatedTarget.hasAttribute('data-slate-spacer')) { - return; - } - // COMPAT: The event should be ignored if the focus is moving to a - // non- editable section of an element that isn't a void node (eg. - // a list item of the check list example). - if (relatedTarget != null && - isDOMNode(relatedTarget) && - ReactEditor.hasDOMNode(editor, relatedTarget)) { - const node = ReactEditor.toSlateNode(editor, relatedTarget); - if (slate.Element.isElement(node) && !editor.isVoid(node)) { - return; - } - } - IS_FOCUSED.delete(editor); - }, [readOnly, attributes.onBlur]), onClick: React.useCallback((event) => { - if (!readOnly && - hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onClick) && - isDOMNode(event.target)) { - const node = ReactEditor.toSlateNode(editor, event.target); - const path = ReactEditor.findPath(editor, node); - const start = slate.Editor.start(editor, path); - if (slate.Editor.void(editor, { at: start })) { - const range = slate.Editor.range(editor, start); - slate.Transforms.select(editor, range); - } - } - }, [readOnly, attributes.onClick]), onCompositionEnd: React.useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionEnd)) { - state.isComposing = false; - // COMPAT: In Chrome, `beforeinput` events for compositions - // aren't correct and never fire the "insertFromComposition" - // type that we need. So instead, insert whenever a composition - // ends since it will already have been committed to the DOM. - if (!IS_SAFARI && !IS_FIREFOX && event.data) { - slate.Editor.insertText(editor, event.data); - } - } - }, [attributes.onCompositionEnd]), onCompositionStart: React.useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionStart)) { - state.isComposing = true; - } - }, [attributes.onCompositionStart]), onCopy: React.useCallback((event) => { - if (hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCopy)) { - event.preventDefault(); - setFragmentData(event.clipboardData, editor); - } - }, [attributes.onCopy]), onCut: React.useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCut)) { - event.preventDefault(); - setFragmentData(event.clipboardData, editor); - const { selection } = editor; - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - } - }, [readOnly, attributes.onCut]), onDragOver: React.useCallback((event) => { - if (hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragOver)) { - // Only when the target is void, call `preventDefault` to signal - // that drops are allowed. Editable content is droppable by - // default, and calling `preventDefault` hides the cursor. - const node = ReactEditor.toSlateNode(editor, event.target); - if (slate.Editor.isVoid(editor, node)) { - event.preventDefault(); - } - } - }, [attributes.onDragOver]), onDragStart: React.useCallback((event) => { - if (hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragStart)) { - const node = ReactEditor.toSlateNode(editor, event.target); - const path = ReactEditor.findPath(editor, node); - const voidMatch = slate.Editor.void(editor, { at: path }); - // If starting a drag on a void node, make sure it is selected - // so that it shows up in the selection's fragment. - if (voidMatch) { - const range = slate.Editor.range(editor, path); - slate.Transforms.select(editor, range); - } - setFragmentData(event.dataTransfer, editor); - } - }, [attributes.onDragStart]), onDrop: React.useCallback((event) => { - if (hasTarget(editor, event.target) && - !readOnly && - !isEventHandled(event, attributes.onDrop)) { - // COMPAT: Firefox doesn't fire `beforeinput` events at all, and - // Chromium browsers don't properly fire them for files being - // dropped into a `contenteditable`. (2019/11/26) - // https://bugs.chromium.org/p/chromium/issues/detail?id=1028668 - if (IS_FIREFOX || - (!IS_SAFARI && event.dataTransfer.files.length > 0)) { - event.preventDefault(); - const range = ReactEditor.findEventRange(editor, event); - const data = event.dataTransfer; - slate.Transforms.select(editor, range); - ReactEditor.insertData(editor, data); - } - } - }, [readOnly, attributes.onDrop]), onFocus: React.useCallback((event) => { - if (!readOnly && - !state.isUpdatingSelection && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onFocus)) { - const el = ReactEditor.toDOMNode(editor, editor); - state.latestElement = window.document.activeElement; - // COMPAT: If the editor has nested editable elements, the focus - // can go to them. In Firefox, this must be prevented because it - // results in issues with keyboard navigation. (2017/03/30) - if (IS_FIREFOX && event.target !== el) { - el.focus(); - return; - } - IS_FOCUSED.set(editor, true); - } - }, [readOnly, attributes.onFocus]), onKeyDown: React.useCallback((event) => { - if (!readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onKeyDown)) { - const { nativeEvent } = event; - const { selection } = editor; - const element = editor.children[selection !== null ? selection.focus.path[0] : 0]; - const isRTL = getDirection(slate.Node.string(element)) === 'rtl'; - // COMPAT: Since we prevent the default behavior on - // `beforeinput` events, the browser doesn't think there's ever - // any history stack to undo or redo, so we have to manage these - // hotkeys ourselves. (2019/11/06) - if (Hotkeys.isRedo(nativeEvent)) { - event.preventDefault(); - if (editor.redo) { - editor.redo(); - } - return; - } - if (Hotkeys.isUndo(nativeEvent)) { - event.preventDefault(); - if (editor.undo) { - editor.undo(); - } - return; - } - // COMPAT: Certain browsers don't handle the selection updates - // properly. In Chrome, the selection isn't properly extended. - // And in Firefox, the selection isn't properly collapsed. - // (2017/10/17) - if (Hotkeys.isMoveLineBackward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { unit: 'line', reverse: true }); - return; - } - if (Hotkeys.isMoveLineForward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { unit: 'line' }); - return; - } - if (Hotkeys.isExtendLineBackward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { - unit: 'line', - edge: 'focus', - reverse: true, - }); - return; - } - if (Hotkeys.isExtendLineForward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { unit: 'line', edge: 'focus' }); - return; - } - // COMPAT: If a void node is selected, or a zero-width text node - // adjacent to an inline is selected, we need to handle these - // hotkeys manually because browsers won't be able to skip over - // the void node with the zero-width space not being an empty - // string. - if (Hotkeys.isMoveBackward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isCollapsed(selection)) { - const { anchor } = selection; - if (anchor.offset === 1 && anchor.path[1] > 0) { - // Hack to position the cursor at the end of the previous text node - slate.Transforms.move(editor, { reverse: !isRTL, distance: 2 }); - slate.Transforms.move(editor, { reverse: isRTL }); - } - else { - slate.Transforms.move(editor, { reverse: !isRTL }); - } - } - else { - slate.Transforms.collapse(editor, { edge: 'start' }); - } - return; - } - if (Hotkeys.isMoveForward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isCollapsed(selection)) { - slate.Transforms.move(editor, { reverse: isRTL }); - } - else { - slate.Transforms.collapse(editor, { edge: 'end' }); - } - return; - } - if (Hotkeys.isMoveWordBackward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { unit: 'word', reverse: !isRTL }); - return; - } - if (Hotkeys.isMoveWordForward(nativeEvent)) { - event.preventDefault(); - slate.Transforms.move(editor, { unit: 'word', reverse: isRTL }); - return; - } - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to guessing at the input intention for hotkeys. - // COMPAT: In iOS, some of these hotkeys are handled in the - if (IS_FIREFOX) { - // We don't have a core behavior for these, but they change the - // DOM if we don't prevent them, so we have to. - if (Hotkeys.isBold(nativeEvent) || - Hotkeys.isItalic(nativeEvent) || - Hotkeys.isTransposeCharacter(nativeEvent)) { - event.preventDefault(); - return; - } - if (Hotkeys.isSplitBlock(nativeEvent)) { - event.preventDefault(); - slate.Editor.insertBreak(editor); - return; - } - if (Hotkeys.isDeleteBackward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteBackward(editor); - } - return; - } - if (Hotkeys.isDeleteForward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteForward(editor); - } - return; - } - if (Hotkeys.isDeleteLineBackward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteBackward(editor, { unit: 'line' }); - } - return; - } - if (Hotkeys.isDeleteLineForward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteForward(editor, { unit: 'line' }); - } - return; - } - if (Hotkeys.isDeleteWordBackward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteBackward(editor, { unit: 'word' }); - } - return; - } - if (Hotkeys.isDeleteWordForward(nativeEvent)) { - event.preventDefault(); - if (selection && slate.Range.isExpanded(selection)) { - slate.Editor.deleteFragment(editor); - } - else { - slate.Editor.deleteForward(editor, { unit: 'word' }); - } - return; - } - } - } - }, [readOnly, attributes.onKeyDown]), onPaste: React.useCallback((event) => { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to React's `onPaste` here instead. - if (IS_FIREFOX && - !readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onPaste)) { - event.preventDefault(); - ReactEditor.insertData(editor, event.clipboardData); - } - }, [readOnly, attributes.onPaste]) }), - React__default.createElement(Children, { decorate: decorate, decorations: decorations, node: editor, renderElement: renderElement, renderLeaf: renderLeaf, selection: editor.selection, ReactHappyWindow: ReactHappyWindow, reactHappyWindowProps: reactHappyWindowProps })))); -}; -/** - * A default memoized decorate function. - */ -const defaultDecorate = () => []; -/** - * Check if two DOM range objects are equal. - */ -const isRangeEqual = (a, b) => { - return ((a.startContainer === b.startContainer && - a.startOffset === b.startOffset && - a.endContainer === b.endContainer && - a.endOffset === b.endOffset) || - (a.startContainer === b.endContainer && - a.startOffset === b.endOffset && - a.endContainer === b.startContainer && - a.endOffset === b.startOffset)); -}; -/** - * Check if the target is in the editor. - */ -const hasTarget = (editor, target) => { - return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target); -}; -/** - * Check if the target is editable and in the editor. - */ -const hasEditableTarget = (editor, target) => { - return (isDOMNode(target) && - ReactEditor.hasDOMNode(editor, target, { editable: true })); -}; -/** - * Check if an event is overrided by a handler. - */ -const isEventHandled = (event, handler) => { - if (!handler) { - return false; - } - handler(event); - return event.isDefaultPrevented() || event.isPropagationStopped(); -}; -/** - * Check if a DOM event is overrided by a handler. - */ -const isDOMEventHandled = (event, handler) => { - if (!handler) { - return false; - } - handler(event); - return event.defaultPrevented; -}; -/** - * Set the currently selected fragment to the clipboard. - */ -const setFragmentData = (dataTransfer, editor) => { - const { selection } = editor; - if (!selection) { - return; - } - const [start, end] = slate.Range.edges(selection); - const startVoid = slate.Editor.void(editor, { at: start.path }); - const endVoid = slate.Editor.void(editor, { at: end.path }); - if (slate.Range.isCollapsed(selection) && !startVoid) { - return; - } - // Create a fake selection so that we can add a Base64-encoded copy of the - // fragment to the HTML, to decode on future pastes. - const domRange = ReactEditor.toDOMRange(editor, selection); - let contents = domRange.cloneContents(); - let attach = contents.childNodes[0]; - // Make sure attach is non-empty, since empty nodes will not get copied. - contents.childNodes.forEach(node => { - if (node.textContent && node.textContent.trim() !== '') { - attach = node; - } - }); - // COMPAT: If the end node is a void node, we need to move the end of the - // range from the void node's spacer span, to the end of the void node's - // content, since the spacer is before void's content in the DOM. - if (endVoid) { - const [voidNode] = endVoid; - const r = domRange.cloneRange(); - const domNode = ReactEditor.toDOMNode(editor, voidNode); - r.setEndAfter(domNode); - contents = r.cloneContents(); - } - // COMPAT: If the start node is a void node, we need to attach the encoded - // fragment to the void node's content node instead of the spacer, because - // attaching it to empty `
/` nodes will end up having it erased by - // most browsers. (2018/04/27) - if (startVoid) { - attach = contents.querySelector('[data-slate-spacer]'); - } - // Remove any zero-width space spans from the cloned DOM so that they don't - // show up elsewhere when pasted. - Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(zw => { - const isNewline = zw.getAttribute('data-slate-zero-width') === 'n'; - zw.textContent = isNewline ? '\n' : ''; - }); - // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up - // in the HTML, and can be used for intra-Slate pasting. If it's a text - // node, wrap it in a `` so we have something to set an attribute on. - if (isDOMText(attach)) { - const span = document.createElement('span'); - // COMPAT: In Chrome and Safari, if we don't add the `white-space` style - // then leading and trailing spaces will be ignored. (2017/09/21) - span.style.whiteSpace = 'pre'; - span.appendChild(attach); - contents.appendChild(span); - attach = span; - } - const fragment = slate.Node.fragment(editor, selection); - const string = JSON.stringify(fragment); - const encoded = window.btoa(encodeURIComponent(string)); - attach.setAttribute('data-slate-fragment', encoded); - // Overwriting the default functionality - const { getFormattedSelection, getHTMLFormattedSelection } = editor; - if (typeof getFormattedSelection === 'function' && - typeof getHTMLFormattedSelection === 'function') { - try { - const plainText = getFormattedSelection(); - const htmlText = getHTMLFormattedSelection(); - dataTransfer.setData('text/plain', plainText); - dataTransfer.setData('text/html', htmlText); - return; - } - catch (e) { - // eslint-disable-next-line no-console - console.log('Error in slate-react/src/components/editable.tsx: ', e); - // Only setData application/x-slate-fragment as a fallback because - // we don't want to copy the timestamps of words - dataTransfer.setData('application/x-slate-fragment', encoded); - } - } - // Add the content to a
so that we can get its inner HTML. - const div = document.createElement('div'); - div.appendChild(contents); - dataTransfer.setData('text/html', div.innerHTML); - dataTransfer.setData('text/plain', getPlainText(div)); -}; -/** - * Get a plaintext representation of the content of a node, accounting for block - * elements which get a newline appended. - */ -const getPlainText = (domNode) => { - let text = ''; - if (isDOMText(domNode) && domNode.nodeValue) { - return domNode.nodeValue; - } - if (isDOMElement(domNode)) { - for (const childNode of Array.from(domNode.childNodes)) { - text += getPlainText(childNode); - } - const display = getComputedStyle(domNode).getPropertyValue('display'); - if (display === 'block' || display === 'list' || domNode.tagName === 'BR') { - text += '\n'; - } - } - return text; -}; - -/** - * An auto-incrementing identifier for keys. - */ -var n = 0; -/** - * A class that keeps track of a key string. We use a full class here because we - * want to be able to use them as keys in `WeakMap` objects. - */ - -class Key { - constructor() { - this.id = "".concat(n++); - } - -} - -var ReactEditor = { - /** - * Find a key for a Slate node. - */ - findKey(editor, node) { - var key = NODE_TO_KEY.get(node); - - if (!key) { - key = new Key(); - NODE_TO_KEY.set(node, key); - } - - return key; - }, - - /** - * Find the path of Slate node. - */ - findPath(editor, node) { - var path = []; - var child = node; - - while (true) { - var parent = NODE_TO_PARENT.get(child); - - if (parent == null) { - if (slate.Editor.isEditor(child)) { - return path; - } else { - break; - } - } - - var i = NODE_TO_INDEX.get(child); - - if (i == null) { - break; - } - - path.unshift(i); - child = parent; - } - - throw new Error("Unable to find the path for Slate node: ".concat(JSON.stringify(node))); - }, - - /** - * Check if the editor is focused. - */ - isFocused(editor) { - return !!IS_FOCUSED.get(editor); - }, - - /** - * Check if the editor is in read-only mode. - */ - isReadOnly(editor) { - return !!IS_READ_ONLY.get(editor); - }, - - /** - * Blur the editor. - */ - blur(editor) { - var el = ReactEditor.toDOMNode(editor, editor); - IS_FOCUSED.set(editor, false); - - if (window.document.activeElement === el) { - el.blur(); - } - }, - - /** - * Focus the editor. - */ - focus(editor) { - var el = ReactEditor.toDOMNode(editor, editor); - IS_FOCUSED.set(editor, true); - - if (window.document.activeElement !== el) { - el.focus({ - preventScroll: true - }); - } - }, - - /** - * Deselect the editor. - */ - deselect(editor) { - var { - selection - } = editor; - var domSelection = window.getSelection(); - - if (domSelection && domSelection.rangeCount > 0) { - domSelection.removeAllRanges(); - } - - if (selection) { - slate.Transforms.deselect(editor); - } - }, - - /** - * Check if a DOM node is within the editor. - */ - hasDOMNode(editor, target) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var { - editable = false - } = options; - var el = ReactEditor.toDOMNode(editor, editor); - var element; // COMPAT: In Firefox, reading `target.nodeType` will throw an error if - // target is originating from an internal "restricted" element (e.g. a - // stepper arrow on a number input). (2018/05/04) - // https://github.com/ianstormtaylor/slate/issues/1819 - - try { - element = isDOMElement(target) ? target : target.parentElement; - } catch (err) { - if (!err.message.includes('Permission denied to access property "nodeType"')) { - throw err; - } - } - - if (!element) { - return false; - } - - return element.closest("[data-slate-editor]") === el && (!editable || el.isContentEditable); - }, - - /** - * Insert data from a `DataTransfer` into the editor. - */ - insertData(editor, data) { - editor.insertData(data); - }, - - /** - * Find the native DOM element from a Slate node. - */ - toDOMNode(editor, node) { - var domNode = slate.Editor.isEditor(node) ? EDITOR_TO_ELEMENT.get(editor) : KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node)); - - if (!domNode) { - throw new Error("Cannot resolve a DOM node from Slate node: ".concat(JSON.stringify(node))); - } - - return domNode; - }, - - /** - * Find a native DOM selection point from a Slate point. - */ - toDOMPoint(editor, point) { - var [node] = slate.Editor.node(editor, point.path); - var el = ReactEditor.toDOMNode(editor, node); - var domPoint; // If we're inside a void node, force the offset to 0, otherwise the zero - // width spacing character will result in an incorrect offset of 1 - - if (slate.Editor.void(editor, { - at: point - })) { - point = { - path: point.path, - offset: 0 - }; - } // For each leaf, we need to isolate its content, which means filtering - // to its direct text and zero-width spans. (We have to filter out any - // other siblings that may have been rendered alongside them.) - - - var selector = "[data-slate-string], [data-slate-zero-width]"; - var texts = Array.from(el.querySelectorAll(selector)); - var start = 0; - - for (var text of texts) { - var domNode = text.childNodes[0]; - - if (domNode == null || domNode.textContent == null) { - continue; - } - - var { - length - } = domNode.textContent; - var attr = text.getAttribute('data-slate-length'); - var trueLength = attr == null ? length : parseInt(attr, 10); - var end = start + trueLength; - - if (point.offset <= end) { - var offset = Math.min(length, Math.max(0, point.offset - start)); - domPoint = [domNode, offset]; - break; - } - - start = end; - } - - if (!domPoint) { - throw new Error("Cannot resolve a DOM point from Slate point: ".concat(JSON.stringify(point))); - } - - return domPoint; - }, - - /** - * Find a native DOM range from a Slate `range`. - */ - toDOMRange(editor, range) { - var { - anchor, - focus - } = range; - var domAnchor = ReactEditor.toDOMPoint(editor, anchor); - var domFocus = slate.Range.isCollapsed(range) ? domAnchor : ReactEditor.toDOMPoint(editor, focus); - var domRange = window.document.createRange(); - var start = slate.Range.isBackward(range) ? domFocus : domAnchor; - var end = slate.Range.isBackward(range) ? domAnchor : domFocus; - domRange.setStart(start[0], start[1]); - domRange.setEnd(end[0], end[1]); - return domRange; - }, - - /** - * Find a Slate node from a native DOM `element`. - */ - toSlateNode(editor, domNode) { - var domEl = isDOMElement(domNode) ? domNode : domNode.parentElement; - - if (domEl && !domEl.hasAttribute('data-slate-node')) { - domEl = domEl.closest("[data-slate-node]"); - } - - var node = domEl ? ELEMENT_TO_NODE.get(domEl) : null; - - if (!node) { - throw new Error("Cannot resolve a Slate node from DOM node: ".concat(domEl)); - } - - return node; - }, - - /** - * Get the target range from a DOM `event`. - */ - findEventRange(editor, event) { - if ('nativeEvent' in event) { - event = event.nativeEvent; - } - - var { - clientX: x, - clientY: y, - target - } = event; - - if (x == null || y == null) { - throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event)); - } - - var node = ReactEditor.toSlateNode(editor, event.target); - var path = ReactEditor.findPath(editor, node); // If the drop target is inside a void node, move it into either the - // next or previous node, depending on which side the `x` and `y` - // coordinates are closest to. - - if (slate.Editor.isVoid(editor, node)) { - var rect = target.getBoundingClientRect(); - var isPrev = editor.isInline(node) ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y; - var edge = slate.Editor.point(editor, path, { - edge: isPrev ? 'start' : 'end' - }); - var point = isPrev ? slate.Editor.before(editor, edge) : slate.Editor.after(editor, edge); - - if (point) { - var _range = slate.Editor.range(editor, point); - - return _range; - } - } // Else resolve a range from the caret position where the drop occured. - - - var domRange; - var { - document - } = window; // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25) - - if (document.caretRangeFromPoint) { - domRange = document.caretRangeFromPoint(x, y); - } else { - var position = document.caretPositionFromPoint(x, y); - - if (position) { - domRange = document.createRange(); - domRange.setStart(position.offsetNode, position.offset); - domRange.setEnd(position.offsetNode, position.offset); - } - } - - if (!domRange) { - throw new Error("Cannot resolve a Slate range from a DOM event: ".concat(event)); - } // Resolve a Slate range from the DOM range. - - - var range = ReactEditor.toSlateRange(editor, domRange); - return range; - }, - - /** - * Find a Slate point from a DOM selection's `domNode` and `domOffset`. - */ - toSlatePoint(editor, domPoint) { - var [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint); - var parentNode = nearestNode.parentNode; - var textNode = null; - var offset = 0; - - if (parentNode) { - var voidNode = parentNode.closest('[data-slate-void="true"]'); - var leafNode = parentNode.closest('[data-slate-leaf]'); - var domNode = null; // Calculate how far into the text node the `nearestNode` is, so that we - // can determine what the offset relative to the text node is. - - if (leafNode) { - textNode = leafNode.closest('[data-slate-node="text"]'); - var range = window.document.createRange(); - range.setStart(textNode, 0); - range.setEnd(nearestNode, nearestOffset); - var contents = range.cloneContents(); - var removals = [...contents.querySelectorAll('[data-slate-zero-width]'), ...contents.querySelectorAll('[contenteditable=false]')]; - removals.forEach(el => { - el.parentNode.removeChild(el); - }); // COMPAT: Edge has a bug where Range.prototype.toString() will - // convert \n into \r\n. The bug causes a loop when slate-react - // attempts to reposition its cursor to match the native position. Use - // textContent.length instead. - // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/ - - offset = contents.textContent.length; - domNode = textNode; - } else if (voidNode) { - // For void nodes, the element with the offset key will be a cousin, not an - // ancestor, so find it by going down from the nearest void parent. - leafNode = voidNode.querySelector('[data-slate-leaf]'); - textNode = leafNode.closest('[data-slate-node="text"]'); - domNode = leafNode; - offset = domNode.textContent.length; - } // COMPAT: If the parent node is a Slate zero-width space, editor is - // because the text node should have no characters. However, during IME - // composition the ASCII characters will be prepended to the zero-width - // space, so subtract 1 from the offset to account for the zero-width - // space character. - - - if (domNode && offset === domNode.textContent.length && parentNode.hasAttribute('data-slate-zero-width')) { - offset--; - } - } - - if (!textNode) { - throw new Error("Cannot resolve a Slate point from DOM point: ".concat(domPoint)); - } // COMPAT: If someone is clicking from one Slate editor into another, - // the select event fires twice, once for the old editor's `element` - // first, and then afterwards for the correct `element`. (2017/03/03) - - - var slateNode = ReactEditor.toSlateNode(editor, textNode); - var path = ReactEditor.findPath(editor, slateNode); - return { - path, - offset - }; - }, - - /** - * Find a Slate range from a DOM range or selection. - */ - toSlateRange(editor, domRange) { - var el = domRange instanceof Selection ? domRange.anchorNode : domRange.startContainer; - var anchorNode; - var anchorOffset; - var focusNode; - var focusOffset; - var isCollapsed; - - if (el) { - if (domRange instanceof Selection) { - anchorNode = domRange.anchorNode; - anchorOffset = domRange.anchorOffset; - focusNode = domRange.focusNode; - focusOffset = domRange.focusOffset; - isCollapsed = domRange.isCollapsed; - } else { - anchorNode = domRange.startContainer; - anchorOffset = domRange.startOffset; - focusNode = domRange.endContainer; - focusOffset = domRange.endOffset; - isCollapsed = domRange.collapsed; - } - } - - if (anchorNode == null || focusNode == null || anchorOffset == null || focusOffset == null) { - throw new Error("Cannot resolve a Slate range from DOM range: ".concat(domRange)); - } - - var anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset]); - var focus = isCollapsed ? anchor : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset]); - return { - anchor, - focus - }; - } - -}; - -/** - * A React context for sharing the `focused` state of the editor. - */ - -var FocusedContext = React.createContext(false); -/** - * Get the current `focused` state of the editor. - */ - -var useFocused = () => { - return React.useContext(FocusedContext); -}; - -/** - * A wrapper around the provider to handle `onChange` events, because the editor - * is a mutable singleton so it won't ever register as "changed" otherwise. - */ -const Slate = (props) => { - const { editor, children, onChange, value, ...rest } = props; - const [key, setKey] = React.useState(0); - const context = React.useMemo(() => { - editor.children = value; - Object.assign(editor, rest); - return [editor]; - }, [key, value, ...Object.values(rest)]); - const onContextChange = React.useCallback(() => { - onChange(editor.children); - setKey(key + 1); - }, [key, onChange]); - EDITOR_TO_ON_CHANGE.set(editor, onContextChange); - return (React__default.createElement(SlateContext.Provider, { value: context }, - React__default.createElement(EditorContext.Provider, { value: editor }, - React__default.createElement(FocusedContext.Provider, { value: ReactEditor.isFocused(editor) }, children)))); -}; - -/** - * `withReact` adds React and DOM specific behaviors to the editor. - */ - -var withReact = editor => { - var e = editor; - var { - apply, - onChange - } = e; - - e.apply = op => { - var matches = []; - - switch (op.type) { - case 'insert_text': - case 'remove_text': - case 'set_node': - { - for (var [node, path] of slate.Editor.levels(e, { - at: op.path - })) { - var key = ReactEditor.findKey(e, node); - matches.push([path, key]); - } - - break; - } - - case 'insert_node': - case 'remove_node': - case 'merge_node': - case 'split_node': - { - for (var [_node, _path] of slate.Editor.levels(e, { - at: slate.Path.parent(op.path) - })) { - var _key = ReactEditor.findKey(e, _node); - - matches.push([_path, _key]); - } - - break; - } - } - - apply(op); - - for (var [_path2, _key2] of matches) { - var [_node2] = slate.Editor.node(e, _path2); - NODE_TO_KEY.set(_node2, _key2); - } - }; - - e.insertData = data => { - var fragment = data.getData('application/x-slate-fragment'); - - if (fragment) { - var decoded = decodeURIComponent(window.atob(fragment)); - var parsed = JSON.parse(decoded); - slate.Transforms.insertFragment(e, parsed); - return; - } - - var text = data.getData('text/plain'); - - if (text) { - var lines = text.split('\n'); - var split = false; - - for (var line of lines) { - if (split) { - slate.Transforms.splitNodes(e); - } - - slate.Transforms.insertText(e, line); - split = true; - } - } - }; - - e.onChange = () => { - // COMPAT: React doesn't batch `setState` hook calls, which means that the - // children and selection can get out of sync for one render pass. So we - // have to use this unstable API to ensure it batches them. (2019/12/03) - // https://github.com/facebook/react/issues/14259#issuecomment-439702367 - ReactDOM.unstable_batchedUpdates(() => { - var onContextChange = EDITOR_TO_ON_CHANGE.get(e); - - if (onContextChange) { - onContextChange(); - } - - onChange(); - }); - }; - - return e; -}; - -exports.DefaultElement = DefaultElement; -exports.DefaultLeaf = DefaultLeaf; -exports.Editable = Editable; -exports.ReactEditor = ReactEditor; -exports.Slate = Slate; -exports.useEditor = useEditor; -exports.useFocused = useFocused; -exports.useReadOnly = useReadOnly; -exports.useSelected = useSelected; -exports.useSlate = useSlate; -exports.withReact = withReact; -//# sourceMappingURL=index.js.map diff --git a/dist/index.js.map b/dist/index.js.map deleted file mode 100644 index 5f9ff05..0000000 --- a/dist/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sources":["../src/components/string.tsx","../src/utils/weak-maps.ts","../src/components/leaf.tsx","../src/hooks/use-isomorphic-layout-effect.ts","../src/components/text.tsx","../src/hooks/use-selected.ts","../src/components/element.tsx","../src/hooks/use-editor.tsx","../src/components/children.tsx","../src/utils/environment.ts","../src/utils/hotkeys.ts","../src/hooks/use-read-only.ts","../src/hooks/use-slate.tsx","../src/utils/dom.ts","../src/components/editable.tsx","../src/utils/key.ts","../src/plugin/react-editor.ts","../src/hooks/use-focused.ts","../src/components/slate.tsx","../src/plugin/with-react.ts"],"sourcesContent":["import React from 'react'\nimport { Editor, Text, Path, Element, Node } from 'slate'\n\nimport { ReactEditor, useEditor } from '..'\n\n/**\n * Leaf content strings.\n */\n\nconst String = (props: {\n isLast: boolean\n leaf: Text\n parent: Element\n text: Text\n}) => {\n const { isLast, leaf, parent, text } = props\n const editor = useEditor()\n const path = ReactEditor.findPath(editor, text)\n const parentPath = Path.parent(path)\n\n // COMPAT: Render text inside void nodes with a zero-width space.\n // So the node can contain selection but the text is not visible.\n if (editor.isVoid(parent)) {\n return \n }\n\n // COMPAT: If this is the last text node in an empty block, render a zero-\n // width space that will convert into a line break when copying and pasting\n // to support expected plain text.\n if (\n leaf.text === '' &&\n parent.children[parent.children.length - 1] === text &&\n !editor.isInline(parent) &&\n Editor.string(editor, parentPath) === ''\n ) {\n return \n }\n\n // COMPAT: If the text is empty, it's because it's on the edge of an inline\n // node, so we render a zero-width space so that the selection can be\n // inserted next to it still.\n if (leaf.text === '') {\n return \n }\n\n // COMPAT: Browsers will collapse trailing new lines at the end of blocks,\n // so we need to add an extra trailing new lines to prevent that.\n if (isLast && leaf.text.slice(-1) === '\\n') {\n return \n }\n\n return \n}\n\n/**\n * Leaf strings with text in them.\n */\n\nconst TextString = (props: { text: string; isTrailing?: boolean }) => {\n const { text, isTrailing = false } = props\n return (\n \n {text}\n {isTrailing ? '\\n' : null}\n \n )\n}\n\n/**\n * Leaf strings without text, render as zero-width strings.\n */\n\nconst ZeroWidthString = (props: { length?: number; isLineBreak?: boolean }) => {\n const { length = 0, isLineBreak = false } = props\n return (\n \n {'\\uFEFF'}\n {isLineBreak ?
: null}\n \n )\n}\n\nexport default String\n","import { Node, Ancestor, Editor, Range } from 'slate'\n\nimport { Key } from './key'\n\n/**\n * Two weak maps that allow us rebuild a path given a node. They are populated\n * at render time such that after a render occurs we can always backtrack.\n */\n\nexport const NODE_TO_INDEX: WeakMap = new WeakMap()\nexport const NODE_TO_PARENT: WeakMap = new WeakMap()\n\n/**\n * Weak maps that allow us to go between Slate nodes and DOM nodes. These\n * are used to resolve DOM event-related logic into Slate actions.\n */\n\nexport const EDITOR_TO_ELEMENT: WeakMap = new WeakMap()\nexport const EDITOR_TO_PLACEHOLDER: WeakMap = new WeakMap()\nexport const ELEMENT_TO_NODE: WeakMap = new WeakMap()\nexport const KEY_TO_ELEMENT: WeakMap = new WeakMap()\nexport const NODE_TO_ELEMENT: WeakMap = new WeakMap()\nexport const NODE_TO_KEY: WeakMap = new WeakMap()\n\n/**\n * Weak maps for storing editor-related state.\n */\n\nexport const IS_READ_ONLY: WeakMap = new WeakMap()\nexport const IS_FOCUSED: WeakMap = new WeakMap()\nexport const IS_DRAGGING: WeakMap = new WeakMap()\nexport const IS_CLICKING: WeakMap = new WeakMap()\n\n/**\n * Weak map for associating the context `onChange` context with the plugin.\n */\n\nexport const EDITOR_TO_ON_CHANGE = new WeakMap void>()\n\n/**\n * Symbols.\n */\n\nexport const PLACEHOLDER_SYMBOL = (Symbol('placeholder') as unknown) as string\n","import React from 'react'\nimport { Text, Element } from 'slate'\n\nimport String from './string'\nimport { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'\nimport { RenderLeafProps } from './editable'\n\n/**\n * Individual leaves in a text node with unique formatting.\n */\n\nconst Leaf = (props: {\n isLast: boolean\n leaf: Text\n parent: Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n text: Text\n}) => {\n const {\n leaf,\n isLast,\n text,\n parent,\n renderLeaf = (props: RenderLeafProps) => ,\n } = props\n\n let children = (\n \n )\n\n if (leaf[PLACEHOLDER_SYMBOL]) {\n children = (\n \n \n {leaf.placeholder}\n \n {children}\n \n )\n }\n\n // COMPAT: Having the `data-` attributes on these leaf elements ensures that\n // in certain misbehaving browsers they aren't weirdly cloned/destroyed by\n // contenteditable behaviors. (2019/05/08)\n const attributes: {\n 'data-slate-leaf': true\n } = {\n 'data-slate-leaf': true,\n }\n\n return renderLeaf({ attributes, children, leaf, text })\n}\n\nconst MemoizedLeaf = React.memo(Leaf, (prev, next) => {\n return (\n next.parent === prev.parent &&\n next.isLast === prev.isLast &&\n next.renderLeaf === prev.renderLeaf &&\n next.text === prev.text &&\n Text.matches(next.leaf, prev.leaf)\n )\n})\n\n/**\n * The default custom leaf renderer.\n */\n\nexport const DefaultLeaf = (props: RenderLeafProps) => {\n const { attributes, children } = props\n return {children}\n}\n\nexport default MemoizedLeaf\n","import { useLayoutEffect, useEffect } from 'react'\n\n/**\n * Prevent warning on SSR by falling back to useEffect when window is not defined\n */\nexport const useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect\n","import React, { useRef } from 'react'\nimport { Range, Element, Text as SlateText } from 'slate'\n\nimport Leaf from './leaf'\nimport { ReactEditor, useEditor } from '..'\nimport { RenderLeafProps } from './editable'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n KEY_TO_ELEMENT,\n NODE_TO_ELEMENT,\n ELEMENT_TO_NODE,\n} from '../utils/weak-maps'\n\n/**\n * Text.\n */\n\nconst Text = (props: {\n decorations: Range[]\n isLast: boolean\n parent: Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n text: SlateText\n}) => {\n const { decorations, isLast, parent, renderLeaf, text } = props\n const editor = useEditor()\n const ref = useRef(null)\n const leaves = SlateText.decorations(text, decorations)\n const key = ReactEditor.findKey(editor, text)\n const children = []\n\n for (let i = 0; i < leaves.length; i++) {\n const leaf = leaves[i]\n\n children.push(\n \n )\n }\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n KEY_TO_ELEMENT.set(key, ref.current)\n NODE_TO_ELEMENT.set(text, ref.current)\n ELEMENT_TO_NODE.set(ref.current, text)\n } else {\n KEY_TO_ELEMENT.delete(key)\n NODE_TO_ELEMENT.delete(text)\n }\n })\n\n return (\n \n {children}\n \n )\n}\n\nconst MemoizedText = React.memo(Text, (prev, next) => {\n return (\n next.parent === prev.parent &&\n next.isLast === prev.isLast &&\n next.renderLeaf === prev.renderLeaf &&\n next.text === prev.text\n )\n})\n\nexport default MemoizedText\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `selected` state of an element.\n */\n\nexport const SelectedContext = createContext(false)\n\n/**\n * Get the current `selected` state of an element.\n */\n\nexport const useSelected = (): boolean => {\n return useContext(SelectedContext)\n}\n","import React, { useRef } from 'react'\nimport getDirection from 'direction'\nimport { Editor, Node, Range, NodeEntry, Element as SlateElement } from 'slate'\n\nimport Text from './text'\nimport Children from './children'\nimport { ReactEditor, useEditor, useReadOnly } from '..'\nimport { SelectedContext } from '../hooks/use-selected'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n NODE_TO_ELEMENT,\n ELEMENT_TO_NODE,\n NODE_TO_PARENT,\n NODE_TO_INDEX,\n KEY_TO_ELEMENT,\n} from '../utils/weak-maps'\nimport { RenderElementProps, RenderLeafProps } from './editable'\n\n/**\n * Element.\n */\n\nconst Element = (props: {\n decorate: (entry: NodeEntry) => Range[]\n decorations: Range[]\n element: SlateElement\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n selection: Range | null\n elementIndex: Number\n}) => {\n const {\n decorate,\n decorations,\n element,\n renderElement = (p: RenderElementProps) => ,\n renderLeaf,\n selection,\n elementIndex,\n } = props\n const ref = useRef(null)\n const editor = useEditor()\n const readOnly = useReadOnly()\n const isInline = editor.isInline(element)\n const key = ReactEditor.findKey(editor, element)\n\n let children: JSX.Element | null = (\n \n )\n\n // Attributes that the developer must mix into the element in their\n // custom node renderer component.\n const attributes: {\n 'data-slate-node': 'element'\n 'data-slate-void'?: true\n 'data-slate-inline'?: true\n contentEditable?: false\n dir?: 'rtl'\n ref: any\n elementIndex: Number\n } = {\n 'data-slate-node': 'element',\n ref,\n elementIndex,\n }\n\n if (isInline) {\n attributes['data-slate-inline'] = true\n }\n\n // If it's a block node with inline children, add the proper `dir` attribute\n // for text direction.\n if (!isInline && Editor.hasInlines(editor, element)) {\n const text = Node.string(element)\n const dir = getDirection(text)\n\n if (dir === 'rtl') {\n attributes.dir = dir\n }\n }\n\n // If it's a void node, wrap the children in extra void-specific elements.\n if (Editor.isVoid(editor, element)) {\n attributes['data-slate-void'] = true\n\n if (!readOnly && isInline) {\n attributes.contentEditable = false\n }\n\n const Tag = isInline ? 'span' : 'div'\n const [[text]] = Node.texts(element)\n\n children = readOnly ? null : (\n \n \n \n )\n\n NODE_TO_INDEX.set(text, 0)\n NODE_TO_PARENT.set(text, element)\n }\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n KEY_TO_ELEMENT.set(key, ref.current)\n NODE_TO_ELEMENT.set(element, ref.current)\n ELEMENT_TO_NODE.set(ref.current, element)\n } else {\n KEY_TO_ELEMENT.delete(key)\n NODE_TO_ELEMENT.delete(element)\n }\n })\n\n return (\n \n {renderElement({ attributes, children, element })}\n \n )\n}\n\nconst MemoizedElement = React.memo(Element, (prev, next) => {\n return (\n prev.decorate === next.decorate &&\n prev.element === next.element &&\n prev.renderElement === next.renderElement &&\n prev.renderLeaf === next.renderLeaf &&\n isRangeListEqual(prev.decorations, next.decorations) &&\n (prev.selection === next.selection ||\n (!!prev.selection &&\n !!next.selection &&\n Range.equals(prev.selection, next.selection)))\n )\n})\n\n/**\n * The default element renderer.\n */\n\nexport const DefaultElement = (props: RenderElementProps) => {\n const { attributes, children, element } = props\n const editor = useEditor()\n const Tag = editor.isInline(element) ? 'span' : 'div'\n return (\n \n {children}\n \n )\n}\n\n/**\n * Check if a list of ranges is equal to another.\n *\n * PERF: this requires the two lists to also have the ranges inside them in the\n * same order, but this is an okay constraint for us since decorations are\n * kept in order, and the odd case where they aren't is okay to re-render for.\n */\n\nconst isRangeListEqual = (list: Range[], another: Range[]): boolean => {\n if (list.length !== another.length) {\n return false\n }\n\n for (let i = 0; i < list.length; i++) {\n const range = list[i]\n const other = another[i]\n\n if (!Range.equals(range, other)) {\n return false\n }\n }\n\n return true\n}\n\nexport default MemoizedElement\n","import { createContext, useContext } from 'react'\n\nimport { ReactEditor } from '../plugin/react-editor'\n\n/**\n * A React context for sharing the editor object.\n */\n\nexport const EditorContext = createContext(null)\n\n/**\n * Get the current editor object from the React context.\n */\n\nexport const useEditor = () => {\n const editor = useContext(EditorContext)\n\n if (!editor) {\n throw new Error(\n `The \\`useEditor\\` hook must be used inside the component's context.`\n )\n }\n\n return editor\n}\n","import React from 'react'\nimport { Editor, Range, Element, NodeEntry, Ancestor, Descendant } from 'slate'\n\nimport ElementComponent from './element'\nimport TextComponent from './text'\nimport { ReactEditor } from '..'\nimport { useEditor } from '../hooks/use-editor'\nimport { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps'\nimport { RenderElementProps, RenderLeafProps } from './editable'\n\n/**\n * Children.\n */\n\nconst Children = (props: {\n decorate: (entry: NodeEntry) => Range[]\n decorations: Range[]\n node: Ancestor\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n selection: Range | null\n ReactHappyWindow: React.Component | undefined\n reactHappyWindowProps: Object | undefined\n}) => {\n const {\n decorate,\n decorations,\n node,\n renderElement,\n renderLeaf,\n selection,\n ReactHappyWindow,\n reactHappyWindowProps = {},\n } = props\n const editor = useEditor()\n const path = ReactEditor.findPath(editor, node)\n const children = []\n const isLeafBlock =\n Element.isElement(node) &&\n !editor.isInline(node) &&\n Editor.hasInlines(editor, node)\n\n const renderChild = (i: number) => {\n const p = path.concat(i)\n const n = node.children[i] as Descendant\n const key = ReactEditor.findKey(editor, n)\n const range = Editor.range(editor, p)\n const sel = selection && Range.intersection(range, selection)\n\n // Commented out to improve performance. We don't use decorations\n // const ds = decorate([n, p])\n const ds = [] as Range[]\n // for (const dec of decorations) {\n // const d = Range.intersection(dec, range)\n\n // if (d) {\n // ds.push(d)\n // }\n // }\n\n NODE_TO_INDEX.set(n, i)\n NODE_TO_PARENT.set(n, node)\n\n if (Element.isElement(n)) {\n return (\n \n )\n } else {\n return (\n \n )\n }\n }\n\n if (ReactHappyWindow) {\n return (\n \n )\n }\n\n for (let i = 0; i < node.children.length; i++) {\n children.push(renderChild(i))\n }\n\n return {children}\n}\n\nexport default Children\n","export const IS_IOS =\n typeof navigator !== 'undefined' &&\n typeof window !== 'undefined' &&\n /iPad|iPhone|iPod/.test(navigator.userAgent) &&\n !window.MSStream\n\nexport const IS_APPLE =\n typeof navigator !== 'undefined' && /Mac OS X/.test(navigator.userAgent)\n\nexport const IS_FIREFOX =\n typeof navigator !== 'undefined' &&\n /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent)\n\nexport const IS_SAFARI =\n typeof navigator !== 'undefined' &&\n /Version\\/[\\d\\.]+.*Safari/.test(navigator.userAgent)\n","import { isKeyHotkey } from 'is-hotkey'\nimport { IS_APPLE } from './environment'\n\n/**\n * Hotkey mappings for each platform.\n */\n\nconst HOTKEYS = {\n bold: 'mod+b',\n compose: ['down', 'left', 'right', 'up', 'backspace', 'enter'],\n moveBackward: 'left',\n moveForward: 'right',\n moveWordBackward: 'ctrl+left',\n moveWordForward: 'ctrl+right',\n deleteBackward: 'shift?+backspace',\n deleteForward: 'shift?+delete',\n extendBackward: 'shift+left',\n extendForward: 'shift+right',\n italic: 'mod+i',\n splitBlock: 'shift?+enter',\n undo: 'mod+z',\n}\n\nconst APPLE_HOTKEYS = {\n moveLineBackward: 'opt+up',\n moveLineForward: 'opt+down',\n moveWordBackward: 'opt+left',\n moveWordForward: 'opt+right',\n deleteBackward: ['ctrl+backspace', 'ctrl+h'],\n deleteForward: ['ctrl+delete', 'ctrl+d'],\n deleteLineBackward: 'cmd+shift?+backspace',\n deleteLineForward: ['cmd+shift?+delete', 'ctrl+k'],\n deleteWordBackward: 'opt+shift?+backspace',\n deleteWordForward: 'opt+shift?+delete',\n extendLineBackward: 'opt+shift+up',\n extendLineForward: 'opt+shift+down',\n redo: 'cmd+shift+z',\n transposeCharacter: 'ctrl+t',\n}\n\nconst WINDOWS_HOTKEYS = {\n deleteWordBackward: 'ctrl+shift?+backspace',\n deleteWordForward: 'ctrl+shift?+delete',\n redo: ['ctrl+y', 'ctrl+shift+z'],\n}\n\n/**\n * Create a platform-aware hotkey checker.\n */\n\nconst create = (key: string) => {\n const generic = HOTKEYS[key]\n const apple = APPLE_HOTKEYS[key]\n const windows = WINDOWS_HOTKEYS[key]\n const isGeneric = generic && isKeyHotkey(generic)\n const isApple = apple && isKeyHotkey(apple)\n const isWindows = windows && isKeyHotkey(windows)\n\n return (event: KeyboardEvent) => {\n if (isGeneric && isGeneric(event)) return true\n if (IS_APPLE && isApple && isApple(event)) return true\n if (!IS_APPLE && isWindows && isWindows(event)) return true\n return false\n }\n}\n\n/**\n * Hotkeys.\n */\n\nexport default {\n isBold: create('bold'),\n isCompose: create('compose'),\n isMoveBackward: create('moveBackward'),\n isMoveForward: create('moveForward'),\n isDeleteBackward: create('deleteBackward'),\n isDeleteForward: create('deleteForward'),\n isDeleteLineBackward: create('deleteLineBackward'),\n isDeleteLineForward: create('deleteLineForward'),\n isDeleteWordBackward: create('deleteWordBackward'),\n isDeleteWordForward: create('deleteWordForward'),\n isExtendBackward: create('extendBackward'),\n isExtendForward: create('extendForward'),\n isExtendLineBackward: create('extendLineBackward'),\n isExtendLineForward: create('extendLineForward'),\n isItalic: create('italic'),\n isMoveLineBackward: create('moveLineBackward'),\n isMoveLineForward: create('moveLineForward'),\n isMoveWordBackward: create('moveWordBackward'),\n isMoveWordForward: create('moveWordForward'),\n isRedo: create('redo'),\n isSplitBlock: create('splitBlock'),\n isTransposeCharacter: create('transposeCharacter'),\n isUndo: create('undo'),\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `readOnly` state of the editor.\n */\n\nexport const ReadOnlyContext = createContext(false)\n\n/**\n * Get the current `readOnly` state of the editor.\n */\n\nexport const useReadOnly = (): boolean => {\n return useContext(ReadOnlyContext)\n}\n","import { createContext, useContext } from 'react'\n\nimport { ReactEditor } from '../plugin/react-editor'\n\n/**\n * A React context for sharing the editor object, in a way that re-renders the\n * context whenever changes occur.\n */\n\nexport const SlateContext = createContext<[ReactEditor] | null>(null)\n\n/**\n * Get the current editor object from the React context.\n */\n\nexport const useSlate = () => {\n const context = useContext(SlateContext)\n\n if (!context) {\n throw new Error(\n `The \\`useSlate\\` hook must be used inside the component's context.`\n )\n }\n\n const [editor] = context\n return editor\n}\n","/**\n * Types.\n */\n\n// COMPAT: This is required to prevent TypeScript aliases from doing some very\n// weird things for Slate's types with the same name as globals. (2019/11/27)\n// https://github.com/microsoft/TypeScript/issues/35002\nimport DOMNode = globalThis.Node\nimport DOMComment = globalThis.Comment\nimport DOMElement = globalThis.Element\nimport DOMText = globalThis.Text\nimport DOMRange = globalThis.Range\nimport DOMSelection = globalThis.Selection\nimport DOMStaticRange = globalThis.StaticRange\nexport {\n DOMNode,\n DOMComment,\n DOMElement,\n DOMText,\n DOMRange,\n DOMSelection,\n DOMStaticRange,\n}\n\nexport type DOMPoint = [Node, number]\n\n/**\n * Check if a DOM node is a comment node.\n */\n\nexport const isDOMComment = (value: any): value is DOMComment => {\n return isDOMNode(value) && value.nodeType === 8\n}\n\n/**\n * Check if a DOM node is an element node.\n */\n\nexport const isDOMElement = (value: any): value is DOMElement => {\n return isDOMNode(value) && value.nodeType === 1\n}\n\n/**\n * Check if a value is a DOM node.\n */\n\nexport const isDOMNode = (value: any): value is DOMNode => {\n return value instanceof Node\n}\n\n/**\n * Check if a DOM node is an element node.\n */\n\nexport const isDOMText = (value: any): value is DOMText => {\n return isDOMNode(value) && value.nodeType === 3\n}\n\n/**\n * Normalize a DOM point so that it always refers to a text node.\n */\n\nexport const normalizeDOMPoint = (domPoint: DOMPoint): DOMPoint => {\n let [node, offset] = domPoint\n\n // If it's an element node, its offset refers to the index of its children\n // including comment nodes, so try to find the right text child node.\n if (isDOMElement(node) && node.childNodes.length) {\n const isLast = offset === node.childNodes.length\n const direction = isLast ? 'backward' : 'forward'\n const index = isLast ? offset - 1 : offset\n node = getEditableChild(node, index, direction)\n\n // If the node has children, traverse until we have a leaf node. Leaf nodes\n // can be either text nodes, or other void DOM nodes.\n while (isDOMElement(node) && node.childNodes.length) {\n const i = isLast ? node.childNodes.length - 1 : 0\n node = getEditableChild(node, i, direction)\n }\n\n // Determine the new offset inside the text node.\n offset = isLast && node.textContent != null ? node.textContent.length : 0\n }\n\n // Return the node and offset.\n return [node, offset]\n}\n\n/**\n * Get the nearest editable child at `index` in a `parent`, preferring\n * `direction`.\n */\n\nexport const getEditableChild = (\n parent: DOMElement,\n index: number,\n direction: 'forward' | 'backward'\n): DOMNode => {\n const { childNodes } = parent\n let child = childNodes[index]\n let i = index\n let triedForward = false\n let triedBackward = false\n\n // While the child is a comment node, or an element node with no children,\n // keep iterating to find a sibling non-void, non-comment node.\n while (\n isDOMComment(child) ||\n (isDOMElement(child) && child.childNodes.length === 0) ||\n (isDOMElement(child) && child.getAttribute('contenteditable') === 'false')\n ) {\n if (triedForward && triedBackward) {\n break\n }\n\n if (i >= childNodes.length) {\n triedForward = true\n i = index - 1\n direction = 'backward'\n continue\n }\n\n if (i < 0) {\n triedBackward = true\n i = index + 1\n direction = 'forward'\n continue\n }\n\n child = childNodes[i]\n i += direction === 'forward' ? 1 : -1\n }\n\n return child\n}\n","import React, { useEffect, useRef, useMemo, useCallback } from 'react'\nimport {\n Editor,\n Element,\n NodeEntry,\n Node,\n Range,\n Text,\n Transforms,\n} from 'slate'\nimport getDirection from 'direction'\nimport debounce from 'debounce'\nimport scrollIntoView from 'scroll-into-view-if-needed'\n\nimport Children from './children'\nimport Hotkeys from '../utils/hotkeys'\nimport { IS_FIREFOX, IS_SAFARI } from '../utils/environment'\nimport { ReactEditor } from '..'\nimport { ReadOnlyContext } from '../hooks/use-read-only'\nimport { useSlate } from '../hooks/use-slate'\nimport { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect'\nimport {\n DOMElement,\n DOMNode,\n DOMRange,\n isDOMElement,\n isDOMNode,\n isDOMText,\n DOMStaticRange,\n} from '../utils/dom'\nimport {\n EDITOR_TO_ELEMENT,\n ELEMENT_TO_NODE,\n IS_READ_ONLY,\n NODE_TO_ELEMENT,\n IS_FOCUSED,\n PLACEHOLDER_SYMBOL,\n} from '../utils/weak-maps'\n\n/**\n * `RenderElementProps` are passed to the `renderElement` handler.\n */\n\nexport interface RenderElementProps {\n children: any\n element: Element\n attributes: {\n 'data-slate-node': 'element'\n 'data-slate-inline'?: true\n 'data-slate-void'?: true\n dir?: 'rtl'\n ref: any\n }\n}\n\n/**\n * `RenderLeafProps` are passed to the `renderLeaf` handler.\n */\n\nexport interface RenderLeafProps {\n children: any\n leaf: Text\n text: Text\n attributes: {\n 'data-slate-leaf': true\n }\n}\n\n/**\n * `EditableProps` are passed to the `` component.\n */\n\nexport type EditableProps = {\n decorate?: (entry: NodeEntry) => Range[]\n onDOMBeforeInput?: (event: Event) => void\n placeholder?: string\n readOnly?: boolean\n role?: string\n style?: React.CSSProperties\n renderElement?: (props: RenderElementProps) => JSX.Element\n renderLeaf?: (props: RenderLeafProps) => JSX.Element\n as?: React.ElementType\n ReactHappyWindow?: React.Component\n reactHappyWindowProps?: object\n} & React.TextareaHTMLAttributes\n\n/**\n * Editable.\n */\n\nexport const Editable = (props: EditableProps) => {\n const {\n autoFocus,\n decorate = defaultDecorate,\n onDOMBeforeInput: propsOnDOMBeforeInput,\n placeholder,\n readOnly = false,\n renderElement,\n renderLeaf,\n style = {},\n as: Component = 'div',\n ReactHappyWindow,\n reactHappyWindowProps,\n happyWindowRef,\n ...attributes\n } = props\n const editor = useSlate()\n const ref = useRef(null)\n\n // Update internal state on each render.\n IS_READ_ONLY.set(editor, readOnly)\n\n // Keep track of some state for the event handler logic.\n const state = useMemo(\n () => ({\n isComposing: false,\n isUpdatingSelection: false,\n latestElement: null as DOMElement | null,\n }),\n []\n )\n\n // Update element-related weak maps with the DOM element ref.\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n EDITOR_TO_ELEMENT.set(editor, ref.current)\n NODE_TO_ELEMENT.set(editor, ref.current)\n ELEMENT_TO_NODE.set(ref.current, editor)\n } else {\n NODE_TO_ELEMENT.delete(editor)\n }\n })\n\n // Attach a native DOM event handler for `selectionchange`, because React's\n // built-in `onSelect` handler doesn't fire for all selection changes. It's a\n // leaky polyfill that only fires on keypresses or clicks. Instead, we want to\n // fire for any change to the selection inside the editor. (2019/11/04)\n // https://github.com/facebook/react/issues/5785\n useIsomorphicLayoutEffect(() => {\n window.document.addEventListener('selectionchange', onDOMSelectionChange)\n\n return () => {\n window.document.removeEventListener(\n 'selectionchange',\n onDOMSelectionChange\n )\n }\n }, [])\n\n // Attach a native DOM event handler for `beforeinput` events, because React's\n // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose\n // real `beforeinput` events sadly... (2019/11/04)\n // https://github.com/facebook/react/issues/11211\n useIsomorphicLayoutEffect(() => {\n if (ref.current) {\n // @ts-ignore The `beforeinput` event isn't recognized.\n ref.current.addEventListener('beforeinput', onDOMBeforeInput)\n }\n\n return () => {\n if (ref.current) {\n // @ts-ignore The `beforeinput` event isn't recognized.\n ref.current.removeEventListener('beforeinput', onDOMBeforeInput)\n }\n }\n }, [])\n\n // Whenever the editor updates, make sure the DOM selection state is in sync.\n useIsomorphicLayoutEffect(() => {\n const { selection } = editor\n const domSelection = window.getSelection()\n\n if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {\n return\n }\n\n const hasDomSelection = domSelection.type !== 'None'\n\n // If the DOM selection is properly unset, we're done.\n if (!selection && !hasDomSelection) {\n return\n }\n\n const newDomRange = selection && ReactEditor.toDOMRange(editor, selection)\n\n // If the DOM selection is already correct, we're done.\n if (\n hasDomSelection &&\n newDomRange &&\n isRangeEqual(domSelection.getRangeAt(0), newDomRange)\n ) {\n return\n }\n\n // Otherwise the DOM selection is out of sync, so update it.\n const el = ReactEditor.toDOMNode(editor, editor)\n state.isUpdatingSelection = true\n domSelection.removeAllRanges()\n\n if (newDomRange) {\n domSelection.addRange(newDomRange!)\n const leafEl = newDomRange.startContainer.parentElement!\n scrollIntoView(leafEl, { scrollMode: 'if-needed' })\n }\n\n setTimeout(() => {\n // COMPAT: In Firefox, it's not enough to create a range, you also need\n // to focus the contenteditable element too. (2016/11/16)\n if (newDomRange && IS_FIREFOX) {\n el.focus()\n }\n\n state.isUpdatingSelection = false\n })\n })\n\n // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it\n // needs to be manually focused.\n useEffect(() => {\n if (ref.current && autoFocus) {\n ref.current.focus()\n }\n }, [autoFocus])\n\n // Listen on the native `beforeinput` event to get real \"Level 2\" events. This\n // is required because React's `beforeinput` is fake and never really attaches\n // to the real event sadly. (2019/11/01)\n // https://github.com/facebook/react/issues/11211\n const onDOMBeforeInput = useCallback(\n (\n event: Event & {\n data: string | null\n dataTransfer: DataTransfer | null\n getTargetRanges(): DOMStaticRange[]\n inputType: string\n isComposing: boolean\n }\n ) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isDOMEventHandled(event, propsOnDOMBeforeInput)\n ) {\n const { selection } = editor\n const { inputType: type } = event\n const data = event.dataTransfer || event.data || undefined\n\n // These two types occur while a user is composing text and can't be\n // cancelled. Let them through and wait for the composition to end.\n if (\n type === 'insertCompositionText' ||\n type === 'deleteCompositionText'\n ) {\n return\n }\n\n event.preventDefault()\n\n // COMPAT: For the deleting forward/backward input types we don't want\n // to change the selection because it is the range that will be deleted,\n // and those commands determine that for themselves.\n if (!type.startsWith('delete') || type.startsWith('deleteBy')) {\n const [targetRange] = event.getTargetRanges()\n\n if (targetRange) {\n const range = ReactEditor.toSlateRange(editor, targetRange)\n if (!range) {\n return\n }\n if (!selection || !Range.equals(selection, range)) {\n Transforms.select(editor, range)\n }\n }\n }\n\n // COMPAT: If the selection is expanded, even if the command seems like\n // a delete forward/backward command it should delete the selection.\n if (\n selection &&\n Range.isExpanded(selection) &&\n type.startsWith('delete')\n ) {\n Editor.deleteFragment(editor)\n return\n }\n\n switch (type) {\n case 'deleteByComposition':\n case 'deleteByCut':\n case 'deleteByDrag': {\n Editor.deleteFragment(editor)\n break\n }\n\n case 'deleteContent':\n case 'deleteContentForward': {\n Editor.deleteForward(editor)\n break\n }\n\n case 'deleteContentBackward': {\n Editor.deleteBackward(editor)\n break\n }\n\n case 'deleteEntireSoftLine': {\n Editor.deleteBackward(editor, { unit: 'line' })\n Editor.deleteForward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteHardLineBackward': {\n Editor.deleteBackward(editor, { unit: 'block' })\n break\n }\n\n case 'deleteSoftLineBackward': {\n Editor.deleteBackward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteHardLineForward': {\n Editor.deleteForward(editor, { unit: 'block' })\n break\n }\n\n case 'deleteSoftLineForward': {\n Editor.deleteForward(editor, { unit: 'line' })\n break\n }\n\n case 'deleteWordBackward': {\n Editor.deleteBackward(editor, { unit: 'word' })\n break\n }\n\n case 'deleteWordForward': {\n Editor.deleteForward(editor, { unit: 'word' })\n break\n }\n\n case 'insertLineBreak':\n case 'insertParagraph': {\n Editor.insertBreak(editor)\n break\n }\n\n case 'insertFromComposition':\n case 'insertFromDrop':\n case 'insertFromPaste':\n case 'insertFromYank':\n case 'insertReplacementText':\n case 'insertText': {\n if (data instanceof DataTransfer) {\n ReactEditor.insertData(editor, data)\n } else if (typeof data === 'string') {\n Editor.insertText(editor, data)\n }\n\n break\n }\n }\n }\n },\n []\n )\n\n // Listen on the native `selectionchange` event to be able to update any time\n // the selection changes. This is required because React's `onSelect` is leaky\n // and non-standard so it doesn't fire until after a selection has been\n // released. This causes issues in situations where another change happens\n // while a selection is being dragged.\n const onDOMSelectionChange = useCallback(\n debounce(() => {\n if (!readOnly && !state.isComposing && !state.isUpdatingSelection) {\n const { activeElement } = window.document\n const el = ReactEditor.toDOMNode(editor, editor)\n const domSelection = window.getSelection()\n const domRange =\n domSelection &&\n domSelection.rangeCount > 0 &&\n domSelection.getRangeAt(0)\n\n if (activeElement === el) {\n state.latestElement = activeElement\n IS_FOCUSED.set(editor, true)\n } else {\n IS_FOCUSED.delete(editor)\n }\n\n if (\n domRange &&\n hasEditableTarget(editor, domRange.startContainer) &&\n hasEditableTarget(editor, domRange.endContainer)\n ) {\n const range = ReactEditor.toSlateRange(editor, domRange)\n Transforms.select(editor, range)\n } else {\n Transforms.deselect(editor)\n }\n }\n }, 100),\n []\n )\n\n const decorations = decorate([editor, []])\n\n if (\n placeholder &&\n editor.children.length === 1 &&\n Array.from(Node.texts(editor)).length === 1 &&\n Node.string(editor) === ''\n ) {\n const start = Editor.start(editor, [])\n decorations.push({\n [PLACEHOLDER_SYMBOL]: true,\n placeholder,\n anchor: start,\n focus: start,\n })\n }\n\n return (\n \n {\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to React's leaky polyfill instead just for it. It\n // only works for the `insertText` input type.\n if (IS_FIREFOX && !readOnly && ReactEditor.isFocused(editor)) {\n event.preventDefault()\n const text = (event as any).data as string\n Editor.insertText(editor, text)\n }\n },\n [readOnly]\n )}\n onBlur={useCallback(\n (event: React.FocusEvent) => {\n if (\n readOnly ||\n state.isUpdatingSelection ||\n !hasEditableTarget(editor, event.target) ||\n isEventHandled(event, attributes.onBlur)\n ) {\n return\n }\n\n // COMPAT: If the current `activeElement` is still the previous\n // one, this is due to the window being blurred when the tab\n // itself becomes unfocused, so we want to abort early to allow to\n // editor to stay focused when the tab becomes focused again.\n if (state.latestElement === window.document.activeElement) {\n return\n }\n\n const { relatedTarget } = event\n const el = ReactEditor.toDOMNode(editor, editor)\n\n // COMPAT: The event should be ignored if the focus is returning\n // to the editor from an embedded editable element (eg. an \n // element inside a void node).\n if (relatedTarget === el) {\n return\n }\n\n // COMPAT: The event should be ignored if the focus is moving from\n // the editor to inside a void node's spacer element.\n if (\n isDOMElement(relatedTarget) &&\n relatedTarget.hasAttribute('data-slate-spacer')\n ) {\n return\n }\n\n // COMPAT: The event should be ignored if the focus is moving to a\n // non- editable section of an element that isn't a void node (eg.\n // a list item of the check list example).\n if (\n relatedTarget != null &&\n isDOMNode(relatedTarget) &&\n ReactEditor.hasDOMNode(editor, relatedTarget)\n ) {\n const node = ReactEditor.toSlateNode(editor, relatedTarget)\n\n if (Element.isElement(node) && !editor.isVoid(node)) {\n return\n }\n }\n\n IS_FOCUSED.delete(editor)\n },\n [readOnly, attributes.onBlur]\n )}\n onClick={useCallback(\n (event: React.MouseEvent) => {\n if (\n !readOnly &&\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onClick) &&\n isDOMNode(event.target)\n ) {\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n const start = Editor.start(editor, path)\n\n if (Editor.void(editor, { at: start })) {\n const range = Editor.range(editor, start)\n Transforms.select(editor, range)\n }\n }\n },\n [readOnly, attributes.onClick]\n )}\n onCompositionEnd={useCallback(\n (event: React.CompositionEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCompositionEnd)\n ) {\n state.isComposing = false\n\n // COMPAT: In Chrome, `beforeinput` events for compositions\n // aren't correct and never fire the \"insertFromComposition\"\n // type that we need. So instead, insert whenever a composition\n // ends since it will already have been committed to the DOM.\n if (!IS_SAFARI && !IS_FIREFOX && event.data) {\n Editor.insertText(editor, event.data)\n }\n }\n },\n [attributes.onCompositionEnd]\n )}\n onCompositionStart={useCallback(\n (event: React.CompositionEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCompositionStart)\n ) {\n state.isComposing = true\n }\n },\n [attributes.onCompositionStart]\n )}\n onCopy={useCallback(\n (event: React.ClipboardEvent) => {\n if (\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCopy)\n ) {\n event.preventDefault()\n setFragmentData(event.clipboardData, editor)\n }\n },\n [attributes.onCopy]\n )}\n onCut={useCallback(\n (event: React.ClipboardEvent) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onCut)\n ) {\n event.preventDefault()\n setFragmentData(event.clipboardData, editor)\n const { selection } = editor\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n }\n }\n },\n [readOnly, attributes.onCut]\n )}\n onDragOver={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onDragOver)\n ) {\n // Only when the target is void, call `preventDefault` to signal\n // that drops are allowed. Editable content is droppable by\n // default, and calling `preventDefault` hides the cursor.\n const node = ReactEditor.toSlateNode(editor, event.target)\n\n if (Editor.isVoid(editor, node)) {\n event.preventDefault()\n }\n }\n },\n [attributes.onDragOver]\n )}\n onDragStart={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onDragStart)\n ) {\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n const voidMatch = Editor.void(editor, { at: path })\n\n // If starting a drag on a void node, make sure it is selected\n // so that it shows up in the selection's fragment.\n if (voidMatch) {\n const range = Editor.range(editor, path)\n Transforms.select(editor, range)\n }\n\n setFragmentData(event.dataTransfer, editor)\n }\n },\n [attributes.onDragStart]\n )}\n onDrop={useCallback(\n (event: React.DragEvent) => {\n if (\n hasTarget(editor, event.target) &&\n !readOnly &&\n !isEventHandled(event, attributes.onDrop)\n ) {\n // COMPAT: Firefox doesn't fire `beforeinput` events at all, and\n // Chromium browsers don't properly fire them for files being\n // dropped into a `contenteditable`. (2019/11/26)\n // https://bugs.chromium.org/p/chromium/issues/detail?id=1028668\n if (\n IS_FIREFOX ||\n (!IS_SAFARI && event.dataTransfer.files.length > 0)\n ) {\n event.preventDefault()\n const range = ReactEditor.findEventRange(editor, event)\n const data = event.dataTransfer\n Transforms.select(editor, range)\n ReactEditor.insertData(editor, data)\n }\n }\n },\n [readOnly, attributes.onDrop]\n )}\n onFocus={useCallback(\n (event: React.FocusEvent) => {\n if (\n !readOnly &&\n !state.isUpdatingSelection &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onFocus)\n ) {\n const el = ReactEditor.toDOMNode(editor, editor)\n state.latestElement = window.document.activeElement\n\n // COMPAT: If the editor has nested editable elements, the focus\n // can go to them. In Firefox, this must be prevented because it\n // results in issues with keyboard navigation. (2017/03/30)\n if (IS_FIREFOX && event.target !== el) {\n el.focus()\n return\n }\n\n IS_FOCUSED.set(editor, true)\n }\n },\n [readOnly, attributes.onFocus]\n )}\n onKeyDown={useCallback(\n (event: React.KeyboardEvent) => {\n if (\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onKeyDown)\n ) {\n const { nativeEvent } = event\n const { selection } = editor\n\n const element =\n editor.children[\n selection !== null ? selection.focus.path[0] : 0\n ]\n const isRTL = getDirection(Node.string(element)) === 'rtl'\n\n // COMPAT: Since we prevent the default behavior on\n // `beforeinput` events, the browser doesn't think there's ever\n // any history stack to undo or redo, so we have to manage these\n // hotkeys ourselves. (2019/11/06)\n if (Hotkeys.isRedo(nativeEvent)) {\n event.preventDefault()\n\n if (editor.redo) {\n editor.redo()\n }\n\n return\n }\n\n if (Hotkeys.isUndo(nativeEvent)) {\n event.preventDefault()\n\n if (editor.undo) {\n editor.undo()\n }\n\n return\n }\n\n // COMPAT: Certain browsers don't handle the selection updates\n // properly. In Chrome, the selection isn't properly extended.\n // And in Firefox, the selection isn't properly collapsed.\n // (2017/10/17)\n if (Hotkeys.isMoveLineBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line', reverse: true })\n return\n }\n\n if (Hotkeys.isMoveLineForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line' })\n return\n }\n\n if (Hotkeys.isExtendLineBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, {\n unit: 'line',\n edge: 'focus',\n reverse: true,\n })\n return\n }\n\n if (Hotkeys.isExtendLineForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'line', edge: 'focus' })\n return\n }\n\n // COMPAT: If a void node is selected, or a zero-width text node\n // adjacent to an inline is selected, we need to handle these\n // hotkeys manually because browsers won't be able to skip over\n // the void node with the zero-width space not being an empty\n // string.\n if (Hotkeys.isMoveBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isCollapsed(selection)) {\n const { anchor } = selection\n if (anchor.offset === 1 && anchor.path[1] > 0) {\n // Hack to position the cursor at the end of the previous text node\n Transforms.move(editor, { reverse: !isRTL, distance: 2 })\n Transforms.move(editor, { reverse: isRTL })\n } else {\n Transforms.move(editor, { reverse: !isRTL })\n }\n } else {\n Transforms.collapse(editor, { edge: 'start' })\n }\n\n return\n }\n\n if (Hotkeys.isMoveForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isCollapsed(selection)) {\n Transforms.move(editor, { reverse: isRTL })\n } else {\n Transforms.collapse(editor, { edge: 'end' })\n }\n\n return\n }\n\n if (Hotkeys.isMoveWordBackward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'word', reverse: !isRTL })\n return\n }\n\n if (Hotkeys.isMoveWordForward(nativeEvent)) {\n event.preventDefault()\n Transforms.move(editor, { unit: 'word', reverse: isRTL })\n return\n }\n\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to guessing at the input intention for hotkeys.\n // COMPAT: In iOS, some of these hotkeys are handled in the\n if (IS_FIREFOX) {\n // We don't have a core behavior for these, but they change the\n // DOM if we don't prevent them, so we have to.\n if (\n Hotkeys.isBold(nativeEvent) ||\n Hotkeys.isItalic(nativeEvent) ||\n Hotkeys.isTransposeCharacter(nativeEvent)\n ) {\n event.preventDefault()\n return\n }\n\n if (Hotkeys.isSplitBlock(nativeEvent)) {\n event.preventDefault()\n Editor.insertBreak(editor)\n return\n }\n\n if (Hotkeys.isDeleteBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor)\n }\n\n return\n }\n\n if (Hotkeys.isDeleteForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor)\n }\n\n return\n }\n\n if (Hotkeys.isDeleteLineBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor, { unit: 'line' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteLineForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor, { unit: 'line' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteWordBackward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteBackward(editor, { unit: 'word' })\n }\n\n return\n }\n\n if (Hotkeys.isDeleteWordForward(nativeEvent)) {\n event.preventDefault()\n\n if (selection && Range.isExpanded(selection)) {\n Editor.deleteFragment(editor)\n } else {\n Editor.deleteForward(editor, { unit: 'word' })\n }\n\n return\n }\n }\n }\n },\n [readOnly, attributes.onKeyDown]\n )}\n onPaste={useCallback(\n (event: React.ClipboardEvent) => {\n // COMPAT: Firefox doesn't support the `beforeinput` event, so we\n // fall back to React's `onPaste` here instead.\n if (\n IS_FIREFOX &&\n !readOnly &&\n hasEditableTarget(editor, event.target) &&\n !isEventHandled(event, attributes.onPaste)\n ) {\n event.preventDefault()\n ReactEditor.insertData(editor, event.clipboardData)\n }\n },\n [readOnly, attributes.onPaste]\n )}\n >\n \n \n \n )\n}\n\n/**\n * A default memoized decorate function.\n */\n\nconst defaultDecorate = () => []\n\n/**\n * Check if two DOM range objects are equal.\n */\n\nconst isRangeEqual = (a: DOMRange, b: DOMRange) => {\n return (\n (a.startContainer === b.startContainer &&\n a.startOffset === b.startOffset &&\n a.endContainer === b.endContainer &&\n a.endOffset === b.endOffset) ||\n (a.startContainer === b.endContainer &&\n a.startOffset === b.endOffset &&\n a.endContainer === b.startContainer &&\n a.endOffset === b.startOffset)\n )\n}\n\n/**\n * Check if the target is in the editor.\n */\n\nconst hasTarget = (\n editor: ReactEditor,\n target: EventTarget | null\n): target is DOMNode => {\n return isDOMNode(target) && ReactEditor.hasDOMNode(editor, target)\n}\n\n/**\n * Check if the target is editable and in the editor.\n */\n\nconst hasEditableTarget = (\n editor: ReactEditor,\n target: EventTarget | null\n): target is DOMNode => {\n return (\n isDOMNode(target) &&\n ReactEditor.hasDOMNode(editor, target, { editable: true })\n )\n}\n\n/**\n * Check if an event is overrided by a handler.\n */\n\nconst isEventHandled = <\n EventType extends React.SyntheticEvent\n>(\n event: EventType,\n handler?: (event: EventType) => void\n) => {\n if (!handler) {\n return false\n }\n\n handler(event)\n return event.isDefaultPrevented() || event.isPropagationStopped()\n}\n\n/**\n * Check if a DOM event is overrided by a handler.\n */\n\nconst isDOMEventHandled = (event: Event, handler?: (event: Event) => void) => {\n if (!handler) {\n return false\n }\n\n handler(event)\n return event.defaultPrevented\n}\n\n/**\n * Set the currently selected fragment to the clipboard.\n */\n\nconst setFragmentData = (\n dataTransfer: DataTransfer,\n editor: ReactEditor\n): void => {\n const { selection } = editor\n\n if (!selection) {\n return\n }\n\n const [start, end] = Range.edges(selection)\n const startVoid = Editor.void(editor, { at: start.path })\n const endVoid = Editor.void(editor, { at: end.path })\n\n if (Range.isCollapsed(selection) && !startVoid) {\n return\n }\n\n // Create a fake selection so that we can add a Base64-encoded copy of the\n // fragment to the HTML, to decode on future pastes.\n const domRange = ReactEditor.toDOMRange(editor, selection)\n let contents = domRange.cloneContents()\n let attach = contents.childNodes[0] as HTMLElement\n\n // Make sure attach is non-empty, since empty nodes will not get copied.\n contents.childNodes.forEach(node => {\n if (node.textContent && node.textContent.trim() !== '') {\n attach = node as HTMLElement\n }\n })\n\n // COMPAT: If the end node is a void node, we need to move the end of the\n // range from the void node's spacer span, to the end of the void node's\n // content, since the spacer is before void's content in the DOM.\n if (endVoid) {\n const [voidNode] = endVoid\n const r = domRange.cloneRange()\n const domNode = ReactEditor.toDOMNode(editor, voidNode)\n r.setEndAfter(domNode)\n contents = r.cloneContents()\n }\n\n // COMPAT: If the start node is a void node, we need to attach the encoded\n // fragment to the void node's content node instead of the spacer, because\n // attaching it to empty `
/` nodes will end up having it erased by\n // most browsers. (2018/04/27)\n if (startVoid) {\n attach = contents.querySelector('[data-slate-spacer]')! as HTMLElement\n }\n\n // Remove any zero-width space spans from the cloned DOM so that they don't\n // show up elsewhere when pasted.\n Array.from(contents.querySelectorAll('[data-slate-zero-width]')).forEach(\n zw => {\n const isNewline = zw.getAttribute('data-slate-zero-width') === 'n'\n zw.textContent = isNewline ? '\\n' : ''\n }\n )\n\n // Set a `data-slate-fragment` attribute on a non-empty node, so it shows up\n // in the HTML, and can be used for intra-Slate pasting. If it's a text\n // node, wrap it in a `` so we have something to set an attribute on.\n if (isDOMText(attach)) {\n const span = document.createElement('span')\n // COMPAT: In Chrome and Safari, if we don't add the `white-space` style\n // then leading and trailing spaces will be ignored. (2017/09/21)\n span.style.whiteSpace = 'pre'\n span.appendChild(attach)\n contents.appendChild(span)\n attach = span\n }\n\n const fragment = Node.fragment(editor, selection)\n const string = JSON.stringify(fragment)\n const encoded = window.btoa(encodeURIComponent(string))\n attach.setAttribute('data-slate-fragment', encoded)\n\n // Overwriting the default functionality\n const { getFormattedSelection, getHTMLFormattedSelection } = editor\n if (\n typeof getFormattedSelection === 'function' &&\n typeof getHTMLFormattedSelection === 'function'\n ) {\n try {\n const plainText = getFormattedSelection()\n const htmlText = getHTMLFormattedSelection()\n dataTransfer.setData('text/plain', plainText)\n dataTransfer.setData('text/html', htmlText)\n return\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Error in slate-react/src/components/editable.tsx: ', e)\n // Only setData application/x-slate-fragment as a fallback because\n // we don't want to copy the timestamps of words\n dataTransfer.setData('application/x-slate-fragment', encoded)\n }\n }\n\n // Add the content to a
so that we can get its inner HTML.\n const div = document.createElement('div')\n div.appendChild(contents)\n dataTransfer.setData('text/html', div.innerHTML)\n dataTransfer.setData('text/plain', getPlainText(div))\n}\n\n/**\n * Get a plaintext representation of the content of a node, accounting for block\n * elements which get a newline appended.\n */\n\nconst getPlainText = (domNode: DOMNode) => {\n let text = ''\n\n if (isDOMText(domNode) && domNode.nodeValue) {\n return domNode.nodeValue\n }\n\n if (isDOMElement(domNode)) {\n for (const childNode of Array.from(domNode.childNodes)) {\n text += getPlainText(childNode)\n }\n\n const display = getComputedStyle(domNode).getPropertyValue('display')\n\n if (display === 'block' || display === 'list' || domNode.tagName === 'BR') {\n text += '\\n'\n }\n }\n\n return text\n}\n","/**\n * An auto-incrementing identifier for keys.\n */\n\nlet n = 0\n\n/**\n * A class that keeps track of a key string. We use a full class here because we\n * want to be able to use them as keys in `WeakMap` objects.\n */\n\nexport class Key {\n id: string\n\n constructor() {\n this.id = `${n++}`\n }\n}\n","import { Editor, Node, Path, Point, Range, Transforms } from 'slate'\n\nimport { Key } from '../utils/key'\nimport {\n EDITOR_TO_ELEMENT,\n ELEMENT_TO_NODE,\n IS_FOCUSED,\n IS_READ_ONLY,\n KEY_TO_ELEMENT,\n NODE_TO_INDEX,\n NODE_TO_KEY,\n NODE_TO_PARENT,\n} from '../utils/weak-maps'\nimport {\n DOMElement,\n DOMNode,\n DOMPoint,\n DOMRange,\n DOMSelection,\n DOMStaticRange,\n isDOMElement,\n normalizeDOMPoint,\n} from '../utils/dom'\n\n/**\n * A React and DOM-specific version of the `Editor` interface.\n */\n\nexport interface ReactEditor extends Editor {\n insertData: (data: DataTransfer) => void\n}\n\nexport const ReactEditor = {\n /**\n * Find a key for a Slate node.\n */\n\n findKey(editor: ReactEditor, node: Node): Key {\n let key = NODE_TO_KEY.get(node)\n\n if (!key) {\n key = new Key()\n NODE_TO_KEY.set(node, key)\n }\n\n return key\n },\n\n /**\n * Find the path of Slate node.\n */\n\n findPath(editor: ReactEditor, node: Node): Path {\n const path: Path = []\n let child = node\n\n while (true) {\n const parent = NODE_TO_PARENT.get(child)\n\n if (parent == null) {\n if (Editor.isEditor(child)) {\n return path\n } else {\n break\n }\n }\n\n const i = NODE_TO_INDEX.get(child)\n\n if (i == null) {\n break\n }\n\n path.unshift(i)\n child = parent\n }\n\n throw new Error(\n `Unable to find the path for Slate node: ${JSON.stringify(node)}`\n )\n },\n\n /**\n * Check if the editor is focused.\n */\n\n isFocused(editor: ReactEditor): boolean {\n return !!IS_FOCUSED.get(editor)\n },\n\n /**\n * Check if the editor is in read-only mode.\n */\n\n isReadOnly(editor: ReactEditor): boolean {\n return !!IS_READ_ONLY.get(editor)\n },\n\n /**\n * Blur the editor.\n */\n\n blur(editor: ReactEditor): void {\n const el = ReactEditor.toDOMNode(editor, editor)\n IS_FOCUSED.set(editor, false)\n\n if (window.document.activeElement === el) {\n el.blur()\n }\n },\n\n /**\n * Focus the editor.\n */\n\n focus(editor: ReactEditor): void {\n const el = ReactEditor.toDOMNode(editor, editor)\n IS_FOCUSED.set(editor, true)\n\n if (window.document.activeElement !== el) {\n el.focus({ preventScroll: true })\n }\n },\n\n /**\n * Deselect the editor.\n */\n\n deselect(editor: ReactEditor): void {\n const { selection } = editor\n const domSelection = window.getSelection()\n\n if (domSelection && domSelection.rangeCount > 0) {\n domSelection.removeAllRanges()\n }\n\n if (selection) {\n Transforms.deselect(editor)\n }\n },\n\n /**\n * Check if a DOM node is within the editor.\n */\n\n hasDOMNode(\n editor: ReactEditor,\n target: DOMNode,\n options: { editable?: boolean } = {}\n ): boolean {\n const { editable = false } = options\n const el = ReactEditor.toDOMNode(editor, editor)\n let element\n\n // COMPAT: In Firefox, reading `target.nodeType` will throw an error if\n // target is originating from an internal \"restricted\" element (e.g. a\n // stepper arrow on a number input). (2018/05/04)\n // https://github.com/ianstormtaylor/slate/issues/1819\n try {\n element = isDOMElement(target) ? target : target.parentElement\n } catch (err) {\n if (\n !err.message.includes('Permission denied to access property \"nodeType\"')\n ) {\n throw err\n }\n }\n\n if (!element) {\n return false\n }\n\n return (\n element.closest(`[data-slate-editor]`) === el &&\n (!editable || el.isContentEditable)\n )\n },\n\n /**\n * Insert data from a `DataTransfer` into the editor.\n */\n\n insertData(editor: ReactEditor, data: DataTransfer): void {\n editor.insertData(data)\n },\n\n /**\n * Find the native DOM element from a Slate node.\n */\n\n toDOMNode(editor: ReactEditor, node: Node): HTMLElement {\n const domNode = Editor.isEditor(node)\n ? EDITOR_TO_ELEMENT.get(editor)\n : KEY_TO_ELEMENT.get(ReactEditor.findKey(editor, node))\n\n if (!domNode) {\n throw new Error(\n `Cannot resolve a DOM node from Slate node: ${JSON.stringify(node)}`\n )\n }\n\n return domNode\n },\n\n /**\n * Find a native DOM selection point from a Slate point.\n */\n\n toDOMPoint(editor: ReactEditor, point: Point): DOMPoint {\n const [node] = Editor.node(editor, point.path)\n const el = ReactEditor.toDOMNode(editor, node)\n let domPoint: DOMPoint | undefined\n\n // If we're inside a void node, force the offset to 0, otherwise the zero\n // width spacing character will result in an incorrect offset of 1\n if (Editor.void(editor, { at: point })) {\n point = { path: point.path, offset: 0 }\n }\n\n // For each leaf, we need to isolate its content, which means filtering\n // to its direct text and zero-width spans. (We have to filter out any\n // other siblings that may have been rendered alongside them.)\n const selector = `[data-slate-string], [data-slate-zero-width]`\n const texts = Array.from(el.querySelectorAll(selector))\n let start = 0\n\n for (const text of texts) {\n const domNode = text.childNodes[0] as HTMLElement\n\n if (domNode == null || domNode.textContent == null) {\n continue\n }\n\n const { length } = domNode.textContent\n const attr = text.getAttribute('data-slate-length')\n const trueLength = attr == null ? length : parseInt(attr, 10)\n const end = start + trueLength\n\n if (point.offset <= end) {\n const offset = Math.min(length, Math.max(0, point.offset - start))\n domPoint = [domNode, offset]\n break\n }\n\n start = end\n }\n\n if (!domPoint) {\n throw new Error(\n `Cannot resolve a DOM point from Slate point: ${JSON.stringify(point)}`\n )\n }\n\n return domPoint\n },\n\n /**\n * Find a native DOM range from a Slate `range`.\n */\n\n toDOMRange(editor: ReactEditor, range: Range): DOMRange {\n const { anchor, focus } = range\n const domAnchor = ReactEditor.toDOMPoint(editor, anchor)\n const domFocus = Range.isCollapsed(range)\n ? domAnchor\n : ReactEditor.toDOMPoint(editor, focus)\n\n const domRange = window.document.createRange()\n const start = Range.isBackward(range) ? domFocus : domAnchor\n const end = Range.isBackward(range) ? domAnchor : domFocus\n domRange.setStart(start[0], start[1])\n domRange.setEnd(end[0], end[1])\n return domRange\n },\n\n /**\n * Find a Slate node from a native DOM `element`.\n */\n\n toSlateNode(editor: ReactEditor, domNode: DOMNode): Node {\n let domEl = isDOMElement(domNode) ? domNode : domNode.parentElement\n\n if (domEl && !domEl.hasAttribute('data-slate-node')) {\n domEl = domEl.closest(`[data-slate-node]`)\n }\n\n const node = domEl ? ELEMENT_TO_NODE.get(domEl as HTMLElement) : null\n\n if (!node) {\n throw new Error(`Cannot resolve a Slate node from DOM node: ${domEl}`)\n }\n\n return node\n },\n\n /**\n * Get the target range from a DOM `event`.\n */\n\n findEventRange(editor: ReactEditor, event: any): Range {\n if ('nativeEvent' in event) {\n event = event.nativeEvent\n }\n\n const { clientX: x, clientY: y, target } = event\n\n if (x == null || y == null) {\n throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`)\n }\n\n const node = ReactEditor.toSlateNode(editor, event.target)\n const path = ReactEditor.findPath(editor, node)\n\n // If the drop target is inside a void node, move it into either the\n // next or previous node, depending on which side the `x` and `y`\n // coordinates are closest to.\n if (Editor.isVoid(editor, node)) {\n const rect = target.getBoundingClientRect()\n const isPrev = editor.isInline(node)\n ? x - rect.left < rect.left + rect.width - x\n : y - rect.top < rect.top + rect.height - y\n\n const edge = Editor.point(editor, path, {\n edge: isPrev ? 'start' : 'end',\n })\n const point = isPrev\n ? Editor.before(editor, edge)\n : Editor.after(editor, edge)\n\n if (point) {\n const range = Editor.range(editor, point)\n return range\n }\n }\n\n // Else resolve a range from the caret position where the drop occured.\n let domRange\n const { document } = window\n\n // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25)\n if (document.caretRangeFromPoint) {\n domRange = document.caretRangeFromPoint(x, y)\n } else {\n const position = document.caretPositionFromPoint(x, y)\n\n if (position) {\n domRange = document.createRange()\n domRange.setStart(position.offsetNode, position.offset)\n domRange.setEnd(position.offsetNode, position.offset)\n }\n }\n\n if (!domRange) {\n throw new Error(`Cannot resolve a Slate range from a DOM event: ${event}`)\n }\n\n // Resolve a Slate range from the DOM range.\n const range = ReactEditor.toSlateRange(editor, domRange)\n return range\n },\n\n /**\n * Find a Slate point from a DOM selection's `domNode` and `domOffset`.\n */\n\n toSlatePoint(editor: ReactEditor, domPoint: DOMPoint): Point {\n const [nearestNode, nearestOffset] = normalizeDOMPoint(domPoint)\n const parentNode = nearestNode.parentNode as DOMElement\n let textNode: DOMElement | null = null\n let offset = 0\n\n if (parentNode) {\n const voidNode = parentNode.closest('[data-slate-void=\"true\"]')\n let leafNode = parentNode.closest('[data-slate-leaf]')\n let domNode: DOMElement | null = null\n\n // Calculate how far into the text node the `nearestNode` is, so that we\n // can determine what the offset relative to the text node is.\n if (leafNode) {\n textNode = leafNode.closest('[data-slate-node=\"text\"]')!\n const range = window.document.createRange()\n range.setStart(textNode, 0)\n range.setEnd(nearestNode, nearestOffset)\n const contents = range.cloneContents()\n const removals = [\n ...contents.querySelectorAll('[data-slate-zero-width]'),\n ...contents.querySelectorAll('[contenteditable=false]'),\n ]\n\n removals.forEach(el => {\n el!.parentNode!.removeChild(el)\n })\n\n // COMPAT: Edge has a bug where Range.prototype.toString() will\n // convert \\n into \\r\\n. The bug causes a loop when slate-react\n // attempts to reposition its cursor to match the native position. Use\n // textContent.length instead.\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10291116/\n offset = contents.textContent!.length\n domNode = textNode\n } else if (voidNode) {\n // For void nodes, the element with the offset key will be a cousin, not an\n // ancestor, so find it by going down from the nearest void parent.\n\n leafNode = voidNode.querySelector('[data-slate-leaf]')!\n textNode = leafNode.closest('[data-slate-node=\"text\"]')!\n domNode = leafNode\n offset = domNode.textContent!.length\n }\n\n // COMPAT: If the parent node is a Slate zero-width space, editor is\n // because the text node should have no characters. However, during IME\n // composition the ASCII characters will be prepended to the zero-width\n // space, so subtract 1 from the offset to account for the zero-width\n // space character.\n if (\n domNode &&\n offset === domNode.textContent!.length &&\n parentNode.hasAttribute('data-slate-zero-width')\n ) {\n offset--\n }\n }\n\n if (!textNode) {\n throw new Error(\n `Cannot resolve a Slate point from DOM point: ${domPoint}`\n )\n }\n\n // COMPAT: If someone is clicking from one Slate editor into another,\n // the select event fires twice, once for the old editor's `element`\n // first, and then afterwards for the correct `element`. (2017/03/03)\n const slateNode = ReactEditor.toSlateNode(editor, textNode!)\n const path = ReactEditor.findPath(editor, slateNode)\n return { path, offset }\n },\n\n /**\n * Find a Slate range from a DOM range or selection.\n */\n\n toSlateRange(\n editor: ReactEditor,\n domRange: DOMRange | DOMStaticRange | DOMSelection\n ): Range {\n const el =\n domRange instanceof Selection\n ? domRange.anchorNode\n : domRange.startContainer\n let anchorNode\n let anchorOffset\n let focusNode\n let focusOffset\n let isCollapsed\n\n if (el) {\n if (domRange instanceof Selection) {\n anchorNode = domRange.anchorNode\n anchorOffset = domRange.anchorOffset\n focusNode = domRange.focusNode\n focusOffset = domRange.focusOffset\n isCollapsed = domRange.isCollapsed\n } else {\n anchorNode = domRange.startContainer\n anchorOffset = domRange.startOffset\n focusNode = domRange.endContainer\n focusOffset = domRange.endOffset\n isCollapsed = domRange.collapsed\n }\n }\n\n if (\n anchorNode == null ||\n focusNode == null ||\n anchorOffset == null ||\n focusOffset == null\n ) {\n throw new Error(\n `Cannot resolve a Slate range from DOM range: ${domRange}`\n )\n }\n\n const anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset])\n const focus = isCollapsed\n ? anchor\n : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset])\n\n return { anchor, focus }\n },\n}\n","import { createContext, useContext } from 'react'\n\n/**\n * A React context for sharing the `focused` state of the editor.\n */\n\nexport const FocusedContext = createContext(false)\n\n/**\n * Get the current `focused` state of the editor.\n */\n\nexport const useFocused = (): boolean => {\n return useContext(FocusedContext)\n}\n","import React, { useMemo, useState, useCallback } from 'react'\nimport { Node } from 'slate'\n\nimport { ReactEditor } from '../plugin/react-editor'\nimport { FocusedContext } from '../hooks/use-focused'\nimport { EditorContext } from '../hooks/use-editor'\nimport { SlateContext } from '../hooks/use-slate'\nimport { EDITOR_TO_ON_CHANGE } from '../utils/weak-maps'\n\n/**\n * A wrapper around the provider to handle `onChange` events, because the editor\n * is a mutable singleton so it won't ever register as \"changed\" otherwise.\n */\n\nexport const Slate = (props: {\n editor: ReactEditor\n value: Node[]\n children: React.ReactNode\n onChange: (value: Node[]) => void\n [key: string]: any\n}) => {\n const { editor, children, onChange, value, ...rest } = props\n const [key, setKey] = useState(0)\n const context: [ReactEditor] = useMemo(() => {\n editor.children = value\n Object.assign(editor, rest)\n return [editor]\n }, [key, value, ...Object.values(rest)])\n\n const onContextChange = useCallback(() => {\n onChange(editor.children)\n setKey(key + 1)\n }, [key, onChange])\n\n EDITOR_TO_ON_CHANGE.set(editor, onContextChange)\n\n return (\n \n \n \n {children}\n \n \n \n )\n}\n","import ReactDOM from 'react-dom'\nimport { Editor, Node, Path, Operation, Transforms } from 'slate'\n\nimport { ReactEditor } from './react-editor'\nimport { Key } from '../utils/key'\nimport { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'\n\n/**\n * `withReact` adds React and DOM specific behaviors to the editor.\n */\n\nexport const withReact = (editor: T) => {\n const e = editor as T & ReactEditor\n const { apply, onChange } = e\n\n e.apply = (op: Operation) => {\n const matches: [Path, Key][] = []\n\n switch (op.type) {\n case 'insert_text':\n case 'remove_text':\n case 'set_node': {\n for (const [node, path] of Editor.levels(e, { at: op.path })) {\n const key = ReactEditor.findKey(e, node)\n matches.push([path, key])\n }\n\n break\n }\n\n case 'insert_node':\n case 'remove_node':\n case 'merge_node':\n case 'split_node': {\n for (const [node, path] of Editor.levels(e, {\n at: Path.parent(op.path),\n })) {\n const key = ReactEditor.findKey(e, node)\n matches.push([path, key])\n }\n\n break\n }\n\n case 'move_node': {\n // TODO\n break\n }\n }\n\n apply(op)\n\n for (const [path, key] of matches) {\n const [node] = Editor.node(e, path)\n NODE_TO_KEY.set(node, key)\n }\n }\n\n e.insertData = (data: DataTransfer) => {\n const fragment = data.getData('application/x-slate-fragment')\n\n if (fragment) {\n const decoded = decodeURIComponent(window.atob(fragment))\n const parsed = JSON.parse(decoded) as Node[]\n Transforms.insertFragment(e, parsed)\n return\n }\n\n const text = data.getData('text/plain')\n\n if (text) {\n const lines = text.split('\\n')\n let split = false\n\n for (const line of lines) {\n if (split) {\n Transforms.splitNodes(e)\n }\n\n Transforms.insertText(e, line)\n split = true\n }\n }\n }\n\n e.onChange = () => {\n // COMPAT: React doesn't batch `setState` hook calls, which means that the\n // children and selection can get out of sync for one render pass. So we\n // have to use this unstable API to ensure it batches them. (2019/12/03)\n // https://github.com/facebook/react/issues/14259#issuecomment-439702367\n ReactDOM.unstable_batchedUpdates(() => {\n const onContextChange = EDITOR_TO_ON_CHANGE.get(e)\n\n if (onContextChange) {\n onContextChange()\n }\n\n onChange()\n })\n }\n\n return e\n}\n"],"names":["Path","React","Node","Editor","NODE_TO_INDEX","WeakMap","NODE_TO_PARENT","EDITOR_TO_ELEMENT","ELEMENT_TO_NODE","KEY_TO_ELEMENT","NODE_TO_ELEMENT","NODE_TO_KEY","IS_READ_ONLY","IS_FOCUSED","EDITOR_TO_ON_CHANGE","PLACEHOLDER_SYMBOL","Symbol","Text","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useRef","SlateText","Leaf","SelectedContext","createContext","useSelected","useContext","Range","Element","ElementComponent","TextComponent","IS_IOS","navigator","test","userAgent","MSStream","IS_APPLE","IS_FIREFOX","IS_SAFARI","HOTKEYS","bold","compose","moveBackward","moveForward","moveWordBackward","moveWordForward","deleteBackward","deleteForward","extendBackward","extendForward","italic","splitBlock","undo","APPLE_HOTKEYS","moveLineBackward","moveLineForward","deleteLineBackward","deleteLineForward","deleteWordBackward","deleteWordForward","extendLineBackward","extendLineForward","redo","transposeCharacter","WINDOWS_HOTKEYS","create","key","generic","apple","windows","isGeneric","isKeyHotkey","isApple","isWindows","event","isBold","isCompose","isMoveBackward","isMoveForward","isDeleteBackward","isDeleteForward","isDeleteLineBackward","isDeleteLineForward","isDeleteWordBackward","isDeleteWordForward","isExtendBackward","isExtendForward","isExtendLineBackward","isExtendLineForward","isItalic","isMoveLineBackward","isMoveLineForward","isMoveWordBackward","isMoveWordForward","isRedo","isSplitBlock","isTransposeCharacter","isUndo","ReadOnlyContext","useReadOnly","isDOMComment","value","isDOMNode","nodeType","isDOMElement","isDOMText","normalizeDOMPoint","domPoint","node","offset","childNodes","length","isLast","direction","index","getEditableChild","i","textContent","parent","child","triedForward","triedBackward","getAttribute","useMemo","useCallback","Transforms","n","Key","constructor","id","ReactEditor","findKey","editor","get","set","findPath","path","isEditor","unshift","Error","JSON","stringify","isFocused","isReadOnly","blur","el","toDOMNode","document","activeElement","focus","preventScroll","deselect","selection","domSelection","getSelection","rangeCount","removeAllRanges","hasDOMNode","target","options","editable","element","parentElement","err","message","includes","closest","isContentEditable","insertData","data","domNode","toDOMPoint","point","void","at","selector","texts","Array","from","querySelectorAll","start","text","attr","trueLength","parseInt","end","Math","min","max","toDOMRange","range","anchor","domAnchor","domFocus","isCollapsed","domRange","createRange","isBackward","setStart","setEnd","toSlateNode","domEl","hasAttribute","findEventRange","nativeEvent","clientX","x","clientY","y","isVoid","rect","getBoundingClientRect","isPrev","isInline","left","width","top","height","edge","before","after","caretRangeFromPoint","position","caretPositionFromPoint","offsetNode","toSlateRange","toSlatePoint","nearestNode","nearestOffset","parentNode","textNode","voidNode","leafNode","contents","cloneContents","removals","forEach","removeChild","querySelector","slateNode","Selection","anchorNode","startContainer","anchorOffset","focusNode","focusOffset","startOffset","endContainer","endOffset","collapsed","FocusedContext","useFocused","useState","withReact","e","apply","onChange","op","matches","type","levels","push","fragment","getData","decoded","decodeURIComponent","atob","parsed","parse","insertFragment","lines","split","line","splitNodes","insertText","ReactDOM","unstable_batchedUpdates","onContextChange"],"mappings":"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"} \ No newline at end of file diff --git a/dist/plugin/react-editor.d.ts b/dist/plugin/react-editor.d.ts deleted file mode 100644 index 6c7e484..0000000 --- a/dist/plugin/react-editor.d.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Editor, Node, Path, Point, Range } from 'slate'; -import { Key } from '../utils/key'; -import { DOMNode, DOMPoint, DOMRange, DOMSelection, DOMStaticRange } from '../utils/dom'; -/** - * A React and DOM-specific version of the `Editor` interface. - */ -export interface ReactEditor extends Editor { - insertData: (data: DataTransfer) => void; -} -export declare const ReactEditor: { - /** - * Find a key for a Slate node. - */ - findKey(editor: ReactEditor, node: Node): Key; - /** - * Find the path of Slate node. - */ - findPath(editor: ReactEditor, node: Node): Path; - /** - * Check if the editor is focused. - */ - isFocused(editor: ReactEditor): boolean; - /** - * Check if the editor is in read-only mode. - */ - isReadOnly(editor: ReactEditor): boolean; - /** - * Blur the editor. - */ - blur(editor: ReactEditor): void; - /** - * Focus the editor. - */ - focus(editor: ReactEditor): void; - /** - * Deselect the editor. - */ - deselect(editor: ReactEditor): void; - /** - * Check if a DOM node is within the editor. - */ - hasDOMNode(editor: ReactEditor, target: DOMNode, options?: { - editable?: boolean | undefined; - }): boolean; - /** - * Insert data from a `DataTransfer` into the editor. - */ - insertData(editor: ReactEditor, data: DataTransfer): void; - /** - * Find the native DOM element from a Slate node. - */ - toDOMNode(editor: ReactEditor, node: Node): HTMLElement; - /** - * Find a native DOM selection point from a Slate point. - */ - toDOMPoint(editor: ReactEditor, point: Point): DOMPoint; - /** - * Find a native DOM range from a Slate `range`. - */ - toDOMRange(editor: ReactEditor, range: Range): DOMRange; - /** - * Find a Slate node from a native DOM `element`. - */ - toSlateNode(editor: ReactEditor, domNode: DOMNode): Node; - /** - * Get the target range from a DOM `event`. - */ - findEventRange(editor: ReactEditor, event: any): Range; - /** - * Find a Slate point from a DOM selection's `domNode` and `domOffset`. - */ - toSlatePoint(editor: ReactEditor, domPoint: DOMPoint): Point; - /** - * Find a Slate range from a DOM range or selection. - */ - toSlateRange(editor: ReactEditor, domRange: DOMRange | DOMStaticRange | DOMSelection): Range; -}; -//# sourceMappingURL=react-editor.d.ts.map \ No newline at end of file diff --git a/dist/plugin/react-editor.d.ts.map b/dist/plugin/react-editor.d.ts.map deleted file mode 100644 index 9000f0d..0000000 --- a/dist/plugin/react-editor.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"react-editor.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/plugin/react-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAc,MAAM,OAAO,CAAA;AAEpE,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAWlC,OAAO,EAEL,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,cAAc,EAGf,MAAM,cAAc,CAAA;AAErB;;GAEG;AAEH,MAAM,WAAW,WAAY,SAAQ,MAAM;IACzC,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;CACzC;AAED,eAAO,MAAM,WAAW;IACtB;;OAEG;;IAaH;;OAEG;;IAgCH;;OAEG;;IAMH;;OAEG;;IAMH;;OAEG;;IAWH;;OAEG;;IAWH;;OAEG;;IAeH;;OAEG;;;;IAmCH;;OAEG;;IAMH;;OAEG;;IAgBH;;OAEG;;IAkDH;;OAEG;;IAiBH;;OAEG;;IAkBH;;OAEG;;IAgEH;;OAEG;;IA2EH;;OAEG;;CAkDJ,CAAA"} \ No newline at end of file diff --git a/dist/plugin/with-react.d.ts b/dist/plugin/with-react.d.ts deleted file mode 100644 index 5a97dd9..0000000 --- a/dist/plugin/with-react.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Editor } from 'slate'; -import { ReactEditor } from './react-editor'; -/** - * `withReact` adds React and DOM specific behaviors to the editor. - */ -export declare const withReact: (editor: T) => T & ReactEditor; -//# sourceMappingURL=with-react.d.ts.map \ No newline at end of file diff --git a/dist/plugin/with-react.d.ts.map b/dist/plugin/with-react.d.ts.map deleted file mode 100644 index 04093a1..0000000 --- a/dist/plugin/with-react.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"with-react.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/plugin/with-react.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAqC,MAAM,OAAO,CAAA;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAI5C;;GAEG;AAEH,eAAO,MAAM,SAAS,kDA2FrB,CAAA"} \ No newline at end of file diff --git a/dist/utils/dom.d.ts b/dist/utils/dom.d.ts deleted file mode 100644 index 7f93f8d..0000000 --- a/dist/utils/dom.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Types. - */ -import DOMNode = globalThis.Node; -import DOMComment = globalThis.Comment; -import DOMElement = globalThis.Element; -import DOMText = globalThis.Text; -import DOMRange = globalThis.Range; -import DOMSelection = globalThis.Selection; -import DOMStaticRange = globalThis.StaticRange; -export { DOMNode, DOMComment, DOMElement, DOMText, DOMRange, DOMSelection, DOMStaticRange, }; -export declare type DOMPoint = [Node, number]; -/** - * Check if a DOM node is a comment node. - */ -export declare const isDOMComment: (value: any) => value is DOMComment; -/** - * Check if a DOM node is an element node. - */ -export declare const isDOMElement: (value: any) => value is DOMElement; -/** - * Check if a value is a DOM node. - */ -export declare const isDOMNode: (value: any) => value is DOMNode; -/** - * Check if a DOM node is an element node. - */ -export declare const isDOMText: (value: any) => value is DOMText; -/** - * Normalize a DOM point so that it always refers to a text node. - */ -export declare const normalizeDOMPoint: (domPoint: DOMPoint) => DOMPoint; -/** - * Get the nearest editable child at `index` in a `parent`, preferring - * `direction`. - */ -export declare const getEditableChild: (parent: DOMElement, index: number, direction: "forward" | "backward") => DOMNode; -//# sourceMappingURL=dom.d.ts.map \ No newline at end of file diff --git a/dist/utils/dom.d.ts.map b/dist/utils/dom.d.ts.map deleted file mode 100644 index 95978ea..0000000 --- a/dist/utils/dom.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,OAAO,GAAG,UAAU,CAAC,IAAI,CAAA;AAChC,OAAO,UAAU,GAAG,UAAU,CAAC,OAAO,CAAA;AACtC,OAAO,UAAU,GAAG,UAAU,CAAC,OAAO,CAAA;AACtC,OAAO,OAAO,GAAG,UAAU,CAAC,IAAI,CAAA;AAChC,OAAO,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAA;AAClC,OAAO,YAAY,GAAG,UAAU,CAAC,SAAS,CAAA;AAC1C,OAAO,cAAc,GAAG,UAAU,CAAC,WAAW,CAAA;AAC9C,OAAO,EACL,OAAO,EACP,UAAU,EACV,UAAU,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,CAAA;AAED,oBAAY,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AAErC;;GAEG;AAEH,eAAO,MAAM,YAAY,qCAExB,CAAA;AAED;;GAEG;AAEH,eAAO,MAAM,YAAY,qCAExB,CAAA;AAED;;GAEG;AAEH,eAAO,MAAM,SAAS,kCAErB,CAAA;AAED;;GAEG;AAEH,eAAO,MAAM,SAAS,kCAErB,CAAA;AAED;;GAEG;AAEH,eAAO,MAAM,iBAAiB,kCAwB7B,CAAA;AAED;;;GAGG;AAEH,eAAO,MAAM,gBAAgB,mFAyC5B,CAAA"} \ No newline at end of file diff --git a/dist/utils/environment.d.ts b/dist/utils/environment.d.ts deleted file mode 100644 index abd4123..0000000 --- a/dist/utils/environment.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export declare const IS_IOS: false; -export declare const IS_APPLE: boolean; -export declare const IS_FIREFOX: boolean; -export declare const IS_SAFARI: boolean; -//# sourceMappingURL=environment.d.ts.map \ No newline at end of file diff --git a/dist/utils/environment.d.ts.map b/dist/utils/environment.d.ts.map deleted file mode 100644 index 3c6d91b..0000000 --- a/dist/utils/environment.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/utils/environment.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,OAID,CAAA;AAElB,eAAO,MAAM,QAAQ,SACqD,CAAA;AAE1E,eAAO,MAAM,UAAU,SAEuC,CAAA;AAE9D,eAAO,MAAM,SAAS,SAEgC,CAAA"} \ No newline at end of file diff --git a/dist/utils/hotkeys.d.ts b/dist/utils/hotkeys.d.ts deleted file mode 100644 index 49d5497..0000000 --- a/dist/utils/hotkeys.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -declare const _default: { - isBold: (event: KeyboardEvent) => boolean; - isCompose: (event: KeyboardEvent) => boolean; - isMoveBackward: (event: KeyboardEvent) => boolean; - isMoveForward: (event: KeyboardEvent) => boolean; - isDeleteBackward: (event: KeyboardEvent) => boolean; - isDeleteForward: (event: KeyboardEvent) => boolean; - isDeleteLineBackward: (event: KeyboardEvent) => boolean; - isDeleteLineForward: (event: KeyboardEvent) => boolean; - isDeleteWordBackward: (event: KeyboardEvent) => boolean; - isDeleteWordForward: (event: KeyboardEvent) => boolean; - isExtendBackward: (event: KeyboardEvent) => boolean; - isExtendForward: (event: KeyboardEvent) => boolean; - isExtendLineBackward: (event: KeyboardEvent) => boolean; - isExtendLineForward: (event: KeyboardEvent) => boolean; - isItalic: (event: KeyboardEvent) => boolean; - isMoveLineBackward: (event: KeyboardEvent) => boolean; - isMoveLineForward: (event: KeyboardEvent) => boolean; - isMoveWordBackward: (event: KeyboardEvent) => boolean; - isMoveWordForward: (event: KeyboardEvent) => boolean; - isRedo: (event: KeyboardEvent) => boolean; - isSplitBlock: (event: KeyboardEvent) => boolean; - isTransposeCharacter: (event: KeyboardEvent) => boolean; - isUndo: (event: KeyboardEvent) => boolean; -}; -/** - * Hotkeys. - */ -export default _default; -//# sourceMappingURL=hotkeys.d.ts.map \ No newline at end of file diff --git a/dist/utils/hotkeys.d.ts.map b/dist/utils/hotkeys.d.ts.map deleted file mode 100644 index a26c834..0000000 --- a/dist/utils/hotkeys.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"hotkeys.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/utils/hotkeys.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAkEA;;GAEG;AAEH,wBAwBC"} \ No newline at end of file diff --git a/dist/utils/key.d.ts b/dist/utils/key.d.ts deleted file mode 100644 index 3dfeb2f..0000000 --- a/dist/utils/key.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * An auto-incrementing identifier for keys. - */ -/** - * A class that keeps track of a key string. We use a full class here because we - * want to be able to use them as keys in `WeakMap` objects. - */ -export declare class Key { - id: string; - constructor(); -} -//# sourceMappingURL=key.d.ts.map \ No newline at end of file diff --git a/dist/utils/key.d.ts.map b/dist/utils/key.d.ts.map deleted file mode 100644 index aec06dc..0000000 --- a/dist/utils/key.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/utils/key.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AAEH,qBAAa,GAAG;IACd,EAAE,EAAE,MAAM,CAAA;;CAKX"} \ No newline at end of file diff --git a/dist/utils/weak-maps.d.ts b/dist/utils/weak-maps.d.ts deleted file mode 100644 index 3245d46..0000000 --- a/dist/utils/weak-maps.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Node, Ancestor, Editor } from 'slate'; -import { Key } from './key'; -/** - * Two weak maps that allow us rebuild a path given a node. They are populated - * at render time such that after a render occurs we can always backtrack. - */ -export declare const NODE_TO_INDEX: WeakMap; -export declare const NODE_TO_PARENT: WeakMap; -/** - * Weak maps that allow us to go between Slate nodes and DOM nodes. These - * are used to resolve DOM event-related logic into Slate actions. - */ -export declare const EDITOR_TO_ELEMENT: WeakMap; -export declare const EDITOR_TO_PLACEHOLDER: WeakMap; -export declare const ELEMENT_TO_NODE: WeakMap; -export declare const KEY_TO_ELEMENT: WeakMap; -export declare const NODE_TO_ELEMENT: WeakMap; -export declare const NODE_TO_KEY: WeakMap; -/** - * Weak maps for storing editor-related state. - */ -export declare const IS_READ_ONLY: WeakMap; -export declare const IS_FOCUSED: WeakMap; -export declare const IS_DRAGGING: WeakMap; -export declare const IS_CLICKING: WeakMap; -/** - * Weak map for associating the context `onChange` context with the plugin. - */ -export declare const EDITOR_TO_ON_CHANGE: WeakMap void>; -/** - * Symbols. - */ -export declare const PLACEHOLDER_SYMBOL: string; -//# sourceMappingURL=weak-maps.d.ts.map \ No newline at end of file diff --git a/dist/utils/weak-maps.d.ts.map b/dist/utils/weak-maps.d.ts.map deleted file mode 100644 index be6318c..0000000 --- a/dist/utils/weak-maps.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"weak-maps.d.ts","sourceRoot":"","sources":["../packages/slate-react/src/utils/weak-maps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAS,MAAM,OAAO,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAE3B;;;GAGG;AAEH,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAiB,CAAA;AACjE,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAiB,CAAA;AAEpE;;;GAGG;AAEH,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,CAAiB,CAAA;AAC5E,eAAO,MAAM,qBAAqB,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAiB,CAAA;AAC3E,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,CAAiB,CAAA;AACxE,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,WAAW,CAAiB,CAAA;AACtE,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,CAAiB,CAAA;AACxE,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAiB,CAAA;AAE5D;;GAEG;AAEH,eAAO,MAAM,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAiB,CAAA;AACnE,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAiB,CAAA;AACjE,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAiB,CAAA;AAClE,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAiB,CAAA;AAElE;;GAEG;AAEH,eAAO,MAAM,mBAAmB,6BAAoC,CAAA;AAEpE;;GAEG;AAEH,eAAO,MAAM,kBAAkB,QAA+C,CAAA"} \ No newline at end of file diff --git a/node_modules/.bin/direction b/node_modules/.bin/direction deleted file mode 120000 index 665a528..0000000 --- a/node_modules/.bin/direction +++ /dev/null @@ -1 +0,0 @@ -../../../../node_modules/direction/cli.js \ No newline at end of file diff --git a/package.json b/package.json index e2e30bc..523d92a 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "slate-react", "description": "Tools for building completely customizable richtext editors with React.", - "version": "0.59.12", + "version": "0.117.3", "license": "MIT", - "repository": "git://github.com/happyscribe/slate-react.git", + "repository": "git://github.com/ianstormtaylor/slate.git", "main": "dist/index.js", "module": "dist/index.es.js", "types": "dist/index.d.ts", @@ -14,22 +14,36 @@ "dist/" ], "dependencies": { - "@types/debounce": "^1.2.0", - "@types/is-hotkey": "^0.1.1", - "debounce": "^1.2.0", - "direction": "^1.0.3", - "is-hotkey": "^0.1.6", - "is-plain-object": "^3.0.0", - "scroll-into-view-if-needed": "^2.2.20" + "@juggle/resize-observer": "^3.4.0", + "direction": "^1.0.4", + "is-hotkey": "^0.2.0", + "lodash": "^4.17.21", + "scroll-into-view-if-needed": "^3.1.0", + "tiny-invariant": "1.3.1" }, "devDependencies": { - "slate": "^0.57.1", - "slate-hyperscript": "^0.57.1" + "@babel/runtime": "^7.23.2", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^14.0.0", + "@types/is-hotkey": "^0.1.8", + "@types/jest": "29.5.6", + "@types/jsdom": "^21.1.4", + "@types/lodash": "^4.14.200", + "@types/react": "^18.2.41", + "@types/react-dom": "^18.2.17", + "@types/resize-observer-browser": "^0.1.8", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "slate": "^0.117.2", + "slate-dom": "^0.116.0", + "slate-hyperscript": "^0.115.0", + "source-map-loader": "^4.0.1" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "slate": ">=0.55.0" + "react": ">=18.2.0", + "react-dom": ">=18.2.0", + "slate": ">=0.114.0", + "slate-dom": ">=0.116.0" }, "umdGlobals": { "react": "React", diff --git a/src/chunking/children-helper.ts b/src/chunking/children-helper.ts new file mode 100644 index 0000000..aa3bb61 --- /dev/null +++ b/src/chunking/children-helper.ts @@ -0,0 +1,122 @@ +import { Editor, Descendant } from 'slate' +import { Key } from 'slate-dom' +import { ChunkLeaf } from './types' +import { ReactEditor } from '../plugin/react-editor' + +/** + * Traverse an array of children, providing helpers useful for reconciling the + * children array with a chunk tree + */ +export class ChildrenHelper { + private editor: Editor + private children: Descendant[] + + /** + * Sparse array of Slate node keys, each index corresponding to an index in + * the children array + * + * Fetching the key for a Slate node is expensive, so we cache them here. + */ + private cachedKeys: Array + + /** + * The index of the next node to be read in the children array + */ + public pointerIndex: number + + constructor(editor: Editor, children: Descendant[]) { + this.editor = editor + this.children = children + this.cachedKeys = new Array(children.length) + this.pointerIndex = 0 + } + + /** + * Read a given number of nodes, advancing the pointer by that amount + */ + public read(n: number): Descendant[] { + // PERF: If only one child was requested (the most common case), use array + // indexing instead of slice + if (n === 1) { + return [this.children[this.pointerIndex++]] + } + + const slicedChildren = this.remaining(n) + this.pointerIndex += n + + return slicedChildren + } + + /** + * Get the remaining children without advancing the pointer + * + * @param [maxChildren] Limit the number of children returned. + */ + public remaining(maxChildren?: number): Descendant[] { + if (maxChildren === undefined) { + return this.children.slice(this.pointerIndex) + } + + return this.children.slice( + this.pointerIndex, + this.pointerIndex + maxChildren + ) + } + + /** + * Whether all children have been read + */ + public get reachedEnd() { + return this.pointerIndex >= this.children.length + } + + /** + * Determine whether a node with a given key appears in the unread part of the + * children array, and return its index relative to the current pointer if so + * + * Searching for the node object itself using indexOf is most efficient, but + * will fail to locate nodes that have been modified. In this case, nodes + * should be identified by their keys instead. + * + * Searching an array of keys using indexOf is very inefficient since fetching + * the keys for all children in advance is very slow. Insead, if the node + * search fails to return a value, fetch the keys of each remaining child one + * by one and compare it to the known key. + */ + public lookAhead(node: Descendant, key: Key) { + const elementResult = this.children.indexOf(node, this.pointerIndex) + if (elementResult > -1) return elementResult - this.pointerIndex + + for (let i = this.pointerIndex; i < this.children.length; i++) { + const candidateNode = this.children[i] + const candidateKey = this.findKey(candidateNode, i) + if (candidateKey === key) return i - this.pointerIndex + } + + return -1 + } + + /** + * Convert an array of Slate nodes to an array of chunk leaves, each + * containing the node and its key + */ + public toChunkLeaves(nodes: Descendant[], startIndex: number): ChunkLeaf[] { + return nodes.map((node, i) => ({ + type: 'leaf', + node, + key: this.findKey(node, startIndex + i), + index: startIndex + i, + })) + } + + /** + * Get the key for a Slate node, cached using the node's index + */ + private findKey(node: Descendant, index: number): Key { + const cachedKey = this.cachedKeys[index] + if (cachedKey) return cachedKey + const key = ReactEditor.findKey(this.editor, node) + this.cachedKeys[index] = key + return key + } +} diff --git a/src/chunking/chunk-tree-helper.ts b/src/chunking/chunk-tree-helper.ts new file mode 100644 index 0000000..34bd36a --- /dev/null +++ b/src/chunking/chunk-tree-helper.ts @@ -0,0 +1,574 @@ +import { Path } from 'slate' +import { Key } from 'slate-dom' +import { + Chunk, + ChunkTree, + ChunkLeaf, + ChunkDescendant, + ChunkAncestor, +} from './types' + +type SavedPointer = + | 'start' + | { + chunk: ChunkAncestor + node: ChunkDescendant + } + +export interface ChunkTreeHelperOptions { + chunkSize: number + debug?: boolean +} + +/** + * Traverse and modify a chunk tree + */ +export class ChunkTreeHelper { + /** + * The root of the chunk tree + */ + private root: ChunkTree + + /** + * The ideal size of a chunk + */ + private chunkSize: number + + /** + * Whether debug mode is enabled + * + * If enabled, the pointer state will be checked for internal consistency + * after each mutating operation. + */ + private debug: boolean + + /** + * Whether the traversal has reached the end of the chunk tree + * + * When this is true, the pointerChunk and pointerIndex point to the last + * top-level node in the chunk tree, although pointerNode returns null. + */ + private reachedEnd: boolean + + /** + * The chunk containing the current node + */ + private pointerChunk: ChunkAncestor + + /** + * The index of the current node within pointerChunk + * + * Can be -1 to indicate that the pointer is before the start of the tree. + */ + private pointerIndex: number + + /** + * Similar to a Slate path; tracks the path of pointerChunk relative to the + * root. + * + * Used to move the pointer from the current chunk to the parent chunk more + * efficiently. + */ + private pointerIndexStack: number[] + + /** + * Indexing the current chunk's children has a slight time cost, which adds up + * when traversing very large trees, so the current node is cached. + * + * A value of undefined means that the current node is not cached. This + * property must be set to undefined whenever the pointer is moved, unless + * the pointer is guaranteed to point to the same node that it did previously. + */ + private cachedPointerNode: ChunkDescendant | null | undefined + + constructor( + chunkTree: ChunkTree, + { chunkSize, debug }: ChunkTreeHelperOptions + ) { + this.root = chunkTree + this.chunkSize = chunkSize + // istanbul ignore next + this.debug = debug ?? false + this.pointerChunk = chunkTree + this.pointerIndex = -1 + this.pointerIndexStack = [] + this.reachedEnd = false + this.validateState() + } + + /** + * Move the pointer to the next leaf in the chunk tree + */ + public readLeaf(): ChunkLeaf | null { + // istanbul ignore next + if (this.reachedEnd) return null + + // Get the next sibling or aunt node + while (true) { + if (this.pointerIndex + 1 < this.pointerSiblings.length) { + this.pointerIndex++ + this.cachedPointerNode = undefined + break + } else if (this.pointerChunk.type === 'root') { + this.reachedEnd = true + return null + } else { + this.exitChunk() + } + } + + this.validateState() + + // If the next sibling or aunt is a chunk, descend into it + this.enterChunkUntilLeaf(false) + + return this.pointerNode as ChunkLeaf + } + + /** + * Move the pointer to the previous leaf in the chunk tree + */ + public returnToPreviousLeaf() { + // If we were at the end of the tree, descend into the end of the last + // chunk in the tree + if (this.reachedEnd) { + this.reachedEnd = false + this.enterChunkUntilLeaf(true) + return + } + + // Get the previous sibling or aunt node + while (true) { + if (this.pointerIndex >= 1) { + this.pointerIndex-- + this.cachedPointerNode = undefined + break + } else if (this.pointerChunk.type === 'root') { + this.pointerIndex = -1 + return + } else { + this.exitChunk() + } + } + + this.validateState() + + // If the previous sibling or aunt is a chunk, descend into it + this.enterChunkUntilLeaf(true) + } + + /** + * Insert leaves before the current leaf, leaving the pointer unchanged + */ + public insertBefore(leaves: ChunkLeaf[]) { + this.returnToPreviousLeaf() + this.insertAfter(leaves) + this.readLeaf() + } + + /** + * Insert leaves after the current leaf, leaving the pointer on the last + * inserted leaf + * + * The insertion algorithm first checks for any chunk we're currently at the + * end of that can receive additional leaves. Next, it tries to insert leaves + * at the starts of any subsequent chunks. + * + * Any remaining leaves are passed to rawInsertAfter to be chunked and + * inserted at the highest possible level. + */ + public insertAfter(leaves: ChunkLeaf[]) { + // istanbul ignore next + if (leaves.length === 0) return + + let beforeDepth = 0 + let afterDepth = 0 + + // While at the end of a chunk, insert any leaves that will fit, and then + // exit the chunk + while ( + this.pointerChunk.type === 'chunk' && + this.pointerIndex === this.pointerSiblings.length - 1 + ) { + const remainingCapacity = this.chunkSize - this.pointerSiblings.length + const toInsertCount = Math.min(remainingCapacity, leaves.length) + + if (toInsertCount > 0) { + const leavesToInsert = leaves.splice(0, toInsertCount) + this.rawInsertAfter(leavesToInsert, beforeDepth) + } + + this.exitChunk() + beforeDepth++ + } + + if (leaves.length === 0) return + + // Save the pointer so that we can come back here after inserting leaves + // into the starts of subsequent blocks + const rawInsertPointer = this.savePointer() + + // If leaves are inserted into the start of a subsequent block, then we + // eventually need to restore the pointer to the last such inserted leaf + let finalPointer: SavedPointer | null = null + + // Move the pointer into the chunk containing the next leaf, if it exists + if (this.readLeaf()) { + // While at the start of a chunk, insert any leaves that will fit, and + // then exit the chunk + while (this.pointerChunk.type === 'chunk' && this.pointerIndex === 0) { + const remainingCapacity = this.chunkSize - this.pointerSiblings.length + const toInsertCount = Math.min(remainingCapacity, leaves.length) + + if (toInsertCount > 0) { + const leavesToInsert = leaves.splice(-toInsertCount, toInsertCount) + + // Insert the leaves at the start of the chunk + this.pointerIndex = -1 + this.cachedPointerNode = undefined + this.rawInsertAfter(leavesToInsert, afterDepth) + + // If this is the first batch of insertions at the start of a + // subsequent chunk, set the final pointer to the last inserted leaf + if (!finalPointer) { + finalPointer = this.savePointer() + } + } + + this.exitChunk() + afterDepth++ + } + } + + this.restorePointer(rawInsertPointer) + + // If there are leaves left to insert, insert them between the end of the + // previous chunk and the start of the first subsequent chunk, or wherever + // the pointer ended up after the first batch of insertions + const minDepth = Math.max(beforeDepth, afterDepth) + this.rawInsertAfter(leaves, minDepth) + + if (finalPointer) { + this.restorePointer(finalPointer) + } + + this.validateState() + } + + /** + * Remove the current node and decrement the pointer, deleting any ancestor + * chunk that becomes empty as a result + */ + public remove() { + this.pointerSiblings.splice(this.pointerIndex--, 1) + this.cachedPointerNode = undefined + + if ( + this.pointerSiblings.length === 0 && + this.pointerChunk.type === 'chunk' + ) { + this.exitChunk() + this.remove() + } else { + this.invalidateChunk() + } + + this.validateState() + } + + /** + * Add the current chunk and all ancestor chunks to the list of modified + * chunks + */ + public invalidateChunk() { + for (let c = this.pointerChunk; c.type === 'chunk'; c = c.parent) { + this.root.modifiedChunks.add(c) + } + } + + /** + * Whether the pointer is at the start of the tree + */ + private get atStart() { + return this.pointerChunk.type === 'root' && this.pointerIndex === -1 + } + + /** + * The siblings of the current node + */ + private get pointerSiblings(): ChunkDescendant[] { + return this.pointerChunk.children + } + + /** + * Get the current node (uncached) + * + * If the pointer is at the start or end of the document, returns null. + * + * Usually, the current node is a chunk leaf, although it can be a chunk + * while insertions are in progress. + */ + private getPointerNode(): ChunkDescendant | null { + if (this.reachedEnd || this.pointerIndex === -1) { + return null + } + + return this.pointerSiblings[this.pointerIndex] + } + + /** + * Cached getter for the current node + */ + private get pointerNode(): ChunkDescendant | null { + if (this.cachedPointerNode !== undefined) return this.cachedPointerNode + const pointerNode = this.getPointerNode() + this.cachedPointerNode = pointerNode + return pointerNode + } + + /** + * Get the path of a chunk relative to the root, returning null if the chunk + * is not connected to the root + */ + private getChunkPath(chunk: ChunkAncestor): number[] | null { + const path: number[] = [] + + for (let c = chunk; c.type === 'chunk'; c = c.parent) { + const index = c.parent.children.indexOf(c) + + // istanbul ignore next + if (index === -1) { + return null + } + + path.unshift(index) + } + + return path + } + + /** + * Save the current pointer to be restored later + */ + private savePointer(): SavedPointer { + if (this.atStart) return 'start' + + // istanbul ignore next + if (!this.pointerNode) { + throw new Error('Cannot save pointer when pointerNode is null') + } + + return { + chunk: this.pointerChunk, + node: this.pointerNode, + } + } + + /** + * Restore the pointer to a previous state + */ + private restorePointer(savedPointer: SavedPointer) { + if (savedPointer === 'start') { + this.pointerChunk = this.root + this.pointerIndex = -1 + this.pointerIndexStack = [] + this.reachedEnd = false + this.cachedPointerNode = undefined + return + } + + // Since nodes may have been inserted or removed prior to the saved + // pointer since it was saved, the index and index stack must be + // recomputed. This is slow, but this is fine since restoring a pointer is + // not a frequent operation. + + const { chunk, node } = savedPointer + const index = chunk.children.indexOf(node) + + // istanbul ignore next + if (index === -1) { + throw new Error( + 'Cannot restore point because saved node is no longer in saved chunk' + ) + } + + const indexStack = this.getChunkPath(chunk) + + // istanbul ignore next + if (!indexStack) { + throw new Error( + 'Cannot restore point because saved chunk is no longer connected to root' + ) + } + + this.pointerChunk = chunk + this.pointerIndex = index + this.pointerIndexStack = indexStack + this.reachedEnd = false + this.cachedPointerNode = node + this.validateState() + } + + /** + * Assuming the current node is a chunk, move the pointer into that chunk + * + * @param end If true, place the pointer on the last node of the chunk. + * Otherwise, place the pointer on the first node. + */ + private enterChunk(end: boolean) { + // istanbul ignore next + if (this.pointerNode?.type !== 'chunk') { + throw new Error('Cannot enter non-chunk') + } + + this.pointerIndexStack.push(this.pointerIndex) + this.pointerChunk = this.pointerNode + this.pointerIndex = end ? this.pointerSiblings.length - 1 : 0 + this.cachedPointerNode = undefined + this.validateState() + + // istanbul ignore next + if (this.pointerChunk.children.length === 0) { + throw new Error('Cannot enter empty chunk') + } + } + + /** + * Assuming the current node is a chunk, move the pointer into that chunk + * repeatedly until the current node is a leaf + * + * @param end If true, place the pointer on the last node of the chunk. + * Otherwise, place the pointer on the first node. + */ + private enterChunkUntilLeaf(end: boolean) { + while (this.pointerNode?.type === 'chunk') { + this.enterChunk(end) + } + } + + /** + * Move the pointer to the parent chunk + */ + private exitChunk() { + // istanbul ignore next + if (this.pointerChunk.type === 'root') { + throw new Error('Cannot exit root') + } + + const previousPointerChunk = this.pointerChunk + this.pointerChunk = previousPointerChunk.parent + this.pointerIndex = this.pointerIndexStack.pop()! + this.cachedPointerNode = undefined + this.validateState() + } + + /** + * Insert leaves immediately after the current node, leaving the pointer on + * the last inserted leaf + * + * Leaves are chunked according to the number of nodes already in the parent + * plus the number of nodes being inserted, or the minimum depth if larger + */ + private rawInsertAfter(leaves: ChunkLeaf[], minDepth: number) { + if (leaves.length === 0) return + + const groupIntoChunks = ( + leaves: ChunkLeaf[], + parent: ChunkAncestor, + perChunk: number + ): ChunkDescendant[] => { + if (perChunk === 1) return leaves + const chunks: Chunk[] = [] + + for (let i = 0; i < this.chunkSize; i++) { + const chunkNodes = leaves.slice(i * perChunk, (i + 1) * perChunk) + if (chunkNodes.length === 0) break + + const chunk: Chunk = { + type: 'chunk', + key: new Key(), + parent, + children: [], + } + + chunk.children = groupIntoChunks( + chunkNodes, + chunk, + perChunk / this.chunkSize + ) + chunks.push(chunk) + } + + return chunks + } + + // Determine the chunking depth based on the number of existing nodes in + // the chunk and the number of nodes being inserted + const newTotal = this.pointerSiblings.length + leaves.length + let depthForTotal = 0 + + for (let i = this.chunkSize; i < newTotal; i *= this.chunkSize) { + depthForTotal++ + } + + // A depth of 0 means no chunking + const depth = Math.max(depthForTotal, minDepth) + const perTopLevelChunk = Math.pow(this.chunkSize, depth) + + const chunks = groupIntoChunks(leaves, this.pointerChunk, perTopLevelChunk) + this.pointerSiblings.splice(this.pointerIndex + 1, 0, ...chunks) + this.pointerIndex += chunks.length + this.cachedPointerNode = undefined + this.invalidateChunk() + this.validateState() + } + + /** + * If debug mode is enabled, ensure that the state is internally consistent + */ + // istanbul ignore next + private validateState() { + if (!this.debug) return + + const validateDescendant = (node: ChunkDescendant) => { + if (node.type === 'chunk') { + const { parent, children } = node + + if (!parent.children.includes(node)) { + throw new Error( + `Debug: Chunk ${node.key.id} has an incorrect parent property` + ) + } + + children.forEach(validateDescendant) + } + } + + this.root.children.forEach(validateDescendant) + + if ( + this.cachedPointerNode !== undefined && + this.cachedPointerNode !== this.getPointerNode() + ) { + throw new Error( + 'Debug: The cached pointer is incorrect and has not been invalidated' + ) + } + + const actualIndexStack = this.getChunkPath(this.pointerChunk) + + if (!actualIndexStack) { + throw new Error('Debug: The pointer chunk is not connected to the root') + } + + if (!Path.equals(this.pointerIndexStack, actualIndexStack)) { + throw new Error( + `Debug: The cached index stack [${this.pointerIndexStack.join( + ', ' + )}] does not match the path of the pointer chunk [${actualIndexStack.join( + ', ' + )}]` + ) + } + } +} diff --git a/src/chunking/get-chunk-tree-for-node.ts b/src/chunking/get-chunk-tree-for-node.ts new file mode 100644 index 0000000..fd073b3 --- /dev/null +++ b/src/chunking/get-chunk-tree-for-node.ts @@ -0,0 +1,47 @@ +import { Ancestor, Editor } from 'slate' +import { Key } from 'slate-dom' +import { ChunkTree } from './types' +import { ReconcileOptions, reconcileChildren } from './reconcile-children' +import { ReactEditor } from '../plugin/react-editor' + +export const KEY_TO_CHUNK_TREE = new WeakMap() + +/** + * Get or create the chunk tree for a Slate node + * + * If the reconcile option is provided, the chunk tree will be updated to + * match the current children of the node. The children are chunked + * automatically using the given chunk size. + */ +export const getChunkTreeForNode = ( + editor: Editor, + node: Ancestor, + // istanbul ignore next + options: { + reconcile?: Omit | false + } = {} +) => { + const key = ReactEditor.findKey(editor, node) + let chunkTree = KEY_TO_CHUNK_TREE.get(key) + + if (!chunkTree) { + chunkTree = { + type: 'root', + movedNodeKeys: new Set(), + modifiedChunks: new Set(), + children: [], + } + + KEY_TO_CHUNK_TREE.set(key, chunkTree) + } + + if (options.reconcile) { + reconcileChildren(editor, { + chunkTree, + children: node.children, + ...options.reconcile, + }) + } + + return chunkTree +} diff --git a/src/chunking/index.ts b/src/chunking/index.ts new file mode 100644 index 0000000..ee8ea2a --- /dev/null +++ b/src/chunking/index.ts @@ -0,0 +1,2 @@ +export * from './get-chunk-tree-for-node' +export * from './types' diff --git a/src/chunking/reconcile-children.ts b/src/chunking/reconcile-children.ts new file mode 100644 index 0000000..f8911a1 --- /dev/null +++ b/src/chunking/reconcile-children.ts @@ -0,0 +1,127 @@ +import { Editor, Descendant } from 'slate' +import { ChunkTree, ChunkLeaf } from './types' +import { ChunkTreeHelper, ChunkTreeHelperOptions } from './chunk-tree-helper' +import { ChildrenHelper } from './children-helper' + +export interface ReconcileOptions extends ChunkTreeHelperOptions { + chunkTree: ChunkTree + children: Descendant[] + chunkSize: number + rerenderChildren?: number[] + onInsert?: (node: Descendant, index: number) => void + onUpdate?: (node: Descendant, index: number) => void + onIndexChange?: (node: Descendant, index: number) => void + debug?: boolean +} + +/** + * Update the chunk tree to match the children array, inserting, removing and + * updating differing nodes + */ +export const reconcileChildren = ( + editor: Editor, + { + chunkTree, + children, + chunkSize, + rerenderChildren = [], + onInsert, + onUpdate, + onIndexChange, + debug, + }: ReconcileOptions +) => { + chunkTree.modifiedChunks.clear() + + const chunkTreeHelper = new ChunkTreeHelper(chunkTree, { chunkSize, debug }) + const childrenHelper = new ChildrenHelper(editor, children) + + let treeLeaf: ChunkLeaf | null + + // Read leaves from the tree one by one, each one representing a single Slate + // node. Each leaf from the tree is compared to the current node in the + // children array to determine whether nodes have been inserted, removed or + // updated. + while ((treeLeaf = chunkTreeHelper.readLeaf())) { + // Check where the tree node appears in the children array. In the most + // common case (where no insertions or removals have occurred), this will be + // 0. If the node has been removed, this will be -1. If new nodes have been + // inserted before the node, or if the node has been moved to a later + // position in the same children array, this will be a positive number. + const lookAhead = childrenHelper.lookAhead(treeLeaf.node, treeLeaf.key) + + // If the node was moved, we want to remove it and insert it later, rather + // then re-inserting all intermediate nodes before it. + const wasMoved = lookAhead > 0 && chunkTree.movedNodeKeys.has(treeLeaf.key) + + // If the tree leaf was moved or removed, remove it + if (lookAhead === -1 || wasMoved) { + chunkTreeHelper.remove() + continue + } + + // Get the matching Slate node and any nodes that may have been inserted + // prior to it. Insert these into the chunk tree. + const insertedChildrenStartIndex = childrenHelper.pointerIndex + const insertedChildren = childrenHelper.read(lookAhead + 1) + const matchingChild = insertedChildren.pop()! + + if (insertedChildren.length) { + const leavesToInsert = childrenHelper.toChunkLeaves( + insertedChildren, + insertedChildrenStartIndex + ) + + chunkTreeHelper.insertBefore(leavesToInsert) + + insertedChildren.forEach((node, relativeIndex) => { + onInsert?.(node, insertedChildrenStartIndex + relativeIndex) + }) + } + + const matchingChildIndex = childrenHelper.pointerIndex - 1 + + // Make sure the chunk tree contains the most recent version of the Slate + // node + if (treeLeaf.node !== matchingChild) { + treeLeaf.node = matchingChild + chunkTreeHelper.invalidateChunk() + onUpdate?.(matchingChild, matchingChildIndex) + } + + // Update the index if it has changed + if (treeLeaf.index !== matchingChildIndex) { + treeLeaf.index = matchingChildIndex + onIndexChange?.(matchingChild, matchingChildIndex) + } + + // Manually invalidate chunks containing specific children that we want to + // re-render + if (rerenderChildren.includes(matchingChildIndex)) { + chunkTreeHelper.invalidateChunk() + } + } + + // If there are still Slate nodes remaining from the children array that were + // not matched to nodes in the tree, insert them at the end of the tree + if (!childrenHelper.reachedEnd) { + const remainingChildren = childrenHelper.remaining() + + const leavesToInsert = childrenHelper.toChunkLeaves( + remainingChildren, + childrenHelper.pointerIndex + ) + + // Move the pointer back to the final leaf in the tree, or the start of the + // tree if the tree is currently empty + chunkTreeHelper.returnToPreviousLeaf() + + chunkTreeHelper.insertAfter(leavesToInsert) + + remainingChildren.forEach((node, relativeIndex) => { + onInsert?.(node, childrenHelper.pointerIndex + relativeIndex) + }) + } + + chunkTree.movedNodeKeys.clear() +} diff --git a/src/chunking/types.ts b/src/chunking/types.ts new file mode 100644 index 0000000..b860331 --- /dev/null +++ b/src/chunking/types.ts @@ -0,0 +1,52 @@ +import { Descendant } from 'slate' +import { Key } from 'slate-dom' + +export interface ChunkTree { + type: 'root' + children: ChunkDescendant[] + + /** + * The keys of any Slate nodes that have been moved using move_node since the + * last render + * + * Detecting when a node has been moved to a different position in the + * children array is impossible to do efficiently while reconciling the chunk + * tree. This interferes with the reconciliation logic since it is treated as + * if the intermediate nodes were inserted and removed, causing them to be + * re-chunked unnecessarily. + * + * This set is used to detect when a node has been moved so that this case + * can be handled correctly and efficiently. + */ + movedNodeKeys: Set + + /** + * The chunks whose descendants have been modified during the most recent + * reconciliation + * + * Used to determine when the otherwise memoized React components for each + * chunk should be re-rendered. + */ + modifiedChunks: Set +} + +export interface Chunk { + type: 'chunk' + key: Key + parent: ChunkAncestor + children: ChunkDescendant[] +} + +// A chunk leaf is unrelated to a Slate leaf; it is a leaf of the chunk tree, +// containing a single element that is a child of the Slate node the chunk tree +// belongs to. +export interface ChunkLeaf { + type: 'leaf' + key: Key + node: Descendant + index: number +} + +export type ChunkAncestor = ChunkTree | Chunk +export type ChunkDescendant = Chunk | ChunkLeaf +export type ChunkNode = ChunkTree | Chunk | ChunkLeaf diff --git a/src/components/children.tsx b/src/components/children.tsx deleted file mode 100644 index 53e44fb..0000000 --- a/src/components/children.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react' -import { Editor, Range, Element, NodeEntry, Ancestor, Descendant } from 'slate' - -import ElementComponent from './element' -import TextComponent from './text' -import { ReactEditor } from '..' -import { useEditor } from '../hooks/use-editor' -import { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps' -import { RenderElementProps, RenderLeafProps } from './editable' - -/** - * Children. - */ - -const Children = (props: { - decorate: (entry: NodeEntry) => Range[] - decorations: Range[] - node: Ancestor - renderElement?: (props: RenderElementProps) => JSX.Element - renderLeaf?: (props: RenderLeafProps) => JSX.Element - selection: Range | null - ReactHappyWindow: React.Component | undefined - reactHappyWindowProps: Object | undefined -}) => { - const { - decorate, - decorations, - node, - renderElement, - renderLeaf, - selection, - ReactHappyWindow, - reactHappyWindowProps = {}, - } = props - const editor = useEditor() - const path = ReactEditor.findPath(editor, node) - const children = [] - const isLeafBlock = - Element.isElement(node) && - !editor.isInline(node) && - Editor.hasInlines(editor, node) - - const renderChild = (i: number) => { - const p = path.concat(i) - const n = node.children[i] as Descendant - const key = ReactEditor.findKey(editor, n) - const range = Editor.range(editor, p) - const sel = selection && Range.intersection(range, selection) - - // Commented out to improve performance. We don't use decorations - // const ds = decorate([n, p]) - const ds = [] as Range[] - // for (const dec of decorations) { - // const d = Range.intersection(dec, range) - - // if (d) { - // ds.push(d) - // } - // } - - NODE_TO_INDEX.set(n, i) - NODE_TO_PARENT.set(n, node) - - if (Element.isElement(n)) { - return ( - - ) - } else { - return ( - - ) - } - } - - if (ReactHappyWindow) { - return ( - - ) - } - - for (let i = 0; i < node.children.length; i++) { - children.push(renderChild(i)) - } - - return {children} -} - -export default Children diff --git a/src/components/chunk-tree.tsx b/src/components/chunk-tree.tsx new file mode 100644 index 0000000..d55b8c0 --- /dev/null +++ b/src/components/chunk-tree.tsx @@ -0,0 +1,65 @@ +import React, { Fragment } from 'react' +import { Element } from 'slate' +import { Key } from 'slate-dom' +import { RenderChunkProps } from './editable' +import { + Chunk as TChunk, + ChunkAncestor as TChunkAncestor, + ChunkTree as TChunkTree, +} from '../chunking' + +const defaultRenderChunk = ({ children }: RenderChunkProps) => children + +const ChunkAncestor = (props: { + root: TChunkTree + ancestor: C + renderElement: (node: Element, index: number, key: Key) => JSX.Element + renderChunk?: (props: RenderChunkProps) => JSX.Element +}) => { + const { + root, + ancestor, + renderElement, + renderChunk = defaultRenderChunk, + } = props + + return ancestor.children.map(chunkNode => { + if (chunkNode.type === 'chunk') { + const key = chunkNode.key.id + + const renderedChunk = renderChunk({ + highest: ancestor === root, + lowest: chunkNode.children.some(c => c.type === 'leaf'), + attributes: { 'data-slate-chunk': true }, + children: ( + + ), + }) + + return {renderedChunk} + } + + // Only blocks containing no inlines are chunked + const element = chunkNode.node as Element + + return renderElement(element, chunkNode.index, chunkNode.key) + }) +} + +const ChunkTree = ChunkAncestor + +const MemoizedChunk = React.memo( + ChunkAncestor, + (prev, next) => + prev.root === next.root && + prev.renderElement === next.renderElement && + prev.renderChunk === next.renderChunk && + !next.root.modifiedChunks.has(next.ancestor) +) + +export default ChunkTree diff --git a/src/components/editable.tsx b/src/components/editable.tsx index 34d0dc7..3774a83 100644 --- a/src/components/editable.tsx +++ b/src/components/editable.tsx @@ -1,41 +1,89 @@ -import React, { useEffect, useRef, useMemo, useCallback } from 'react' +import getDirection from 'direction' +import debounce from 'lodash/debounce' +import throttle from 'lodash/throttle' +import React, { + useCallback, + useEffect, + useMemo, + useReducer, + useRef, + useState, + forwardRef, + ForwardedRef, +} from 'react' +import { JSX } from 'react' +import scrollIntoView from 'scroll-into-view-if-needed' import { Editor, Element, - NodeEntry, Node, + NodeEntry, + Path, Range, Text, Transforms, + DecoratedRange, + LeafPosition, } from 'slate' -import getDirection from 'direction' -import debounce from 'debounce' -import scrollIntoView from 'scroll-into-view-if-needed' - -import Children from './children' -import Hotkeys from '../utils/hotkeys' -import { IS_FIREFOX, IS_SAFARI } from '../utils/environment' -import { ReactEditor } from '..' +import { useAndroidInputManager } from '../hooks/android-input-manager/use-android-input-manager' +import useChildren from '../hooks/use-children' +import { DecorateContext, useDecorateContext } from '../hooks/use-decorations' +import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect' import { ReadOnlyContext } from '../hooks/use-read-only' import { useSlate } from '../hooks/use-slate' -import { useIsomorphicLayoutEffect } from '../hooks/use-isomorphic-layout-effect' +import { useTrackUserInput } from '../hooks/use-track-user-input' +import { ReactEditor } from '../plugin/react-editor' +import { TRIPLE_CLICK } from 'slate-dom' import { DOMElement, - DOMNode, DOMRange, + DOMText, + getActiveElement, + getDefaultView, + getSelection, isDOMElement, isDOMNode, - isDOMText, - DOMStaticRange, -} from '../utils/dom' + isPlainTextOnlyPaste, +} from 'slate-dom' import { + CAN_USE_DOM, + HAS_BEFORE_INPUT_SUPPORT, + IS_ANDROID, + IS_CHROME, + IS_FIREFOX, + IS_FIREFOX_LEGACY, + IS_IOS, + IS_WEBKIT, + IS_UC_MOBILE, + IS_WECHATBROWSER, +} from 'slate-dom' +import { Hotkeys } from 'slate-dom' +import { + IS_NODE_MAP_DIRTY, EDITOR_TO_ELEMENT, + EDITOR_TO_FORCE_RENDER, + EDITOR_TO_PENDING_INSERTION_MARKS, + EDITOR_TO_USER_MARKS, + EDITOR_TO_USER_SELECTION, + EDITOR_TO_WINDOW, ELEMENT_TO_NODE, + IS_COMPOSING, + IS_FOCUSED, IS_READ_ONLY, + MARK_PLACEHOLDER_SYMBOL, NODE_TO_ELEMENT, - IS_FOCUSED, PLACEHOLDER_SYMBOL, -} from '../utils/weak-maps' +} from 'slate-dom' +import { RestoreDOM } from './restore-dom/restore-dom' +import { AndroidInputManager } from '../hooks/android-input-manager/android-input-manager' +import { ComposingContext } from '../hooks/use-composing' +import { useFlushDeferredSelectorsOnRender } from '../hooks/use-slate-selector' + +type DeferredOperation = () => void + +const Children = (props: Parameters[0]) => ( + {useChildren(props)} +) /** * `RenderElementProps` are passed to the `renderElement` handler. @@ -53,17 +101,49 @@ export interface RenderElementProps { } } +/** + * `RenderChunkProps` are passed to the `renderChunk` handler + */ +export interface RenderChunkProps { + highest: boolean + lowest: boolean + children: any + attributes: { + 'data-slate-chunk': true + } +} + /** * `RenderLeafProps` are passed to the `renderLeaf` handler. */ export interface RenderLeafProps { children: any + /** + * The leaf node with any applied decorations. + * If no decorations are applied, it will be identical to the `text` property. + */ leaf: Text text: Text attributes: { 'data-slate-leaf': true } + /** + * The position of the leaf within the Text node, only present when the text node is split by decorations. + */ + leafPosition?: LeafPosition +} + +/** + * `RenderTextProps` are passed to the `renderText` handler. + */ +export interface RenderTextProps { + text: Text + children: any + attributes: { + 'data-slate-node': 'text' + ref: any + } } /** @@ -71,1082 +151,1902 @@ export interface RenderLeafProps { */ export type EditableProps = { - decorate?: (entry: NodeEntry) => Range[] - onDOMBeforeInput?: (event: Event) => void + decorate?: (entry: NodeEntry) => DecoratedRange[] + onDOMBeforeInput?: (event: InputEvent) => void placeholder?: string readOnly?: boolean role?: string style?: React.CSSProperties renderElement?: (props: RenderElementProps) => JSX.Element + renderChunk?: (props: RenderChunkProps) => JSX.Element renderLeaf?: (props: RenderLeafProps) => JSX.Element + renderText?: (props: RenderTextProps) => JSX.Element + renderPlaceholder?: (props: RenderPlaceholderProps) => JSX.Element + scrollSelectionIntoView?: (editor: ReactEditor, domRange: DOMRange) => void as?: React.ElementType - ReactHappyWindow?: React.Component - reactHappyWindowProps?: object + disableDefaultStyles?: boolean } & React.TextareaHTMLAttributes /** * Editable. */ -export const Editable = (props: EditableProps) => { - const { - autoFocus, - decorate = defaultDecorate, - onDOMBeforeInput: propsOnDOMBeforeInput, - placeholder, - readOnly = false, - renderElement, - renderLeaf, - style = {}, - as: Component = 'div', - ReactHappyWindow, - reactHappyWindowProps, - happyWindowRef, - ...attributes - } = props - const editor = useSlate() - const ref = useRef(null) - - // Update internal state on each render. - IS_READ_ONLY.set(editor, readOnly) - - // Keep track of some state for the event handler logic. - const state = useMemo( - () => ({ - isComposing: false, - isUpdatingSelection: false, - latestElement: null as DOMElement | null, - }), - [] - ) +export const Editable = forwardRef( + (props: EditableProps, forwardedRef: ForwardedRef) => { + const defaultRenderPlaceholder = useCallback( + (props: RenderPlaceholderProps) => , + [] + ) + const { + autoFocus, + decorate = defaultDecorate, + onDOMBeforeInput: propsOnDOMBeforeInput, + placeholder, + readOnly = false, + renderElement, + renderChunk, + renderLeaf, + renderText, + renderPlaceholder = defaultRenderPlaceholder, + scrollSelectionIntoView = defaultScrollSelectionIntoView, + style: userStyle = {}, + as: Component = 'div', + disableDefaultStyles = false, + ...attributes + } = props + const editor = useSlate() + // Rerender editor when composition status changed + const [isComposing, setIsComposing] = useState(false) + const ref = useRef(null) + const deferredOperations = useRef([]) + const [placeholderHeight, setPlaceholderHeight] = useState< + number | undefined + >() + const processing = useRef(false) + + const { onUserInput, receivedUserInput } = useTrackUserInput() + + const [, forceRender] = useReducer(s => s + 1, 0) + EDITOR_TO_FORCE_RENDER.set(editor, forceRender) + + // Update internal state on each render. + IS_READ_ONLY.set(editor, readOnly) + + // Keep track of some state for the event handler logic. + const state = useMemo( + () => ({ + isDraggingInternally: false, + isUpdatingSelection: false, + latestElement: null as DOMElement | null, + hasMarkPlaceholder: false, + }), + [] + ) + + // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it + // needs to be manually focused. + // + // If this stops working in Firefox, make sure nothing is causing this + // component to re-render during the initial mount. If the DOM selection is + // set by `useIsomorphicLayoutEffect` before `onDOMSelectionChange` updates + // `editor.selection`, the DOM selection can be removed accidentally. + useEffect(() => { + if (ref.current && autoFocus) { + ref.current.focus() + } + }, [autoFocus]) + + /** + * The AndroidInputManager object has a cyclical dependency on onDOMSelectionChange + * + * It is defined as a reference to simplify hook dependencies and clarify that + * it needs to be initialized. + */ + const androidInputManagerRef = useRef< + AndroidInputManager | null | undefined + >() + + // Listen on the native `selectionchange` event to be able to update any time + // the selection changes. This is required because React's `onSelect` is leaky + // and non-standard so it doesn't fire until after a selection has been + // released. This causes issues in situations where another change happens + // while a selection is being dragged. + const onDOMSelectionChange = useMemo( + () => + throttle(() => { + if (IS_NODE_MAP_DIRTY.get(editor)) { + onDOMSelectionChange() + return + } - // Update element-related weak maps with the DOM element ref. - useIsomorphicLayoutEffect(() => { - if (ref.current) { - EDITOR_TO_ELEMENT.set(editor, ref.current) - NODE_TO_ELEMENT.set(editor, ref.current) - ELEMENT_TO_NODE.set(ref.current, editor) - } else { - NODE_TO_ELEMENT.delete(editor) - } - }) - - // Attach a native DOM event handler for `selectionchange`, because React's - // built-in `onSelect` handler doesn't fire for all selection changes. It's a - // leaky polyfill that only fires on keypresses or clicks. Instead, we want to - // fire for any change to the selection inside the editor. (2019/11/04) - // https://github.com/facebook/react/issues/5785 - useIsomorphicLayoutEffect(() => { - window.document.addEventListener('selectionchange', onDOMSelectionChange) - - return () => { - window.document.removeEventListener( - 'selectionchange', - onDOMSelectionChange - ) - } - }, []) - - // Attach a native DOM event handler for `beforeinput` events, because React's - // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose - // real `beforeinput` events sadly... (2019/11/04) - // https://github.com/facebook/react/issues/11211 - useIsomorphicLayoutEffect(() => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.addEventListener('beforeinput', onDOMBeforeInput) - } + const el = ReactEditor.toDOMNode(editor, editor) + const root = el.getRootNode() - return () => { - if (ref.current) { - // @ts-ignore The `beforeinput` event isn't recognized. - ref.current.removeEventListener('beforeinput', onDOMBeforeInput) - } - } - }, []) + if (!processing.current && IS_WEBKIT && root instanceof ShadowRoot) { + processing.current = true - // Whenever the editor updates, make sure the DOM selection state is in sync. - useIsomorphicLayoutEffect(() => { - const { selection } = editor - const domSelection = window.getSelection() + const active = getActiveElement() - if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) { - return - } + if (active) { + document.execCommand('indent') + } else { + Transforms.deselect(editor) + } - const hasDomSelection = domSelection.type !== 'None' + processing.current = false + return + } - // If the DOM selection is properly unset, we're done. - if (!selection && !hasDomSelection) { - return - } + const androidInputManager = androidInputManagerRef.current + if ( + (IS_ANDROID || !ReactEditor.isComposing(editor)) && + (!state.isUpdatingSelection || androidInputManager?.isFlushing()) && + !state.isDraggingInternally + ) { + const root = ReactEditor.findDocumentOrShadowRoot(editor) + const { activeElement } = root + const el = ReactEditor.toDOMNode(editor, editor) + const domSelection = getSelection(root) - const newDomRange = selection && ReactEditor.toDOMRange(editor, selection) + if (activeElement === el) { + state.latestElement = activeElement + IS_FOCUSED.set(editor, true) + } else { + IS_FOCUSED.delete(editor) + } - // If the DOM selection is already correct, we're done. - if ( - hasDomSelection && - newDomRange && - isRangeEqual(domSelection.getRangeAt(0), newDomRange) - ) { - return - } + if (!domSelection) { + return Transforms.deselect(editor) + } - // Otherwise the DOM selection is out of sync, so update it. - const el = ReactEditor.toDOMNode(editor, editor) - state.isUpdatingSelection = true - domSelection.removeAllRanges() + const { anchorNode, focusNode } = domSelection - if (newDomRange) { - domSelection.addRange(newDomRange!) - const leafEl = newDomRange.startContainer.parentElement! - scrollIntoView(leafEl, { scrollMode: 'if-needed' }) - } + const anchorNodeSelectable = + ReactEditor.hasEditableTarget(editor, anchorNode) || + ReactEditor.isTargetInsideNonReadonlyVoid(editor, anchorNode) - setTimeout(() => { - // COMPAT: In Firefox, it's not enough to create a range, you also need - // to focus the contenteditable element too. (2016/11/16) - if (newDomRange && IS_FIREFOX) { - el.focus() - } + const focusNodeInEditor = ReactEditor.hasTarget(editor, focusNode) + + if (anchorNodeSelectable && focusNodeInEditor) { + const range = ReactEditor.toSlateRange(editor, domSelection, { + exactMatch: false, + suppressThrow: true, + }) + + if (range) { + if ( + !ReactEditor.isComposing(editor) && + !androidInputManager?.hasPendingChanges() && + !androidInputManager?.isFlushing() + ) { + Transforms.select(editor, range) + } else { + androidInputManager?.handleUserSelect(range) + } + } + } - state.isUpdatingSelection = false + // Deselect the editor if the dom selection is not selectable in readonly mode + if (readOnly && (!anchorNodeSelectable || !focusNodeInEditor)) { + Transforms.deselect(editor) + } + } + }, 100), + [editor, readOnly, state] + ) + + const scheduleOnDOMSelectionChange = useMemo( + () => debounce(onDOMSelectionChange, 0), + [onDOMSelectionChange] + ) + + androidInputManagerRef.current = useAndroidInputManager({ + node: ref, + onDOMSelectionChange, + scheduleOnDOMSelectionChange, }) - }) - // The autoFocus TextareaHTMLAttribute doesn't do anything on a div, so it - // needs to be manually focused. - useEffect(() => { - if (ref.current && autoFocus) { - ref.current.focus() - } - }, [autoFocus]) - - // Listen on the native `beforeinput` event to get real "Level 2" events. This - // is required because React's `beforeinput` is fake and never really attaches - // to the real event sadly. (2019/11/01) - // https://github.com/facebook/react/issues/11211 - const onDOMBeforeInput = useCallback( - ( - event: Event & { - data: string | null - dataTransfer: DataTransfer | null - getTargetRanges(): DOMStaticRange[] - inputType: string - isComposing: boolean + useIsomorphicLayoutEffect(() => { + // Update element-related weak maps with the DOM element ref. + let window + if (ref.current && (window = getDefaultView(ref.current))) { + EDITOR_TO_WINDOW.set(editor, window) + EDITOR_TO_ELEMENT.set(editor, ref.current) + NODE_TO_ELEMENT.set(editor, ref.current) + ELEMENT_TO_NODE.set(ref.current, editor) + } else { + NODE_TO_ELEMENT.delete(editor) } - ) => { + + // Make sure the DOM selection state is in sync. + const { selection } = editor + const root = ReactEditor.findDocumentOrShadowRoot(editor) + const domSelection = getSelection(root) + if ( - !readOnly && - hasEditableTarget(editor, event.target) && - !isDOMEventHandled(event, propsOnDOMBeforeInput) + !domSelection || + !ReactEditor.isFocused(editor) || + androidInputManagerRef.current?.hasPendingAction() ) { - const { selection } = editor - const { inputType: type } = event - const data = event.dataTransfer || event.data || undefined + return + } + + const setDomSelection = (forceChange?: boolean) => { + const hasDomSelection = domSelection.type !== 'None' - // These two types occur while a user is composing text and can't be - // cancelled. Let them through and wait for the composition to end. + // If the DOM selection is properly unset, we're done. + if (!selection && !hasDomSelection) { + return + } + + // Get anchorNode and focusNode + const focusNode = domSelection.focusNode + let anchorNode + + // COMPAT: In firefox the normal selection way does not work + // (https://github.com/ianstormtaylor/slate/pull/5486#issue-1820720223) + if (IS_FIREFOX && domSelection.rangeCount > 1) { + const firstRange = domSelection.getRangeAt(0) + const lastRange = domSelection.getRangeAt(domSelection.rangeCount - 1) + + // Right to left + if (firstRange.startContainer === focusNode) { + anchorNode = lastRange.endContainer + } else { + // Left to right + anchorNode = firstRange.startContainer + } + } else { + anchorNode = domSelection.anchorNode + } + + // verify that the dom selection is in the editor + const editorElement = EDITOR_TO_ELEMENT.get(editor)! + let hasDomSelectionInEditor = false if ( - type === 'insertCompositionText' || - type === 'deleteCompositionText' + editorElement.contains(anchorNode) && + editorElement.contains(focusNode) ) { - return + hasDomSelectionInEditor = true } - event.preventDefault() + // If the DOM selection is in the editor and the editor selection is already correct, we're done. + if ( + hasDomSelection && + hasDomSelectionInEditor && + selection && + !forceChange + ) { + const slateRange = ReactEditor.toSlateRange(editor, domSelection, { + exactMatch: true, - // COMPAT: For the deleting forward/backward input types we don't want - // to change the selection because it is the range that will be deleted, - // and those commands determine that for themselves. - if (!type.startsWith('delete') || type.startsWith('deleteBy')) { - const [targetRange] = event.getTargetRanges() + // domSelection is not necessarily a valid Slate range + // (e.g. when clicking on contentEditable:false element) + suppressThrow: true, + }) - if (targetRange) { - const range = ReactEditor.toSlateRange(editor, targetRange) - if (!range) { + if (slateRange && Range.equals(slateRange, selection)) { + if (!state.hasMarkPlaceholder) { return } - if (!selection || !Range.equals(selection, range)) { - Transforms.select(editor, range) + + // Ensure selection is inside the mark placeholder + if ( + anchorNode?.parentElement?.hasAttribute( + 'data-slate-mark-placeholder' + ) + ) { + return } } } - // COMPAT: If the selection is expanded, even if the command seems like - // a delete forward/backward command it should delete the selection. - if ( - selection && - Range.isExpanded(selection) && - type.startsWith('delete') - ) { - Editor.deleteFragment(editor) + // when is being controlled through external value + // then its children might just change - DOM responds to it on its own + // but Slate's value is not being updated through any operation + // and thus it doesn't transform selection on its own + if (selection && !ReactEditor.hasRange(editor, selection)) { + editor.selection = ReactEditor.toSlateRange(editor, domSelection, { + exactMatch: false, + suppressThrow: true, + }) return } - switch (type) { - case 'deleteByComposition': - case 'deleteByCut': - case 'deleteByDrag': { - Editor.deleteFragment(editor) - break - } + // Otherwise the DOM selection is out of sync, so update it. + state.isUpdatingSelection = true - case 'deleteContent': - case 'deleteContentForward': { - Editor.deleteForward(editor) - break - } + let newDomRange: DOMRange | null = null - case 'deleteContentBackward': { - Editor.deleteBackward(editor) - break - } - - case 'deleteEntireSoftLine': { - Editor.deleteBackward(editor, { unit: 'line' }) - Editor.deleteForward(editor, { unit: 'line' }) - break - } + try { + newDomRange = selection && ReactEditor.toDOMRange(editor, selection) + } catch (e) { + // Ignore, dom and state might be out of sync + } - case 'deleteHardLineBackward': { - Editor.deleteBackward(editor, { unit: 'block' }) - break + if (newDomRange) { + if (ReactEditor.isComposing(editor) && !IS_ANDROID) { + domSelection.collapseToEnd() + } else if (Range.isBackward(selection!)) { + domSelection.setBaseAndExtent( + newDomRange.endContainer, + newDomRange.endOffset, + newDomRange.startContainer, + newDomRange.startOffset + ) + } else { + domSelection.setBaseAndExtent( + newDomRange.startContainer, + newDomRange.startOffset, + newDomRange.endContainer, + newDomRange.endOffset + ) } + scrollSelectionIntoView(editor, newDomRange) + } else { + domSelection.removeAllRanges() + } - case 'deleteSoftLineBackward': { - Editor.deleteBackward(editor, { unit: 'line' }) - break - } + return newDomRange + } - case 'deleteHardLineForward': { - Editor.deleteForward(editor, { unit: 'block' }) - break - } + // In firefox if there is more then 1 range and we call setDomSelection we remove the ability to select more cells in a table + if (domSelection.rangeCount <= 1) { + setDomSelection() + } - case 'deleteSoftLineForward': { - Editor.deleteForward(editor, { unit: 'line' }) - break - } + const ensureSelection = + androidInputManagerRef.current?.isFlushing() === 'action' - case 'deleteWordBackward': { - Editor.deleteBackward(editor, { unit: 'word' }) - break - } + if (!IS_ANDROID || !ensureSelection) { + setTimeout(() => { + state.isUpdatingSelection = false + }) + return + } - case 'deleteWordForward': { - Editor.deleteForward(editor, { unit: 'word' }) - break - } + let timeoutId: ReturnType | null = null + const animationFrameId = requestAnimationFrame(() => { + if (ensureSelection) { + const ensureDomSelection = (forceChange?: boolean) => { + try { + const el = ReactEditor.toDOMNode(editor, editor) + el.focus() - case 'insertLineBreak': - case 'insertParagraph': { - Editor.insertBreak(editor) - break + setDomSelection(forceChange) + } catch (e) { + // Ignore, dom and state might be out of sync + } } - case 'insertFromComposition': - case 'insertFromDrop': - case 'insertFromPaste': - case 'insertFromYank': - case 'insertReplacementText': - case 'insertText': { - if (data instanceof DataTransfer) { - ReactEditor.insertData(editor, data) - } else if (typeof data === 'string') { - Editor.insertText(editor, data) - } + // Compat: Android IMEs try to force their selection by manually re-applying it even after we set it. + // This essentially would make setting the slate selection during an update meaningless, so we force it + // again here. We can't only do it in the setTimeout after the animation frame since that would cause a + // visible flicker. + ensureDomSelection() + + timeoutId = setTimeout(() => { + // COMPAT: While setting the selection in an animation frame visually correctly sets the selection, + // it doesn't update GBoards spellchecker state. We have to manually trigger a selection change after + // the animation frame to ensure it displays the correct state. + ensureDomSelection(true) + state.isUpdatingSelection = false + }) + } + }) - break - } + return () => { + cancelAnimationFrame(animationFrameId) + if (timeoutId) { + clearTimeout(timeoutId) } } - }, - [] - ) + }) - // Listen on the native `selectionchange` event to be able to update any time - // the selection changes. This is required because React's `onSelect` is leaky - // and non-standard so it doesn't fire until after a selection has been - // released. This causes issues in situations where another change happens - // while a selection is being dragged. - const onDOMSelectionChange = useCallback( - debounce(() => { - if (!readOnly && !state.isComposing && !state.isUpdatingSelection) { - const { activeElement } = window.document + // Listen on the native `beforeinput` event to get real "Level 2" events. This + // is required because React's `beforeinput` is fake and never really attaches + // to the real event sadly. (2019/11/01) + // https://github.com/facebook/react/issues/11211 + const onDOMBeforeInput = useCallback( + (event: InputEvent) => { + handleNativeHistoryEvents(editor, event) const el = ReactEditor.toDOMNode(editor, editor) - const domSelection = window.getSelection() - const domRange = - domSelection && - domSelection.rangeCount > 0 && - domSelection.getRangeAt(0) - - if (activeElement === el) { - state.latestElement = activeElement - IS_FOCUSED.set(editor, true) - } else { - IS_FOCUSED.delete(editor) + const root = el.getRootNode() + + if (processing?.current && IS_WEBKIT && root instanceof ShadowRoot) { + const ranges = event.getTargetRanges() + const range = ranges[0] + + const newRange = new window.Range() + + newRange.setStart(range.startContainer, range.startOffset) + newRange.setEnd(range.endContainer, range.endOffset) + + // Translate the DOM Range into a Slate Range + const slateRange = ReactEditor.toSlateRange(editor, newRange, { + exactMatch: false, + suppressThrow: false, + }) + + Transforms.select(editor, slateRange) + + event.preventDefault() + event.stopImmediatePropagation() + return } + onUserInput() if ( - domRange && - hasEditableTarget(editor, domRange.startContainer) && - hasEditableTarget(editor, domRange.endContainer) + !readOnly && + ReactEditor.hasEditableTarget(editor, event.target) && + !isDOMEventHandled(event, propsOnDOMBeforeInput) ) { - const range = ReactEditor.toSlateRange(editor, domRange) - Transforms.select(editor, range) - } else { - Transforms.deselect(editor) - } - } - }, 100), - [] - ) + // COMPAT: BeforeInput events aren't cancelable on android, so we have to handle them differently using the android input manager. + if (androidInputManagerRef.current) { + return androidInputManagerRef.current.handleDOMBeforeInput(event) + } - const decorations = decorate([editor, []]) + // Some IMEs/Chrome extensions like e.g. Grammarly set the selection immediately before + // triggering a `beforeinput` expecting the change to be applied to the immediately before + // set selection. + scheduleOnDOMSelectionChange.flush() + onDOMSelectionChange.flush() - if ( - placeholder && - editor.children.length === 1 && - Array.from(Node.texts(editor)).length === 1 && - Node.string(editor) === '' - ) { - const start = Editor.start(editor, []) - decorations.push({ - [PLACEHOLDER_SYMBOL]: true, - placeholder, - anchor: start, - focus: start, - }) - } + const { selection } = editor + const { inputType: type } = event + const data = (event as any).dataTransfer || event.data || undefined - return ( - - { - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to React's leaky polyfill instead just for it. It - // only works for the `insertText` input type. - if (IS_FIREFOX && !readOnly && ReactEditor.isFocused(editor)) { - event.preventDefault() - const text = (event as any).data as string - Editor.insertText(editor, text) - } - }, - [readOnly] - )} - onBlur={useCallback( - (event: React.FocusEvent) => { - if ( - readOnly || - state.isUpdatingSelection || - !hasEditableTarget(editor, event.target) || - isEventHandled(event, attributes.onBlur) - ) { - return - } + const isCompositionChange = + type === 'insertCompositionText' || type === 'deleteCompositionText' - // COMPAT: If the current `activeElement` is still the previous - // one, this is due to the window being blurred when the tab - // itself becomes unfocused, so we want to abort early to allow to - // editor to stay focused when the tab becomes focused again. - if (state.latestElement === window.document.activeElement) { - return + // COMPAT: use composition change events as a hint to where we should insert + // composition text if we aren't composing to work around https://github.com/ianstormtaylor/slate/issues/5038 + if (isCompositionChange && ReactEditor.isComposing(editor)) { + return + } + + let native = false + if ( + type === 'insertText' && + selection && + Range.isCollapsed(selection) && + // Only use native character insertion for single characters a-z or space for now. + // Long-press events (hold a + press 4 = ä) to choose a special character otherwise + // causes duplicate inserts. + event.data && + event.data.length === 1 && + /[a-z ]/i.test(event.data) && + // Chrome has issues correctly editing the start of nodes: https://bugs.chromium.org/p/chromium/issues/detail?id=1249405 + // When there is an inline element, e.g. a link, and you select + // right after it (the start of the next node). + selection.anchor.offset !== 0 + ) { + native = true + + // Skip native if there are marks, as + // `insertText` will insert a node, not just text. + if (editor.marks) { + native = false } - const { relatedTarget } = event - const el = ReactEditor.toDOMNode(editor, editor) + // If the NODE_MAP is dirty, we can't trust the selection anchor (eg ReactEditor.toDOMPoint) + if (!IS_NODE_MAP_DIRTY.get(editor)) { + // Chrome also has issues correctly editing the end of anchor elements: https://bugs.chromium.org/p/chromium/issues/detail?id=1259100 + // Therefore we don't allow native events to insert text at the end of anchor nodes. + const { anchor } = selection - // COMPAT: The event should be ignored if the focus is returning - // to the editor from an embedded editable element (eg. an - // element inside a void node). - if (relatedTarget === el) { - return - } + const [node, offset] = ReactEditor.toDOMPoint(editor, anchor) + const anchorNode = node.parentElement?.closest('a') - // COMPAT: The event should be ignored if the focus is moving from - // the editor to inside a void node's spacer element. - if ( - isDOMElement(relatedTarget) && - relatedTarget.hasAttribute('data-slate-spacer') - ) { - return - } + const window = ReactEditor.getWindow(editor) - // COMPAT: The event should be ignored if the focus is moving to a - // non- editable section of an element that isn't a void node (eg. - // a list item of the check list example). - if ( - relatedTarget != null && - isDOMNode(relatedTarget) && - ReactEditor.hasDOMNode(editor, relatedTarget) - ) { - const node = ReactEditor.toSlateNode(editor, relatedTarget) + if ( + native && + anchorNode && + ReactEditor.hasDOMNode(editor, anchorNode) + ) { + // Find the last text node inside the anchor. + const lastText = window?.document + .createTreeWalker(anchorNode, NodeFilter.SHOW_TEXT) + .lastChild() as DOMText | null - if (Element.isElement(node) && !editor.isVoid(node)) { - return + if ( + lastText === node && + lastText.textContent?.length === offset + ) { + native = false + } } - } - IS_FOCUSED.delete(editor) - }, - [readOnly, attributes.onBlur] - )} - onClick={useCallback( - (event: React.MouseEvent) => { - if ( - !readOnly && - hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onClick) && - isDOMNode(event.target) - ) { - const node = ReactEditor.toSlateNode(editor, event.target) - const path = ReactEditor.findPath(editor, node) - const start = Editor.start(editor, path) + // Chrome has issues with the presence of tab characters inside elements with whiteSpace = 'pre' + // causing abnormal insert behavior: https://bugs.chromium.org/p/chromium/issues/detail?id=1219139 + if ( + native && + node.parentElement && + window?.getComputedStyle(node.parentElement)?.whiteSpace === + 'pre' + ) { + const block = Editor.above(editor, { + at: anchor.path, + match: n => Element.isElement(n) && Editor.isBlock(editor, n), + }) - if (Editor.void(editor, { at: start })) { - const range = Editor.range(editor, start) - Transforms.select(editor, range) - } - } - }, - [readOnly, attributes.onClick] - )} - onCompositionEnd={useCallback( - (event: React.CompositionEvent) => { - if ( - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionEnd) - ) { - state.isComposing = false - - // COMPAT: In Chrome, `beforeinput` events for compositions - // aren't correct and never fire the "insertFromComposition" - // type that we need. So instead, insert whenever a composition - // ends since it will already have been committed to the DOM. - if (!IS_SAFARI && !IS_FIREFOX && event.data) { - Editor.insertText(editor, event.data) + if (block && Node.string(block[0]).includes('\t')) { + native = false + } } } - }, - [attributes.onCompositionEnd] - )} - onCompositionStart={useCallback( - (event: React.CompositionEvent) => { - if ( - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCompositionStart) - ) { - state.isComposing = true - } - }, - [attributes.onCompositionStart] - )} - onCopy={useCallback( - (event: React.ClipboardEvent) => { - if ( - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCopy) - ) { - event.preventDefault() - setFragmentData(event.clipboardData, editor) - } - }, - [attributes.onCopy] - )} - onCut={useCallback( - (event: React.ClipboardEvent) => { - if ( - !readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onCut) - ) { - event.preventDefault() - setFragmentData(event.clipboardData, editor) - const { selection } = editor + } + // COMPAT: For the deleting forward/backward input types we don't want + // to change the selection because it is the range that will be deleted, + // and those commands determine that for themselves. + // If the NODE_MAP is dirty, we can't trust the selection anchor (eg ReactEditor.toDOMPoint via ReactEditor.toSlateRange) + if ( + (!type.startsWith('delete') || type.startsWith('deleteBy')) && + !IS_NODE_MAP_DIRTY.get(editor) + ) { + const [targetRange] = (event as any).getTargetRanges() + + if (targetRange) { + const range = ReactEditor.toSlateRange(editor, targetRange, { + exactMatch: false, + suppressThrow: false, + }) + + if (!selection || !Range.equals(selection, range)) { + native = false + + const selectionRef = + !isCompositionChange && + editor.selection && + Editor.rangeRef(editor, editor.selection) + + Transforms.select(editor, range) - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor) + if (selectionRef) { + EDITOR_TO_USER_SELECTION.set(editor, selectionRef) + } } } - }, - [readOnly, attributes.onCut] - )} - onDragOver={useCallback( - (event: React.DragEvent) => { - if ( - hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragOver) - ) { - // Only when the target is void, call `preventDefault` to signal - // that drops are allowed. Editable content is droppable by - // default, and calling `preventDefault` hides the cursor. - const node = ReactEditor.toSlateNode(editor, event.target) + } - if (Editor.isVoid(editor, node)) { - event.preventDefault() - } + // Composition change types occur while a user is composing text and can't be + // cancelled. Let them through and wait for the composition to end. + if (isCompositionChange) { + return + } + + if (!native) { + event.preventDefault() + } + + // COMPAT: If the selection is expanded, even if the command seems like + // a delete forward/backward command it should delete the selection. + if ( + selection && + Range.isExpanded(selection) && + type.startsWith('delete') + ) { + const direction = type.endsWith('Backward') ? 'backward' : 'forward' + Editor.deleteFragment(editor, { direction }) + return + } + + switch (type) { + case 'deleteByComposition': + case 'deleteByCut': + case 'deleteByDrag': { + Editor.deleteFragment(editor) + break } - }, - [attributes.onDragOver] - )} - onDragStart={useCallback( - (event: React.DragEvent) => { - if ( - hasTarget(editor, event.target) && - !isEventHandled(event, attributes.onDragStart) - ) { - const node = ReactEditor.toSlateNode(editor, event.target) - const path = ReactEditor.findPath(editor, node) - const voidMatch = Editor.void(editor, { at: path }) - - // If starting a drag on a void node, make sure it is selected - // so that it shows up in the selection's fragment. - if (voidMatch) { - const range = Editor.range(editor, path) - Transforms.select(editor, range) - } - setFragmentData(event.dataTransfer, editor) + case 'deleteContent': + case 'deleteContentForward': { + Editor.deleteForward(editor) + break } - }, - [attributes.onDragStart] - )} - onDrop={useCallback( - (event: React.DragEvent) => { - if ( - hasTarget(editor, event.target) && - !readOnly && - !isEventHandled(event, attributes.onDrop) - ) { - // COMPAT: Firefox doesn't fire `beforeinput` events at all, and - // Chromium browsers don't properly fire them for files being - // dropped into a `contenteditable`. (2019/11/26) - // https://bugs.chromium.org/p/chromium/issues/detail?id=1028668 - if ( - IS_FIREFOX || - (!IS_SAFARI && event.dataTransfer.files.length > 0) - ) { - event.preventDefault() - const range = ReactEditor.findEventRange(editor, event) - const data = event.dataTransfer - Transforms.select(editor, range) - ReactEditor.insertData(editor, data) - } + + case 'deleteContentBackward': { + Editor.deleteBackward(editor) + break } - }, - [readOnly, attributes.onDrop] - )} - onFocus={useCallback( - (event: React.FocusEvent) => { - if ( - !readOnly && - !state.isUpdatingSelection && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onFocus) - ) { - const el = ReactEditor.toDOMNode(editor, editor) - state.latestElement = window.document.activeElement - - // COMPAT: If the editor has nested editable elements, the focus - // can go to them. In Firefox, this must be prevented because it - // results in issues with keyboard navigation. (2017/03/30) - if (IS_FIREFOX && event.target !== el) { - el.focus() - return - } - IS_FOCUSED.set(editor, true) + case 'deleteEntireSoftLine': { + Editor.deleteBackward(editor, { unit: 'line' }) + Editor.deleteForward(editor, { unit: 'line' }) + break } - }, - [readOnly, attributes.onFocus] - )} - onKeyDown={useCallback( - (event: React.KeyboardEvent) => { - if ( - !readOnly && - hasEditableTarget(editor, event.target) && - !isEventHandled(event, attributes.onKeyDown) - ) { - const { nativeEvent } = event - const { selection } = editor - - const element = - editor.children[ - selection !== null ? selection.focus.path[0] : 0 - ] - const isRTL = getDirection(Node.string(element)) === 'rtl' - - // COMPAT: Since we prevent the default behavior on - // `beforeinput` events, the browser doesn't think there's ever - // any history stack to undo or redo, so we have to manage these - // hotkeys ourselves. (2019/11/06) - if (Hotkeys.isRedo(nativeEvent)) { - event.preventDefault() - - if (editor.redo) { - editor.redo() - } - return - } + case 'deleteHardLineBackward': { + Editor.deleteBackward(editor, { unit: 'block' }) + break + } - if (Hotkeys.isUndo(nativeEvent)) { - event.preventDefault() + case 'deleteSoftLineBackward': { + Editor.deleteBackward(editor, { unit: 'line' }) + break + } - if (editor.undo) { - editor.undo() - } + case 'deleteHardLineForward': { + Editor.deleteForward(editor, { unit: 'block' }) + break + } - return - } + case 'deleteSoftLineForward': { + Editor.deleteForward(editor, { unit: 'line' }) + break + } - // COMPAT: Certain browsers don't handle the selection updates - // properly. In Chrome, the selection isn't properly extended. - // And in Firefox, the selection isn't properly collapsed. - // (2017/10/17) - if (Hotkeys.isMoveLineBackward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { unit: 'line', reverse: true }) - return - } + case 'deleteWordBackward': { + Editor.deleteBackward(editor, { unit: 'word' }) + break + } - if (Hotkeys.isMoveLineForward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { unit: 'line' }) - return - } + case 'deleteWordForward': { + Editor.deleteForward(editor, { unit: 'word' }) + break + } - if (Hotkeys.isExtendLineBackward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { - unit: 'line', - edge: 'focus', - reverse: true, - }) - return - } + case 'insertLineBreak': + Editor.insertSoftBreak(editor) + break - if (Hotkeys.isExtendLineForward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { unit: 'line', edge: 'focus' }) - return - } + case 'insertParagraph': { + Editor.insertBreak(editor) + break + } - // COMPAT: If a void node is selected, or a zero-width text node - // adjacent to an inline is selected, we need to handle these - // hotkeys manually because browsers won't be able to skip over - // the void node with the zero-width space not being an empty - // string. - if (Hotkeys.isMoveBackward(nativeEvent)) { - event.preventDefault() - - if (selection && Range.isCollapsed(selection)) { - const { anchor } = selection - if (anchor.offset === 1 && anchor.path[1] > 0) { - // Hack to position the cursor at the end of the previous text node - Transforms.move(editor, { reverse: !isRTL, distance: 2 }) - Transforms.move(editor, { reverse: isRTL }) - } else { - Transforms.move(editor, { reverse: !isRTL }) - } - } else { - Transforms.collapse(editor, { edge: 'start' }) + case 'insertFromComposition': + case 'insertFromDrop': + case 'insertFromPaste': + case 'insertFromYank': + case 'insertReplacementText': + case 'insertText': { + if (type === 'insertFromComposition') { + // COMPAT: in Safari, `compositionend` is dispatched after the + // `beforeinput` for "insertFromComposition". But if we wait for it + // then we will abort because we're still composing and the selection + // won't be updated properly. + // https://www.w3.org/TR/input-events-2/ + if (ReactEditor.isComposing(editor)) { + setIsComposing(false) + IS_COMPOSING.set(editor, false) } - - return } - if (Hotkeys.isMoveForward(nativeEvent)) { - event.preventDefault() - - if (selection && Range.isCollapsed(selection)) { - Transforms.move(editor, { reverse: isRTL }) + // use a weak comparison instead of 'instanceof' to allow + // programmatic access of paste events coming from external windows + // like cypress where cy.window does not work realibly + if (data?.constructor.name === 'DataTransfer') { + ReactEditor.insertData(editor, data) + } else if (typeof data === 'string') { + // Only insertText operations use the native functionality, for now. + // Potentially expand to single character deletes, as well. + if (native) { + deferredOperations.current.push(() => + Editor.insertText(editor, data) + ) } else { - Transforms.collapse(editor, { edge: 'end' }) + Editor.insertText(editor, data) } - - return } - if (Hotkeys.isMoveWordBackward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { unit: 'word', reverse: !isRTL }) - return - } - - if (Hotkeys.isMoveWordForward(nativeEvent)) { - event.preventDefault() - Transforms.move(editor, { unit: 'word', reverse: isRTL }) - return - } - - // COMPAT: Firefox doesn't support the `beforeinput` event, so we - // fall back to guessing at the input intention for hotkeys. - // COMPAT: In iOS, some of these hotkeys are handled in the - if (IS_FIREFOX) { - // We don't have a core behavior for these, but they change the - // DOM if we don't prevent them, so we have to. - if ( - Hotkeys.isBold(nativeEvent) || - Hotkeys.isItalic(nativeEvent) || - Hotkeys.isTransposeCharacter(nativeEvent) - ) { - event.preventDefault() - return - } + break + } + } - if (Hotkeys.isSplitBlock(nativeEvent)) { - event.preventDefault() - Editor.insertBreak(editor) - return - } + // Restore the actual user section if nothing manually set it. + const toRestore = EDITOR_TO_USER_SELECTION.get(editor)?.unref() + EDITOR_TO_USER_SELECTION.delete(editor) - if (Hotkeys.isDeleteBackward(nativeEvent)) { - event.preventDefault() + if ( + toRestore && + (!editor.selection || !Range.equals(editor.selection, toRestore)) + ) { + Transforms.select(editor, toRestore) + } + } + }, + [ + editor, + onDOMSelectionChange, + onUserInput, + propsOnDOMBeforeInput, + readOnly, + scheduleOnDOMSelectionChange, + ] + ) + + const callbackRef = useCallback( + (node: HTMLDivElement | null) => { + if (node == null) { + onDOMSelectionChange.cancel() + scheduleOnDOMSelectionChange.cancel() + + EDITOR_TO_ELEMENT.delete(editor) + NODE_TO_ELEMENT.delete(editor) + + if (ref.current && HAS_BEFORE_INPUT_SUPPORT) { + // @ts-ignore The `beforeinput` event isn't recognized. + ref.current.removeEventListener('beforeinput', onDOMBeforeInput) + } + } else { + // Attach a native DOM event handler for `beforeinput` events, because React's + // built-in `onBeforeInput` is actually a leaky polyfill that doesn't expose + // real `beforeinput` events sadly... (2019/11/04) + // https://github.com/facebook/react/issues/11211 + if (HAS_BEFORE_INPUT_SUPPORT) { + // @ts-ignore The `beforeinput` event isn't recognized. + node.addEventListener('beforeinput', onDOMBeforeInput) + } + } - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor) - } else { - Editor.deleteBackward(editor) - } + ref.current = node + if (typeof forwardedRef === 'function') { + forwardedRef(node) + } else if (forwardedRef) { + forwardedRef.current = node + } + }, + [ + onDOMSelectionChange, + scheduleOnDOMSelectionChange, + editor, + onDOMBeforeInput, + forwardedRef, + ] + ) + + useIsomorphicLayoutEffect(() => { + const window = ReactEditor.getWindow(editor) + + // COMPAT: In Chrome, `selectionchange` events can fire when and + //