mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
@@ -1,7 +1,12 @@
|
|||||||
import { TableModelFlavour } from '@blocksuite/affine-model';
|
import {
|
||||||
import { generateFractionalIndexingKeyBetween } from '@blocksuite/affine-shared/utils';
|
type TableBlockModel,
|
||||||
|
TableModelFlavour,
|
||||||
|
} from '@blocksuite/affine-model';
|
||||||
import type { Command } from '@blocksuite/block-std';
|
import type { Command } from '@blocksuite/block-std';
|
||||||
import { type BlockModel, nanoid, Text } from '@blocksuite/store';
|
import { type BlockModel } from '@blocksuite/store';
|
||||||
|
|
||||||
|
import { TableDataManager } from './table-data-manager';
|
||||||
|
|
||||||
export const insertTableBlockCommand: Command<
|
export const insertTableBlockCommand: Command<
|
||||||
{
|
{
|
||||||
place?: 'after' | 'before';
|
place?: 'after' | 'before';
|
||||||
@@ -22,41 +27,25 @@ export const insertTableBlockCommand: Command<
|
|||||||
|
|
||||||
if (!targetModel) return;
|
if (!targetModel) return;
|
||||||
|
|
||||||
const row1Id = nanoid();
|
|
||||||
const row2Id = nanoid();
|
|
||||||
const col1Id = nanoid();
|
|
||||||
const col2Id = nanoid();
|
|
||||||
const order1 = generateFractionalIndexingKeyBetween(null, null);
|
|
||||||
const order2 = generateFractionalIndexingKeyBetween(order1, null);
|
|
||||||
|
|
||||||
const initialTableData = {
|
|
||||||
rows: {
|
|
||||||
[row1Id]: { rowId: row1Id, order: order1 },
|
|
||||||
[row2Id]: { rowId: row2Id, order: order2 },
|
|
||||||
},
|
|
||||||
columns: {
|
|
||||||
[col1Id]: { columnId: col1Id, order: order1 },
|
|
||||||
[col2Id]: { columnId: col2Id, order: order2 },
|
|
||||||
},
|
|
||||||
cells: {
|
|
||||||
[`${row1Id}:${col1Id}`]: { text: new Text() },
|
|
||||||
[`${row1Id}:${col2Id}`]: { text: new Text() },
|
|
||||||
[`${row2Id}:${col1Id}`]: { text: new Text() },
|
|
||||||
[`${row2Id}:${col2Id}`]: { text: new Text() },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = std.store.addSiblingBlocks(
|
const result = std.store.addSiblingBlocks(
|
||||||
targetModel,
|
targetModel,
|
||||||
[{ flavour: TableModelFlavour, ...initialTableData }],
|
[{ flavour: TableModelFlavour }],
|
||||||
place
|
place
|
||||||
);
|
);
|
||||||
const blockId = result[0];
|
const blockId = result[0];
|
||||||
|
|
||||||
if (blockId == null) return;
|
if (blockId == null) return;
|
||||||
|
|
||||||
if (removeEmptyLine && targetModel.text?.length === 0) {
|
const model = std.store.getBlock(blockId)?.model as TableBlockModel;
|
||||||
std.store.deleteBlock(targetModel);
|
if (model == null) return;
|
||||||
|
|
||||||
|
const dataManager = new TableDataManager(model);
|
||||||
|
|
||||||
|
dataManager.addNRow(2);
|
||||||
|
dataManager.addNColumn(2);
|
||||||
|
|
||||||
|
if (removeEmptyLine && model.text?.length === 0) {
|
||||||
|
std.store.deleteBlock(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
next({ insertedTableBlockId: blockId });
|
next({ insertedTableBlockId: blockId });
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ export class TableDataManager {
|
|||||||
`${this.virtualRowCount$.value + this.rows$.value.length} x ${this.virtualColumnCount$.value + this.columns$.value.length}`
|
`${this.virtualRowCount$.value + this.rows$.value.length} x ${this.virtualColumnCount$.value + this.columns$.value.length}`
|
||||||
);
|
);
|
||||||
rows$ = computed(() => {
|
rows$ = computed(() => {
|
||||||
return Object.values(this.model.rows$.value).sort((a, b) =>
|
return Object.values(this.model.props.rows$.value).sort((a, b) =>
|
||||||
a.order > b.order ? 1 : -1
|
a.order > b.order ? 1 : -1
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
columns$ = computed(() => {
|
columns$ = computed(() => {
|
||||||
return Object.values(this.model.columns$.value).sort((a, b) =>
|
return Object.values(this.model.props.columns$.value).sort((a, b) =>
|
||||||
a.order > b.order ? 1 : -1
|
a.order > b.order ? 1 : -1
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -72,19 +72,20 @@ export class TableDataManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
getCell(rowId: string, columnId: string): TableCell | undefined {
|
getCell(rowId: string, columnId: string): TableCell | undefined {
|
||||||
return this.model.cells$.value[`${rowId}:${columnId}`];
|
return this.model.props.cells$.value[`${rowId}:${columnId}`];
|
||||||
}
|
}
|
||||||
|
|
||||||
addRow(after?: number) {
|
addRow(after?: number) {
|
||||||
const order = this.getOrder(this.rows$.value, after);
|
const order = this.getOrder(this.rows$.value, after);
|
||||||
const rowId = nanoid();
|
const rowId = nanoid();
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
this.model.rows[rowId] = {
|
this.model.props.rows[rowId] = {
|
||||||
rowId,
|
rowId,
|
||||||
order,
|
order,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.columns$.value.forEach(column => {
|
this.columns$.value.forEach(column => {
|
||||||
this.model.cells[`${rowId}:${column.columnId}`] = {
|
this.model.props.cells[`${rowId}:${column.columnId}`] = {
|
||||||
text: new Text(),
|
text: new Text(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -148,12 +149,12 @@ export class TableDataManager {
|
|||||||
const order = this.getOrder(this.columns$.value, after);
|
const order = this.getOrder(this.columns$.value, after);
|
||||||
const columnId = nanoid();
|
const columnId = nanoid();
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
this.model.columns[columnId] = {
|
this.model.props.columns[columnId] = {
|
||||||
columnId,
|
columnId,
|
||||||
order,
|
order,
|
||||||
};
|
};
|
||||||
this.rows$.value.forEach(row => {
|
this.rows$.value.forEach(row => {
|
||||||
this.model.cells[`${row.rowId}:${columnId}`] = {
|
this.model.props.cells[`${row.rowId}:${columnId}`] = {
|
||||||
text: new Text(),
|
text: new Text(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -163,14 +164,14 @@ export class TableDataManager {
|
|||||||
|
|
||||||
deleteRow(rowId: string) {
|
deleteRow(rowId: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
Object.keys(this.model.rows).forEach(id => {
|
Object.keys(this.model.props.rows).forEach(id => {
|
||||||
if (id === rowId) {
|
if (id === rowId) {
|
||||||
delete this.model.rows[id];
|
delete this.model.props.rows[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Object.keys(this.model.cells).forEach(id => {
|
Object.keys(this.model.props.cells).forEach(id => {
|
||||||
if (id.startsWith(rowId)) {
|
if (id.startsWith(rowId)) {
|
||||||
delete this.model.cells[id];
|
delete this.model.props.cells[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -178,14 +179,14 @@ export class TableDataManager {
|
|||||||
|
|
||||||
deleteColumn(columnId: string) {
|
deleteColumn(columnId: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
Object.keys(this.model.columns).forEach(id => {
|
Object.keys(this.model.props.columns).forEach(id => {
|
||||||
if (id === columnId) {
|
if (id === columnId) {
|
||||||
delete this.model.columns[id];
|
delete this.model.props.columns[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Object.keys(this.model.cells).forEach(id => {
|
Object.keys(this.model.props.cells).forEach(id => {
|
||||||
if (id.endsWith(`:${columnId}`)) {
|
if (id.endsWith(`:${columnId}`)) {
|
||||||
delete this.model.cells[id];
|
delete this.model.props.cells[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -193,51 +194,51 @@ export class TableDataManager {
|
|||||||
|
|
||||||
updateRowOrder(rowId: string, newOrder: string) {
|
updateRowOrder(rowId: string, newOrder: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
if (this.model.rows[rowId]) {
|
if (this.model.props.rows[rowId]) {
|
||||||
this.model.rows[rowId].order = newOrder;
|
this.model.props.rows[rowId].order = newOrder;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColumnOrder(columnId: string, newOrder: string) {
|
updateColumnOrder(columnId: string, newOrder: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
if (this.model.columns[columnId]) {
|
if (this.model.props.columns[columnId]) {
|
||||||
this.model.columns[columnId].order = newOrder;
|
this.model.props.columns[columnId].order = newOrder;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setRowBackgroundColor(rowId: string, color?: string) {
|
setRowBackgroundColor(rowId: string, color?: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
if (this.model.rows[rowId]) {
|
if (this.model.props.rows[rowId]) {
|
||||||
this.model.rows[rowId].backgroundColor = color;
|
this.model.props.rows[rowId].backgroundColor = color;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setColumnBackgroundColor(columnId: string, color?: string) {
|
setColumnBackgroundColor(columnId: string, color?: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
if (this.model.columns[columnId]) {
|
if (this.model.props.columns[columnId]) {
|
||||||
this.model.columns[columnId].backgroundColor = color;
|
this.model.props.columns[columnId].backgroundColor = color;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setColumnWidth(columnId: string, width: number) {
|
setColumnWidth(columnId: string, width: number) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
if (this.model.columns[columnId]) {
|
if (this.model.props.columns[columnId]) {
|
||||||
this.model.columns[columnId].width = width;
|
this.model.props.columns[columnId].width = width;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
clearRow(rowId: string) {
|
clearRow(rowId: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
Object.keys(this.model.cells).forEach(id => {
|
Object.keys(this.model.props.cells).forEach(id => {
|
||||||
if (id.startsWith(rowId)) {
|
if (id.startsWith(rowId)) {
|
||||||
this.model.cells[id]?.text.replace(
|
this.model.props.cells[id]?.text.replace(
|
||||||
0,
|
0,
|
||||||
this.model.cells[id]?.text.length,
|
this.model.props.cells[id]?.text.length,
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -247,11 +248,11 @@ export class TableDataManager {
|
|||||||
|
|
||||||
clearColumn(columnId: string) {
|
clearColumn(columnId: string) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
Object.keys(this.model.cells).forEach(id => {
|
Object.keys(this.model.props.cells).forEach(id => {
|
||||||
if (id.endsWith(`:${columnId}`)) {
|
if (id.endsWith(`:${columnId}`)) {
|
||||||
this.model.cells[id]?.text.replace(
|
this.model.props.cells[id]?.text.replace(
|
||||||
0,
|
0,
|
||||||
this.model.cells[id]?.text.length,
|
this.model.props.cells[id]?.text.length,
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -286,7 +287,7 @@ export class TableDataManager {
|
|||||||
clearCells(cells: { rowId: string; columnId: string }[]) {
|
clearCells(cells: { rowId: string; columnId: string }[]) {
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
cells.forEach(({ rowId, columnId }) => {
|
cells.forEach(({ rowId, columnId }) => {
|
||||||
const text = this.model.cells[`${rowId}:${columnId}`]?.text;
|
const text = this.model.props.cells[`${rowId}:${columnId}`]?.text;
|
||||||
if (text) {
|
if (text) {
|
||||||
text.replace(0, text.length, '');
|
text.replace(0, text.length, '');
|
||||||
}
|
}
|
||||||
@@ -308,7 +309,7 @@ export class TableDataManager {
|
|||||||
if (!column) return;
|
if (!column) return;
|
||||||
const order = this.getOrder(columns, after);
|
const order = this.getOrder(columns, after);
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
const realColumn = this.model.columns[column.columnId];
|
const realColumn = this.model.props.columns[column.columnId];
|
||||||
if (realColumn) {
|
if (realColumn) {
|
||||||
realColumn.order = order;
|
realColumn.order = order;
|
||||||
}
|
}
|
||||||
@@ -321,7 +322,7 @@ export class TableDataManager {
|
|||||||
if (!row) return;
|
if (!row) return;
|
||||||
const order = this.getOrder(rows, after);
|
const order = this.getOrder(rows, after);
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
const realRow = this.model.rows[row.rowId];
|
const realRow = this.model.props.rows[row.rowId];
|
||||||
if (realRow) {
|
if (realRow) {
|
||||||
realRow.order = order;
|
realRow.order = order;
|
||||||
}
|
}
|
||||||
@@ -334,15 +335,15 @@ export class TableDataManager {
|
|||||||
const order = this.getOrder(this.columns$.value, index);
|
const order = this.getOrder(this.columns$.value, index);
|
||||||
const newColumnId = nanoid();
|
const newColumnId = nanoid();
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
this.model.columns[newColumnId] = {
|
this.model.props.columns[newColumnId] = {
|
||||||
...oldColumn,
|
...oldColumn,
|
||||||
columnId: newColumnId,
|
columnId: newColumnId,
|
||||||
order,
|
order,
|
||||||
};
|
};
|
||||||
this.rows$.value.forEach(row => {
|
this.rows$.value.forEach(row => {
|
||||||
this.model.cells[`${row.rowId}:${newColumnId}`] = {
|
this.model.props.cells[`${row.rowId}:${newColumnId}`] = {
|
||||||
text:
|
text:
|
||||||
this.model.cells[
|
this.model.props.cells[
|
||||||
`${row.rowId}:${oldColumn.columnId}`
|
`${row.rowId}:${oldColumn.columnId}`
|
||||||
]?.text.clone() ?? new Text(),
|
]?.text.clone() ?? new Text(),
|
||||||
};
|
};
|
||||||
@@ -357,15 +358,15 @@ export class TableDataManager {
|
|||||||
const order = this.getOrder(this.rows$.value, index);
|
const order = this.getOrder(this.rows$.value, index);
|
||||||
const newRowId = nanoid();
|
const newRowId = nanoid();
|
||||||
this.model.doc.transact(() => {
|
this.model.doc.transact(() => {
|
||||||
this.model.rows[newRowId] = {
|
this.model.props.rows[newRowId] = {
|
||||||
...oldRow,
|
...oldRow,
|
||||||
rowId: newRowId,
|
rowId: newRowId,
|
||||||
order,
|
order,
|
||||||
};
|
};
|
||||||
this.columns$.value.forEach(column => {
|
this.columns$.value.forEach(column => {
|
||||||
this.model.cells[`${newRowId}:${column.columnId}`] = {
|
this.model.props.cells[`${newRowId}:${column.columnId}`] = {
|
||||||
text:
|
text:
|
||||||
this.model.cells[
|
this.model.props.cells[
|
||||||
`${oldRow.rowId}:${column.columnId}`
|
`${oldRow.rowId}:${column.columnId}`
|
||||||
]?.text.clone() ?? new Text(),
|
]?.text.clone() ?? new Text(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const TableBlockSchema = defineBlockSchema({
|
|||||||
cells: {},
|
cells: {},
|
||||||
}),
|
}),
|
||||||
metadata: {
|
metadata: {
|
||||||
|
isFlatData: true,
|
||||||
role: 'content',
|
role: 'content',
|
||||||
version: 1,
|
version: 1,
|
||||||
parent: ['affine:note'],
|
parent: ['affine:note'],
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ export const SCHEMA_NOT_FOUND_MESSAGE =
|
|||||||
export const TEXT_UNIQ_IDENTIFIER = '$blocksuite:internal:text$';
|
export const TEXT_UNIQ_IDENTIFIER = '$blocksuite:internal:text$';
|
||||||
export const NATIVE_UNIQ_IDENTIFIER = '$blocksuite:internal:native$';
|
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
|
const onChange = !options.onChange
|
||||||
? undefined
|
? undefined
|
||||||
: (key: string, value: unknown) => {
|
: (key: string, value: unknown) => {
|
||||||
|
if (!this._syncController || !this.model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
options.onChange?.(this, key, value);
|
options.onChange?.(this, key, value);
|
||||||
};
|
};
|
||||||
const flavour = yBlock.get('sys:flavour') as string;
|
const flavour = yBlock.get('sys:flavour') as string;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export class FlatSyncController {
|
|||||||
model.schema = schema;
|
model.schema = schema;
|
||||||
|
|
||||||
model.id = this.id;
|
model.id = this.id;
|
||||||
model.keys = Array.from(props).map(key => key.replace('prop:', ''));
|
model.keys = Array.from(props);
|
||||||
model.yBlock = this.yBlock;
|
model.yBlock = this.yBlock;
|
||||||
const reactive = new ReactiveFlatYMap(
|
const reactive = new ReactiveFlatYMap(
|
||||||
this.yBlock,
|
this.yBlock,
|
||||||
@@ -69,8 +69,7 @@ export class FlatSyncController {
|
|||||||
const defaultProps = schema.model.props?.(internalPrimitives);
|
const defaultProps = schema.model.props?.(internalPrimitives);
|
||||||
if (defaultProps) {
|
if (defaultProps) {
|
||||||
Object.entries(defaultProps).forEach(([key, value]) => {
|
Object.entries(defaultProps).forEach(([key, value]) => {
|
||||||
const keyWithProp = `prop:${key}`;
|
if (key in proxy) {
|
||||||
if (keyWithProp in proxy) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proxy[key] = value;
|
proxy[key] = value;
|
||||||
@@ -149,9 +148,8 @@ export class FlatSyncController {
|
|||||||
// Set default props if not exists
|
// Set default props if not exists
|
||||||
if (defaultProps) {
|
if (defaultProps) {
|
||||||
Object.keys(defaultProps).forEach(key => {
|
Object.keys(defaultProps).forEach(key => {
|
||||||
const keyWithProp = `prop:${key}`;
|
if (props.has(key)) return;
|
||||||
if (props.has(keyWithProp)) return;
|
props.add(key);
|
||||||
props.add(keyWithProp);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||||
import * as Y from 'yjs';
|
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 { Schema } from '../../schema/index.js';
|
||||||
import type { BlockModel } from '../block/block-model.js';
|
import type { BlockModel } from '../block/block-model.js';
|
||||||
import type { YBlock } from '../block/types.js';
|
import type { YBlock } from '../block/types.js';
|
||||||
@@ -95,11 +95,26 @@ export class DocCRUD {
|
|||||||
delete props.flavour;
|
delete props.flavour;
|
||||||
delete props.children;
|
delete props.children;
|
||||||
|
|
||||||
Object.entries(props).forEach(([key, value]) => {
|
const isFlatData = schema.model.isFlatData;
|
||||||
if (value === undefined) return;
|
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 =
|
const parentId =
|
||||||
parent ?? (schema.model.role === 'root' ? null : this.root);
|
parent ?? (schema.model.role === 'root' ? null : this.root);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
import { SYS_KEYS } from '../../consts.js';
|
import { SYS_KEYS } from '../../consts.js';
|
||||||
import { native2Y } from '../../reactive/index.js';
|
|
||||||
import type { BlockModel } from '../block/block-model.js';
|
import type { BlockModel } from '../block/block-model.js';
|
||||||
import type { BlockProps, YBlock } from '../block/types.js';
|
import type { BlockProps, YBlock } from '../block/types.js';
|
||||||
import type { BlockSchema } from '../block/zod.js';
|
import type { BlockSchema } from '../block/zod.js';
|
||||||
@@ -32,6 +31,6 @@ export function syncBlockProps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error allow props
|
// @ts-expect-error allow props
|
||||||
model[key] = native2Y(value);
|
model[key] = value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type CreateProxyOptions = {
|
|||||||
shouldByPassSignal: () => boolean;
|
shouldByPassSignal: () => boolean;
|
||||||
byPassSignalUpdate: (fn: () => void) => void;
|
byPassSignalUpdate: (fn: () => void) => void;
|
||||||
stashed: Set<string | number>;
|
stashed: Set<string | number>;
|
||||||
|
initialized: () => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const proxySymbol = Symbol('proxy');
|
const proxySymbol = Symbol('proxy');
|
||||||
@@ -60,6 +61,7 @@ function createProxy(
|
|||||||
byPassSignalUpdate,
|
byPassSignalUpdate,
|
||||||
basePath,
|
basePath,
|
||||||
onChange,
|
onChange,
|
||||||
|
initialized,
|
||||||
transform = (_key, value) => value,
|
transform = (_key, value) => value,
|
||||||
stashed,
|
stashed,
|
||||||
} = options;
|
} = options;
|
||||||
@@ -73,7 +75,7 @@ function createProxy(
|
|||||||
if (isPureObject(value) && !isProxy(value)) {
|
if (isPureObject(value) && !isProxy(value)) {
|
||||||
const proxy = createProxy(yMap, value as UnRecord, root, {
|
const proxy = createProxy(yMap, value as UnRecord, root, {
|
||||||
...options,
|
...options,
|
||||||
basePath: `${basePath}.${key}`,
|
basePath: basePath ? `${basePath}.${key}` : key,
|
||||||
});
|
});
|
||||||
base[key] = proxy;
|
base[key] = proxy;
|
||||||
}
|
}
|
||||||
@@ -111,6 +113,9 @@ function createProxy(
|
|||||||
root[signalKey] = signalData;
|
root[signalKey] = signalData;
|
||||||
onDispose.once(
|
onDispose.once(
|
||||||
signalData.subscribe(next => {
|
signalData.subscribe(next => {
|
||||||
|
if (!initialized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
byPassSignalUpdate(() => {
|
byPassSignalUpdate(() => {
|
||||||
proxy[p] = next;
|
proxy[p] = next;
|
||||||
onChange?.(firstKey, next);
|
onChange?.(firstKey, next);
|
||||||
@@ -137,7 +142,7 @@ function createProxy(
|
|||||||
if (isPureObject(value)) {
|
if (isPureObject(value)) {
|
||||||
const syncYMap = () => {
|
const syncYMap = () => {
|
||||||
yMap.forEach((_, key) => {
|
yMap.forEach((_, key) => {
|
||||||
if (keyWithoutPrefix(key).startsWith(fullPath)) {
|
if (initialized() && keyWithoutPrefix(key).startsWith(fullPath)) {
|
||||||
yMap.delete(key);
|
yMap.delete(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -148,13 +153,13 @@ function createProxy(
|
|||||||
run(value, fullPath);
|
run(value, fullPath);
|
||||||
} else {
|
} else {
|
||||||
list.push(() => {
|
list.push(() => {
|
||||||
yMap.set(keyWithPrefix(fullPath), value);
|
yMap.set(keyWithPrefix(fullPath), native2Y(value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
run(value, fullPath);
|
run(value, fullPath);
|
||||||
if (list.length) {
|
if (list.length && initialized()) {
|
||||||
yMap.doc?.transact(
|
yMap.doc?.transact(
|
||||||
() => {
|
() => {
|
||||||
list.forEach(fn => fn());
|
list.forEach(fn => fn());
|
||||||
@@ -180,7 +185,7 @@ function createProxy(
|
|||||||
|
|
||||||
const yValue = native2Y(value);
|
const yValue = native2Y(value);
|
||||||
const next = transform(firstKey, value, yValue);
|
const next = transform(firstKey, value, yValue);
|
||||||
if (!isStashed) {
|
if (!isStashed && initialized()) {
|
||||||
yMap.doc?.transact(
|
yMap.doc?.transact(
|
||||||
() => {
|
() => {
|
||||||
yMap.set(keyWithPrefix(fullPath), yValue);
|
yMap.set(keyWithPrefix(fullPath), yValue);
|
||||||
@@ -233,7 +238,7 @@ function createProxy(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isStashed) {
|
if (!isStashed && initialized()) {
|
||||||
yMap.doc?.transact(
|
yMap.doc?.transact(
|
||||||
() => {
|
() => {
|
||||||
const fullKey = keyWithPrefix(fullPath);
|
const fullKey = keyWithPrefix(fullPath);
|
||||||
@@ -268,6 +273,8 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
protected readonly _source: UnRecord;
|
protected readonly _source: UnRecord;
|
||||||
protected readonly _options?: ProxyOptions<UnRecord>;
|
protected readonly _options?: ProxyOptions<UnRecord>;
|
||||||
|
|
||||||
|
private readonly _initialized;
|
||||||
|
|
||||||
private readonly _observer = (event: YMapEvent<unknown>) => {
|
private readonly _observer = (event: YMapEvent<unknown>) => {
|
||||||
const yMap = this._ySource;
|
const yMap = this._ySource;
|
||||||
const proxy = this._proxy;
|
const proxy = this._proxy;
|
||||||
@@ -344,9 +351,12 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _createDefaultData = (): UnRecord => {
|
private readonly _createDefaultData = (): UnRecord => {
|
||||||
const data: UnRecord = {};
|
const root: UnRecord = {};
|
||||||
const transform = this._transform;
|
const transform = this._transform;
|
||||||
Array.from(this._ySource.entries()).forEach(([key, value]) => {
|
Array.from(this._ySource.entries()).forEach(([key, value]) => {
|
||||||
|
if (key.startsWith('sys')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const keys = keyWithoutPrefix(key).split('.');
|
const keys = keyWithoutPrefix(key).split('.');
|
||||||
const firstKey = keys[0];
|
const firstKey = keys[0];
|
||||||
|
|
||||||
@@ -356,7 +366,8 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
} else if (value instanceof YArray) {
|
} else if (value instanceof YArray) {
|
||||||
finalData = transform(firstKey, value.toArray(), value);
|
finalData = transform(firstKey, value.toArray(), value);
|
||||||
} else if (value instanceof YText) {
|
} 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) {
|
} else if (value instanceof YMap) {
|
||||||
throw new BlockSuiteError(
|
throw new BlockSuiteError(
|
||||||
ErrorCode.ReactiveProxyError,
|
ErrorCode.ReactiveProxyError,
|
||||||
@@ -369,21 +380,25 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
void keys.reduce((acc: UnRecord, key, index) => {
|
void keys.reduce((acc: UnRecord, key, index) => {
|
||||||
if (!acc[key] && index !== allLength - 1) {
|
if (!acc[key] && index !== allLength - 1) {
|
||||||
const path = keys.slice(0, index + 1).join('.');
|
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;
|
acc[key] = data;
|
||||||
}
|
}
|
||||||
if (index === allLength - 1) {
|
if (index === allLength - 1) {
|
||||||
acc[key] = finalData;
|
acc[key] = finalData;
|
||||||
}
|
}
|
||||||
return acc[key] as UnRecord;
|
return acc[key] as UnRecord;
|
||||||
}, data);
|
}, root);
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return root;
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _getProxy = (source: UnRecord, path?: string): UnRecord => {
|
private readonly _getProxy = (
|
||||||
return createProxy(this._ySource, source, source, {
|
source: UnRecord,
|
||||||
|
root: UnRecord,
|
||||||
|
path?: string
|
||||||
|
): UnRecord => {
|
||||||
|
return createProxy(this._ySource, source, root, {
|
||||||
onDispose: this._onDispose,
|
onDispose: this._onDispose,
|
||||||
shouldByPassSignal: () => this._skipNext,
|
shouldByPassSignal: () => this._skipNext,
|
||||||
byPassSignalUpdate: this._updateWithSkip,
|
byPassSignalUpdate: this._updateWithSkip,
|
||||||
@@ -391,6 +406,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
onChange: this._onChange,
|
onChange: this._onChange,
|
||||||
transform: this._transform,
|
transform: this._transform,
|
||||||
stashed: this._stashed,
|
stashed: this._stashed,
|
||||||
|
initialized: () => this._initialized,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -400,16 +416,20 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
private readonly _onChange?: OnChange
|
private readonly _onChange?: OnChange
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this._initialized = false;
|
||||||
const source = this._createDefaultData();
|
const source = this._createDefaultData();
|
||||||
this._source = source;
|
this._source = source;
|
||||||
|
|
||||||
const proxy = this._getProxy(source);
|
const proxy = this._getProxy(source, source);
|
||||||
|
|
||||||
Object.entries(source).forEach(([key, value]) => {
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
const signalData = signal(value);
|
const signalData = signal(value);
|
||||||
source[`${key}$`] = signalData;
|
source[`${key}$`] = signalData;
|
||||||
_onDispose.once(
|
_onDispose.once(
|
||||||
signalData.subscribe(next => {
|
signalData.subscribe(next => {
|
||||||
|
if (!this._initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._updateWithSkip(() => {
|
this._updateWithSkip(() => {
|
||||||
proxy[key] = next;
|
proxy[key] = next;
|
||||||
this._onChange?.(key, next);
|
this._onChange?.(key, next);
|
||||||
@@ -420,6 +440,7 @@ export class ReactiveFlatYMap extends BaseReactiveYData<
|
|||||||
|
|
||||||
this._proxy = proxy;
|
this._proxy = proxy;
|
||||||
this._ySource.observe(this._observer);
|
this._ySource.observe(this._observer);
|
||||||
|
this._initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pop = (prop: string): void => {
|
pop = (prop: string): void => {
|
||||||
|
|||||||
Reference in New Issue
Block a user