@byline/richtext-lexical 1.11.2 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# `@byline/richtext-lexical` extensions
|
|
2
|
+
|
|
3
|
+
Every built-in feature of the Lexical adapter — and every supported way for a third party to extend it — lives in this directory as a Lexical `defineExtension(...)` co-located with its node class(es), modal, decorator, and (where relevant) populate visitor.
|
|
4
|
+
|
|
5
|
+
This README is a navigation aid only. The full reference and authoring contract lives in the project's [`docs/RICHTEXT.md`](../../../../../docs/RICHTEXT.md) — start with the **Extensibility** section.
|
|
6
|
+
|
|
7
|
+
## What's where
|
|
8
|
+
|
|
9
|
+
| Directory | What it owns |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `byline-toolbar/` | `BylineToolbarExtension` — the registry that built-in and third-party extensions contribute toolbar items into via `peerDependencies`. |
|
|
12
|
+
| `byline-floating-ui/` | `BylineFloatingUIExtension` — the registry every floating UI (link editor, table action menu, format pop-over, third-party) plugs into via `peerDependencies`. |
|
|
13
|
+
| `floating-text-format/` | Standalone extension that contributes the selection-format pop-over to `BylineFloatingUIExtension`. |
|
|
14
|
+
| `link/` | `LinkExtension`, `AutoLinkExtension`, link node + paste handling + `FloatingLinkEditorPlugin` (contributed back via peer dep), and the link populate visitor. |
|
|
15
|
+
| `table/` | `TableExtension` (Byline wrapper over `@lexical/table`), the table modal, and the `TableActionMenuPlugin` (contributed to the floating-UI registry). |
|
|
16
|
+
| `inline-image/` | `InlineImageExtension`, node + decorator + modal, picker-time embed, and the populate visitor for `{ title, altText, image, sizes }`. |
|
|
17
|
+
| `layout/` | `LayoutExtension`, columns layout node + modal. |
|
|
18
|
+
| `admonition/` | `AdmonitionExtension`, admonition node + modal. |
|
|
19
|
+
| `auto-embed/` | `AutoEmbedExtension` — paste-to-embed UX shared by the YouTube/Vimeo embedders. |
|
|
20
|
+
| `youtube/`, `vimeo/` | Embed extensions and their node decorators. |
|
|
21
|
+
| `code-highlight/` | Syntax-highlight extension over `@lexical/code`. |
|
|
22
|
+
| `horizontal-rule/` | Byline wrapper over the upstream `@lexical/react/LexicalHorizontalRuleNode`. |
|
|
23
|
+
|
|
24
|
+
## Adding a new extension
|
|
25
|
+
|
|
26
|
+
1. Create a directory next to these.
|
|
27
|
+
2. Implement your `defineExtension(...)` (and any nodes / decorators).
|
|
28
|
+
3. To contribute a toolbar item or a floating UI, declare a peer dependency against `BylineToolbarExtension` / `BylineFloatingUIExtension` — see the worked recipes in `docs/RICHTEXT.md`.
|
|
29
|
+
4. Either register your extension at site level via `lexicalEditor((c) => c.extensions.add(MyExtension))`, or — if it's a built-in being shipped by this package — append it to `defaultExtensionsArray()` in `field/config/default-extensions.ts`.
|
|
30
|
+
|
|
31
|
+
You should never need to touch `field/editor.tsx` to add a feature.
|
|
@@ -12,19 +12,29 @@ import * as React from 'react'
|
|
|
12
12
|
import { useEffect } from 'react'
|
|
13
13
|
|
|
14
14
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
15
|
+
import { ReactExtension } from '@lexical/react/ReactExtension'
|
|
15
16
|
import { $insertNodeToNearestRoot, mergeRegister } from '@lexical/utils'
|
|
16
17
|
import {
|
|
17
18
|
$getSelection,
|
|
18
19
|
$isRangeSelection,
|
|
19
20
|
COMMAND_PRIORITY_EDITOR,
|
|
20
21
|
COMMAND_PRIORITY_NORMAL,
|
|
22
|
+
configExtension,
|
|
21
23
|
createCommand,
|
|
24
|
+
declarePeerDependency,
|
|
25
|
+
defineExtension,
|
|
22
26
|
type LexicalCommand,
|
|
23
27
|
} from 'lexical'
|
|
24
28
|
|
|
25
|
-
import {
|
|
29
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
30
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
31
|
+
import {
|
|
32
|
+
type BylineToolbarConfig,
|
|
33
|
+
BylineToolbarExtension,
|
|
34
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
26
35
|
import { AdmonitionModal } from './admonition-modal'
|
|
27
|
-
import
|
|
36
|
+
import { $createAdmonitionNode, AdmonitionNode } from './admonition-node'
|
|
37
|
+
import type { AdmonitionAttributes } from './node-types'
|
|
28
38
|
import type { AdmonitionData } from './types'
|
|
29
39
|
|
|
30
40
|
export type InsertAdmonitionPayload = Readonly<AdmonitionAttributes>
|
|
@@ -103,3 +113,36 @@ export function AdmonitionPlugin(): React.JSX.Element {
|
|
|
103
113
|
/>
|
|
104
114
|
)
|
|
105
115
|
}
|
|
116
|
+
|
|
117
|
+
function AdmonitionInsertItem(): React.JSX.Element {
|
|
118
|
+
const editor = useToolbarActiveEditor()
|
|
119
|
+
return (
|
|
120
|
+
<DropDownItem
|
|
121
|
+
onClick={() => {
|
|
122
|
+
editor.dispatchCommand(OPEN_ADMONITION_MODAL_COMMAND, null)
|
|
123
|
+
}}
|
|
124
|
+
className="item"
|
|
125
|
+
>
|
|
126
|
+
<i className="icon admonition" />
|
|
127
|
+
<span className="text">Admonition</span>
|
|
128
|
+
</DropDownItem>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const AdmonitionExtension = defineExtension({
|
|
133
|
+
name: '@byline/richtext-lexical/Admonition',
|
|
134
|
+
nodes: () => [AdmonitionNode],
|
|
135
|
+
dependencies: [configExtension(ReactExtension, { decorators: [<AdmonitionPlugin key="d" />] })],
|
|
136
|
+
peerDependencies: [
|
|
137
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
138
|
+
items: [
|
|
139
|
+
{
|
|
140
|
+
id: '@byline/richtext-lexical/Admonition/insert',
|
|
141
|
+
placement: 'insert-menu',
|
|
142
|
+
order: 30,
|
|
143
|
+
node: <AdmonitionInsertItem />,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
147
|
+
],
|
|
148
|
+
})
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from '@byline/ui/react'
|
|
23
23
|
|
|
24
24
|
import { admonitionTypeOptions, getInitialState, validateFields } from './fields'
|
|
25
|
-
import type { AdmonitionType } from '
|
|
25
|
+
import type { AdmonitionType } from './node-types'
|
|
26
26
|
import type { AdmonitionDrawerProps, AdmonitionFormState } from './types'
|
|
27
27
|
|
|
28
28
|
import './admonition-modal.css'
|
package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.tsx
RENAMED
|
@@ -35,18 +35,18 @@ import {
|
|
|
35
35
|
} from 'lexical'
|
|
36
36
|
|
|
37
37
|
import { useEditorConfig } from '../../config/editor-config-context'
|
|
38
|
-
// import { LinkPlugin } from '
|
|
39
|
-
// import { FloatingLinkEditorPlugin } from '
|
|
38
|
+
// import { LinkPlugin } from '../link/link-extension'
|
|
39
|
+
// import { FloatingLinkEditorPlugin } from '../link/floating-link-editor'
|
|
40
40
|
import { ContentEditable } from '../../content-editable'
|
|
41
41
|
import { useSharedHistoryContext } from '../../context/shared-history-context'
|
|
42
42
|
import { useSharedOnChange } from '../../context/shared-on-change-context'
|
|
43
|
-
import { AdmonitionModal } from '../../plugins/admonition-plugin/admonition-modal'
|
|
44
43
|
import { Placeholder } from '../../ui/placeholder'
|
|
44
|
+
import { AdmonitionModal } from './admonition-modal'
|
|
45
45
|
import { $isAdmonitionNode } from './admonition-node'
|
|
46
46
|
import { DangerIcon, NoteIcon, TipIcon, WarningIcon } from './icons'
|
|
47
|
-
import type { AdmonitionData } from '../../plugins/admonition-plugin/types'
|
|
48
47
|
import type { AdmonitionNode } from './admonition-node'
|
|
49
|
-
import type { AdmonitionAttributes, AdmonitionType } from './types'
|
|
48
|
+
import type { AdmonitionAttributes, AdmonitionType } from './node-types'
|
|
49
|
+
import type { AdmonitionData } from './types'
|
|
50
50
|
|
|
51
51
|
import './admonition-node-component.css'
|
|
52
52
|
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
} from 'lexical'
|
|
22
22
|
import { $applyNodeReplacement, createEditor, DecoratorNode } from 'lexical'
|
|
23
23
|
|
|
24
|
-
import type { AdmonitionAttributes, AdmonitionType, SerializedAdmonitionNode } from './types'
|
|
24
|
+
import type { AdmonitionAttributes, AdmonitionType, SerializedAdmonitionNode } from './node-types'
|
|
25
25
|
|
|
26
26
|
const AdmonitionNodeComponent = React.lazy(async () => await import('./admonition-node-component'))
|
|
27
27
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { RadioGroupValue } from '@byline/ui/react'
|
|
10
10
|
|
|
11
|
-
import type { AdmonitionType } from '
|
|
11
|
+
import type { AdmonitionType } from './node-types'
|
|
12
12
|
import type { AdmonitionFormState } from './types'
|
|
13
13
|
|
|
14
14
|
export const admonitionTypeOptions: RadioGroupValue[] = [
|
|
@@ -11,4 +11,8 @@ export * from './admonition-node'
|
|
|
11
11
|
// lazily via `React.lazy` inside `admonition-node.tsx` so it can land in
|
|
12
12
|
// its own chunk. Re-exporting it here would static-import it back into
|
|
13
13
|
// any consumer of this barrel and defeat the split.
|
|
14
|
-
|
|
14
|
+
//
|
|
15
|
+
// Likewise NOT re-exported: `admonition-extension.tsx` and its dependencies
|
|
16
|
+
// (`admonition-modal.tsx`, `fields.ts`, `types.ts`) — those pull React UI
|
|
17
|
+
// and would bloat consumers that only want the node class.
|
|
18
|
+
export * from './node-types'
|
|
@@ -15,13 +15,26 @@ import {
|
|
|
15
15
|
AutoEmbedOption,
|
|
16
16
|
type EmbedConfig,
|
|
17
17
|
type EmbedMatchResult,
|
|
18
|
+
INSERT_EMBED_COMMAND,
|
|
18
19
|
LexicalAutoEmbedPlugin,
|
|
19
20
|
} from '@lexical/react/LexicalAutoEmbedPlugin'
|
|
20
|
-
import
|
|
21
|
+
import { ReactExtension } from '@lexical/react/ReactExtension'
|
|
22
|
+
import {
|
|
23
|
+
configExtension,
|
|
24
|
+
declarePeerDependency,
|
|
25
|
+
defineExtension,
|
|
26
|
+
type LexicalEditor,
|
|
27
|
+
} from 'lexical'
|
|
21
28
|
import * as ReactDOM from 'react-dom'
|
|
22
29
|
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
30
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
31
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
32
|
+
import {
|
|
33
|
+
type BylineToolbarConfig,
|
|
34
|
+
BylineToolbarExtension,
|
|
35
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
36
|
+
import { INSERT_VIMEO_COMMAND } from '../vimeo/vimeo-extension'
|
|
37
|
+
import { INSERT_YOUTUBE_COMMAND } from '../youtube/youtube-extension'
|
|
25
38
|
|
|
26
39
|
// import { INSERT_FIGMA_COMMAND } from '../FigmaPlugin'
|
|
27
40
|
// import { INSERT_TWEET_COMMAND } from '../TwitterPlugin'
|
|
@@ -321,3 +334,33 @@ export function AutoEmbedPlugin(): React.JSX.Element {
|
|
|
321
334
|
</>
|
|
322
335
|
)
|
|
323
336
|
}
|
|
337
|
+
|
|
338
|
+
function EmbedInsertItem({ embedConfig }: { embedConfig: AutoEmbedConfig }): React.JSX.Element {
|
|
339
|
+
const editor = useToolbarActiveEditor()
|
|
340
|
+
return (
|
|
341
|
+
<DropDownItem
|
|
342
|
+
onClick={() => {
|
|
343
|
+
editor.dispatchCommand(INSERT_EMBED_COMMAND, embedConfig.type)
|
|
344
|
+
}}
|
|
345
|
+
className="item"
|
|
346
|
+
>
|
|
347
|
+
{embedConfig.icon}
|
|
348
|
+
<span className="text">{embedConfig.contentName}</span>
|
|
349
|
+
</DropDownItem>
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export const AutoEmbedExtension = defineExtension({
|
|
354
|
+
name: '@byline/richtext-lexical/AutoEmbed',
|
|
355
|
+
dependencies: [configExtension(ReactExtension, { decorators: [<AutoEmbedPlugin key="d" />] })],
|
|
356
|
+
peerDependencies: [
|
|
357
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
358
|
+
items: EmbedConfigs.map((embedConfig, idx) => ({
|
|
359
|
+
id: `@byline/richtext-lexical/AutoEmbed/${embedConfig.type}`,
|
|
360
|
+
placement: 'insert-menu' as const,
|
|
361
|
+
order: 60 + idx,
|
|
362
|
+
node: <EmbedInsertItem embedConfig={embedConfig} />,
|
|
363
|
+
})),
|
|
364
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
365
|
+
],
|
|
366
|
+
})
|
|
@@ -4,7 +4,7 @@ import { Button, CloseIcon, IconButton, Input, Modal } from '@byline/ui/react'
|
|
|
4
4
|
import { type EmbedMatchResult, URL_MATCHER } from '@lexical/react/LexicalAutoEmbedPlugin'
|
|
5
5
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
6
6
|
|
|
7
|
-
import type { AutoEmbedConfig } from './
|
|
7
|
+
import type { AutoEmbedConfig } from './auto-embed-extension'
|
|
8
8
|
|
|
9
9
|
const debounce = (callback: (text: string) => void, delay: number): ((text: string) => void) => {
|
|
10
10
|
let timeoutId: number
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type * as React from 'react'
|
|
10
|
+
|
|
11
|
+
import { defineExtension, safeCast, shallowMergeConfig } from 'lexical'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Props passed by `Editor.tsx` to every registered floating-UI component.
|
|
15
|
+
* The component renders itself (usually via `createPortal(..., anchorElem)`)
|
|
16
|
+
* inside the editor's floating slot.
|
|
17
|
+
*/
|
|
18
|
+
export interface BylineFloatingUIProps {
|
|
19
|
+
anchorElem: HTMLElement
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface BylineFloatingUIItem {
|
|
23
|
+
/**
|
|
24
|
+
* Stable identifier — used as React key and for de-duplication.
|
|
25
|
+
* Convention: `<extension-name>/<purpose>`, e.g.
|
|
26
|
+
* `'@byline/richtext-lexical/Link/floating-editor'`.
|
|
27
|
+
*/
|
|
28
|
+
id: string
|
|
29
|
+
/**
|
|
30
|
+
* The floating UI component. Receives `anchorElem` (the editor's
|
|
31
|
+
* inner content-editable wrapper) as a prop and is expected to portal
|
|
32
|
+
* itself into that element.
|
|
33
|
+
*/
|
|
34
|
+
Component: React.ComponentType<BylineFloatingUIProps>
|
|
35
|
+
/** Sort key — lower numbers render first. Mostly cosmetic. */
|
|
36
|
+
order?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface BylineFloatingUIConfig {
|
|
40
|
+
items: BylineFloatingUIItem[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The floating-UI contract. Other extensions contribute floating UIs by
|
|
45
|
+
* listing `BylineFloatingUIExtension` in their `peerDependencies` and
|
|
46
|
+
* supplying an `items` array. The editor's floating slot reads the merged
|
|
47
|
+
* list once and renders every contributor under the shared anchor.
|
|
48
|
+
*
|
|
49
|
+
* Mirror of `BylineToolbarExtension` for the floating-UI surface — same
|
|
50
|
+
* pattern, same authoring shape.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { declarePeerDependency, defineExtension } from 'lexical'
|
|
55
|
+
* import { BylineFloatingUIExtension } from '@byline/richtext-lexical'
|
|
56
|
+
*
|
|
57
|
+
* export const MyExtension = defineExtension({
|
|
58
|
+
* name: '@example/MyExtension',
|
|
59
|
+
* peerDependencies: [
|
|
60
|
+
* declarePeerDependency<typeof BylineFloatingUIExtension>(
|
|
61
|
+
* BylineFloatingUIExtension.name,
|
|
62
|
+
* {
|
|
63
|
+
* items: [{
|
|
64
|
+
* id: '@example/MyExtension/floating',
|
|
65
|
+
* Component: MyFloatingPopover,
|
|
66
|
+
* }],
|
|
67
|
+
* }
|
|
68
|
+
* ),
|
|
69
|
+
* ],
|
|
70
|
+
* })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export const BylineFloatingUIExtension = defineExtension({
|
|
74
|
+
name: '@byline/richtext-lexical/FloatingUI',
|
|
75
|
+
config: safeCast<BylineFloatingUIConfig>({ items: [] }),
|
|
76
|
+
mergeConfig(a, b) {
|
|
77
|
+
const merged = shallowMergeConfig(a, b)
|
|
78
|
+
if (b.items && b.items.length > 0) {
|
|
79
|
+
merged.items = [...a.items, ...b.items]
|
|
80
|
+
}
|
|
81
|
+
return merged
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
/** Sort helper used by the editor's floating-UI slot. */
|
|
86
|
+
export function selectFloatingUIItems(
|
|
87
|
+
items: ReadonlyArray<BylineFloatingUIItem>
|
|
88
|
+
): BylineFloatingUIItem[] {
|
|
89
|
+
return items.slice().sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
90
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
type BylineFloatingUIConfig,
|
|
11
|
+
BylineFloatingUIExtension,
|
|
12
|
+
type BylineFloatingUIItem,
|
|
13
|
+
type BylineFloatingUIProps,
|
|
14
|
+
selectFloatingUIItems,
|
|
15
|
+
} from './byline-floating-ui-extension'
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type * as React from 'react'
|
|
10
|
+
|
|
11
|
+
import { defineExtension, safeCast, shallowMergeConfig } from 'lexical'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Where in the Byline toolbar a contributed item is rendered. Built-in
|
|
15
|
+
* extensions and third-party extensions both contribute against these
|
|
16
|
+
* placements via `peerDependencies`; the toolbar plugin reads the merged
|
|
17
|
+
* list and dispatches by `placement`.
|
|
18
|
+
*
|
|
19
|
+
* - `'toolbar'` — appended to the end of the main toolbar row.
|
|
20
|
+
* - `'insert-menu'` — listed inside the "Insert" dropdown that the
|
|
21
|
+
* toolbar shows when at least one insert-menu contribution exists.
|
|
22
|
+
*/
|
|
23
|
+
export type BylineToolbarPlacement = 'toolbar' | 'insert-menu'
|
|
24
|
+
|
|
25
|
+
export interface BylineToolbarItem {
|
|
26
|
+
/**
|
|
27
|
+
* Stable identifier — used as React key and for de-duplication.
|
|
28
|
+
* Convention: `<extension-name>/<purpose>`, e.g.
|
|
29
|
+
* `'@byline/richtext-lexical/InlineImage/insert'`.
|
|
30
|
+
*/
|
|
31
|
+
id: string
|
|
32
|
+
placement: BylineToolbarPlacement
|
|
33
|
+
/** Sort key within `placement`. Lower numbers render first. */
|
|
34
|
+
order?: number
|
|
35
|
+
node: React.ReactNode
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface BylineToolbarConfig {
|
|
39
|
+
items: BylineToolbarItem[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The toolbar contract. Other extensions add toolbar entries by listing
|
|
44
|
+
* `BylineToolbarExtension` in their `peerDependencies` and supplying an
|
|
45
|
+
* `items` array — the configs are merged across every contributor and
|
|
46
|
+
* read once by the toolbar plugin.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { declarePeerDependency, defineExtension } from 'lexical'
|
|
51
|
+
* import { BylineToolbarExtension } from '@byline/richtext-lexical'
|
|
52
|
+
*
|
|
53
|
+
* export const MyExtension = defineExtension({
|
|
54
|
+
* name: '@example/MyExtension',
|
|
55
|
+
* peerDependencies: [
|
|
56
|
+
* declarePeerDependency<typeof BylineToolbarExtension>(
|
|
57
|
+
* BylineToolbarExtension.name,
|
|
58
|
+
* {
|
|
59
|
+
* items: [{
|
|
60
|
+
* id: '@example/MyExtension/insert',
|
|
61
|
+
* placement: 'insert-menu',
|
|
62
|
+
* order: 100,
|
|
63
|
+
* node: <MyInsertMenuItem />,
|
|
64
|
+
* }],
|
|
65
|
+
* }
|
|
66
|
+
* ),
|
|
67
|
+
* ],
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export const BylineToolbarExtension = defineExtension({
|
|
72
|
+
name: '@byline/richtext-lexical/Toolbar',
|
|
73
|
+
config: safeCast<BylineToolbarConfig>({ items: [] }),
|
|
74
|
+
mergeConfig(a, b) {
|
|
75
|
+
const merged = shallowMergeConfig(a, b)
|
|
76
|
+
if (b.items && b.items.length > 0) {
|
|
77
|
+
merged.items = [...a.items, ...b.items]
|
|
78
|
+
}
|
|
79
|
+
return merged
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sort and filter helper used by `toolbar-plugin` and any external
|
|
85
|
+
* surface that wants to render Byline toolbar contributions itself.
|
|
86
|
+
*/
|
|
87
|
+
export function selectToolbarItems(
|
|
88
|
+
items: ReadonlyArray<BylineToolbarItem>,
|
|
89
|
+
placement: BylineToolbarPlacement
|
|
90
|
+
): BylineToolbarItem[] {
|
|
91
|
+
return items
|
|
92
|
+
.filter((item) => item.placement === placement)
|
|
93
|
+
.slice()
|
|
94
|
+
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
|
95
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
type BylineToolbarConfig,
|
|
11
|
+
BylineToolbarExtension,
|
|
12
|
+
type BylineToolbarItem,
|
|
13
|
+
type BylineToolbarPlacement,
|
|
14
|
+
selectToolbarItems,
|
|
15
|
+
} from './byline-toolbar-extension'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*
|
|
8
|
+
* Portions Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { CodeHighlightNode, CodeNode, registerCodeHighlighting } from '@lexical/code'
|
|
12
|
+
import { defineExtension } from 'lexical'
|
|
13
|
+
|
|
14
|
+
export const CodeHighlightExtension = defineExtension({
|
|
15
|
+
name: '@byline/richtext-lexical/CodeHighlight',
|
|
16
|
+
nodes: () => [CodeNode, CodeHighlightNode],
|
|
17
|
+
register: (editor) => registerCodeHighlighting(editor),
|
|
18
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { declarePeerDependency, defineExtension } from 'lexical'
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
type BylineFloatingUIConfig,
|
|
13
|
+
BylineFloatingUIExtension,
|
|
14
|
+
} from '../byline-floating-ui/byline-floating-ui-extension'
|
|
15
|
+
import { FloatingTextFormatToolbarPlugin } from './index'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Standalone Byline extension that contributes the floating text-format
|
|
19
|
+
* toolbar (the popover shown above a non-collapsed range selection) to
|
|
20
|
+
* the editor. Removing this extension from the registered list hides the
|
|
21
|
+
* UI — `c.extensions.remove(FloatingTextFormatExtension)`.
|
|
22
|
+
*
|
|
23
|
+
* Lives in its own extension because the popover isn't owned by any
|
|
24
|
+
* single feature: it handles bold / italic / underline / strikethrough /
|
|
25
|
+
* subscript / superscript / inline-code / link toggle in one place.
|
|
26
|
+
*/
|
|
27
|
+
export const FloatingTextFormatExtension = defineExtension({
|
|
28
|
+
name: '@byline/richtext-lexical/FloatingTextFormat',
|
|
29
|
+
peerDependencies: [
|
|
30
|
+
declarePeerDependency<typeof BylineFloatingUIExtension>(BylineFloatingUIExtension.name, {
|
|
31
|
+
items: [
|
|
32
|
+
{
|
|
33
|
+
id: '@byline/richtext-lexical/FloatingTextFormat/popover',
|
|
34
|
+
Component: FloatingTextFormatToolbarPlugin,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
} satisfies Partial<BylineFloatingUIConfig>),
|
|
38
|
+
],
|
|
39
|
+
})
|
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
} from 'lexical'
|
|
28
28
|
import { createPortal } from 'react-dom'
|
|
29
29
|
|
|
30
|
-
import { $isLinkNode, type LinkAttributes, TOGGLE_LINK_COMMAND } from '../../nodes/link-nodes'
|
|
31
30
|
import { getDOMRangeRect } from '../../utils/getDOMRangeRect'
|
|
32
31
|
import { getSelectedNode } from '../../utils/getSelectedNode'
|
|
33
32
|
import { setFloatingElemPosition } from '../../utils/setFloatingElemPosition'
|
|
33
|
+
import { $isLinkNode, type LinkAttributes, TOGGLE_LINK_COMMAND } from '../link'
|
|
34
34
|
|
|
35
35
|
function TextFormatFloatingToolbar({
|
|
36
36
|
editor,
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { HorizontalRuleExtension as LexicalHorizontalRuleExtension } from '@lexical/extension'
|
|
12
|
+
import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode'
|
|
13
|
+
import { declarePeerDependency, defineExtension } from 'lexical'
|
|
14
|
+
|
|
15
|
+
import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
|
|
16
|
+
import { DropDownItem } from '../../ui/dropdown'
|
|
17
|
+
import {
|
|
18
|
+
type BylineToolbarConfig,
|
|
19
|
+
BylineToolbarExtension,
|
|
20
|
+
} from '../byline-toolbar/byline-toolbar-extension'
|
|
21
|
+
|
|
22
|
+
function HorizontalRuleInsertItem(): React.JSX.Element {
|
|
23
|
+
const editor = useToolbarActiveEditor()
|
|
24
|
+
return (
|
|
25
|
+
<DropDownItem
|
|
26
|
+
onClick={() => {
|
|
27
|
+
editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined)
|
|
28
|
+
}}
|
|
29
|
+
className="item"
|
|
30
|
+
>
|
|
31
|
+
<i className="icon horizontal-rule" />
|
|
32
|
+
<span className="text">Horizontal Rule</span>
|
|
33
|
+
</DropDownItem>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Byline wrapper around the upstream `HorizontalRuleExtension`. Adds a
|
|
39
|
+
* single insert-menu contribution; the underlying extension still owns
|
|
40
|
+
* the node registration and command behaviour.
|
|
41
|
+
*/
|
|
42
|
+
export const HorizontalRuleExtension = defineExtension({
|
|
43
|
+
name: '@byline/richtext-lexical/HorizontalRule',
|
|
44
|
+
dependencies: [LexicalHorizontalRuleExtension],
|
|
45
|
+
peerDependencies: [
|
|
46
|
+
declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
|
|
47
|
+
items: [
|
|
48
|
+
{
|
|
49
|
+
id: '@byline/richtext-lexical/HorizontalRule/insert',
|
|
50
|
+
placement: 'insert-menu',
|
|
51
|
+
order: 10,
|
|
52
|
+
node: <HorizontalRuleInsertItem />,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
} satisfies Partial<BylineToolbarConfig>),
|
|
56
|
+
],
|
|
57
|
+
})
|