mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(editor): add isLocal flag in blockUpdated subject (#10799)
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import type { Doc as YDoc, YEvent } from 'yjs';
|
||||
import { UndoManager } from 'yjs';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import type { ProxyOptions } from './types';
|
||||
|
||||
export abstract class BaseReactiveYData<T, Y> {
|
||||
export abstract class BaseReactiveYData<
|
||||
T,
|
||||
YSource extends Y.AbstractType<any>,
|
||||
> {
|
||||
protected _getOrigin = (
|
||||
doc: YDoc
|
||||
doc: Y.Doc
|
||||
): {
|
||||
doc: YDoc;
|
||||
doc: Y.Doc;
|
||||
proxy: true;
|
||||
|
||||
target: BaseReactiveYData<any, any>;
|
||||
@@ -19,16 +21,24 @@ export abstract class BaseReactiveYData<T, Y> {
|
||||
};
|
||||
};
|
||||
|
||||
protected _onObserve = (event: YEvent<any>, handler: () => void) => {
|
||||
protected _onObserve = (event: Y.YEvent<any>, handler: () => void) => {
|
||||
if (
|
||||
event.transaction.origin?.proxy !== true &&
|
||||
(!event.transaction.local ||
|
||||
event.transaction.origin instanceof UndoManager)
|
||||
event.transaction.origin instanceof Y.UndoManager)
|
||||
) {
|
||||
handler();
|
||||
}
|
||||
|
||||
this._options?.onChange?.(this._proxy);
|
||||
const isLocal =
|
||||
!event.transaction.origin ||
|
||||
!this._ySource.doc ||
|
||||
event.transaction.origin instanceof Y.UndoManager ||
|
||||
event.transaction.origin.proxy
|
||||
? true
|
||||
: event.transaction.origin === this._ySource.doc.clientID;
|
||||
|
||||
this._options?.onChange?.(this._proxy, isLocal);
|
||||
};
|
||||
|
||||
protected abstract readonly _options?: ProxyOptions<T>;
|
||||
@@ -41,7 +51,7 @@ export abstract class BaseReactiveYData<T, Y> {
|
||||
|
||||
protected readonly _stashed = new Set<string | number>();
|
||||
|
||||
protected _transact = (doc: YDoc, fn: () => void) => {
|
||||
protected _transact = (doc: Y.Doc, fn: () => void) => {
|
||||
doc.transact(fn, this._getOrigin(doc));
|
||||
};
|
||||
|
||||
@@ -54,7 +64,7 @@ export abstract class BaseReactiveYData<T, Y> {
|
||||
this._skipNext = false;
|
||||
};
|
||||
|
||||
protected abstract readonly _ySource: Y;
|
||||
protected abstract readonly _ySource: YSource;
|
||||
|
||||
get proxy() {
|
||||
return this._proxy;
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as Y from 'yjs';
|
||||
|
||||
import { NATIVE_UNIQ_IDENTIFIER } from '../consts.js';
|
||||
|
||||
export type OnBoxedChange = (data: unknown) => void;
|
||||
export type OnBoxedChange = (data: unknown, isLocal: boolean) => void;
|
||||
|
||||
export class Boxed<T = unknown> {
|
||||
static from = <T>(map: Y.Map<T>, onChange?: OnBoxedChange): Boxed<T> => {
|
||||
@@ -44,8 +44,17 @@ export class Boxed<T = unknown> {
|
||||
this._map.set('type', NATIVE_UNIQ_IDENTIFIER as T);
|
||||
this._map.set('value', value);
|
||||
}
|
||||
this._map.observeDeep(() => {
|
||||
this._onChange?.(this.getValue());
|
||||
this._map.observeDeep(events => {
|
||||
events.forEach(event => {
|
||||
const isLocal =
|
||||
!event.transaction.origin ||
|
||||
!this._map.doc ||
|
||||
event.transaction.origin instanceof Y.UndoManager ||
|
||||
event.transaction.origin.proxy
|
||||
? true
|
||||
: event.transaction.origin === this._map.doc.clientID;
|
||||
this._onChange?.(this.getValue(), isLocal);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const keyWithoutPrefix = (key: string) => key.replace(/(prop|sys):/, '');
|
||||
const keyWithPrefix = (key: string) =>
|
||||
SYS_KEYS.has(key) ? `sys:${key}` : `prop:${key}`;
|
||||
|
||||
type OnChange = (key: string) => void;
|
||||
type OnChange = (key: string, isLocal: boolean) => void;
|
||||
type Transform = (key: string, value: unknown, origin: unknown) => unknown;
|
||||
|
||||
type CreateProxyOptions = {
|
||||
@@ -119,7 +119,7 @@ function createProxy(
|
||||
}
|
||||
byPassSignalUpdate(() => {
|
||||
proxy[p] = next;
|
||||
onChange?.(firstKey);
|
||||
onChange?.(firstKey, true);
|
||||
});
|
||||
});
|
||||
const subscription = onDispose.subscribe(() => {
|
||||
@@ -139,7 +139,7 @@ function createProxy(
|
||||
: prev;
|
||||
// @ts-expect-error allow magic props
|
||||
root[signalKey].value = next;
|
||||
onChange?.(firstKey);
|
||||
onChange?.(firstKey, true);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -162,7 +162,7 @@ function createProxy(
|
||||
list.push(() => {
|
||||
if (value instanceof Text || Boxed.is(value)) {
|
||||
value.bind(() => {
|
||||
onChange?.(firstKey);
|
||||
onChange?.(firstKey, true);
|
||||
});
|
||||
}
|
||||
yMap.set(keyWithPrefix(fullPath), native2Y(value));
|
||||
@@ -197,7 +197,7 @@ function createProxy(
|
||||
|
||||
if (value instanceof Text || Boxed.is(value)) {
|
||||
value.bind(() => {
|
||||
onChange?.(firstKey);
|
||||
onChange?.(firstKey, true);
|
||||
});
|
||||
}
|
||||
const yValue = native2Y(value);
|
||||
@@ -251,7 +251,7 @@ function createProxy(
|
||||
: prev;
|
||||
// @ts-expect-error allow magic props
|
||||
root[signalKey].value = next;
|
||||
onChange?.(firstKey);
|
||||
onChange?.(firstKey, true);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -324,6 +324,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
return acc[key] as UnRecord;
|
||||
}, proxy as UnRecord);
|
||||
});
|
||||
this._onChange?.(firstKey, false);
|
||||
return;
|
||||
}
|
||||
if (type.action === 'delete') {
|
||||
@@ -390,8 +391,8 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
};
|
||||
|
||||
private readonly _getPropOnChange = (key: string) => {
|
||||
return () => {
|
||||
this._onChange?.(key);
|
||||
return (_: unknown, isLocal: boolean) => {
|
||||
this._onChange?.(key, isLocal);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -485,7 +486,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
}
|
||||
this._updateWithSkip(() => {
|
||||
proxy[key] = next;
|
||||
this._onChange?.(key);
|
||||
this._onChange?.(key, true);
|
||||
});
|
||||
});
|
||||
const subscription = _onDispose.subscribe(() => {
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ReactiveYArray extends BaseReactiveYData<
|
||||
|
||||
if (this._stashed.has(index)) {
|
||||
const result = Reflect.set(target, p, value, receiver);
|
||||
this._options.onChange?.(this._proxy);
|
||||
this._options.onChange?.(this._proxy, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ export class ReactiveYMap extends BaseReactiveYData<UnRecord, YMap<unknown>> {
|
||||
|
||||
if (this._stashed.has(p)) {
|
||||
const result = Reflect.set(target, p, value, receiver);
|
||||
this._options.onChange?.(this._proxy);
|
||||
this._options.onChange?.(this._proxy, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export type DeltaOperation = {
|
||||
retain?: number;
|
||||
} & OptionalAttributes;
|
||||
|
||||
export type OnTextChange = (data: Y.Text) => void;
|
||||
export type OnTextChange = (data: Y.Text, isLocal: boolean) => void;
|
||||
|
||||
export class Text {
|
||||
private readonly _deltas$: Signal<DeltaOperation[]>;
|
||||
@@ -67,10 +67,17 @@ export class Text {
|
||||
|
||||
this._length$ = signal(length);
|
||||
this._deltas$ = signal(this._yText.doc ? this._yText.toDelta() : []);
|
||||
this._yText.observe(() => {
|
||||
this._yText.observe(event => {
|
||||
const isLocal =
|
||||
!event.transaction.origin ||
|
||||
!this._yText.doc ||
|
||||
event.transaction.origin instanceof Y.UndoManager ||
|
||||
event.transaction.origin.proxy
|
||||
? true
|
||||
: event.transaction.origin === this._yText.doc.clientID;
|
||||
this._length$.value = this._yText.length;
|
||||
this._deltas$.value = this._yText.toDelta();
|
||||
this._onChange?.(this._yText);
|
||||
this._onChange?.(this._yText, isLocal);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,5 +15,5 @@ export type TransformOptions = {
|
||||
};
|
||||
|
||||
export type ProxyOptions<T> = {
|
||||
onChange?: (data: T) => void;
|
||||
onChange?: (data: T, isLocal: boolean) => void;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user