New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@blocksuite/virgo

Package Overview
Dependencies
Maintainers
5
Versions
509
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blocksuite/virgo - npm Package Compare versions

Comparing version 0.4.0-20230208200347-b55e9fe to 0.4.0-20230209191848-0a912e3

playwright.config.ts

31

dist/components/base-text.d.ts
import { LitElement } from 'lit';
import type { BaseArrtiubtes, DeltaInsert } from '../types.js';
import { z } from 'zod';
import type { DeltaInsert } from '../types.js';
export declare const baseTextAttributes: z.ZodOptional<z.ZodObject<{
bold: z.ZodOptional<z.ZodBoolean>;
italic: z.ZodOptional<z.ZodBoolean>;
underline: z.ZodOptional<z.ZodBoolean>;
strikethrough: z.ZodOptional<z.ZodBoolean>;
inlineCode: z.ZodOptional<z.ZodBoolean>;
color: z.ZodOptional<z.ZodString>;
link: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
bold?: boolean | undefined;
italic?: boolean | undefined;
underline?: boolean | undefined;
strikethrough?: boolean | undefined;
inlineCode?: boolean | undefined;
color?: string | undefined;
link?: string | undefined;
}, {
bold?: boolean | undefined;
italic?: boolean | undefined;
underline?: boolean | undefined;
strikethrough?: boolean | undefined;
inlineCode?: boolean | undefined;
color?: string | undefined;
link?: string | undefined;
}>>;
export type BaseTextAttributes = z.infer<typeof baseTextAttributes>;
export declare class BaseText extends LitElement {
delta: DeltaInsert<BaseArrtiubtes>;
delta: DeltaInsert<BaseTextAttributes>;
render(): import("lit-html").TemplateResult<1>;

@@ -6,0 +33,0 @@ createRenderRoot(): this;

@@ -10,5 +10,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import { styleMap } from 'lit/directives/style-map.js';
import { z } from 'zod';
import { ZERO_WIDTH_SPACE } from '../constant.js';
import { VirgoUnitText } from './virgo-unit-text.js';
export const baseTextAttributes = z
.object({
bold: z.boolean().optional(),
italic: z.boolean().optional(),
underline: z.boolean().optional(),
strikethrough: z.boolean().optional(),
inlineCode: z.boolean().optional(),
color: z.string().optional(),
link: z.string().optional(),
})
.optional();
function virgoTextStyles(props) {
if (!props)
return styleMap({});
let textDecorations = '';

@@ -21,2 +35,14 @@ if (props.underline) {

}
let inlineCodeStyle = {};
if (props.inlineCode) {
inlineCodeStyle = {
'font-family': '"SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace',
'line-height': 'normal',
background: 'rgba(135,131,120,0.15)',
color: '#EB5757',
'border-radius': '3px',
'font-size': '85%',
padding: '0.2em 0.4em',
};
}
return styleMap({

@@ -27,2 +53,3 @@ 'white-space': 'break-spaces',

'text-decoration': textDecorations.length > 0 ? textDecorations : 'none',
...inlineCodeStyle,
});

@@ -35,5 +62,2 @@ }

insert: ZERO_WIDTH_SPACE,
attributes: {
type: 'base',
},
};

@@ -43,3 +67,3 @@ }

const unitText = new VirgoUnitText();
unitText.delta = this.delta;
unitText.str = this.delta.insert;
// we need to avoid \n appearing before and after the span element, which will

@@ -46,0 +70,0 @@ // cause the unexpected space

1

dist/components/index.d.ts
export * from './base-text.js';
export * from './virgo-line.js';
export * from './virgo-unit-text.js';
export * from './optional/inline-code.js';
//# sourceMappingURL=index.d.ts.map
export * from './base-text.js';
export * from './virgo-line.js';
export * from './virgo-unit-text.js';
// optional elements
export * from './optional/inline-code.js';
//# sourceMappingURL=index.js.map
import { LitElement } from 'lit';
import type { BaseArrtiubtes, DeltaInsert } from '../types.js';
export declare class VirgoUnitText extends LitElement {
delta: DeltaInsert<BaseArrtiubtes>;
str: string;
render(): import("lit-html").TemplateResult<1>;

@@ -6,0 +5,0 @@ createRenderRoot(): this;

@@ -13,8 +13,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

super(...arguments);
this.delta = {
insert: ZERO_WIDTH_SPACE,
attributes: {
type: 'base',
},
};
this.str = ZERO_WIDTH_SPACE;
}

