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

@@ -34,6 +34,7 @@
"lit": "^3.2.0",
"lodash-es": "^4.17.21",
"minimatch": "^10.0.1",
"rxjs": "^7.8.1",
"zod": "^3.23.8"
},
"exports": {

View File

@@ -7,8 +7,8 @@ import {
} from '@blocksuite/affine-shared/utils';
import { type BlockComponent, WidgetComponent } from '@blocksuite/block-std';
import type { GfxModel } from '@blocksuite/block-std/gfx';
import { DisposableGroup } from '@blocksuite/global/disposable';
import type { IVec, Point, Rect } from '@blocksuite/global/gfx';
import { DisposableGroup } from '@blocksuite/global/slot';
import { computed, type ReadonlySignal, signal } from '@preact/signals-core';
import { html, nothing } from 'lit';
import { query, state } from 'lit/decorators.js';
@@ -100,10 +100,12 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
this._anchorModelDisposables = new DisposableGroup();
this._anchorModelDisposables.add(
blockModel.propsUpdated.on(() => this.hide())
blockModel.propsUpdated.subscribe(() => this.hide())
);
this._anchorModelDisposables.add(blockModel.deleted.on(() => this.hide()));
this._anchorModelDisposables.add(
blockModel.deleted.subscribe(() => this.hide())
);
};
hide = (force = false) => {

View File

@@ -144,7 +144,7 @@ export class PreviewHelper {
return;
}
this.std.view.viewUpdated.on(payload => {
this.std.view.viewUpdated.subscribe(payload => {
if (payload.type !== 'block') return;
if (payload.view.model.flavour === 'affine:page') {

View File

@@ -40,7 +40,7 @@ export const gfxBlocksFilter = (
}
return ({ slots, transformerConfigs }) => {
slots.beforeExport.on(payload => {
slots.beforeExport.subscribe(payload => {
if (payload.type !== 'block') {
return;
}
@@ -54,7 +54,7 @@ export const gfxBlocksFilter = (
}
});
slots.afterExport.on(payload => {
slots.afterExport.subscribe(payload => {
if (payload.type !== 'block') {
return;
}

View File

@@ -9,7 +9,7 @@ export const newIdCrossDoc =
let samePage = false;
const oldToNewIdMap = new Map<string, string>();
slots.beforeImport.on(payload => {
slots.beforeImport.subscribe(payload => {
if (payload.type === 'slice') {
samePage = payload.snapshot.pageId === std.store.id;
}
@@ -21,7 +21,7 @@ export const newIdCrossDoc =
}
});
slots.afterImport.on(payload => {
slots.afterImport.subscribe(payload => {
if (
!samePage &&
payload.type === 'block' &&

View File

@@ -7,7 +7,7 @@ import type { TransformerMiddleware } from '@blocksuite/store';
export const reorderList =
(std: BlockStdScope): TransformerMiddleware =>
({ slots }) => {
slots.afterImport.on(payload => {
slots.afterImport.subscribe(payload => {
if (payload.type === 'block') {
const model = payload.model;
if (matchModels(model, [ListBlockModel]) && model.type === 'numbered') {

View File

@@ -1624,7 +1624,7 @@ export class DragEventWatcher {
disposables.add(this._monitorBlockDrag());
disposables.add(
std.view.viewUpdated.on(payload => {
std.view.viewUpdated.subscribe(payload => {
if (payload.type !== 'block') {
return;
}

View File

@@ -177,23 +177,23 @@ export class EdgelessWatcher {
const edgelessSlots = std.get(EdgelessLegacySlotIdentifier);
disposables.add(
viewport.viewportUpdated.on(this._handleEdgelessViewPortUpdated)
viewport.viewportUpdated.subscribe(this._handleEdgelessViewPortUpdated)
);
disposables.add(
selection.slots.updated.on(() => {
selection.slots.updated.subscribe(() => {
this.updateAnchorElement();
})
);
disposables.add(
edgelessSlots.readonlyUpdated.on(() => {
edgelessSlots.readonlyUpdated.subscribe(() => {
this.updateAnchorElement();
})
);
disposables.add(
edgelessSlots.elementResizeEnd.on(() => {
edgelessSlots.elementResizeEnd.subscribe(() => {
this.updateAnchorElement();
})
);
@@ -207,14 +207,14 @@ export class EdgelessWatcher {
);
disposables.add(
edgelessSlots.elementResizeStart.on(() => {
edgelessSlots.elementResizeStart.subscribe(() => {
this.widget.hide();
})
);
if (surface) {
disposables.add(
surface.elementUpdated.on(() => {
surface.elementUpdated.subscribe(() => {
if (this.widget.isGfxDragHandleVisible) {
this._showDragHandle().catch(console.error);
}

View File

@@ -13,11 +13,11 @@ export class PageWatcher {
const { disposables } = this.widget;
disposables.add(
this.widget.doc.slots.blockUpdated.on(() => this.widget.hide())
this.widget.doc.slots.blockUpdated.subscribe(() => this.widget.hide())
);
disposables.add(
this.pageViewportService.on(() => {
this.pageViewportService.subscribe(() => {
this.widget.hide();
})
);

View File

@@ -23,7 +23,8 @@
"@blocksuite/icons": "^2.2.3",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"lit": "^3.2.0"
"lit": "^3.2.0",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -305,12 +305,12 @@ export class EdgelessAutoConnectWidget extends WidgetComponent<RootBlockModel> {
};
this._disposables.add(
this._selection.slots.updated.on(() => {
this._selection.slots.updated.subscribe(() => {
getVisibility();
})
);
this._disposables.add(
this.doc.slots.blockUpdated.on(payload => {
this.doc.slots.blockUpdated.subscribe(payload => {
if (payload.flavour === 'affine:surface-ref') {
switch (payload.type) {
case 'add':
@@ -339,7 +339,7 @@ export class EdgelessAutoConnectWidget extends WidgetComponent<RootBlockModel> {
const surface = this._gfx.surface;
if (surface) {
this._disposables.add(
surface.elementUpdated.on(payload => {
surface.elementUpdated.subscribe(payload => {
if (
payload.props['xywh'] &&
surfaceRefs.some(ref => ref.reference === payload.id)
@@ -539,13 +539,13 @@ export class EdgelessAutoConnectWidget extends WidgetComponent<RootBlockModel> {
const gfx = std.get(GfxControllerIdentifier);
_disposables.add(
gfx.viewport.viewportUpdated.on(() => {
gfx.viewport.viewportUpdated.subscribe(() => {
this.requestUpdate();
})
);
_disposables.add(
gfx.selection.slots.updated.on(() => {
gfx.selection.slots.updated.subscribe(() => {
const { selectedElements } = gfx.selection;
if (
!(selectedElements.length === 1 && isNoteBlock(selectedElements[0]))
@@ -566,12 +566,12 @@ export class EdgelessAutoConnectWidget extends WidgetComponent<RootBlockModel> {
})
);
_disposables.add(
slots.elementResizeStart.on(() => {
slots.elementResizeStart.subscribe(() => {
this._dragging = true;
})
);
_disposables.add(
slots.elementResizeEnd.on(() => {
slots.elementResizeEnd.subscribe(() => {
this._dragging = false;
})
);

View File

@@ -21,7 +21,8 @@
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"lit": "^3.2.0"
"lit": "^3.2.0",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -161,7 +161,7 @@ export class AffineFrameTitle extends SignalWatcher(
this._nestedFrame = this._isInsideFrame();
_disposables.add(
doc.slots.blockUpdated.on(payload => {
doc.slots.blockUpdated.subscribe(payload => {
if (
(payload.type === 'update' &&
payload.props.key === 'xywh' &&
@@ -182,14 +182,14 @@ export class AffineFrameTitle extends SignalWatcher(
);
_disposables.add(
this.model.propsUpdated.on(() => {
this.model.propsUpdated.subscribe(() => {
this._xywh = this.model.xywh;
this.requestUpdate();
})
);
_disposables.add(
gfx.selection.slots.updated.on(() => {
gfx.selection.slots.updated.subscribe(() => {
this._editing =
gfx.selection.selectedIds[0] === this.model.id &&
gfx.selection.editing;
@@ -197,7 +197,7 @@ export class AffineFrameTitle extends SignalWatcher(
);
_disposables.add(
gfx.viewport.viewportUpdated.on(({ zoom }) => {
gfx.viewport.viewportUpdated.subscribe(({ zoom }) => {
this._zoom = zoom;
this.requestUpdate();
})

View File

@@ -24,7 +24,8 @@
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"lit": "^3.2.0",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -303,14 +303,14 @@ export class AffineDocRemoteSelectionWidget extends WidgetComponent {
);
this.disposables.add(
this.std.store.slots.blockUpdated.on(() => {
this.std.store.slots.blockUpdated.subscribe(() => {
this._updateSelectionsThrottled(this._remoteSelections.peek());
})
);
const gfx = this.std.get(GfxControllerIdentifier);
this.disposables.add(
gfx.viewport.viewportUpdated.on(() => {
gfx.viewport.viewportUpdated.subscribe(() => {
const selections = this._remoteSelections.peek();
this._updateSelections(selections);
})

View File

@@ -184,27 +184,31 @@ export class EdgelessRemoteSelectionWidget extends WidgetComponent<RootBlockMode
if (this.surface) {
_disposables.add(
this.surface.elementAdded.on(this._updateOnElementChange)
this.surface.elementAdded.subscribe(this._updateOnElementChange)
);
_disposables.add(
this.surface.elementRemoved.on(this._updateOnElementChange)
this.surface.elementRemoved.subscribe(this._updateOnElementChange)
);
_disposables.add(
this.surface.elementUpdated.on(this._updateOnElementChange)
this.surface.elementUpdated.subscribe(this._updateOnElementChange)
);
}
_disposables.add(doc.slots.blockUpdated.on(this._updateOnElementChange));
_disposables.add(
this.selection.slots.remoteUpdated.on(this._updateRemoteRects)
);
_disposables.add(
this.selection.slots.remoteCursorUpdated.on(this._updateRemoteCursor)
doc.slots.blockUpdated.subscribe(this._updateOnElementChange)
);
_disposables.add(
this.gfx.viewport.viewportUpdated.on(() => {
this.selection.slots.remoteUpdated.subscribe(this._updateRemoteRects)
);
_disposables.add(
this.selection.slots.remoteCursorUpdated.subscribe(
this._updateRemoteCursor
)
);
_disposables.add(
this.gfx.viewport.viewportUpdated.subscribe(() => {
this._updateTransform();
})
);

View File

@@ -19,7 +19,8 @@
"@blocksuite/global": "workspace:*",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"lit": "^3.2.0"
"lit": "^3.2.0",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -102,18 +102,24 @@ export class AffineScrollAnchoringWidget extends WidgetComponent {
if (!xywh) {
if (!this.#listened) return;
// listen for document updates
this.disposables.add(
this.std.store.slots.blockUpdated
.filter(v => v.type === 'add' && v.id === id)
.once(() => this.#moveToAnchorInEdgeless(id))
);
const blockUpdatedSubscription =
this.std.store.slots.blockUpdated.subscribe(v => {
if (v.type === 'add' && v.id === id) {
blockUpdatedSubscription.unsubscribe();
this.#moveToAnchorInEdgeless(id);
}
});
this.disposables.add(
surface.elementAdded
.filter(v => v.id === id && v.local === false)
.once(() => this.#moveToAnchorInEdgeless(id))
);
const elementAddedSubscription = surface.elementAdded.subscribe(v => {
if (v.id === id && v.local === false) {
elementAddedSubscription.unsubscribe();
this.#moveToAnchorInEdgeless(id);
}
});
// listen for document updates
this.disposables.add(blockUpdatedSubscription);
this.disposables.add(elementAddedSubscription);
return;
}
@@ -152,11 +158,13 @@ export class AffineScrollAnchoringWidget extends WidgetComponent {
if (!this.#listened) return;
// listen for document updates
this.disposables.add(
this.std.store.slots.blockUpdated
.filter(v => v.type === 'add' && v.id === id)
.once(() => this.#moveToAnchorInPage(id))
);
const subscription = this.std.store.slots.blockUpdated.subscribe(v => {
if (v.type === 'add' && v.id === id) {
subscription.unsubscribe();
this.#moveToAnchorInPage(id);
}
});
this.disposables.add(subscription);
return;
}
@@ -192,7 +200,7 @@ export class AffineScrollAnchoringWidget extends WidgetComponent {
// In edgeless
const controler = this.std.get(GfxControllerIdentifier);
this.disposables.add(
controler.viewport.viewportUpdated.on(this.#requestUpdateFn)
controler.viewport.viewportUpdated.subscribe(this.#requestUpdateFn)
);
this.disposables.add(

View File

@@ -26,7 +26,8 @@
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"lit": "^3.2.0",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -233,8 +233,11 @@ export class SlashMenu extends WithDisposable(LitElement) {
if (isComposition) {
this._updateFilteredItems();
} else {
this.inlineEditor.slots.renderComplete.once(
this._updateFilteredItems
const subscription = this.inlineEditor.slots.renderComplete.subscribe(
() => {
subscription.unsubscribe();
this._updateFilteredItems();
}
);
}
},
@@ -251,7 +254,12 @@ export class SlashMenu extends WithDisposable(LitElement) {
if (curRange.index < this._startRange.index) {
this.abortController.abort();
}
this.inlineEditor.slots.renderComplete.once(this._updateFilteredItems);
const subscription = this.inlineEditor.slots.renderComplete.subscribe(
() => {
subscription.unsubscribe();
this._updateFilteredItems();
}
);
},
onAbort: () => this.abortController.abort(),
});

View File

@@ -4,7 +4,7 @@ import {
} from '@blocksuite/affine-rich-text';
import type { UIEventStateContext } from '@blocksuite/block-std';
import { TextSelection, WidgetComponent } from '@blocksuite/block-std';
import { DisposableGroup } from '@blocksuite/global/slot';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { InlineEditor } from '@blocksuite/inline';
import debounce from 'lodash-es/debounce';
@@ -93,8 +93,16 @@ export class AffineSlashMenuWidget extends WidgetComponent {
) => {
const inlineRangeApplyCallback = (callback: () => void) => {
// the inline ranged updated in compositionEnd event before this event callback
if (isCompositionEnd) callback();
else inlineEditor.slots.inlineRangeSync.once(callback);
if (isCompositionEnd) {
callback();
} else {
const subscription = inlineEditor.slots.inlineRangeSync.subscribe(
() => {
subscription.unsubscribe();
callback();
}
);
}
};
if (this.block.model.flavour !== 'affine:page') {

View File

@@ -26,7 +26,8 @@
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"lit": "^3.2.0",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1"
},
"exports": {
".": "./src/index.ts",

View File

@@ -211,7 +211,7 @@ export class AffineToolbarWidget extends WidgetComponent {
);
disposables.add(
std.selection.slots.changed.on(selections => {
std.selection.slots.changed.subscribe(selections => {
if (!context.activated) return;
const value = flags.value$.peek();
@@ -239,26 +239,25 @@ export class AffineToolbarWidget extends WidgetComponent {
// When switch the view mode, wait until the view is created
// `card view` or `embed view`
disposables.add(
std.view.viewUpdated
.filter(view => view.type === 'block')
.on(record => {
if (
flags.isBlock() &&
std.selection
.filter$(BlockSelection)
.peek()
.find(s => s.blockId === record.id)
) {
if (record.method === 'add') {
flags.refresh(Flag.Block);
}
return;
std.view.viewUpdated.subscribe(record => {
if (
record.type === 'block' &&
flags.isBlock() &&
std.selection
.filter$(BlockSelection)
.peek()
.find(s => s.blockId === record.id)
) {
if (record.method === 'add') {
flags.refresh(Flag.Block);
}
})
return;
}
})
);
disposables.add(
std.store.slots.blockUpdated.on(record => {
std.store.slots.blockUpdated.subscribe(record => {
if (
flags.isBlock() &&
record.type === 'update' &&
@@ -334,28 +333,30 @@ export class AffineToolbarWidget extends WidgetComponent {
// Should update position of notes' toolbar in edgeless
disposables.add(
this.std.get(GfxControllerIdentifier).viewport.viewportUpdated.on(() => {
if (!context.activated) return;
this.std
.get(GfxControllerIdentifier)
.viewport.viewportUpdated.subscribe(() => {
if (!context.activated) return;
if (flags.value === Flag.None || flags.check(Flag.Hiding)) {
return;
}
if (flags.value === Flag.None || flags.check(Flag.Hiding)) {
return;
}
if (flags.isText()) {
flags.refresh(Flag.Text);
return;
}
if (flags.isText()) {
flags.refresh(Flag.Text);
return;
}
if (flags.isNative()) {
flags.refresh(Flag.Native);
return;
}
if (flags.isNative()) {
flags.refresh(Flag.Native);
return;
}
if (flags.isBlock()) {
flags.refresh(Flag.Block);
return;
}
})
if (flags.isBlock()) {
flags.refresh(Flag.Block);
return;
}
})
);
disposables.add(