feat(editor): replace slot with rxjs subject (#10768)

This commit is contained in:
Mirone
2025-03-12 11:29:24 +09:00
committed by GitHub
parent 19f978d9aa
commit cd63e0ed8b
302 changed files with 1405 additions and 1251 deletions

View File

@@ -1,5 +1,5 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import { IS_ANDROID, IS_MAC } from '@blocksuite/global/env';
import { DisposableGroup } from '@blocksuite/global/slot';
import {
type UIEventHandler,

View File

@@ -1,5 +1,5 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { DisposableGroup } from '@blocksuite/global/slot';
import { LifeCycleWatcher } from '../extension/index.js';
import { KeymapIdentifier } from '../identifier.js';

View File

@@ -1,4 +1,5 @@
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { Subject } from 'rxjs';
import type { BlockStdScope } from '../scope/block-std-scope';
import { LifeCycleWatcher } from './lifecycle-watcher';
@@ -9,10 +10,10 @@ export class EditorLifeCycleExtension extends LifeCycleWatcher {
disposables = new DisposableGroup();
readonly slots = {
created: new Slot(),
mounted: new Slot(),
rendered: new Slot(),
unmounted: new Slot(),
created: new Subject<void>(),
mounted: new Subject<void>(),
rendered: new Subject<void>(),
unmounted: new Subject<void>(),
};
constructor(override readonly std: BlockStdScope) {
@@ -26,22 +27,22 @@ export class EditorLifeCycleExtension extends LifeCycleWatcher {
override created() {
super.created();
this.slots.created.emit();
this.slots.created.next();
}
override mounted() {
super.mounted();
this.slots.mounted.emit();
this.slots.mounted.next();
}
override rendered() {
super.rendered();
this.slots.rendered.emit();
this.slots.rendered.next();
}
override unmounted() {
super.unmounted();
this.slots.unmounted.emit();
this.slots.unmounted.next();
this.disposables.dispose();
}

View File

@@ -1,6 +1,6 @@
import type { Container } from '@blocksuite/global/di';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { DisposableGroup } from '@blocksuite/global/slot';
import { Extension } from '@blocksuite/store';
import type { EventName, UIEventHandler } from '../event/index.js';
@@ -109,12 +109,12 @@ export abstract class BlockService extends Extension {
// life cycle end
mounted() {
this.specSlots.mounted.emit({ service: this });
this.specSlots.mounted.next({ service: this });
}
unmounted() {
this.dispose();
this.specSlots.unmounted.emit({ service: this });
this.specSlots.unmounted.next({ service: this });
}
// event handlers end
}

View File

@@ -1,10 +1,10 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import {
Bound,
getCommonBound,
getCommonBoundWithRotation,
type IBound,
} from '@blocksuite/global/gfx';
import { DisposableGroup } from '@blocksuite/global/slot';
import { assertType } from '@blocksuite/global/utils';
import type { BlockModel } from '@blocksuite/store';
import { Signal } from '@preact/signals-core';

View File

@@ -1,10 +1,10 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import type { IBound } from '@blocksuite/global/gfx';
import {
Bound,
getBoundWithRotation,
intersects,
} from '@blocksuite/global/gfx';
import { DisposableGroup } from '@blocksuite/global/slot';
import type { BlockModel } from '@blocksuite/store';
import { compare } from '../utils/layer.js';
@@ -385,7 +385,7 @@ export class GridManager extends GfxExtension {
};
disposables.add(
store.slots.blockUpdated.on(payload => {
store.slots.blockUpdated.subscribe(payload => {
if (payload.type === 'add' && canBeRenderedAsGfxBlock(payload.model)) {
this.add(payload.model);
}
@@ -441,19 +441,19 @@ export class GridManager extends GfxExtension {
);
disposables.add(
surface.elementAdded.on(payload => {
surface.elementAdded.subscribe(payload => {
this.add(surface.getElementById(payload.id)!);
})
);
disposables.add(
surface.elementRemoved.on(payload => {
surface.elementRemoved.subscribe(payload => {
this.remove(payload.model);
})
);
disposables.add(
surface.elementUpdated.on(payload => {
surface.elementUpdated.subscribe(payload => {
if (
payload.props['xywh'] ||
payload.props['externalXYWH'] ||
@@ -465,13 +465,13 @@ export class GridManager extends GfxExtension {
);
disposables.add(
surface.localElementAdded.on(elm => {
surface.localElementAdded.subscribe(elm => {
this.add(elm);
})
);
disposables.add(
surface.localElementUpdated.on(payload => {
surface.localElementUpdated.subscribe(payload => {
if (payload.props['xywh'] || payload.props['responseExtension']) {
this.update(payload.model);
}
@@ -479,7 +479,7 @@ export class GridManager extends GfxExtension {
);
disposables.add(
surface.localElementDeleted.on(elm => {
surface.localElementDeleted.subscribe(elm => {
this.remove(elm);
})
);

View File

@@ -1,4 +1,4 @@
import { DisposableGroup } from '@blocksuite/global/slot';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { Signal } from '@preact/signals-core';
import type { BlockStdScope } from '../scope/block-std-scope.js';

View File

@@ -1,8 +1,9 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import { Bound } from '@blocksuite/global/gfx';
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { assertType } from '@blocksuite/global/utils';
import { generateKeyBetween } from 'fractional-indexing';
import last from 'lodash-es/last';
import { Subject } from 'rxjs';
import {
compare,
@@ -101,7 +102,7 @@ export class LayerManager extends GfxExtension {
layers: Layer[] = [];
slots = {
layerUpdated: new Slot<{
layerUpdated: new Subject<{
type: 'delete' | 'add' | 'update';
initiatingElement: GfxModel | GfxLocalElementModel;
}>(),
@@ -588,7 +589,7 @@ export class LayerManager extends GfxExtension {
element.childElements.forEach(child => child && this._updateLayer(child));
}
this._buildCanvasLayers();
this.slots.layerUpdated.emit({
this.slots.layerUpdated.next({
type: 'add',
initiatingElement: element,
});
@@ -650,7 +651,7 @@ export class LayerManager extends GfxExtension {
if (isGroup) {
this._reset();
this.slots.layerUpdated.emit({
this.slots.layerUpdated.next({
type: 'delete',
initiatingElement: element as GfxModel,
});
@@ -673,14 +674,14 @@ export class LayerManager extends GfxExtension {
this._removeFromLayer(element, deleteType);
this._buildCanvasLayers();
this.slots.layerUpdated.emit({
this.slots.layerUpdated.next({
type: 'delete',
initiatingElement: element,
});
}
override unmounted() {
this.slots.layerUpdated.dispose();
this.slots.layerUpdated.complete();
this._disposable.dispose();
}
@@ -784,7 +785,7 @@ export class LayerManager extends GfxExtension {
) {
if (this._updateLayer(element, props)) {
this._buildCanvasLayers();
this.slots.layerUpdated.emit({
this.slots.layerUpdated.next({
type: 'update',
initiatingElement: element,
});
@@ -795,7 +796,7 @@ export class LayerManager extends GfxExtension {
const store = this._doc;
this._disposable.add(
store.slots.blockUpdated.on(payload => {
store.slots.blockUpdated.subscribe(payload => {
if (payload.type === 'add') {
const block = store.getBlockById(payload.id)!;
@@ -854,34 +855,34 @@ export class LayerManager extends GfxExtension {
);
this._disposable.add(
surface.elementAdded.on(payload =>
surface.elementAdded.subscribe(payload =>
this.add(surface.getElementById(payload.id)!)
)
);
this._disposable.add(
surface.elementUpdated.on(payload => {
surface.elementUpdated.subscribe(payload => {
if (payload.props['index'] || payload.props['childIds']) {
this.update(surface.getElementById(payload.id)!, payload.props);
}
})
);
this._disposable.add(
surface.elementRemoved.on(payload => this.delete(payload.model!))
surface.elementRemoved.subscribe(payload => this.delete(payload.model!))
);
this._disposable.add(
surface.localElementAdded.on(elm => {
surface.localElementAdded.subscribe(elm => {
this.add(elm);
})
);
this._disposable.add(
surface.localElementUpdated.on(payload => {
surface.localElementUpdated.subscribe(payload => {
if (payload.props['index'] || payload.props['groupId']) {
this.update(payload.model, payload.props);
}
})
);
this._disposable.add(
surface.localElementDeleted.on(elm => {
surface.localElementDeleted.subscribe(elm => {
this.delete(elm);
})
);

View File

@@ -39,7 +39,7 @@ function startWatch(prop: string | symbol, receiver: GfxPrimitiveElementModel) {
if (!watchFn) return;
receiver['_disposable'].add(
receiver.surface.elementUpdated.on(payload => {
receiver.surface.elementUpdated.subscribe(payload => {
if (payload.id === receiver.id && prop in payload.props) {
watchFn(payload.oldValues[prop as string], receiver, payload.local);
}

View File

@@ -1,3 +1,4 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import {
Bound,
deserializeXYWH,
@@ -13,9 +14,9 @@ import {
type SerializedXYWH,
type XYWH,
} from '@blocksuite/global/gfx';
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { createMutex } from 'lib0/mutex';
import isEqual from 'lodash-es/isEqual';
import { Subject } from 'rxjs';
import * as Y from 'yjs';
import {
@@ -86,7 +87,7 @@ export abstract class GfxPrimitiveElementModel<
protected _stashed: Map<keyof Props | string, unknown>;
propsUpdated = new Slot<{ key: string }>();
propsUpdated = new Subject<{ key: string }>();
abstract rotate: number;
@@ -262,7 +263,7 @@ export abstract class GfxPrimitiveElementModel<
onDestroyed() {
this._disposable.dispose();
this.propsUpdated.dispose();
this.propsUpdated.complete();
}
pop(prop: keyof Props | string) {

View File

@@ -142,7 +142,7 @@ export abstract class GfxLocalElementModel implements GfxCompatibleInterface {
if (surfaceModel.localElementModels.has(p)) {
this._mutex(() => {
surfaceModel.localElementUpdated.emit({
surfaceModel.localElementUpdated.next({
model: p,
props: {
[prop as string]: value,

View File

@@ -1,8 +1,9 @@
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { assertType, type Constructor } from '@blocksuite/global/utils';
import type { Boxed } from '@blocksuite/store';
import { BlockModel, nanoid } from '@blocksuite/store';
import { signal } from '@preact/signals-core';
import { Subject } from 'rxjs';
import * as Y from 'yjs';
import {
@@ -77,24 +78,24 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
protected _surfaceBlockModel = true;
elementAdded = new Slot<{ id: string; local: boolean }>();
protected localElements = new Set<GfxLocalElementModel>();
elementRemoved = new Slot<{
elementAdded = new Subject<{ id: string; local: boolean }>();
elementRemoved = new Subject<{
id: string;
type: string;
model: GfxPrimitiveElementModel;
local: boolean;
}>();
elementUpdated = new Slot<ElementUpdatedData>();
elementUpdated = new Subject<ElementUpdatedData>();
localElementAdded = new Slot<GfxLocalElementModel>();
localElementAdded = new Subject<GfxLocalElementModel>();
localElementDeleted = new Slot<GfxLocalElementModel>();
localElementDeleted = new Subject<GfxLocalElementModel>();
protected localElements = new Set<GfxLocalElementModel>();
localElementUpdated = new Slot<{
localElementUpdated = new Subject<{
model: GfxLocalElementModel;
props: Record<string, unknown>;
oldValues: Record<string, unknown>;
@@ -122,7 +123,10 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
constructor() {
super();
this.created.once(() => this._init());
const subscription = this.created.subscribe(() => {
this._init();
subscription.unsubscribe();
});
}
private _createElementFromProps(
@@ -296,9 +300,9 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
element,
{
onChange: payload => {
this.elementUpdated.emit(payload);
this.elementUpdated.next(payload);
Object.keys(payload.props).forEach(key => {
model.model.propsUpdated.emit({ key });
model.model.propsUpdated.next({ key });
});
},
skipFieldInit: true,
@@ -323,11 +327,11 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
addedElements.forEach(({ mount, model }) => {
mount();
this.elementAdded.emit({ id: model.id, local: transaction.local });
this.elementAdded.next({ id: model.id, local: transaction.local });
});
deletedElements.forEach(({ unmount, model }) => {
unmount();
this.elementRemoved.emit({
this.elementRemoved.next({
id: model.id,
type: model.type,
model,
@@ -343,9 +347,9 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
val,
{
onChange: payload => {
this.elementUpdated.emit(payload),
this.elementUpdated.next(payload),
Object.keys(payload.props).forEach(key => {
model.model.propsUpdated.emit({ key });
model.model.propsUpdated.next({ key });
});
},
skipFieldInit: true,
@@ -368,7 +372,7 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
elementsYMap.observe(onElementsMapChange);
const disposable = this.doc.slots.blockUpdated.on(payload => {
const subscription = this.doc.slots.blockUpdated.subscribe(payload => {
switch (payload.type) {
case 'add':
if (isGfxGroupCompatibleModel(payload.model)) {
@@ -392,9 +396,9 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
}
});
this.deleted.on(() => {
this.deleted.subscribe(() => {
elementsYMap.unobserve(onElementsMapChange);
disposable.dispose();
subscription.unsubscribe();
});
}
@@ -435,7 +439,7 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
): element is GfxGroupLikeElementModel =>
element instanceof GfxGroupLikeElementModel;
const disposable = this.elementUpdated.on(({ id, oldValues }) => {
const disposable = this.elementUpdated.subscribe(({ id, oldValues }) => {
const element = this.getElementById(id)!;
if (
@@ -446,8 +450,8 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
this.deleteElement(id);
}
});
this.deleted.on(() => {
disposable.dispose();
this.deleted.subscribe(() => {
disposable.unsubscribe();
});
}
@@ -458,14 +462,14 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
};
const disposables = new DisposableGroup();
disposables.add(this.elementAdded.on(updateIsEmpty));
disposables.add(this.elementRemoved.on(updateIsEmpty));
this.doc.slots.blockUpdated.on(payload => {
disposables.add(this.elementAdded.subscribe(updateIsEmpty));
disposables.add(this.elementRemoved.subscribe(updateIsEmpty));
this.doc.slots.blockUpdated.subscribe(payload => {
if (['add', 'delete'].includes(payload.type)) {
updateIsEmpty();
}
});
this.deleted.on(() => {
this.deleted.subscribe(() => {
disposables.dispose();
});
}
@@ -518,9 +522,9 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
const elementModel = this._createElementFromProps(props, {
onChange: payload => {
this.elementUpdated.emit(payload);
this.elementUpdated.next(payload);
Object.keys(payload.props).forEach(key => {
elementModel.model.propsUpdated.emit({ key });
elementModel.model.propsUpdated.next({ key });
});
},
});
@@ -536,7 +540,7 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
addLocalElement(elem: GfxLocalElementModel) {
this.localElements.add(elem);
this.localElementAdded.emit(elem);
this.localElementAdded.next(elem);
}
applyMiddlewares(middlewares: SurfaceMiddleware[]) {
@@ -575,16 +579,16 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
deleteLocalElement(elem: GfxLocalElementModel) {
if (this.localElements.delete(elem)) {
this.localElementDeleted.emit(elem);
this.localElementDeleted.next(elem);
}
}
override dispose(): void {
super.dispose();
this.elementAdded.dispose();
this.elementRemoved.dispose();
this.elementUpdated.dispose();
this.elementAdded.complete();
this.elementRemoved.complete();
this.elementUpdated.complete();
this._elementModels.forEach(({ unmount }) => unmount());
this._elementModels.clear();

View File

@@ -1,10 +1,11 @@
import { DisposableGroup } from '@blocksuite/global/disposable';
import {
getCommonBoundWithRotation,
type IPoint,
} from '@blocksuite/global/gfx';
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { assertType } from '@blocksuite/global/utils';
import groupBy from 'lodash-es/groupBy';
import { Subject } from 'rxjs';
import {
BlockSelection,
@@ -60,11 +61,11 @@ export class GfxSelectionManager extends GfxExtension {
disposable: DisposableGroup = new DisposableGroup();
readonly slots = {
updated: new Slot<SurfaceSelection[]>(),
remoteUpdated: new Slot(),
updated: new Subject<SurfaceSelection[]>(),
remoteUpdated: new Subject<void>(),
cursorUpdated: new Slot<CursorSelection>(),
remoteCursorUpdated: new Slot(),
cursorUpdated: new Subject<CursorSelection>(),
remoteCursorUpdated: new Subject<void>(),
};
get activeGroup() {
@@ -217,7 +218,7 @@ export class GfxSelectionManager extends GfxExtension {
override mounted() {
this.disposable.add(
this.stdSelection.slots.changed.on(selections => {
this.stdSelection.slots.changed.subscribe(selections => {
const { cursor = [], surface = [] } = groupBy(selections, sel => {
if (sel.is(SurfaceSelection)) {
return 'surface';
@@ -233,7 +234,7 @@ export class GfxSelectionManager extends GfxExtension {
if (cursor[0] && !this.cursorSelection?.equals(cursor[0])) {
this._cursorSelection = cursor[0];
this.slots.cursorUpdated.emit(cursor[0]);
this.slots.cursorUpdated.next(cursor[0]);
}
if ((surface.length === 0 && this.empty) || this.equals(surface)) {
@@ -250,12 +251,12 @@ export class GfxSelectionManager extends GfxExtension {
})
);
this.slots.updated.emit(this.surfaceSelections);
this.slots.updated.next(this.surfaceSelections);
})
);
this.disposable.add(
this.stdSelection.slots.remoteChanged.on(states => {
this.stdSelection.slots.remoteChanged.subscribe(states => {
const surfaceMap = new Map<number, SurfaceSelection[]>();
const cursorMap = new Map<number, CursorSelection>();
const selectedSet = new Set<string>();
@@ -299,8 +300,8 @@ export class GfxSelectionManager extends GfxExtension {
this._remoteSurfaceSelectionsMap = surfaceMap;
this._remoteSelectedSet = selectedSet;
this.slots.remoteUpdated.emit();
this.slots.remoteCursorUpdated.emit();
this.slots.remoteUpdated.next();
this.slots.remoteCursorUpdated.next();
})
);
}

View File

@@ -1,8 +1,9 @@
import type { ServiceIdentifier } from '@blocksuite/global/di';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { IBound, IPoint } from '@blocksuite/global/gfx';
import { DisposableGroup, Slot } from '@blocksuite/global/slot';
import { Signal } from '@preact/signals-core';
import { Subject } from 'rxjs';
import type { PointerEventState } from '../../event/index.js';
import type { GfxController } from '../controller.js';
@@ -79,7 +80,7 @@ export const eventTarget = Symbol('eventTarget');
export class ToolController extends GfxExtension {
static override key = 'ToolController';
private readonly _builtInHookSlot = new Slot<BuiltInSlotContext>();
private readonly _builtInHookSlot = new Subject<BuiltInSlotContext>();
private readonly _disposableGroup = new DisposableGroup();
@@ -441,7 +442,7 @@ export class ToolController extends GfxExtension {
);
});
this._builtInHookSlot.on(evt => {
this._builtInHookSlot.subscribe(evt => {
hooks[evt.event]?.forEach(hook => hook(evt));
});
@@ -499,7 +500,7 @@ export class ToolController extends GfxExtension {
const beforeUpdateCtx = this._createBuiltInHookCtx('beforeToolUpdate', {
toolName: toolNameStr,
});
this._builtInHookSlot.emit(beforeUpdateCtx.slotCtx);
this._builtInHookSlot.next(beforeUpdateCtx.slotCtx);
if (beforeUpdateCtx.prevented) {
return;
@@ -528,7 +529,7 @@ export class ToolController extends GfxExtension {
const afterUpdateCtx = this._createBuiltInHookCtx('toolUpdate', {
toolName: toolNameStr,
});
this._builtInHookSlot.emit(afterUpdateCtx.slotCtx);
this._builtInHookSlot.next(afterUpdateCtx.slotCtx);
}
override unmounted(): void {
@@ -537,7 +538,7 @@ export class ToolController extends GfxExtension {
tool.unmounted();
tool['disposable'].dispose();
});
this._builtInHookSlot.dispose();
this._builtInHookSlot.complete();
}
}

View File

@@ -1,6 +1,6 @@
import { type Container, createIdentifier } from '@blocksuite/global/di';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { DisposableGroup } from '@blocksuite/global/slot';
import { Extension } from '@blocksuite/store';
import type { PointerEventState } from '../../event/index.js';

View File

@@ -1,4 +1,4 @@
import { DisposableGroup } from '@blocksuite/global/slot';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { onSurfaceAdded } from '../../utils/gfx.js';
import type { GfxController } from '../controller.js';
@@ -70,14 +70,14 @@ export class ViewManager extends GfxExtension {
};
this._disposable.add(
surface.elementAdded.on(payload => {
surface.elementAdded.subscribe(payload => {
const model = surface.getElementById(payload.id)!;
createView(model);
})
);
this._disposable.add(
surface.elementRemoved.on(elem => {
surface.elementRemoved.subscribe(elem => {
const view = this._viewMap.get(elem.id);
this._viewMap.delete(elem.id);
view?.onDestroyed();
@@ -85,13 +85,13 @@ export class ViewManager extends GfxExtension {
);
this._disposable.add(
surface.localElementAdded.on(model => {
surface.localElementAdded.subscribe(model => {
createView(model);
})
);
this._disposable.add(
surface.localElementDeleted.on(model => {
surface.localElementDeleted.subscribe(model => {
const view = this._viewMap.get(model.id);
this._viewMap.delete(model.id);
view?.onDestroyed();

View File

@@ -1,7 +1,7 @@
import { type Container, createIdentifier } from '@blocksuite/global/di';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { Bound, IVec } from '@blocksuite/global/gfx';
import { DisposableGroup } from '@blocksuite/global/slot';
import type { Extension } from '@blocksuite/store';
import type { PointerEventState } from '../../event/index.js';

View File

@@ -131,10 +131,10 @@ export class GfxViewportElement extends WithDisposable(ShadowlessElement) {
this._hideOutsideBlock();
this.disposables.add(
this.viewport.viewportUpdated.on(() => viewportUpdateCallback())
this.viewport.viewportUpdated.subscribe(() => viewportUpdateCallback())
);
this.disposables.add(
this.viewport.sizeUpdated.on(() => viewportUpdateCallback())
this.viewport.sizeUpdated.subscribe(() => viewportUpdateCallback())
);
}

View File

@@ -5,9 +5,9 @@ import {
type IVec,
Vec,
} from '@blocksuite/global/gfx';
import { Slot } from '@blocksuite/global/slot';
import { signal } from '@preact/signals-core';
import debounce from 'lodash-es/debounce';
import { Subject } from 'rxjs';
import type { GfxViewportElement } from '.';
@@ -74,18 +74,18 @@ export class Viewport {
protected _zoom: number = 1.0;
elementReady = new Slot<GfxViewportElement>();
elementReady = new Subject<GfxViewportElement>();
sizeUpdated = new Slot<{
sizeUpdated = new Subject<{
width: number;
height: number;
left: number;
top: number;
}>();
viewportMoved = new Slot<IVec>();
viewportMoved = new Subject<IVec>();
viewportUpdated = new Slot<{
viewportUpdated = new Subject<{
zoom: number;
center: IVec;
}>();
@@ -106,7 +106,10 @@ export class Viewport {
}, 200);
constructor() {
this.elementReady.once(el => (this._element = el));
const subscription = this.elementReady.subscribe(el => {
this._element = el;
subscription.unsubscribe();
});
}
get boundingClientRect() {
@@ -233,9 +236,9 @@ export class Viewport {
dispose() {
this.clearViewportElement();
this.sizeUpdated.dispose();
this.viewportMoved.dispose();
this.viewportUpdated.dispose();
this.sizeUpdated.complete();
this.viewportMoved.complete();
this.viewportUpdated.complete();
this.zooming$.value = false;
this.panning$.value = false;
}
@@ -296,7 +299,7 @@ export class Viewport {
this._center.x = centerX;
this._center.y = centerY;
this.panning$.value = true;
this.viewportUpdated.emit({
this.viewportUpdated.next({
zoom: this.zoom,
center: Vec.toVec(this.center) as IVec,
});
@@ -306,7 +309,7 @@ export class Viewport {
setRect(left: number, top: number, width: number, height: number) {
this._left = left;
this._top = top;
this.sizeUpdated.emit({
this.sizeUpdated.next({
left,
top,
width,
@@ -420,7 +423,7 @@ export class Viewport {
this.zooming$.value = true;
}
this.setCenter(newCenter[0], newCenter[1]);
this.viewportUpdated.emit({
this.viewportUpdated.next({
zoom: this.zoom,
center: Vec.toVec(this.center) as IVec,
});

View File

@@ -87,7 +87,7 @@ export const getInlineRangeProvider: (
const inlineRange$: InlineRangeProvider['inlineRange$'] = signal(null);
editorHost.disposables.add(
selectionManager.slots.changed.on(selections => {
selectionManager.slots.changed.subscribe(selections => {
if (!isActiveInEditor(editorHost)) return;
const textSelection = selections.find(s => s.type === 'text') as

View File

@@ -313,7 +313,7 @@ export class RangeBinding {
constructor(public manager: RangeManager) {
this.host.disposables.add(
this.selectionManager.slots.changed.on(this._onStdSelectionChanged)
this.selectionManager.slots.changed.subscribe(this._onStdSelectionChanged)
);
this.host.disposables.addFromEvent(

View File

@@ -1,15 +1,15 @@
import { Slot } from '@blocksuite/global/slot';
import { Subject } from 'rxjs';
import type { BlockService } from '../extension/service.js';
import type { BlockComponent, WidgetComponent } from '../view/index.js';
export type BlockSpecSlots<Service extends BlockService = BlockService> = {
mounted: Slot<{ service: Service }>;
unmounted: Slot<{ service: Service }>;
viewConnected: Slot<{ component: BlockComponent; service: Service }>;
viewDisconnected: Slot<{ component: BlockComponent; service: Service }>;
widgetConnected: Slot<{ component: WidgetComponent; service: Service }>;
widgetDisconnected: Slot<{
mounted: Subject<{ service: Service }>;
unmounted: Subject<{ service: Service }>;
viewConnected: Subject<{ component: BlockComponent; service: Service }>;
viewDisconnected: Subject<{ component: BlockComponent; service: Service }>;
widgetConnected: Subject<{ component: WidgetComponent; service: Service }>;
widgetDisconnected: Subject<{
component: WidgetComponent;
service: Service;
}>;
@@ -17,11 +17,11 @@ export type BlockSpecSlots<Service extends BlockService = BlockService> = {
export const getSlots = (): BlockSpecSlots => {
return {
mounted: new Slot(),
unmounted: new Slot(),
viewConnected: new Slot(),
viewDisconnected: new Slot(),
widgetConnected: new Slot(),
widgetDisconnected: new Slot(),
mounted: new Subject(),
unmounted: new Subject(),
viewConnected: new Subject(),
viewDisconnected: new Subject(),
widgetConnected: new Subject(),
widgetDisconnected: new Subject(),
};
};

View File

@@ -214,21 +214,23 @@ export class BlockComponent<
this.std.view.setBlock(this);
const disposable = this.std.store.slots.blockUpdated.on(({ type, id }) => {
if (id === this.model.id && type === 'delete') {
this.std.view.deleteBlock(this);
disposable.dispose();
const disposable = this.std.store.slots.blockUpdated.subscribe(
({ type, id }) => {
if (id === this.model.id && type === 'delete') {
this.std.view.deleteBlock(this);
disposable.unsubscribe();
}
}
});
);
this._disposables.add(disposable);
this._disposables.add(
this.model.propsUpdated.on(() => {
this.model.propsUpdated.subscribe(() => {
this.requestUpdate();
})
);
this.service?.specSlots.viewConnected.emit({
this.service?.specSlots.viewConnected.next({
service: this.service,
component: this,
});
@@ -237,7 +239,7 @@ export class BlockComponent<
override disconnectedCallback() {
super.disconnectedCallback();
this.service?.specSlots.viewDisconnected.emit({
this.service?.specSlots.viewDisconnected.next({
service: this.service,
component: this,
});

View File

@@ -30,13 +30,13 @@ function handleGfxConnection(instance: GfxBlockComponent) {
instance.style.position = 'absolute';
instance.disposables.add(
instance.gfx.viewport.viewportUpdated.on(() => {
instance.gfx.viewport.viewportUpdated.subscribe(() => {
updateTransform(instance);
})
);
instance.disposables.add(
instance.doc.slots.blockUpdated.on(({ type, id }) => {
instance.doc.slots.blockUpdated.subscribe(({ type, id }) => {
if (id === instance.model.id && type === 'update') {
updateTransform(instance);
}

View File

@@ -74,7 +74,7 @@ export class WidgetComponent<
super.connectedCallback();
this.std.view.setWidget(this);
this.service?.specSlots.widgetConnected.emit({
this.service?.specSlots.widgetConnected.next({
service: this.service,
component: this,
});
@@ -83,7 +83,7 @@ export class WidgetComponent<
override disconnectedCallback() {
super.disconnectedCallback();
this.std?.view.deleteWidget(this);
this.service?.specSlots.widgetDisconnected.emit({
this.service?.specSlots.widgetDisconnected.next({
service: this.service,
component: this,
});

View File

@@ -1,4 +1,4 @@
import { Slot } from '@blocksuite/global/slot';
import { Subject } from 'rxjs';
import { LifeCycleWatcher } from '../extension/index.js';
import type { BlockComponent, WidgetComponent } from './element/index.js';
@@ -24,7 +24,7 @@ export class ViewStore extends LifeCycleWatcher {
private readonly _blockMap = new Map<string, BlockComponent>();
viewUpdated: Slot<ViewUpdatePayload> = new Slot();
viewUpdated: Subject<ViewUpdatePayload> = new Subject();
get views() {
return Array.from(this._blockMap.values());
@@ -44,7 +44,7 @@ export class ViewStore extends LifeCycleWatcher {
deleteBlock = (node: BlockComponent) => {
this._blockMap.delete(node.model.id);
this.viewUpdated.emit({
this.viewUpdated.next({
id: node.model.id,
method: 'delete',
type: 'block',
@@ -56,7 +56,7 @@ export class ViewStore extends LifeCycleWatcher {
const id = node.dataset.widgetId as string;
const widgetIndex = `${node.model.id}|${id}`;
this._widgetMap.delete(widgetIndex);
this.viewUpdated.emit({
this.viewUpdated.next({
id: node.model.id,
method: 'delete',
type: 'widget',
@@ -81,7 +81,7 @@ export class ViewStore extends LifeCycleWatcher {
this.deleteBlock(node);
}
this._blockMap.set(node.model.id, node);
this.viewUpdated.emit({
this.viewUpdated.next({
id: node.model.id,
method: 'add',
type: 'block',
@@ -93,7 +93,7 @@ export class ViewStore extends LifeCycleWatcher {
const id = node.dataset.widgetId as string;
const widgetIndex = `${node.model.id}|${id}`;
this._widgetMap.set(widgetIndex, node);
this.viewUpdated.emit({
this.viewUpdated.next({
id: node.model.id,
method: 'add',
type: 'widget',
@@ -140,5 +140,6 @@ export class ViewStore extends LifeCycleWatcher {
override unmounted() {
this._blockMap.clear();
this._widgetMap.clear();
this.viewUpdated.complete();
}
}