@lexical/react 0.5.0 → 0.5.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,103 @@ var reactDom = require('react-dom');
14
14
  var dragon = require('@lexical/dragon');
15
15
  var plainText = require('@lexical/plain-text');
16
16
 
17
+ /**
18
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE file in the root directory of this source tree.
22
+ *
23
+ */
24
+
25
+ const changedArray = (a = [], b = []) => a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
26
+
27
+ const initialState = {
28
+ error: null
29
+ };
30
+
31
+ class ErrorBoundary extends React.Component {
32
+ constructor(props) {
33
+ super(props);
34
+ this.state = initialState;
35
+ this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
36
+ }
37
+
38
+ static getDerivedStateFromError(error) {
39
+ return {
40
+ error
41
+ };
42
+ }
43
+
44
+ resetErrorBoundary(...args) {
45
+ // @ts-ignore
46
+ // eslint-disable-next-line no-unused-expressions
47
+ this.props.onReset && this.props.onReset(...args);
48
+ this.reset();
49
+ }
50
+
51
+ reset() {
52
+ this.setState(initialState);
53
+ }
54
+
55
+ componentDidCatch(error, info) {
56
+ // @ts-ignore
57
+ // eslint-disable-next-line no-unused-expressions
58
+ this.props.onError && this.props.onError(error, info);
59
+ }
60
+
61
+ componentDidUpdate(prevProps, prevState) {
62
+ const {
63
+ error
64
+ } = this.state;
65
+ const {
66
+ resetKeys
67
+ } = this.props; // There's an edge case where if the thing that triggered the error
68
+ // happens to *also* be in the resetKeys array, we'd end up resetting
69
+ // the error boundary immediately. This would likely trigger a second
70
+ // error to be thrown.
71
+ // So we make sure that we don't check the resetKeys on the first call
72
+ // of cDU after the error is set
73
+
74
+ if (error !== null && prevState.error !== null && changedArray(prevProps.resetKeys, resetKeys)) {
75
+ // @ts-ignore
76
+ // eslint-disable-next-line no-unused-expressions
77
+ this.props.onResetKeysChange && this.props.onResetKeysChange(prevProps.resetKeys, resetKeys);
78
+ this.reset();
79
+ }
80
+ }
81
+
82
+ render() {
83
+ const {
84
+ error
85
+ } = this.state;
86
+ const {
87
+ fallbackRender,
88
+ FallbackComponent,
89
+ fallback
90
+ } = this.props;
91
+
92
+ if (error !== null) {
93
+ const props = {
94
+ error,
95
+ resetErrorBoundary: this.resetErrorBoundary
96
+ };
97
+
98
+ if ( /*#__PURE__*/React.isValidElement(fallback)) {
99
+ return fallback;
100
+ } else if (typeof fallbackRender === 'function') {
101
+ return fallbackRender(props);
102
+ } else if (FallbackComponent) {
103
+ return /*#__PURE__*/React.createElement(FallbackComponent, props);
104
+ } else {
105
+ throw new Error('react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop');
106
+ }
107
+ }
108
+
109
+ return this.props.children;
110
+ }
111
+
112
+ }
113
+
17
114
  /**
18
115
  * Copyright (c) Meta Platforms, Inc. and affiliates.
19
116
  *
@@ -71,7 +168,14 @@ function useCanShowPlaceholder(editor) {
71
168
  * LICENSE file in the root directory of this source tree.
72
169
  *
73
170
  */
