mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
feat(editor): replace slot with rxjs subject (#10768)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import type { Subject } from 'rxjs';
|
||||
import { assert, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { applyUpdate, type Doc, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
@@ -36,8 +36,13 @@ function serializCollection(doc: Doc): Record<string, any> {
|
||||
};
|
||||
}
|
||||
|
||||
function waitOnce<T>(slot: Slot<T>) {
|
||||
return new Promise<T>(resolve => slot.once(val => resolve(val)));
|
||||
function waitOnce<T>(slot: Subject<T>) {
|
||||
return new Promise<T>(resolve => {
|
||||
const subscription = slot.subscribe(val => {
|
||||
subscription.unsubscribe();
|
||||
resolve(val);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createRoot(doc: Store) {
|
||||
@@ -150,8 +155,8 @@ describe('basic', () => {
|
||||
|
||||
const readyCallback = vi.fn();
|
||||
const rootAddedCallback = vi.fn();
|
||||
doc.slots.ready.on(readyCallback);
|
||||
doc.slots.rootAdded.on(rootAddedCallback);
|
||||
doc.slots.ready.subscribe(readyCallback);
|
||||
doc.slots.rootAdded.subscribe(rootAddedCallback);
|
||||
|
||||
doc.load(() => {
|
||||
const rootId = doc.addBlock('affine:page', {
|
||||
@@ -428,7 +433,7 @@ describe('addBlock', () => {
|
||||
);
|
||||
|
||||
let called = false;
|
||||
collection.slots.docListUpdated.on(() => {
|
||||
collection.slots.docListUpdated.subscribe(() => {
|
||||
called = true;
|
||||
});
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ test('trigger props updated', () => {
|
||||
expect(rootModel).not.toBeNull();
|
||||
|
||||
const onPropsUpdated = vi.fn();
|
||||
rootModel.propsUpdated.on(onPropsUpdated);
|
||||
rootModel.propsUpdated.subscribe(onPropsUpdated);
|
||||
|
||||
const getColor = () =>
|
||||
(rootModel.yBlock.get('prop:style') as Y.Map<string>).get('color');
|
||||
@@ -101,7 +101,7 @@ test('stash and pop', () => {
|
||||
expect(rootModel).not.toBeNull();
|
||||
|
||||
const onPropsUpdated = vi.fn();
|
||||
rootModel.propsUpdated.on(onPropsUpdated);
|
||||
rootModel.propsUpdated.subscribe(onPropsUpdated);
|
||||
|
||||
const getCount = () => rootModel.yBlock.get('prop:count');
|
||||
const getColor = () =>
|
||||
@@ -171,7 +171,7 @@ test('always get latest value in onChange', () => {
|
||||
expect(rootModel).not.toBeNull();
|
||||
|
||||
let value: unknown;
|
||||
rootModel.propsUpdated.on(({ key }) => {
|
||||
rootModel.propsUpdated.subscribe(({ key }) => {
|
||||
// @ts-expect-error ignore
|
||||
value = rootModel[key];
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { Subject } from 'rxjs';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
@@ -184,7 +184,7 @@ test('flat', () => {
|
||||
map.set('prop:col.c.d', 3);
|
||||
map.set('prop:col.c.e', 4);
|
||||
|
||||
const reactive = new ReactiveFlatYMap(map, new Slot());
|
||||
const reactive = new ReactiveFlatYMap(map, new Subject());
|
||||
const proxy = reactive.proxy as Record<string, any>;
|
||||
proxy.col.c.d = 200;
|
||||
expect(map.get('prop:col.c.d')).toBe(200);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { computed, signal } from '@preact/signals-core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import { nanoid } from '../../utils/id-generator';
|
||||
import type { StackItem } from '../../yjs';
|
||||
@@ -42,8 +42,8 @@ export class StoreSelectionExtension extends StoreExtension {
|
||||
};
|
||||
|
||||
slots = {
|
||||
changed: new Slot<BaseSelection[]>(),
|
||||
remoteChanged: new Slot<Map<number, BaseSelection[]>>(),
|
||||
changed: new Subject<BaseSelection[]>(),
|
||||
remoteChanged: new Subject<Map<number, BaseSelection[]>>(),
|
||||
};
|
||||
|
||||
override loaded() {
|
||||
@@ -98,7 +98,7 @@ export class StoreSelectionExtension extends StoreExtension {
|
||||
map.set(id, selections);
|
||||
});
|
||||
this._remoteSelections.value = map;
|
||||
this.slots.remoteChanged.emit(map);
|
||||
this.slots.remoteChanged.next(map);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -162,7 +162,7 @@ export class StoreSelectionExtension extends StoreExtension {
|
||||
this._id,
|
||||
selections.map(s => s.toJSON())
|
||||
);
|
||||
this.slots.changed.emit(selections);
|
||||
this.slots.changed.next(selections);
|
||||
}
|
||||
|
||||
setGroup(group: string, selections: BaseSelection[]) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { type Disposable, Slot } from '@blocksuite/global/slot';
|
||||
import type { Disposable } from '@blocksuite/global/disposable';
|
||||
import { computed, type Signal, signal } from '@preact/signals-core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import type { Text } from '../../reactive/index.js';
|
||||
import type { Store } from '../store/store.js';
|
||||
@@ -57,9 +59,9 @@ export class BlockModel<
|
||||
}, new Map<string, number>())
|
||||
);
|
||||
|
||||
created = new Slot();
|
||||
created = new Subject<void>();
|
||||
|
||||
deleted = new Slot();
|
||||
deleted = new Subject<void>();
|
||||
|
||||
id!: string;
|
||||
|
||||
@@ -76,7 +78,7 @@ export class BlockModel<
|
||||
|
||||
pop!: (prop: keyof Props & string) => void;
|
||||
|
||||
propsUpdated = new Slot<{ key: string }>();
|
||||
propsUpdated = new Subject<{ key: string }>();
|
||||
|
||||
stash!: (prop: keyof Props & string) => void;
|
||||
|
||||
@@ -124,26 +126,30 @@ export class BlockModel<
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._onCreated = this.created.once(() => {
|
||||
this._children.value = this.yBlock.get('sys:children').toArray();
|
||||
this.yBlock.get('sys:children').observe(event => {
|
||||
this._children.value = event.target.toArray();
|
||||
});
|
||||
this.yBlock.observe(event => {
|
||||
if (event.keysChanged.has('sys:children')) {
|
||||
this._children.value = this.yBlock.get('sys:children').toArray();
|
||||
}
|
||||
});
|
||||
});
|
||||
this._onDeleted = this.deleted.once(() => {
|
||||
this._onCreated.dispose();
|
||||
});
|
||||
this._onCreated = {
|
||||
dispose: this.created.pipe(take(1)).subscribe(() => {
|
||||
this._children.value = this.yBlock.get('sys:children').toArray();
|
||||
this.yBlock.get('sys:children').observe(event => {
|
||||
this._children.value = event.target.toArray();
|
||||
});
|
||||
this.yBlock.observe(event => {
|
||||
if (event.keysChanged.has('sys:children')) {
|
||||
this._children.value = this.yBlock.get('sys:children').toArray();
|
||||
}
|
||||
});
|
||||
}).unsubscribe,
|
||||
};
|
||||
this._onDeleted = {
|
||||
dispose: this.deleted.pipe(take(1)).subscribe(() => {
|
||||
this._onCreated.dispose();
|
||||
}).unsubscribe,
|
||||
};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.created.dispose();
|
||||
this.deleted.dispose();
|
||||
this.propsUpdated.dispose();
|
||||
this.created.complete();
|
||||
this.deleted.complete();
|
||||
this.propsUpdated.complete();
|
||||
}
|
||||
|
||||
firstChild(): BlockModel | null {
|
||||
|
||||
@@ -142,7 +142,10 @@ export class SyncController {
|
||||
this.model[key] = value;
|
||||
});
|
||||
});
|
||||
model.deleted.once(dispose);
|
||||
const subscription = model.deleted.subscribe(() => {
|
||||
subscription.unsubscribe();
|
||||
dispose();
|
||||
});
|
||||
return {
|
||||
...acc,
|
||||
[`${key}$`]: data,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import type { Subject } from 'rxjs';
|
||||
import type * as Y from 'yjs';
|
||||
|
||||
import type { AwarenessStore } from '../yjs/awareness.js';
|
||||
@@ -24,8 +24,8 @@ export interface Doc {
|
||||
dispose(): void;
|
||||
|
||||
slots: {
|
||||
historyUpdated: Slot;
|
||||
yBlockUpdated: Slot<
|
||||
historyUpdated: Subject<void>;
|
||||
yBlockUpdated: Subject<
|
||||
| {
|
||||
type: 'add';
|
||||
id: string;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Container, type ServiceProvider } from '@blocksuite/global/di';
|
||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
|
||||
import { computed, signal } from '@preact/signals-core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import type { ExtensionType } from '../../extension/extension.js';
|
||||
import {
|
||||
@@ -67,15 +68,15 @@ export class Store {
|
||||
|
||||
readonly slots: Doc['slots'] & {
|
||||
/** This is always triggered after `doc.load` is called. */
|
||||
ready: Slot;
|
||||
ready: Subject<void>;
|
||||
/**
|
||||
* This fires when the root block is added via API call or has just been initialized from existing ydoc.
|
||||
* useful for internal block UI components to start subscribing following up events.
|
||||
* Note that at this moment, the whole block tree may not be fully initialized yet.
|
||||
*/
|
||||
rootAdded: Slot<string>;
|
||||
rootDeleted: Slot<string>;
|
||||
blockUpdated: Slot<
|
||||
rootAdded: Subject<string>;
|
||||
rootDeleted: Subject<string>;
|
||||
blockUpdated: Subject<
|
||||
| {
|
||||
type: 'add';
|
||||
id: string;
|
||||
@@ -313,13 +314,15 @@ export class Store {
|
||||
return this._doc.withoutTransact.bind(this._doc);
|
||||
}
|
||||
|
||||
private _isDisposed = false;
|
||||
|
||||
constructor({ doc, readonly, query, provider, extensions }: StoreOptions) {
|
||||
this._doc = doc;
|
||||
this.slots = {
|
||||
ready: new Slot(),
|
||||
rootAdded: new Slot(),
|
||||
rootDeleted: new Slot(),
|
||||
blockUpdated: new Slot(),
|
||||
ready: new Subject(),
|
||||
rootAdded: new Subject(),
|
||||
rootDeleted: new Subject(),
|
||||
blockUpdated: new Subject(),
|
||||
historyUpdated: this._doc.slots.historyUpdated,
|
||||
yBlockUpdated: this._doc.slots.yBlockUpdated,
|
||||
};
|
||||
@@ -362,18 +365,31 @@ export class Store {
|
||||
|
||||
private readonly _subscribeToSlots = () => {
|
||||
this.disposableGroup.add(
|
||||
this._doc.slots.yBlockUpdated.on(({ type, id }) => {
|
||||
switch (type) {
|
||||
case 'add': {
|
||||
this._onBlockAdded(id);
|
||||
return;
|
||||
}
|
||||
case 'delete': {
|
||||
this._onBlockRemoved(id);
|
||||
return;
|
||||
this._doc.slots.yBlockUpdated.subscribe(
|
||||
({ type, id }: { type: string; id: string }) => {
|
||||
switch (type) {
|
||||
case 'add': {
|
||||
this._onBlockAdded(id);
|
||||
return;
|
||||
}
|
||||
case 'delete': {
|
||||
this._onBlockRemoved(id);
|
||||
return;
|
||||
}
|
||||
case 'update': {
|
||||
const block = this.getBlock(id);
|
||||
if (!block) return;
|
||||
this.slots.blockUpdated.next({
|
||||
type: 'update',
|
||||
id,
|
||||
flavour: block.flavour,
|
||||
props: { key: 'content' },
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
this.disposableGroup.add(this.slots.ready);
|
||||
this.disposableGroup.add(this.slots.blockUpdated);
|
||||
@@ -412,10 +428,10 @@ export class Store {
|
||||
const options: BlockOptions = {
|
||||
onChange: (block, key) => {
|
||||
if (key) {
|
||||
block.model.propsUpdated.emit({ key });
|
||||
block.model.propsUpdated.next({ key });
|
||||
}
|
||||
|
||||
this.slots.blockUpdated.emit({
|
||||
this.slots.blockUpdated.next({
|
||||
type: 'update',
|
||||
id,
|
||||
flavour: block.flavour,
|
||||
@@ -431,13 +447,13 @@ export class Store {
|
||||
...this._blocks.value,
|
||||
[id]: block,
|
||||
};
|
||||
block.model.created.emit();
|
||||
block.model.created.next();
|
||||
|
||||
if (block.model.role === 'root') {
|
||||
this.slots.rootAdded.emit(id);
|
||||
this.slots.rootAdded.next(id);
|
||||
}
|
||||
|
||||
this.slots.blockUpdated.emit({
|
||||
this.slots.blockUpdated.next({
|
||||
type: 'add',
|
||||
id,
|
||||
init,
|
||||
@@ -456,13 +472,13 @@ export class Store {
|
||||
if (!block) return;
|
||||
|
||||
if (block.model.role === 'root') {
|
||||
this.slots.rootDeleted.emit(id);
|
||||
this.slots.rootDeleted.next(id);
|
||||
}
|
||||
|
||||
this.slots.blockUpdated.emit({
|
||||
this.slots.blockUpdated.next({
|
||||
type: 'delete',
|
||||
id,
|
||||
flavour: block.model.flavour,
|
||||
flavour: block.flavour,
|
||||
parent: this.getParent(block.model)?.id ?? '',
|
||||
model: block.model,
|
||||
});
|
||||
@@ -470,7 +486,7 @@ export class Store {
|
||||
const { [id]: _, ...blocks } = this._blocks.peek();
|
||||
this._blocks.value = blocks;
|
||||
|
||||
block.model.deleted.emit();
|
||||
block.model.deleted.next();
|
||||
block.model.dispose();
|
||||
} catch (e) {
|
||||
console.error('An error occurred while removing block:');
|
||||
@@ -604,8 +620,12 @@ export class Store {
|
||||
this._provider.getAll(StoreExtensionIdentifier).forEach(ext => {
|
||||
ext.disposed();
|
||||
});
|
||||
|
||||
this.slots.ready.complete();
|
||||
this.slots.rootAdded.complete();
|
||||
this.slots.rootDeleted.complete();
|
||||
this.slots.blockUpdated.complete();
|
||||
this.disposableGroup.dispose();
|
||||
this._isDisposed = true;
|
||||
}
|
||||
|
||||
getBlock(id: string): Block | undefined {
|
||||
@@ -705,16 +725,18 @@ export class Store {
|
||||
}
|
||||
|
||||
load(initFn?: () => void) {
|
||||
if (this.disposableGroup.disposed) {
|
||||
if (this._isDisposed) {
|
||||
this.disposableGroup = new DisposableGroup();
|
||||
this._subscribeToSlots();
|
||||
this._isDisposed = false;
|
||||
}
|
||||
|
||||
this._doc.load(initFn);
|
||||
this._provider.getAll(StoreExtensionIdentifier).forEach(ext => {
|
||||
ext.loaded();
|
||||
});
|
||||
this.slots.ready.emit();
|
||||
this.slots.ready.next();
|
||||
this.slots.rootAdded.next(this.root?.id ?? '');
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import type { Subject } from 'rxjs';
|
||||
|
||||
export type Tag = {
|
||||
id: string;
|
||||
@@ -39,8 +39,8 @@ export interface WorkspaceMeta {
|
||||
get docs(): unknown[] | undefined;
|
||||
initialize(): void;
|
||||
|
||||
commonFieldsUpdated: Slot;
|
||||
docMetaAdded: Slot<string>;
|
||||
docMetaRemoved: Slot<string>;
|
||||
docMetaUpdated: Slot;
|
||||
commonFieldsUpdated: Subject<void>;
|
||||
docMetaAdded: Subject<string>;
|
||||
docMetaRemoved: Subject<string>;
|
||||
docMetaUpdated: Subject<void>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import type { BlobEngine } from '@blocksuite/sync';
|
||||
import type { Subject } from 'rxjs';
|
||||
import type { Awareness } from 'y-protocols/awareness.js';
|
||||
import type * as Y from 'yjs';
|
||||
|
||||
@@ -20,9 +20,9 @@ export interface Workspace {
|
||||
get docs(): Map<string, Doc>;
|
||||
|
||||
slots: {
|
||||
docListUpdated: Slot;
|
||||
docCreated: Slot<string>;
|
||||
docRemoved: Slot<string>;
|
||||
docListUpdated: Subject<void>;
|
||||
docCreated: Subject<string>;
|
||||
docRemoved: Subject<string>;
|
||||
};
|
||||
|
||||
createDoc(options?: CreateBlocksOptions): Store;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import type { Subject } from 'rxjs';
|
||||
import {
|
||||
Array as YArray,
|
||||
Map as YMap,
|
||||
@@ -29,7 +29,7 @@ type CreateProxyOptions = {
|
||||
basePath?: string;
|
||||
onChange?: OnChange;
|
||||
transform: Transform;
|
||||
onDispose: Slot;
|
||||
onDispose: Subject<void>;
|
||||
shouldByPassSignal: () => boolean;
|
||||
shouldByPassYjs: () => boolean;
|
||||
byPassSignalUpdate: (fn: () => void) => void;
|
||||
@@ -113,17 +113,19 @@ function createProxy(
|
||||
}
|
||||
const signalData = signal(value);
|
||||
root[signalKey] = signalData;
|
||||
onDispose.once(
|
||||
signalData.subscribe(next => {
|
||||
if (!initialized()) {
|
||||
return;
|
||||
}
|
||||
byPassSignalUpdate(() => {
|
||||
proxy[p] = next;
|
||||
onChange?.(firstKey);
|
||||
});
|
||||
})
|
||||
);
|
||||
const unsubscribe = signalData.subscribe(next => {
|
||||
if (!initialized()) {
|
||||
return;
|
||||
}
|
||||
byPassSignalUpdate(() => {
|
||||
proxy[p] = next;
|
||||
onChange?.(firstKey);
|
||||
});
|
||||
});
|
||||
const subscription = onDispose.subscribe(() => {
|
||||
subscription.unsubscribe();
|
||||
unsubscribe();
|
||||
});
|
||||
return;
|
||||
}
|
||||
byPassSignalUpdate(() => {
|
||||
@@ -464,7 +466,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
|
||||
constructor(
|
||||
protected readonly _ySource: YMap<unknown>,
|
||||
private readonly _onDispose: Slot,
|
||||
private readonly _onDispose: Subject<void>,
|
||||
private readonly _onChange?: OnChange
|
||||
) {
|
||||
super();
|
||||
@@ -477,17 +479,19 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
Object.entries(source).forEach(([key, value]) => {
|
||||
const signalData = signal(value);
|
||||
source[`${key}$`] = signalData;
|
||||
_onDispose.once(
|
||||
signalData.subscribe(next => {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._updateWithSkip(() => {
|
||||
proxy[key] = next;
|
||||
this._onChange?.(key);
|
||||
});
|
||||
})
|
||||
);
|
||||
const unsubscribe = signalData.subscribe(next => {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._updateWithSkip(() => {
|
||||
proxy[key] = next;
|
||||
this._onChange?.(key);
|
||||
});
|
||||
});
|
||||
const subscription = _onDispose.subscribe(() => {
|
||||
subscription.unsubscribe();
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
this._proxy = proxy;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import { Subject } from 'rxjs';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import type { YBlock } from '../model/block/types.js';
|
||||
@@ -34,7 +34,7 @@ export class TestDoc implements Doc {
|
||||
|
||||
private readonly _historyObserver = () => {
|
||||
this._updateCanUndoRedoSignals();
|
||||
this.slots.historyUpdated.emit();
|
||||
this.slots.historyUpdated.next();
|
||||
};
|
||||
|
||||
private readonly _initSubDoc = () => {
|
||||
@@ -45,7 +45,7 @@ export class TestDoc implements Doc {
|
||||
});
|
||||
this.rootDoc.getMap('spaces').set(this.id, subDoc);
|
||||
this._loaded = true;
|
||||
this._onLoadSlot.emit();
|
||||
this._onLoadSlot.next();
|
||||
} else {
|
||||
this._loaded = false;
|
||||
this.rootDoc.on('subdocs', this._onSubdocEvent);
|
||||
@@ -56,7 +56,7 @@ export class TestDoc implements Doc {
|
||||
|
||||
private _loaded!: boolean;
|
||||
|
||||
private readonly _onLoadSlot = new Slot();
|
||||
private readonly _onLoadSlot = new Subject<void>();
|
||||
|
||||
private readonly _onSubdocEvent = ({
|
||||
loaded,
|
||||
@@ -71,7 +71,7 @@ export class TestDoc implements Doc {
|
||||
}
|
||||
this.rootDoc.off('subdocs', this._onSubdocEvent);
|
||||
this._loaded = true;
|
||||
this._onLoadSlot.emit();
|
||||
this._onLoadSlot.next();
|
||||
};
|
||||
|
||||
/** Indicate whether the block tree is ready */
|
||||
@@ -105,8 +105,8 @@ export class TestDoc implements Doc {
|
||||
readonly rootDoc: Y.Doc;
|
||||
|
||||
readonly slots = {
|
||||
historyUpdated: new Slot(),
|
||||
yBlockUpdated: new Slot<
|
||||
historyUpdated: new Subject<void>(),
|
||||
yBlockUpdated: new Subject<
|
||||
| {
|
||||
type: 'add';
|
||||
id: string;
|
||||
@@ -186,11 +186,11 @@ export class TestDoc implements Doc {
|
||||
}
|
||||
|
||||
private _handleYBlockAdd(id: string) {
|
||||
this.slots.yBlockUpdated.emit({ type: 'add', id });
|
||||
this.slots.yBlockUpdated.next({ type: 'add', id });
|
||||
}
|
||||
|
||||
private _handleYBlockDelete(id: string) {
|
||||
this.slots.yBlockUpdated.emit({ type: 'delete', id });
|
||||
this.slots.yBlockUpdated.next({ type: 'delete', id });
|
||||
}
|
||||
|
||||
private _handleYEvent(event: Y.YEvent<YBlock | Y.Text | Y.Array<unknown>>) {
|
||||
@@ -244,12 +244,12 @@ export class TestDoc implements Doc {
|
||||
|
||||
private _destroy() {
|
||||
this._ySpaceDoc.destroy();
|
||||
this._onLoadSlot.dispose();
|
||||
this._onLoadSlot.complete();
|
||||
this._loaded = false;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.slots.historyUpdated.dispose();
|
||||
this.slots.historyUpdated.complete();
|
||||
|
||||
if (this.ready) {
|
||||
this._yBlocks.unobserveDeep(this._handleYEvents);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { Subject } from 'rxjs';
|
||||
import type * as Y from 'yjs';
|
||||
|
||||
import type {
|
||||
@@ -45,15 +45,15 @@ export class TestMeta implements WorkspaceMeta {
|
||||
DocCollectionMetaState[keyof DocCollectionMetaState]
|
||||
>;
|
||||
|
||||
commonFieldsUpdated = new Slot();
|
||||
commonFieldsUpdated = new Subject<void>();
|
||||
|
||||
readonly doc: Y.Doc;
|
||||
|
||||
docMetaAdded = new Slot<string>();
|
||||
docMetaAdded = new Subject<string>();
|
||||
|
||||
docMetaRemoved = new Slot<string>();
|
||||
docMetaRemoved = new Subject<string>();
|
||||
|
||||
docMetaUpdated = new Slot();
|
||||
docMetaUpdated = new Subject<void>();
|
||||
|
||||
readonly id: string = 'meta';
|
||||
|
||||
@@ -103,7 +103,7 @@ export class TestMeta implements WorkspaceMeta {
|
||||
}
|
||||
|
||||
private _handleCommonFieldsEvent() {
|
||||
this.commonFieldsUpdated.emit();
|
||||
this.commonFieldsUpdated.next();
|
||||
}
|
||||
|
||||
private _handleDocMetaEvent() {
|
||||
@@ -113,7 +113,7 @@ export class TestMeta implements WorkspaceMeta {
|
||||
|
||||
docMetas.forEach(docMeta => {
|
||||
if (!_prevDocs.has(docMeta.id)) {
|
||||
this.docMetaAdded.emit(docMeta.id);
|
||||
this.docMetaAdded.next(docMeta.id);
|
||||
}
|
||||
newDocs.add(docMeta.id);
|
||||
});
|
||||
@@ -121,13 +121,13 @@ export class TestMeta implements WorkspaceMeta {
|
||||
_prevDocs.forEach(prevDocId => {
|
||||
const isRemoved = newDocs.has(prevDocId) === false;
|
||||
if (isRemoved) {
|
||||
this.docMetaRemoved.emit(prevDocId);
|
||||
this.docMetaRemoved.next(prevDocId);
|
||||
}
|
||||
});
|
||||
|
||||
this._prevDocs = newDocs;
|
||||
|
||||
this.docMetaUpdated.emit();
|
||||
this.docMetaUpdated.next();
|
||||
}
|
||||
|
||||
addDocMeta(doc: DocMeta, index?: number) {
|
||||
@@ -204,6 +204,6 @@ export class TestMeta implements WorkspaceMeta {
|
||||
|
||||
setProperties(meta: DocsPropertiesMeta) {
|
||||
this._proxy.properties = meta;
|
||||
this.docMetaUpdated.emit();
|
||||
this.docMetaUpdated.next();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { NoopLogger } from '@blocksuite/global/utils';
|
||||
import {
|
||||
AwarenessEngine,
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
MemoryBlobSource,
|
||||
NoopDocSource,
|
||||
} from '@blocksuite/sync';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Awareness } from 'y-protocols/awareness.js';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
@@ -67,9 +67,9 @@ export class TestWorkspace implements Workspace {
|
||||
meta: WorkspaceMeta;
|
||||
|
||||
slots = {
|
||||
docListUpdated: new Slot(),
|
||||
docRemoved: new Slot<string>(),
|
||||
docCreated: new Slot<string>(),
|
||||
docListUpdated: new Subject<void>(),
|
||||
docRemoved: new Subject<string>(),
|
||||
docCreated: new Subject<string>(),
|
||||
};
|
||||
|
||||
get docs() {
|
||||
@@ -116,7 +116,7 @@ export class TestWorkspace implements Workspace {
|
||||
}
|
||||
|
||||
private _bindDocMetaEvents() {
|
||||
this.meta.docMetaAdded.on(docId => {
|
||||
this.meta.docMetaAdded.subscribe(docId => {
|
||||
const doc = new TestDoc({
|
||||
id: docId,
|
||||
collection: this,
|
||||
@@ -126,14 +126,14 @@ export class TestWorkspace implements Workspace {
|
||||
this.blockCollections.set(doc.id, doc);
|
||||
});
|
||||
|
||||
this.meta.docMetaUpdated.on(() => this.slots.docListUpdated.emit());
|
||||
this.meta.docMetaUpdated.subscribe(() => this.slots.docListUpdated.next());
|
||||
|
||||
this.meta.docMetaRemoved.on(id => {
|
||||
this.meta.docMetaRemoved.subscribe(id => {
|
||||
const space = this.getBlockCollection(id);
|
||||
if (!space) return;
|
||||
this.blockCollections.delete(id);
|
||||
space.remove();
|
||||
this.slots.docRemoved.emit(id);
|
||||
this.slots.docRemoved.next(id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ export class TestWorkspace implements Workspace {
|
||||
createDate: Date.now(),
|
||||
tags: [],
|
||||
});
|
||||
this.slots.docCreated.emit(docId);
|
||||
this.slots.docCreated.next(docId);
|
||||
return this.getDoc(docId, {
|
||||
id: docId,
|
||||
query,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Slot } from '@blocksuite/global/slot';
|
||||
import type { Subject } from 'rxjs';
|
||||
|
||||
import type { BlockModel, DraftModel, Store } from '../model/index.js';
|
||||
import type { AssetsManager } from './assets.js';
|
||||
@@ -95,10 +95,10 @@ export type AfterImportPayload =
|
||||
};
|
||||
|
||||
export type TransformerSlots = {
|
||||
beforeImport: Slot<BeforeImportPayload>;
|
||||
afterImport: Slot<AfterImportPayload>;
|
||||
beforeExport: Slot<BeforeExportPayload>;
|
||||
afterExport: Slot<AfterExportPayload>;
|
||||
beforeImport: Subject<BeforeImportPayload>;
|
||||
afterImport: Subject<AfterImportPayload>;
|
||||
beforeExport: Subject<BeforeExportPayload>;
|
||||
afterExport: Subject<AfterExportPayload>;
|
||||
};
|
||||
|
||||
type TransformerMiddlewareOptions = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Slot } from '@blocksuite/global/slot';
|
||||
import { nextTick } from '@blocksuite/global/utils';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import {
|
||||
BlockModel,
|
||||
@@ -68,10 +68,10 @@ export class Transformer {
|
||||
private readonly _docCRUD: DocCRUD;
|
||||
|
||||
private readonly _slots: TransformerSlots = {
|
||||
beforeImport: new Slot<BeforeImportPayload>(),
|
||||
afterImport: new Slot<AfterImportPayload>(),
|
||||
beforeExport: new Slot<BeforeExportPayload>(),
|
||||
afterExport: new Slot<AfterExportPayload>(),
|
||||
beforeImport: new Subject<BeforeImportPayload>(),
|
||||
afterImport: new Subject<AfterImportPayload>(),
|
||||
beforeExport: new Subject<BeforeExportPayload>(),
|
||||
afterExport: new Subject<AfterExportPayload>(),
|
||||
};
|
||||
|
||||
blockToSnapshot = (
|
||||
@@ -99,7 +99,7 @@ export class Transformer {
|
||||
|
||||
docToSnapshot = (doc: Store): DocSnapshot | undefined => {
|
||||
try {
|
||||
this._slots.beforeExport.emit({
|
||||
this._slots.beforeExport.next({
|
||||
type: 'page',
|
||||
page: doc,
|
||||
});
|
||||
@@ -120,7 +120,7 @@ export class Transformer {
|
||||
meta,
|
||||
blocks,
|
||||
};
|
||||
this._slots.afterExport.emit({
|
||||
this._slots.afterExport.next({
|
||||
type: 'page',
|
||||
page: doc,
|
||||
snapshot: docSnapshot,
|
||||
@@ -137,7 +137,7 @@ export class Transformer {
|
||||
|
||||
sliceToSnapshot = (slice: Slice): SliceSnapshot | undefined => {
|
||||
try {
|
||||
this._slots.beforeExport.emit({
|
||||
this._slots.beforeExport.next({
|
||||
type: 'slice',
|
||||
slice,
|
||||
});
|
||||
@@ -156,7 +156,7 @@ export class Transformer {
|
||||
pageId,
|
||||
content: contentSnapshot,
|
||||
};
|
||||
this._slots.afterExport.emit({
|
||||
this._slots.afterExport.next({
|
||||
type: 'slice',
|
||||
slice,
|
||||
snapshot,
|
||||
@@ -191,7 +191,7 @@ export class Transformer {
|
||||
|
||||
snapshotToDoc = async (snapshot: DocSnapshot): Promise<Store | undefined> => {
|
||||
try {
|
||||
this._slots.beforeImport.emit({
|
||||
this._slots.beforeImport.next({
|
||||
type: 'page',
|
||||
snapshot,
|
||||
});
|
||||
@@ -200,7 +200,7 @@ export class Transformer {
|
||||
const doc = this.docCRUD.create(meta.id);
|
||||
doc.load();
|
||||
await this.snapshotToBlock(blocks, doc);
|
||||
this._slots.afterImport.emit({
|
||||
this._slots.afterImport.next({
|
||||
type: 'page',
|
||||
snapshot,
|
||||
page: doc,
|
||||
@@ -247,7 +247,7 @@ export class Transformer {
|
||||
): Promise<Slice | undefined> => {
|
||||
SliceSnapshotSchema.parse(snapshot);
|
||||
try {
|
||||
this._slots.beforeImport.emit({
|
||||
this._slots.beforeImport.next({
|
||||
type: 'slice',
|
||||
snapshot,
|
||||
});
|
||||
@@ -303,7 +303,7 @@ export class Transformer {
|
||||
pageId,
|
||||
});
|
||||
|
||||
this._slots.afterImport.emit({
|
||||
this._slots.afterImport.next({
|
||||
type: 'slice',
|
||||
snapshot,
|
||||
slice,
|
||||
@@ -376,7 +376,7 @@ export class Transformer {
|
||||
}
|
||||
|
||||
private _blockToSnapshot(model: DraftModel): BlockSnapshot | null {
|
||||
this._slots.beforeExport.emit({
|
||||
this._slots.beforeExport.next({
|
||||
type: 'block',
|
||||
model,
|
||||
});
|
||||
@@ -397,7 +397,7 @@ export class Transformer {
|
||||
...snapshotLeaf,
|
||||
children,
|
||||
};
|
||||
this._slots.afterExport.emit({
|
||||
this._slots.afterExport.next({
|
||||
type: 'block',
|
||||
model,
|
||||
snapshot,
|
||||
@@ -539,7 +539,7 @@ export class Transformer {
|
||||
);
|
||||
}
|
||||
|
||||
this._slots.afterImport.emit({
|
||||
this._slots.afterImport.next({
|
||||
type: 'block',
|
||||
model,
|
||||
snapshot: node.snapshot,
|
||||
@@ -627,7 +627,7 @@ export class Transformer {
|
||||
parent?: string,
|
||||
index?: number
|
||||
) => {
|
||||
this._slots.beforeImport.emit({
|
||||
this._slots.beforeImport.next({
|
||||
type: 'block',
|
||||
snapshot: node,
|
||||
parent: parent,
|
||||
|
||||
Reference in New Issue
Block a user