@@ -24,3 +19,3 @@ render() {

// cause the sync problem about the cursor position
return html `<span data-virgo-text="true">${this.delta.insert}</span>`;
return html `<span data-virgo-text="true">${this.str}</span>`;
}

@@ -32,4 +27,4 @@ createRenderRoot() {

__decorate([
property({ type: Object })
], VirgoUnitText.prototype, "delta", void 0);
property()
], VirgoUnitText.prototype, "str", void 0);
VirgoUnitText = __decorate([

@@ -36,0 +31,0 @@ customElement('virgo-unit-text')

import { expect, test } from '@playwright/test';
import { ZERO_WIDTH_SPACE } from '../constant.js';
import { enterVirgoPlayground, focusVirgoRichText, getDeltaFromVirgoRichText, setVirgoRichTextRange, type, } from './utils/misc.js';
const ZERO_WIDTH_SPACE = '\u200B';
test('basic input', async ({ page }) => {

@@ -39,2 +39,3 @@ await enterVirgoPlayground(page);

await type(page, 'bbb');
page.waitForTimeout(100);
expect(await editorA.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nbbb');

@@ -123,3 +124,2 @@ expect(await editorB.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nbbb');

const editorAInlineCode = page.getByText('inline-code').nth(0);
const editorAReset = page.getByText('reset').nth(0);
expect(await editorA.innerText()).toBe(ZERO_WIDTH_SPACE);

@@ -134,5 +134,2 @@ expect(await editorB.innerText()).toBe(ZERO_WIDTH_SPACE);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},

@@ -146,5 +143,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -154,3 +148,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -161,5 +154,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -172,5 +162,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -180,3 +167,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -188,5 +174,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -199,5 +182,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -207,3 +187,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -216,5 +195,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -227,5 +203,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -235,3 +208,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -245,5 +217,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -256,5 +225,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -264,3 +230,2 @@ {

attributes: {
type: 'base',
italic: true,

@@ -273,5 +238,2 @@ underline: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -284,5 +246,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -292,3 +251,2 @@ {

attributes: {
type: 'base',
underline: true,

@@ -300,5 +258,2 @@ strikethrough: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -311,5 +266,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -319,3 +271,2 @@ {

attributes: {
type: 'base',
strikethrough: true,

@@ -326,5 +277,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -337,17 +285,4 @@ ]);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},
]);
editorAReset.click();
delta = await getDeltaFromVirgoRichText(page);
expect(delta).toEqual([
{
insert: 'abcdefg',
attributes: {
type: 'base',
},
},
]);
editorAInlineCode.click();

@@ -358,5 +293,2 @@ delta = await getDeltaFromVirgoRichText(page);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -366,3 +298,3 @@ {

attributes: {
type: 'inline-code',
inlineCode: true,
},

@@ -372,5 +304,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -383,5 +312,2 @@ ]);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},

@@ -388,0 +314,0 @@ ]);

@@ -1,15 +0,2 @@

import type { BaseText } from './components/base-text.js';
import type { InlineCode, InlineCodeAttributes } from './components/optional/inline-code.js';
export interface BaseArrtiubtes {
type: 'base';
bold?: true;
italic?: true;
underline?: true;
strikethrough?: true;
}
export interface LineBreakAttributes {
type: 'line-break';
}
export type BaseTextElement = BaseText | InlineCode;
export type BaseTextAttributes = BaseArrtiubtes | LineBreakAttributes | InlineCodeAttributes;
import type { BaseText, BaseTextAttributes } from './components/base-text.js';
export interface CustomTypes {

@@ -20,9 +7,9 @@ [key: string]: unknown;

type ExtendedType<K extends ExtendableKeys, B> = unknown extends CustomTypes[K] ? B : CustomTypes[K];
export type TextElement = ExtendedType<'Element', BaseTextElement>;
export type TextAttributes = ExtendedType<'Attributes', BaseTextAttributes>;
export type TextElement = ExtendedType<'Element', BaseText>;
export type DeltaInsert<A extends TextAttributes = TextAttributes> = {
insert: string;
attributes: A;
attributes?: A;
};
export {};
//# sourceMappingURL=types.d.ts.map

@@ -0,1 +1,25 @@

// TODO unit test
function transformDelta(delta) {
const result = [];
let tmpString = delta.insert;
while (tmpString.length > 0) {
const index = tmpString.indexOf('\n');
if (index === -1) {
result.push({
insert: tmpString,
attributes: delta.attributes,
});
break;
}
if (tmpString.slice(0, index).length > 0) {
result.push({
insert: tmpString.slice(0, index),
attributes: delta.attributes,
});
}
result.push('\n');
tmpString = tmpString.slice(index + 1);
}
return result;
}
/**

@@ -8,6 +32,7 @@ * convert a delta insert array to chunks, each chunk is a line

}
const transformedDelta = delta.flatMap(transformDelta);
function* chunksGenerator(arr) {
let start = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i].attributes.type === 'line-break') {
if (arr[i] === '\n') {
const chunk = arr.slice(start, i);

@@ -21,8 +46,8 @@ start = i + 1;

}
if (arr[arr.length - 1].attributes.type === 'line-break') {
if (arr.at(-1) === '\n') {
yield [];
}
}
return [...chunksGenerator(delta)];
return [...chunksGenerator(transformedDelta)];
}
//# sourceMappingURL=convert.js.map

@@ -1,2 +0,2 @@

import { BaseText } from '../components/base-text.js';
import { BaseText, baseTextAttributes } from '../components/base-text.js';
/**

@@ -6,12 +6,10 @@ * a default render function for text element

export function baseRenderElement(delta) {
switch (delta.attributes.type) {
case 'base': {
const baseText = new BaseText();
baseText.delta = delta;
return baseText;
}
default:
throw new Error(`Unknown text type: ${delta.attributes.type}`);
}
const parseResult = baseTextAttributes.parse(delta.attributes);
const baseText = new BaseText();
baseText.delta = {
insert: delta.insert,
attributes: parseResult,
};
return baseText;
}
//# sourceMappingURL=render.js.map

@@ -28,3 +28,2 @@ import { Signal } from '@blocksuite/global/utils';

unmount(): void;
getBaseElement(node: Node): TextElement | null;
getNativeSelection(): Selection | null;

@@ -42,3 +41,3 @@ getDeltaByRangeIndex(rangeIndex: VRange['index']): DeltaInsert | null;

insertLineBreak(vRange: VRange): void;
formatText(vRange: VRange, attributes: TextAttributes, options?: {
formatText(vRange: VRange, attributes: NonNullable<TextAttributes>, options?: {
match?: (delta: DeltaInsert, deltaVRange: VRange) => boolean;

@@ -45,0 +44,0 @@ mode?: 'replace' | 'merge';

@@ -20,11 +20,3 @@ import { assertExists, Signal } from '@blocksuite/global/utils';

assertExists(this._rootElement);
const deltas = this.yText.toDelta().flatMap(d => {
if (d.attributes.type === 'line-break') {
return d.insert
.split('')
.map(c => ({ insert: c, attributes: d.attributes }));
}
return d;
});
renderDeltas(deltas, this._rootElement, this._renderElement);
renderDeltas(this.yText.toDelta(), this._rootElement, this._renderElement);
};

@@ -77,3 +69,5 @@ this._onSelectionChange = () => {

if (onKeyDown) {
this._onKeyDown = onKeyDown;
this._onKeyDown = e => {
onKeyDown(e);
};
}

@@ -124,9 +118,2 @@ this.signals = {

}
getBaseElement(node) {
const element = node.parentElement?.closest('[data-virgo-element="true"]');
if (element) {
return element;
}
return null;
}
getNativeSelection() {

@@ -197,15 +184,6 @@ const selectionRoot = findDocumentOrShadowRoot(this);

}
// TODO add support for formatting
insertText(vRange, text) {
const currentDelta = this.getDeltaByRangeIndex(vRange.index);
this._transact(() => {
this.yText.delete(vRange.index, vRange.length);
if (vRange.index > 0 &&
currentDelta &&
currentDelta.attributes.type !== 'line-break') {
this.yText.insert(vRange.index, text, currentDelta.attributes);
}
else {
this.yText.insert(vRange.index, text, { type: 'base' });
}
this.yText.insert(vRange.index, text);
});

@@ -216,3 +194,3 @@ }

this.yText.delete(vRange.index, vRange.length);
this.yText.insert(vRange.index, '\n', { type: 'line-break' });
this.yText.insert(vRange.index, '\n');
});

@@ -224,5 +202,2 @@ }

for (const [delta, deltaVRange] of deltas) {
if (delta.attributes.type === 'line-break') {
continue;
}
if (match(delta, deltaVRange)) {

@@ -250,7 +225,8 @@ const targetVRange = {

}
const unset = Object.fromEntries(coverDeltas.flatMap(delta => Object.keys(delta.attributes).map(key => [key, null])));
const unset = Object.fromEntries(coverDeltas.flatMap(delta => delta.attributes
? Object.keys(delta.attributes).map(key => [key, null])
: []));
this._transact(() => {
this.yText.format(vRange.index, vRange.length, {
...unset,
type: 'base',
});

@@ -257,0 +233,0 @@ });

{
"name": "@blocksuite/virgo",
"version": "0.4.0-20230208200347-b55e9fe",
"version": "0.4.0-20230209191848-0a912e3",
"description": "A micro editor.",

@@ -11,8 +11,8 @@ "main": "dist/index.js",

"devDependencies": {
"yjs": "^13.5.45",
"lit": "^2.6.1"
"lit": "^2.6.1",
"yjs": "^13.5.45"
},
"peerDependencies": {
"yjs": "^13",
"lit": "^2"
"lit": "^2",
"yjs": "^13"
},

@@ -27,8 +27,10 @@ "exports": {

"dependencies": {
"@blocksuite/global": "0.4.0-20230208200347-b55e9fe"
"@blocksuite/global": "0.4.0-20230209191848-0a912e3",
"zod": "^3.20.2"
},
"scripts": {
"build": "tsc"
"build": "tsc",
"test": "playwright test"
},
"types": "dist/index.d.ts"
}

@@ -5,3 +5,3 @@ # `@blocksuite/virgo`

Virgo is a minimized rich-text editing kernel that synchronizes the state between DOM and [Y.Text](https://docs.yjs.dev/api/shared-types/y.text), which differs from other rich-text editing frameworks in that its data model are _natively_ CRDT. For example, to support collaborative editing in Slate.js, you may need to use a plugin like slate-yjs, a wrapper around [Yjs](https://github.com/yjs/yjs). In these plugins, all text operations should be converted between Yjs and Slate.js operations. This may result in undo/redo properly and hard to maintain the code. However, with Virgo, we can directly synchronize the DOM state between Yjs and DOM, which means that the state in Yjs is the single source of truth. This means that to update, can just calling the `Y.Text` API to manipulate the DOM state, which could significantly reduces the complexity of the editor.
Virgo is a minimized rich-text editing kernel that synchronizes the state between DOM and [Y.Text](https://docs.yjs.dev/api/shared-types/y.text), which differs from other rich-text editing frameworks in that its data model are _natively_ CRDT. For example, to support collaborative editing in Slate.js, you may need to use a plugin like slate-yjs, a wrapper around [Yjs](https://github.com/yjs/yjs). In these plugins, all text operations should be converted between Yjs and Slate.js operations. This may result in undo/redo properly and hard to maintain the code. However, with Virgo, we can directly synchronize the DOM state between Yjs and DOM, which means that the state in Yjs is the single source of truth. It signify that to update, can just calling the `Y.Text` API to manipulate the DOM state, which could significantly reduces the complexity of the editor.

@@ -23,19 +23,4 @@ Initially in BlockSuite, we use [Quill](https://github.com/quilljs/quill) for in-block rich-text editing, which only utilizes a small subset of its APIs. Every paragraph in BlockSuite is managed in a standalone Quill instance, which is attached to a `Y.Text` instance for collaborative editing. Virgo makes this further simpler, since what it needs to do is the same as how we use the Quill subset. It just needs to provide a flat rich-text synchronization mechanism, since the block-tree-level state management is handled by the data store in BlockSuite.

{
insert: 'aaa',
attributes: {
type: 'base',
},
insert: 'aaa\nbbb',
},
{
insert: '\n',
attributes: {
type: 'line-break',
},
},
{
insert: 'bbb',
attributes: {
type: 'base',
},
},
];

@@ -58,3 +43,2 @@ */

attributes: {
type: 'base',
bold: true,

@@ -64,19 +48,4 @@ },

{
insert: 'a',
attributes: {
type: 'base',
},
insert: 'a\nbbb',
},
{
insert: '\n',
attributes: {
type: 'line-break',
},
},
{
insert: 'bbb',
attributes: {
type: 'base',
},
},
];

@@ -83,0 +52,0 @@ */

import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { z } from 'zod';
import { ZERO_WIDTH_SPACE } from '../constant.js';
import type { BaseArrtiubtes, DeltaInsert } from '../types.js';
import type { DeltaInsert } from '../types.js';
import { VirgoUnitText } from './virgo-unit-text.js';
function virgoTextStyles(props: BaseArrtiubtes): ReturnType<typeof styleMap> {
export const baseTextAttributes = z
.object({
bold: z.boolean().optional(),
italic: z.boolean().optional(),
underline: z.boolean().optional(),
strikethrough: z.boolean().optional(),
inlineCode: z.boolean().optional(),
color: z.string().optional(),
link: z.string().optional(),
})
.optional();
export type BaseTextAttributes = z.infer<typeof baseTextAttributes>;
function virgoTextStyles(
props: BaseTextAttributes
): ReturnType<typeof styleMap> {
if (!props) return styleMap({});
let textDecorations = '';

@@ -18,2 +37,16 @@ if (props.underline) {

let inlineCodeStyle = {};
if (props.inlineCode) {
inlineCodeStyle = {
'font-family':
'"SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace',
'line-height': 'normal',
background: 'rgba(135,131,120,0.15)',
color: '#EB5757',
'border-radius': '3px',
'font-size': '85%',
padding: '0.2em 0.4em',
};
}
return styleMap({

@@ -24,2 +57,3 @@ 'white-space': 'break-spaces',

'text-decoration': textDecorations.length > 0 ? textDecorations : 'none',
...inlineCodeStyle,
});

@@ -31,7 +65,4 @@ }

@property({ type: Object })
delta: DeltaInsert<BaseArrtiubtes> = {
delta: DeltaInsert<BaseTextAttributes> = {
insert: ZERO_WIDTH_SPACE,
attributes: {
type: 'base',
},
};

@@ -41,3 +72,3 @@

const unitText = new VirgoUnitText();
unitText.delta = this.delta;
unitText.str = this.delta.insert;

@@ -44,0 +75,0 @@ // we need to avoid \n appearing before and after the span element, which will

export * from './base-text.js';
export * from './virgo-line.js';
export * from './virgo-unit-text.js';
// optional elements
export * from './optional/inline-code.js';

@@ -5,13 +5,7 @@ import { html, LitElement } from 'lit';

import { ZERO_WIDTH_SPACE } from '../constant.js';
import type { BaseArrtiubtes, DeltaInsert } from '../types.js';
@customElement('virgo-unit-text')
export class VirgoUnitText extends LitElement {
@property({ type: Object })
delta: DeltaInsert<BaseArrtiubtes> = {
insert: ZERO_WIDTH_SPACE,
attributes: {
type: 'base',
},
};
@property()
str: string = ZERO_WIDTH_SPACE;

@@ -21,3 +15,3 @@ render() {

// cause the sync problem about the cursor position
return html`<span data-virgo-text="true">${this.delta.insert}</span>`;
return html`<span data-virgo-text="true">${this.str}</span>`;
}

@@ -24,0 +18,0 @@

import { expect, test } from '@playwright/test';
import { ZERO_WIDTH_SPACE } from '../constant.js';
import {

@@ -11,3 +12,2 @@ enterVirgoPlayground,

const ZERO_WIDTH_SPACE = '\u200B';
test('basic input', async ({ page }) => {

@@ -65,2 +65,4 @@ await enterVirgoPlayground(page);

page.waitForTimeout(100);
expect(await editorA.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nbbb');

@@ -184,3 +186,2 @@ expect(await editorB.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nbbb');

const editorAInlineCode = page.getByText('inline-code').nth(0);
const editorAReset = page.getByText('reset').nth(0);

@@ -199,5 +200,2 @@ expect(await editorA.innerText()).toBe(ZERO_WIDTH_SPACE);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},

@@ -213,5 +211,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -221,3 +216,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -228,5 +222,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -240,5 +231,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -248,3 +236,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -256,5 +243,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -268,5 +252,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -276,3 +257,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -285,5 +265,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -297,5 +274,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -305,3 +279,2 @@ {

attributes: {
type: 'base',
bold: true,

@@ -315,5 +288,2 @@ italic: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -327,5 +297,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -335,3 +302,2 @@ {

attributes: {
type: 'base',
italic: true,

@@ -344,5 +310,2 @@ underline: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -356,5 +319,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -364,3 +324,2 @@ {

attributes: {
type: 'base',
underline: true,

@@ -372,5 +331,2 @@ strikethrough: true,

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -384,5 +340,2 @@ ]);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -392,3 +345,2 @@ {

attributes: {
type: 'base',
strikethrough: true,

@@ -399,5 +351,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -411,19 +360,5 @@ ]);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},
]);
editorAReset.click();
delta = await getDeltaFromVirgoRichText(page);
expect(delta).toEqual([
{
insert: 'abcdefg',
attributes: {
type: 'base',
},
},
]);
editorAInlineCode.click();

@@ -434,5 +369,2 @@ delta = await getDeltaFromVirgoRichText(page);

insert: 'ab',
attributes: {
type: 'base',
},
},

@@ -442,3 +374,3 @@ {

attributes: {
type: 'inline-code',
inlineCode: true,
},

@@ -448,5 +380,2 @@ },

insert: 'fg',
attributes: {
type: 'base',
},
},

@@ -460,7 +389,4 @@ ]);

insert: 'abcdefg',
attributes: {
type: 'base',
},
},
]);
});

@@ -1,25 +0,3 @@

import type { BaseText } from './components/base-text.js';
import type {
InlineCode,
InlineCodeAttributes,
} from './components/optional/inline-code.js';
import type { BaseText, BaseTextAttributes } from './components/base-text.js';
export interface BaseArrtiubtes {
type: 'base';
bold?: true;
italic?: true;
underline?: true;
strikethrough?: true;
}
export interface LineBreakAttributes {
type: 'line-break';
}
export type BaseTextElement = BaseText | InlineCode;
export type BaseTextAttributes =
| BaseArrtiubtes
| LineBreakAttributes
| InlineCodeAttributes;
export interface CustomTypes {

@@ -34,8 +12,8 @@ [key: string]: unknown;

export type TextElement = ExtendedType<'Element', BaseTextElement>;
export type TextAttributes = ExtendedType<'Attributes', BaseTextAttributes>;
export type TextElement = ExtendedType<'Element', BaseText>;
export type DeltaInsert<A extends TextAttributes = TextAttributes> = {
insert: string;
attributes: A;
attributes?: A;
};
import type { DeltaInsert } from '../types.js';
// TODO unit test
function transformDelta(delta: DeltaInsert): (DeltaInsert | '\n')[] {
const result: (DeltaInsert | '\n')[] = [];
let tmpString = delta.insert;
while (tmpString.length > 0) {
const index = tmpString.indexOf('\n');
if (index === -1) {
result.push({
insert: tmpString,
attributes: delta.attributes,
});
break;
}
if (tmpString.slice(0, index).length > 0) {
result.push({
insert: tmpString.slice(0, index),
attributes: delta.attributes,
});
}
result.push('\n');
tmpString = tmpString.slice(index + 1);
}
return result;
}
/**

@@ -11,15 +40,17 @@ * convert a delta insert array to chunks, each chunk is a line

function* chunksGenerator(arr: DeltaInsert[]) {
const transformedDelta = delta.flatMap(transformDelta);
function* chunksGenerator(arr: (DeltaInsert | '\n')[]) {
let start = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i].attributes.type === 'line-break') {
if (arr[i] === '\n') {
const chunk = arr.slice(start, i);
start = i + 1;
yield chunk;
yield chunk as DeltaInsert[];
} else if (i === arr.length - 1) {
yield arr.slice(start);
yield arr.slice(start) as DeltaInsert[];
}
}
if (arr[arr.length - 1].attributes.type === 'line-break') {
if (arr.at(-1) === '\n') {
yield [];

@@ -29,3 +60,3 @@ }

return [...chunksGenerator(delta)];
return [...chunksGenerator(transformedDelta)];
}

@@ -1,3 +0,3 @@

import { BaseText } from '../components/base-text.js';
import type { BaseArrtiubtes, DeltaInsert, TextElement } from '../types.js';
import { BaseText, baseTextAttributes } from '../components/base-text.js';
import type { DeltaInsert, TextElement } from '../types.js';

@@ -8,11 +8,11 @@ /**

export function baseRenderElement(delta: DeltaInsert): TextElement {
switch (delta.attributes.type) {
case 'base': {
const baseText = new BaseText();
baseText.delta = delta as DeltaInsert<BaseArrtiubtes>;
return baseText;
}
default:
throw new Error(`Unknown text type: ${delta.attributes.type}`);
}
const parseResult = baseTextAttributes.parse(delta.attributes);
const baseText = new BaseText();
baseText.delta = {
insert: delta.insert,
attributes: parseResult,
};
return baseText;
}

@@ -59,3 +59,5 @@ import { assertExists, Signal } from '@blocksuite/global/utils';

if (onKeyDown) {
this._onKeyDown = onKeyDown;
this._onKeyDown = e => {
onKeyDown(e);
};
}

@@ -130,12 +132,2 @@

getBaseElement(node: Node): TextElement | null {
const element = node.parentElement?.closest('[data-virgo-element="true"]');
if (element) {
return element as TextElement;
}
return null;
}
getNativeSelection(): Selection | null {

@@ -225,17 +217,6 @@ const selectionRoot = findDocumentOrShadowRoot(this);

// TODO add support for formatting
insertText(vRange: VRange, text: string): void {
const currentDelta = this.getDeltaByRangeIndex(vRange.index);
this._transact(() => {
this.yText.delete(vRange.index, vRange.length);
if (
vRange.index > 0 &&
currentDelta &&
currentDelta.attributes.type !== 'line-break'
) {
this.yText.insert(vRange.index, text, currentDelta.attributes);
} else {
this.yText.insert(vRange.index, text, { type: 'base' });
}
this.yText.insert(vRange.index, text);
});

@@ -247,3 +228,3 @@ }

this.yText.delete(vRange.index, vRange.length);
this.yText.insert(vRange.index, '\n', { type: 'line-break' });
this.yText.insert(vRange.index, '\n');
});

@@ -254,3 +235,3 @@ }

vRange: VRange,
attributes: TextAttributes,
attributes: NonNullable<TextAttributes>,
options: {

@@ -265,6 +246,2 @@ match?: (delta: DeltaInsert, deltaVRange: VRange) => boolean;

for (const [delta, deltaVRange] of deltas) {
if (delta.attributes.type === 'line-break') {
continue;
}
if (match(delta, deltaVRange)) {

@@ -306,3 +283,5 @@ const targetVRange = {

coverDeltas.flatMap(delta =>
Object.keys(delta.attributes).map(key => [key, null])
delta.attributes
? Object.keys(delta.attributes).map(key => [key, null])
: []
)

@@ -314,3 +293,2 @@ );

...unset,
type: 'base',
});

@@ -646,12 +624,7 @@ });

const deltas = (this.yText.toDelta() as DeltaInsert[]).flatMap(d => {
if (d.attributes.type === 'line-break') {
return d.insert
.split('')
.map(c => ({ insert: c, attributes: d.attributes }));
}
return d;
}) as DeltaInsert[];
renderDeltas(deltas, this._rootElement, this._renderElement);
renderDeltas(
this.yText.toDelta() as DeltaInsert[],
this._rootElement,
this._renderElement
);
};

@@ -658,0 +631,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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc