@lexical/react 0.3.7 → 0.3.10
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/LexicalAutoEmbedPlugin.d.ts +46 -0
- package/LexicalAutoEmbedPlugin.dev.js +490 -0
- package/LexicalAutoEmbedPlugin.js +9 -0
- package/LexicalAutoEmbedPlugin.prod.js +21 -0
- package/LexicalAutoLinkPlugin.dev.js +1 -1
- package/LexicalAutoLinkPlugin.prod.js +2 -2
- package/LexicalCollaborationContext.d.ts +19 -0
- package/LexicalCollaborationContext.dev.js +38 -0
- package/LexicalCollaborationContext.js +9 -0
- package/LexicalCollaborationContext.js.flow +21 -0
- package/LexicalCollaborationContext.prod.js +8 -0
- package/LexicalCollaborationPlugin.d.ts +0 -10
- package/LexicalCollaborationPlugin.dev.js +13 -20
- package/LexicalCollaborationPlugin.js.flow +0 -9
- package/LexicalCollaborationPlugin.prod.js +9 -10
- package/LexicalLinkPlugin.dev.js +15 -2
- package/LexicalLinkPlugin.prod.js +2 -1
- package/LexicalNestedComposer.dev.js +11 -5
- package/LexicalNestedComposer.prod.js +3 -3
- package/LexicalOnChangePlugin.d.ts +2 -1
- package/LexicalOnChangePlugin.dev.js +6 -3
- package/LexicalOnChangePlugin.js.flow +2 -0
- package/LexicalOnChangePlugin.prod.js +2 -2
- package/LexicalTableOfContents__EXPERIMENTAL.d.ts +14 -0
- package/LexicalTableOfContents__EXPERIMENTAL.dev.js +144 -0
- package/LexicalTableOfContents__EXPERIMENTAL.js +9 -0
- package/LexicalTableOfContents__EXPERIMENTAL.js.flow +17 -0
- package/LexicalTableOfContents__EXPERIMENTAL.prod.js +10 -0
- package/LexicalTreeView.dev.js +43 -9
- package/LexicalTreeView.prod.js +13 -13
- package/LexicalTypeaheadMenuPlugin.d.ts +52 -0
- package/LexicalTypeaheadMenuPlugin.dev.js +520 -0
- package/LexicalTypeaheadMenuPlugin.js +9 -0
- package/LexicalTypeaheadMenuPlugin.prod.js +22 -0
- package/package.json +19 -19
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {Doc} from 'yjs';
|
|
11
|
+
|
|
12
|
+
type CollaborationContextType = {
|
|
13
|
+
clientID: number,
|
|
14
|
+
color: string,
|
|
15
|
+
isCollabActive: boolean,
|
|
16
|
+
name: string,
|
|
17
|
+
yjsDocMap: Map<string, Doc>,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
declare export var CollaborationContext: React$Context<CollaborationContextType>;
|
|
21
|
+
declare export function useCollaborationContext(): CollaborationContextType;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';var a=require("react");let b=[["Cat","255,165,0"],["Dog","0,200,55"],["Rabbit","160,0,200"],["Frog","0,172,200"],["Fox","197,200,0"],["Hedgehog","31,200,0"],["Pigeon","200,0,0"],["Squirrel","200,0,148"],["Bear","255,235,0"],["Tiger","86,255,0"],["Leopard","0,255,208"],["Zebra","0,243,255"],["Wolf","0,102,255"],["Owl","147,0,255"],["Gull","255,0,153"],["Squid","0,220,255"]],c=b[Math.floor(Math.random()*b.length)],d=a.createContext({clientID:0,color:c[1],isCollabActive:!1,name:c[0],yjsDocMap:new Map});
|
|
8
|
+
exports.CollaborationContext=d;exports.useCollaborationContext=function(e){let f=a.useContext(d);null!=e&&(f.name=e);return f}
|
|
@@ -5,21 +5,11 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
/// <reference types="react" />
|
|
9
8
|
import type { Doc } from 'yjs';
|
|
10
9
|
import { WebsocketProvider } from 'y-websocket';
|
|
11
|
-
declare type CollaborationContextType = {
|
|
12
|
-
clientID: number;
|
|
13
|
-
color: string;
|
|
14
|
-
name: string;
|
|
15
|
-
yjsDocMap: Map<string, Doc>;
|
|
16
|
-
};
|
|
17
10
|
export declare function CollaborationPlugin({ id, providerFactory, shouldBootstrap, username, }: {
|
|
18
11
|
id: string;
|
|
19
12
|
providerFactory: (id: string, yjsDocMap: Map<string, Doc>) => WebsocketProvider;
|
|
20
13
|
shouldBootstrap: boolean;
|
|
21
14
|
username?: string;
|
|
22
15
|
}): JSX.Element;
|
|
23
|
-
export declare const CollaborationContext: React.Context<CollaborationContextType>;
|
|
24
|
-
export declare function useCollaborationContext(username?: string): CollaborationContextType;
|
|
25
|
-
export {};
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
var LexicalCollaborationContext = require('@lexical/react/LexicalCollaborationContext');
|
|
9
10
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
10
11
|
var React = require('react');
|
|
11
12
|
var utils = require('@lexical/utils');
|
|
@@ -102,6 +103,7 @@ function useYjsCollaboration(editor, id, provider, docMap, name, color, shouldBo
|
|
|
102
103
|
provider.off('reload', onProviderDocReload);
|
|
103
104
|
awareness.off('update', onAwarenessUpdate);
|
|
104
105
|
root.getSharedType().unobserveDeep(onYjsTreeChanges);
|
|
106
|
+
docMap.delete(id);
|
|
105
107
|
removeListener();
|
|
106
108
|
};
|
|
107
109
|
}, [binding, color, connect, disconnect, docMap, editor, id, name, provider, shouldBootstrap]);
|
|
@@ -240,21 +242,29 @@ function clearEditorSkipCollab(editor, binding) {
|
|
|
240
242
|
* LICENSE file in the root directory of this source tree.
|
|
241
243
|
*
|
|
242
244
|
*/
|
|
243
|
-
const entries = [['Cat', '255,165,0'], ['Dog', '0,200,55'], ['Rabbit', '160,0,200'], ['Frog', '0,172,200'], ['Fox', '197,200,0'], ['Hedgehog', '31,200,0'], ['Pigeon', '200,0,0'], ['Squirrel', '200,0,148'], ['Bear', '255,235,0'], ['Tiger', '86,255,0'], ['Leopard', '0,255,208'], ['Zebra', '0,243,255'], ['Wolf', '0,102,255'], ['Owl', '147,0,255'], ['Gull', '255,0,153'], ['Squid', '0,220,255']];
|
|
244
|
-
const randomEntry = entries[Math.floor(Math.random() * entries.length)];
|
|
245
245
|
function CollaborationPlugin({
|
|
246
246
|
id,
|
|
247
247
|
providerFactory,
|
|
248
248
|
shouldBootstrap,
|
|
249
249
|
username
|
|
250
250
|
}) {
|
|
251
|
-
const collabContext = useCollaborationContext(username);
|
|
251
|
+
const collabContext = LexicalCollaborationContext.useCollaborationContext(username);
|
|
252
252
|
const {
|
|
253
253
|
yjsDocMap,
|
|
254
254
|
name,
|
|
255
255
|
color
|
|
256
256
|
} = collabContext;
|
|
257
257
|
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
258
|
+
React.useEffect(() => {
|
|
259
|
+
collabContext.isCollabActive = true;
|
|
260
|
+
return () => {
|
|
261
|
+
// Reseting flag only when unmount top level editor collab plugin. Nested
|
|
262
|
+
// editors (e.g. image caption) should unmount without affecting it
|
|
263
|
+
if (editor._parentEditor == null) {
|
|
264
|
+
collabContext.isCollabActive = false;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}, [collabContext, editor]);
|
|
258
268
|
const provider = React.useMemo(() => providerFactory(id, yjsDocMap), [id, providerFactory, yjsDocMap]);
|
|
259
269
|
const [cursors, binding] = useYjsCollaboration(editor, id, provider, yjsDocMap, name, color, shouldBootstrap);
|
|
260
270
|
collabContext.clientID = binding.clientID;
|
|
@@ -262,22 +272,5 @@ function CollaborationPlugin({
|
|
|
262
272
|
useYjsFocusTracking(editor, provider, name, color);
|
|
263
273
|
return cursors;
|
|
264
274
|
}
|
|
265
|
-
const CollaborationContext = /*#__PURE__*/React.createContext({
|
|
266
|
-
clientID: 0,
|
|
267
|
-
color: randomEntry[1],
|
|
268
|
-
name: randomEntry[0],
|
|
269
|
-
yjsDocMap: new Map()
|
|
270
|
-
});
|
|
271
|
-
function useCollaborationContext(username) {
|
|
272
|
-
const collabContext = React.useContext(CollaborationContext);
|
|
273
|
-
|
|
274
|
-
if (username != null) {
|
|
275
|
-
collabContext.name = username;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return collabContext;
|
|
279
|
-
}
|
|
280
275
|
|
|
281
|
-
exports.CollaborationContext = CollaborationContext;
|
|
282
276
|
exports.CollaborationPlugin = CollaborationPlugin;
|
|
283
|
-
exports.useCollaborationContext = useCollaborationContext;
|
|
@@ -41,13 +41,6 @@ export interface Provider {
|
|
|
41
41
|
off(type: 'reload', cb: (doc: Doc) => void): void;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
type CollaborationContextType = {
|
|
45
|
-
clientID: number,
|
|
46
|
-
color: string,
|
|
47
|
-
name: string,
|
|
48
|
-
yjsDocMap: Map<string, Doc>,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
44
|
export type ProviderFactory = (
|
|
52
45
|
id: string,
|
|
53
46
|
yjsDocMap: Map<string, Doc>,
|
|
@@ -59,5 +52,3 @@ declare export function CollaborationPlugin(arg0: {
|
|
|
59
52
|
shouldBootstrap: boolean,
|
|
60
53
|
username?: string,
|
|
61
54
|
}): React$Node;
|
|
62
|
-
declare export var CollaborationContext: React$Context<CollaborationContextType>;
|
|
63
|
-
declare export function useCollaborationContext(): CollaborationContextType;
|
|
@@ -4,13 +4,12 @@
|
|
|
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 e=require("@lexical/react/
|
|
8
|
-
function
|
|
9
|
-
a,
|
|
10
|
-
y.off("update",B);m.getSharedType().unobserveDeep(C);
|
|
11
|
-
function
|
|
12
|
-
function
|
|
13
|
-
function
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
function U(b){let c=f.useContext(T);null!=b&&(c.name=b);return c}exports.CollaborationContext=T;exports.CollaborationPlugin=function({id:b,providerFactory:c,shouldBootstrap:a,username:d}){d=U(d);let {yjsDocMap:l,name:p,color:q}=d,[n]=e.useLexicalComposerContext(),r=f.useMemo(()=>c(b,l),[b,c,l]),[v,g]=H(n,b,r,l,p,q,a);d.clientID=g.clientID;L(n,g);K(n,r,p,q);return v};exports.useCollaborationContext=U
|
|
7
|
+
'use strict';var e=require("@lexical/react/LexicalCollaborationContext"),f=require("@lexical/react/LexicalComposerContext"),k=require("react"),x=require("@lexical/utils"),F=require("@lexical/yjs"),G=require("lexical"),H=require("react-dom");
|
|
8
|
+
function I(b,c,a,d,h,q,r){let p=k.useRef(!1),[n,v]=k.useState(d.get(c)),g=k.useMemo(()=>F.createBinding(b,a,c,n,d),[b,a,c,d,n]),t=k.useCallback(()=>{a.connect()},[a]),u=k.useCallback(()=>{try{a.disconnect()}catch(m){}},[a]);k.useEffect(()=>{let {root:m}=g,{awareness:y}=a,z=({status:l})=>{b.dispatchCommand(F.CONNECTED_COMMAND,"connected"===l)},A=l=>{r&&l&&m.isEmpty()&&0===m._xmlText._length&&!1===p.current&&J(b);p.current=!1},B=()=>{F.syncCursorPositions(g,a)},C=(l,w)=>{w.origin!==g&&F.syncYjsChangesToLexical(g,
|
|
9
|
+
a,l)};F.initLocalState(a,h,q,document.activeElement===b.getRootElement());let D=l=>{K(b,g);v(l);d.set(c,l);p.current=!0};a.on("reload",D);a.on("status",z);a.on("sync",A);y.on("update",B);m.getSharedType().observeDeep(C);let O=b.registerUpdateListener(({prevEditorState:l,editorState:w,dirtyLeaves:L,dirtyElements:M,normalizedNodes:N,tags:E})=>{!1===E.has("skip-collab")&&F.syncLexicalUpdateToYjs(g,a,l,w,M,L,N,E)});t();return()=>{!1===p.current&&u();a.off("sync",A);a.off("status",z);a.off("reload",D);
|
|
10
|
+
y.off("update",B);m.getSharedType().unobserveDeep(C);d.delete(c);O()}},[g,q,t,u,d,b,c,h,a,r]);let P=k.useMemo(()=>H.createPortal(k.createElement("div",{ref:m=>{g.cursorsContainer=m}}),document.body),[g]);k.useEffect(()=>b.registerCommand(F.TOGGLE_CONNECT_COMMAND,m=>{void 0!==t&&void 0!==u&&(m?(console.log("Collaboration connected!"),t()):(console.log("Collaboration disconnected!"),u()));return!0},G.COMMAND_PRIORITY_EDITOR),[t,u,b]);return[P,g]}
|
|
11
|
+
function Q(b,c,a,d){k.useEffect(()=>x.mergeRegister(b.registerCommand(G.FOCUS_COMMAND,()=>{F.setLocalStateFocus(c,a,d,!0);return!0},G.COMMAND_PRIORITY_EDITOR),b.registerCommand(G.BLUR_COMMAND,()=>{F.setLocalStateFocus(c,a,d,!1);return!0},G.COMMAND_PRIORITY_EDITOR)),[d,b,a,c])}
|
|
12
|
+
function R(b,c){let a=k.useMemo(()=>F.createUndoManager(c,c.root.getSharedType()),[c]);k.useEffect(()=>x.mergeRegister(b.registerCommand(G.UNDO_COMMAND,()=>{a.undo();return!0},G.COMMAND_PRIORITY_EDITOR),b.registerCommand(G.REDO_COMMAND,()=>{a.redo();return!0},G.COMMAND_PRIORITY_EDITOR)));return k.useCallback(()=>{a.clear()},[a])}
|
|
13
|
+
function J(b){b.update(()=>{var c=G.$getRoot();if(null===c.getFirstChild()){let a=G.$createParagraphNode();c.append(a);c=document.activeElement;(null!==G.$getSelection()||null!==c&&c===b.getRootElement())&&a.select()}},{tag:"history-merge"})}
|
|
14
|
+
function K(b,c){b.update(()=>{let d=G.$getRoot();d.clear();d.select()},{tag:"skip-collab"});if(null!=c.cursors&&(b=c.cursors,null!=b&&(c=c.cursorsContainer,null!=c))){b=Array.from(b.values());for(let d=0;d<b.length;d++){var a=b[d].selection;if(a&&null!=a.selections){a=a.selections;for(let h=0;h<a.length;h++)c.removeChild(a[d])}}}}
|
|
15
|
+
exports.CollaborationPlugin=function({id:b,providerFactory:c,shouldBootstrap:a,username:d}){let h=e.useCollaborationContext(d),{yjsDocMap:q,name:r,color:p}=h,[n]=f.useLexicalComposerContext();k.useEffect(()=>{h.isCollabActive=!0;return()=>{null==n._parentEditor&&(h.isCollabActive=!1)}},[h,n]);d=k.useMemo(()=>c(b,q),[b,c,q]);let [v,g]=I(n,b,d,q,r,p,a);h.clientID=g.clientID;R(n,g);Q(n,d,r,p);return v}
|
package/LexicalLinkPlugin.dev.js
CHANGED
|
@@ -26,8 +26,21 @@ function LinkPlugin() {
|
|
|
26
26
|
}
|
|
27
27
|
}, [editor]);
|
|
28
28
|
react.useEffect(() => {
|
|
29
|
-
return editor.registerCommand(link.TOGGLE_LINK_COMMAND,
|
|
30
|
-
|
|
29
|
+
return editor.registerCommand(link.TOGGLE_LINK_COMMAND, payload => {
|
|
30
|
+
if (typeof payload === 'string' || payload === null) {
|
|
31
|
+
link.toggleLink(payload);
|
|
32
|
+
} else {
|
|
33
|
+
const {
|
|
34
|
+
url,
|
|
35
|
+
target,
|
|
36
|
+
rel
|
|
37
|
+
} = payload;
|
|
38
|
+
link.toggleLink(url, {
|
|
39
|
+
rel,
|
|
40
|
+
target
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
return true;
|
|
32
45
|
}, lexical.COMMAND_PRIORITY_EDITOR);
|
|
33
46
|
}, [editor]);
|
|
@@ -4,4 +4,5 @@
|
|
|
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
|
|
7
|
+
'use strict';var a=require("@lexical/link"),d=require("@lexical/react/LexicalComposerContext"),e=require("lexical"),f=require("react");
|
|
8
|
+
exports.LinkPlugin=function(){let [b]=d.useLexicalComposerContext();f.useEffect(()=>{if(!b.hasNodes([a.LinkNode]))throw Error("LinkPlugin: LinkNode not registered on editor");},[b]);f.useEffect(()=>b.registerCommand(a.TOGGLE_LINK_COMMAND,c=>{if("string"===typeof c||null===c)a.toggleLink(c);else{let {url:g,target:h,rel:k}=c;a.toggleLink(g,{rel:k,target:h})}return!0},e.COMMAND_PRIORITY_EDITOR),[b]);return null}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var LexicalCollaborationContext = require('@lexical/react/LexicalCollaborationContext');
|
|
10
10
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
11
11
|
var React = require('react');
|
|
12
12
|
|
|
@@ -22,6 +22,7 @@ function LexicalNestedComposer({
|
|
|
22
22
|
children,
|
|
23
23
|
initialTheme
|
|
24
24
|
}) {
|
|
25
|
+
const wasCollabPreviouslyReadyRef = React.useRef(false);
|
|
25
26
|
const parentContext = React.useContext(LexicalComposerContext.LexicalComposerContext);
|
|
26
27
|
|
|
27
28
|
if (parentContext == null) {
|
|
@@ -49,13 +50,18 @@ function LexicalNestedComposer({
|
|
|
49
50
|
// until the collaboration subdocument is ready.
|
|
50
51
|
|
|
51
52
|
const {
|
|
53
|
+
isCollabActive,
|
|
52
54
|
yjsDocMap
|
|
53
|
-
} =
|
|
54
|
-
const
|
|
55
|
-
|
|
55
|
+
} = LexicalCollaborationContext.useCollaborationContext();
|
|
56
|
+
const isCollabReady = wasCollabPreviouslyReadyRef.current || yjsDocMap.has(initialEditor.getKey());
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
if (isCollabReady) {
|
|
59
|
+
wasCollabPreviouslyReadyRef.current = true;
|
|
60
|
+
}
|
|
61
|
+
}, [isCollabReady]);
|
|
56
62
|
return /*#__PURE__*/React.createElement(LexicalComposerContext.LexicalComposerContext.Provider, {
|
|
57
63
|
value: composerContext
|
|
58
|
-
}, !
|
|
64
|
+
}, !isCollabActive || isCollabReady ? children : null);
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
exports.LexicalNestedComposer = LexicalNestedComposer;
|
|
@@ -4,6 +4,6 @@
|
|
|
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.LexicalNestedComposer=function({initialEditor:a,children:
|
|
9
|
-
a._config.namespace=
|
|
7
|
+
'use strict';var b=require("@lexical/react/LexicalCollaborationContext"),c=require("@lexical/react/LexicalComposerContext"),k=require("react");
|
|
8
|
+
exports.LexicalNestedComposer=function({initialEditor:a,children:l,initialTheme:m}){let h=k.useRef(!1),d=k.useContext(c.LexicalComposerContext);if(null==d)throw Error("Minified Lexical error #9; visit https://lexical.dev/docs/error?code=9 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");let q=k.useMemo(()=>{const [e,n]=d,f=m||n.getTheme()||void 0,p=c.createLexicalComposerContext(d,f);void 0!==f&&(a._config.theme=f);a._parentEditor=e;a._nodes=
|
|
9
|
+
e._nodes;a._config.namespace=e._config.namespace;return[a,p]},[]),{isCollabActive:r,yjsDocMap:t}=b.useCollaborationContext(),g=h.current||t.has(a.getKey());k.useEffect(()=>{g&&(h.current=!0)},[g]);return k.createElement(c.LexicalComposerContext.Provider,{value:q},!r||g?l:null)}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
import type { EditorState, LexicalEditor } from 'lexical';
|
|
9
|
-
export declare function OnChangePlugin({ ignoreInitialChange, ignoreSelectionChange, onChange, }: {
|
|
9
|
+
export declare function OnChangePlugin({ ignoreHistoryMergeTagChange, ignoreInitialChange, ignoreSelectionChange, onChange, }: {
|
|
10
|
+
ignoreHistoryMergeTagChange?: boolean;
|
|
10
11
|
ignoreInitialChange?: boolean;
|
|
11
12
|
ignoreSelectionChange?: boolean;
|
|
12
13
|
onChange: (editorState: EditorState, editor: LexicalEditor) => void;
|
|
@@ -36,6 +36,8 @@ var useLayoutEffect = useLayoutEffectImpl;
|
|
|
36
36
|
*
|
|
37
37
|
*/
|
|
38
38
|
function OnChangePlugin({
|
|
39
|
+
// TODO 0.4 flip to true
|
|
40
|
+
ignoreHistoryMergeTagChange = false,
|
|
39
41
|
ignoreInitialChange = true,
|
|
40
42
|
ignoreSelectionChange = false,
|
|
41
43
|
onChange
|
|
@@ -47,9 +49,10 @@ function OnChangePlugin({
|
|
|
47
49
|
editorState,
|
|
48
50
|
dirtyElements,
|
|
49
51
|
dirtyLeaves,
|
|
50
|
-
prevEditorState
|
|
52
|
+
prevEditorState,
|
|
53
|
+
tags
|
|
51
54
|
}) => {
|
|
52
|
-
if (ignoreSelectionChange && dirtyElements.size === 0 && dirtyLeaves.size === 0) {
|
|
55
|
+
if (ignoreSelectionChange && dirtyElements.size === 0 && dirtyLeaves.size === 0 || ignoreHistoryMergeTagChange && tags.has('history-merge')) {
|
|
53
56
|
return;
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -60,7 +63,7 @@ function OnChangePlugin({
|
|
|
60
63
|
onChange(editorState, editor);
|
|
61
64
|
});
|
|
62
65
|
}
|
|
63
|
-
}, [editor, ignoreInitialChange, ignoreSelectionChange, onChange]);
|
|
66
|
+
}, [editor, ignoreHistoryMergeTagChange, ignoreInitialChange, ignoreSelectionChange, onChange]);
|
|
64
67
|
return null;
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
import type {EditorState, LexicalEditor} from 'lexical';
|
|
11
11
|
|
|
12
12
|
declare export function OnChangePlugin({
|
|
13
|
+
ignoreHistoryMergeTagChange?: boolean,
|
|
14
|
+
// TODO 0.4 remove
|
|
13
15
|
ignoreInitialChange?: boolean,
|
|
14
16
|
ignoreSelectionChange?: boolean,
|
|
15
17
|
onChange: (editorState: EditorState, editor: LexicalEditor) => void,
|
|
@@ -4,5 +4,5 @@
|
|
|
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"),
|
|
8
|
-
exports.OnChangePlugin=function({
|
|
7
|
+
'use strict';var c=require("@lexical/react/LexicalComposerContext"),g=require("react"),h="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement?g.useLayoutEffect:g.useEffect;
|
|
8
|
+
exports.OnChangePlugin=function({ignoreHistoryMergeTagChange:d=!1,ignoreInitialChange:e=!0,ignoreSelectionChange:f=!1,onChange:a}){let [b]=c.useLexicalComposerContext();h(()=>{if(a)return b.registerUpdateListener(({editorState:k,dirtyElements:l,dirtyLeaves:m,prevEditorState:n,tags:p})=>{f&&0===l.size&&0===m.size||d&&p.has("history-merge")||e&&n.isEmpty()||a(k,b)})},[b,d,e,f,a]);return null}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { LexicalEditor, NodeKey } from 'lexical';
|
|
9
|
+
import { HeadingTagType } from '@lexical/rich-text';
|
|
10
|
+
declare type Props = {
|
|
11
|
+
children: (values: Array<[key: NodeKey, text: string, tag: HeadingTagType]>, editor: LexicalEditor) => JSX.Element;
|
|
12
|
+
};
|
|
13
|
+
export default function LexicalTableOfContentsPlugin({ children, }: Props): JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
10
|
+
var richText = require('@lexical/rich-text');
|
|
11
|
+
var lexical = require('lexical');
|
|
12
|
+
var react = require('react');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
16
|
+
*
|
|
17
|
+
* This source code is licensed under the MIT license found in the
|
|
18
|
+
* LICENSE file in the root directory of this source tree.
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
function $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents) {
|
|
23
|
+
if (newHeading === null) {
|
|
24
|
+
return currentTableOfContents;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const newEntry = [newHeading.getKey(), newHeading.getTextContent(), newHeading.getTag()];
|
|
28
|
+
let newTableOfContents = [];
|
|
29
|
+
|
|
30
|
+
if (prevHeading === null) {
|
|
31
|
+
newTableOfContents = [newEntry, ...currentTableOfContents];
|
|
32
|
+
} else {
|
|
33
|
+
for (let i = 0; i < currentTableOfContents.length; i++) {
|
|
34
|
+
const key = currentTableOfContents[i][0];
|
|
35
|
+
newTableOfContents.push(currentTableOfContents[i]);
|
|
36
|
+
|
|
37
|
+
if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
|
|
38
|
+
newTableOfContents.push(newEntry);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return newTableOfContents;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function $deleteHeadingFromTableOfContents(key, currentTableOfContents) {
|
|
47
|
+
const newTableOfContents = [];
|
|
48
|
+
|
|
49
|
+
for (const heading of currentTableOfContents) {
|
|
50
|
+
if (heading[0] !== key) {
|
|
51
|
+
newTableOfContents.push(heading);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return newTableOfContents;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function $updateHeadingInTableOfContents(heading, currentTableOfContents) {
|
|
59
|
+
const newTextContent = heading.getTextContent();
|
|
60
|
+
const newTableOfContents = [];
|
|
61
|
+
|
|
62
|
+
for (const oldHeading of currentTableOfContents) {
|
|
63
|
+
if (oldHeading[0] === heading.getKey()) {
|
|
64
|
+
newTableOfContents.push([heading.getKey(), newTextContent, heading.getTag()]);
|
|
65
|
+
} else {
|
|
66
|
+
newTableOfContents.push(oldHeading);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return newTableOfContents;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function LexicalTableOfContentsPlugin({
|
|
74
|
+
children
|
|
75
|
+
}) {
|
|
76
|
+
const [tableOfContents, setTableOfContents] = react.useState([]);
|
|
77
|
+
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
78
|
+
react.useEffect(() => {
|
|
79
|
+
// Set table of contents initial state
|
|
80
|
+
let currentTableOfContents = [];
|
|
81
|
+
editor.getEditorState().read(() => {
|
|
82
|
+
const root = lexical.$getRoot();
|
|
83
|
+
const rootChildren = root.getChildren();
|
|
84
|
+
|
|
85
|
+
for (const child of rootChildren) {
|
|
86
|
+
if (richText.$isHeadingNode(child)) {
|
|
87
|
+
currentTableOfContents.push([child.getKey(), child.getTextContent(), child.getTag()]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setTableOfContents(currentTableOfContents);
|
|
92
|
+
}); // Listen to updates to heading mutations and update state
|
|
93
|
+
|
|
94
|
+
const removeHeaderMutationListener = editor.registerMutationListener(richText.HeadingNode, mutatedNodes => {
|
|
95
|
+
editor.getEditorState().read(() => {
|
|
96
|
+
for (const [nodeKey, mutation] of mutatedNodes) {
|
|
97
|
+
if (mutation === 'created') {
|
|
98
|
+
const newHeading = lexical.$getNodeByKey(nodeKey);
|
|
99
|
+
|
|
100
|
+
if (newHeading !== null) {
|
|
101
|
+
let prevHeading = newHeading.getPreviousSibling();
|
|
102
|
+
|
|
103
|
+
while (prevHeading && !richText.$isHeadingNode(prevHeading)) {
|
|
104
|
+
prevHeading = prevHeading.getPreviousSibling();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
currentTableOfContents = $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents);
|
|
108
|
+
setTableOfContents(currentTableOfContents);
|
|
109
|
+
}
|
|
110
|
+
} else if (mutation === 'destroyed') {
|
|
111
|
+
currentTableOfContents = $deleteHeadingFromTableOfContents(nodeKey, currentTableOfContents);
|
|
112
|
+
setTableOfContents(currentTableOfContents);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}); // Listen to text node mutation updates
|
|
117
|
+
|
|
118
|
+
const removeTextNodeMutationListener = editor.registerMutationListener(lexical.TextNode, mutatedNodes => {
|
|
119
|
+
editor.getEditorState().read(() => {
|
|
120
|
+
for (const [nodeKey, mutation] of mutatedNodes) {
|
|
121
|
+
if (mutation === 'updated') {
|
|
122
|
+
const currNode = lexical.$getNodeByKey(nodeKey);
|
|
123
|
+
|
|
124
|
+
if (currNode !== null) {
|
|
125
|
+
const parentNode = currNode.getParentOrThrow();
|
|
126
|
+
|
|
127
|
+
if (richText.$isHeadingNode(parentNode)) {
|
|
128
|
+
currentTableOfContents = $updateHeadingInTableOfContents(parentNode, currentTableOfContents);
|
|
129
|
+
setTableOfContents(currentTableOfContents);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
return () => {
|
|
137
|
+
removeHeaderMutationListener();
|
|
138
|
+
removeTextNodeMutationListener();
|
|
139
|
+
};
|
|
140
|
+
}, [editor]);
|
|
141
|
+
return children(tableOfContents, editor);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = LexicalTableOfContentsPlugin;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict'
|
|
8
|
+
const LexicalTableOfContents__EXPERIMENTAL = process.env.NODE_ENV === 'development' ? require('./LexicalTableOfContents__EXPERIMENTAL.dev.js') : require('./LexicalTableOfContents__EXPERIMENTAL.prod.js')
|
|
9
|
+
module.exports = LexicalTableOfContents__EXPERIMENTAL;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {HeadingTagType} from '@lexical/rich-text';
|
|
11
|
+
import type {NodeKey} from 'lexical';
|
|
12
|
+
|
|
13
|
+
declare export function LexicalTableOfContentsPlugin({
|
|
14
|
+
children: (
|
|
15
|
+
tableOfContents: Array<[NodeKey, string, HeadingTagType]>,
|
|
16
|
+
) => React$Node,
|
|
17
|
+
}): React$Node;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';var k=require("@lexical/react/LexicalComposerContext"),l=require("@lexical/rich-text"),r=require("lexical"),u=require("react");
|
|
8
|
+
module.exports=function({children:v}){let [w,m]=u.useState([]),[f]=k.useLexicalComposerContext();u.useEffect(()=>{let b=[];f.getEditorState().read(()=>{let h=r.$getRoot().getChildren();for(let a of h)l.$isHeadingNode(a)&&b.push([a.getKey(),a.getTextContent(),a.getTag()]);m(b)});let x=f.registerMutationListener(l.HeadingNode,h=>{f.getEditorState().read(()=>{for(const [n,p]of h)if("created"===p){var a=r.$getNodeByKey(n);if(null!==a){for(var c=a.getPreviousSibling();c&&!l.$isHeadingNode(c);)c=c.getPreviousSibling();
|
|
9
|
+
a:{var d=b;if(null===a){b=d;break a}let e=[a.getKey(),a.getTextContent(),a.getTag()],g=[];if(null===c)g=[e,...d];else for(let q=0;q<d.length;q++){let t=d[q][0];g.push(d[q]);t===c.getKey()&&t!==a.getKey()&&g.push(e)}b=g}m(b)}}else if("destroyed"===p){c=n;a=b;d=[];for(let e of a)e[0]!==c&&d.push(e);b=d;m(b)}})}),y=f.registerMutationListener(r.TextNode,h=>{f.getEditorState().read(()=>{for(const [d,n]of h)if("updated"===n){var a=r.$getNodeByKey(d);if(null!==a&&(a=a.getParentOrThrow(),l.$isHeadingNode(a))){var c=
|
|
10
|
+
b;let p=a.getTextContent(),e=[];for(let g of c)g[0]===a.getKey()?e.push([a.getKey(),p,a.getTag()]):e.push(g);b=e;m(b)}}})});return()=>{x();y()}},[f]);return v(w,f)}
|