mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
fix(editor): ime input error at empty line (#11636)
Close [BS-3106](https://linear.app/affine-design/issue/BS-3106/mac-chrom在空行使用ime输入,文档卡住)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
@@ -111,7 +111,7 @@ export class AffineCodeUnit extends ShadowlessElement {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
INLINE_ROOT_ATTR,
|
INLINE_ROOT_ATTR,
|
||||||
type InlineRootElement,
|
type InlineRootElement,
|
||||||
ZERO_WIDTH_NON_JOINER,
|
ZERO_WIDTH_FOR_EMBED_NODE,
|
||||||
ZERO_WIDTH_SPACE,
|
ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
} from '@blocksuite/std/inline';
|
} from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { shift } from '@floating-ui/dom';
|
import { shift } from '@floating-ui/dom';
|
||||||
@@ -186,7 +186,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
|||||||
return html`<span
|
return html`<span
|
||||||
${this.hidePopup ? '' : ref(this._whenHover.setReference)}
|
${this.hidePopup ? '' : ref(this._whenHover.setReference)}
|
||||||
class=${nodeClasses}
|
class=${nodeClasses}
|
||||||
>${node}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
>${node}<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
@@ -50,6 +50,6 @@ export class LatexEditorUnit extends ShadowlessElement {
|
|||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import {
|
|||||||
} from '@blocksuite/std';
|
} from '@blocksuite/std';
|
||||||
import {
|
import {
|
||||||
type InlineEditor,
|
type InlineEditor,
|
||||||
ZERO_WIDTH_NON_JOINER,
|
ZERO_WIDTH_FOR_EMBED_NODE,
|
||||||
ZERO_WIDTH_SPACE,
|
ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
} from '@blocksuite/std/inline';
|
} from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { signal } from '@preact/signals-core';
|
import { signal } from '@preact/signals-core';
|
||||||
@@ -178,7 +178,7 @@ export class AffineLatexNode extends SignalWatcher(
|
|||||||
override render() {
|
override render() {
|
||||||
return html`<span class="affine-latex" data-selected=${this.selected}
|
return html`<span class="affine-latex" data-selected=${this.selected}
|
||||||
><div class="latex-container"></div>
|
><div class="latex-container"></div>
|
||||||
<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ export class AffineLatexNode extends SignalWatcher(
|
|||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std';
|
|||||||
import {
|
import {
|
||||||
INLINE_ROOT_ATTR,
|
INLINE_ROOT_ATTR,
|
||||||
type InlineRootElement,
|
type InlineRootElement,
|
||||||
ZERO_WIDTH_SPACE,
|
ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
} from '@blocksuite/std/inline';
|
} from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { css, html } from 'lit';
|
import { css, html } from 'lit';
|
||||||
@@ -177,7 +177,7 @@ export class AffineLink extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
|||||||
import type { BlockStdScope } from '@blocksuite/std';
|
import type { BlockStdScope } from '@blocksuite/std';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
import {
|
import {
|
||||||
ZERO_WIDTH_NON_JOINER,
|
ZERO_WIDTH_FOR_EMBED_NODE,
|
||||||
ZERO_WIDTH_SPACE,
|
ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
} from '@blocksuite/std/inline';
|
} from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { css, html } from 'lit';
|
import { css, html } from 'lit';
|
||||||
@@ -88,7 +88,7 @@ export class AffineMention extends SignalWatcher(
|
|||||||
data-selected=${this.selected}
|
data-selected=${this.selected}
|
||||||
data-type="error"
|
data-type="error"
|
||||||
class="affine-mention"
|
class="affine-mention"
|
||||||
>@Unknown Member<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
>@Unknown Member<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
|
|
||||||
const userService = this.std.getOptional(UserProvider);
|
const userService = this.std.getOptional(UserProvider);
|
||||||
@@ -107,7 +107,7 @@ export class AffineMention extends SignalWatcher(
|
|||||||
data-selected=${this.selected}
|
data-selected=${this.selected}
|
||||||
data-type="removed"
|
data-type="removed"
|
||||||
class="affine-mention"
|
class="affine-mention"
|
||||||
>@Inactive Member<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
>@Inactive Member<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
} else {
|
} else {
|
||||||
return html`<span
|
return html`<span
|
||||||
@@ -115,7 +115,7 @@ export class AffineMention extends SignalWatcher(
|
|||||||
data-type="default"
|
data-type="default"
|
||||||
class="affine-mention"
|
class="affine-mention"
|
||||||
>@${userInfo$.value.name ?? 'Unknown'}<v-text
|
>@${userInfo$.value.name ?? 'Unknown'}<v-text
|
||||||
.str=${ZERO_WIDTH_NON_JOINER}
|
.str=${ZERO_WIDTH_FOR_EMBED_NODE}
|
||||||
></v-text
|
></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ export class AffineMention extends SignalWatcher(
|
|||||||
>@loading<span class="dots"
|
>@loading<span class="dots"
|
||||||
><span class="dot">.</span><span class="dot">.</span
|
><span class="dot">.</span><span class="dot">.</span
|
||||||
><span class="dot">.</span></span
|
><span class="dot">.</span></span
|
||||||
><v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
><v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ export class AffineMention extends SignalWatcher(
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import { ShadowlessElement } from '@blocksuite/std';
|
import { ShadowlessElement } from '@blocksuite/std';
|
||||||
import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert } from '@blocksuite/store';
|
import type { DeltaInsert } from '@blocksuite/store';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
@@ -30,6 +30,6 @@ export class AffineText extends ShadowlessElement {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std';
|
|||||||
import {
|
import {
|
||||||
INLINE_ROOT_ATTR,
|
INLINE_ROOT_ATTR,
|
||||||
type InlineRootElement,
|
type InlineRootElement,
|
||||||
ZERO_WIDTH_NON_JOINER,
|
ZERO_WIDTH_FOR_EMBED_NODE,
|
||||||
ZERO_WIDTH_SPACE,
|
ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
} from '@blocksuite/std/inline';
|
} from '@blocksuite/std/inline';
|
||||||
import type { DeltaInsert, DocMeta, Store } from '@blocksuite/store';
|
import type { DeltaInsert, DocMeta, Store } from '@blocksuite/store';
|
||||||
import { css, html, nothing } from 'lit';
|
import { css, html, nothing } from 'lit';
|
||||||
@@ -274,14 +274,14 @@ export class AffineReference extends WithDisposable(ShadowlessElement) {
|
|||||||
>${title}</span
|
>${title}</span
|
||||||
>`;
|
>`;
|
||||||
|
|
||||||
// we need to add `<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text>` in an
|
// we need to add `<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text>` in an
|
||||||
// embed element to make sure inline range calculation is correct
|
// embed element to make sure inline range calculation is correct
|
||||||
return html`<span
|
return html`<span
|
||||||
data-selected=${this.selected}
|
data-selected=${this.selected}
|
||||||
class="affine-reference"
|
class="affine-reference"
|
||||||
style=${styleMap(style)}
|
style=${styleMap(style)}
|
||||||
@click=${(event: MouseEvent) => this.open({ event })}
|
@click=${(event: MouseEvent) => this.open({ event })}
|
||||||
>${content}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
>${content}<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ export class AffineReference extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
accessor delta: DeltaInsert<AffineTextAttributes> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { html, LitElement } from 'lit';
|
|||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
import { ZERO_WIDTH_SPACE } from '../consts.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
|
||||||
import type { InlineEditor } from '../inline-editor.js';
|
import type { InlineEditor } from '../inline-editor.js';
|
||||||
import { isInlineRangeIntersect } from '../utils/inline-range.js';
|
import { isInlineRangeIntersect } from '../utils/inline-range.js';
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ export class VElement<
|
|||||||
|
|
||||||
@property({ type: Object })
|
@property({ type: Object })
|
||||||
accessor delta: DeltaInsert<T> = {
|
accessor delta: DeltaInsert<T> = {
|
||||||
insert: ZERO_WIDTH_SPACE,
|
insert: ZERO_WIDTH_FOR_EMPTY_LINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { html, LitElement, type TemplateResult } from 'lit';
|
|||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js';
|
import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
|
||||||
import type { InlineRootElement } from '../inline-editor.js';
|
import type { InlineRootElement } from '../inline-editor.js';
|
||||||
import { EmbedGap } from './embed-gap.js';
|
import { EmbedGap } from './embed-gap.js';
|
||||||
|
|
||||||
@@ -89,7 +89,9 @@ export class VLine extends LitElement {
|
|||||||
renderVElements() {
|
renderVElements() {
|
||||||
if (this.elements.length === 0) {
|
if (this.elements.length === 0) {
|
||||||
// don't use v-element because it not correspond to the actual delta
|
// don't use v-element because it not correspond to the actual delta
|
||||||
return html`<div><v-text .str=${ZERO_WIDTH_SPACE}></v-text></div>`;
|
return html`
|
||||||
|
<div><v-text .str=${ZERO_WIDTH_FOR_EMPTY_LINE}></v-text></div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const inlineEditor = this.inlineEditor;
|
const inlineEditor = this.inlineEditor;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { html, LitElement } from 'lit';
|
|||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { styleMap } from 'lit/directives/style-map.js';
|
import { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
|
||||||
import { ZERO_WIDTH_SPACE } from '../consts.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
|
||||||
|
|
||||||
export class VText extends LitElement {
|
export class VText extends LitElement {
|
||||||
override createRenderRoot() {
|
override createRenderRoot() {
|
||||||
@@ -24,7 +24,7 @@ export class VText extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor str: string = ZERO_WIDTH_SPACE;
|
accessor str: string = ZERO_WIDTH_FOR_EMPTY_LINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const ZERO_WIDTH_SPACE = '\u200C';
|
import { IS_SAFARI } from '@blocksuite/global/env';
|
||||||
// see https://en.wikipedia.org/wiki/Zero-width_non-joiner
|
|
||||||
export const ZERO_WIDTH_NON_JOINER = '\u200B';
|
export const ZERO_WIDTH_FOR_EMPTY_LINE = IS_SAFARI ? '\u200C' : '\u200B';
|
||||||
|
export const ZERO_WIDTH_FOR_EMBED_NODE = IS_SAFARI ? '\u200B' : '\u200C';
|
||||||
|
|
||||||
export const INLINE_ROOT_ATTR = 'data-v-root';
|
export const INLINE_ROOT_ATTR = 'data-v-root';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||||
|
|
||||||
import type { VElement, VLine } from '../components/index.js';
|
import type { VElement, VLine } from '../components/index.js';
|
||||||
import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js';
|
import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
|
||||||
import type { DomPoint, TextPoint } from '../types.js';
|
import type { DomPoint, TextPoint } from '../types.js';
|
||||||
import {
|
import {
|
||||||
isInlineRoot,
|
isInlineRoot,
|
||||||
@@ -76,7 +76,7 @@ export function textPointToDomPoint(
|
|||||||
index += calculateTextLength(text);
|
index += calculateTextLength(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.wholeText !== ZERO_WIDTH_SPACE) {
|
if (text.wholeText !== ZERO_WIDTH_FOR_EMPTY_LINE) {
|
||||||
index += offset;
|
index += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ZERO_WIDTH_SPACE } from '../consts.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js';
|
||||||
|
|
||||||
export function calculateTextLength(text: Text): number {
|
export function calculateTextLength(text: Text): number {
|
||||||
if (text.wholeText === ZERO_WIDTH_SPACE) {
|
if (text.wholeText === ZERO_WIDTH_FOR_EMPTY_LINE) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return text.wholeText.length;
|
return text.wholeText.length;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { effects } from '@blocksuite/affine/std/effects';
|
|||||||
import {
|
import {
|
||||||
type AttributeRenderer,
|
type AttributeRenderer,
|
||||||
InlineEditor,
|
InlineEditor,
|
||||||
ZERO_WIDTH_NON_JOINER,
|
ZERO_WIDTH_FOR_EMBED_NODE,
|
||||||
} from '@blocksuite/affine/std/inline';
|
} from '@blocksuite/affine/std/inline';
|
||||||
import {
|
import {
|
||||||
type BaseTextAttributes,
|
type BaseTextAttributes,
|
||||||
@@ -62,7 +62,7 @@ const attributeRenderer: AttributeRenderer = ({ delta, selected }) => {
|
|||||||
border: selected ? '1px solid #eb763a' : '',
|
border: selected ? '1px solid #eb763a' : '',
|
||||||
background: 'rgba(135,131,120,0.15)',
|
background: 'rgba(135,131,120,0.15)',
|
||||||
})}
|
})}
|
||||||
>@flrande<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
|
>@flrande<v-text .str=${ZERO_WIDTH_FOR_EMBED_NODE}></v-text
|
||||||
></span>`;
|
></span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ test(scoped`delete emoji forward`, async ({ page }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
scoped`ZERO_WIDTH_SPACE should be counted by one cursor position`,
|
scoped`ZERO_WIDTH_FOR_EMPTY_LINE should be counted by one cursor position`,
|
||||||
async ({ page }) => {
|
async ({ page }) => {
|
||||||
await enterPlaygroundRoom(page);
|
await enterPlaygroundRoom(page);
|
||||||
await initEmptyParagraphState(page);
|
await initEmptyParagraphState(page);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
getEditorLocator,
|
getEditorLocator,
|
||||||
waitNextFrame,
|
waitNextFrame,
|
||||||
} from '../utils/actions/misc.js';
|
} from '../utils/actions/misc.js';
|
||||||
import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js';
|
||||||
|
|
||||||
export async function press(page: Page, content: string) {
|
export async function press(page: Page, content: string) {
|
||||||
await page.keyboard.press(content, { delay: 50 });
|
await page.keyboard.press(content, { delay: 50 });
|
||||||
@@ -95,7 +95,7 @@ export async function assertDatabaseTitleColumnText(
|
|||||||
const text = await selectCell1.innerText();
|
const text = await selectCell1.innerText();
|
||||||
|
|
||||||
if (title === '') {
|
if (title === '') {
|
||||||
expect(text).toMatch(new RegExp(`^(|[${ZERO_WIDTH_SPACE}])$`));
|
expect(text).toMatch(new RegExp(`^(|[${ZERO_WIDTH_FOR_EMPTY_LINE}])$`));
|
||||||
} else {
|
} else {
|
||||||
expect(text).toBe(title);
|
expect(text).toBe(title);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
initEmptyParagraphState,
|
initEmptyParagraphState,
|
||||||
} from '../utils/actions/misc.js';
|
} from '../utils/actions/misc.js';
|
||||||
import { assertRichTextInlineDeltas } from '../utils/asserts.js';
|
import { assertRichTextInlineDeltas } from '../utils/asserts.js';
|
||||||
import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js';
|
||||||
// FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts
|
// FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts
|
||||||
const defaultPlaygroundURL = new URL(
|
const defaultPlaygroundURL = new URL(
|
||||||
`http://localhost:${process.env.CI ? 4173 : 5173}/`
|
`http://localhost:${process.env.CI ? 4173 : 5173}/`
|
||||||
@@ -165,8 +165,8 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
const editorAUndo = page.getByText('undo').nth(0);
|
const editorAUndo = page.getByText('undo').nth(0);
|
||||||
const editorARedo = page.getByText('redo').nth(0);
|
const editorARedo = page.getByText('redo').nth(0);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -177,8 +177,8 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
|
|
||||||
await editorAUndo.click();
|
await editorAUndo.click();
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await editorARedo.click();
|
await editorARedo.click();
|
||||||
|
|
||||||
@@ -244,12 +244,18 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
});
|
{
|
||||||
await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
useInnerText: true, // for multi-line text
|
||||||
useInnerText: true, // for multi-line text
|
}
|
||||||
});
|
);
|
||||||
|
await expect(editorB).toHaveText(
|
||||||
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await editorAUndo.click();
|
await editorAUndo.click();
|
||||||
|
|
||||||
@@ -258,12 +264,18 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
|
|
||||||
await editorARedo.click();
|
await editorARedo.click();
|
||||||
|
|
||||||
await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
});
|
{
|
||||||
await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
useInnerText: true, // for multi-line text
|
||||||
useInnerText: true, // for multi-line text
|
}
|
||||||
});
|
);
|
||||||
|
await expect(editorB).toHaveText(
|
||||||
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await focusInlineRichText(page);
|
await focusInlineRichText(page);
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
@@ -274,12 +286,18 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
|
|
||||||
await editorAUndo.click();
|
await editorAUndo.click();
|
||||||
|
|
||||||
await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
});
|
{
|
||||||
await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', {
|
useInnerText: true, // for multi-line text
|
||||||
useInnerText: true, // for multi-line text
|
}
|
||||||
});
|
);
|
||||||
|
await expect(editorB).toHaveText(
|
||||||
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb',
|
||||||
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await editorARedo.click();
|
await editorARedo.click();
|
||||||
|
|
||||||
@@ -314,12 +332,18 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
await press(page, 'Enter');
|
await press(page, 'Enter');
|
||||||
await press(page, 'Enter');
|
await press(page, 'Enter');
|
||||||
|
|
||||||
await expect(editorA).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd',
|
||||||
});
|
{
|
||||||
await expect(editorB).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', {
|
useInnerText: true, // for multi-line text
|
||||||
useInnerText: true, // for multi-line text
|
}
|
||||||
});
|
);
|
||||||
|
await expect(editorB).toHaveText(
|
||||||
|
'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd',
|
||||||
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await editorAUndo.click();
|
await editorAUndo.click();
|
||||||
|
|
||||||
@@ -328,12 +352,18 @@ test('basic input', async ({ page, browserName }) => {
|
|||||||
|
|
||||||
await editorARedo.click();
|
await editorARedo.click();
|
||||||
|
|
||||||
await expect(editorA).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd',
|
||||||
});
|
{
|
||||||
await expect(editorB).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', {
|
useInnerText: true, // for multi-line text
|
||||||
useInnerText: true, // for multi-line text
|
}
|
||||||
});
|
);
|
||||||
|
await expect(editorB).toHaveText(
|
||||||
|
'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd',
|
||||||
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('chinese input', async ({ page, browserName }) => {
|
test('chinese input', async ({ page, browserName }) => {
|
||||||
@@ -348,8 +378,8 @@ test('chinese input', async ({ page, browserName }) => {
|
|||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
const client = await page.context().newCDPSession(page);
|
const client = await page.context().newCDPSession(page);
|
||||||
@@ -396,8 +426,8 @@ test('readonly mode', async ({ page }) => {
|
|||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -441,8 +471,8 @@ test('basic styles', async ({ page }) => {
|
|||||||
const editorAUndo = page.getByText('undo').nth(0);
|
const editorAUndo = page.getByText('undo').nth(0);
|
||||||
const editorARedo = page.getByText('redo').nth(0);
|
const editorARedo = page.getByText('redo').nth(0);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -696,8 +726,8 @@ test('overlapping styles', async ({ page }) => {
|
|||||||
const editorAUndo = page.getByText('undo').nth(0);
|
const editorAUndo = page.getByText('undo').nth(0);
|
||||||
const editorARedo = page.getByText('redo').nth(0);
|
const editorARedo = page.getByText('redo').nth(0);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -868,8 +898,8 @@ test('input continuous spaces', async ({ page }) => {
|
|||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -902,8 +932,8 @@ test('select from the start of line using shift+arrow', async ({ page }) => {
|
|||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -961,8 +991,8 @@ test('getLine', async ({ page }) => {
|
|||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
const editorB = page.locator('[data-v-root="true"]').nth(1);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await expect(editorB).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -1032,7 +1062,7 @@ test('embed', async ({ page }) => {
|
|||||||
|
|
||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorAEmbed = page.getByText('embed').nth(0);
|
const editorAEmbed = page.getByText('embed').nth(0);
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
|
|
||||||
@@ -1101,7 +1131,7 @@ test('delete embed when pressing backspace after embed', async ({ page }) => {
|
|||||||
|
|
||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
const editorAEmbed = page.getByText('embed').nth(0);
|
const editorAEmbed = page.getByText('embed').nth(0);
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
await type(page, 'ab');
|
await type(page, 'ab');
|
||||||
await expect(editorA).toHaveText('ab');
|
await expect(editorA).toHaveText('ab');
|
||||||
@@ -1146,7 +1176,7 @@ test('triple click to select line', async ({ page }) => {
|
|||||||
|
|
||||||
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
const editorA = page.locator('[data-v-root="true"]').nth(0);
|
||||||
|
|
||||||
await expect(editorA).toHaveText(ZERO_WIDTH_SPACE);
|
await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await page.waitForTimeout(100);
|
await page.waitForTimeout(100);
|
||||||
await type(page, 'abc\nabc abc abc\nabc');
|
await type(page, 'abc\nabc abc abc\nabc');
|
||||||
|
|
||||||
@@ -1161,9 +1191,12 @@ test('triple click to select line', async ({ page }) => {
|
|||||||
await assertSelection(page, 0, 4, 11);
|
await assertSelection(page, 0, 4, 11);
|
||||||
|
|
||||||
await pressBackspace(page);
|
await pressBackspace(page);
|
||||||
await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nabc', {
|
await expect(editorA).toHaveText(
|
||||||
useInnerText: true, // for multi-line text
|
'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nabc',
|
||||||
});
|
{
|
||||||
|
useInnerText: true, // for multi-line text
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('caret should move correctly when inline elements are exist', async ({
|
test('caret should move correctly when inline elements are exist', async ({
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
assertRichTextInlineDeltas,
|
assertRichTextInlineDeltas,
|
||||||
assertRichTextInlineRange,
|
assertRichTextInlineRange,
|
||||||
} from '../utils/asserts.js';
|
} from '../utils/asserts.js';
|
||||||
import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js';
|
||||||
import { test } from '../utils/playwright.js';
|
import { test } from '../utils/playwright.js';
|
||||||
|
|
||||||
test('add inline latex at the start of line', async ({ page }) => {
|
test('add inline latex at the start of line', async ({ page }) => {
|
||||||
@@ -162,13 +162,13 @@ test('latex editor', async ({ page }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await pressBackspaceWithShortKey(page, 2);
|
await pressBackspaceWithShortKey(page, 2);
|
||||||
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE);
|
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await undoByKeyboard(page);
|
await undoByKeyboard(page);
|
||||||
expect(await latexEditorLine.innerText()).toBe(
|
expect(await latexEditorLine.innerText()).toBe(
|
||||||
'ababababababababababababababababababababababababab'
|
'ababababababababababababababababababababababababab'
|
||||||
);
|
);
|
||||||
await redoByKeyboard(page);
|
await redoByKeyboard(page);
|
||||||
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE);
|
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
await undoByKeyboard(page);
|
await undoByKeyboard(page);
|
||||||
expect(await latexEditorLine.innerText()).toBe(
|
expect(await latexEditorLine.innerText()).toBe(
|
||||||
'ababababababababababababababababababababababababab'
|
'ababababababababababababababababababababababababab'
|
||||||
@@ -200,7 +200,7 @@ test('latex editor', async ({ page }) => {
|
|||||||
|
|
||||||
await selectAllByKeyboard(page);
|
await selectAllByKeyboard(page);
|
||||||
await pressBackspace(page);
|
await pressBackspace(page);
|
||||||
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE);
|
expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE);
|
||||||
|
|
||||||
// highlight
|
// highlight
|
||||||
await type(
|
await type(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { expect } from '@playwright/test';
|
|||||||
import stringify from 'json-stable-stringify';
|
import stringify from 'json-stable-stringify';
|
||||||
import lz from 'lz-string';
|
import lz from 'lz-string';
|
||||||
|
|
||||||
import { ZERO_WIDTH_SPACE } from '../inline-editor.js';
|
import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../inline-editor.js';
|
||||||
import { currentEditorIndex } from '../multiple-editor.js';
|
import { currentEditorIndex } from '../multiple-editor.js';
|
||||||
import {
|
import {
|
||||||
pressArrowRight,
|
pressArrowRight,
|
||||||
@@ -1054,7 +1054,7 @@ export async function getIndexCoordinate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function inlineEditorInnerTextToString(innerText: string): string {
|
export function inlineEditorInnerTextToString(innerText: string): string {
|
||||||
return innerText.replace(ZERO_WIDTH_SPACE, '').trim();
|
return innerText.replace(ZERO_WIDTH_FOR_EMPTY_LINE, '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function focusTitle(page: Page) {
|
export async function focusTitle(page: Page) {
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ export async function getStringFromRichText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error
|
// Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error
|
||||||
export const ZERO_WIDTH_SPACE = '\u200C';
|
export const ZERO_WIDTH_FOR_EMPTY_LINE =
|
||||||
|
process.env.BROWSER === 'webkit' ? '\u200C' : '\u200B';
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
|
|||||||
declare type _GLOBAL_ = typeof BlocksuiteEffects;
|
declare type _GLOBAL_ = typeof BlocksuiteEffects;
|
||||||
|
|
||||||
const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget';
|
const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget';
|
||||||
export const ZERO_WIDTH_SPACE = '\u200C';
|
export const ZERO_WIDTH_FOR_EMPTY_LINE =
|
||||||
|
process.env.BROWSER === 'webkit' ? '\u200C' : '\u200B';
|
||||||
|
|
||||||
export function inlineEditorInnerTextToString(innerText: string): string {
|
export function inlineEditorInnerTextToString(innerText: string): string {
|
||||||
return innerText.replace(ZERO_WIDTH_SPACE, '').trim();
|
return innerText.replace(ZERO_WIDTH_FOR_EMPTY_LINE, '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARAGRAPH_BLOCK_LOCATOR = 'affine-paragraph';
|
const PARAGRAPH_BLOCK_LOCATOR = 'affine-paragraph';
|
||||||
|
|||||||
Reference in New Issue
Block a user