Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ module.exports = {
varsIgnorePattern: '^_',
},
],
'header/header': [2, 'scripts/www/headerTemplate.js'],
// 暂时关闭版权头声明
'header/header': [OFF, 'scripts/www/headerTemplate.js'],
},
},
{
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
plugins: [
[
require('./scripts/error-codes/transform-error-messages'),
// 禁用错误信息的压缩/简化处理
{noMinify: true},
],
],
Expand Down
1 change: 1 addition & 0 deletions packages/lexical-plain-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ export function registerPlainText(editor: LexicalEditor): () => void {
const selection = $getSelection();

if (!$isRangeSelection(selection)) {
// 使用浏览器默认粘贴行为
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-playground/src/appSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions packages/lexical-playground/src/utils/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import debug from 'debug';

export const DebugLog = debug('Debug');
12 changes: 12 additions & 0 deletions packages/lexical-react/src/shared/useDecorators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export function useDecorators(
// Subscribe to changes
useLayoutEffect(() => {
return editor.registerDecoratorListener<JSX.Element>((nextDecorators) => {
// 确保状态同步更新
// 确保在下次绘制前状态已更新
flushSync(() => {
setDecorators(nextDecorators);
});
Expand All @@ -54,14 +56,24 @@ export function useDecorators(

for (let i = 0; i < decoratorKeys.length; i++) {
const nodeKey = decoratorKeys[i];
// 渲染元素,来自 DecoratorNode.decorate
// 支持异步组件加载、错误处理
const reactDecorator = (
<ErrorBoundary onError={(e) => editor._onError(e)}>
<Suspense fallback={null}>{decorators[nodeKey]}</Suspense>
</ErrorBoundary>
);
// 占位符元素,来自 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));
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/lexical/src/LexicalEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 4 additions & 0 deletions packages/lexical/src/LexicalUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,7 @@ function $processNestedUpdates(
if (options.skipTransforms) {
skipTransforms = true;
}
// 检测到 discrete 配置,强制设置为同步执行
if (options.discrete) {
invariant(
pendingEditorState !== null,
Expand Down Expand Up @@ -922,6 +923,7 @@ function $beginUpdate(
);
editorStateWasCloned = true;
}
// 关键:将 discrete 配置设置到 pendingEditorState._flushSync 中
pendingEditorState._flushSync = discrete;

const previousActiveEditorState = activeEditorState;
Expand Down Expand Up @@ -1032,9 +1034,11 @@ function $beginUpdate(

if (shouldUpdate) {
if (pendingEditorState._flushSync) {
// 同步执行:直接调用 $commitPendingUpdates
pendingEditorState._flushSync = false;
$commitPendingUpdates(editor);
} else if (editorStateWasCloned) {
// 异步执行:使用 scheduleMicroTask 延迟执行
scheduleMicroTask(() => {
$commitPendingUpdates(editor);
});
Expand Down
1 change: 1 addition & 0 deletions packages/lexical/src/LexicalUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export function toggleTextFormatType(
) {
return format;
}
// 位运算 异或 实现 toggle
let newFormat = format ^ activeFormat;
if (type === 'subscript') {
newFormat &= ~TEXT_TYPE_TO_FORMAT.superscript;
Expand Down
5 changes: 3 additions & 2 deletions packages/lexical/src/nodes/LexicalTextNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 9 additions & 2 deletions scripts/error-codes/transform-error-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down