diff --git a/.eslintrc.js b/.eslintrc.js index 24949684e5d..d2cd440c7f2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -97,7 +97,8 @@ module.exports = { varsIgnorePattern: '^_', }, ], - 'header/header': [2, 'scripts/www/headerTemplate.js'], + // 暂时关闭版权头声明 + 'header/header': [OFF, 'scripts/www/headerTemplate.js'], }, }, { @@ -195,8 +196,8 @@ module.exports = { 'ft-flow/object-type-delimiter': OFF, 'ft-flow/sort-keys': ERROR, - - 'header/header': [2, 'scripts/www/headerTemplate.js'], + // 暂时关闭版权头声明 + 'header/header': [OFF, 'scripts/www/headerTemplate.js'], // (This helps configure simple-import-sort) Make sure all imports are at the top of the file 'import/first': ERROR, diff --git a/babel.config.js b/babel.config.js index 7ef7f39d372..fb31b18df53 100644 --- a/babel.config.js +++ b/babel.config.js @@ -12,6 +12,7 @@ module.exports = { plugins: [ [ require('./scripts/error-codes/transform-error-messages'), + // 禁用错误信息的压缩/简化处理 {noMinify: true}, ], ], diff --git a/packages/lexical-plain-text/src/index.ts b/packages/lexical-plain-text/src/index.ts index bd9326c6c67..acfa1696e1b 100644 --- a/packages/lexical-plain-text/src/index.ts +++ b/packages/lexical-plain-text/src/index.ts @@ -378,6 +378,7 @@ export function registerPlainText(editor: LexicalEditor): () => void { const selection = $getSelection(); if (!$isRangeSelection(selection)) { + // 使用浏览器默认粘贴行为 return false; } diff --git a/packages/lexical-playground/src/appSettings.ts b/packages/lexical-playground/src/appSettings.ts index 5953edb240d..012d08b4e7f 100644 --- a/packages/lexical-playground/src/appSettings.ts +++ b/packages/lexical-playground/src/appSettings.ts @@ -13,7 +13,8 @@ export const isDevPlayground: boolean = export const DEFAULT_SETTINGS = { disableBeforeInput: false, - emptyEditor: isDevPlayground, + // emptyEditor: isDevPlayground, + emptyEditor: false, hasLinkAttributes: false, isAutocomplete: false, isCharLimit: false, diff --git a/packages/lexical-playground/src/utils/debug.ts b/packages/lexical-playground/src/utils/debug.ts new file mode 100644 index 00000000000..b9d7dfa77d9 --- /dev/null +++ b/packages/lexical-playground/src/utils/debug.ts @@ -0,0 +1,3 @@ +import debug from 'debug'; + +export const DebugLog = debug('Debug'); diff --git a/packages/lexical-react/src/shared/useDecorators.tsx b/packages/lexical-react/src/shared/useDecorators.tsx index aefda99d520..c33fdc45e05 100644 --- a/packages/lexical-react/src/shared/useDecorators.tsx +++ b/packages/lexical-react/src/shared/useDecorators.tsx @@ -34,6 +34,8 @@ export function useDecorators( // Subscribe to changes useLayoutEffect(() => { return editor.registerDecoratorListener((nextDecorators) => { + // 确保状态同步更新 + // 确保在下次绘制前状态已更新 flushSync(() => { setDecorators(nextDecorators); }); @@ -54,14 +56,24 @@ export function useDecorators( for (let i = 0; i < decoratorKeys.length; i++) { const nodeKey = decoratorKeys[i]; + // 渲染元素,来自 DecoratorNode.decorate + // 支持异步组件加载、错误处理 const reactDecorator = ( editor._onError(e)}> {decorators[nodeKey]} ); + // 占位符元素,来自 DecoratorNode.createDOM const element = editor.getElementByKey(nodeKey); if (element !== null) { + // 将渲染元素渲染到占位符元素中,连接 React 组件系统与 Lexical DOM 系统 + // 使用 createPortal 的好处: + // 1. 架构分离:React 组件与 Lexical DOM 解耦 + // 2. 功能完整:保持 React 生态(Hooks、Context、错误边界等) + // 3. 性能优化:渲染隔离,避免不必要的更新 + // 4. 开发体验:使用熟悉的 React 模式,易于调试 + // 5. 扩展性:支持复杂 UI 组件,易于添加新装饰器 decoratedPortals.push(createPortal(reactDecorator, element, nodeKey)); } } diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts index 5857801e6a3..681379218ce 100644 --- a/packages/lexical/src/LexicalEditor.ts +++ b/packages/lexical/src/LexicalEditor.ts @@ -1312,6 +1312,7 @@ export class LexicalEditor { * @param options - A bag of options to control the behavior of the update. */ update(updateFn: () => void, options?: EditorUpdateOptions): void { + // 当 options.discrete 为 true 时,强制设置为同步执行,否则放入微任务队列异步执行 updateEditor(this, updateFn, options); } diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts index f216e1caed0..8e37cfbeb21 100644 --- a/packages/lexical/src/LexicalUpdates.ts +++ b/packages/lexical/src/LexicalUpdates.ts @@ -864,6 +864,7 @@ function $processNestedUpdates( if (options.skipTransforms) { skipTransforms = true; } + // 检测到 discrete 配置,强制设置为同步执行 if (options.discrete) { invariant( pendingEditorState !== null, @@ -922,6 +923,7 @@ function $beginUpdate( ); editorStateWasCloned = true; } + // 关键:将 discrete 配置设置到 pendingEditorState._flushSync 中 pendingEditorState._flushSync = discrete; const previousActiveEditorState = activeEditorState; @@ -1032,9 +1034,11 @@ function $beginUpdate( if (shouldUpdate) { if (pendingEditorState._flushSync) { + // 同步执行:直接调用 $commitPendingUpdates pendingEditorState._flushSync = false; $commitPendingUpdates(editor); } else if (editorStateWasCloned) { + // 异步执行:使用 scheduleMicroTask 延迟执行 scheduleMicroTask(() => { $commitPendingUpdates(editor); }); diff --git a/packages/lexical/src/LexicalUtils.ts b/packages/lexical/src/LexicalUtils.ts index d5da4722289..d90232f78c3 100644 --- a/packages/lexical/src/LexicalUtils.ts +++ b/packages/lexical/src/LexicalUtils.ts @@ -275,6 +275,7 @@ export function toggleTextFormatType( ) { return format; } + // 位运算 异或 实现 toggle let newFormat = format ^ activeFormat; if (type === 'subscript') { newFormat &= ~TEXT_TYPE_TO_FORMAT.superscript; diff --git a/packages/lexical/src/nodes/LexicalTextNode.ts b/packages/lexical/src/nodes/LexicalTextNode.ts index d917bf21c30..68d8f3de60d 100644 --- a/packages/lexical/src/nodes/LexicalTextNode.ts +++ b/packages/lexical/src/nodes/LexicalTextNode.ts @@ -924,7 +924,7 @@ export class TextNode extends LexicalNode { * This method is meant to be overridden by TextNode subclasses to control the behavior of those nodes * when a user event would cause text to be inserted before them in the editor. If true, Lexical will attempt * to insert text into this node. If false, it will insert the text in a new sibling node. - * + * * 不将新文本插入到当前节点中,保持节点独立性 * @returns true if text can be inserted before the node, false otherwise. */ canInsertTextBefore(): boolean { @@ -1167,7 +1167,8 @@ export class TextNode extends LexicalNode { * This method is meant to be overridden by TextNode subclasses to control the behavior of those nodes * when used with the registerLexicalTextEntity function. If you're using registerLexicalTextEntity, the * node class that you create and replace matched text with should return true from this method. - * + * * 返回 true 时表示这个 node 是一个整体 + * TODO yu 搞清楚 isTextEntity & registerLexicalTextEntity 的关系 * @returns true if the node is to be treated as a "text entity", false otherwise. */ isTextEntity(): boolean { diff --git a/scripts/error-codes/transform-error-messages.js b/scripts/error-codes/transform-error-messages.js index 164da0e47d1..207e7f430af 100644 --- a/scripts/error-codes/transform-error-messages.js +++ b/scripts/error-codes/transform-error-messages.js @@ -6,12 +6,19 @@ * */ +/** + * Babel 插件:转换 invariant() 错误消息 + * 功能: + * 1. 开发环境 - 保留完整错误信息(包含上下文和参数) + * 2. 生产环境 - 替换为简化的错误代码(通过 codes.json 映射) + */ + 'use strict'; // @ts-check const fs = require('fs-extra'); -const ErrorMap = require('./ErrorMap'); -const evalToString = require('./evalToString'); +const ErrorMap = require('./ErrorMap'); // 错误代码映射表管理 +const evalToString = require('./evalToString'); // 计算错误消息字符串 const helperModuleImports = require('@babel/helper-module-imports'); const prettier = require('@prettier/sync');