@blocksuite/virgo
Advanced tools
Comparing version 0.4.0-20230204233304-6e37e29 to 0.4.0-20230205175611-17a62e3
import { expect, test } from '@playwright/test'; | ||
import { ZERO_WIDTH_SPACE } from '../constant.js'; | ||
import { enterPlayground, focusRichText, pagePress, pageType, } from './utils/misc.js'; | ||
import { enterPlayground, focusRichText, getDeltaFromFirstEditor, pagePress, pageType, setFirstEditorRange, } from './utils/misc.js'; | ||
test('basic input', async ({ page }) => { | ||
@@ -112,2 +112,251 @@ await enterPlayground(page); | ||
}); | ||
test('basic text style', async ({ page }) => { | ||
await enterPlayground(page); | ||
await focusRichText(page); | ||
const editorA = page.locator('[data-virgo-root="true"]').nth(0); | ||
const editorB = page.locator('[data-virgo-root="true"]').nth(1); | ||
const editorABold = page.getByText('bold').nth(0); | ||
const editorAItalic = page.getByText('italic').nth(0); | ||
const editorAUnderline = page.getByText('underline').nth(0); | ||
const editorAStrikethrough = page.getByText('strikethrough').nth(0); | ||
const editorAInlineCode = page.getByText('inline-code').nth(0); | ||
const editorAReset = page.getByText('reset').nth(0); | ||
expect(await editorA.innerText()).toBe(ZERO_WIDTH_SPACE); | ||
expect(await editorB.innerText()).toBe(ZERO_WIDTH_SPACE); | ||
await pageType(page, 'abcdefg'); | ||
expect(await editorA.innerText()).toBe('abcdefg'); | ||
expect(await editorB.innerText()).toBe('abcdefg'); | ||
let delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
await setFirstEditorRange(page, { index: 2, length: 3 }); | ||
editorABold.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAItalic.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAUnderline.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
underline: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAStrikethrough.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorABold.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
italic: true, | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAItalic.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAUnderline.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAStrikethrough.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAReset.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAInlineCode.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'inline-code', | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAInlineCode.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
}); | ||
//# sourceMappingURL=input.spec.js.map |
@@ -0,1 +1,3 @@ | ||
import type { DeltaInsert } from '@blocksuite/virgo/types.js'; | ||
import type { VRange } from '@blocksuite/virgo/virgo.js'; | ||
import type { Page } from '@playwright/test'; | ||
@@ -6,2 +8,4 @@ export declare function enterPlayground(page: Page): Promise<void>; | ||
export declare function pagePress(page: Page, key: string): Promise<void>; | ||
export declare function getDeltaFromFirstEditor(page: Page): Promise<DeltaInsert>; | ||
export declare function setFirstEditorRange(page: Page, vRange: VRange): Promise<void>; | ||
//# sourceMappingURL=misc.d.ts.map |
@@ -23,2 +23,29 @@ export async function enterPlayground(page) { | ||
} | ||
export async function getDeltaFromFirstEditor(page) { | ||
await page.waitForTimeout(50); | ||
return await page.evaluate(() => { | ||
const richTextA = document | ||
.querySelector('test-page') | ||
?.shadowRoot?.querySelector('rich-text'); | ||
if (!richTextA) { | ||
throw new Error('Cannot find editor'); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const editor = richTextA.vEditor; | ||
return editor.yText.toDelta(); | ||
}); | ||
} | ||
export async function setFirstEditorRange(page, vRange) { | ||
await page.evaluate(vRange => { | ||
const richTextA = document | ||
.querySelector('test-page') | ||
?.shadowRoot?.querySelector('rich-text'); | ||
if (!richTextA) { | ||
throw new Error('Cannot find editor'); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const editor = richTextA.vEditor; | ||
editor.setVRange(vRange); | ||
}, vRange); | ||
} | ||
//# sourceMappingURL=misc.js.map |
@@ -13,2 +13,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
function virgoTextStyles(props) { | ||
let textDecorations = ''; | ||
if (props.underline) { | ||
textDecorations += 'underline'; | ||
} | ||
if (props.strikethrough) { | ||
textDecorations += ' line-through'; | ||
} | ||
return styleMap({ | ||
@@ -18,3 +25,3 @@ 'white-space': 'break-spaces', | ||
'font-style': props.italic ? 'italic' : 'normal', | ||
'text-decoration': props.underline ? 'underline' : 'none', | ||
'text-decoration': textDecorations.length > 0 ? textDecorations : 'none', | ||
}); | ||
@@ -21,0 +28,0 @@ } |
@@ -352,2 +352,10 @@ import { ZERO_WIDTH_SPACE } from './constant.js'; | ||
} | ||
else if (anchorNode instanceof HTMLElement && | ||
anchorNode.dataset.virgoElement === 'true') { | ||
const textNode = getTextNodeFromElement(anchorNode); | ||
if (textNode) { | ||
anchorText = textNode; | ||
anchorTextOffset = anchorOffset; | ||
} | ||
} | ||
if (focusNode instanceof Text && isVText(focusNode)) { | ||
@@ -357,2 +365,10 @@ focusText = focusNode; | ||
} | ||
else if (focusNode instanceof HTMLElement && | ||
focusNode.dataset.virgoElement === 'true') { | ||
const textNode = getTextNodeFromElement(focusNode); | ||
if (textNode) { | ||
focusText = textNode; | ||
focusTextOffset = focusOffset; | ||
} | ||
} | ||
// case 1 | ||
@@ -561,3 +577,3 @@ if (anchorText && focusText) { | ||
else { | ||
spanElement = element.querySelector('span'); | ||
spanElement = element.querySelector('[data-virgo-text="true"]'); | ||
} | ||
@@ -564,0 +580,0 @@ if (!spanElement) { |
{ | ||
"name": "@blocksuite/virgo", | ||
"version": "0.4.0-20230204233304-6e37e29", | ||
"version": "0.4.0-20230205175611-17a62e3", | ||
"description": "A micro editor.", | ||
@@ -26,3 +26,3 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@blocksuite/global": "0.4.0-20230204233304-6e37e29" | ||
"@blocksuite/global": "0.4.0-20230205175611-17a62e3" | ||
}, | ||
@@ -29,0 +29,0 @@ "scripts": { |
@@ -6,4 +6,6 @@ import { expect, test } from '@playwright/test'; | ||
focusRichText, | ||
getDeltaFromFirstEditor, | ||
pagePress, | ||
pageType, | ||
setFirstEditorRange, | ||
} from './utils/misc.js'; | ||
@@ -168,1 +170,269 @@ | ||
}); | ||
test('basic text style', async ({ page }) => { | ||
await enterPlayground(page); | ||
await focusRichText(page); | ||
const editorA = page.locator('[data-virgo-root="true"]').nth(0); | ||
const editorB = page.locator('[data-virgo-root="true"]').nth(1); | ||
const editorABold = page.getByText('bold').nth(0); | ||
const editorAItalic = page.getByText('italic').nth(0); | ||
const editorAUnderline = page.getByText('underline').nth(0); | ||
const editorAStrikethrough = page.getByText('strikethrough').nth(0); | ||
const editorAInlineCode = page.getByText('inline-code').nth(0); | ||
const editorAReset = page.getByText('reset').nth(0); | ||
expect(await editorA.innerText()).toBe(ZERO_WIDTH_SPACE); | ||
expect(await editorB.innerText()).toBe(ZERO_WIDTH_SPACE); | ||
await pageType(page, 'abcdefg'); | ||
expect(await editorA.innerText()).toBe('abcdefg'); | ||
expect(await editorB.innerText()).toBe('abcdefg'); | ||
let delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
await setFirstEditorRange(page, { index: 2, length: 3 }); | ||
editorABold.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAItalic.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAUnderline.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
underline: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAStrikethrough.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
bold: true, | ||
italic: true, | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorABold.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
italic: true, | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAItalic.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
underline: true, | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAUnderline.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'base', | ||
strikethrough: true, | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAStrikethrough.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAReset.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAInlineCode.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'ab', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
{ | ||
insert: 'cde', | ||
attributes: { | ||
type: 'inline-code', | ||
}, | ||
}, | ||
{ | ||
insert: 'fg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
editorAInlineCode.click(); | ||
delta = await getDeltaFromFirstEditor(page); | ||
expect(delta).toEqual([ | ||
{ | ||
insert: 'abcdefg', | ||
attributes: { | ||
type: 'base', | ||
}, | ||
}, | ||
]); | ||
}); |
@@ -0,1 +1,3 @@ | ||
import type { DeltaInsert } from '@blocksuite/virgo/types.js'; | ||
import type { VEditor, VRange } from '@blocksuite/virgo/virgo.js'; | ||
import type { Page } from '@playwright/test'; | ||
@@ -31,1 +33,39 @@ | ||
} | ||
export async function getDeltaFromFirstEditor( | ||
page: Page | ||
): Promise<DeltaInsert> { | ||
await page.waitForTimeout(50); | ||
return await page.evaluate(() => { | ||
const richTextA = document | ||
.querySelector('test-page') | ||
?.shadowRoot?.querySelector('rich-text'); | ||
if (!richTextA) { | ||
throw new Error('Cannot find editor'); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const editor = (richTextA as any).vEditor as VEditor; | ||
return editor.yText.toDelta(); | ||
}); | ||
} | ||
export async function setFirstEditorRange( | ||
page: Page, | ||
vRange: VRange | ||
): Promise<void> { | ||
await page.evaluate(vRange => { | ||
const richTextA = document | ||
.querySelector('test-page') | ||
?.shadowRoot?.querySelector('rich-text'); | ||
if (!richTextA) { | ||
throw new Error('Cannot find editor'); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const editor = (richTextA as any).vEditor as VEditor; | ||
editor.setVRange(vRange); | ||
}, vRange); | ||
} |
@@ -9,2 +9,10 @@ import { LitElement, html } from 'lit'; | ||
function virgoTextStyles(props: BaseArrtiubtes): ReturnType<typeof styleMap> { | ||
let textDecorations = ''; | ||
if (props.underline) { | ||
textDecorations += 'underline'; | ||
} | ||
if (props.strikethrough) { | ||
textDecorations += ' line-through'; | ||
} | ||
return styleMap({ | ||
@@ -14,3 +22,3 @@ 'white-space': 'break-spaces', | ||
'font-style': props.italic ? 'italic' : 'normal', | ||
'text-decoration': props.underline ? 'underline' : 'none', | ||
'text-decoration': textDecorations.length > 0 ? textDecorations : 'none', | ||
}); | ||
@@ -17,0 +25,0 @@ } |
@@ -429,2 +429,11 @@ import type * as Y from 'yjs'; | ||
anchorTextOffset = anchorOffset; | ||
} else if ( | ||
anchorNode instanceof HTMLElement && | ||
anchorNode.dataset.virgoElement === 'true' | ||
) { | ||
const textNode = getTextNodeFromElement(anchorNode); | ||
if (textNode) { | ||
anchorText = textNode; | ||
anchorTextOffset = anchorOffset; | ||
} | ||
} | ||
@@ -434,2 +443,11 @@ if (focusNode instanceof Text && isVText(focusNode)) { | ||
focusTextOffset = focusOffset; | ||
} else if ( | ||
focusNode instanceof HTMLElement && | ||
focusNode.dataset.virgoElement === 'true' | ||
) { | ||
const textNode = getTextNodeFromElement(focusNode); | ||
if (textNode) { | ||
focusText = textNode; | ||
focusTextOffset = focusOffset; | ||
} | ||
} | ||
@@ -771,3 +789,3 @@ | ||
} else { | ||
spanElement = element.querySelector('span'); | ||
spanElement = element.querySelector('[data-virgo-text="true"]'); | ||
} | ||
@@ -774,0 +792,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
204532
2857
+ Added@blocksuite/global@0.4.0-20230205175611-17a62e3(transitive)
- Removed@blocksuite/global@0.4.0-20230204233304-6e37e29(transitive)