@lobehub/editor 1.5.2 → 1.5.4

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/README.md CHANGED
@@ -8,17 +8,17 @@
8
8
 
9
9
  A modern, extensible rich text editor built on Meta's Lexical framework with dual-architecture design, featuring both a powerful kernel and React integration. Optimized for AI applications and chat interfaces.
10
10
 
11
- [![][npm-release-shield]][npm-release-link]
12
- [![][github-releasedate-shield]][github-releasedate-link]
13
- [![][github-action-test-shield]][github-action-test-link]
14
- [![][github-action-release-shield]][github-action-release-link]<br/>
15
- [![][github-contributors-shield]][github-contributors-link]
16
- [![][github-forks-shield]][github-forks-link]
17
- [![][github-stars-shield]][github-stars-link]
18
- [![][github-issues-shield]][github-issues-link]
19
- [![][github-license-shield]][github-license-link]
20
-
21
- [Changelog](./CHANGELOG.md) · [Report Bug][github-issues-link] · [Request Feature][github-issues-link]
11
+ \[!\[]\[npm-release-shield]]\[npm-release-link]
12
+ \[!\[]\[github-releasedate-shield]]\[github-releasedate-link]
13
+ \[!\[]\[github-action-test-shield]]\[github-action-test-link]
14
+ \[!\[]\[github-action-release-shield]]\[github-action-release-link]<br/>
15
+ \[!\[]\[github-contributors-shield]]\[github-contributors-link]
16
+ \[!\[]\[github-forks-shield]]\[github-forks-link]
17
+ \[!\[]\[github-stars-shield]]\[github-stars-link]
18
+ \[!\[]\[github-issues-shield]]\[github-issues-link]
19
+ \[!\[]\[github-license-shield]]\[github-license-link]
20
+
21
+ [Changelog](./CHANGELOG.md) · \[Report Bug]\[github-issues-link] · \[Request Feature]\[github-issues-link]
22
22
 
