mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
fix(editor): use nullable inline editor root element (#9320)
Fixes `sentry-7906c03b79a54ede819c56cc15ad9889`
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { assertExists, DisposableGroup, Slot } from '@blocksuite/global/utils';
|
||||
import { DisposableGroup, Slot } from '@blocksuite/global/utils';
|
||||
import { type Signal, signal } from '@preact/signals-core';
|
||||
import { nothing, render, type TemplateResult } from 'lit';
|
||||
import type * as Y from 'yjs';
|
||||
@@ -136,7 +136,6 @@ export class InlineEditor<
|
||||
|
||||
private _rootElement: InlineRootElement<TextAttributes> | null = null;
|
||||
get rootElement() {
|
||||
assertExists(this._rootElement);
|
||||
return this._rootElement;
|
||||
}
|
||||
|
||||
@@ -244,7 +243,7 @@ export class InlineEditor<
|
||||
this._rootElement.dataset.vRoot = 'true';
|
||||
this.setReadonly(isReadonly);
|
||||
|
||||
this.rootElement.replaceChildren();
|
||||
this._rootElement.replaceChildren();
|
||||
|
||||
delete (this.rootElement as any)['_$litPart$'];
|
||||
|
||||
@@ -259,10 +258,12 @@ export class InlineEditor<
|
||||
}
|
||||
|
||||
unmount() {
|
||||
if (this.rootElement.isConnected) {
|
||||
render(nothing, this.rootElement);
|
||||
if (this.rootElement) {
|
||||
if (this.rootElement.isConnected) {
|
||||
render(nothing, this.rootElement);
|
||||
}
|
||||
this.rootElement.removeAttribute(INLINE_ROOT_ATTR);
|
||||
}
|
||||
this.rootElement.removeAttribute(INLINE_ROOT_ATTR);
|
||||
this._rootElement = null;
|
||||
this._mounted = false;
|
||||
this.disposables.dispose();
|
||||
@@ -272,7 +273,7 @@ export class InlineEditor<
|
||||
setReadonly(isReadonly: boolean): void {
|
||||
const value = isReadonly ? 'false' : 'true';
|
||||
|
||||
if (this.rootElement.contentEditable !== value) {
|
||||
if (this.rootElement && this.rootElement.contentEditable !== value) {
|
||||
this.rootElement.contentEditable = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
if (range.commonAncestorContainer.ownerDocument !== document) return false;
|
||||
|
||||
const rootElement = this.editor.rootElement;
|
||||
if (!rootElement) return false;
|
||||
|
||||
const rootRange = document.createRange();
|
||||
rootRange.selectNode(rootElement);
|
||||
|
||||
@@ -140,7 +142,9 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
|
||||
private readonly _onCompositionEnd = async (event: CompositionEvent) => {
|
||||
this._isComposing = false;
|
||||
if (!this.editor.rootElement.isConnected) return;
|
||||
if (!this.editor.rootElement || !this.editor.rootElement.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = this.editor.rangeService.getNativeRange();
|
||||
if (
|
||||
@@ -181,6 +185,7 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
|
||||
private readonly _onCompositionStart = () => {
|
||||
this._isComposing = true;
|
||||
if (!this.editor.rootElement) return;
|
||||
// embeds is not editable and it will break IME
|
||||
const embeds = this.editor.rootElement.querySelectorAll(
|
||||
'[data-v-embed="true"]'
|
||||
@@ -198,7 +203,9 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
};
|
||||
|
||||
private readonly _onCompositionUpdate = () => {
|
||||
if (!this.editor.rootElement.isConnected) return;
|
||||
if (!this.editor.rootElement || !this.editor.rootElement.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = this.editor.rangeService.getNativeRange();
|
||||
if (
|
||||
@@ -272,6 +279,8 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
|
||||
private readonly _onSelectionChange = () => {
|
||||
const rootElement = this.editor.rootElement;
|
||||
if (!rootElement) return;
|
||||
|
||||
const previousInlineRange = this.editor.getInlineRange();
|
||||
if (this._isComposing) {
|
||||
return;
|
||||
@@ -361,7 +370,9 @@ export class EventService<TextAttributes extends BaseTextAttributes> {
|
||||
'keydown',
|
||||
this._onKeyDown
|
||||
);
|
||||
this.editor.disposables.addFromEvent(rootElement, 'click', this._onClick);
|
||||
if (rootElement) {
|
||||
this.editor.disposables.addFromEvent(rootElement, 'click', this._onClick);
|
||||
}
|
||||
};
|
||||
|
||||
get isComposing() {
|
||||
|
||||
@@ -63,6 +63,8 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
|
||||
rangeIndexRelatedToLine: number;
|
||||
} | null => {
|
||||
const rootElement = this.editor.rootElement;
|
||||
if (!rootElement) return null;
|
||||
|
||||
const lineElements = Array.from(rootElement.querySelectorAll('v-line'));
|
||||
|
||||
let beforeIndex = 0;
|
||||
@@ -100,6 +102,8 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
|
||||
|
||||
getTextPoint = (rangeIndex: InlineRange['index']): TextPoint | null => {
|
||||
const rootElement = this.editor.rootElement;
|
||||
if (!rootElement) return null;
|
||||
|
||||
const vLines = Array.from(rootElement.querySelectorAll('v-line'));
|
||||
|
||||
let index = 0;
|
||||
@@ -280,6 +284,7 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
|
||||
const handler = () => {
|
||||
const selection = document.getSelection();
|
||||
if (!selection) return;
|
||||
if (!this.editor.rootElement) return;
|
||||
|
||||
if (inlineRange === null) {
|
||||
if (selection.rangeCount > 0) {
|
||||
@@ -321,6 +326,7 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
|
||||
*/
|
||||
toDomRange = (inlineRange: InlineRange): Range | null => {
|
||||
const rootElement = this.editor.rootElement;
|
||||
if (!rootElement) return null;
|
||||
return inlineRangeToDomRange(rootElement, inlineRange);
|
||||
};
|
||||
|
||||
@@ -358,7 +364,7 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
|
||||
*/
|
||||
toInlineRange = (range: Range): InlineRange | null => {
|
||||
const { rootElement, yText } = this.editor;
|
||||
|
||||
if (!rootElement || !yText) return null;
|
||||
return domRangeToInlineRange(range, rootElement, yText);
|
||||
};
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export class RenderService<TextAttributes extends BaseTextAttributes> {
|
||||
}
|
||||
// render current deltas to VLines
|
||||
render = () => {
|
||||
if (!this.editor.mounted) return;
|
||||
if (!this.editor.rootElement) return;
|
||||
|
||||
this._rendering = true;
|
||||
|
||||
@@ -160,7 +160,7 @@ export class RenderService<TextAttributes extends BaseTextAttributes> {
|
||||
rerenderWholeEditor = () => {
|
||||
const rootElement = this.editor.rootElement;
|
||||
|
||||
if (!rootElement.isConnected) return;
|
||||
if (!rootElement || !rootElement.isConnected) return;
|
||||
|
||||
rootElement.replaceChildren();
|
||||
// Because we bypassed Lit and disrupted the DOM structure, this will cause an inconsistency in the original state of `ChildPart`.
|
||||
@@ -172,6 +172,7 @@ export class RenderService<TextAttributes extends BaseTextAttributes> {
|
||||
};
|
||||
|
||||
waitForUpdate = async () => {
|
||||
if (!this.editor.rootElement) return;
|
||||
const vLines = Array.from(
|
||||
this.editor.rootElement.querySelectorAll('v-line')
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user