mirror of
https://github.com/facebook/lexical.git
synced 2025-05-16 22:48:52 +08:00
[lexical-react] Breaking change: Deprecate public default exports (#6088)
This commit is contained in:
22
.eslintrc.js
22
.eslintrc.js
@ -111,6 +111,28 @@ module.exports = {
|
||||
'lexical/no-optional-chaining': OFF,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'packages/*/src/index.ts',
|
||||
'packages/*/src/index.tsx',
|
||||
'packages/lexical-react/src/*.ts',
|
||||
'packages/lexical-react/src/*.tsx',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-exports': [
|
||||
'error',
|
||||
{
|
||||
restrictDefaultExports: {
|
||||
defaultFrom: true,
|
||||
direct: true,
|
||||
named: true,
|
||||
namedFrom: true,
|
||||
namespaceFrom: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
parser: '@babel/eslint-parser',
|
||||
|
@ -69,6 +69,7 @@ module.name_mapper='^@lexical/react/LexicalPlainTextPlugin$' -> '<PROJECT_ROOT>/
|
||||
module.name_mapper='^@lexical/react/LexicalRichTextPlugin$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalRichTextPlugin.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTabIndentationPlugin$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTabIndentationPlugin.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTableOfContents$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTableOfContents.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTableOfContentsPlugin$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTableOfContentsPlugin.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTablePlugin$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTablePlugin.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTreeView$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTreeView.js.flow'
|
||||
module.name_mapper='^@lexical/react/LexicalTypeaheadMenuPlugin$' -> '<PROJECT_ROOT>/packages/lexical-react/flow/LexicalTypeaheadMenuPlugin.js.flow'
|
||||
|
@ -62,7 +62,7 @@ import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {OnChangePlugin} from '@lexical/react/LexicalOnChangePlugin';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
|
||||
const theme = {
|
||||
// Theme styling goes here
|
||||
|
@ -24,7 +24,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
],
|
||||
'@babel/preset-react',
|
||||
['@babel/preset-react', {runtime: 'automatic'}],
|
||||
'@babel/preset-flow',
|
||||
],
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
|
||||
import ToolbarPlugin from './plugins/ToolbarPlugin';
|
||||
|
@ -8,7 +8,7 @@
|
||||
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {LexicalComposer} from '@lexical/react/LexicalComposer';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
|
||||
|
@ -123,6 +123,9 @@
|
||||
"@lexical/react/LexicalTableOfContents": [
|
||||
"../lexical-react/src/LexicalTableOfContents.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTableOfContentsPlugin": [
|
||||
"../lexical-react/src/LexicalTableOfContentsPlugin.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTablePlugin": [
|
||||
"../lexical-react/src/LexicalTablePlugin.ts"
|
||||
],
|
||||
|
@ -112,7 +112,7 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
],
|
||||
presets: ['@babel/preset-react'],
|
||||
presets: [['@babel/preset-react', {runtime: 'automatic'}]],
|
||||
}),
|
||||
react(),
|
||||
],
|
||||
|
@ -14,4 +14,5 @@
|
||||
import * as plugin from './LexicalEslintPlugin.js';
|
||||
|
||||
export type {RulesOfLexicalOptions} from './rules/rules-of-lexical.js';
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default plugin;
|
||||
|
@ -9,7 +9,7 @@
|
||||
import {createEmptyHistoryState, registerHistory} from '@lexical/history';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {$createQuoteNode} from '@lexical/rich-text';
|
||||
|
@ -10,9 +10,9 @@ import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {CharacterLimitPlugin} from '@lexical/react/LexicalCharacterLimitPlugin';
|
||||
import {CheckListPlugin} from '@lexical/react/LexicalCheckListPlugin';
|
||||
import {ClearEditorPlugin} from '@lexical/react/LexicalClearEditorPlugin';
|
||||
import LexicalClickableLinkPlugin from '@lexical/react/LexicalClickableLinkPlugin';
|
||||
import {ClickableLinkPlugin} from '@lexical/react/LexicalClickableLinkPlugin';
|
||||
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {HorizontalRulePlugin} from '@lexical/react/LexicalHorizontalRulePlugin';
|
||||
@ -21,7 +21,7 @@ import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {TabIndentationPlugin} from '@lexical/react/LexicalTabIndentationPlugin';
|
||||
import {TablePlugin} from '@lexical/react/LexicalTablePlugin';
|
||||
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
||||
import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
|
||||
import * as React from 'react';
|
||||
import {useEffect, useState} from 'react';
|
||||
import {CAN_USE_DOM} from 'shared/canUseDOM';
|
||||
@ -191,7 +191,7 @@ export default function Editor(): JSX.Element {
|
||||
<TwitterPlugin />
|
||||
<YouTubePlugin />
|
||||
<FigmaPlugin />
|
||||
<LexicalClickableLinkPlugin disabled={isEditable} />
|
||||
<ClickableLinkPlugin disabled={isEditable} />
|
||||
<HorizontalRulePlugin />
|
||||
<EquationsPlugin />
|
||||
<ExcalidrawPlugin />
|
||||
|
@ -19,7 +19,7 @@ import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext';
|
||||
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HashtagPlugin} from '@lexical/react/LexicalHashtagPlugin';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
|
||||
|
@ -12,7 +12,7 @@ import './InlineImageNode.css';
|
||||
|
||||
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection';
|
||||
|
@ -13,7 +13,7 @@ import './StickyNode.css';
|
||||
import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext';
|
||||
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {LexicalNestedComposer} from '@lexical/react/LexicalNestedComposer';
|
||||
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
|
||||
|
@ -32,7 +32,7 @@ import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContex
|
||||
import {LexicalComposer} from '@lexical/react/LexicalComposer';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {EditorRefPlugin} from '@lexical/react/LexicalEditorRefPlugin';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {OnChangePlugin} from '@lexical/react/LexicalOnChangePlugin';
|
||||
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
|
||||
|
@ -9,7 +9,7 @@
|
||||
import type {ElementNode, LexicalEditor} from 'lexical';
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
||||
import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
|
||||
import {
|
||||
$deleteTableColumn__EXPERIMENTAL,
|
||||
$deleteTableRow__EXPERIMENTAL,
|
||||
|
@ -11,7 +11,7 @@ import type {LexicalEditor} from 'lexical';
|
||||
import './index.css';
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
||||
import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
|
||||
import {
|
||||
$getTableColumnIndexFromTableCellNode,
|
||||
$getTableNodeFromLexicalNodeOrThrow,
|
||||
|
@ -5,14 +5,14 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
import type {TableOfContentsEntry} from '@lexical/react/LexicalTableOfContents';
|
||||
import type {TableOfContentsEntry} from '@lexical/react/LexicalTableOfContentsPlugin';
|
||||
import type {HeadingTagType} from '@lexical/rich-text';
|
||||
import type {NodeKey} from 'lexical';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalTableOfContents from '@lexical/react/LexicalTableOfContents';
|
||||
import {TableOfContentsPlugin as LexicalTableOfContentsPlugin} from '@lexical/react/LexicalTableOfContentsPlugin';
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
@ -188,10 +188,10 @@ function TableOfContentsList({
|
||||
|
||||
export default function TableOfContentsPlugin() {
|
||||
return (
|
||||
<LexicalTableOfContents>
|
||||
<LexicalTableOfContentsPlugin>
|
||||
{(tableOfContents) => {
|
||||
return <TableOfContentsList tableOfContents={tableOfContents} />;
|
||||
}}
|
||||
</LexicalTableOfContents>
|
||||
</LexicalTableOfContentsPlugin>
|
||||
);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ export default defineConfig(({command}) => {
|
||||
},
|
||||
],
|
||||
],
|
||||
presets: ['@babel/preset-react'],
|
||||
presets: [['@babel/preset-react', {runtime: 'automatic'}]],
|
||||
}),
|
||||
react(),
|
||||
viteCopyEsm(),
|
||||
|
@ -62,7 +62,7 @@ export default defineConfig({
|
||||
exclude: '/**/node_modules/**',
|
||||
extensions: ['jsx', 'js', 'ts', 'tsx', 'mjs'],
|
||||
plugins: ['@babel/plugin-transform-flow-strip-types'],
|
||||
presets: ['@babel/preset-react'],
|
||||
presets: [['@babel/preset-react', {runtime: 'automatic'}]],
|
||||
}),
|
||||
react(),
|
||||
viteCopyEsm(),
|
||||
|
@ -7,6 +7,8 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
declare export function MLCClickableLinkPlugin({
|
||||
declare export function ClickableLinkPlugin({
|
||||
newTab?: boolean,
|
||||
}): null;
|
||||
|
||||
declare export default typeof ClickableLinkPlugin;
|
||||
|
@ -12,6 +12,9 @@ export type LexicalErrorBoundaryProps = $ReadOnly<{
|
||||
onError: (error: Error) => void,
|
||||
}>;
|
||||
|
||||
declare export default function LexicalErrorBoundary(
|
||||
declare export function LexicalErrorBoundary(
|
||||
props: LexicalErrorBoundaryProps,
|
||||
): React$Node;
|
||||
|
||||
/** @deprecated use the named export {@link LexicalErrorBoundary} */
|
||||
export default typeof LexicalErrorBoundary;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
import type {EditorState, LexicalEditor} from 'lexical';
|
||||
|
||||
import typeof LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {typeof LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
import type {EditorState, LexicalEditor} from 'lexical';
|
||||
|
||||
import typeof LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {typeof LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
|
@ -7,11 +7,7 @@
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {HeadingTagType} from '@lexical/rich-text';
|
||||
import type {NodeKey} from 'lexical';
|
||||
import {TableOfContentsPlugin} from '@lexical/react/LexicalTableOfContentsPlugin';
|
||||
|
||||
declare export default function LexicalTableOfContentsPlugin({
|
||||
children: (
|
||||
tableOfContents: Array<[NodeKey, string, HeadingTagType]>,
|
||||
) => React$Node,
|
||||
}): React$Node;
|
||||
/** @deprecated use the named export {@link LexicalTableOfContentsPlugin} */
|
||||
declare export default typeof TableOfContentsPlugin;
|
||||
|
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
*/
|
||||
|
||||
import type {HeadingTagType} from '@lexical/rich-text';
|
||||
import type {LexicalEditor, NodeKey} from 'lexical';
|
||||
|
||||
declare export function TableOfContentsPlugin({
|
||||
children: (
|
||||
tableOfContents: Array<[NodeKey, string, HeadingTagType]>,
|
||||
editor: LexicalEditor,
|
||||
) => React$Node,
|
||||
}): React$Node;
|
@ -9,4 +9,7 @@
|
||||
|
||||
import type {LexicalEditor} from 'lexical';
|
||||
|
||||
declare export default function useLexicalEditable(): boolean;
|
||||
declare export function useLexicalEditable(): boolean;
|
||||
|
||||
/** @deprecated use the named export {@link useLexicalEditable} */
|
||||
declare export default typeof useLexicalEditable;
|
||||
|
@ -14,6 +14,9 @@ export type LexicalSubscription<T> = {
|
||||
subscribe: (callback: (value: T) => void) => () => void,
|
||||
};
|
||||
|
||||
declare export default function useLexicalSubscription<T>(
|
||||
declare export function useLexicalSubscription<T>(
|
||||
subscription: (editor: LexicalEditor) => LexicalSubscription<T>,
|
||||
): T;
|
||||
|
||||
/** @deprecated use the named export {@link useLexicalSubscription} */
|
||||
declare export default typeof useLexicalSubscription;
|
||||
|
@ -1001,6 +1001,36 @@
|
||||
"default": "./LexicalTableOfContents.js"
|
||||
}
|
||||
},
|
||||
"./LexicalTableOfContentsPlugin": {
|
||||
"import": {
|
||||
"types": "./LexicalTableOfContentsPlugin.d.ts",
|
||||
"development": "./LexicalTableOfContentsPlugin.dev.mjs",
|
||||
"production": "./LexicalTableOfContentsPlugin.prod.mjs",
|
||||
"node": "./LexicalTableOfContentsPlugin.node.mjs",
|
||||
"default": "./LexicalTableOfContentsPlugin.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./LexicalTableOfContentsPlugin.d.ts",
|
||||
"development": "./LexicalTableOfContentsPlugin.dev.js",
|
||||
"production": "./LexicalTableOfContentsPlugin.prod.js",
|
||||
"default": "./LexicalTableOfContentsPlugin.js"
|
||||
}
|
||||
},
|
||||
"./LexicalTableOfContentsPlugin.js": {
|
||||
"import": {
|
||||
"types": "./LexicalTableOfContentsPlugin.d.ts",
|
||||
"development": "./LexicalTableOfContentsPlugin.dev.mjs",
|
||||
"production": "./LexicalTableOfContentsPlugin.prod.mjs",
|
||||
"node": "./LexicalTableOfContentsPlugin.node.mjs",
|
||||
"default": "./LexicalTableOfContentsPlugin.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./LexicalTableOfContentsPlugin.d.ts",
|
||||
"development": "./LexicalTableOfContentsPlugin.dev.js",
|
||||
"production": "./LexicalTableOfContentsPlugin.prod.js",
|
||||
"default": "./LexicalTableOfContentsPlugin.js"
|
||||
}
|
||||
},
|
||||
"./LexicalTablePlugin": {
|
||||
"import": {
|
||||
"types": "./LexicalTablePlugin.d.ts",
|
||||
|
@ -32,7 +32,7 @@ function findMatchingDOM<T extends Node>(
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function LexicalClickableLinkPlugin({
|
||||
export function ClickableLinkPlugin({
|
||||
newTab = true,
|
||||
disabled = false,
|
||||
}: {
|
||||
@ -122,3 +122,7 @@ export default function LexicalClickableLinkPlugin({
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @deprecated use the named export {@link ClickableLinkPlugin} */
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default ClickableLinkPlugin;
|
||||
|
@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {ErrorBoundary as ReactErrorBoundary} from 'react-error-boundary';
|
||||
|
||||
export type LexicalErrorBoundaryProps = {
|
||||
@ -14,7 +13,7 @@ export type LexicalErrorBoundaryProps = {
|
||||
onError: (error: Error) => void;
|
||||
};
|
||||
|
||||
export default function LexicalErrorBoundary({
|
||||
export function LexicalErrorBoundary({
|
||||
children,
|
||||
onError,
|
||||
}: LexicalErrorBoundaryProps): JSX.Element {
|
||||
@ -35,3 +34,7 @@ export default function LexicalErrorBoundary({
|
||||
</ReactErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated use the named export {@link LexicalErrorBoundary} */
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default LexicalErrorBoundary;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
||||
import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
|
||||
import * as React from 'react';
|
||||
|
||||
import {useCanShowPlaceholder} from './shared/useCanShowPlaceholder';
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
||||
import {useLexicalEditable} from '@lexical/react/useLexicalEditable';
|
||||
import * as React from 'react';
|
||||
|
||||
import {useCanShowPlaceholder} from './shared/useCanShowPlaceholder';
|
||||
|
@ -6,264 +6,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {$isHeadingNode, HeadingNode, HeadingTagType} from '@lexical/rich-text';
|
||||
import {$getNextRightPreorderNode} from '@lexical/utils';
|
||||
/** @deprecated moved to @lexical/react/LexicalTableOfContentsPlugin */
|
||||
import {
|
||||
$getNodeByKey,
|
||||
$getRoot,
|
||||
$isElementNode,
|
||||
ElementNode,
|
||||
LexicalEditor,
|
||||
NodeKey,
|
||||
NodeMutation,
|
||||
TextNode,
|
||||
} from 'lexical';
|
||||
import {useEffect, useState} from 'react';
|
||||
type TableOfContentsEntry,
|
||||
TableOfContentsPlugin,
|
||||
} from './LexicalTableOfContentsPlugin';
|
||||
|
||||
export type TableOfContentsEntry = [
|
||||
key: NodeKey,
|
||||
text: string,
|
||||
tag: HeadingTagType,
|
||||
];
|
||||
/** @deprecated use the module @lexical/react/LexicalTableOfContentsPlugin */
|
||||
export {type TableOfContentsEntry};
|
||||
|
||||
function toEntry(heading: HeadingNode): TableOfContentsEntry {
|
||||
return [heading.getKey(), heading.getTextContent(), heading.getTag()];
|
||||
}
|
||||
|
||||
function $insertHeadingIntoTableOfContents(
|
||||
prevHeading: HeadingNode | null,
|
||||
newHeading: HeadingNode | null,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
if (newHeading === null) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
const newEntry: TableOfContentsEntry = toEntry(newHeading);
|
||||
let newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
if (prevHeading === null) {
|
||||
// check if key already exists
|
||||
if (
|
||||
currentTableOfContents.length > 0 &&
|
||||
currentTableOfContents[0][0] === newHeading.__key
|
||||
) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
newTableOfContents = [newEntry, ...currentTableOfContents];
|
||||
} else {
|
||||
for (let i = 0; i < currentTableOfContents.length; i++) {
|
||||
const key = currentTableOfContents[i][0];
|
||||
newTableOfContents.push(currentTableOfContents[i]);
|
||||
if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
|
||||
// check if key already exists
|
||||
if (
|
||||
i + 1 < currentTableOfContents.length &&
|
||||
currentTableOfContents[i + 1][0] === newHeading.__key
|
||||
) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $deleteHeadingFromTableOfContents(
|
||||
key: NodeKey,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents = [];
|
||||
for (const heading of currentTableOfContents) {
|
||||
if (heading[0] !== key) {
|
||||
newTableOfContents.push(heading);
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $updateHeadingInTableOfContents(
|
||||
heading: HeadingNode,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
for (const oldHeading of currentTableOfContents) {
|
||||
if (oldHeading[0] === heading.getKey()) {
|
||||
newTableOfContents.push(toEntry(heading));
|
||||
} else {
|
||||
newTableOfContents.push(oldHeading);
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the updated table of contents, placing the given `heading` before the given `prevHeading`. If `prevHeading`
|
||||
* is undefined, `heading` is placed at the start of table of contents
|
||||
*/
|
||||
function $updateHeadingPosition(
|
||||
prevHeading: HeadingNode | null,
|
||||
heading: HeadingNode,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
const newEntry: TableOfContentsEntry = toEntry(heading);
|
||||
|
||||
if (!prevHeading) {
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
for (const oldHeading of currentTableOfContents) {
|
||||
if (oldHeading[0] === heading.getKey()) {
|
||||
continue;
|
||||
}
|
||||
newTableOfContents.push(oldHeading);
|
||||
if (prevHeading && oldHeading[0] === prevHeading.getKey()) {
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $getPreviousHeading(node: HeadingNode): HeadingNode | null {
|
||||
let prevHeading = $getNextRightPreorderNode(node);
|
||||
while (prevHeading !== null && !$isHeadingNode(prevHeading)) {
|
||||
prevHeading = $getNextRightPreorderNode(prevHeading);
|
||||
}
|
||||
return prevHeading;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
children: (
|
||||
values: Array<TableOfContentsEntry>,
|
||||
editor: LexicalEditor,
|
||||
) => JSX.Element;
|
||||
};
|
||||
|
||||
export default function LexicalTableOfContentsPlugin({
|
||||
children,
|
||||
}: Props): JSX.Element {
|
||||
const [tableOfContents, setTableOfContents] = useState<
|
||||
Array<TableOfContentsEntry>
|
||||
>([]);
|
||||
const [editor] = useLexicalComposerContext();
|
||||
useEffect(() => {
|
||||
// Set table of contents initial state
|
||||
let currentTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
editor.getEditorState().read(() => {
|
||||
const root = $getRoot();
|
||||
const rootChildren = root.getChildren();
|
||||
for (const child of rootChildren) {
|
||||
if ($isHeadingNode(child)) {
|
||||
currentTableOfContents.push([
|
||||
child.getKey(),
|
||||
child.getTextContent(),
|
||||
child.getTag(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
setTableOfContents(currentTableOfContents);
|
||||
});
|
||||
|
||||
const removeRootUpdateListener = editor.registerUpdateListener(
|
||||
({editorState, dirtyElements}) => {
|
||||
editorState.read(() => {
|
||||
const updateChildHeadings = (node: ElementNode) => {
|
||||
for (const child of node.getChildren()) {
|
||||
if ($isHeadingNode(child)) {
|
||||
const prevHeading = $getPreviousHeading(child);
|
||||
currentTableOfContents = $updateHeadingPosition(
|
||||
prevHeading,
|
||||
child,
|
||||
currentTableOfContents,
|
||||
);
|
||||
setTableOfContents(currentTableOfContents);
|
||||
} else if ($isElementNode(child)) {
|
||||
updateChildHeadings(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If a node is changes, all child heading positions need to be updated
|
||||
$getRoot()
|
||||
.getChildren()
|
||||
.forEach((node) => {
|
||||
if ($isElementNode(node) && dirtyElements.get(node.__key)) {
|
||||
updateChildHeadings(node);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Listen to updates to heading mutations and update state
|
||||
const removeHeaderMutationListener = editor.registerMutationListener(
|
||||
HeadingNode,
|
||||
(mutatedNodes: Map<string, NodeMutation>) => {
|
||||
editor.getEditorState().read(() => {
|
||||
for (const [nodeKey, mutation] of mutatedNodes) {
|
||||
if (mutation === 'created') {
|
||||
const newHeading = $getNodeByKey<HeadingNode>(nodeKey);
|
||||
if (newHeading !== null) {
|
||||
const prevHeading = $getPreviousHeading(newHeading);
|
||||
currentTableOfContents = $insertHeadingIntoTableOfContents(
|
||||
prevHeading,
|
||||
newHeading,
|
||||
currentTableOfContents,
|
||||
);
|
||||
}
|
||||
} else if (mutation === 'destroyed') {
|
||||
currentTableOfContents = $deleteHeadingFromTableOfContents(
|
||||
nodeKey,
|
||||
currentTableOfContents,
|
||||
);
|
||||
} else if (mutation === 'updated') {
|
||||
const newHeading = $getNodeByKey<HeadingNode>(nodeKey);
|
||||
if (newHeading !== null) {
|
||||
const prevHeading = $getPreviousHeading(newHeading);
|
||||
currentTableOfContents = $updateHeadingPosition(
|
||||
prevHeading,
|
||||
newHeading,
|
||||
currentTableOfContents,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTableOfContents(currentTableOfContents);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Listen to text node mutation updates
|
||||
const removeTextNodeMutationListener = editor.registerMutationListener(
|
||||
TextNode,
|
||||
(mutatedNodes: Map<string, NodeMutation>) => {
|
||||
editor.getEditorState().read(() => {
|
||||
for (const [nodeKey, mutation] of mutatedNodes) {
|
||||
if (mutation === 'updated') {
|
||||
const currNode = $getNodeByKey(nodeKey);
|
||||
if (currNode !== null) {
|
||||
const parentNode = currNode.getParentOrThrow();
|
||||
if ($isHeadingNode(parentNode)) {
|
||||
currentTableOfContents = $updateHeadingInTableOfContents(
|
||||
parentNode,
|
||||
currentTableOfContents,
|
||||
);
|
||||
setTableOfContents(currentTableOfContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
removeHeaderMutationListener();
|
||||
removeTextNodeMutationListener();
|
||||
removeRootUpdateListener();
|
||||
};
|
||||
}, [editor]);
|
||||
|
||||
return children(tableOfContents, editor);
|
||||
}
|
||||
/** @deprecated use module @lexical/react/LexicalTableOfContentsPlugin */
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default TableOfContentsPlugin;
|
||||
|
267
packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx
Normal file
267
packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx
Normal file
@ -0,0 +1,267 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {$isHeadingNode, HeadingNode, HeadingTagType} from '@lexical/rich-text';
|
||||
import {$getNextRightPreorderNode} from '@lexical/utils';
|
||||
import {
|
||||
$getNodeByKey,
|
||||
$getRoot,
|
||||
$isElementNode,
|
||||
ElementNode,
|
||||
LexicalEditor,
|
||||
NodeKey,
|
||||
NodeMutation,
|
||||
TextNode,
|
||||
} from 'lexical';
|
||||
import {useEffect, useState} from 'react';
|
||||
|
||||
export type TableOfContentsEntry = [
|
||||
key: NodeKey,
|
||||
text: string,
|
||||
tag: HeadingTagType,
|
||||
];
|
||||
|
||||
function toEntry(heading: HeadingNode): TableOfContentsEntry {
|
||||
return [heading.getKey(), heading.getTextContent(), heading.getTag()];
|
||||
}
|
||||
|
||||
function $insertHeadingIntoTableOfContents(
|
||||
prevHeading: HeadingNode | null,
|
||||
newHeading: HeadingNode | null,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
if (newHeading === null) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
const newEntry: TableOfContentsEntry = toEntry(newHeading);
|
||||
let newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
if (prevHeading === null) {
|
||||
// check if key already exists
|
||||
if (
|
||||
currentTableOfContents.length > 0 &&
|
||||
currentTableOfContents[0][0] === newHeading.__key
|
||||
) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
newTableOfContents = [newEntry, ...currentTableOfContents];
|
||||
} else {
|
||||
for (let i = 0; i < currentTableOfContents.length; i++) {
|
||||
const key = currentTableOfContents[i][0];
|
||||
newTableOfContents.push(currentTableOfContents[i]);
|
||||
if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
|
||||
// check if key already exists
|
||||
if (
|
||||
i + 1 < currentTableOfContents.length &&
|
||||
currentTableOfContents[i + 1][0] === newHeading.__key
|
||||
) {
|
||||
return currentTableOfContents;
|
||||
}
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $deleteHeadingFromTableOfContents(
|
||||
key: NodeKey,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents = [];
|
||||
for (const heading of currentTableOfContents) {
|
||||
if (heading[0] !== key) {
|
||||
newTableOfContents.push(heading);
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $updateHeadingInTableOfContents(
|
||||
heading: HeadingNode,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
for (const oldHeading of currentTableOfContents) {
|
||||
if (oldHeading[0] === heading.getKey()) {
|
||||
newTableOfContents.push(toEntry(heading));
|
||||
} else {
|
||||
newTableOfContents.push(oldHeading);
|
||||
}
|
||||
}
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the updated table of contents, placing the given `heading` before the given `prevHeading`. If `prevHeading`
|
||||
* is undefined, `heading` is placed at the start of table of contents
|
||||
*/
|
||||
function $updateHeadingPosition(
|
||||
prevHeading: HeadingNode | null,
|
||||
heading: HeadingNode,
|
||||
currentTableOfContents: Array<TableOfContentsEntry>,
|
||||
): Array<TableOfContentsEntry> {
|
||||
const newTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
const newEntry: TableOfContentsEntry = toEntry(heading);
|
||||
|
||||
if (!prevHeading) {
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
for (const oldHeading of currentTableOfContents) {
|
||||
if (oldHeading[0] === heading.getKey()) {
|
||||
continue;
|
||||
}
|
||||
newTableOfContents.push(oldHeading);
|
||||
if (prevHeading && oldHeading[0] === prevHeading.getKey()) {
|
||||
newTableOfContents.push(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return newTableOfContents;
|
||||
}
|
||||
|
||||
function $getPreviousHeading(node: HeadingNode): HeadingNode | null {
|
||||
let prevHeading = $getNextRightPreorderNode(node);
|
||||
while (prevHeading !== null && !$isHeadingNode(prevHeading)) {
|
||||
prevHeading = $getNextRightPreorderNode(prevHeading);
|
||||
}
|
||||
return prevHeading;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
children: (
|
||||
values: Array<TableOfContentsEntry>,
|
||||
editor: LexicalEditor,
|
||||
) => JSX.Element;
|
||||
};
|
||||
|
||||
export function TableOfContentsPlugin({children}: Props): JSX.Element {
|
||||
const [tableOfContents, setTableOfContents] = useState<
|
||||
Array<TableOfContentsEntry>
|
||||
>([]);
|
||||
const [editor] = useLexicalComposerContext();
|
||||
useEffect(() => {
|
||||
// Set table of contents initial state
|
||||
let currentTableOfContents: Array<TableOfContentsEntry> = [];
|
||||
editor.getEditorState().read(() => {
|
||||
const root = $getRoot();
|
||||
const rootChildren = root.getChildren();
|
||||
for (const child of rootChildren) {
|
||||
if ($isHeadingNode(child)) {
|
||||
currentTableOfContents.push([
|
||||
child.getKey(),
|
||||
child.getTextContent(),
|
||||
child.getTag(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
setTableOfContents(currentTableOfContents);
|
||||
});
|
||||
|
||||
const removeRootUpdateListener = editor.registerUpdateListener(
|
||||
({editorState, dirtyElements}) => {
|
||||
editorState.read(() => {
|
||||
const updateChildHeadings = (node: ElementNode) => {
|
||||
for (const child of node.getChildren()) {
|
||||
if ($isHeadingNode(child)) {
|
||||
const prevHeading = $getPreviousHeading(child);
|
||||
currentTableOfContents = $updateHeadingPosition(
|
||||
prevHeading,
|
||||
child,
|
||||
currentTableOfContents,
|
||||
);
|
||||
setTableOfContents(currentTableOfContents);
|
||||
} else if ($isElementNode(child)) {
|
||||
updateChildHeadings(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If a node is changes, all child heading positions need to be updated
|
||||
$getRoot()
|
||||
.getChildren()
|
||||
.forEach((node) => {
|
||||
if ($isElementNode(node) && dirtyElements.get(node.__key)) {
|
||||
updateChildHeadings(node);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Listen to updates to heading mutations and update state
|
||||
const removeHeaderMutationListener = editor.registerMutationListener(
|
||||
HeadingNode,
|
||||
(mutatedNodes: Map<string, NodeMutation>) => {
|
||||
editor.getEditorState().read(() => {
|
||||
for (const [nodeKey, mutation] of mutatedNodes) {
|
||||
if (mutation === 'created') {
|
||||
const newHeading = $getNodeByKey<HeadingNode>(nodeKey);
|
||||
if (newHeading !== null) {
|
||||
const prevHeading = $getPreviousHeading(newHeading);
|
||||
currentTableOfContents = $insertHeadingIntoTableOfContents(
|
||||
prevHeading,
|
||||
newHeading,
|
||||
currentTableOfContents,
|
||||
);
|
||||
}
|
||||
} else if (mutation === 'destroyed') {
|
||||
currentTableOfContents = $deleteHeadingFromTableOfContents(
|
||||
nodeKey,
|
||||
currentTableOfContents,
|
||||
);
|
||||
} else if (mutation === 'updated') {
|
||||
const newHeading = $getNodeByKey<HeadingNode>(nodeKey);
|
||||
if (newHeading !== null) {
|
||||
const prevHeading = $getPreviousHeading(newHeading);
|
||||
currentTableOfContents = $updateHeadingPosition(
|
||||
prevHeading,
|
||||
newHeading,
|
||||
currentTableOfContents,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTableOfContents(currentTableOfContents);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Listen to text node mutation updates
|
||||
const removeTextNodeMutationListener = editor.registerMutationListener(
|
||||
TextNode,
|
||||
(mutatedNodes: Map<string, NodeMutation>) => {
|
||||
editor.getEditorState().read(() => {
|
||||
for (const [nodeKey, mutation] of mutatedNodes) {
|
||||
if (mutation === 'updated') {
|
||||
const currNode = $getNodeByKey(nodeKey);
|
||||
if (currNode !== null) {
|
||||
const parentNode = currNode.getParentOrThrow();
|
||||
if ($isHeadingNode(parentNode)) {
|
||||
currentTableOfContents = $updateHeadingInTableOfContents(
|
||||
parentNode,
|
||||
currentTableOfContents,
|
||||
);
|
||||
setTableOfContents(currentTableOfContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
removeHeaderMutationListener();
|
||||
removeTextNodeMutationListener();
|
||||
removeRootUpdateListener();
|
||||
};
|
||||
}, [editor]);
|
||||
|
||||
return children(tableOfContents, editor);
|
||||
}
|
@ -12,7 +12,7 @@ import {AutoLinkNode, LinkNode} from '@lexical/link';
|
||||
import {ListItemNode, ListNode} from '@lexical/list';
|
||||
import {OverflowNode} from '@lexical/overflow';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HeadingNode, QuoteNode} from '@lexical/rich-text';
|
||||
import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
|
||||
import {$rootTextContent} from '@lexical/text';
|
||||
|
@ -19,7 +19,7 @@ import {CollaborationPlugin} from '../../LexicalCollaborationPlugin';
|
||||
import {LexicalComposer} from '../../LexicalComposer';
|
||||
import {useLexicalComposerContext} from '../../LexicalComposerContext';
|
||||
import {ContentEditable} from '../../LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '../../LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '../../LexicalErrorBoundary';
|
||||
import {RichTextPlugin} from '../../LexicalRichTextPlugin';
|
||||
|
||||
function Editor({
|
||||
|
@ -9,7 +9,7 @@
|
||||
import type {LexicalSubscription} from './useLexicalSubscription';
|
||||
import type {LexicalEditor} from 'lexical';
|
||||
|
||||
import useLexicalSubscription from './useLexicalSubscription';
|
||||
import {useLexicalSubscription} from './useLexicalSubscription';
|
||||
|
||||
function subscription(editor: LexicalEditor): LexicalSubscription<boolean> {
|
||||
return {
|
||||
@ -20,6 +20,10 @@ function subscription(editor: LexicalEditor): LexicalSubscription<boolean> {
|
||||
};
|
||||
}
|
||||
|
||||
export default function useLexicalEditable(): boolean {
|
||||
export function useLexicalEditable(): boolean {
|
||||
return useLexicalSubscription(subscription);
|
||||
}
|
||||
|
||||
/** @deprecated use the named export {@link useLexicalEditable} */
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default useLexicalEditable;
|
||||
|
@ -20,7 +20,7 @@ export type LexicalSubscription<T> = {
|
||||
/**
|
||||
* Shortcut to Lexical subscriptions when values are used for render.
|
||||
*/
|
||||
export default function useLexicalSubscription<T>(
|
||||
export function useLexicalSubscription<T>(
|
||||
subscription: (editor: LexicalEditor) => LexicalSubscription<T>,
|
||||
): T {
|
||||
const [editor] = useLexicalComposerContext();
|
||||
@ -46,3 +46,7 @@ export default function useLexicalSubscription<T>(
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @deprecated use the named export {@link useLexicalSubscription} */
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default useLexicalSubscription;
|
||||
|
@ -10,7 +10,7 @@ import {$createLinkNode} from '@lexical/link';
|
||||
import {$createListItemNode, $createListNode} from '@lexical/list';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {$createHeadingNode} from '@lexical/rich-text';
|
||||
|
@ -14,7 +14,7 @@ import {OverflowNode} from '@lexical/overflow';
|
||||
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {HeadingNode, QuoteNode} from '@lexical/rich-text';
|
||||
import {
|
||||
|
@ -43,7 +43,7 @@ $ HOST=localhost PORT=1234 YPERSISTENCE=./yjs-wss-db npx y-websocket
|
||||
import {$getRoot, $createParagraphNode, $createTextNode} from 'lexical';
|
||||
import {LexicalComposer} from '@lexical/react/LexicalComposer';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {CollaborationPlugin} from '@lexical/react/LexicalCollaborationPlugin';
|
||||
import * as Y from 'yjs';
|
||||
|
@ -37,7 +37,7 @@ import {LexicalComposer} from '@lexical/react/LexicalComposer';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
|
||||
const theme = {
|
||||
// Theme styling goes here
|
||||
|
@ -49,7 +49,7 @@ import {LexicalComposer} from '@lexical/react/LexicalComposer';
|
||||
import {PlainTextPlugin} from '@lexical/react/LexicalPlainTextPlugin';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import {exampleTheme} from './exampleTheme';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
|
||||
const initialConfig = {namespace: 'MyEditor', theme: exampleTheme};
|
||||
|
||||
|
@ -169,20 +169,22 @@ Adds markdown shortcut support: headings, lists, code blocks, quotes, links and
|
||||
<MarkdownShortcutPlugin />
|
||||
```
|
||||
|
||||
### `TableOfContentsPlugin`
|
||||
This plugin allows you to navigate to certain sections of the page by clicking on headings that exist inside these sections. Once you load the plugin, it automatically collects and injects the headings of the page inside the table of contents, then it listens to any deletions or modifications to those headings and updates the table of contents. Additionally, it's able to track any newly added headings and inserts them in the table of contents once they are created. This plugin also supports lazy loading - so you can defer adding the plugin until when the user needs it.
|
||||
### `LexicalTableOfContentsPlugin`
|
||||
|
||||
This plugin allows you to render a table of contents for a page from the headings from the editor. It listens to any deletions or modifications to those headings and updates the table of contents. Additionally, it's able to track any newly added headings and inserts them in the table of contents once they are created. This plugin also supports lazy loading - so you can defer adding the plugin until when the user needs it.
|
||||
|
||||
In order to use `TableOfContentsPlugin`, you need to pass a callback function in its children. This callback function gives you access to the up-to-date data of the table of contents. You can access this data through a single parameter for the callback which comes in the form of an array of arrays `[[headingKey, headingTextContent, headingTag], [], [], ...]`
|
||||
|
||||
`headingKey`: Unique key that identifies the heading.
|
||||
`headingTextContent`: A string of the exact text of the heading.
|
||||
`headingTag`: A string that reads either 'h1', 'h2', or 'h3'.
|
||||
|
||||
```jsx
|
||||
<TableOfContentsPlugin />
|
||||
```
|
||||
You can alternatively leverage the use of `LexicalTableOfContents` API, which provides you with all the functionality that `TableOfContentsPlugin` provides, but without any styling.
|
||||
In order to use `LexicalTableOfContents`, you need to pass a callback function in its children. This callback function gives you access to the up-to-date data of the table of contents. You can access this data through a single parameter for the callback which comes in the form of an array of arrays `[[headingKey, headingTextContent, headingTag], [], [], ...]`
|
||||
`headingKey`: Unique key that identifies the heading.`headingTextContent`: A string of the exact text of the heading.`headingTag`: A string that reads either 'h1', 'h2', or 'h3'.
|
||||
```jsx
|
||||
<LexicalTableOfContents>
|
||||
<TableOfContentsPlugin>
|
||||
{(tableOfContentsArray) => {
|
||||
return <MyCustomTableOfContetsPlugin tableOfContents={tableOfContentsArray} />;
|
||||
return <MyCustomTableOfContentsPlugin tableOfContents={tableOfContentsArray} />;
|
||||
}}
|
||||
</LexicalTableOfContents>
|
||||
</TableOfContentsPlugin>
|
||||
```
|
||||
|
||||
### `LexicalEditorRefPlugin`
|
||||
|
@ -447,7 +447,7 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor {
|
||||
// Ensure custom nodes implement required methods.
|
||||
if (__DEV__) {
|
||||
const name = klass.name;
|
||||
if (name !== 'RootNode') {
|
||||
if (name !== 'RootNode' && name !== 'ArtificialNode__DO_NOT_USE') {
|
||||
const proto = klass.prototype;
|
||||
['getType', 'clone'].forEach((method) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {
|
||||
$createTableCellNode,
|
||||
|
@ -8,7 +8,7 @@
|
||||
import {ListItemNode, ListNode} from '@lexical/list';
|
||||
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
||||
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
|
||||
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
|
||||
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
|
||||
import {ListPlugin} from '@lexical/react/LexicalListPlugin';
|
||||
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
|
||||
import {
|
||||
|
@ -8,7 +8,7 @@
|
||||
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
|
||||
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
||||
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
||||
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
|
||||
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
||||
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
||||
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
||||
import {
|
||||
|
@ -9,7 +9,7 @@
|
||||
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
|
||||
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
||||
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
||||
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
|
||||
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
||||
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
||||
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
||||
import {
|
||||
|
@ -191,7 +191,7 @@ async function build(name, inputFile, outputPath, outputFile, isProd, format) {
|
||||
tsconfig: path.resolve('./tsconfig.build.json'),
|
||||
},
|
||||
],
|
||||
'@babel/preset-react',
|
||||
['@babel/preset-react', {runtime: 'automatic'}],
|
||||
],
|
||||
}),
|
||||
{
|
||||
@ -238,7 +238,7 @@ async function build(name, inputFile, outputPath, outputFile, isProd, format) {
|
||||
};
|
||||
const outputOptions = {
|
||||
esModule: false,
|
||||
exports: 'auto',
|
||||
exports: 'named',
|
||||
externalLiveBindings: false,
|
||||
file: outputFile,
|
||||
format, // change between es and cjs modules
|
||||
|
@ -92,8 +92,6 @@ async function expectTransform(opts) {
|
||||
const {code} = babel.transform(fmt`${opts.codeBefore}`, {
|
||||
plugins: [[transformErrorMessages, {errorCodesPath, ...opts.opts}]],
|
||||
});
|
||||
const afterCode = fmt`${code}`;
|
||||
console.log({afterCode, code});
|
||||
expect(fmt`${code}`).toEqual(fmt`${opts.codeExpect}`);
|
||||
},
|
||||
);
|
||||
|
@ -23,7 +23,7 @@ const BLOCK_REGEX =
|
||||
|
||||
function flowTemplate(wwwName) {
|
||||
return (
|
||||
headerTemplate.replace(/^( *\/)$/, '* @flow strict\n$1') +
|
||||
headerTemplate.replace(/^( \*\/)$/m, '* @flow strict\n$1') +
|
||||
`
|
||||
/**
|
||||
* ${wwwName}
|
||||
|
@ -124,6 +124,9 @@
|
||||
"@lexical/react/LexicalTableOfContents": [
|
||||
"./packages/lexical-react/src/LexicalTableOfContents.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTableOfContentsPlugin": [
|
||||
"./packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTablePlugin": [
|
||||
"./packages/lexical-react/src/LexicalTablePlugin.ts"
|
||||
],
|
||||
|
@ -132,6 +132,9 @@
|
||||
"@lexical/react/LexicalTableOfContents": [
|
||||
"./packages/lexical-react/src/LexicalTableOfContents.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTableOfContentsPlugin": [
|
||||
"./packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx"
|
||||
],
|
||||
"@lexical/react/LexicalTablePlugin": [
|
||||
"./packages/lexical-react/src/LexicalTablePlugin.ts"
|
||||
],
|
||||
|
Reference in New Issue
Block a user