23
23
  ![](https://github.com/user-attachments/assets/98c9a810-1c7d-4c33-acd7-ae9d4c0695da)
24
24
 
@@ -47,12 +47,7 @@ A modern, extensible rich text editor built on Meta's Lexical framework with dua
47
47
  - [🛠️ Development](#️-development)
48
48
  - [Setup](#setup)
49
49
  - [Available Scripts](#available-scripts)
50
- - [Project Architecture](#project-architecture)
51
- - [🤝 Contributing](#-contributing)
52
- - [🔗 Links](#-links)
53
- - [More Products](#more-products)
54
- - [Design Resources](#design-resources)
55
- - [Development Resources](#development-resources)
50
+ - [Debug Environment Variables](#debug-environment-variables)
56
51
 
57
52
  ####
58
53
 
@@ -75,7 +70,7 @@ A modern, extensible rich text editor built on Meta's Lexical framework with dua
75
70
 
76
71
  To install `@lobehub/editor`, run the following command:
77
72
 
78
- [![][bun-shield]][bun-link]
73
+ \[!\[]\[bun-shield]]\[bun-link]
79
74
 
80
75
  ```bash
81
76
  $ bun add @lobehub/editor
@@ -87,7 +82,7 @@ $ pnpm add @lobehub/editor
87
82
 
88
83
  <div align="right">
89
84
 
90
- [![][back-to-top]](#readme-top)
85
+ [!\[\]\[back-to-top\]](#readme-top)
91
86
 
92
87
  </div>
93
88
 
@@ -236,7 +231,7 @@ editor.dispatchCommand(INSERT_HEADING_COMMAND, { tag: 'h2' });
236
231
 
237
232
  <div align="right">
238
233
 
239
- [![][back-to-top]](#readme-top)
234
+ [!\[\]\[back-to-top\]](#readme-top)
240
235
 
241
236
  </div>
242
237
 
@@ -395,7 +390,7 @@ CLEAR_FORMAT_COMMAND;
395
390
 
396
391
  <div align="right">
397
392
 
398
- [![][back-to-top]](#readme-top)
393
+ [!\[\]\[back-to-top\]](#readme-top)
399
394
 
400
395
  </div>
401
396
 
@@ -405,11 +400,11 @@ CLEAR_FORMAT_COMMAND;
405
400
 
406
401
  You can use Github Codespaces for online development:
407
402
 
408
- [![][github-codespace-shield]][github-codespace-link]
403
+ \[!\[]\[github-codespace-shield]]\[github-codespace-link]
409
404
 
410
405
  Or clone it for local development:
411
406
 
412
- [![][bun-shield]][bun-link]
407
+ \[!\[]\[bun-shield]]\[bun-link]
413
408
 
414
409
  ```bash
415
410
  $ git clone https://github.com/lobehub/lobe-editor.git
@@ -434,6 +429,61 @@ This will start the Dumi documentation server with live playground at `http://lo
434
429
  | `pnpm docs:build` | Build documentation for production |
435
430
  | `pnpm release` | Publish new version with semantic-release |
436
431
 
432
+ ### Debug Environment Variables
433
+
434
+ LobeHub Editor includes comprehensive debug logging that can be controlled via environment variables:
435
+
436
+ #### Basic Debug Configuration
437
+
438
+ ```bash
439
+ # Enable all LobeHub Editor debug output
440
+ DEBUG=lobe-editor:*
441
+
442
+ # Enable only important logs (recommended for development)
443
+ DEBUG=lobe-editor:*:info,lobe-editor:*:warn,lobe-editor:*:error
444
+
445
+ # Enable specific components
446
+ DEBUG=lobe-editor:kernel,lobe-editor:plugin:*
447
+ ```
448
+
449
+ #### Available Debug Categories
450
+
451
+ | Category | Description | Example |
452
+ | ------------------ | ------------------------- | ------------------------------------ |
453
+ | `kernel` | Core editor functionality | `DEBUG=lobe-editor:kernel` |
454
+ | `plugin:*` | All plugins | `DEBUG=lobe-editor:plugin:*` |
455
+ | `plugin:slash` | Slash commands | `DEBUG=lobe-editor:plugin:slash` |
456
+ | `plugin:mention` | Mention system | `DEBUG=lobe-editor:plugin:mention` |
457
+ | `plugin:image` | Image handling | `DEBUG=lobe-editor:plugin:image` |
458
+ | `plugin:file` | File operations | `DEBUG=lobe-editor:plugin:file` |
459
+ | `service:*` | All services | `DEBUG=lobe-editor:service:*` |
460
+ | `service:upload` | Upload service | `DEBUG=lobe-editor:service:upload` |
461
+ | `service:markdown` | Markdown processing | `DEBUG=lobe-editor:service:markdown` |
462
+
463
+ #### Debug Levels
464
+
465
+ | Level | Browser Display | Usage | Environment Variable |
466
+ | ------- | --------------------- | ------------------- | --------------------------- |
467
+ | `debug` | Console.log (gray) | Detailed tracing | `DEBUG=lobe-editor:*:debug` |
468
+ | `info` | Console.log (blue) | General information | `DEBUG=lobe-editor:*:info` |
469
+ | `warn` | Console.warn (yellow) | Warnings | `DEBUG=lobe-editor:*:warn` |
470
+ | `error` | Console.error (red) | Errors | `DEBUG=lobe-editor:*:error` |
471
+
472
+ #### Development Usage
473
+
474
+ ````bash
475
+ # Full debug during development
476
+ DEBUG=lobe-editor:*
477
+
478
+ # Only critical logs
479
+ DEBUG=lobe-editor:*:error,lobe-editor:*:warn
480
+ # Plugin debugging
481
+ DEBUG=lobe-editor:plugin:*
482
+ # Service debugging
483
+ DEBUG=lobe-editor:service:*
484
+ ```
485
+
486
+
437
487
  ### Project Architecture
438
488
 
439
489
  ```
@@ -635,3 +685,4 @@ This project is [MIT](./LICENSE) licensed.
635
685
  [pr-welcome-link]: https://github.com/lobehub/lobe-editor/pulls
636
686
  [pr-welcome-shield]: https://img.shields.io/badge/%F0%9F%A4%AF%20PR%20WELCOME-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge
637
687
  [profile-link]: https://github.com/lobehub
688
+ ````
@@ -14,6 +14,7 @@ export declare class Kernel extends EventEmitter implements IEditorKernel {
14
14
  private serviceMap;
15
15
  private localeMap;
16
16
  private hotReloadMode;
17
+ private logger;
17
18
  private editor?;
18
19
  constructor();
19
20
  private detectDevelopmentMode;
@@ -1,8 +1,8 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
1
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
2
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
3
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5
4
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
6
6
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7
7
  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); }
8
8
  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; }
@@ -24,6 +24,7 @@ import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, createEdit
24
24
  import { get, merge, template, templateSettings } from 'lodash-es';
25
25
  import defaultLocale from "../locale";
26
26
  import { $isRootTextContentEmpty } from "../plugins/common/utils";
27
+ import { createDebugLogger } from "../utils/debug";
27
28
  import { registerEvent } from "./event";
28
29
  import { KernelPlugin } from "./plugin";
29
30
  import { createEmptyEditorState } from "./utils";
@@ -45,12 +46,14 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
45
46
  _defineProperty(_assertThisInitialized(_this), "serviceMap", new Map());
46
47
  _defineProperty(_assertThisInitialized(_this), "localeMap", defaultLocale);
47
48
  _defineProperty(_assertThisInitialized(_this), "hotReloadMode", false);
49
+ _defineProperty(_assertThisInitialized(_this), "logger", createDebugLogger('kernel'));
48
50
  _defineProperty(_assertThisInitialized(_this), "editor", void 0);
49
51
  _defineProperty(_assertThisInitialized(_this), "_commands", new Map());
50
52
  _defineProperty(_assertThisInitialized(_this), "_commandsClean", new Map());
51
53
  _this.dataTypeMap = new Map();
52
54
  // Enable hot reload mode in development
53
55
  _this.hotReloadMode = _this.detectDevelopmentMode();
56
+ _this.logger.info("\uD83D\uDE80 Kernel initialized (hot reload: ".concat(_this.hotReloadMode, ")"));
54
57
  return _this;
55
58
  }
56
59
  _createClass(Kernel, [{
@@ -109,6 +112,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
109
112
  key: "destroy",
110
113
  value: function destroy() {
111
114
  var _this$editor;
115
+ this.logger.info("\uD83D\uDDD1\uFE0F Destroying editor with ".concat(this.pluginsInstances.length, " plugins"));
112
116
  (_this$editor = this.editor) === null || _this$editor === void 0 || _this$editor.setEditorState(createEmptyEditorState());
113
117
  this.dataTypeMap.clear();
114
118
  this.pluginsInstances.forEach(function (plugin) {
@@ -121,7 +125,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
121
125
  this.serviceMap.clear();
122
126
  // Clear decorators to prevent memory leaks
123
127
  this.decorators = {};
124
- console.debug('[Editor] Cleared all decorators during destroy');
128
+ this.logger.info('Editor destroyed');
125
129
  }
126
130
  }, {
127
131
  key: "getRootElement",
@@ -135,13 +139,14 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
135
139
  var _this2 = this;
136
140
  // Check if editor is already initialized to prevent re-initialization
137
141
  if (this.editor) {
138
- console.warn('[Editor] Editor is already initialized, updating root element only');
142
+ this.logger.warn('[Editor] Editor is already initialized, updating root element only');
139
143
  this.editor.setRootElement(dom);
140
144
  return this.editor;
141
145
  }
142
146
 
143
147
  // Initialize plugins if not already done
144
148
  if (this.pluginsInstances.length === 0) {
149
+ this.logger.info("\uD83D\uDD0C Initializing ".concat(this.plugins.length, " plugins"));
145
150
  var _iterator = _createForOfIteratorHelper(this.plugins),
146
151
  _step;
147
152
  try {
@@ -156,12 +161,14 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
156
161
  _iterator.f();
157
162
  }
158
163
  }
164
+ this.logger.info("\uD83D\uDCDD Creating editor with ".concat(this.nodes.length, " nodes"));
159
165
  var editor = this.editor = createEditor({
160
166
  // @ts-expect-error Inject into lexical editor instance
161
167
  __kernel: this,
162
168
  namespace: 'lobehub',
163
169
  nodes: this.nodes,
164
170
  onError: function onError(error) {
171
+ _this2.logger.error('❌ Lexical editor error:', error);
165
172
  _this2.emit('error', error);
166
173
  },
167
174
  theme: this.themes
@@ -172,6 +179,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
172
179
  var _plugin$onInit;
173
180
  (_plugin$onInit = plugin.onInit) === null || _plugin$onInit === void 0 || _plugin$onInit.call(plugin, editor);
174
181
  });
182
+ this.logger.info("\u2705 Editor ready with ".concat(this.pluginsInstances.length, " plugins"));
175
183
  this.emit('initialized', editor);
176
184
  return this.editor;
177
185
  }
@@ -180,12 +188,15 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
180
188
  value: function setDocument(type, content) {
181
189
  var datasource = this.dataTypeMap.get(type);
182
190
  if (!datasource) {
191
+ this.logger.error("\u274C DataSource for type \"".concat(type, "\" not found"));
183
192
  throw new Error("DataSource for type \"".concat(type, "\" is not registered."));
184
193
  }
185
194
  if (!this.editor) {
195
+ this.logger.error('❌ Editor not initialized');
186
196
  throw new Error("Editor is not initialized.");
187
197
  }
188
198
  datasource.read(this.editor, content);
199
+ this.logger.debug("\uD83D\uDCE5 Set ".concat(type, " document"));
189
200
  }
190
201
  }, {
191
202
  key: "focus",
@@ -204,12 +215,15 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
204
215
  value: function getDocument(type) {
205
216
  var datasource = this.dataTypeMap.get(type);
206
217
  if (!datasource) {
218
+ this.logger.error("\u274C DataSource for type \"".concat(type, "\" not found"));
207
219
  throw new Error("DataSource for type \"".concat(type, "\" is not registered."));
208
220
  }
209
221
  if (!this.editor) {
222
+ this.logger.error('❌ Editor not initialized');
210
223
  throw new Error("Editor is not initialized.");
211
224
  }
212
- return datasource.write(this.editor);
225
+ var result = datasource.write(this.editor);
226
+ return result;
213
227
  }
214
228
  }, {
215
229
  key: "getSelectionDocument",
@@ -231,7 +245,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
231
245
  if (this.decorators[name]) {
232
246
  if (this.hotReloadMode) {
233
247
  // In hot reload mode, allow decorator override with warning
234
- console.warn("[Hot Reload] Overriding decorator \"".concat(name, "\""));
248
+ this.logger.warn("\uD83D\uDD04 Hot reload: decorator \"".concat(name, "\""));
235
249
  this.decorators[name] = decorator;
236
250
  return this;
237
251
  } else {
@@ -239,17 +253,17 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
239
253
  var existingDecorator = this.decorators[name];
240
254
  if (existingDecorator === decorator) {
241
255
  // Same decorator function, no need to re-register
242
- console.warn("[Editor] Decorator \"".concat(name, "\" is already registered with the same function"));
256
+ this.logger.warn("[Editor] Decorator \"".concat(name, "\" is already registered with the same function"));
243
257
  return this;
244
258
  }
245
259
 
246
260
  // Different decorator function in production mode
247
- console.error("[Editor] Attempting to register duplicate decorator \"".concat(name, "\". Enable hot reload mode if this is intended."));
261
+ this.logger.error("[Editor] Attempting to register duplicate decorator \"".concat(name, "\". Enable hot reload mode if this is intended."));
248
262
  throw new Error("Decorator with name \"".concat(name, "\" is already registered."));
249
263
  }
250
264
  }
251
265
  this.decorators[name] = decorator;
252
- console.debug("[Editor] Registered decorator: ".concat(name));
266
+ this.logger.debug("\uD83C\uDFAD Decorator: ".concat(name));
253
267
  return this;
254
268
  }
255
269
  }, {
@@ -267,10 +281,10 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
267
281
  value: function unregisterDecorator(name) {
268
282
  if (this.decorators[name]) {
269
283
  delete this.decorators[name];
270
- console.debug("[Editor] Unregistered decorator: ".concat(name));
284
+ this.logger.debug("\uD83D\uDDD1\uFE0F Removed decorator: ".concat(name));
271
285
  return true;
272
286
  }
273
- console.warn("[Editor] Decorator \"".concat(name, "\" not found for unregistration"));
287
+ this.logger.warn("\u26A0\uFE0F Decorator \"".concat(name, "\" not found"));
274
288
  return false;
275
289
  }
276
290
 
@@ -291,6 +305,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
291
305
  key: "registerDataSource",
292
306
  value: function registerDataSource(dataSource) {
293
307
  this.dataTypeMap.set(dataSource.type, dataSource);
308
+ this.logger.debug("\uD83D\uDCC4 Data source: ".concat(dataSource.type));
294
309
  }
295
310
  }, {
296
311
  key: "registerThemes",
@@ -307,7 +322,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
307
322
  // Error if same name but different plugin
308
323
  if (findPlugin !== plugin) {
309
324
  if (this.hotReloadMode) {
310
- console.warn("[Hot Reload] Replacing plugin \"".concat(plugin.pluginName, "\" with new implementation"));
325
+ this.logger.warn("\uD83D\uDD04 Hot reload: plugin \"".concat(plugin.pluginName, "\""));
311
326
  // Remove old plugin
312
327
  var index = this.plugins.findIndex(function (p) {
313
328
  return p.pluginName === plugin.pluginName;
@@ -329,7 +344,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
329
344
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
330
345
  var decoratorName = _step2.value;
331
346
  this.unregisterDecorator(decoratorName);
332
- console.debug("[Hot Reload] Cleaned up decorator \"".concat(decoratorName, "\" from old plugin instance"));
347
+ this.logger.debug("\uD83E\uDDE8 Cleanup: decorator \"".concat(decoratorName, "\""));
333
348
  }
334
349
  } catch (err) {
335
350
  _iterator2.e(err);
@@ -359,6 +374,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
359
374
  plugin.__config = config || {};
360
375
  // @ts-expect-error not error
361
376
  this.plugins.push(plugin);
377
+ this.logger.debug("\uD83D\uDD0C Plugin: ".concat(plugin.pluginName));
362
378
  return this;
363
379
  }
364
380
  }, {
@@ -380,13 +396,30 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
380
396
  } finally {
381
397
  _iterator3.f();
382
398
  }
399
+ this.logger.debug("\uD83D\uDD0C Registered ".concat(plugins.length, " plugins"));
383
400
  return this;
384
401
  }
385
402
  }, {
386
403
  key: "registerNodes",
387
404
  value: function registerNodes(nodes) {
388
405
  var _this$nodes;
406
+ var nodeTypes = nodes.map(function (node) {
407
+ // Handle both node classes and node replacements
408
+ if (typeof node === 'function' && node.getType) {
409
+ return node.getType();
410
+ } else if (_typeof(node) === 'object' && node.replace && typeof node.replace === 'function' && node.replace.getType) {
411
+ return node.replace.getType();
412
+ }
413
+ return 'unknown';
414
+ }).filter(function (type) {
415
+ return type !== 'unknown';
416
+ });
389
417
  (_this$nodes = this.nodes).push.apply(_this$nodes, _toConsumableArray(nodes));
418
+ if (nodeTypes.length > 3) {
419
+ this.logger.debug("\uD83E\uDDE9 Nodes: ".concat(nodeTypes.length, " types"));
420
+ } else {
421
+ this.logger.debug("\uD83E\uDDE9 Nodes: ".concat(nodeTypes.join(', ')));
422
+ }
390
423
  }
391
424
  }, {
392
425
  key: "registerService",
@@ -395,7 +428,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
395
428
  if (this.serviceMap.has(serviceIdString)) {
396
429
  if (this.hotReloadMode) {
397
430
  // In hot reload mode, allow service override with warning
398
- console.warn("[Hot Reload] Overriding service with ID \"".concat(serviceIdString, "\""));
431
+ this.logger.warn("\uD83D\uDD04 Hot reload: service \"".concat(serviceIdString, "\""));
399
432
  this.serviceMap.set(serviceIdString, service);
400
433
  return;
401
434
  } else {
@@ -403,17 +436,17 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
403
436
  var existingService = this.serviceMap.get(serviceIdString);
404
437
  if (existingService === service) {
405
438
  // Same service instance, no need to re-register
406
- console.warn("[Editor] Service \"".concat(serviceIdString, "\" is already registered with the same instance"));
439
+ this.logger.warn("[Editor] Service \"".concat(serviceIdString, "\" is already registered with the same instance"));
407
440
  return;
408
441
  }
409
442
 
410
443
  // Different service instance in production mode
411
- console.error("[Editor] Attempting to register duplicate service \"".concat(serviceIdString, "\". Enable hot reload mode if this is intended."));
444
+ this.logger.error("[Editor] Attempting to register duplicate service \"".concat(serviceIdString, "\". Enable hot reload mode if this is intended."));
412
445
  throw new Error("Service with ID \"".concat(serviceIdString, "\" is already registered."));
413
446
  }
414
447
  }
415
448
  this.serviceMap.set(serviceIdString, service);
416
- console.debug("[Editor] Registered service: ".concat(serviceIdString));
449
+ this.logger.debug("\uD83D\uDD27 Service: ".concat(serviceIdString));
417
450
  }
418
451
 
419
452
  /**
@@ -425,6 +458,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
425
458
  key: "registerServiceHotReload",
426
459
  value: function registerServiceHotReload(serviceId, service) {
427
460
  this.serviceMap.set(serviceId.__serviceId, service);
461
+ this.logger.debug("\uD83D\uDD04 Hot-reload service: ".concat(serviceId.__serviceId));
428
462
  }
429
463
 
430
464
  /**
@@ -480,7 +514,9 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
480
514
  }, {
481
515
  key: "registerLocale",
482
516
  value: function registerLocale(locale) {
517
+ var localeKeys = Object.keys(locale);
483
518
  this.localeMap = merge(this.localeMap, locale);
519
+ this.logger.debug("\uD83C\uDF10 Locale: ".concat(localeKeys.length, " keys"));
484
520
  }
485
521
  }, {
486
522
  key: "t",
@@ -532,6 +568,7 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
532
568
  }
533
569
  var commandsMap = this._commands;
534
570
  if (!commandsMap.has(command)) {
571
+ var _command$type;
535
572
  commandsMap.set(command, [new Set(), new Set(), new Set(), new Set(), new Set()]);
536
573
  this._commandsClean.set(command, lexicalEditor.registerCommand(command, function (payload) {
537
574
  for (var i = 4; i >= 0; i--) {
@@ -556,6 +593,10 @@ export var Kernel = /*#__PURE__*/function (_EventEmitter) {
556
593
  }
557
594
  return false;
558
595
  }, COMMAND_PRIORITY_CRITICAL));
596
+ // Only log non-keyboard commands to reduce noise
597
+ if (!((_command$type = command.type) !== null && _command$type !== void 0 && _command$type.includes('KEY'))) {
598
+ this.logger.debug("\u26A1 Command: ".concat(command.type || 'unknown'));
599
+ }
559
600
  }
560
601
  var listenersInPriorityOrder = commandsMap.get(command);
561
602
  if (listenersInPriorityOrder === undefined) {
@@ -25,16 +25,26 @@ export function useDecorators(editor, ErrorBoundary) {
25
25
  useLayoutEffectImpl(function () {
26
26
  var clears = [];
27
27
  var handleInit = function handleInit(editor) {
28
+ // Get initial decorators
29
+ var initialDecorators = editor.getDecorators();
30
+ setDecorators(initialDecorators);
28
31
  clears.push(editor.registerDecoratorListener(function (nextDecorators) {
29
32
  flushSync(function () {
30
33
  setDecorators(nextDecorators);
31
34
  });
32
35
  }));
33
36
  };
34
- editor.on('initialized', handleInit);
35
- clears.push(function () {
36
- editor.off('initialized', handleInit);
37
- });
37
+
38
+ // Check if editor is already initialized
39
+ var lexicalEditor = editor.getLexicalEditor();
40
+ if (lexicalEditor) {
41
+ handleInit(lexicalEditor);
42
+ } else {
43
+ editor.on('initialized', handleInit);
44
+ clears.push(function () {
45
+ editor.off('initialized', handleInit);
46
+ });
47
+ }
38
48
  return function () {
39
49
  clears.forEach(function (clear) {
40
50
  return clear();
package/es/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export * from './plugins/slash';
14
14
  export * from './plugins/table';
15
15
  export * from './plugins/upload';
16
16
  export type { IEditor } from './types';
17
+ export { browserDebug, createDebugLogger, debugLogger, debugLoggers, devConsole, prodSafeLogger, } from './utils/debug';
17
18
  export { Kernel } from './editor-kernel/kernel';
18
19
  /**
19
20
  * Enable hot reload mode globally for all editor instances
package/es/index.js CHANGED
@@ -13,6 +13,9 @@ export * from "./plugins/mention";
13
13
  export * from "./plugins/slash";
14
14
  export * from "./plugins/table";
15
15
  export * from "./plugins/upload";
16
+ // Debug utilities
17
+ export { browserDebug, createDebugLogger, debugLogger, debugLoggers, devConsole, prodSafeLogger } from "./utils/debug";
18
+
16
19
  // Hot reload utilities
17
20
  export { Kernel } from "./editor-kernel/kernel";
18
21
 
@@ -24,8 +27,10 @@ export function enableHotReload() {
24
27
  if (typeof window !== 'undefined') {
25
28
  var _require = require("./editor-kernel/kernel"),
26
29
  Kernel = _require.Kernel;
30
+ var _require2 = require("./utils/debug"),
31
+ debugLoggers = _require2.debugLoggers;
27
32
  Kernel.setGlobalHotReloadMode(true);
28
- console.log('[LobeHub Editor] Hot reload mode enabled globally');
33
+ debugLoggers.kernel.info('[LobeHub Editor] Hot reload mode enabled globally');
29
34
  }
30
35
  }
31
36
 
@@ -34,9 +39,11 @@ export function enableHotReload() {
34
39
  */
35
40
  export function disableHotReload() {
36
41
  if (typeof window !== 'undefined') {
37
- var _require2 = require("./editor-kernel/kernel"),
38
- Kernel = _require2.Kernel;
42
+ var _require3 = require("./editor-kernel/kernel"),
43
+ Kernel = _require3.Kernel;
44
+ var _require4 = require("./utils/debug"),
45
+ debugLoggers = _require4.debugLoggers;
39
46
  Kernel.setGlobalHotReloadMode(false);
40
- console.log('[LobeHub Editor] Hot reload mode disabled globally');
47
+ debugLoggers.kernel.info('[LobeHub Editor] Hot reload mode disabled globally');
41
48
  }
42
49
  }
@@ -20,6 +20,8 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
20
20
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
21
21
  import { mergeRegister } from '@lexical/utils';
22
22
  import { $createTextNode, $getNodeByKey, $getSelection, $isDecoratorNode, $isRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, DecoratorNode, ElementNode, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_BACKSPACE_COMMAND, TextNode } from 'lexical';
23
+ import { createDebugLogger } from "../../../utils/debug";
24
+ var logger = createDebugLogger('common', 'cursor');
23
25
  export var CardLikeElementNode = /*#__PURE__*/function (_ElementNode) {
24
26
  _inherits(CardLikeElementNode, _ElementNode);
25
27
  var _super = _createSuper(CardLikeElementNode);
@@ -87,7 +89,7 @@ export function registerCursorNode(editor) {
87
89
  key = _step2$value[0],
88
90
  mutation = _step2$value[1];
89
91
  var node = $getNodeByKey(key);
90
- console.info('DecoratorNode mutated', node, mutation);
92
+ logger.debug('🎭 DecoratorNode mutated:', node === null || node === void 0 ? void 0 : node.getType(), mutation, node);
91
93
  if (mutation === 'created' && node !== null && node !== void 0 && node.isInline() && node.getNextSibling() === null) {
92
94
  needAddCursor.push(node);
93
95
  }
@@ -237,7 +239,7 @@ export function registerCursorNode(editor) {
237
239
  $setSelection(sel);
238
240
  return true;
239
241
  } catch (error) {
240
- console.error(error);
242
+ logger.error('❌ Cursor selection error:', error);
241
243
  }
242
244
  } else if ($isCursorNode(focusNode)) {
243
245
  try {
@@ -255,7 +257,7 @@ export function registerCursorNode(editor) {
255
257
  $setSelection(_sel);
256
258
  return true;
257
259
  } catch (error) {
258
- console.error(error);
260
+ logger.error('❌ Cursor navigation error:', error);
259
261
  }
260
262
  }
261
263
  return false;
@@ -1,6 +1,8 @@
1
1
  import { $wrapNodeInElement } from '@lexical/utils';
2
2
  import { $createParagraphNode, $insertNodes, $isRootOrShadowRoot, COMMAND_PRIORITY_HIGH, createCommand } from 'lexical';
3
+ import { createDebugLogger } from "../../../utils/debug";
3
4
  import { $createFileNode } from "../node/FileNode";
5
+ var logger = createDebugLogger('plugin', 'file');
4
6
  export var INSERT_FILE_COMMAND = createCommand('INSERT_FILE_COMMAND');
5
7
  export function registerFileCommand(editor, handleUpload) {
6
8
  return editor.registerCommand(INSERT_FILE_COMMAND, function (payload) {
@@ -16,7 +18,7 @@ export function registerFileCommand(editor, handleUpload) {
16
18
  fileNode.setUploaded(url.url);
17
19
  });
18
20
  }).catch(function (error) {
19
- console.error('File upload failed:', error);
21
+ logger.error('File upload failed:', error);
20
22
  editor.update(function () {
21
23
  fileNode.setError('File upload failed : ' + error.message);
22
24
  });
@@ -21,6 +21,7 @@ import { $createParagraphNode, $createRangeSelection, $insertNodes, $isRootOrSha
21
21
  import { KernelPlugin } from "../../../editor-kernel/plugin";
22
22
  import { IMarkdownShortCutService } from "../../markdown";
23
23
  import { IUploadService } from "../../upload";
24
+ import { createDebugLogger } from "../../../utils/debug";
24
25
  import { registerFileCommand } from "../command";
25
26
  import { $createFileNode, $isFileNode, FileNode } from "../node/FileNode";
26
27
  import { registerFileNodeSelectionObserver } from "../utils";
@@ -36,6 +37,7 @@ export var FilePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
36
37
  _classCallCheck(this, FilePlugin);
37
38
  _this = _super.call(this);
38
39
  // Register the file node
40
+ _defineProperty(_assertThisInitialized(_this), "logger", createDebugLogger('plugin', 'file'));
39
41
  _this.kernel = kernel;
40
42
  _this.config = config;
41
43
  kernel.registerNodes([FileNode]);
@@ -91,7 +93,7 @@ export var FilePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
91
93
  fileNode.setUploaded(url.url);
92
94
  });
93
95
  }).catch(function (error) {
94
- console.error('File upload failed:', error);
96
+ _this2.logger.error('File upload failed:', error);
95
97
  editor.update(function () {
96
98
  fileNode.setError('File upload failed : ' + error.message);
97
99
  });
@@ -1,6 +1,8 @@
1
1
  import { $wrapNodeInElement } from '@lexical/utils';
2
2
  import { $createParagraphNode, $createRangeSelection, $insertNodes, $isRootOrShadowRoot, $setSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical';
3
+ import { createDebugLogger } from "../../../utils/debug";
3
4
  import { $createImageNode } from "../node/image-node";
5
+ var logger = createDebugLogger('plugin', 'image');
4
6
  export var INSERT_IMAGE_COMMAND = createCommand('INSERT_IMAGE_COMMAND');
5
7
  function isImageFile(file) {
6
8
  return file.type.startsWith('image/');
@@ -34,7 +36,7 @@ export function registerImageCommand(editor, handleUpload) {
34
36
  imageNode.setUploaded(res.url);
35
37
  });
36
38
  }).catch(function (error) {
37
- console.error('Image upload failed:', error);
39
+ logger.error('Image upload failed:', error);
38
40
  editor.update(function () {
39
41
  imageNode.setError('Image upload failed : ' + error.message);
40
42
  });
@@ -71,4 +71,4 @@ export var ImagePlugin = (_class = /*#__PURE__*/function (_KernelPlugin) {
71
71
  }
72
72
  }]);
73
73
  return ImagePlugin;
74
- }(KernelPlugin), _defineProperty(_class, "pluginName", 'image'), _class);
74
+ }(KernelPlugin), _defineProperty(_class, "pluginName", 'ImagePlugin'), _class);
@@ -90,6 +90,7 @@ export declare class MarkdownShortCutService implements IMarkdownShortCutService
90
90
  private elementTransformers;
91
91
  private textFormatTransformers;
92
92
  private textMatchTransformers;
93
+ private logger;
93
94
  private _markdownWriters;
94
95
  constructor(kernel?: import("../../../types/kernel").IEditorKernel | undefined);
95
96
  get markdownWriters(): Record<string, (ctx: IMarkdownWriterContext, node: LexicalNode) => boolean | void>;