@lexical/react 0.5.0 → 0.5.1-next.1
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.
- package/DEPRECATED_useLexicalDecorators.d.ts +2 -1
- package/DEPRECATED_useLexicalDecorators.dev.js +125 -10
- package/DEPRECATED_useLexicalDecorators.js.flow +8 -0
- package/DEPRECATED_useLexicalDecorators.prod.js +6 -2
- package/LexicalAutoEmbedPlugin.d.ts +3 -11
- package/LexicalAutoEmbedPlugin.dev.js +3 -18
- package/LexicalAutoEmbedPlugin.js.flow +3 -11
- package/LexicalAutoEmbedPlugin.prod.js +4 -5
- package/LexicalAutoLinkPlugin.dev.js +49 -46
- package/LexicalAutoLinkPlugin.prod.js +6 -6
- package/LexicalHorizontalRuleNode.dev.js +1 -1
- package/LexicalHorizontalRuleNode.prod.js +1 -1
- package/LexicalPlainTextPlugin.d.ts +3 -1
- package/LexicalPlainTextPlugin.dev.js +121 -5
- package/LexicalPlainTextPlugin.js.flow +3 -0
- package/LexicalPlainTextPlugin.prod.js +6 -4
- package/LexicalRichTextPlugin.d.ts +3 -1
- package/LexicalRichTextPlugin.dev.js +121 -5
- package/LexicalRichTextPlugin.js.flow +3 -0
- package/LexicalRichTextPlugin.prod.js +6 -4
- package/LexicalTreeView.dev.js +24 -9
- package/LexicalTreeView.prod.js +14 -13
- package/LexicalTypeaheadMenuPlugin.d.ts +20 -11
- package/LexicalTypeaheadMenuPlugin.dev.js +199 -59
- package/LexicalTypeaheadMenuPlugin.js.flow +19 -21
- package/LexicalTypeaheadMenuPlugin.prod.js +20 -16
- package/README.md +3 -3
- package/package.json +19 -19
- package/shared/ReactErrorBoundary.d.ts +63 -0
- package/shared/useDecorators.d.ts +8 -1
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
import type { LexicalEditor } from 'lexical';
|
|
9
|
-
|
|
9
|
+
import { ErrorBoundaryType } from './shared/useDecorators';
|
|
10
|
+
export declare function useLexicalDecorators(editor: LexicalEditor, ErrorBoundary?: ErrorBoundaryType): Array<JSX.Element>;
|
|
@@ -6,9 +6,106 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var React = require('react');
|
|
10
10
|
var reactDom = require('react-dom');
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const changedArray = (a = [], b = []) => a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
|
|
21
|
+
|
|
22
|
+
const initialState = {
|
|
23
|
+
error: null
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
class ErrorBoundary extends React.Component {
|
|
27
|
+
constructor(props) {
|
|
28
|
+
super(props);
|
|
29
|
+
this.state = initialState;
|
|
30
|
+
this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static getDerivedStateFromError(error) {
|
|
34
|
+
return {
|
|
35
|
+
error
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
resetErrorBoundary(...args) {
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
// eslint-disable-next-line no-unused-expressions
|
|
42
|
+
this.props.onReset && this.props.onReset(...args);
|
|
43
|
+
this.reset();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
reset() {
|
|
47
|
+
this.setState(initialState);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
componentDidCatch(error, info) {
|
|
51
|
+
// @ts-ignore
|
|
52
|
+
// eslint-disable-next-line no-unused-expressions
|
|
53
|
+
this.props.onError && this.props.onError(error, info);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
componentDidUpdate(prevProps, prevState) {
|
|
57
|
+
const {
|
|
58
|
+
error
|
|
59
|
+
} = this.state;
|
|
60
|
+
const {
|
|
61
|
+
resetKeys
|
|
62
|
+
} = this.props; // There's an edge case where if the thing that triggered the error
|
|
63
|
+
// happens to *also* be in the resetKeys array, we'd end up resetting
|
|
64
|
+
// the error boundary immediately. This would likely trigger a second
|
|
65
|
+
// error to be thrown.
|
|
66
|
+
// So we make sure that we don't check the resetKeys on the first call
|
|
67
|
+
// of cDU after the error is set
|
|
68
|
+
|
|
69
|
+
if (error !== null && prevState.error !== null && changedArray(prevProps.resetKeys, resetKeys)) {
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
// eslint-disable-next-line no-unused-expressions
|
|
72
|
+
this.props.onResetKeysChange && this.props.onResetKeysChange(prevProps.resetKeys, resetKeys);
|
|
73
|
+
this.reset();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
render() {
|
|
78
|
+
const {
|
|
79
|
+
error
|
|
80
|
+
} = this.state;
|
|
81
|
+
const {
|
|
82
|
+
fallbackRender,
|
|
83
|
+
FallbackComponent,
|
|
84
|
+
fallback
|
|
85
|
+
} = this.props;
|
|
86
|
+
|
|
87
|
+
if (error !== null) {
|
|
88
|
+
const props = {
|
|
89
|
+
error,
|
|
90
|
+
resetErrorBoundary: this.resetErrorBoundary
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if ( /*#__PURE__*/React.isValidElement(fallback)) {
|
|
94
|
+
return fallback;
|
|
95
|
+
} else if (typeof fallbackRender === 'function') {
|
|
96
|
+
return fallbackRender(props);
|
|
97
|
+
} else if (FallbackComponent) {
|
|
98
|
+
return /*#__PURE__*/React.createElement(FallbackComponent, props);
|
|
99
|
+
} else {
|
|
100
|
+
throw new Error('react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return this.props.children;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
12
109
|
/**
|
|
13
110
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
111
|
*
|
|
@@ -25,7 +122,7 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
|
|
|
25
122
|
* LICENSE file in the root directory of this source tree.
|
|
26
123
|
*
|
|
27
124
|
*/
|
|
28
|
-
const useLayoutEffectImpl = CAN_USE_DOM ?
|
|
125
|
+
const useLayoutEffectImpl = CAN_USE_DOM ? React.useLayoutEffect : React.useEffect;
|
|
29
126
|
var useLayoutEffect = useLayoutEffectImpl;
|
|
30
127
|
|
|
31
128
|
/**
|
|
@@ -35,8 +132,15 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
35
132
|
* LICENSE file in the root directory of this source tree.
|
|
36
133
|
*
|
|
37
134
|
*/
|
|
38
|
-
function useDecorators(editor
|
|
39
|
-
|
|
135
|
+
function useDecorators(editor, // TODO 0.6 Make non-optional non-default
|
|
136
|
+
ErrorBoundary$1 = ({
|
|
137
|
+
children,
|
|
138
|
+
onError
|
|
139
|
+
}) => /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
140
|
+
fallback: null,
|
|
141
|
+
onError: onError
|
|
142
|
+
}, children)) {
|
|
143
|
+
const [decorators, setDecorators] = React.useState(() => editor.getDecorators()); // Subscribe to changes
|
|
40
144
|
|
|
41
145
|
useLayoutEffect(() => {
|
|
42
146
|
return editor.registerDecoratorListener(nextDecorators => {
|
|
@@ -45,20 +149,24 @@ function useDecorators(editor) {
|
|
|
45
149
|
});
|
|
46
150
|
});
|
|
47
151
|
}, [editor]);
|
|
48
|
-
|
|
152
|
+
React.useEffect(() => {
|
|
49
153
|
// If the content editable mounts before the subscription is added, then
|
|
50
154
|
// nothing will be rendered on initial pass. We can get around that by
|
|
51
155
|
// ensuring that we set the value.
|
|
52
156
|
setDecorators(editor.getDecorators());
|
|
53
157
|
}, [editor]); // Return decorators defined as React Portals
|
|
54
158
|
|
|
55
|
-
return
|
|
159
|
+
return React.useMemo(() => {
|
|
56
160
|
const decoratedPortals = [];
|
|
57
161
|
const decoratorKeys = Object.keys(decorators);
|
|
58
162
|
|
|
59
163
|
for (let i = 0; i < decoratorKeys.length; i++) {
|
|
60
164
|
const nodeKey = decoratorKeys[i];
|
|
61
|
-
const reactDecorator =
|
|
165
|
+
const reactDecorator = /*#__PURE__*/React.createElement(ErrorBoundary$1, {
|
|
166
|
+
onError: e => editor._onError(e)
|
|
167
|
+
}, /*#__PURE__*/React.createElement(React.Suspense, {
|
|
168
|
+
fallback: null
|
|
169
|
+
}, decorators[nodeKey]));
|
|
62
170
|
const element = editor.getElementByKey(nodeKey);
|
|
63
171
|
|
|
64
172
|
if (element !== null) {
|
|
@@ -67,7 +175,7 @@ function useDecorators(editor) {
|
|
|
67
175
|
}
|
|
68
176
|
|
|
69
177
|
return decoratedPortals;
|
|
70
|
-
}, [decorators, editor]);
|
|
178
|
+
}, [ErrorBoundary$1, decorators, editor]);
|
|
71
179
|
}
|
|
72
180
|
|
|
73
181
|
/**
|
|
@@ -77,8 +185,15 @@ function useDecorators(editor) {
|
|
|
77
185
|
* LICENSE file in the root directory of this source tree.
|
|
78
186
|
*
|
|
79
187
|
*/
|
|
80
|
-
function useLexicalDecorators(editor
|
|
81
|
-
|
|
188
|
+
function useLexicalDecorators(editor, // TODO 0.6 Make non-optional non-default
|
|
189
|
+
ErrorBoundary$1 = ({
|
|
190
|
+
children,
|
|
191
|
+
onError
|
|
192
|
+
}) => /*#__PURE__*/React.createElement(ErrorBoundary, {
|
|
193
|
+
fallback: null,
|
|
194
|
+
onError: onError
|
|
195
|
+
}, children)) {
|
|
196
|
+
return useDecorators(editor, ErrorBoundary$1);
|
|
82
197
|
}
|
|
83
198
|
|
|
84
199
|
exports.useLexicalDecorators = useLexicalDecorators;
|
|
@@ -12,6 +12,14 @@ import type {LexicalEditor} from 'lexical';
|
|
|
12
12
|
|
|
13
13
|
import * as React from 'react';
|
|
14
14
|
|
|
15
|
+
type ErrorBoundaryProps = $ReadOnly<{
|
|
16
|
+
children: React.Node,
|
|
17
|
+
onError?: (error: Error) => void,
|
|
18
|
+
}>;
|
|
19
|
+
export type ErrorBoundaryType = React.AbstractComponent<ErrorBoundaryProps>;
|
|
20
|
+
|
|
15
21
|
declare export function useLexicalDecorators(
|
|
16
22
|
editor: LexicalEditor,
|
|
23
|
+
// TODO 0.6 Make non-optional non-default
|
|
24
|
+
ErrorBoundary?: ErrorBoundaryType,
|
|
17
25
|
): Array<React.Node>;
|
|
@@ -4,5 +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
|
|
8
|
-
|
|
7
|
+
'use strict';var e=require("react"),k=require("react-dom");let l=(a=[],b=[])=>a.length!==b.length||a.some((c,d)=>!Object.is(c,b[d])),m={error:null};
|
|
8
|
+
class p extends e.Component{constructor(a){super(a);this.state=m;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(m)}componentDidCatch(a,b){this.props.onError&&this.props.onError(a,b)}componentDidUpdate(a,b){let {error:c}=this.state,{resetKeys:d}=this.props;null!==c&&null!==b.error&&l(a.resetKeys,d)&&(this.props.onResetKeysChange&&this.props.onResetKeysChange(a.resetKeys,
|
|
9
|
+
d),this.reset())}render(){var {error:a}=this.state;let {fallbackRender:b,FallbackComponent:c,fallback:d}=this.props;if(null!==a){a={error:a,resetErrorBoundary:this.resetErrorBoundary};if(e.isValidElement(d))return d;if("function"===typeof b)return b(a);if(c)return e.createElement(c,a);throw Error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop");}return this.props.children}}
|
|
10
|
+
var q="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?e.useLayoutEffect:e.useEffect;
|
|
11
|
+
function r(a,b=({children:c,onError:d})=>e.createElement(p,{fallback:null,onError:d},c)){let [c,d]=e.useState(()=>a.getDecorators());q(()=>a.registerDecoratorListener(g=>{k.flushSync(()=>{d(g)})}),[a]);e.useEffect(()=>{d(a.getDecorators())},[a]);return e.useMemo(()=>{let g=[],n=Object.keys(c);for(let h=0;h<n.length;h++){var f=n[h];let u=e.createElement(b,{onError:t=>a._onError(t)},e.createElement(e.Suspense,{fallback:null},c[f]));f=a.getElementByKey(f);null!==f&&g.push(k.createPortal(u,f))}return g},
|
|
12
|
+
[b,c,a])}exports.useLexicalDecorators=function(a,b=({children:c,onError:d})=>e.createElement(p,{fallback:null,onError:d},c)){return r(a,b)}
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
import type { LexicalNode } from 'lexical';
|
|
9
|
-
import { TypeaheadOption } from '@lexical/react/LexicalTypeaheadMenuPlugin';
|
|
9
|
+
import { MenuRenderFn, TypeaheadOption } from '@lexical/react/LexicalTypeaheadMenuPlugin';
|
|
10
10
|
import { LexicalCommand, LexicalEditor } from 'lexical';
|
|
11
|
-
import * as React from 'react';
|
|
12
11
|
export declare type EmbedMatchResult = {
|
|
13
12
|
url: string;
|
|
14
13
|
id: string;
|
|
@@ -20,13 +19,6 @@ export interface EmbedConfig {
|
|
|
20
19
|
}
|
|
21
20
|
export declare const URL_MATCHER: RegExp;
|
|
22
21
|
export declare const INSERT_EMBED_COMMAND: LexicalCommand<EmbedConfig['type']>;
|
|
23
|
-
export declare type EmbedMenuProps = {
|
|
24
|
-
selectedItemIndex: number | null;
|
|
25
|
-
onOptionClick: (option: AutoEmbedOption, index: number) => void;
|
|
26
|
-
onOptionMouseEnter: (index: number) => void;
|
|
27
|
-
options: Array<AutoEmbedOption>;
|
|
28
|
-
};
|
|
29
|
-
export declare type EmbedMenuComponent = React.ComponentType<EmbedMenuProps>;
|
|
30
22
|
export declare class AutoEmbedOption extends TypeaheadOption {
|
|
31
23
|
title: string;
|
|
32
24
|
onSelect: (targetNode: LexicalNode | null) => void;
|
|
@@ -37,8 +29,8 @@ export declare class AutoEmbedOption extends TypeaheadOption {
|
|
|
37
29
|
declare type LexicalAutoEmbedPluginProps<TEmbedConfig extends EmbedConfig> = {
|
|
38
30
|
embedConfigs: Array<TEmbedConfig>;
|
|
39
31
|
onOpenEmbedModalForConfig: (embedConfig: TEmbedConfig) => void;
|
|
40
|
-
menuComponent: EmbedMenuComponent;
|
|
41
32
|
getMenuOptions: (activeEmbedConfig: TEmbedConfig, embedFn: () => void, dismissFn: () => void) => Array<AutoEmbedOption>;
|
|
33
|
+
menuRenderFn: MenuRenderFn<AutoEmbedOption>;
|
|
42
34
|
};
|
|
43
|
-
export declare function LexicalAutoEmbedPlugin<TEmbedConfig extends EmbedConfig>({ embedConfigs, onOpenEmbedModalForConfig, getMenuOptions,
|
|
35
|
+
export declare function LexicalAutoEmbedPlugin<TEmbedConfig extends EmbedConfig>({ embedConfigs, onOpenEmbedModalForConfig, getMenuOptions, menuRenderFn, }: LexicalAutoEmbedPluginProps<TEmbedConfig>): JSX.Element | null;
|
|
44
36
|
export {};
|
|
@@ -12,7 +12,6 @@ var LexicalTypeaheadMenuPlugin = require('@lexical/react/LexicalTypeaheadMenuPlu
|
|
|
12
12
|
var utils = require('@lexical/utils');
|
|
13
13
|
var lexical = require('lexical');
|
|
14
14
|
var React = require('react');
|
|
15
|
-
var ReactDOM = require('react-dom');
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -22,7 +21,7 @@ var ReactDOM = require('react-dom');
|
|
|
22
21
|
*
|
|
23
22
|
*/
|
|
24
23
|
const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
25
|
-
const INSERT_EMBED_COMMAND = lexical.createCommand();
|
|
24
|
+
const INSERT_EMBED_COMMAND = lexical.createCommand('INSERT_EMBED_COMMAND');
|
|
26
25
|
class AutoEmbedOption extends LexicalTypeaheadMenuPlugin.TypeaheadOption {
|
|
27
26
|
constructor(title, options) {
|
|
28
27
|
super(title);
|
|
@@ -35,7 +34,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
35
34
|
embedConfigs,
|
|
36
35
|
onOpenEmbedModalForConfig,
|
|
37
36
|
getMenuOptions,
|
|
38
|
-
|
|
37
|
+
menuRenderFn
|
|
39
38
|
}) {
|
|
40
39
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
41
40
|
const [nodeKey, setNodeKey] = React.useState(null);
|
|
@@ -131,21 +130,7 @@ function LexicalAutoEmbedPlugin({
|
|
|
131
130
|
onClose: reset,
|
|
132
131
|
onSelectOption: onSelectOption,
|
|
133
132
|
options: options,
|
|
134
|
-
menuRenderFn:
|
|
135
|
-
selectedIndex,
|
|
136
|
-
selectOptionAndCleanUp,
|
|
137
|
-
setHighlightedIndex
|
|
138
|
-
}) => anchorElement && nodeKey != null ? /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(MenuComponent, {
|
|
139
|
-
options: options,
|
|
140
|
-
selectedItemIndex: selectedIndex,
|
|
141
|
-
onOptionClick: (option, index) => {
|
|
142
|
-
setHighlightedIndex(index);
|
|
143
|
-
selectOptionAndCleanUp(option);
|
|
144
|
-
},
|
|
145
|
-
onOptionMouseEnter: index => {
|
|
146
|
-
setHighlightedIndex(index);
|
|
147
|
-
}
|
|
148
|
-
}), anchorElement) : null
|
|
133
|
+
menuRenderFn: menuRenderFn
|
|
149
134
|
}) : null;
|
|
150
135
|
}
|
|
151
136
|
|
|
@@ -13,6 +13,7 @@ import {TypeaheadOption} from '@lexical/react/LexicalTypeaheadMenuPlugin';
|
|
|
13
13
|
import type {LexicalCommand, LexicalEditor, NodeKey, TextNode} from 'lexical';
|
|
14
14
|
import * as React from 'react';
|
|
15
15
|
import {createCommand} from 'lexical';
|
|
16
|
+
import type {MenuRenderFn} from './LexicalTypeaheadMenuPlugin';
|
|
16
17
|
|
|
17
18
|
export type EmbedMatchResult = {
|
|
18
19
|
url: string,
|
|
@@ -32,26 +33,17 @@ export const URL_MATCHER: RegExp =
|
|
|
32
33
|
/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
|
33
34
|
|
|
34
35
|
export const INSERT_EMBED_COMMAND: LexicalCommand<EmbedConfig['type']> =
|
|
35
|
-
createCommand();
|
|
36
|
-
|
|
37
|
-
export type EmbedMenuProps = {
|
|
38
|
-
selectedItemIndex: number | null,
|
|
39
|
-
onOptionClick: (option: AutoEmbedOption, index: number) => void,
|
|
40
|
-
onOptionMouseEnter: (index: number) => void,
|
|
41
|
-
options: Array<AutoEmbedOption>,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export type EmbedMenuComponent = React.ComponentType<EmbedMenuProps>;
|
|
36
|
+
createCommand('INSERT_EMBED_COMMAND');
|
|
45
37
|
|
|
46
38
|
type LexicalAutoEmbedPluginProps<TEmbedConfig> = {
|
|
47
39
|
embedConfigs: Array<TEmbedConfig>,
|
|
48
40
|
onOpenEmbedModalForConfig: (embedConfig: TEmbedConfig) => void,
|
|
49
|
-
menuComponent: EmbedMenuComponent,
|
|
50
41
|
getMenuOptions: (
|
|
51
42
|
activeEmbedConfig: TEmbedConfig,
|
|
52
43
|
embedFn: () => void,
|
|
53
44
|
dismissFn: () => void,
|
|
54
45
|
) => Array<AutoEmbedOption>,
|
|
46
|
+
menuRenderFn: MenuRenderFn<AutoEmbedOption>,
|
|
55
47
|
};
|
|
56
48
|
|
|
57
49
|
declare export class AutoEmbedOption extends TypeaheadOption {
|
|
@@ -4,8 +4,7 @@
|
|
|
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
|
|
8
|
-
exports.LexicalAutoEmbedPlugin=function({embedConfigs:g,onOpenEmbedModalForConfig:
|
|
9
|
-
|
|
10
|
-
(
|
|
11
|
-
d(l)},onOptionMouseEnter:l=>{k(l)}}),b):null}):null};exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/
|
|
7
|
+
'use strict';var d=require("@lexical/link"),k=require("@lexical/react/LexicalComposerContext"),m=require("@lexical/react/LexicalTypeaheadMenuPlugin"),q=require("@lexical/utils"),r=require("lexical"),z=require("react");let A=r.createCommand("INSERT_EMBED_COMMAND");class B extends m.TypeaheadOption{constructor(g,n){super(g);this.title=g;this.onSelect=n.onSelect.bind(this)}}exports.AutoEmbedOption=B;exports.INSERT_EMBED_COMMAND=A;
|
|
8
|
+
exports.LexicalAutoEmbedPlugin=function({embedConfigs:g,onOpenEmbedModalForConfig:n,getMenuOptions:t,menuRenderFn:C}){let [b]=k.useLexicalComposerContext(),[f,u]=z.useState(null),[h,v]=z.useState(null),l=z.useCallback(()=>{u(null);v(null)},[]),w=z.useCallback(c=>{b.getEditorState().read(()=>{const a=r.$getNodeByKey(c);if(d.$isLinkNode(a)){const e=g.find(p=>p.parseUrl(a.__url));null!=e&&(v(e),u(a.getKey()))}})},[b,g]);z.useEffect(()=>{let c=(a,{updateTags:e,dirtyLeaves:p})=>{for(const [x,D]of a)"created"===
|
|
9
|
+
D&&e.has("paste")&&1===p.size?w(x):x===f&&l()};return q.mergeRegister(...[d.LinkNode,d.AutoLinkNode].map(a=>b.registerMutationListener(a,(...e)=>c(...e))))},[w,b,g,f,l]);z.useEffect(()=>b.registerCommand(A,c=>{let a=g.find(({type:e})=>e===c);return a?(n(a),!0):!1},r.COMMAND_PRIORITY_EDITOR),[b,g,n]);let y=z.useCallback(()=>{if(null!=h&&null!=f){const c=b.getEditorState().read(()=>{const a=r.$getNodeByKey(f);return d.$isLinkNode(a)?a:null});if(d.$isLinkNode(c)){const a=h.parseUrl(c.__url);null!=a&&
|
|
10
|
+
(b.update(()=>{h.insertNode(b,a)}),c.isAttached()&&b.update(()=>{c.remove()}))}}},[h,b,f]),E=z.useMemo(()=>null!=h&&null!=f?t(h,y,l):[],[h,y,t,f,l]),F=z.useCallback((c,a,e)=>{b.update(()=>{c.onSelect(a);e()})},[b]);return null!=f?z.createElement(m.LexicalNodeMenuPlugin,{nodeKey:f,onClose:l,onSelectOption:F,options:E,menuRenderFn:C}):null};exports.URL_MATCHER=/((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/
|
|
@@ -32,6 +32,20 @@ function findFirstMatch(text, matchers) {
|
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const PUNCTUATION_OR_SPACE = /[.,;\s]/;
|
|
36
|
+
|
|
37
|
+
function isSeparator(char) {
|
|
38
|
+
return PUNCTUATION_OR_SPACE.test(char);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function endsWithSeparator(textContent) {
|
|
42
|
+
return isSeparator(textContent[textContent.length - 1]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function startsWithSeparator(textContent) {
|
|
46
|
+
return isSeparator(textContent[0]);
|
|
47
|
+
}
|
|
48
|
+
|
|
35
49
|
function isPreviousNodeValid(node) {
|
|
36
50
|
let previousNode = node.getPreviousSibling();
|
|
37
51
|
|
|
@@ -39,7 +53,7 @@ function isPreviousNodeValid(node) {
|
|
|
39
53
|
previousNode = previousNode.getLastDescendant();
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && previousNode.getTextContent()
|
|
56
|
+
return previousNode === null || lexical.$isLineBreakNode(previousNode) || lexical.$isTextNode(previousNode) && endsWithSeparator(previousNode.getTextContent());
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
function isNextNodeValid(node) {
|
|
@@ -49,64 +63,55 @@ function isNextNodeValid(node) {
|
|
|
49
63
|
nextNode = nextNode.getFirstDescendant();
|
|
50
64
|
}
|
|
51
65
|
|
|
52
|
-
return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && nextNode.getTextContent()
|
|
66
|
+
return nextNode === null || lexical.$isLineBreakNode(nextNode) || lexical.$isTextNode(nextNode) && startsWithSeparator(nextNode.getTextContent());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isContentAroundIsValid(matchStart, matchEnd, text, node) {
|
|
70
|
+
const contentBeforeIsValid = matchStart > 0 ? isSeparator(text[matchStart - 1]) : isPreviousNodeValid(node);
|
|
71
|
+
|
|
72
|
+
if (!contentBeforeIsValid) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const contentAfterIsValid = matchEnd < text.length ? isSeparator(text[matchEnd]) : isNextNodeValid(node);
|
|
77
|
+
return contentAfterIsValid;
|
|
53
78
|
}
|
|
54
79
|
|
|
55
80
|
function handleLinkCreation(node, matchers, onChange) {
|
|
56
81
|
const nodeText = node.getTextContent();
|
|
57
|
-
const nodeTextLength = nodeText.length;
|
|
58
82
|
let text = nodeText;
|
|
59
|
-
let
|
|
60
|
-
let
|
|
83
|
+
let invalidMatchEnd = 0;
|
|
84
|
+
let remainingTextNode = node;
|
|
61
85
|
let match;
|
|
62
86
|
|
|
63
87
|
while ((match = findFirstMatch(text, matchers)) && match !== null) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
// 2. Space in previous simple text node
|
|
69
|
-
// 3. Previous node is LineBreakNode
|
|
70
|
-
|
|
71
|
-
let contentBeforeMatchIsValid;
|
|
72
|
-
|
|
73
|
-
if (offset > 0) {
|
|
74
|
-
contentBeforeMatchIsValid = nodeText[offset - 1] === ' ';
|
|
75
|
-
} else {
|
|
76
|
-
contentBeforeMatchIsValid = isPreviousNodeValid(node);
|
|
77
|
-
} // Next node is valid if any of:
|
|
78
|
-
// 1. Space after same node
|
|
79
|
-
// 2. Space in next simple text node
|
|
80
|
-
// 3. Next node is LineBreakNode
|
|
81
|
-
|
|
88
|
+
const matchStart = match.index;
|
|
89
|
+
const matchLength = match.length;
|
|
90
|
+
const matchEnd = matchStart + matchLength;
|
|
91
|
+
const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, nodeText, node);
|
|
82
92
|
|
|
83
|
-
|
|
93
|
+
if (isValid) {
|
|
94
|
+
let linkTextNode;
|
|
84
95
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} else {
|
|
88
|
-
contentAfterMatchIsValid = isNextNodeValid(node);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (contentBeforeMatchIsValid && contentAfterMatchIsValid) {
|
|
92
|
-
let middleNode;
|
|
93
|
-
|
|
94
|
-
if (matchOffset === 0) {
|
|
95
|
-
[middleNode, lastNode] = lastNode.splitText(matchLength);
|
|
96
|
+
if (invalidMatchEnd + matchStart === 0) {
|
|
97
|
+
[linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchLength);
|
|
96
98
|
} else {
|
|
97
|
-
[,
|
|
99
|
+
[, linkTextNode, remainingTextNode] = remainingTextNode.splitText(invalidMatchEnd + matchStart, invalidMatchEnd + matchStart + matchLength);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
const nodeFormat = node.__format;
|
|
101
102
|
const linkNode = link.$createAutoLinkNode(match.url);
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
const textNode = lexical.$createTextNode(match.text);
|
|
104
|
+
textNode.setFormat(linkTextNode.getFormat());
|
|
105
|
+
textNode.setDetail(linkTextNode.getDetail());
|
|
106
|
+
linkNode.append(textNode);
|
|
107
|
+
linkTextNode.replace(linkNode);
|
|
104
108
|
onChange(match.url, null);
|
|
109
|
+
invalidMatchEnd = 0;
|
|
110
|
+
} else {
|
|
111
|
+
invalidMatchEnd += matchEnd;
|
|
105
112
|
}
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
text = text.substring(iterationOffset);
|
|
109
|
-
textOffset += iterationOffset;
|
|
114
|
+
text = text.substring(matchEnd);
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
117
|
|
|
@@ -157,12 +162,12 @@ function handleBadNeighbors(textNode, onChange) {
|
|
|
157
162
|
const nextSibling = textNode.getNextSibling();
|
|
158
163
|
const text = textNode.getTextContent();
|
|
159
164
|
|
|
160
|
-
if (link.$isAutoLinkNode(previousSibling) && !text
|
|
165
|
+
if (link.$isAutoLinkNode(previousSibling) && !startsWithSeparator(text)) {
|
|
161
166
|
replaceWithChildren(previousSibling);
|
|
162
167
|
onChange(null, previousSibling.getURL());
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
if (link.$isAutoLinkNode(nextSibling) && !text
|
|
170
|
+
if (link.$isAutoLinkNode(nextSibling) && !endsWithSeparator(text)) {
|
|
166
171
|
replaceWithChildren(nextSibling);
|
|
167
172
|
onChange(null, nextSibling.getURL());
|
|
168
173
|
}
|
|
@@ -206,8 +211,6 @@ function useAutoLink(editor, matchers, onChange) {
|
|
|
206
211
|
|
|
207
212
|
handleBadNeighbors(textNode, onChangeWrapped);
|
|
208
213
|
}
|
|
209
|
-
}), editor.registerNodeTransform(link.AutoLinkNode, linkNode => {
|
|
210
|
-
handleLinkEdit(linkNode, matchers, onChangeWrapped);
|
|
211
214
|
}));
|
|
212
215
|
}, [editor, matchers, onChange]);
|
|
213
216
|
}
|
|
@@ -4,9 +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 h=require("@lexical/link"),
|
|
8
|
-
function
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
'use strict';var h=require("@lexical/link"),l=require("@lexical/react/LexicalComposerContext"),m=require("@lexical/utils"),q=require("lexical"),y=require("react");function z(b,e){for(let c=0;c<e.length;c++){let a=e[c](b);if(a)return a}return null}let A=/[.,;\s]/;function C(b){b=b.getPreviousSibling();q.$isElementNode(b)&&(b=b.getLastDescendant());var e;!(e=null===b||q.$isLineBreakNode(b))&&(e=q.$isTextNode(b))&&(b=b.getTextContent(),e=A.test(b[b.length-1]));return e}
|
|
8
|
+
function D(b){b=b.getNextSibling();q.$isElementNode(b)&&(b=b.getFirstDescendant());return null===b||q.$isLineBreakNode(b)||q.$isTextNode(b)&&A.test(b.getTextContent()[0])}function E(b){let e=b.getChildren();var c=e.length;for(--c;0<=c;c--)b.insertAfter(e[c]);b.remove();return e.map(a=>a.getLatest())}
|
|
9
|
+
function F(b,e,c){y.useEffect(()=>{if(!b.hasNodes([h.AutoLinkNode]))throw Error("Minified Lexical error #77; visit https://lexical.dev/docs/error?code=77 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");return m.mergeRegister(b.registerNodeTransform(q.TextNode,a=>{var f=a.getParentOrThrow();if(h.$isAutoLinkNode(f))a:{a=f.getChildren();var d=a.length;for(var g=0;g<d;g++){var n=a[g];if(!q.$isTextNode(n)||!n.isSimpleText()){E(f);a=f.getURL();
|
|
10
|
+
c&&c(null,a);break a}}d=f.getTextContent();a=z(d,e);null===a||a.text!==d?(E(f),a=f.getURL(),c&&c(null,a)):C(f)&&D(f)?(d=f.getURL(),null!==a&&d!==a.url&&(f.setURL(a.url),c&&c(a.url,d))):(E(f),a=f.getURL(),c&&c(null,a))}else if(!h.$isLinkNode(f)){if(a.isSimpleText()){n=f=a.getTextContent();let k=0,u=a;for(;(d=z(n,e))&&null!==d;){let r=d.index,v=d.length,w=r+v;var t=k+r,p=k+w,x=f,B=a;(0<t?A.test(x[t-1]):C(B))&&(p<x.length?A.test(x[p]):D(B))?(0===k+r?[g,u]=u.splitText(k+v):[,g,u]=u.splitText(k+r,k+r+
|
|
11
|
+
v),t=h.$createAutoLinkNode(d.url),p=q.$createTextNode(d.text),p.setFormat(g.getFormat()),p.setDetail(g.getDetail()),t.append(p),g.replace(t),c&&c(d.url,null),k=0):k+=w;n=n.substring(w)}}g=a.getPreviousSibling();d=a.getNextSibling();a=a.getTextContent();h.$isAutoLinkNode(g)&&!A.test(a[0])&&(E(g),g=g.getURL(),c&&c(null,g));h.$isAutoLinkNode(d)&&!A.test(a[a.length-1])&&(E(d),a=d.getURL(),c&&c(null,a))}}))},[b,e,c])}
|
|
12
|
+
exports.AutoLinkPlugin=function({matchers:b,onChange:e}){let [c]=l.useLexicalComposerContext();F(c,b,e);return null}
|
|
@@ -19,7 +19,7 @@ var React = require('react');
|
|
|
19
19
|
* LICENSE file in the root directory of this source tree.
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
|
-
const INSERT_HORIZONTAL_RULE_COMMAND = lexical.createCommand();
|
|
22
|
+
const INSERT_HORIZONTAL_RULE_COMMAND = lexical.createCommand('INSERT_HORIZONTAL_RULE_COMMAND');
|
|
23
23
|
|
|
24
24
|
function HorizontalRuleComponent({
|
|
25
25
|
nodeKey
|
|
@@ -4,7 +4,7 @@
|
|
|
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 a=require("@lexical/react/LexicalComposerContext"),d=require("@lexical/react/useLexicalNodeSelection"),h=require("@lexical/utils"),l=require("lexical"),p=require("react");let q=l.createCommand();
|
|
7
|
+
'use strict';var a=require("@lexical/react/LexicalComposerContext"),d=require("@lexical/react/useLexicalNodeSelection"),h=require("@lexical/utils"),l=require("lexical"),p=require("react");let q=l.createCommand("INSERT_HORIZONTAL_RULE_COMMAND");
|
|
8
8
|
function r({nodeKey:b}){let [f]=a.useLexicalComposerContext(),m=p.useRef(null),[e,g,n]=d.useLexicalNodeSelection(b),k=p.useCallback(c=>{e&&l.$isNodeSelection(l.$getSelection())&&(c.preventDefault(),c=l.$getNodeByKey(b),t(c)&&c.remove(),g(!1));return!1},[e,b,g]);p.useEffect(()=>h.mergeRegister(f.registerCommand(l.CLICK_COMMAND,c=>c.target===m.current?(c.shiftKey||n(),g(!e),!0):!1,l.COMMAND_PRIORITY_LOW),f.registerCommand(l.KEY_DELETE_COMMAND,k,l.COMMAND_PRIORITY_LOW),f.registerCommand(l.KEY_BACKSPACE_COMMAND,
|
|
9
9
|
k,l.COMMAND_PRIORITY_LOW)),[n,f,e,k,g]);return p.createElement("hr",{ref:m,className:e?"selected":void 0})}
|
|
10
10
|
class u extends l.DecoratorNode{static getType(){return"horizontalrule"}static clone(b){return new u(b.__key)}static importJSON(){return v()}static importDOM(){return{hr:()=>({conversion:w,priority:0})}}exportJSON(){return{type:"horizontalrule",version:1}}exportDOM(){return{element:document.createElement("hr")}}createDOM(){let b=document.createElement("div");b.style.display="contents";return b}getTextContent(){return"\n"}isInline(){return!1}updateDOM(){return!1}decorate(){return p.createElement(r,{nodeKey:this.__key})}}
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
import { ErrorBoundaryType } from './shared/useDecorators';
|
|
9
|
+
export declare function PlainTextPlugin({ contentEditable, placeholder, ErrorBoundary, }: {
|
|
9
10
|
contentEditable: JSX.Element;
|
|
10
11
|
placeholder: JSX.Element | string;
|
|
12
|
+
ErrorBoundary?: ErrorBoundaryType;
|
|
11
13
|
}): JSX.Element;
|