74
- function useDecorators(editor) {
171
+ function useDecorators(editor, // TODO 0.6 Make non-optional non-default
172
+ ErrorBoundary$1 = ({
173
+ children,
174
+ onError
175
+ }) => /*#__PURE__*/React.createElement(ErrorBoundary, {
176
+ fallback: null,
177
+ onError: onError
178
+ }, children)) {
75
179
  const [decorators, setDecorators] = React.useState(() => editor.getDecorators()); // Subscribe to changes
76
180
 
77
181
  useLayoutEffect(() => {
@@ -94,7 +198,11 @@ function useDecorators(editor) {
94
198
 
95
199
  for (let i = 0; i < decoratorKeys.length; i++) {
96
200
  const nodeKey = decoratorKeys[i];
97
- const reactDecorator = decorators[nodeKey];
201
+ const reactDecorator = /*#__PURE__*/React.createElement(ErrorBoundary$1, {
202
+ onError: e => editor._onError(e)
203
+ }, /*#__PURE__*/React.createElement(React.Suspense, {
204
+ fallback: null
205
+ }, decorators[nodeKey]));
98
206
  const element = editor.getElementByKey(nodeKey);
99
207
 
100
208
  if (element !== null) {
@@ -103,7 +211,7 @@ function useDecorators(editor) {
103
211
  }
104
212
 
105
213
  return decoratedPortals;
106
- }, [decorators, editor]);
214
+ }, [ErrorBoundary$1, decorators, editor]);
107
215
  }
108
216
 
109
217
  /**
@@ -129,11 +237,19 @@ function usePlainTextSetup(editor) {
129
237
  */
130
238
  function PlainTextPlugin({
131
239
  contentEditable,
132
- placeholder
240
+ placeholder,
241
+ // TODO 0.6 Make non-optional non-default
242
+ ErrorBoundary: ErrorBoundary$1 = ({
243
+ children,
244
+ onError
245
+ }) => /*#__PURE__*/React.createElement(ErrorBoundary, {
246
+ fallback: null,
247
+ onError: onError
248
+ }, children)
133
249
  }) {
134
250
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
135
251
  const showPlaceholder = useCanShowPlaceholder(editor);
136
- const decorators = useDecorators(editor);
252
+ const decorators = useDecorators(editor, ErrorBoundary$1);
137
253
  usePlainTextSetup(editor);
138
254
  return /*#__PURE__*/React.createElement(React.Fragment, null, contentEditable, showPlaceholder && placeholder, decorators);
139
255
  }
@@ -7,6 +7,7 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
+ import type {ErrorBoundaryType} from './DEPRECATED_useLexicalDecorators';
10
11
  import type {EditorState, LexicalEditor} from 'lexical';
11
12
 
12
13
  type InitialEditorStateType =
@@ -18,4 +19,6 @@ type InitialEditorStateType =
18
19
  declare export function PlainTextPlugin({
19
20
  contentEditable: React$Node,
20
21
  placeholder: React$Node,
22
+ // TODO 0.6 Make non-optional non-default
23
+ ErrorBoundary?: ErrorBoundaryType,
21
24
  }): React$Node;
@@ -4,7 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- 'use strict';var c=require("@lexical/react/LexicalComposerContext"),h=require("react"),l=require("@lexical/text"),m=require("@lexical/utils"),n=require("react-dom"),p=require("@lexical/dragon"),q=require("@lexical/plain-text"),r="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;function t(a){return a.getEditorState().read(l.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}
8
- function u(a){let [e,d]=h.useState(()=>t(a));r(()=>{function b(){let f=t(a);d(f)}b();return m.mergeRegister(a.registerUpdateListener(()=>{b()}),a.registerEditableListener(()=>{b()}))},[a]);return e}
9
- function v(a){let [e,d]=h.useState(()=>a.getDecorators());r(()=>a.registerDecoratorListener(b=>{n.flushSync(()=>{d(b)})}),[a]);h.useEffect(()=>{d(a.getDecorators())},[a]);return h.useMemo(()=>{let b=[],f=Object.keys(e);for(let k=0;k<f.length;k++){var g=f[k];let w=e[g];g=a.getElementByKey(g);null!==g&&b.push(n.createPortal(w,g))}return b},[e,a])}function x(a){r(()=>m.mergeRegister(q.registerPlainText(a),p.registerDragonSupport(a)),[a])}
10
- exports.PlainTextPlugin=function({contentEditable:a,placeholder:e}){let [d]=c.useLexicalComposerContext(),b=u(d),f=v(d);x(d);return h.createElement(h.Fragment,null,a,b&&e,f)}
7
+ 'use strict';var d=require("@lexical/react/LexicalComposerContext"),h=require("react"),l=require("@lexical/text"),m=require("@lexical/utils"),n=require("react-dom"),p=require("@lexical/dragon"),q=require("@lexical/plain-text");let t=(a=[],e=[])=>a.length!==e.length||a.some((c,b)=>!Object.is(c,e[b])),u={error:null};
8
+ class v extends h.Component{constructor(a){super(a);this.state=u;this.resetErrorBoundary=this.resetErrorBoundary.bind(this)}static getDerivedStateFromError(a){return{error:a}}resetErrorBoundary(...a){this.props.onReset&&this.props.onReset(...a);this.reset()}reset(){this.setState(u)}componentDidCatch(a,e){this.props.onError&&this.props.onError(a,e)}componentDidUpdate(a,e){let {error:c}=this.state,{resetKeys:b}=this.props;null!==c&&null!==e.error&&t(a.resetKeys,b)&&(this.props.onResetKeysChange&&this.props.onResetKeysChange(a.resetKeys,
9
+ b),this.reset())}render(){var {error:a}=this.state;let {fallbackRender:e,FallbackComponent:c,fallback:b}=this.props;if(null!==a){a={error:a,resetErrorBoundary:this.resetErrorBoundary};if(h.isValidElement(b))return b;if("function"===typeof e)return e(a);if(c)return h.createElement(c,a);throw Error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop");}return this.props.children}}
10
+ var w="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;function x(a){return a.getEditorState().read(l.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}function y(a){let [e,c]=h.useState(()=>x(a));w(()=>{function b(){let f=x(a);c(f)}b();return m.mergeRegister(a.registerUpdateListener(()=>{b()}),a.registerEditableListener(()=>{b()}))},[a]);return e}
11
+ function z(a,e=({children:c,onError:b})=>h.createElement(v,{fallback:null,onError:b},c)){let [c,b]=h.useState(()=>a.getDecorators());w(()=>a.registerDecoratorListener(f=>{n.flushSync(()=>{b(f)})}),[a]);h.useEffect(()=>{b(a.getDecorators())},[a]);return h.useMemo(()=>{let f=[],r=Object.keys(c);for(let k=0;k<r.length;k++){var g=r[k];let B=h.createElement(e,{onError:A=>a._onError(A)},h.createElement(h.Suspense,{fallback:null},c[g]));g=a.getElementByKey(g);null!==g&&f.push(n.createPortal(B,g))}return f},
12
+ [e,c,a])}function C(a){w(()=>m.mergeRegister(q.registerPlainText(a),p.registerDragonSupport(a)),[a])}exports.PlainTextPlugin=function({contentEditable:a,placeholder:e,ErrorBoundary:c=({children:b,onError:f})=>h.createElement(v,{fallback:null,onError:f},b)}){let [b]=d.useLexicalComposerContext(),f=y(b);c=z(b,c);C(b);return h.createElement(h.Fragment,null,a,f&&e,c)}
@@ -5,7 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- export declare function RichTextPlugin({ contentEditable, placeholder, }: Readonly<{
8
+ import { ErrorBoundaryType } from './shared/useDecorators';
9
+ export declare function RichTextPlugin({ contentEditable, placeholder, ErrorBoundary, }: Readonly<{
9
10
  contentEditable: JSX.Element;
10
11
  placeholder: JSX.Element | string;
12
+ ErrorBoundary?: ErrorBoundaryType;
11
13
  }>): JSX.Element;
@@ -14,6 +14,103 @@ var reactDom = require('react-dom');
14
14
  var dragon = require('@lexical/dragon');
15
15
  var richText = require('@lexical/rich-text');
16
16
 
17
+ /**
18
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE file in the root directory of this source tree.
22
+ *
23
+ */
24
+
25
+ const changedArray = (a = [], b = []) => a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
26
+
27
+ const initialState = {
28
+ error: null
29
+ };
30
+
31
+ class ErrorBoundary extends React.Component {
32
+ constructor(props) {
33
+ super(props);
34
+ this.state = initialState;
35
+ this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
36
+ }
37
+
38
+ static getDerivedStateFromError(error) {
39
+ return {
40
+ error
41
+ };
42
+ }
43
+
44
+ resetErrorBoundary(...args) {
45
+ // @ts-ignore
46
+ // eslint-disable-next-line no-unused-expressions
47
+ this.props.onReset && this.props.onReset(...args);
48
+ this.reset();
49
+ }
50
+
51
+ reset() {
52
+ this.setState(initialState);
53
+ }
54
+
55
+ componentDidCatch(error, info) {
56
+ // @ts-ignore
57
+ // eslint-disable-next-line no-unused-expressions
58
+ this.props.onError && this.props.onError(error, info);
59
+ }
60
+
61
+ componentDidUpdate(prevProps, prevState) {
62
+ const {
63
+ error
64
+ } = this.state;
65
+ const {
66
+ resetKeys
67
+ } = this.props; // There's an edge case where if the thing that triggered the error
68
+ // happens to *also* be in the resetKeys array, we'd end up resetting
69
+ // the error boundary immediately. This would likely trigger a second
70
+ // error to be thrown.
71
+ // So we make sure that we don't check the resetKeys on the first call
72
+ // of cDU after the error is set
73
+
74
+ if (error !== null && prevState.error !== null && changedArray(prevProps.resetKeys, resetKeys)) {
75
+ // @ts-ignore
76
+ // eslint-disable-next-line no-unused-expressions
77
+ this.props.onResetKeysChange && this.props.onResetKeysChange(prevProps.resetKeys, resetKeys);
78
+ this.reset();
79
+ }
80
+ }
81
+
82
+ render() {
83
+ const {
84
+ error
85
+ } = this.state;
86
+ const {
87
+ fallbackRender,
88
+ FallbackComponent,
89
+ fallback
90
+ } = this.props;
91
+
92
+ if (error !== null) {
93
+ const props = {
94
+ error,
95
+ resetErrorBoundary: this.resetErrorBoundary
96
+ };
97
+
98
+ if ( /*#__PURE__*/React.isValidElement(fallback)) {
99
+ return fallback;
100
+ } else if (typeof fallbackRender === 'function') {
101
+ return fallbackRender(props);
102
+ } else if (FallbackComponent) {
103
+ return /*#__PURE__*/React.createElement(FallbackComponent, props);
104
+ } else {
105
+ throw new Error('react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop');
106
+ }
107
+ }
108
+
109
+ return this.props.children;
110
+ }
111
+
112
+ }
113
+
17
114
  /**
18
115
  * Copyright (c) Meta Platforms, Inc. and affiliates.
19
116
  *
@@ -71,7 +168,14 @@ function useCanShowPlaceholder(editor) {
71
168
  * LICENSE file in the root directory of this source tree.
72
169
  *
73
170
  */
74
- function useDecorators(editor) {
171
+ function useDecorators(editor, // TODO 0.6 Make non-optional non-default
172
+ ErrorBoundary$1 = ({
173
+ children,
174
+ onError
175
+ }) => /*#__PURE__*/React.createElement(ErrorBoundary, {
176
+ fallback: null,
177
+ onError: onError
178
+ }, children)) {
75
179
  const [decorators, setDecorators] = React.useState(() => editor.getDecorators()); // Subscribe to changes
76
180
 
77
181
  useLayoutEffect(() => {
@@ -94,7 +198,11 @@ function useDecorators(editor) {
94
198
 
95
199
  for (let i = 0; i < decoratorKeys.length; i++) {
96
200
  const nodeKey = decoratorKeys[i];
97
- const reactDecorator = decorators[nodeKey];
201
+ const reactDecorator = /*#__PURE__*/React.createElement(ErrorBoundary$1, {
202
+ onError: e => editor._onError(e)
203
+ }, /*#__PURE__*/React.createElement(React.Suspense, {
204
+ fallback: null
205
+ }, decorators[nodeKey]));
98
206
  const element = editor.getElementByKey(nodeKey);
99
207
 
100
208
  if (element !== null) {
@@ -103,7 +211,7 @@ function useDecorators(editor) {
103
211
  }
104
212
 
105
213
  return decoratedPortals;
106
- }, [decorators, editor]);
214
+ }, [ErrorBoundary$1, decorators, editor]);
107
215
  }
108
216
 
109
217
  /**
@@ -129,11 +237,19 @@ function useRichTextSetup(editor) {
129
237
  */
130
238
  function RichTextPlugin({
131
239
  contentEditable,
132
- placeholder
240
+ placeholder,
241
+ // TODO 0.6 Make non-optional non-default
242
+ ErrorBoundary: ErrorBoundary$1 = ({
243
+ children,
244
+ onError
245
+ }) => /*#__PURE__*/React.createElement(ErrorBoundary, {
246
+ fallback: null,
247
+ onError: onError
248
+ }, children)
133
249
  }) {
134
250
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
135
251
  const showPlaceholder = useCanShowPlaceholder(editor);
136
- const decorators = useDecorators(editor);
252
+ const decorators = useDecorators(editor, ErrorBoundary$1);
137
253
  useRichTextSetup(editor);
138
254
  return /*#__PURE__*/React.createElement(React.Fragment, null, contentEditable, showPlaceholder && placeholder, decorators);
139
255
  }
@@ -7,6 +7,7 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
+ import type {ErrorBoundaryType} from './DEPRECATED_useLexicalDecorators';
10
11
  import type {EditorState, LexicalEditor} from 'lexical';
11
12
 
12
13
  type InitialEditorStateType =
@@ -18,4 +19,6 @@ type InitialEditorStateType =
18
19
  declare export function RichTextPlugin({
19
20
  contentEditable: React$Node,
20
21
  placeholder: React$Node,
22
+ // TODO 0.6 Make non-optional non-default
23
+ ErrorBoundary?: ErrorBoundaryType,
21
24
  }): React$Node;
@@ -4,7 +4,9 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- 'use strict';var c=require("@lexical/react/LexicalComposerContext"),h=require("react"),l=require("@lexical/text"),m=require("@lexical/utils"),n=require("react-dom"),p=require("@lexical/dragon"),q=require("@lexical/rich-text"),r="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;function t(a){return a.getEditorState().read(l.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}
8
- function u(a){let [e,d]=h.useState(()=>t(a));r(()=>{function b(){let f=t(a);d(f)}b();return m.mergeRegister(a.registerUpdateListener(()=>{b()}),a.registerEditableListener(()=>{b()}))},[a]);return e}
9
- function v(a){let [e,d]=h.useState(()=>a.getDecorators());r(()=>a.registerDecoratorListener(b=>{n.flushSync(()=>{d(b)})}),[a]);h.useEffect(()=>{d(a.getDecorators())},[a]);return h.useMemo(()=>{let b=[],f=Object.keys(e);for(let k=0;k<f.length;k++){var g=f[k];let w=e[g];g=a.getElementByKey(g);null!==g&&b.push(n.createPortal(w,g))}return b},[e,a])}function x(a){r(()=>m.mergeRegister(q.registerRichText(a),p.registerDragonSupport(a)),[a])}
10
- exports.RichTextPlugin=function({contentEditable:a,placeholder:e}){let [d]=c.useLexicalComposerContext(),b=u(d),f=v(d);x(d);return h.createElement(h.Fragment,null,a,b&&e,f)}
7
+ 'use strict';var d=require("@lexical/react/LexicalComposerContext"),h=require("react"),l=require("@lexical/text"),m=require("@lexical/utils"),n=require("react-dom"),p=require("@lexical/dragon"),q=require("@lexical/rich-text");let t=(a=[],e=[])=>a.length!==e.length||a.some((c,b)=>!Object.is(c,e[b])),u={error:null};
8
+ class v extends h.Component{constructor(a){super(a);this.state=u;this.resetErrorBoundary=this.resetErrorBoundary.bind(this)}static getDerivedStateFromError(a){return{error:a}}resetErrorBoundary(...a){this.props.onReset&&this.props.onReset(...a);this.reset()}reset(){this.setState(u)}componentDidCatch(a,e){this.props.onError&&this.props.onError(a,e)}componentDidUpdate(a,e){let {error:c}=this.state,{resetKeys:b}=this.props;null!==c&&null!==e.error&&t(a.resetKeys,b)&&(this.props.onResetKeysChange&&this.props.onResetKeysChange(a.resetKeys,
9
+ b),this.reset())}render(){var {error:a}=this.state;let {fallbackRender:e,FallbackComponent:c,fallback:b}=this.props;if(null!==a){a={error:a,resetErrorBoundary:this.resetErrorBoundary};if(h.isValidElement(b))return b;if("function"===typeof e)return e(a);if(c)return h.createElement(c,a);throw Error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop");}return this.props.children}}
10
+ var w="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?h.useLayoutEffect:h.useEffect;function x(a){return a.getEditorState().read(l.$canShowPlaceholderCurry(a.isComposing(),a.isEditable()))}function y(a){let [e,c]=h.useState(()=>x(a));w(()=>{function b(){let f=x(a);c(f)}b();return m.mergeRegister(a.registerUpdateListener(()=>{b()}),a.registerEditableListener(()=>{b()}))},[a]);return e}
11
+ function z(a,e=({children:c,onError:b})=>h.createElement(v,{fallback:null,onError:b},c)){let [c,b]=h.useState(()=>a.getDecorators());w(()=>a.registerDecoratorListener(f=>{n.flushSync(()=>{b(f)})}),[a]);h.useEffect(()=>{b(a.getDecorators())},[a]);return h.useMemo(()=>{let f=[],r=Object.keys(c);for(let k=0;k<r.length;k++){var g=r[k];let B=h.createElement(e,{onError:A=>a._onError(A)},h.createElement(h.Suspense,{fallback:null},c[g]));g=a.getElementByKey(g);null!==g&&f.push(n.createPortal(B,g))}return f},
12
+ [e,c,a])}function C(a){w(()=>m.mergeRegister(q.registerRichText(a),p.registerDragonSupport(a)),[a])}exports.RichTextPlugin=function({contentEditable:a,placeholder:e,ErrorBoundary:c=({children:b,onError:f})=>h.createElement(v,{fallback:null,onError:f},b)}){let [b]=d.useLexicalComposerContext(),f=y(b);c=z(b,c);C(b);return h.createElement(h.Fragment,null,a,f&&e,c)}
@@ -8,6 +8,7 @@
8
8
 
9
9
  var link = require('@lexical/link');
10
10
  var mark = require('@lexical/mark');
11
+ var utils = require('@lexical/utils');
11
12
  var lexical = require('lexical');
12
13
  var React = require('react');
13
14
 
@@ -47,19 +48,20 @@ function TreeView({
47
48
  const inputRef = React.useRef(null);
48
49
  const [isPlaying, setIsPlaying] = React.useState(false);
49
50
  React.useEffect(() => {
50
- setContent(generateContent(editor.getEditorState()));
51
- return editor.registerUpdateListener(({
51
+ setContent(generateContent(editor.getEditorState(), editor._config, editor._compositionKey, editor._editable));
52
+ return utils.mergeRegister(editor.registerUpdateListener(({
52
53
  editorState
53
54
  }) => {
54
- const compositionKey = editor._compositionKey;
55
- const treeText = generateContent(editor.getEditorState());
56
- const compositionText = compositionKey !== null && `Composition key: ${compositionKey}`;
57
- setContent([treeText, compositionText].filter(Boolean).join('\n\n'));
55
+ const treeText = generateContent(editor.getEditorState(), editor._config, editor._compositionKey, editor._editable);
56
+ setContent(treeText);
58
57
 
59
58
  if (!timeTravelEnabled) {
60
59
  setTimeStampedEditorStates(currentEditorStates => [...currentEditorStates, [Date.now(), editorState]]);
61
60
  }
62
- });
61
+ }), editor.registerEditableListener(() => {
62
+ const treeText = generateContent(editor.getEditorState(), editor._config, editor._compositionKey, editor._editable);
63
+ setContent(treeText);
64
+ }));
63
65
  }, [timeTravelEnabled, editor]);
64
66
  const totalEditorStates = timeStampedEditorStates.length;
65
67
  React.useEffect(() => {
@@ -130,6 +132,10 @@ function TreeView({
130
132
  }, /*#__PURE__*/React.createElement("button", {
131
133
  className: timeTravelPanelButtonClassName,
132
134
  onClick: () => {
135
+ if (playingIndexRef.current === totalEditorStates - 1) {
136
+ playingIndexRef.current = 1;
137
+ }
138
+
133
139
  setIsPlaying(!isPlaying);
134
140
  },
135
141
  type: "button"
@@ -193,7 +199,7 @@ function printGridSelection(selection) {
193
199
  return `: grid\n └ { grid: ${selection.gridKey}, anchorCell: ${selection.anchor.key}, focusCell: ${selection.focus.key} }`;
194
200
  }
195
201
 
196
- function generateContent(editorState) {
202
+ function generateContent(editorState, editorConfig, compositionKey, editable) {
197
203
  let res = ' root\n';
198
204
  const selectionString = editorState.read(() => {
199
205
  const selection = lexical.$getSelection();
@@ -215,7 +221,16 @@ function generateContent(editorState) {
215
221
  });
216
222
  return selection === null ? ': null' : lexical.$isRangeSelection(selection) ? printRangeSelection(selection) : lexical.DEPRECATED_$isGridSelection(selection) ? printGridSelection(selection) : printObjectSelection(selection);
217
223
  });
218
- return res + '\n selection' + selectionString;
224
+ res += '\n selection' + selectionString;
225
+ res += '\n\n editor:';
226
+ res += `\n └ namespace ${editorConfig.namespace}`;
227
+
228
+ if (compositionKey !== null) {
229
+ res += `\n └ compositionKey ${compositionKey}`;
230
+ }
231
+
232
+ res += `\n └ editable ${String(editable)}`;
233
+ return res;
219
234
  }
220
235
 
221
236
  function visitTree(currentNode, visitor, indent = []) {
@@ -4,17 +4,18 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- 'use strict';var l=require("@lexical/link"),q=require("@lexical/mark"),t=require("lexical"),D=require("react");let E=Object.freeze({"\t":"\\t","\n":"\\n"}),F=new RegExp(Object.keys(E).join("|"),"g"),G=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"\u251c",isLastChild:"\u2514",selectedChar:"^",selectedLine:">"});
8
- function H(a){let b="",c=I(a),d=a.anchor;a=a.focus;let e=d.offset,g=a.offset;b=b+`: range ${""!==c?`{ ${c} }`:""}`+`\n \u251c anchor { key: ${d.key}, offset: ${null===e?"null":e}, type: ${d.type} }`;return b+=`\n \u2514 focus { key: ${a.key}, offset: ${null===g?"null":g}, type: ${a.type} }`}
9
- function K(a){let b=" root\n";a=a.read(()=>{const c=t.$getSelection();L(t.$getRoot(),(d,e)=>{const g=`(${d.getKey()})`,h=d.getType()||"",n=d.isSelected(),w=q.$isMarkNode(d)?` id: [ ${d.getIDs().join(", ")} ] `:"";var v=b,r=n?G.selectedLine:" ",x=e.join(" ");if(t.$isTextNode(d)){var f=d.getTextContent();var m=0===f.length?"(empty)":`"${M(f)}"`;f=[I(d),N(d),O(d)].filter(Boolean).join(", ");f=[m,0!==f.length?`{ ${f} }`:null].filter(Boolean).join(" ").trim()}else if(l.$isLinkNode(d)){f=d.getURL();f=0===
10
- f.length?"(empty)":`"${M(f)}"`;m=d.getTarget();null!=m&&(m="target: "+m);var y=Boolean;let u=d.getRel();null!=u&&(u="rel: "+u);m=[m,u].filter(y).join(", ");f=[f,0!==m.length?`{ ${m} }`:null].filter(Boolean).join(" ").trim()}else f="";b=v+`${r} ${x} ${g} ${h} ${w} ${f}\n`;b+=P({indent:e,isSelected:n,node:d,nodeKeyDisplay:g,selection:c,typeDisplay:h})});return null===c?": null":t.$isRangeSelection(c)?H(c):t.DEPRECATED_$isGridSelection(c)?`: grid\n \u2514 { grid: ${c.gridKey}, anchorCell: ${c.anchor.key}, focusCell: ${c.focus.key} }`:
11
- `: node\n \u2514 [${Array.from(c._nodes).join(", ")}]`});return b+"\n selection"+a}function L(a,b,c=[]){a=a.getChildren();let d=a.length;a.forEach((e,g)=>{b(e,c.concat(g===d-1?G.isLastChild:G.hasNextSibling));t.$isElementNode(e)&&L(e,b,c.concat(g===d-1?G.ancestorIsLastChild:G.ancestorHasNextSibling))})}function M(a){return Object.entries(E).reduce((b,[c,d])=>b.replace(new RegExp(c,"g"),String(d)),a)}
12
- let Q=[a=>a.hasFormat("bold")&&"Bold",a=>a.hasFormat("code")&&"Code",a=>a.hasFormat("italic")&&"Italic",a=>a.hasFormat("strikethrough")&&"Strikethrough",a=>a.hasFormat("subscript")&&"Subscript",a=>a.hasFormat("superscript")&&"Superscript",a=>a.hasFormat("underline")&&"Underline"],R=[a=>a.isDirectionless()&&"Directionless",a=>a.isUnmergeable()&&"Unmergeable"],S=[a=>a.isToken()&&"Token",a=>a.isSegmented()&&"Segmented"];
13
- function N(a){let b=R.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="detail: "+b);return b}function O(a){let b=S.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="mode: "+b);return b}function I(a){let b=Q.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="format: "+b);return b}
14
- function P({indent:a,isSelected:b,node:c,nodeKeyDisplay:d,selection:e,typeDisplay:g}){if(!t.$isTextNode(c)||!t.$isRangeSelection(e)||!b||t.$isElementNode(c))return"";b=e.anchor;var h=e.focus;if(""===c.getTextContent()||b.getNode()===e.focus.getNode()&&b.offset===h.offset)return"";h=e.anchor;let n=e.focus,w=c.getTextContent(),v=w.length;b=e=-1;if("text"===h.type&&"text"===n.type){let f=h.getNode(),m=n.getNode();f===m&&c===f&&h.offset!==n.offset?[e,b]=h.offset<n.offset?[h.offset,n.offset]:[n.offset,
15
- h.offset]:c===f?[e,b]=f.isBefore(m)?[h.offset,v]:[0,h.offset]:c===m?[e,b]=m.isBefore(f)?[n.offset,v]:[0,n.offset]:[e,b]=[0,v]}c=(w.slice(0,e).match(F)||[]).length;h=(w.slice(e,b).match(F)||[]).length;let [r,x]=[e+c,b+c+h];if(r===x)return"";c=a[a.length-1]===G.hasNextSibling?G.ancestorHasNextSibling:G.ancestorIsLastChild;a=[...a.slice(0,a.length-1),c];c=Array(r+1).fill(" ");e=Array(x-r).fill(G.selectedChar);d=Array(d.length+(g.length+3)).fill(" ");return[G.selectedLine,a.join(" "),[...d,...c,...e].join("")].join(" ")+
7
+ 'use strict';var k=require("@lexical/link"),r=require("@lexical/mark"),v=require("@lexical/utils"),C=require("lexical"),D=require("react");let E=Object.freeze({"\t":"\\t","\n":"\\n"}),F=new RegExp(Object.keys(E).join("|"),"g"),G=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"\u251c",isLastChild:"\u2514",selectedChar:"^",selectedLine:">"});
8
+ function H(a){let c="",e=K(a),l=a.anchor;a=a.focus;let f=l.offset,b=a.offset;c=c+`: range ${""!==e?`{ ${e} }`:""}`+`\n \u251c anchor { key: ${l.key}, offset: ${null===f?"null":f}, type: ${l.type} }`;return c+=`\n \u2514 focus { key: ${a.key}, offset: ${null===b?"null":b}, type: ${a.type} }`}
9
+ function L(a,c,e,l){let f=" root\n";a=a.read(()=>{const b=C.$getSelection();M(C.$getRoot(),(d,n)=>{const x=`(${d.getKey()})`,t=d.getType()||"",q=d.isSelected(),z=r.$isMarkNode(d)?` id: [ ${d.getIDs().join(", ")} ] `:"";var m=f,w=q?G.selectedLine:" ",A=n.join(" ");if(C.$isTextNode(d)){var h=d.getTextContent();var p=0===h.length?"(empty)":`"${N(h)}"`;h=[K(d),O(d),P(d)].filter(Boolean).join(", ");h=[p,0!==h.length?`{ ${h} }`:null].filter(Boolean).join(" ").trim()}else if(k.$isLinkNode(d)){h=d.getURL();
10
+ h=0===h.length?"(empty)":`"${N(h)}"`;p=d.getTarget();null!=p&&(p="target: "+p);var y=Boolean;let g=d.getRel();null!=g&&(g="rel: "+g);p=[p,g].filter(y).join(", ");h=[h,0!==p.length?`{ ${p} }`:null].filter(Boolean).join(" ").trim()}else h="";f=m+`${w} ${A} ${x} ${t} ${z} ${h}\n`;f+=Q({indent:n,isSelected:q,node:d,nodeKeyDisplay:x,selection:b,typeDisplay:t})});return null===b?": null":C.$isRangeSelection(b)?H(b):C.DEPRECATED_$isGridSelection(b)?`: grid\n \u2514 { grid: ${b.gridKey}, anchorCell: ${b.anchor.key}, focusCell: ${b.focus.key} }`:
11
+ `: node\n \u2514 [${Array.from(b._nodes).join(", ")}]`});f+="\n selection"+a;f+="\n\n editor:";f+=`\n \u2514 namespace ${c.namespace}`;null!==e&&(f+=`\n \u2514 compositionKey ${e}`);return f+=`\n \u2514 editable ${String(l)}`}function M(a,c,e=[]){a=a.getChildren();let l=a.length;a.forEach((f,b)=>{c(f,e.concat(b===l-1?G.isLastChild:G.hasNextSibling));C.$isElementNode(f)&&M(f,c,e.concat(b===l-1?G.ancestorIsLastChild:G.ancestorHasNextSibling))})}
12
+ function N(a){return Object.entries(E).reduce((c,[e,l])=>c.replace(new RegExp(e,"g"),String(l)),a)}
13
+ let R=[a=>a.hasFormat("bold")&&"Bold",a=>a.hasFormat("code")&&"Code",a=>a.hasFormat("italic")&&"Italic",a=>a.hasFormat("strikethrough")&&"Strikethrough",a=>a.hasFormat("subscript")&&"Subscript",a=>a.hasFormat("superscript")&&"Superscript",a=>a.hasFormat("underline")&&"Underline"],S=[a=>a.isDirectionless()&&"Directionless",a=>a.isUnmergeable()&&"Unmergeable"],T=[a=>a.isToken()&&"Token",a=>a.isSegmented()&&"Segmented"];
14
+ function O(a){let c=S.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="detail: "+c);return c}function P(a){let c=T.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="mode: "+c);return c}function K(a){let c=R.map(e=>e(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==c&&(c="format: "+c);return c}
15
+ function Q({indent:a,isSelected:c,node:e,nodeKeyDisplay:l,selection:f,typeDisplay:b}){if(!C.$isTextNode(e)||!C.$isRangeSelection(f)||!c||C.$isElementNode(e))return"";c=f.anchor;var d=f.focus;if(""===e.getTextContent()||c.getNode()===f.focus.getNode()&&c.offset===d.offset)return"";d=f.anchor;let n=f.focus,x=e.getTextContent(),t=x.length;c=f=-1;if("text"===d.type&&"text"===n.type){let m=d.getNode(),w=n.getNode();m===w&&e===m&&d.offset!==n.offset?[f,c]=d.offset<n.offset?[d.offset,n.offset]:[n.offset,
16
+ d.offset]:e===m?[f,c]=m.isBefore(w)?[d.offset,t]:[0,d.offset]:e===w?[f,c]=w.isBefore(m)?[n.offset,t]:[0,n.offset]:[f,c]=[0,t]}e=(x.slice(0,f).match(F)||[]).length;d=(x.slice(f,c).match(F)||[]).length;let [q,z]=[f+e,c+e+d];if(q===z)return"";e=a[a.length-1]===G.hasNextSibling?G.ancestorHasNextSibling:G.ancestorIsLastChild;a=[...a.slice(0,a.length-1),e];e=Array(q+1).fill(" ");f=Array(z-q).fill(G.selectedChar);l=Array(l.length+(b.length+3)).fill(" ");return[G.selectedLine,a.join(" "),[...l,...e,...f].join("")].join(" ")+
16
17
  "\n"}
17
- exports.TreeView=function({timeTravelButtonClassName:a,timeTravelPanelSliderClassName:b,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:e,editor:g}){let [h,n]=D.useState([]),[w,v]=D.useState(""),[r,x]=D.useState(!1),f=D.useRef(0),m=D.useRef(null),y=D.useRef(null),[u,C]=D.useState(!1);D.useEffect(()=>{v(K(g.getEditorState()));return g.registerUpdateListener(({editorState:k})=>{let p=g._compositionKey,z=K(g.getEditorState());v([z,null!==p&&`Composition key: ${p}`].filter(Boolean).join("\n\n"));r||
18
- n(B=>[...B,[Date.now(),k]])})},[r,g]);let A=h.length;D.useEffect(()=>{if(u){let k,p=()=>{const z=f.current;z===A-1?C(!1):k=setTimeout(()=>{f.current++;const B=f.current,J=y.current;null!==J&&(J.value=String(B));g.setEditorState(h[B][1]);p()},h[z+1][0]-h[z][0])};p();return()=>{clearTimeout(k)}}},[h,u,g,A]);D.useEffect(()=>{let k=m.current;if(null!==k)return k.__lexicalEditor=g,()=>{k.__lexicalEditor=null}},[g]);return D.createElement("div",{className:d},!r&&2<A&&D.createElement("button",{onClick:()=>
19
- {let k=g.getRootElement();null!==k&&(k.contentEditable="false",f.current=A-1,x(!0))},className:a,type:"button"},"Time Travel"),D.createElement("pre",{ref:m},w),r&&D.createElement("div",{className:e},D.createElement("button",{className:c,onClick:()=>{C(!u)},type:"button"},u?"Pause":"Play"),D.createElement("input",{className:b,ref:y,onChange:k=>{k=Number(k.target.value);let p=h[k];p&&(f.current=k,g.setEditorState(p[1]))},type:"range",min:"1",max:A-1}),D.createElement("button",{className:c,onClick:()=>
20
- {var k=g.getRootElement();if(null!==k){k.contentEditable="true";k=h.length-1;g.setEditorState(h[k][1]);let p=y.current;null!==p&&(p.value=String(k));x(!1);C(!1)}},type:"button"},"Exit")))}
18
+ exports.TreeView=function({timeTravelButtonClassName:a,timeTravelPanelSliderClassName:c,timeTravelPanelButtonClassName:e,viewClassName:l,timeTravelPanelClassName:f,editor:b}){let [d,n]=D.useState([]),[x,t]=D.useState(""),[q,z]=D.useState(!1),m=D.useRef(0),w=D.useRef(null),A=D.useRef(null),[h,p]=D.useState(!1);D.useEffect(()=>{t(L(b.getEditorState(),b._config,b._compositionKey,b._editable));return v.mergeRegister(b.registerUpdateListener(({editorState:g})=>{let u=L(b.getEditorState(),b._config,b._compositionKey,
19
+ b._editable);t(u);q||n(B=>[...B,[Date.now(),g]])}),b.registerEditableListener(()=>{let g=L(b.getEditorState(),b._config,b._compositionKey,b._editable);t(g)}))},[q,b]);let y=d.length;D.useEffect(()=>{if(h){let g,u=()=>{const B=m.current;B===y-1?p(!1):g=setTimeout(()=>{m.current++;const I=m.current,J=A.current;null!==J&&(J.value=String(I));b.setEditorState(d[I][1]);u()},d[B+1][0]-d[B][0])};u();return()=>{clearTimeout(g)}}},[d,h,b,y]);D.useEffect(()=>{let g=w.current;if(null!==g)return g.__lexicalEditor=
20
+ b,()=>{g.__lexicalEditor=null}},[b]);return D.createElement("div",{className:l},!q&&2<y&&D.createElement("button",{onClick:()=>{let g=b.getRootElement();null!==g&&(g.contentEditable="false",m.current=y-1,z(!0))},className:a,type:"button"},"Time Travel"),D.createElement("pre",{ref:w},x),q&&D.createElement("div",{className:f},D.createElement("button",{className:e,onClick:()=>{m.current===y-1&&(m.current=1);p(!h)},type:"button"},h?"Pause":"Play"),D.createElement("input",{className:c,ref:A,onChange:g=>
21
+ {g=Number(g.target.value);let u=d[g];u&&(m.current=g,b.setEditorState(u[1]))},type:"range",min:"1",max:y-1}),D.createElement("button",{className:e,onClick:()=>{var g=b.getRootElement();if(null!==g){g.contentEditable="true";g=d.length-1;b.setEditorState(d[g][1]);let u=A.current;null!==u&&(u.value=String(g));z(!1);p(!1)}},type:"button"},"Exit")))}
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
- import { LexicalEditor, NodeKey, TextNode } from 'lexical';
8
+ import { LexicalCommand, LexicalEditor, NodeKey, TextNode } from 'lexical';
9
9
  import { MutableRefObject, ReactPortal } from 'react';
10
10
  export declare type QueryMatch = {
11
11
  leadOffset: number;
@@ -14,8 +14,7 @@ export declare type QueryMatch = {
14
14
  };
15
15
  export declare type Resolution = {
16
16
  match: QueryMatch;
17
- position: 'start' | 'end';
18
- getRect: () => ClientRect;
17
+ getRect: () => DOMRect;
19
18
  };
20
19
  export declare const PUNCTUATION = "\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'\"~=<>_:;";
21
20
  export declare class TypeaheadOption {
@@ -24,32 +23,42 @@ export declare class TypeaheadOption {
24
23
  constructor(key: string);
25
24
  setRefElement(element: HTMLElement | null): void;
26
25
  }
27
- export declare type MenuRenderFn<TOption extends TypeaheadOption> = (anchorElement: HTMLElement | null, itemProps: {
26
+ export declare type MenuRenderFn<TOption extends TypeaheadOption> = (anchorElementRef: MutableRefObject<HTMLElement | null>, itemProps: {
28
27
  selectedIndex: number | null;
29
28
  selectOptionAndCleanUp: (option: TOption) => void;
30
29
  setHighlightedIndex: (index: number) => void;
30
+ options: Array<TOption>;
31
31
  }, matchingString: string) => ReactPortal | JSX.Element | null;
32
+ export declare function getScrollParent(element: HTMLElement, includeHidden: boolean): HTMLElement | HTMLBodyElement;
33
+ export declare function useDynamicPositioning(resolution: Resolution | null, targetElement: HTMLElement | null, onReposition: () => void, onVisibilityChange?: (isInView: boolean) => void): void;
34
+ export declare const SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
35
+ index: number;
36
+ option: TypeaheadOption;
37
+ }>;
32
38
  export declare function useBasicTypeaheadTriggerMatch(trigger: string, { minLength, maxLength }: {
33
39
  minLength?: number;
34
40
  maxLength?: number;
35
41
  }): TriggerFn;
36
- export declare type TypeaheadMenuPluginArgs<TOption extends TypeaheadOption> = {
42
+ export declare type TypeaheadMenuPluginProps<TOption extends TypeaheadOption> = {
37
43
  onQueryChange: (matchingString: string | null) => void;
38
44
  onSelectOption: (option: TOption, textNodeContainingQuery: TextNode | null, closeMenu: () => void, matchingString: string) => void;
39
45
  options: Array<TOption>;
40
46
  menuRenderFn: MenuRenderFn<TOption>;
41
47
  triggerFn: TriggerFn;
42
- position?: 'start' | 'end';
48
+ onOpen?: (resolution: Resolution) => void;
49
+ onClose?: () => void;
50
+ anchorClassName?: string;
43
51
  };
44
52
  export declare type TriggerFn = (text: string, editor: LexicalEditor) => QueryMatch | null;
45
- export declare function LexicalTypeaheadMenuPlugin<TOption extends TypeaheadOption>({ options, onQueryChange, onSelectOption, menuRenderFn, triggerFn, position, }: TypeaheadMenuPluginArgs<TOption>): JSX.Element | null;
46
- declare type NodeMenuPluginArgs<TOption extends TypeaheadOption> = {
53
+ export declare function LexicalTypeaheadMenuPlugin<TOption extends TypeaheadOption>({ options, onQueryChange, onSelectOption, onOpen, onClose, menuRenderFn, triggerFn, anchorClassName, }: TypeaheadMenuPluginProps<TOption>): JSX.Element | null;
54
+ declare type NodeMenuPluginProps<TOption extends TypeaheadOption> = {
47
55
  onSelectOption: (option: TOption, textNodeContainingQuery: TextNode | null, closeMenu: () => void, matchingString: string) => void;
48
56
  options: Array<TOption>;
49
57
  nodeKey: NodeKey | null;
50
- onClose: () => void;
51
- position?: 'start' | 'end';
58
+ onClose?: () => void;
59
+ onOpen?: (resolution: Resolution) => void;
52
60
  menuRenderFn: MenuRenderFn<TOption>;
61
+ anchorClassName?: string;
53
62
  };
54
- export declare function LexicalNodeMenuPlugin<TOption extends TypeaheadOption>({ options, nodeKey, position, onClose, onSelectOption, menuRenderFn, }: NodeMenuPluginArgs<TOption>): JSX.Element | null;
63
+ export declare function LexicalNodeMenuPlugin<TOption extends TypeaheadOption>({ options, nodeKey, onClose, onOpen, onSelectOption, menuRenderFn, anchorClassName, }: NodeMenuPluginProps<TOption>): JSX.Element | null;
55
64
  export {};