@lobehub/editor 1.16.2 → 1.17.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/es/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './plugins/hr';
8
8
  export * from './plugins/image';
9
9
  export * from './plugins/link';
10
10
  export * from './plugins/list';
11
+ export * from './plugins/markdown';
11
12
  export * from './plugins/math';
12
13
  export * from './plugins/mention';
13
14
  export * from './plugins/slash';
package/es/index.js CHANGED
@@ -8,6 +8,7 @@ export * from "./plugins/hr";
8
8
  export * from "./plugins/image";
9
9
  export * from "./plugins/link";
10
10
  export * from "./plugins/list";
11
+ export * from "./plugins/markdown";
11
12
  export * from "./plugins/math";
12
13
  export * from "./plugins/mention";
13
14
  export * from "./plugins/slash";
@@ -16,6 +16,12 @@ declare const _default: {
16
16
  placeholder: string;
17
17
  unlink: string;
18
18
  };
19
+ markdown: {
20
+ cancel: string;
21
+ confirm: string;
22
+ parseMessage: string;
23
+ parseTitle: string;
24
+ };
19
25
  math: {
20
26
  placeholder: string;
21
27
  };
@@ -16,6 +16,12 @@ export default {
16
16
  placeholder: 'Enter link URL',
17
17
  unlink: 'Unlink Link'
18
18
  },
19
+ markdown: {
20
+ cancel: 'Cancel',
21
+ confirm: 'Confirm',
22
+ parseMessage: 'Convert to markdown format, existing content will be overwritten, confirm? (Auto close in 5 seconds)',
23
+ parseTitle: 'Parse Markdown'
24
+ },
19
25
  math: {
20
26
  placeholder: 'Enter TeX formula'
21
27
  },
