mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 20:38:52 +00:00
@@ -4,4 +4,4 @@ export const SCHEMA_NOT_FOUND_MESSAGE =
|
||||
export const TEXT_UNIQ_IDENTIFIER = '$blocksuite:internal:text$';
|
||||
export const NATIVE_UNIQ_IDENTIFIER = '$blocksuite:internal:native$';
|
||||
|
||||
export const SYS_KEYS = new Set(['id', 'flavour', 'children']);
|
||||
export const SYS_KEYS = new Set(['id', 'flavour', 'children', 'version']);
|
||||
|
||||
@@ -44,6 +44,9 @@ export class Block {
|
||||
const onChange = !options.onChange
|
||||
? undefined
|
||||
: (key: string, value: unknown) => {
|
||||
if (!this._syncController || !this.model) {
|
||||
return;
|
||||
}
|
||||
options.onChange?.(this, key, value);
|
||||
};
|
||||
const flavour = yBlock.get('sys:flavour') as string;
|
||||
|
||||
@@ -50,7 +50,7 @@ export class FlatSyncController {
|
||||
model.schema = schema;
|
||||
|
||||
model.id = this.id;
|
||||
model.keys = Array.from(props).map(key => key.replace('prop:', ''));
|
||||
model.keys = Array.from(props);
|
||||
model.yBlock = this.yBlock;
|
||||
const reactive = new ReactiveFlatYMap(
|
||||
this.yBlock,
|
||||
@@ -69,8 +69,7 @@ export class FlatSyncController {
|
||||
const defaultProps = schema.model.props?.(internalPrimitives);
|
||||
if (defaultProps) {
|
||||
Object.entries(defaultProps).forEach(([key, value]) => {
|
||||
const keyWithProp = `prop:${key}`;
|
||||
if (keyWithProp in proxy) {
|
||||
if (key in proxy) {
|
||||
return;
|
||||
}
|
||||
proxy[key] = value;
|
||||
@@ -149,9 +148,8 @@ export class FlatSyncController {
|
||||
// Set default props if not exists
|
||||
if (defaultProps) {
|
||||
Object.keys(defaultProps).forEach(key => {
|
||||
const keyWithProp = `prop:${key}`;
|
||||
if (props.has(keyWithProp)) return;
|
||||
props.add(keyWithProp);
|
||||
if (props.has(key)) return;
|
||||
props.add(key);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { native2Y } from '../../reactive/index.js';
|
||||
import { isPureObject, native2Y } from '../../reactive/index.js';
|
||||
import type { Schema } from '../../schema/index.js';
|
||||
import type { BlockModel } from '../block/block-model.js';
|
||||
import type { YBlock } from '../block/types.js';
|
||||
@@ -95,11 +95,26 @@ export class DocCRUD {
|
||||
delete props.flavour;
|
||||
delete props.children;
|
||||
|
||||
Object.entries(props).forEach(([key, value]) => {
|
||||
if (value === undefined) return;
|
||||
const isFlatData = schema.model.isFlatData;
|
||||
if (isFlatData) {
|
||||
const run = (obj: unknown, basePath: string) => {
|
||||
if (isPureObject(obj)) {
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
const fullPath = basePath ? `${basePath}.${key}` : key;
|
||||
run(value, fullPath);
|
||||
});
|
||||
} else {
|
||||
yBlock.set(`prop:${basePath}`, native2Y(obj));
|
||||
}
|
||||
};
|
||||
run(props, '');
|
||||
} else {
|
||||
Object.entries(props).forEach(([key, value]) => {
|
||||
if (value === undefined) return;
|
||||
|
||||
yBlock.set(`prop:${key}`, native2Y(value));
|
||||
});
|
||||
yBlock.set(`prop:${key}`, native2Y(value));
|
||||
});
|
||||
}
|
||||
|
||||
const parentId =
|
||||
parent ?? (schema.model.role === 'root' ? null : this.root);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { SYS_KEYS } from '../../consts.js';
|
||||
import { native2Y } from '../../reactive/index.js';
|
||||
import type { BlockModel } from '../block/block-model.js';
|
||||
import type { BlockProps, YBlock } from '../block/types.js';
|
||||
import type { BlockSchema } from '../block/zod.js';
|
||||
@@ -32,6 +31,6 @@ export function syncBlockProps(
|
||||
}
|
||||
|
||||
// @ts-expect-error allow props
|
||||
model[key] = native2Y(value);
|
||||
model[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type CreateProxyOptions = {
|
||||
shouldByPassSignal: () => boolean;
|
||||
byPassSignalUpdate: (fn: () => void) => void;
|
||||
stashed: Set<string | number>;
|
||||
initialized: () => boolean;
|
||||
};
|
||||
|
||||
const proxySymbol = Symbol('proxy');
|
||||
@@ -60,6 +61,7 @@ function createProxy(
|
||||
byPassSignalUpdate,
|
||||
basePath,
|
||||
onChange,
|
||||
initialized,
|
||||
transform = (_key, value) => value,
|
||||
stashed,
|
||||
} = options;
|
||||
@@ -73,7 +75,7 @@ function createProxy(
|
||||
if (isPureObject(value) && !isProxy(value)) {
|
||||
const proxy = createProxy(yMap, value as UnRecord, root, {
|
||||
...options,
|
||||
basePath: `${basePath}.${key}`,
|
||||
basePath: basePath ? `${basePath}.${key}` : key,
|
||||
});
|
||||
base[key] = proxy;
|
||||
}
|
||||
@@ -111,6 +113,9 @@ function createProxy(
|
||||
root[signalKey] = signalData;
|
||||
onDispose.once(
|
||||
signalData.subscribe(next => {
|
||||
if (!initialized()) {
|
||||
return;
|
||||
}
|
||||
byPassSignalUpdate(() => {
|
||||
proxy[p] = next;
|
||||
onChange?.(firstKey, next);
|
||||
@@ -137,7 +142,7 @@ function createProxy(
|
||||
if (isPureObject(value)) {
|
||||
const syncYMap = () => {
|
||||
yMap.forEach((_, key) => {
|
||||
if (keyWithoutPrefix(key).startsWith(fullPath)) {
|
||||
if (initialized() && keyWithoutPrefix(key).startsWith(fullPath)) {
|
||||
yMap.delete(key);
|
||||
}
|
||||
});
|
||||
@@ -148,13 +153,13 @@ function createProxy(
|
||||
run(value, fullPath);
|
||||
} else {
|
||||
list.push(() => {
|
||||
yMap.set(keyWithPrefix(fullPath), value);
|
||||
yMap.set(keyWithPrefix(fullPath), native2Y(value));
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
run(value, fullPath);
|
||||
if (list.length) {
|
||||
if (list.length && initialized()) {
|
||||
yMap.doc?.transact(
|
||||
() => {
|
||||
list.forEach(fn => fn());
|
||||
@@ -180,7 +185,7 @@ function createProxy(
|
||||
|
||||
const yValue = native2Y(value);
|
||||
const next = transform(firstKey, value, yValue);
|
||||
if (!isStashed) {
|
||||
if (!isStashed && initialized()) {
|
||||
yMap.doc?.transact(
|
||||
() => {
|
||||
yMap.set(keyWithPrefix(fullPath), yValue);
|
||||
@@ -233,7 +238,7 @@ function createProxy(
|
||||
});
|
||||
};
|
||||
|
||||
if (!isStashed) {
|
||||
if (!isStashed && initialized()) {
|
||||
yMap.doc?.transact(
|
||||
() => {
|
||||
const fullKey = keyWithPrefix(fullPath);
|
||||
@@ -268,6 +273,8 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
protected readonly _source: UnRecord;
|
||||
protected readonly _options?: ProxyOptions<UnRecord>;
|
||||
|
||||
private readonly _initialized;
|
||||
|
||||
private readonly _observer = (event: YMapEvent<unknown>) => {
|
||||
const yMap = this._ySource;
|
||||
const proxy = this._proxy;
|
||||
@@ -344,9 +351,12 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
};
|
||||
|
||||
private readonly _createDefaultData = (): UnRecord => {
|
||||
const data: UnRecord = {};
|
||||
const root: UnRecord = {};
|
||||
const transform = this._transform;
|
||||
Array.from(this._ySource.entries()).forEach(([key, value]) => {
|
||||
if (key.startsWith('sys')) {
|
||||
return;
|
||||
}
|
||||
const keys = keyWithoutPrefix(key).split('.');
|
||||
const firstKey = keys[0];
|
||||
|
||||
@@ -356,7 +366,8 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
} else if (value instanceof YArray) {
|
||||
finalData = transform(firstKey, value.toArray(), value);
|
||||
} else if (value instanceof YText) {
|
||||
finalData = transform(firstKey, new Text(value), value);
|
||||
const next = new Text(value);
|
||||
finalData = transform(firstKey, next, value);
|
||||
} else if (value instanceof YMap) {
|
||||
throw new BlockSuiteError(
|
||||
ErrorCode.ReactiveProxyError,
|
||||
@@ -369,21 +380,25 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
void keys.reduce((acc: UnRecord, key, index) => {
|
||||
if (!acc[key] && index !== allLength - 1) {
|
||||
const path = keys.slice(0, index + 1).join('.');
|
||||
const data = this._getProxy({} as UnRecord, path);
|
||||
const data = this._getProxy({} as UnRecord, root, path);
|
||||
acc[key] = data;
|
||||
}
|
||||
if (index === allLength - 1) {
|
||||
acc[key] = finalData;
|
||||
}
|
||||
return acc[key] as UnRecord;
|
||||
}, data);
|
||||
}, root);
|
||||
});
|
||||
|
||||
return data;
|
||||
return root;
|
||||
};
|
||||
|
||||
private readonly _getProxy = (source: UnRecord, path?: string): UnRecord => {
|
||||
return createProxy(this._ySource, source, source, {
|
||||
private readonly _getProxy = (
|
||||
source: UnRecord,
|
||||
root: UnRecord,
|
||||
path?: string
|
||||
): UnRecord => {
|
||||
return createProxy(this._ySource, source, root, {
|
||||
onDispose: this._onDispose,
|
||||
shouldByPassSignal: () => this._skipNext,
|
||||
byPassSignalUpdate: this._updateWithSkip,
|
||||
@@ -391,6 +406,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
onChange: this._onChange,
|
||||
transform: this._transform,
|
||||
stashed: this._stashed,
|
||||
initialized: () => this._initialized,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -400,16 +416,20 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
private readonly _onChange?: OnChange
|
||||
) {
|
||||
super();
|
||||
this._initialized = false;
|
||||
const source = this._createDefaultData();
|
||||
this._source = source;
|
||||
|
||||
const proxy = this._getProxy(source);
|
||||
const proxy = this._getProxy(source, source);
|
||||
|
||||
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, next);
|
||||
@@ -420,6 +440,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
||||
|
||||
this._proxy = proxy;
|
||||
this._ySource.observe(this._observer);
|
||||
this._initialized = true;
|
||||
}
|
||||
|
||||
pop = (prop: string): void => {
|
||||
|
||||
Reference in New Issue
Block a user