Huge News!Announcing our $40M Series B led by Abstract Ventures.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.0.0-20230827224823-81f8728e-nightly to 0.0.0-20230828163942-e5356e86-nightly

dist/services/hook.d.ts

16

dist/services/event.d.ts

@@ -1,24 +0,10 @@

import type { VRange } from '../types.js';
import { type BaseTextAttributes } from '../utils/index.js';
import type { VEditor } from '../virgo.js';
export interface VHandlerContext<T extends BaseTextAttributes, E extends Event = Event> {
event: E;
data: string | null;
vRange: VRange;
skipDefault: boolean;
attributes: T | null;
}
export declare class VirgoEventService<TextAttributes extends BaseTextAttributes> {
private readonly _editor;
private _mountAbortController;
private _handlerAbortController;
readonly editor: VEditor<TextAttributes>;
private _isComposing;
private _handlers;
private _previousAnchor;
private _previousFocus;
constructor(editor: VEditor<TextAttributes>);
defaultHandlers: VirgoEventService<TextAttributes>['_handlers'];
mount: () => void;
unmount: () => void;
bindHandlers: (handlers?: VirgoEventService<TextAttributes>['_handlers']) => void;
private _onSelectionChange;

@@ -25,0 +11,0 @@ private _onCompositionStart;

@@ -8,96 +8,23 @@ import { assertExists } from '@blocksuite/global/utils';

constructor(editor) {
this._mountAbortController = null;
this._handlerAbortController = null;
this.editor = editor;
this._isComposing = false;
this._handlers = {};
this._previousAnchor = null;
this._previousFocus = null;
this.defaultHandlers = {
paste: (event) => {
const data = event.clipboardData?.getData('text/plain');
if (data) {
const vRange = this._editor.getVRange();
const text = data.replace(/(\r\n|\r|\n)/g, '\n');
if (vRange) {
this._editor.insertText(vRange, text);
this._editor.setVRange({
index: vRange.index + text.length,
length: 0,
});
}
}
},
};
this.mount = () => {
const rootElement = this._editor.rootElement;
this._mountAbortController = new AbortController();
const signal = this._mountAbortController.signal;
document.addEventListener('selectionchange', this._onSelectionChange, {
signal,
});
rootElement.addEventListener('beforeinput', this._onBeforeInput, {
signal,
});
rootElement
.querySelectorAll('[data-virgo-text="true"]')
.forEach(textNode => {
textNode.addEventListener('dragstart', event => {
event.preventDefault();
}, {
signal,
});
});
rootElement.addEventListener('compositionstart', this._onCompositionStart, {
signal,
});
rootElement.addEventListener('compositionend', this._onCompositionEnd, {
signal,
});
rootElement.addEventListener('scroll', this._onScroll, {
signal,
});
rootElement.addEventListener('keydown', this._onKeyDown, {
signal,
});
rootElement.addEventListener('click', this._onClick, {
signal,
});
this.bindHandlers();
const rootElement = this.editor.rootElement;
this.editor.disposables.addFromEvent(document, 'selectionchange', this._onSelectionChange);
this.editor.disposables.addFromEvent(rootElement, 'beforeinput', this._onBeforeInput);
this.editor.disposables.addFromEvent(rootElement, 'compositionstart', this._onCompositionStart);
this.editor.disposables.addFromEvent(rootElement, 'compositionend', this._onCompositionEnd);
this.editor.disposables.addFromEvent(rootElement, 'scroll', this._onScroll);
this.editor.disposables.addFromEvent(rootElement, 'keydown', this._onKeyDown);
this.editor.disposables.addFromEvent(rootElement, 'click', this._onClick);
};
this.unmount = () => {
if (this._mountAbortController) {
this._mountAbortController.abort();
this._mountAbortController = null;
}
if (this._handlerAbortController) {
this._handlerAbortController.abort();
this._handlerAbortController = null;
}
this._handlers = this.defaultHandlers;
};
this.bindHandlers = (handlers = this
.defaultHandlers) => {
this._handlers = handlers;
if (this._handlerAbortController) {
this._handlerAbortController.abort();
}
this._handlerAbortController = new AbortController();
if (this._handlers.paste) {
this._editor.rootElement.addEventListener('paste', this._handlers.paste, {
signal: this._handlerAbortController.signal,
});
}
if (this._handlers.keydown) {
this._editor.rootElement.addEventListener('keydown', this._handlers.keydown, {
signal: this._handlerAbortController.signal,
});
}
};
this._onSelectionChange = () => {
const rootElement = this._editor.rootElement;
const previousVRange = this._editor.getVRange();
const rootElement = this.editor.rootElement;
const previousVRange = this.editor.getVRange();
if (this._isComposing) {
return;
}
const selectionRoot = findDocumentOrShadowRoot(this._editor);
const selectionRoot = findDocumentOrShadowRoot(this.editor);
const selection = selectionRoot.getSelection();

@@ -108,3 +35,3 @@ if (!selection)

if (previousVRange !== null) {
this._editor.slots.vRangeUpdated.emit([null, 'native']);
this.editor.slots.vRangeUpdated.emit([null, 'native']);
}

@@ -129,3 +56,3 @@ return;

if (isContainerSelected) {
this._editor.focusEnd();
this.editor.focusEnd();
return;

@@ -135,3 +62,3 @@ }

if (previousVRange !== null) {
this._editor.slots.vRangeUpdated.emit([null, 'native']);
this.editor.slots.vRangeUpdated.emit([null, 'native']);
}

@@ -143,5 +70,5 @@ return;

this._previousFocus = [range.endContainer, range.endOffset];
const vRange = this._editor.toVRange(selection.getRangeAt(0));
const vRange = this.editor.toVRange(selection.getRangeAt(0));
if (!isMaybeVRangeEqual(previousVRange, vRange)) {
this._editor.slots.vRangeUpdated.emit([vRange, 'native']);
this.editor.slots.vRangeUpdated.emit([vRange, 'native']);
}

@@ -157,3 +84,3 @@ // avoid infinite syncVRange

range.endContainer.nodeType === Node.COMMENT_NODE) {
this._editor.syncVRange();
this.editor.syncVRange();
}

@@ -164,3 +91,3 @@ };

// embeds is not editable and it will break IME
const embeds = this._editor.rootElement.querySelectorAll('[data-virgo-embed="true"]');
const embeds = this.editor.rootElement.querySelectorAll('[data-virgo-embed="true"]');
embeds.forEach(embed => {

@@ -172,22 +99,23 @@ embed.removeAttribute('contenteditable');

this._isComposing = false;
this._editor.rerenderWholeEditor();
await this._editor.waitForUpdate();
if (this._editor.isReadonly)
this.editor.rerenderWholeEditor();
await this.editor.waitForUpdate();
if (this.editor.isReadonly)
return;
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange)
return;
let ctx = {
event,
vEditor: this.editor,
raw: event,
vRange,
data: event.data,
vRange,
skipDefault: false,
attributes: null,
attributes: {},
};
if (this._handlers.virgoCompositionEnd) {
ctx = this._handlers.virgoCompositionEnd(ctx);
const hook = this.editor.hooks.compositionEnd;
if (hook) {
ctx = hook(ctx);
}
if (ctx.skipDefault)
if (!ctx)
return;
const { data, vRange: newVRange } = ctx;
const { vRange: newVRange, data: newData } = ctx;
if (newVRange.index >= 0) {

@@ -206,3 +134,3 @@ const selection = window.getSelection();

else {
const [text] = this._editor.getTextPoint(newVRange.index);
const [text] = this.editor.getTextPoint(newVRange.index);
const vText = text.parentElement?.closest('v-text');

@@ -228,3 +156,3 @@ if (vText) {

}
const newRange = this._editor.toDomRange(newVRange);
const newRange = this.editor.toDomRange(newVRange);
if (newRange) {

@@ -237,7 +165,7 @@ assertExists(newRange);

}
if (data && data.length > 0) {
this._editor.insertText(newVRange, data, ctx.attributes ?? {});
this._editor.slots.vRangeUpdated.emit([
if (newData && newData.length > 0) {
this.editor.insertText(newVRange, newData, ctx.attributes);
this.editor.slots.vRangeUpdated.emit([
{
index: newVRange.index + data.length,
index: newVRange.index + newData.length,
length: 0,

@@ -253,3 +181,3 @@ },

event.preventDefault();
if (this._editor.isReadonly || this._isComposing)
if (this.editor.isReadonly || this._isComposing)
return;

@@ -263,22 +191,23 @@ if (this._firstRecomputeInFrame) {

}
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange)
return;
let ctx = {
event,
vEditor: this.editor,
raw: event,
vRange,
data: event.data,
vRange,
skipDefault: false,
attributes: null,
attributes: {},
};
if (this._handlers.virgoInput) {
ctx = this._handlers.virgoInput(ctx);
const hook = this.editor.hooks.beforeinput;
if (hook) {
ctx = hook(ctx);
}
if (ctx.skipDefault)
if (!ctx)
return;
const { event: newEvent, data, vRange: newVRange } = ctx;
transformInput(newEvent.inputType, data, ctx.attributes ?? {}, newVRange, this._editor);
const { raw: newEvent, data, vRange: newVRange } = ctx;
transformInput(newEvent.inputType, data, ctx.attributes, newVRange, this.editor);
};
this._onScroll = () => {
this._editor.slots.scrollUpdated.emit(this._editor.rootElement.scrollLeft);
this.editor.slots.scrollUpdated.emit(this.editor.rootElement.scrollLeft);
};

@@ -288,3 +217,3 @@ this._onKeyDown = (event) => {

(event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange || vRange.length !== 0)

@@ -296,7 +225,7 @@ return;

};
const deltas = this._editor.getDeltasByVRange(vRange);
const deltas = this.editor.getDeltasByVRange(vRange);
if (deltas.length === 2) {
if (event.key === 'ArrowLeft' && this._editor.isEmbed(deltas[0][0])) {
if (event.key === 'ArrowLeft' && this.editor.isEmbed(deltas[0][0])) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index - 1,

@@ -307,5 +236,5 @@ length: 1,

else if (event.key === 'ArrowRight' &&
this._editor.isEmbed(deltas[1][0])) {
this.editor.isEmbed(deltas[1][0])) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index,

@@ -318,6 +247,6 @@ length: 1,

const delta = deltas[0][0];
if (this._editor.isEmbed(delta)) {
if (this.editor.isEmbed(delta)) {
if (event.key === 'ArrowLeft' && vRange.index - 1 >= 0) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index - 1,

@@ -328,5 +257,5 @@ length: 1,

else if (event.key === 'ArrowRight' &&
vRange.index + 1 <= this._editor.yText.length) {
vRange.index + 1 <= this.editor.yTextLength) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index,

@@ -343,3 +272,3 @@ length: 1,

if (event.target instanceof Node && isInEmbedElement(event.target)) {
const selectionRoot = findDocumentOrShadowRoot(this._editor);
const selectionRoot = findDocumentOrShadowRoot(this.editor);
const selection = selectionRoot.getSelection();

@@ -362,5 +291,4 @@ if (!selection)

};
this._editor = editor;
}
}
//# sourceMappingURL=event.js.map
export * from './attribute.js';
export * from './delta.js';
export * from './event.js';
export * from './hook.js';
export * from './range.js';
//# sourceMappingURL=index.d.ts.map
export * from './attribute.js';
export * from './delta.js';
export * from './event.js';
export * from './hook.js';
export * from './range.js';
//# sourceMappingURL=index.js.map
import type { NullablePartial } from '@blocksuite/global/utils';
import { Slot } from '@blocksuite/global/utils';
import { DisposableGroup, Slot } from '@blocksuite/global/utils';
import type * as Y from 'yjs';
import type { VirgoLine } from './components/index.js';
import { VirgoHookService } from './services/hook.js';
import { VirgoAttributeService, VirgoDeltaService, VirgoEventService, VirgoRangeService } from './services/index.js';

@@ -16,2 +17,4 @@ import type { DeltaInsert, TextPoint, VRange, VRangeUpdatedProp } from './types.js';

static getTextNodesFromElement: typeof getTextNodesFromElement;
private _disposables;
get disposables(): DisposableGroup;
private readonly _yText;

@@ -24,2 +27,3 @@ private _rootElement;

private _deltaService;
private _hooksService;
private _mounted;

@@ -53,8 +57,2 @@ shouldLineScrollIntoView: boolean;

getFormat: (vRange: VRange, loose?: boolean) => TextAttributes;
bindHandlers: (handlers?: {
keydown?: ((event: KeyboardEvent) => void) | undefined;
paste?: ((event: ClipboardEvent) => void) | undefined;
virgoInput?: ((ctx: import("./services/event.js").VHandlerContext<TextAttributes, InputEvent>) => import("./services/event.js").VHandlerContext<TextAttributes, InputEvent>) | undefined;
virgoCompositionEnd?: ((ctx: import("./services/event.js").VHandlerContext<TextAttributes, CompositionEvent>) => import("./services/event.js").VHandlerContext<TextAttributes, CompositionEvent>) | undefined;
}) => void;
toDomRange: (vRange: VRange) => Range | null;

@@ -69,4 +67,9 @@ toVRange: (range: Range) => VRange | null;

isNormalizedDeltaSelected: (normalizedDeltaIndex: number, vRange: VRange) => boolean;
get hooks(): {
beforeinput?: ((props: import("./services/hook.js").VBeforeinputHookCtx<TextAttributes>) => import("./services/hook.js").VBeforeinputHookCtx<TextAttributes> | null) | undefined;
compositionEnd?: ((props: import("./services/hook.js").VCompositionEndHookCtx<TextAttributes>) => import("./services/hook.js").VCompositionEndHookCtx<TextAttributes> | null) | undefined;
};
constructor(yText: VEditor['yText'], ops?: {
isEmbed?: (delta: DeltaInsert<TextAttributes>) => boolean;
hooks?: VirgoHookService<TextAttributes>['hooks'];
});

@@ -96,6 +99,7 @@ mount(rootElement: HTMLElement): void;

setText(text: string, attributes?: TextAttributes): void;
rerenderWholeEditor(): void;
private _onYTextChange;
rerenderWholeEditor(): void;
private _transact;
private _bindYTextObserver;
}
//# sourceMappingURL=virgo.d.ts.map

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

import { assertExists, Slot } from '@blocksuite/global/utils';
import { assertExists, DisposableGroup, Slot } from '@blocksuite/global/utils';
import { nothing, render } from 'lit';
import { VirgoHookService } from './services/hook.js';
import { VirgoAttributeService, VirgoDeltaService, VirgoEventService, VirgoRangeService, } from './services/index.js';

@@ -8,2 +9,5 @@ import { findDocumentOrShadowRoot, nativePointToTextPoint, textPointToDomPoint, } from './utils/index.js';

export class VEditor {
get disposables() {
return this._disposables;
}
get yText() {

@@ -44,3 +48,8 @@ return this._yText;

}
constructor(yText, ops) {
// Expose hook service API
get hooks() {
return this._hooksService.hooks;
}
constructor(yText, ops = {}) {
this._disposables = new DisposableGroup();
this._rootElement = null;

@@ -60,4 +69,2 @@ this._isReadonly = false;

this.getFormat = this._attributeService.getFormat;
// Expose event service API
this.bindHandlers = this._eventService.bindHandlers;
// Expose range service API

@@ -89,4 +96,6 @@ this.toDomRange = this.rangeService.toDomRange;

}
const { isEmbed = () => false, hooks = {} } = ops;
this._yText = yText;
this.isEmbed = ops?.isEmbed ?? (() => false);
this.isEmbed = isEmbed;
this._hooksService = new VirgoHookService(this, hooks);
this.slots = {

@@ -110,3 +119,3 @@ mounted: new Slot(),

this._rootElement.dataset.virgoRoot = 'true';
this.yText.observe(this._onYTextChange);
this._bindYTextObserver();
this._deltaService.render();

@@ -118,7 +127,6 @@ this._eventService.mount();

unmount() {
this._eventService.unmount();
this.yText.unobserve(this._onYTextChange);
render(nothing, this.rootElement);
this._rootElement = null;
this._mounted = false;
this.disposables.dispose();
this.slots.unmounted.emit();

@@ -278,2 +286,10 @@ }

}
_bindYTextObserver() {
this.yText.observe(this._onYTextChange);
this.disposables.add({
dispose: () => {
this.yText.unobserve(this._onYTextChange);
},
});
}
}

@@ -280,0 +296,0 @@ VEditor.nativePointToTextPoint = nativePointToTextPoint;

{
"name": "@blocksuite/virgo",
"version": "0.0.0-20230827224823-81f8728e-nightly",
"version": "0.0.0-20230828163942-e5356e86-nightly",
"description": "A micro editor.",

@@ -28,3 +28,3 @@ "main": "dist/index.js",

"zod": "^3.22.2",
"@blocksuite/global": "0.0.0-20230827224823-81f8728e-nightly"
"@blocksuite/global": "0.0.0-20230828163942-e5356e86-nightly"
},

@@ -31,0 +31,0 @@ "scripts": {

import { assertExists } from '@blocksuite/global/utils';
import { ZERO_WIDTH_SPACE } from '../consts.js';
import type { NativePoint, VRange } from '../types.js';
import type { NativePoint } from '../types.js';
import {

@@ -13,150 +13,47 @@ type BaseTextAttributes,

import type { VEditor } from '../virgo.js';
import type { VBeforeinputHookCtx, VCompositionEndHookCtx } from './hook.js';
export interface VHandlerContext<
T extends BaseTextAttributes,
E extends Event = Event
> {
event: E;
data: string | null;
vRange: VRange;
skipDefault: boolean;
attributes: T | null;
}
export class VirgoEventService<TextAttributes extends BaseTextAttributes> {
private readonly _editor: VEditor<TextAttributes>;
private _mountAbortController: AbortController | null = null;
private _handlerAbortController: AbortController | null = null;
private _isComposing = false;
private _handlers: {
keydown?: (event: KeyboardEvent) => void;
paste?: (event: ClipboardEvent) => void;
// corresponding to native input event and used to take over default behavior in virgo
virgoInput?: (
ctx: VHandlerContext<TextAttributes, InputEvent>
) => VHandlerContext<TextAttributes, InputEvent>;
// corresponding to native compositionend event and used to take over default behavior in virgo
virgoCompositionEnd?: (
ctx: VHandlerContext<TextAttributes, CompositionEvent>
) => VHandlerContext<TextAttributes, CompositionEvent>;
} = {};
private _previousAnchor: NativePoint | null = null;
private _previousFocus: NativePoint | null = null;
constructor(editor: VEditor<TextAttributes>) {
this._editor = editor;
}
constructor(public readonly editor: VEditor<TextAttributes>) {}
defaultHandlers: VirgoEventService<TextAttributes>['_handlers'] = {
paste: (event: ClipboardEvent) => {
const data = event.clipboardData?.getData('text/plain');
if (data) {
const vRange = this._editor.getVRange();
const text = data.replace(/(\r\n|\r|\n)/g, '\n');
if (vRange) {
this._editor.insertText(vRange, text);
this._editor.setVRange({
index: vRange.index + text.length,
length: 0,
});
}
}
},
};
mount = () => {
const rootElement = this._editor.rootElement;
this._mountAbortController = new AbortController();
const signal = this._mountAbortController.signal;
const rootElement = this.editor.rootElement;
document.addEventListener('selectionchange', this._onSelectionChange, {
signal,
});
rootElement.addEventListener('beforeinput', this._onBeforeInput, {
signal,
});
rootElement
.querySelectorAll('[data-virgo-text="true"]')
.forEach(textNode => {
textNode.addEventListener(
'dragstart',
event => {
event.preventDefault();
},
{
signal,
}
);
});
rootElement.addEventListener('compositionstart', this._onCompositionStart, {
signal,
});
rootElement.addEventListener('compositionend', this._onCompositionEnd, {
signal,
});
rootElement.addEventListener('scroll', this._onScroll, {
signal,
});
rootElement.addEventListener('keydown', this._onKeyDown, {
signal,
});
rootElement.addEventListener('click', this._onClick, {
signal,
});
this.bindHandlers();
this.editor.disposables.addFromEvent(
document,
'selectionchange',
this._onSelectionChange
);
this.editor.disposables.addFromEvent(
rootElement,
'beforeinput',
this._onBeforeInput
);
this.editor.disposables.addFromEvent(
rootElement,
'compositionstart',
this._onCompositionStart
);
this.editor.disposables.addFromEvent(
rootElement,
'compositionend',
this._onCompositionEnd
);
this.editor.disposables.addFromEvent(rootElement, 'scroll', this._onScroll);
this.editor.disposables.addFromEvent(
rootElement,
'keydown',
this._onKeyDown
);
this.editor.disposables.addFromEvent(rootElement, 'click', this._onClick);
};
unmount = () => {
if (this._mountAbortController) {
this._mountAbortController.abort();
this._mountAbortController = null;
}
if (this._handlerAbortController) {
this._handlerAbortController.abort();
this._handlerAbortController = null;
}
this._handlers = this.defaultHandlers;
};
bindHandlers = (
handlers: VirgoEventService<TextAttributes>['_handlers'] = this
.defaultHandlers
) => {
this._handlers = handlers;
if (this._handlerAbortController) {
this._handlerAbortController.abort();
}
this._handlerAbortController = new AbortController();
if (this._handlers.paste) {
this._editor.rootElement.addEventListener('paste', this._handlers.paste, {
signal: this._handlerAbortController.signal,
});
}
if (this._handlers.keydown) {
this._editor.rootElement.addEventListener(
'keydown',
this._handlers.keydown,
{
signal: this._handlerAbortController.signal,
}
);
}
};
private _onSelectionChange = () => {
const rootElement = this._editor.rootElement;
const previousVRange = this._editor.getVRange();
const rootElement = this.editor.rootElement;
const previousVRange = this.editor.getVRange();
if (this._isComposing) {

@@ -166,3 +63,3 @@ return;

const selectionRoot = findDocumentOrShadowRoot(this._editor);
const selectionRoot = findDocumentOrShadowRoot(this.editor);
const selection = selectionRoot.getSelection();

@@ -172,3 +69,3 @@ if (!selection) return;

if (previousVRange !== null) {
this._editor.slots.vRangeUpdated.emit([null, 'native']);
this.editor.slots.vRangeUpdated.emit([null, 'native']);
}

@@ -204,7 +101,7 @@

if (isContainerSelected) {
this._editor.focusEnd();
this.editor.focusEnd();
return;
} else {
if (previousVRange !== null) {
this._editor.slots.vRangeUpdated.emit([null, 'native']);
this.editor.slots.vRangeUpdated.emit([null, 'native']);
}

@@ -218,5 +115,5 @@ return;

const vRange = this._editor.toVRange(selection.getRangeAt(0));
const vRange = this.editor.toVRange(selection.getRangeAt(0));
if (!isMaybeVRangeEqual(previousVRange, vRange)) {
this._editor.slots.vRangeUpdated.emit([vRange, 'native']);
this.editor.slots.vRangeUpdated.emit([vRange, 'native']);
}

@@ -235,3 +132,3 @@

) {
this._editor.syncVRange();
this.editor.syncVRange();
}

@@ -243,3 +140,3 @@ };

// embeds is not editable and it will break IME
const embeds = this._editor.rootElement.querySelectorAll(
const embeds = this.editor.rootElement.querySelectorAll(
'[data-virgo-embed="true"]'

@@ -254,23 +151,24 @@ );

this._isComposing = false;
this._editor.rerenderWholeEditor();
await this._editor.waitForUpdate();
this.editor.rerenderWholeEditor();
await this.editor.waitForUpdate();
if (this._editor.isReadonly) return;
if (this.editor.isReadonly) return;
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange) return;
let ctx: VHandlerContext<TextAttributes, CompositionEvent> = {
event,
let ctx: VCompositionEndHookCtx<TextAttributes> | null = {
vEditor: this.editor,
raw: event,
vRange,
data: event.data,
vRange,
skipDefault: false,
attributes: null,
attributes: {} as TextAttributes,
};
if (this._handlers.virgoCompositionEnd) {
ctx = this._handlers.virgoCompositionEnd(ctx);
const hook = this.editor.hooks.compositionEnd;
if (hook) {
ctx = hook(ctx);
}
if (ctx.skipDefault) return;
if (!ctx) return;
const { data, vRange: newVRange } = ctx;
const { vRange: newVRange, data: newData } = ctx;
if (newVRange.index >= 0) {

@@ -289,3 +187,3 @@ const selection = window.getSelection();

} else {
const [text] = this._editor.getTextPoint(newVRange.index);
const [text] = this.editor.getTextPoint(newVRange.index);
const vText = text.parentElement?.closest('v-text');

@@ -314,3 +212,3 @@ if (vText) {

const newRange = this._editor.toDomRange(newVRange);
const newRange = this.editor.toDomRange(newVRange);
if (newRange) {

@@ -324,12 +222,8 @@ assertExists(newRange);

if (data && data.length > 0) {
this._editor.insertText(
newVRange,
data,
ctx.attributes ?? ({} as TextAttributes)
);
if (newData && newData.length > 0) {
this.editor.insertText(newVRange, newData, ctx.attributes);
this._editor.slots.vRangeUpdated.emit([
this.editor.slots.vRangeUpdated.emit([
{
index: newVRange.index + data.length,
index: newVRange.index + newData.length,
length: 0,

@@ -342,2 +236,3 @@ },

};
private _firstRecomputeInFrame = true;

@@ -347,3 +242,3 @@ private _onBeforeInput = (event: InputEvent) => {

if (this._editor.isReadonly || this._isComposing) return;
if (this.editor.isReadonly || this._isComposing) return;
if (this._firstRecomputeInFrame) {

@@ -356,25 +251,25 @@ this._firstRecomputeInFrame = false;

}
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange) return;
let ctx: VHandlerContext<TextAttributes, InputEvent> = {
event,
let ctx: VBeforeinputHookCtx<TextAttributes> | null = {
vEditor: this.editor,
raw: event,
vRange,
data: event.data,
vRange,
skipDefault: false,
attributes: null,
attributes: {} as TextAttributes,
};
if (this._handlers.virgoInput) {
ctx = this._handlers.virgoInput(ctx);
const hook = this.editor.hooks.beforeinput;
if (hook) {
ctx = hook(ctx);
}
if (!ctx) return;
if (ctx.skipDefault) return;
const { event: newEvent, data, vRange: newVRange } = ctx;
const { raw: newEvent, data, vRange: newVRange } = ctx;
transformInput<TextAttributes>(
newEvent.inputType,
data,
ctx.attributes ?? ({} as TextAttributes),
ctx.attributes,
newVRange,
this._editor as VEditor
this.editor as VEditor
);

@@ -384,3 +279,3 @@ };

private _onScroll = () => {
this._editor.slots.scrollUpdated.emit(this._editor.rootElement.scrollLeft);
this.editor.slots.scrollUpdated.emit(this.editor.rootElement.scrollLeft);
};

@@ -393,3 +288,3 @@

) {
const vRange = this._editor.getVRange();
const vRange = this.editor.getVRange();
if (!vRange || vRange.length !== 0) return;

@@ -402,7 +297,7 @@

const deltas = this._editor.getDeltasByVRange(vRange);
const deltas = this.editor.getDeltasByVRange(vRange);
if (deltas.length === 2) {
if (event.key === 'ArrowLeft' && this._editor.isEmbed(deltas[0][0])) {
if (event.key === 'ArrowLeft' && this.editor.isEmbed(deltas[0][0])) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index - 1,

@@ -413,6 +308,6 @@ length: 1,

event.key === 'ArrowRight' &&
this._editor.isEmbed(deltas[1][0])
this.editor.isEmbed(deltas[1][0])
) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index,

@@ -424,6 +319,6 @@ length: 1,

const delta = deltas[0][0];
if (this._editor.isEmbed(delta)) {
if (this.editor.isEmbed(delta)) {
if (event.key === 'ArrowLeft' && vRange.index - 1 >= 0) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index - 1,

@@ -434,6 +329,6 @@ length: 1,

event.key === 'ArrowRight' &&
vRange.index + 1 <= this._editor.yText.length
vRange.index + 1 <= this.editor.yTextLength
) {
prevent();
this._editor.setVRange({
this.editor.setVRange({
index: vRange.index,

@@ -451,3 +346,3 @@ length: 1,

if (event.target instanceof Node && isInEmbedElement(event.target)) {
const selectionRoot = findDocumentOrShadowRoot(this._editor);
const selectionRoot = findDocumentOrShadowRoot(this.editor);
const selection = selectionRoot.getSelection();

@@ -454,0 +349,0 @@ if (!selection) return;

export * from './attribute.js';
export * from './delta.js';
export * from './event.js';
export * from './hook.js';
export * from './range.js';
import type { NullablePartial } from '@blocksuite/global/utils';
import { assertExists, Slot } from '@blocksuite/global/utils';
import { assertExists, DisposableGroup, Slot } from '@blocksuite/global/utils';
import { nothing, render } from 'lit';

@@ -7,2 +7,3 @@ import type * as Y from 'yjs';

import type { VirgoLine } from './components/index.js';
import { VirgoHookService } from './services/hook.js';
import {

@@ -42,2 +43,7 @@ VirgoAttributeService,

private _disposables = new DisposableGroup();
get disposables() {
return this._disposables;
}
private readonly _yText: Y.Text;

@@ -59,2 +65,4 @@ private _rootElement: VirgoRootElement<TextAttributes> | null = null;

private _hooksService: VirgoHookService<TextAttributes>;
private _mounted = false;

@@ -127,5 +135,2 @@

// Expose event service API
bindHandlers = this._eventService.bindHandlers;
// Expose range service API

@@ -144,7 +149,13 @@ toDomRange = this.rangeService.toDomRange;

// Expose hook service API
get hooks() {
return this._hooksService.hooks;
}
constructor(
yText: VEditor['yText'],
ops?: {
ops: {
isEmbed?: (delta: DeltaInsert<TextAttributes>) => boolean;
}
hooks?: VirgoHookService<TextAttributes>['hooks'];
} = {}
) {

@@ -161,4 +172,7 @@ if (!yText.doc) {

const { isEmbed = () => false, hooks = {} } = ops;
this._yText = yText;
this.isEmbed = ops?.isEmbed ?? (() => false);
this.isEmbed = isEmbed;
this._hooksService = new VirgoHookService(this, hooks);
this.slots = {

@@ -184,4 +198,5 @@ mounted: new Slot(),

this._rootElement.dataset.virgoRoot = 'true';
this.yText.observe(this._onYTextChange);
this._bindYTextObserver();
this._deltaService.render();

@@ -196,9 +211,6 @@

unmount() {
this._eventService.unmount();
this.yText.unobserve(this._onYTextChange);
render(nothing, this.rootElement);
this._rootElement = null;
this._mounted = false;
this.disposables.dispose();
this.slots.unmounted.emit();

@@ -403,2 +415,7 @@ }

rerenderWholeEditor() {
render(nothing, this.rootElement);
this._deltaService.render();
}
private _onYTextChange = () => {

@@ -418,7 +435,2 @@ if (this.yText.toString().includes('\r')) {

rerenderWholeEditor() {
render(nothing, this.rootElement);
this._deltaService.render();
}
private _transact(fn: () => void): void {

@@ -432,2 +444,11 @@ const doc = this.yText.doc;

}
private _bindYTextObserver() {
this.yText.observe(this._onYTextChange);
this.disposables.add({
dispose: () => {
this.yText.unobserve(this._onYTextChange);
},
});
}
}

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