@@ -30,15 +30,15 @@ export var useStyles = createStyles(function (_ref2, _ref3) {
30
30
  lineHeight = _ref3$lineHeight === void 0 ? 1.8 : _ref3$lineHeight;
31
31
  var __root = css(_templateObject11 || (_templateObject11 = _taggedTemplateLiteral(["\n --lobe-markdown-font-size: ", "px;\n --lobe-markdown-header-multiple: ", ";\n --lobe-markdown-margin-multiple: ", ";\n --lobe-markdown-line-height: ", ";\n --lobe-markdown-border-radius: ", ";\n --lobe-markdown-border-color: ", ";\n\n position: relative;\n\n display: flex;\n flex-direction: column;\n\n width: 100%;\n max-width: 100%;\n height: 100%;\n\n font-size: var(--lobe-markdown-font-size);\n line-height: var(--lobe-markdown-line-height);\n word-break: break-word;\n\n @keyframes cursor-blink {\n to {\n visibility: hidden;\n }\n }\n\n [data-lexical-cursor='true'] {\n pointer-events: none;\n position: absolute;\n display: block;\n\n &::after {\n content: '';\n\n position: absolute;\n inset-block-start: -2px;\n\n display: block;\n\n width: 20px;\n border-block-start: 1px solid ", ";\n\n animation: cursor-blink 1.1s steps(2, start) infinite;\n }\n }\n "])), fontSize, headerMultiple, marginMultiple, lineHeight, token.borderRadiusLG, token.colorFillQuaternary, token.colorText);
32
32
  var header = css(_templateObject12 || (_templateObject12 = _taggedTemplateLiteral(["\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-block: max(\n calc(var(--lobe-markdown-header-multiple) * var(--lobe-markdown-margin-multiple) * 0.4em),\n var(--lobe-markdown-font-size)\n );\n font-weight: bold;\n line-height: 1.25;\n }\n\n h1 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 1.5 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h2 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + var(--lobe-markdown-header-multiple))\n );\n }\n\n h3 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 0.5 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h4 {\n font-size: calc(\n var(--lobe-markdown-font-size) * (1 + 0.25 * var(--lobe-markdown-header-multiple))\n );\n }\n\n h5,\n h6 {\n font-size: calc(var(--lobe-markdown-font-size) * 1);\n }\n "])));
33
- var p = css(_templateObject13 || (_templateObject13 = _taggedTemplateLiteral(["\n p {\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n line-height: var(--lobe-markdown-line-height);\n letter-spacing: 0.02em;\n\n &:not(:first-child) {\n margin-block-start: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n\n &:not(:last-child) {\n margin-block-end: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n }\n "])));
33
+ var p = css(_templateObject13 || (_templateObject13 = _taggedTemplateLiteral(["\n p {\n margin-block: 4px;\n line-height: var(--lobe-markdown-line-height);\n letter-spacing: 0.02em;\n\n &:not(:first-child) {\n margin-block-start: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n\n &:not(:last-child) {\n margin-block-end: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n }\n "])));
34
34
  var blockquote = css(_templateObject14 || (_templateObject14 = _taggedTemplateLiteral(["\n .editor_quote {\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n margin-inline: 0;\n padding-block: 0;\n padding-inline: 1em;\n border-inline-start: solid 4px ", ";\n\n color: ", ";\n }\n "])), token.colorBorder, token.colorTextSecondary);
35
35
  var code = css(_templateObject15 || (_templateObject15 = _taggedTemplateLiteral(["\n .editor_code {\n display: inline;\n\n margin-inline: 0.25em;\n padding-block: 0.2em;\n padding-inline: 0.4em;\n border: 1px solid var(--lobe-markdown-border-color);\n border-radius: 0.25em;\n\n font-family: ", ";\n font-size: 0.875em;\n line-height: 1;\n word-break: break-word;\n white-space: break-spaces;\n\n background: ", ";\n }\n "])), token.fontFamilyCode, token.colorFillSecondary);
36
36
  return {
37
37
  blockquote: blockquote,
38
38
  code: code,
39
39
  header: header,
40
- noHeader: css(_templateObject16 || (_templateObject16 = _taggedTemplateLiteral(["\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-block: 4px;\n font-size: var(--lobe-markdown-font-size);\n line-height: var(--lobe-markdown-line-height);\n letter-spacing: 0.02em;\n\n &:not(:first-child) {\n margin-block-start: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n\n &:not(:last-child) {\n margin-block-end: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n }\n }\n "]))),
41
- noStyle: css(_templateObject17 || (_templateObject17 = _taggedTemplateLiteral(["\n --lobe-markdown-header-multiple: 0;\n --lobe-markdown-margin-multiple: 0;\n --lobe-markdown-line-height: 1.5;\n\n p {\n margin-block: 0;\n }\n "]))),
40
+ noHeader: css(_templateObject16 || (_templateObject16 = _taggedTemplateLiteral(["\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-block: 0;\n font-size: var(--lobe-markdown-font-size);\n font-weight: normal;\n line-height: var(--lobe-markdown-line-height);\n }\n "]))),
41
+ noStyle: css(_templateObject17 || (_templateObject17 = _taggedTemplateLiteral(["\n --lobe-markdown-header-multiple: 0;\n --lobe-markdown-margin-multiple: 0;\n --lobe-markdown-line-height: 1.5;\n\n p {\n margin-block: 4px;\n }\n "]))),
42
42
  p: p,
43
43
  root: __root,
44
44
  variant: cx(header, p, blockquote, code)
@@ -0,0 +1,6 @@
1
+ import { LexicalEditor } from 'lexical';
2
+ import { MarkdownShortCutService } from '../service/shortcut';
3
+ export declare const INSERT_MARKDOWN_COMMAND: import("lexical").LexicalCommand<{
4
+ markdown: string;
5
+ }>;
6
+ export declare function registerMarkdownCommand(editor: LexicalEditor, service: MarkdownShortCutService): () => void;
@@ -0,0 +1,27 @@
1
+ import { $getSelection, COMMAND_PRIORITY_HIGH, createCommand } from 'lexical';
2
+ import { createDebugLogger } from "../../../utils/debug";
3
+ import { parseMarkdownToLexical } from "../data-source/markdown/parse";
4
+ import { $generateNodesFromSerializedNodes, $insertGeneratedNodes } from "../utils";
5
+ var logger = createDebugLogger('plugin', 'markdown');
6
+ export var INSERT_MARKDOWN_COMMAND = createCommand('INSERT_MARKDOWN_COMMAND');
7
+ export function registerMarkdownCommand(editor, service) {
8
+ return editor.registerCommand(INSERT_MARKDOWN_COMMAND, function (payload) {
9
+ var markdown = payload.markdown;
10
+ logger.debug('INSERT_MARKDOWN_COMMAND payload:', payload);
11
+ editor.update(function () {
12
+ try {
13
+ // Use the markdown data source to parse the content
14
+ var root = parseMarkdownToLexical(markdown, service.markdownReaders);
15
+ var selection = $getSelection();
16
+ var nodes = $generateNodesFromSerializedNodes(root.children);
17
+ logger.debug('INSERT_MARKDOWN_COMMAND nodes:', nodes);
18
+ $insertGeneratedNodes(editor, nodes, selection);
19
+ return true;
20
+ } catch (error) {
21
+ logger.error('Failed to handle markdown paste:', error);
22
+ }
23
+ });
24
+ return false;
25
+ }, COMMAND_PRIORITY_HIGH // Priority
26
+ );
27
+ }
@@ -68,6 +68,10 @@ function convertMdastToLexical(node, index, ctx) {
68
68
  var htmlStack = []; // 当前循环是否包含 HTML 标签
69
69
  _children = node.children.reduce(function (ret, child, index) {
70
70
  if (child.type === 'html') {
71
+ var isComment = child.value.startsWith('<!--') && child.value.endsWith('-->');
72
+ if (isComment) {
73
+ return ret;
74
+ }
71
75
  var tag = child.value.replaceAll(/^<\/?|>$/g, '');
72
76
  var isEndTag = child.value.startsWith('</');
73
77
  if (selfClosingHtmlTags.has(tag)) {
@@ -1,4 +1,6 @@
1
+ export { INSERT_MARKDOWN_COMMAND } from './command';
1
2
  export { MarkdownPlugin } from './plugin';
3
+ export { default as ReactMarkdownPlugin } from './react';
2
4
  export type { MARKDOWN_READER_LEVEL } from './service/shortcut';
3
5
  export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX, } from './service/shortcut';
4
6
  export { isPunctuationChar } from './utils';
@@ -1,3 +1,5 @@
1
+ export { INSERT_MARKDOWN_COMMAND } from "./command";
1
2
  export { MarkdownPlugin } from "./plugin";
3
+ export { default as ReactMarkdownPlugin } from "./react";
2
4
  export { IMarkdownShortCutService, MARKDOWN_READER_LEVEL_HIGH, MARKDOWN_READER_LEVEL_NORMAL, MARKDOWN_WRITER_LEVEL_MAX } from "./service/shortcut";
3
5
  export { isPunctuationChar } from "./utils";
@@ -17,10 +17,10 @@ import { $isCodeNode } from '@lexical/code';
17
17
  import { $getNodeByKey, $getSelection, $isRangeSelection, $isTextNode, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, HISTORIC_TAG, KEY_ENTER_COMMAND, PASTE_COMMAND } from 'lexical';
18
18
  import { KernelPlugin } from "../../../editor-kernel/plugin";
19
19
  import { createDebugLogger } from "../../../utils/debug";
20
+ import { registerMarkdownCommand } from "../command";
20
21
  import MarkdownDataSource from "../data-source/markdown-data-source";
21
- import { parseMarkdownToLexical } from "../data-source/markdown/parse";
22
22
  import { IMarkdownShortCutService, MarkdownShortCutService } from "../service/shortcut";
23
- import { $generateNodesFromSerializedNodes, $insertGeneratedNodes, canContainTransformableMarkdown } from "../utils";
23
+ import { canContainTransformableMarkdown } from "../utils";
24
24
  export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
25
25
  _inherits(MarkdownPlugin, _KernelPlugin);
26
26
  var _super = _createSuper(MarkdownPlugin);
@@ -120,12 +120,6 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
120
120
  }, COMMAND_PRIORITY_CRITICAL));
121
121
  this.register(editor.registerCommand(PASTE_COMMAND, function (event) {
122
122
  var _this2$config$enableP, _this2$config;
123
- // Check if markdown paste formatting is enabled (default: true)
124
- var enablePasteMarkdown = (_this2$config$enableP = (_this2$config = _this2.config) === null || _this2$config === void 0 ? void 0 : _this2$config.enablePasteMarkdown) !== null && _this2$config$enableP !== void 0 ? _this2$config$enableP : true;
125
- if (!enablePasteMarkdown) {
126
- _this2.logger.debug('paste markdown formatting is disabled');
127
- return false;
128
- }
129
123
  if (!(event instanceof ClipboardEvent)) return false;
130
124
  var clipboardData = event.clipboardData;
131
125
  if (!clipboardData) return false;
@@ -137,6 +131,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
137
131
  // If there's no text content, let Lexical handle it
138
132
  if (!text) return false;
139
133
 
134
+ // Check if markdown paste formatting is enabled (default: true)
135
+ var enablePasteMarkdown = (_this2$config$enableP = (_this2$config = _this2.config) === null || _this2$config === void 0 ? void 0 : _this2$config.enablePasteMarkdown) !== null && _this2$config$enableP !== void 0 ? _this2$config$enableP : true;
136
+ if (!enablePasteMarkdown) {
137
+ // Force plain text paste - ignore all formatting (like Cmd+Shift+V)
138
+ _this2.logger.debug('paste markdown formatting is disabled, inserting as plain text');
139
+ event.preventDefault();
140
+ event.stopPropagation();
141
+ editor.update(function () {
142
+ var selection = $getSelection();
143
+ if (!$isRangeSelection(selection)) return;
144
+
145
+ // Simply insert the plain text
146
+ selection.insertText(text);
147
+ });
148
+ return true;
149
+ }
150
+
140
151
  // If there's HTML content, it's a rich text paste
141
152
  // Let Lexical's rich text handler process it
142
153
  if (html && html.trim()) {
@@ -154,10 +165,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
154
165
  });
155
166
  if (hasMarkdownContent) {
156
167
  // Handle markdown paste
157
- return _this2.handleMarkdownPaste(editor, text);
168
+ // return this.handleMarkdownPaste(editor, text);
169
+ var cacheState = editor.getEditorState();
170
+ _this2.kernel.emit('markdownParse', {
171
+ cacheState: cacheState,
172
+ markdown: text
173
+ });
174
+ // setTimeout(() => {
175
+ // editor.setEditorState(cacheState);
176
+ // editor.update(() => {
177
+ // this.handleMarkdownPaste(editor, text);
178
+ // });
179
+ // }, 5000);
180
+ return false;
158
181
  }
159
182
  return false;
160
183
  }, COMMAND_PRIORITY_CRITICAL));
184
+ this.register(registerMarkdownCommand(editor, this.service));
161
185
  }
162
186
 
163
187
  /**
@@ -249,24 +273,23 @@ export var MarkdownPlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
249
273
  });
250
274
  }
251
275
 
252
- /**
253
- * Handle markdown paste by parsing and inserting as structured content
254
- */
255
- }, {
256
- key: "handleMarkdownPaste",
257
- value: function handleMarkdownPaste(editor, text) {
258
- try {
259
- // Use the markdown data source to parse the content
260
- var root = parseMarkdownToLexical(text, this.service.markdownReaders);
261
- var selection = $getSelection();
262
- var nodes = $generateNodesFromSerializedNodes(root.children);
263
- $insertGeneratedNodes(editor, nodes, selection);
264
- return true;
265
- } catch (error) {
266
- this.logger.error('Failed to handle markdown paste:', error);
267
- }
268
- return false;
269
- }
276
+ // /**
277
+ // * Handle markdown paste by parsing and inserting as structured content
278
+ // */
279
+ // private handleMarkdownPaste(editor: LexicalEditor, text: string): boolean {
280
+ // try {
281
+ // // Use the markdown data source to parse the content
282
+ // const root = parseMarkdownToLexical(text, this.service.markdownReaders);
283
+ // const selection = $getSelection();
284
+ // const nodes = $generateNodesFromSerializedNodes(root.children);
285
+ // $insertGeneratedNodes(editor, nodes, selection!);
286
+ // return true;
287
+ // } catch (error) {
288
+ // this.logger.error('Failed to handle markdown paste:', error);
289
+ // }
290
+
291
+ // return false;
292
+ // }
270
293
  }]);
271
294
  return MarkdownPlugin;
272
295
  }(KernelPlugin), _defineProperty(_class, "pluginName", 'MarkdownPlugin'), _class);
@@ -0,0 +1,3 @@
1
+ import { type FC } from 'react';
2
+ declare const ReactMarkdownPlugin: FC<void>;
3
+ export default ReactMarkdownPlugin;
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+
3
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
4
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
7
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
8
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
9
+ import { Button, Space, notification } from 'antd';
10
+ import { UNDO_COMMAND } from 'lexical';
11
+ import { useLayoutEffect } from 'react';
12
+ import { useLexicalComposerContext } from "../../../editor-kernel/react";
13
+ import { useTranslation } from "../../../editor-kernel/react/useTranslation";
14
+ import { INSERT_MARKDOWN_COMMAND } from "../command";
15
+ import { MarkdownPlugin } from "../plugin";
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ import { jsxs as _jsxs } from "react/jsx-runtime";
18
+ var ReactMarkdownPlugin = function ReactMarkdownPlugin() {
19
+ var _useLexicalComposerCo = useLexicalComposerContext(),
20
+ _useLexicalComposerCo2 = _slicedToArray(_useLexicalComposerCo, 1),
21
+ editor = _useLexicalComposerCo2[0];
22
+ var _notification$useNoti = notification.useNotification(),
23
+ _notification$useNoti2 = _slicedToArray(_notification$useNoti, 2),
24
+ api = _notification$useNoti2[0],
25
+ contextHolder = _notification$useNoti2[1];
26
+ var t = useTranslation();
27
+ useLayoutEffect(function () {
28
+ editor.registerPlugin(MarkdownPlugin);
29
+ var handleEvent = function handleEvent(_ref) {
30
+ var markdown = _ref.markdown;
31
+ var key = "open".concat(Date.now());
32
+ var actions = /*#__PURE__*/_jsxs(Space, {
33
+ children: [/*#__PURE__*/_jsx(Button, {
34
+ onClick: function onClick() {
35
+ return api.destroy();
36
+ },
37
+ size: "small",
38
+ type: "link",
39
+ children: t('markdown.cancel')
40
+ }), /*#__PURE__*/_jsx(Button, {
41
+ onClick: function onClick() {
42
+ editor.dispatchCommand(UNDO_COMMAND, undefined);
43
+ editor.dispatchCommand(INSERT_MARKDOWN_COMMAND, {
44
+ markdown: markdown
45
+ });
46
+ api.destroy();
47
+ },
48
+ size: "small",
49
+ type: "primary",
50
+ children: t('markdown.confirm')
51
+ })]
52
+ });
53
+ api.open({
54
+ actions: actions,
55
+ description: t('markdown.parseMessage'),
56
+ duration: 5,
57
+ key: key,
58
+ message: t('markdown.parseTitle'),
59
+ onClose: close
60
+ });
61
+ };
62
+ editor.on('markdownParse', handleEvent);
63
+ return function () {
64
+ editor.off('markdownParse', handleEvent);
65
+ };
66
+ }, [editor]);
67
+ return contextHolder;
68
+ };
69
+ ReactMarkdownPlugin.displayName = 'ReactMarkdownPlugin';
70
+ export default ReactMarkdownPlugin;
@@ -1,4 +1,4 @@
1
- import type { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
1
+ import type { CommandListener, CommandListenerPriority, CommandPayloadType, DecoratorNode, EditorState, LexicalCommand, LexicalEditor, LexicalNodeConfig } from 'lexical';
2
2
  import type DataSource from "../editor-kernel/data-source";
3
3
  import { HotkeyId } from "./hotkey";
4
4
  import { HotkeyOptions, HotkeysEvent } from "../utils/hotkey/registerHotkey";
@@ -23,6 +23,13 @@ export interface IKernelEventMap {
23
23
  * @returns
24
24
  */
25
25
  initialized: (editor: LexicalEditor) => void;
26
+ /**
27
+ * handle markdown parse event
28
+ */
29
+ markdownParse: (params: {
30
+ cacheState: EditorState;
31
+ markdown: string;
32
+ }) => void;
26
33
  }
27
34
  /**
28
35
  * External API
@@ -175,6 +182,7 @@ export interface IEditor {
175
182
  * API provided to plugins
176
183
  */
177
184
  export interface IEditorKernel extends IEditor {
185
+ emit<T extends keyof IKernelEventMap>(event: T, params: Parameters<IKernelEventMap[T]>[0]): void;
178
186
  /**
179
187
  * Get editor Node decorator for specific Node rendering
180
188
  * @param name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "1.16.2",
3
+ "version": "1.17.0",
4
4
  "description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
5
5
  "keywords": [
6
6
  "lobehub",