@byline/richtext-lexical 1.11.2 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/field/apply-value-plugin.js +1 -3
- package/dist/field/config/default-extensions.d.ts +32 -0
- package/dist/field/config/default-extensions.js +49 -0
- package/dist/field/config/default.d.ts +8 -0
- package/dist/field/config/default.js +0 -28
- package/dist/field/config/editor-config-context.js +2 -6
- package/dist/field/config/extensions-list.d.ts +44 -0
- package/dist/field/config/extensions-list.js +55 -0
- package/dist/field/config/types.d.ts +28 -1
- package/dist/field/editor-context.d.ts +1 -1
- package/dist/field/editor-context.js +39 -35
- package/dist/field/editor.js +11 -57
- package/dist/field/{plugins/admonition-plugin/index.d.ts → extensions/admonition/admonition-extension.d.ts} +2 -1
- package/dist/field/{plugins/admonition-plugin/index.js → extensions/admonition/admonition-extension.js} +51 -4
- package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.d.ts +1 -1
- package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.js +1 -1
- package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node.d.ts +1 -1
- package/dist/field/{plugins/admonition-plugin → extensions/admonition}/fields.d.ts +1 -1
- package/dist/field/{nodes/admonition-node → extensions/admonition}/index.js +1 -1
- package/dist/field/{plugins/admonition-plugin → extensions/admonition}/types.d.ts +1 -1
- package/dist/field/{plugins/auto-embed-plugin/index.d.ts → extensions/auto-embed/auto-embed-extension.d.ts} +1 -0
- package/dist/field/{plugins/auto-embed-plugin/index.js → extensions/auto-embed/auto-embed-extension.js} +47 -4
- package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.d.ts +1 -1
- package/dist/field/extensions/byline-floating-ui/byline-floating-ui-extension.d.ts +68 -0
- package/dist/field/extensions/byline-floating-ui/byline-floating-ui-extension.js +19 -0
- package/dist/field/{nodes/admonition-node → extensions/byline-floating-ui}/index.d.ts +1 -2
- package/dist/field/extensions/byline-floating-ui/index.js +1 -0
- package/dist/field/extensions/byline-toolbar/byline-toolbar-extension.d.ts +69 -0
- package/dist/field/extensions/byline-toolbar/byline-toolbar-extension.js +19 -0
- package/dist/field/{nodes/inline-image-node → extensions/byline-toolbar}/index.d.ts +1 -2
- package/dist/field/extensions/byline-toolbar/index.js +1 -0
- package/dist/field/extensions/code-highlight/code-highlight-extension.d.ts +10 -0
- package/dist/field/extensions/code-highlight/code-highlight-extension.js +11 -0
- package/dist/field/extensions/floating-text-format/floating-text-format-extension.d.ts +18 -0
- package/dist/field/extensions/floating-text-format/floating-text-format-extension.js +17 -0
- package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.js +1 -1
- package/dist/field/extensions/horizontal-rule/horizontal-rule-extension.d.ts +6 -0
- package/dist/field/extensions/horizontal-rule/horizontal-rule-extension.js +45 -0
- package/dist/field/{nodes/inline-image-node → extensions/inline-image}/index.js +1 -1
- package/dist/field/{plugins/inline-image-plugin/index.d.ts → extensions/inline-image/inline-image-extension.d.ts} +6 -3
- package/dist/field/{plugins/inline-image-plugin/index.js → extensions/inline-image/inline-image-extension.js} +57 -5
- package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.d.ts +2 -2
- package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.js +4 -4
- package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.d.ts +2 -2
- package/dist/field/{nodes/inline-image-node/types.d.ts → extensions/inline-image/node-types.d.ts} +1 -1
- package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/types.d.ts +1 -1
- package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.d.ts +1 -1
- package/dist/field/{plugins/layout-plugin/layout-plugin.d.ts → extensions/layout/layout-extension.d.ts} +1 -0
- package/dist/field/{plugins/layout-plugin/layout-plugin.js → extensions/layout/layout-extension.js} +53 -5
- package/dist/field/extensions/link/auto-link-extension.d.ts +12 -0
- package/dist/field/{plugins/link-plugin/auto-link/index.js → extensions/link/auto-link-extension.js} +14 -2
- package/dist/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.d.ts +1 -1
- package/dist/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.js +2 -2
- package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.css +2 -2
- package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.js +4 -4
- package/dist/field/extensions/link/index.d.ts +5 -0
- package/dist/field/extensions/link/index.js +5 -0
- package/dist/field/extensions/link/link-extension.d.ts +14 -0
- package/dist/field/extensions/link/link-extension.js +66 -0
- package/dist/field/{plugins/link-plugin/link/types.d.ts → extensions/link/link-modal-types.d.ts} +1 -1
- package/dist/field/{plugins/link-plugin → extensions}/link/link-modal.d.ts +1 -1
- package/dist/field/{plugins/link-plugin → extensions}/link/link-modal.js +3 -3
- package/dist/field/{nodes/link-nodes → extensions/link}/types.d.ts +1 -1
- package/dist/field/extensions/table/table-action-menu-plugin/index.d.ts +4 -0
- package/dist/field/{plugins → extensions/table}/table-action-menu-plugin/index.js +8 -6
- package/dist/field/extensions/table/table-extension.d.ts +17 -0
- package/dist/field/extensions/table/table-extension.js +58 -0
- package/dist/field/extensions/vimeo/vimeo-extension.d.ts +12 -0
- package/dist/field/extensions/vimeo/vimeo-extension.js +16 -0
- package/dist/field/extensions/youtube/youtube-extension.d.ts +12 -0
- package/dist/field/extensions/youtube/youtube-extension.js +16 -0
- package/dist/field/nodes/index.js +7 -7
- package/dist/field/plugins/table-plugin/index.js +5 -6
- package/dist/field/plugins/toolbar-plugin/index.js +40 -114
- package/dist/field/plugins/toolbar-plugin/toolbar-active-editor.d.ts +25 -0
- package/dist/field/plugins/toolbar-plugin/toolbar-active-editor.js +17 -0
- package/dist/field/themes/lexical-editor-theme.css +13 -3
- package/dist/field/themes/lexical-editor-theme.js +1 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.js +16 -0
- package/dist/lexical-editor.d.ts +25 -13
- package/dist/lexical-editor.js +9 -1
- package/dist/richtext-field.js +6 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/package.json +7 -10
- package/src/field/apply-value-plugin.tsx +6 -6
- package/src/field/config/default-extensions.ts +104 -0
- package/src/field/config/default.ts +8 -28
- package/src/field/config/editor-config-context.tsx +1 -7
- package/src/field/config/extensions-list.ts +107 -0
- package/src/field/config/types.ts +28 -28
- package/src/field/editor-context.tsx +77 -41
- package/src/field/editor.tsx +24 -72
- package/src/field/extensions/README.md +31 -0
- package/src/field/{plugins/admonition-plugin/index.tsx → extensions/admonition/admonition-extension.tsx} +45 -2
- package/src/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.tsx +1 -1
- package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.tsx +5 -5
- package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node.tsx +1 -1
- package/src/field/{plugins/admonition-plugin → extensions/admonition}/fields.ts +1 -1
- package/src/field/{nodes/admonition-node → extensions/admonition}/index.ts +5 -1
- package/src/field/{plugins/admonition-plugin → extensions/admonition}/types.ts +1 -1
- package/src/field/{plugins/auto-embed-plugin/index.tsx → extensions/auto-embed/auto-embed-extension.tsx} +46 -3
- package/src/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.tsx +1 -1
- package/src/field/extensions/byline-floating-ui/byline-floating-ui-extension.ts +90 -0
- package/src/field/extensions/byline-floating-ui/index.ts +15 -0
- package/src/field/extensions/byline-toolbar/byline-toolbar-extension.ts +95 -0
- package/src/field/extensions/byline-toolbar/index.ts +15 -0
- package/src/field/extensions/code-highlight/code-highlight-extension.ts +18 -0
- package/src/field/extensions/floating-text-format/floating-text-format-extension.ts +39 -0
- package/src/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.tsx +1 -1
- package/src/field/extensions/horizontal-rule/horizontal-rule-extension.tsx +57 -0
- package/src/field/{nodes/inline-image-node → extensions/inline-image}/index.ts +1 -1
- package/src/field/{plugins/inline-image-plugin/index.tsx → extensions/inline-image/inline-image-extension.tsx} +54 -6
- package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.tsx +1 -1
- package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.tsx +6 -6
- package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.tsx +2 -2
- package/src/field/{nodes/inline-image-node/types.ts → extensions/inline-image/node-types.ts} +1 -1
- package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/types.ts +1 -1
- package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.ts +1 -1
- package/src/field/{plugins/layout-plugin/layout-plugin.tsx → extensions/layout/layout-extension.tsx} +47 -8
- package/src/field/{plugins/link-plugin/auto-link/index.tsx → extensions/link/auto-link-extension.tsx} +13 -3
- package/src/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.tsx +2 -2
- package/src/field/{plugins/link-plugin → extensions}/link/floating-link-editor.css +2 -2
- package/src/field/{plugins/link-plugin → extensions}/link/floating-link-editor.tsx +5 -5
- package/src/field/extensions/link/index.ts +5 -0
- package/src/field/extensions/link/link-extension.tsx +131 -0
- package/src/field/{plugins/link-plugin/link/types.ts → extensions/link/link-modal-types.ts} +1 -1
- package/src/field/{plugins/link-plugin → extensions}/link/link-modal.tsx +6 -6
- package/src/field/{nodes/link-nodes → extensions/link}/types.ts +1 -1
- package/src/field/{plugins → extensions/table}/table-action-menu-plugin/index.tsx +12 -8
- package/src/field/extensions/table/table-extension.tsx +86 -0
- package/src/field/extensions/vimeo/vimeo-extension.ts +36 -0
- package/src/field/extensions/youtube/youtube-extension.ts +37 -0
- package/src/field/nodes/index.ts +7 -7
- package/src/field/plugins/table-plugin/index.tsx +10 -10
- package/src/field/plugins/toolbar-plugin/index.tsx +59 -122
- package/src/field/plugins/toolbar-plugin/toolbar-active-editor.tsx +48 -0
- package/src/field/themes/lexical-editor-theme.css +18 -3
- package/src/field/themes/lexical-editor-theme.tsx +1 -0
- package/src/index.ts +45 -2
- package/src/lexical-editor.tsx +35 -14
- package/src/richtext-field.tsx +8 -1
- package/src/server.ts +4 -4
- package/dist/field/nodes/link-nodes/index.d.ts +0 -3
- package/dist/field/nodes/link-nodes/index.js +0 -3
- package/dist/field/plugins/code-highlight-plugin/index.d.ts +0 -9
- package/dist/field/plugins/code-highlight-plugin/index.js +0 -11
- package/dist/field/plugins/link-plugin/auto-link/index.d.ts +0 -9
- package/dist/field/plugins/link-plugin/link/index.d.ts +0 -1
- package/dist/field/plugins/link-plugin/link/index.js +0 -43
- package/dist/field/plugins/table-action-menu-plugin/index.d.ts +0 -5
- package/dist/field/plugins/vimeo-plugin/index.d.ts +0 -3
- package/dist/field/plugins/vimeo-plugin/index.js +0 -24
- package/dist/field/plugins/youtube-plugin/index.d.ts +0 -3
- package/dist/field/plugins/youtube-plugin/index.js +0 -24
- package/dist/field/toolbar-extensions.d.ts +0 -31
- package/dist/field/toolbar-extensions.js +0 -56
- package/src/field/nodes/link-nodes/index.ts +0 -3
- package/src/field/plugins/code-highlight-plugin/index.ts +0 -23
- package/src/field/plugins/link-plugin/link/index.tsx +0 -99
- package/src/field/plugins/vimeo-plugin/index.ts +0 -42
- package/src/field/plugins/youtube-plugin/index.ts +0 -43
- package/src/field/themes/lexical-editor-theme.js +0 -104
- package/src/field/toolbar-extensions.tsx +0 -93
- /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.css +0 -0
- /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.d.ts +0 -0
- /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.css +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node.js +0 -0
- /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/fields.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.css +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.d.ts +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/index.d.ts +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/index.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.css +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.d.ts +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.css +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.d.ts +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.js +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.css +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.d.ts +0 -0
- /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.js +0 -0
- /package/dist/field/{nodes/admonition-node/types.d.ts → extensions/admonition/node-types.d.ts} +0 -0
- /package/dist/field/{nodes/admonition-node/types.js → extensions/admonition/node-types.js} +0 -0
- /package/dist/field/{nodes/inline-image-node → extensions/admonition}/types.js +0 -0
- /package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.css +0 -0
- /package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.js +0 -0
- /package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.css +0 -0
- /package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.d.ts +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.d.ts +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.js +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.css +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.d.ts +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.js +0 -0
- /package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.css +0 -0
- /package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.js +0 -0
- /package/dist/field/{nodes/link-nodes/types.js → extensions/inline-image/node-types.js} +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.d.ts +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.js +0 -0
- /package/dist/field/{plugins/admonition-plugin → extensions/inline-image}/types.js +0 -0
- /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.js +0 -0
- /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.css +0 -0
- /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.d.ts +0 -0
- /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.js +0 -0
- /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.d.ts +0 -0
- /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.js +0 -0
- /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.d.ts +0 -0
- /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.js +0 -0
- /package/dist/field/{nodes/link-nodes → extensions/link}/auto-link-node.d.ts +0 -0
- /package/dist/field/{nodes/link-nodes → extensions/link}/auto-link-node.js +0 -0
- /package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.d.ts +0 -0
- /package/dist/field/{plugins/inline-image-plugin/types.js → extensions/link/link-modal-types.js} +0 -0
- /package/dist/field/{nodes/link-nodes → extensions/link}/link-node.d.ts +0 -0
- /package/dist/field/{nodes/link-nodes → extensions/link}/link-node.js +0 -0
- /package/dist/field/{plugins/link-plugin → extensions/link}/populate.d.ts +0 -0
- /package/dist/field/{plugins/link-plugin → extensions/link}/populate.js +0 -0
- /package/dist/field/{plugins/link-plugin → extensions}/link/types.js +0 -0
- /package/dist/field/{nodes/vimeo-node/index.d.ts → extensions/vimeo/vimeo-node.d.ts} +0 -0
- /package/dist/field/{nodes/vimeo-node/index.js → extensions/vimeo/vimeo-node.js} +0 -0
- /package/dist/field/{nodes/youtube-node/index.d.ts → extensions/youtube/youtube-node.d.ts} +0 -0
- /package/dist/field/{nodes/youtube-node/index.js → extensions/youtube/youtube-node.js} +0 -0
- /package/src/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.js +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.tsx +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/index.js +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/index.ts +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.js +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.tsx +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.js +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.tsx +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.css +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.js +0 -0
- /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.tsx +0 -0
- /package/src/field/{nodes/admonition-node/types.ts → extensions/admonition/node-types.ts} +0 -0
- /package/src/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.css +0 -0
- /package/src/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.css +0 -0
- /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.ts +0 -0
- /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.css +0 -0
- /package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.css +0 -0
- /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.ts +0 -0
- /package/src/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.css +0 -0
- /package/src/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.tsx +0 -0
- /package/src/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.ts +0 -0
- /package/src/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.ts +0 -0
- /package/src/field/{nodes/link-nodes → extensions/link}/auto-link-node.ts +0 -0
- /package/src/field/{nodes/link-nodes → extensions/link}/link-node.ts +0 -0
- /package/src/field/{plugins/link-plugin → extensions/link}/populate.ts +0 -0
- /package/src/field/{nodes/vimeo-node/index.tsx → extensions/vimeo/vimeo-node.tsx} +0 -0
- /package/src/field/{nodes/youtube-node/index.tsx → extensions/youtube/youtube-node.tsx} +0 -0
|
@@ -14,6 +14,8 @@ import type * as React from 'react'
|
|
|
14
14
|
import { useCallback, useEffect, useState } from 'react'
|
|
15
15
|
|
|
16
16
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
17
|
+
import { ReactExtension } from '@lexical/react/ReactExtension'
|
|
18
|
+
import { useExtensionDependency } from '@lexical/react/useExtensionComponent'
|
|
17
19
|
import { $wrapNodeInElement, mergeRegister } from '@lexical/utils'
|
|
18
20
|
import {
|
|
19
21
|
$createParagraphNode,
|
|
@@ -22,19 +24,25 @@ import {
|
|
|
22
24
|
$isRootOrShadowRoot,
|
|
23
25
|
COMMAND_PRIORITY_EDITOR,
|
|
24
26
|
COMMAND_PRIORITY_NORMAL,
|
|
27
|
+
configExtension,
|
|
25
28
|
createCommand,
|
|
29
|
+
declarePeerDependency,
|
|
30
|
+
defineExtension,
|
|
26
31
|
type LexicalCommand,
|
|
27
32
|
type LexicalEditor,
|
|
28
33
|
type NodeKey,
|
|
34
|
+
safeCast,
|
|
29
35
|
} from 'lexical'
|
|
30
36
|
|
|
37
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
38
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
31
39
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from '../../nodes/inline-image-node'
|
|
40
|
+
type BylineToolbarConfig,
|
|
41
|
+
BylineToolbarExtension,
|
|
42
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
36
43
|
import { InlineImageModal } from './inline-image-modal'
|
|
37
|
-
import
|
|
44
|
+
import { $createInlineImageNode, $isInlineImageNode, InlineImageNode } from './inline-image-node'
|
|
45
|
+
import type { InlineImageAttributes } from './node-types'
|
|
38
46
|
import type { InlineImageData } from './types'
|
|
39
47
|
|
|
40
48
|
export type InsertInlineImagePayload = Readonly<InlineImageAttributes>
|
|
@@ -102,8 +110,9 @@ function readNodeAsInitialData(
|
|
|
102
110
|
return data
|
|
103
111
|
}
|
|
104
112
|
|
|
105
|
-
export function InlineImagePlugin(
|
|
113
|
+
export function InlineImagePlugin(): React.JSX.Element {
|
|
106
114
|
const [editor] = useLexicalComposerContext()
|
|
115
|
+
const { collection } = useExtensionDependency(InlineImageExtension).config
|
|
107
116
|
const [modalState, setModalState] = useState<ModalState>(CLOSED_STATE)
|
|
108
117
|
|
|
109
118
|
useEffect(() => {
|
|
@@ -200,3 +209,42 @@ export function InlineImagePlugin({ collection }: { collection: string }): React
|
|
|
200
209
|
/>
|
|
201
210
|
)
|
|
202
211
|
}
|
|
212
|
+
|
|
213
|
+
export interface InlineImageConfig {
|
|
214
|
+
/** Upload collection that the inline-image modal targets. Required. */
|
|
215
|
+
collection: string
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function InlineImageInsertItem(): React.JSX.Element {
|
|
219
|
+
const editor = useToolbarActiveEditor()
|
|
220
|
+
return (
|
|
221
|
+
<DropDownItem
|
|
222
|
+
onClick={() => {
|
|
223
|
+
editor.dispatchCommand(OPEN_INLINE_IMAGE_MODAL_COMMAND, null)
|
|
224
|
+
}}
|
|
225
|
+
className="item"
|
|
226
|
+
>
|
|
227
|
+
<i className="icon image" />
|
|
228
|
+
<span className="text">Inline Image</span>
|
|
229
|
+
</DropDownItem>
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export const InlineImageExtension = defineExtension({
|
|
234
|
+
name: '@byline/richtext-lexical/InlineImage',
|
|
235
|
+
nodes: () => [InlineImageNode],
|
|
236
|
+
config: safeCast<InlineImageConfig>({ collection: '' }),
|
|
237
|
+
dependencies: [configExtension(ReactExtension, { decorators: [<InlineImagePlugin key="d" />] })],
|
|
238
|
+
peerDependencies: [
|
|
239
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
240
|
+
items: [
|
|
241
|
+
{
|
|
242
|
+
id: '@byline/richtext-lexical/InlineImage/insert',
|
|
243
|
+
placement: 'insert-menu',
|
|
244
|
+
order: 40,
|
|
245
|
+
node: <InlineImageInsertItem />,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
249
|
+
],
|
|
250
|
+
})
|
package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.tsx
RENAMED
|
@@ -32,7 +32,7 @@ import { useModalFormState } from '../../shared/useModalFormState'
|
|
|
32
32
|
import { isAltTextValid, positionOptions } from './fields'
|
|
33
33
|
import { deriveImageSizes, getPreferredSize } from './utils'
|
|
34
34
|
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
35
|
-
import type { Position } from '
|
|
35
|
+
import type { Position } from './node-types'
|
|
36
36
|
import type { InlineImageData, InlineImageModalProps } from './types'
|
|
37
37
|
|
|
38
38
|
interface FormState {
|
|
@@ -39,14 +39,14 @@ import {
|
|
|
39
39
|
import ContentEditableInline from '../../content-editable-inline'
|
|
40
40
|
import { useSharedHistoryContext } from '../../context/shared-history-context'
|
|
41
41
|
import { useSharedOnChange } from '../../context/shared-on-change-context'
|
|
42
|
-
import { FloatingTextFormatToolbarPlugin } from '../../plugins/floating-text-format-toolbar-plugin/index'
|
|
43
|
-
import { OPEN_INLINE_IMAGE_MODAL_COMMAND } from '../../plugins/inline-image-plugin'
|
|
44
|
-
import { LinkPlugin } from '../../plugins/link-plugin/link'
|
|
45
|
-
import { FloatingLinkEditorPlugin } from '../../plugins/link-plugin/link/floating-link-editor'
|
|
46
42
|
import PlaceholderInline from '../../ui/placeholder-inline'
|
|
43
|
+
import { FloatingTextFormatToolbarPlugin } from '../floating-text-format'
|
|
44
|
+
import { FloatingLinkEditorPlugin } from '../link/floating-link-editor'
|
|
45
|
+
import { LinkPlugin } from '../link/link-extension'
|
|
46
|
+
import { OPEN_INLINE_IMAGE_MODAL_COMMAND } from './inline-image-extension'
|
|
47
47
|
import { $isInlineImageNode } from './inline-image-node'
|
|
48
|
-
import type { DocumentRelation } from '
|
|
49
|
-
import type { Position } from './types'
|
|
48
|
+
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
49
|
+
import type { Position } from './node-types'
|
|
50
50
|
|
|
51
51
|
import './inline-image-node-component.css'
|
|
52
52
|
|
|
@@ -22,8 +22,8 @@ import type {
|
|
|
22
22
|
} from 'lexical'
|
|
23
23
|
import { $applyNodeReplacement, createEditor, DecoratorNode } from 'lexical'
|
|
24
24
|
|
|
25
|
-
import type { DocumentRelation } from '
|
|
26
|
-
import type { InlineImageAttributes, Position, SerializedInlineImageNode } from './types'
|
|
25
|
+
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
26
|
+
import type { InlineImageAttributes, Position, SerializedInlineImageNode } from './node-types'
|
|
27
27
|
|
|
28
28
|
const InlineImageComponent = React.lazy(async () => await import('./inline-image-node-component'))
|
|
29
29
|
|
package/src/field/{nodes/inline-image-node/types.ts → extensions/inline-image/node-types.ts}
RENAMED
|
@@ -14,7 +14,7 @@ import type {
|
|
|
14
14
|
Spread,
|
|
15
15
|
} from 'lexical'
|
|
16
16
|
|
|
17
|
-
import type { DocumentRelation } from '
|
|
17
|
+
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
18
18
|
|
|
19
19
|
export type Position = 'left' | 'right' | 'full' | 'wide' | 'default' | undefined
|
|
20
20
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
10
|
-
import type { Position } from '
|
|
10
|
+
import type { Position } from './node-types'
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The form-shape carried into / out of the inline image modal. Mirrors
|
package/src/field/{plugins/layout-plugin/layout-plugin.tsx → extensions/layout/layout-extension.tsx}
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { useEffect } from 'react'
|
|
5
5
|
|
|
6
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
6
7
|
/**
|
|
7
8
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
8
9
|
*
|
|
@@ -10,7 +11,7 @@ import { useEffect } from 'react'
|
|
|
10
11
|
* LICENSE file in the root directory of this source tree.
|
|
11
12
|
*
|
|
12
13
|
*/
|
|
13
|
-
import {
|
|
14
|
+
import { ReactExtension } from '@lexical/react/ReactExtension'
|
|
14
15
|
import { $insertNodeToNearestRoot, mergeRegister } from '@lexical/utils'
|
|
15
16
|
import type { ElementNode, LexicalCommand, LexicalNode, NodeKey } from 'lexical'
|
|
16
17
|
import {
|
|
@@ -18,20 +19,25 @@ import {
|
|
|
18
19
|
$getNodeByKey,
|
|
19
20
|
COMMAND_PRIORITY_EDITOR,
|
|
20
21
|
COMMAND_PRIORITY_NORMAL,
|
|
22
|
+
configExtension,
|
|
21
23
|
createCommand,
|
|
24
|
+
declarePeerDependency,
|
|
25
|
+
defineExtension,
|
|
22
26
|
} from 'lexical'
|
|
23
27
|
|
|
28
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
29
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
30
|
+
import {
|
|
31
|
+
type BylineToolbarConfig,
|
|
32
|
+
BylineToolbarExtension,
|
|
33
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
34
|
+
import { InsertLayoutModal } from './insert-layout-modal'
|
|
24
35
|
import {
|
|
25
36
|
$createLayoutContainerNode,
|
|
26
37
|
$isLayoutContainerNode,
|
|
27
38
|
LayoutContainerNode,
|
|
28
|
-
} from '
|
|
29
|
-
import {
|
|
30
|
-
$createLayoutItemNode,
|
|
31
|
-
$isLayoutItemNode,
|
|
32
|
-
LayoutItemNode,
|
|
33
|
-
} from '../../nodes/layout-container-node/layout-item-node'
|
|
34
|
-
import { InsertLayoutModal } from './insert-layout-modal'
|
|
39
|
+
} from './layout-container-node'
|
|
40
|
+
import { $createLayoutItemNode, $isLayoutItemNode, LayoutItemNode } from './layout-item-node'
|
|
35
41
|
|
|
36
42
|
export const OPEN_INSERT_LAYOUT_MODAL_COMMAND = createCommand('OPEN_INSERT_LAYOUT_MODAL_COMMAND')
|
|
37
43
|
|
|
@@ -160,3 +166,36 @@ export function LayoutPlugin(): React.JSX.Element {
|
|
|
160
166
|
function getItemsCountFromTemplate(template: string): number {
|
|
161
167
|
return template.trim().split(/\s+/).length
|
|
162
168
|
}
|
|
169
|
+
|
|
170
|
+
function LayoutInsertItem(): React.JSX.Element {
|
|
171
|
+
const editor = useToolbarActiveEditor()
|
|
172
|
+
return (
|
|
173
|
+
<DropDownItem
|
|
174
|
+
onClick={() => {
|
|
175
|
+
editor.dispatchCommand(OPEN_INSERT_LAYOUT_MODAL_COMMAND, null)
|
|
176
|
+
}}
|
|
177
|
+
className="item"
|
|
178
|
+
>
|
|
179
|
+
<i className="icon columns" />
|
|
180
|
+
<span className="text">Columns Layout</span>
|
|
181
|
+
</DropDownItem>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const LayoutExtension = defineExtension({
|
|
186
|
+
name: '@byline/richtext-lexical/Layout',
|
|
187
|
+
nodes: () => [LayoutContainerNode, LayoutItemNode],
|
|
188
|
+
dependencies: [configExtension(ReactExtension, { decorators: [<LayoutPlugin key="d" />] })],
|
|
189
|
+
peerDependencies: [
|
|
190
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
191
|
+
items: [
|
|
192
|
+
{
|
|
193
|
+
id: '@byline/richtext-lexical/Layout/insert',
|
|
194
|
+
placement: 'insert-menu',
|
|
195
|
+
order: 20,
|
|
196
|
+
node: <LayoutInsertItem />,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
200
|
+
],
|
|
201
|
+
})
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
8
9
|
*
|
|
10
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import type * as React from 'react'
|
|
12
14
|
|
|
15
|
+
import { ReactExtension } from '@lexical/react/ReactExtension'
|
|
16
|
+
import { configExtension, defineExtension } from 'lexical'
|
|
17
|
+
|
|
13
18
|
import {
|
|
14
19
|
createLinkMatcherWithRegExp,
|
|
15
20
|
AutoLinkPlugin as LexicalAutoLinkPlugin,
|
|
@@ -33,3 +38,8 @@ const MATCHERS = [
|
|
|
33
38
|
export function AutoLinkPlugin(): React.JSX.Element {
|
|
34
39
|
return <LexicalAutoLinkPlugin matchers={MATCHERS} />
|
|
35
40
|
}
|
|
41
|
+
|
|
42
|
+
export const AutoLinkExtension = defineExtension({
|
|
43
|
+
name: '@byline/richtext-lexical/AutoLink',
|
|
44
|
+
dependencies: [configExtension(ReactExtension, { decorators: [<AutoLinkPlugin key="d" />] })],
|
|
45
|
+
})
|
|
@@ -15,6 +15,7 @@ import { mergeRegister } from '@lexical/utils'
|
|
|
15
15
|
import type { ElementNode, LexicalEditor, LexicalNode } from 'lexical'
|
|
16
16
|
import { $createTextNode, $isElementNode, $isLineBreakNode, $isTextNode, TextNode } from 'lexical'
|
|
17
17
|
|
|
18
|
+
import invariant from '../../shared/invariant'
|
|
18
19
|
import {
|
|
19
20
|
$createAutoLinkNode,
|
|
20
21
|
$isAutoLinkNode,
|
|
@@ -22,8 +23,7 @@ import {
|
|
|
22
23
|
AutoLinkNode,
|
|
23
24
|
type CustomLinkAttributes,
|
|
24
25
|
type LinkAttributes,
|
|
25
|
-
} from '
|
|
26
|
-
import invariant from '../../../shared/invariant'
|
|
26
|
+
} from '.'
|
|
27
27
|
|
|
28
28
|
type ChangeHandler = (url: string | null, prevUrl: string | null) => void
|
|
29
29
|
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.link-editor div.link-edit {
|
|
70
|
-
background-image: url(
|
|
70
|
+
background-image: url(../../images/icons/pencil-fill.svg);
|
|
71
71
|
background-size: 16px;
|
|
72
72
|
background-position: center;
|
|
73
73
|
background-repeat: no-repeat;
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.link-editor div.link-trash {
|
|
84
|
-
background-image: url(
|
|
84
|
+
background-image: url(../../images/icons/trash.svg);
|
|
85
85
|
background-size: 16px;
|
|
86
86
|
background-position: center;
|
|
87
87
|
background-repeat: no-repeat;
|
|
@@ -29,18 +29,18 @@ import {
|
|
|
29
29
|
} from 'lexical'
|
|
30
30
|
import { createPortal } from 'react-dom'
|
|
31
31
|
|
|
32
|
+
import { getSelectedNode } from '../../utils/getSelectedNode'
|
|
33
|
+
import { setFloatingElemPositionForLinkEditor } from '../../utils/setFloatingElemPositionForLinkEditor'
|
|
34
|
+
import { sanitizeUrl } from '../../utils/url'
|
|
32
35
|
import {
|
|
33
36
|
$isAutoLinkNode,
|
|
34
37
|
$isLinkNode,
|
|
35
38
|
type LinkAttributes,
|
|
36
39
|
OPEN_LINK_MODAL_COMMAND,
|
|
37
40
|
TOGGLE_LINK_COMMAND,
|
|
38
|
-
} from '
|
|
39
|
-
import { getSelectedNode } from '../../../utils/getSelectedNode'
|
|
40
|
-
import { setFloatingElemPositionForLinkEditor } from '../../../utils/setFloatingElemPositionForLinkEditor'
|
|
41
|
-
import { sanitizeUrl } from '../../../utils/url'
|
|
41
|
+
} from '.'
|
|
42
42
|
import { LinkModal } from './link-modal'
|
|
43
|
-
import type { LinkData } from './types'
|
|
43
|
+
import type { LinkData } from './link-modal-types'
|
|
44
44
|
|
|
45
45
|
import './floating-link-editor.css'
|
|
46
46
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*
|
|
10
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useEffect } from 'react'
|
|
14
|
+
|
|
15
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
16
|
+
import { mergeRegister } from '@lexical/utils'
|
|
17
|
+
import {
|
|
18
|
+
$getSelection,
|
|
19
|
+
$isElementNode,
|
|
20
|
+
$isRangeSelection,
|
|
21
|
+
COMMAND_PRIORITY_LOW,
|
|
22
|
+
declarePeerDependency,
|
|
23
|
+
defineExtension,
|
|
24
|
+
type LexicalEditor,
|
|
25
|
+
PASTE_COMMAND,
|
|
26
|
+
} from 'lexical'
|
|
27
|
+
|
|
28
|
+
import { validateUrl } from '../../utils/url'
|
|
29
|
+
import {
|
|
30
|
+
type BylineFloatingUIConfig,
|
|
31
|
+
BylineFloatingUIExtension,
|
|
32
|
+
} from '../byline-floating-ui/byline-floating-ui-extension'
|
|
33
|
+
import { $toggleLink, AutoLinkNode, type LinkAttributes, LinkNode, TOGGLE_LINK_COMMAND } from '.'
|
|
34
|
+
import { FloatingLinkEditorPlugin } from './floating-link-editor'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Registers Byline's custom link command + paste handling on `editor`.
|
|
38
|
+
* Shared between the LinkPlugin React shell (used inside nested composers)
|
|
39
|
+
* and the LinkExtension's `register` phase (used by the top-level editor).
|
|
40
|
+
*/
|
|
41
|
+
export function registerLink(editor: LexicalEditor): () => void {
|
|
42
|
+
return mergeRegister(
|
|
43
|
+
editor.registerCommand(
|
|
44
|
+
TOGGLE_LINK_COMMAND,
|
|
45
|
+
(payload: LinkAttributes | null) => {
|
|
46
|
+
if (payload === null) {
|
|
47
|
+
$toggleLink(payload)
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// For custom links, accept either a fully-formed URL or a
|
|
52
|
+
// root-relative path (starts with `/`). Drop the command when the
|
|
53
|
+
// URL is unusable so the toolbar doesn't insert garbage.
|
|
54
|
+
if (payload.linkType === 'custom') {
|
|
55
|
+
const url = payload.url ?? ''
|
|
56
|
+
if (!url.startsWith('/') && !validateUrl(url)) {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$toggleLink(payload)
|
|
62
|
+
return true
|
|
63
|
+
},
|
|
64
|
+
COMMAND_PRIORITY_LOW
|
|
65
|
+
),
|
|
66
|
+
|
|
67
|
+
editor.registerCommand(
|
|
68
|
+
PASTE_COMMAND,
|
|
69
|
+
(event) => {
|
|
70
|
+
const selection = $getSelection()
|
|
71
|
+
if (
|
|
72
|
+
!$isRangeSelection(selection) ||
|
|
73
|
+
selection.isCollapsed() ||
|
|
74
|
+
!(event instanceof ClipboardEvent) ||
|
|
75
|
+
event.clipboardData == null
|
|
76
|
+
) {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
const clipboardText = event.clipboardData.getData('text')
|
|
80
|
+
if (!validateUrl(clipboardText)) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
// Don't auto-link when the selection spans block-level nodes.
|
|
84
|
+
if (selection.getNodes().some((node) => $isElementNode(node))) {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, {
|
|
88
|
+
linkType: 'custom',
|
|
89
|
+
url: clipboardText,
|
|
90
|
+
})
|
|
91
|
+
event.preventDefault()
|
|
92
|
+
return true
|
|
93
|
+
},
|
|
94
|
+
COMMAND_PRIORITY_LOW
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Legacy React shell — still used inside the inline-image nested composer
|
|
101
|
+
* (`inline-image-node-component.tsx`) where the nested editor needs link
|
|
102
|
+
* behaviour wired up. The top-level editor uses `LinkExtension` instead.
|
|
103
|
+
*/
|
|
104
|
+
export function LinkPlugin(): null {
|
|
105
|
+
const [editor] = useLexicalComposerContext()
|
|
106
|
+
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!editor.hasNodes([LinkNode])) {
|
|
109
|
+
throw new Error('LinkPlugin: LinkNode not registered on editor')
|
|
110
|
+
}
|
|
111
|
+
return registerLink(editor)
|
|
112
|
+
}, [editor])
|
|
113
|
+
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const LinkExtension = defineExtension({
|
|
118
|
+
name: '@byline/richtext-lexical/Link',
|
|
119
|
+
nodes: () => [LinkNode, AutoLinkNode],
|
|
120
|
+
register: registerLink,
|
|
121
|
+
peerDependencies: [
|
|
122
|
+
declarePeerDependency<typeof BylineFloatingUIExtension>(BylineFloatingUIExtension.name, {
|
|
123
|
+
items: [
|
|
124
|
+
{
|
|
125
|
+
id: '@byline/richtext-lexical/Link/floating-editor',
|
|
126
|
+
Component: FloatingLinkEditorPlugin,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
} satisfies Partial<BylineFloatingUIConfig>),
|
|
130
|
+
],
|
|
131
|
+
})
|
|
@@ -28,12 +28,12 @@ import {
|
|
|
28
28
|
type SelectValue,
|
|
29
29
|
} from '@byline/ui/react'
|
|
30
30
|
|
|
31
|
-
import { useEditorConfig } from '
|
|
32
|
-
import { useModalFormState } from '
|
|
33
|
-
import { validateUrl } from '
|
|
34
|
-
import type { DocumentRelation } from '
|
|
35
|
-
import type { LinkAttributes } from '
|
|
36
|
-
import type { LinkData, LinkModalProps } from './types'
|
|
31
|
+
import { useEditorConfig } from '../../config/editor-config-context'
|
|
32
|
+
import { useModalFormState } from '../../shared/useModalFormState'
|
|
33
|
+
import { validateUrl } from '../../utils/url'
|
|
34
|
+
import type { DocumentRelation } from '../../nodes/document-relation'
|
|
35
|
+
import type { LinkAttributes } from '.'
|
|
36
|
+
import type { LinkData, LinkModalProps } from './link-modal-types'
|
|
37
37
|
|
|
38
38
|
interface FormState {
|
|
39
39
|
text: string
|
|
@@ -14,6 +14,7 @@ import type * as React from 'react'
|
|
|
14
14
|
import { type ReactPortal, useCallback, useEffect, useRef, useState } from 'react'
|
|
15
15
|
|
|
16
16
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
17
|
+
import { useExtensionDependency } from '@lexical/react/useExtensionComponent'
|
|
17
18
|
import { useLexicalEditable } from '@lexical/react/useLexicalEditable'
|
|
18
19
|
import {
|
|
19
20
|
$deleteTableColumnAtSelection,
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
$unmergeCell,
|
|
32
33
|
getTableObserverFromTableElement,
|
|
33
34
|
type HTMLTableElementWithWithTableSelectionState,
|
|
35
|
+
TableExtension as LexicalTableExtension,
|
|
34
36
|
TableCellHeaderStates,
|
|
35
37
|
TableCellNode,
|
|
36
38
|
type TableRowNode,
|
|
@@ -48,9 +50,9 @@ import {
|
|
|
48
50
|
} from 'lexical'
|
|
49
51
|
import { createPortal } from 'react-dom'
|
|
50
52
|
|
|
51
|
-
import useModal from '
|
|
52
|
-
import invariant from '
|
|
53
|
-
import ColorPicker from '
|
|
53
|
+
import useModal from '../../../hooks/use-modal'
|
|
54
|
+
import invariant from '../../../shared/invariant'
|
|
55
|
+
import ColorPicker from '../../../ui/color-picker'
|
|
54
56
|
|
|
55
57
|
function computeSelectionCount(selection: TableSelection): {
|
|
56
58
|
columns: number
|
|
@@ -788,16 +790,18 @@ function TableCellActionMenuContainer({
|
|
|
788
790
|
}
|
|
789
791
|
|
|
790
792
|
export function TableActionMenuPlugin({
|
|
791
|
-
anchorElem
|
|
792
|
-
cellMerge = false,
|
|
793
|
+
anchorElem,
|
|
793
794
|
}: {
|
|
794
|
-
anchorElem
|
|
795
|
-
cellMerge?: boolean
|
|
795
|
+
anchorElem: HTMLElement
|
|
796
796
|
}): null | ReactPortal {
|
|
797
797
|
const isEditable = useLexicalEditable()
|
|
798
|
+
// Read the upstream `@lexical/table` config so the cell-merge UI lives
|
|
799
|
+
// in lockstep with `c.extensions.configure(LexicalTableExtension, {...})`
|
|
800
|
+
// instead of needing a separate prop wired from `Editor.tsx`.
|
|
801
|
+
const { hasCellMerge } = useExtensionDependency(LexicalTableExtension).config
|
|
798
802
|
return createPortal(
|
|
799
803
|
isEditable ? (
|
|
800
|
-
<TableCellActionMenuContainer anchorElem={anchorElem} cellMerge={
|
|
804
|
+
<TableCellActionMenuContainer anchorElem={anchorElem} cellMerge={hasCellMerge ?? false} />
|
|
801
805
|
) : null,
|
|
802
806
|
anchorElem
|
|
803
807
|
)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { TableExtension as LexicalTableExtension } from '@lexical/table'
|
|
12
|
+
import { configExtension, declarePeerDependency, defineExtension } from 'lexical'
|
|
13
|
+
|
|
14
|
+
import { OPEN_TABLE_MODAL_COMMAND } from '../../plugins/table-plugin'
|
|
15
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
16
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
17
|
+
import {
|
|
18
|
+
type BylineFloatingUIConfig,
|
|
19
|
+
BylineFloatingUIExtension,
|
|
20
|
+
} from '../byline-floating-ui/byline-floating-ui-extension'
|
|
21
|
+
import {
|
|
22
|
+
type BylineToolbarConfig,
|
|
23
|
+
BylineToolbarExtension,
|
|
24
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
25
|
+
import { TableActionMenuPlugin } from './table-action-menu-plugin'
|
|
26
|
+
|
|
27
|
+
function TableInsertItem(): React.JSX.Element {
|
|
28
|
+
const editor = useToolbarActiveEditor()
|
|
29
|
+
return (
|
|
30
|
+
<DropDownItem
|
|
31
|
+
onClick={() => {
|
|
32
|
+
editor.dispatchCommand(OPEN_TABLE_MODAL_COMMAND, null)
|
|
33
|
+
}}
|
|
34
|
+
className="item"
|
|
35
|
+
>
|
|
36
|
+
<i className="icon table" />
|
|
37
|
+
<span className="text">Table</span>
|
|
38
|
+
</DropDownItem>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Byline wrapper around `@lexical/table`'s `TableExtension`. Forwards
|
|
44
|
+
* cell-merge / cell-background-color config to the upstream extension
|
|
45
|
+
* via `configExtension` and contributes the "Insert table" toolbar item.
|
|
46
|
+
*
|
|
47
|
+
* Override the upstream config with:
|
|
48
|
+
* ```ts
|
|
49
|
+
* lexicalEditor((c) => {
|
|
50
|
+
* c.extensions.configure(LexicalTableExtension, {
|
|
51
|
+
* hasCellMerge: false,
|
|
52
|
+
* hasCellBackgroundColor: false,
|
|
53
|
+
* })
|
|
54
|
+
* return c
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const TableExtension = defineExtension({
|
|
59
|
+
name: '@byline/richtext-lexical/Table',
|
|
60
|
+
dependencies: [
|
|
61
|
+
configExtension(LexicalTableExtension, {
|
|
62
|
+
hasCellMerge: true,
|
|
63
|
+
hasCellBackgroundColor: true,
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
peerDependencies: [
|
|
67
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
68
|
+
items: [
|
|
69
|
+
{
|
|
70
|
+
id: '@byline/richtext-lexical/Table/insert',
|
|
71
|
+
placement: 'insert-menu',
|
|
72
|
+
order: 50,
|
|
73
|
+
node: <TableInsertItem />,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
77
|
+
declarePeerDependency<typeof BylineFloatingUIExtension>(BylineFloatingUIExtension.name, {
|
|
78
|
+
items: [
|
|
79
|
+
{
|
|
80
|
+
id: '@byline/richtext-lexical/Table/action-menu',
|
|
81
|
+
Component: TableActionMenuPlugin,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
} satisfies Partial<BylineFloatingUIConfig>),
|
|
85
|
+
],
|
|
86
|
+
})
|