Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@blocksuite/store

Package Overview
Dependencies
Maintainers
5
Versions
1273
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blocksuite/store - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0-20230110000526-9d95ace

dist/workspace/migrations.d.ts

16

dist/base.d.ts

@@ -0,1 +1,2 @@

/// <reference types="blocksuite__global-types" />
import type { Page } from './workspace/index.js';

@@ -8,12 +9,5 @@ import type { TextType } from './text-adapter.js';

}
export interface IBaseBlockProps {
flavour: string;
type: string;
id: string;
children: IBaseBlockProps[];
text?: TextType;
}
export declare class BaseBlockModel implements IBaseBlockProps {
export declare class BaseBlockModel<Props = unknown> implements BlockSuiteInternal.IBaseBlockProps {
static version: number;
flavour: string;
flavour: keyof BlockSuiteInternal.BlockModels & string;
tag: StaticValue;

@@ -29,4 +23,4 @@ id: string;

sourceId?: string;
constructor(page: Page, props: Partial<IBaseBlockProps>);
firstChild(): BaseBlockModel | null;
constructor(page: Page, props: Pick<BlockSuiteInternal.IBaseBlockProps, 'id'>);
firstChild(): BaseBlockModel<unknown> | null;
lastChild(): BaseBlockModel | null;

@@ -33,0 +27,0 @@ block2html(childText: string, _previousSiblingId: string, _nextSiblingId: string, begin?: number, end?: number): string;

@@ -17,5 +17,7 @@ export * from './space.js';

? window
: typeof global !== 'undefined'
? global
: {};
: // @ts-ignore
typeof global !== 'undefined'
? // @ts-ignore
global
: {};
const importIdentifier = '__ $BLOCKSUITE_STORE$ __';

@@ -22,0 +24,0 @@ // @ts-ignore

@@ -54,10 +54,6 @@ import type { Space } from './space.js';

/**
* @internal Only for testing
*/
serializeDoc(): SerializedStore;
/**
* @internal Only for testing, 'page0' should be replaced by props 'spaceId'
*/
toJSXElement(id?: string): import("./utils/jsx.js").JSXElement | null;
exportJSX(id?: string): import("./utils/jsx.js").JSXElement | null;
}
//# sourceMappingURL=store.d.ts.map

@@ -56,12 +56,6 @@ import { Awareness } from 'y-protocols/awareness.js';

/**
* @internal Only for testing
*/
serializeDoc() {
return serializeYDoc(this.doc);
}
/**
* @internal Only for testing, 'page0' should be replaced by props 'spaceId'
*/
toJSXElement(id = '0') {
const json = this.serializeDoc();
exportJSX(id = '0') {
const json = serializeYDoc(this.doc);
if (!('space:page0' in json)) {

@@ -68,0 +62,0 @@ throw new Error("Failed to convert to JSX: 'space:page0' not found");

@@ -10,4 +10,4 @@ import { Doc } from 'yjs';

}
export declare const yDocToJSXNode: (serializedDoc: Record<string, unknown>, nodeId: string) => JSXElement;
export declare const serializeYDoc: (doc: Doc) => Record<string, unknown>;
export declare function yDocToJSXNode(serializedDoc: Record<string, unknown>, nodeId: string): JSXElement;
export declare function serializeYDoc(doc: Doc): Record<string, unknown>;
//# sourceMappingURL=jsx.d.ts.map

@@ -5,3 +5,3 @@ import { AbstractType, Map, Text, Array } from 'yjs';

const testSymbol = Symbol.for('react.test.json');
const isValidRecord = (data) => {
function isValidRecord(data) {
if (typeof data !== 'object' || data === null) {

@@ -12,5 +12,5 @@ return false;

return true;
};
}
const IGNORE_PROPS = ['sys:id', 'sys:flavour', 'sys:children'];
export const yDocToJSXNode = (serializedDoc, nodeId) => {
export function yDocToJSXNode(serializedDoc, nodeId) {
if (!isValidRecord(serializedDoc)) {

@@ -37,4 +37,4 @@ throw new Error('Failed to parse doc record! Invalid data.');

};
};
export const serializeYDoc = (doc) => {
}
export function serializeYDoc(doc) {
const json = {};

@@ -50,4 +50,4 @@ doc.share.forEach((value, key) => {

return json;
};
const serializeYMap = (map) => {
}
function serializeYMap(map) {
const json = {};

@@ -72,8 +72,8 @@ map.forEach((value, key) => {

return json;
};
const serializeYText = (text) => {
}
function serializeYText(text) {
const delta = text.toDelta();
return delta;
};
const parseDelta = (text) => {
}
function parseDelta(text) {
if (!text.length) {

@@ -104,3 +104,3 @@ return undefined;

};
};
}
//# sourceMappingURL=jsx.js.map

@@ -0,1 +1,2 @@

/// <reference types="blocksuite__global-types" />
import type { BaseBlockModel } from '../base.js';

@@ -7,3 +8,3 @@ import type { BlockProps, PrefixedBlockProps, YBlock, YBlocks } from '../workspace/page.js';

export declare function assertFlavours(model: BaseBlockModel, allowed: string[]): void;
export declare function matchFlavours(model: BaseBlockModel, expected: string[]): boolean;
export declare function matchFlavours<Key extends keyof BlockSuiteInternal.BlockModels & string = keyof BlockSuiteInternal.BlockModels & string>(model: BaseBlockModel, expected: Key[]): boolean;
export declare function assertValidChildren(yBlocks: YBlocks, props: Partial<BlockProps>): void;

@@ -10,0 +11,0 @@ export declare function initSysProps(yBlock: YBlock, props: Partial<BlockProps>): void;

@@ -67,3 +67,3 @@ import * as Y from 'yjs';

}
if (props.flavour === 'affine:group' && !yBlock.has('prop:xywh')) {
if (props.flavour === 'affine:frame' && !yBlock.has('prop:xywh')) {
yBlock.set('prop:xywh', props.xywh ?? '[0,0,720,480]');

@@ -70,0 +70,0 @@ }

@@ -0,1 +1,2 @@

/// <reference types="blocksuite__global-types" />
import * as Y from 'yjs';

@@ -38,4 +39,4 @@ import type { Quill } from 'quill';

historyUpdated: Signal<void>;
rootAdded: Signal<BaseBlockModel>;
rootDeleted: Signal<string>;
rootAdded: Signal<BaseBlockModel<unknown> | BaseBlockModel<unknown>[]>;
rootDeleted: Signal<string | string[]>;
textUpdated: Signal<Y.YTextEvent>;

@@ -49,3 +50,4 @@ updated: Signal<void>;

private get _yBlocks();
get root(): BaseBlockModel | null;
get root(): BaseBlockModel<unknown> | null;
get rootLayer(): BaseBlockModel<unknown> | null;
get isEmpty(): boolean;

@@ -60,12 +62,17 @@ get canUndo(): boolean;

resetHistory(): void;
getBlockById(id: string): BaseBlockModel | null;
getBlockByFlavour(blockFlavour: string): BaseBlockModel[];
getBlockById(id: string): BaseBlockModel<unknown> | null;
getBlockByFlavour(blockFlavour: string): BaseBlockModel<unknown>[];
getParentById(rootId: string, target: BaseBlockModel): BaseBlockModel | null;
getParent(block: BaseBlockModel): BaseBlockModel | null;
getPreviousSibling(block: BaseBlockModel): BaseBlockModel | null;
getPreviousSiblings(block: BaseBlockModel): BaseBlockModel[];
getNextSibling(block: BaseBlockModel): BaseBlockModel | null;
getNextSiblings(block: BaseBlockModel): BaseBlockModel[];
addBlock<T extends BlockProps>(blockProps: Partial<T>, parent?: BaseBlockModel | string, parentIndex?: number): string;
getParent(block: BaseBlockModel): BaseBlockModel<unknown> | null;
getPreviousSibling(block: BaseBlockModel): BaseBlockModel<unknown> | null;
getPreviousSiblings(block: BaseBlockModel): BaseBlockModel<unknown>[];
getNextSibling(block: BaseBlockModel): BaseBlockModel<unknown> | null;
getNextSiblings(block: BaseBlockModel): BaseBlockModel<unknown>[];
addBlockByFlavour<ALLProps extends Record<string, any> = BlockSuiteModelProps.ALL, Flavour extends keyof ALLProps & string = keyof ALLProps & string>(flavour: Flavour, blockProps?: Partial<ALLProps[Flavour] & Omit<BlockSuiteInternal.IBaseBlockProps, 'flavour' | 'id'>>, parent?: BaseBlockModel | string | null, parentIndex?: number): string;
/**
* @deprecated use `addBlockByFlavour`
*/
addBlock<T extends BlockProps>(blockProps: Partial<T>, parent?: BaseBlockModel | string | null, parentIndex?: number): string;
updateBlockById(id: string, props: Partial<BlockProps>): void;
moveBlock(model: BaseBlockModel, targetModel: BaseBlockModel, top?: boolean): void;
updateBlock<T extends Partial<BlockProps>>(model: BaseBlockModel, props: T): void;

@@ -72,0 +79,0 @@ deleteBlockById(id: string): void;

@@ -8,2 +8,3 @@ import * as Y from 'yjs';

import { assertValidChildren, initSysProps, syncBlockProps, trySyncTextProp, toBlockProps, matchFlavours, } from '../utils/utils.js';
import { tryMigrate } from './migrations.js';
const isWeb = typeof window !== 'undefined';

@@ -21,3 +22,5 @@ function createChildMap(yChildIds) {

// TODO use schema
this._ignoredKeys = new Set(Object.keys(new BaseBlockModel(this, {})));
this._ignoredKeys = new Set(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Object.keys(new BaseBlockModel(this, { id: null })));
this.signals = {

@@ -70,4 +73,7 @@ historyUpdated: new Signal(),

get root() {
return this._root;
return Array.isArray(this._root) ? this._root[0] : this._root;
}
get rootLayer() {
return Array.isArray(this._root) ? this._root[1] : null;
}
get isEmpty() {

@@ -120,5 +126,5 @@ return this._yBlocks.size === 0;

getParent(block) {
if (!this._root)
if (!this.root)
return null;
return this.getParentById(this._root.id, block);
return this.getParentById(this.root.id, block);
}

@@ -169,2 +175,11 @@ getPreviousSibling(block) {

}
addBlockByFlavour(flavour, blockProps = {}, parent, parentIndex) {
return this.addBlock({
flavour,
...blockProps,
}, parent, parentIndex);
}
/**
* @deprecated use `addBlockByFlavour`
*/
addBlock(blockProps, parent, parentIndex) {

@@ -174,7 +189,7 @@ if (!blockProps.flavour) {

}
if (blockProps.flavour === 'affine:shape') {
if (parent != null || parentIndex != null) {
throw new Error('Shape block should only be appear under page');
}
}
// if (blockProps.flavour === 'affine:shape') {
// if (parent != null || parentIndex != null) {
// throw new Error('Shape block should only be appear under page');
// }
// }
const clonedProps = { ...blockProps };

@@ -192,3 +207,3 @@ const id = this._idGenerator();

}
const parentId = parent?.id ?? this._root?.id;
const parentId = parent === null ? null : parent?.id ?? this.root?.id;
if (parentId) {

@@ -208,2 +223,28 @@ const yParent = this._yBlocks.get(parentId);

}
moveBlock(model, targetModel, top = true) {
const currentParentModel = this.getParent(model);
const nextParentModel = this.getParent(targetModel);
if (currentParentModel === null || nextParentModel === null) {
throw new Error('cannot find parent model');
}
this.transact(() => {
const yParentA = this._yBlocks.get(currentParentModel.id);
const yChildrenA = yParentA.get('sys:children');
const idx = yChildrenA.toArray().findIndex(id => id === model.id);
yChildrenA.delete(idx);
const yParentB = this._yBlocks.get(nextParentModel.id);
const yChildrenB = yParentB.get('sys:children');
const nextIdx = yChildrenB
.toArray()
.findIndex(id => id === targetModel.id);
if (top) {
yChildrenB.insert(nextIdx, [model.id]);
}
else {
yChildrenB.insert(nextIdx + 1, [model.id]);
}
});
currentParentModel.propsUpdated.emit();
nextParentModel.propsUpdated.emit();
}
updateBlock(model, props) {

@@ -283,2 +324,3 @@ const yBlock = this._yBlocks.get(model.id);

}
tryMigrate(this.doc);
this._handleVersion();

@@ -335,2 +377,5 @@ this._initYBlocks();

}
else if (!props.id) {
throw new Error('Block id is not defined');
}
const blockModel = new BlockModelCtor(this, props);

@@ -342,5 +387,9 @@ return blockModel;

const isRoot = this._blockMap.size === 0;
let isSurface = false;
const prefixedProps = yBlock.toJSON();
const props = toBlockProps(prefixedProps);
const model = this._createBlockModel({ ...props, id });
if (model.flavour === 'affine:surface') {
isSurface = true;
}
this._blockMap.set(props.id, model);

@@ -380,2 +429,6 @@ if (

}
else if (isSurface) {
this._root = [this.root, model];
this.signals.rootAdded.emit(this._root);
}
else {

@@ -382,0 +435,0 @@ const parent = this.getParent(model);

@@ -78,7 +78,13 @@ import * as Y from 'yjs';

removePage(pageId: string): void;
serializeDoc(): import("../store.js").SerializedStore;
search(query: QueryContent): Map<string, string>;
toJSXElement(id?: string): import("../utils/jsx.js").JSXElement | null;
/**
* @internal Only for testing
*/
exportYDoc(): void;
/**
* @internal Only for testing
*/
exportJSX(id?: string): import("../utils/jsx.js").JSXElement | null;
}
export {};
//# sourceMappingURL=workspace.d.ts.map

@@ -237,13 +237,26 @@ import * as Y from 'yjs';

}
serializeDoc() {
return this._store.serializeDoc();
}
search(query) {
return this._indexer.search(query);
}
toJSXElement(id = '0') {
return this._store.toJSXElement(id);
/**
* @internal Only for testing
*/
exportYDoc() {
const binary = Y.encodeStateAsUpdate(this.doc);
const file = new Blob([binary], { type: 'application/octet-stream' });
const fileUrl = URL.createObjectURL(file);
const link = document.createElement('a');
link.href = fileUrl;
link.download = 'workspace.ydoc';
link.click();
URL.revokeObjectURL(fileUrl);
}
/**
* @internal Only for testing
*/
exportJSX(id = '0') {
return this._store.exportJSX(id);
}
}
Workspace.Y = Y;
//# sourceMappingURL=workspace.js.map
{
"name": "@blocksuite/store",
"version": "0.3.1",
"version": "0.4.0-20230110000526-9d95ace",
"description": "BlockSuite data store built for general purpose state management.",

@@ -24,3 +24,3 @@ "main": "dist/index.js",

"lit": "^2.5.0",
"yjs": "^13.5.43"
"yjs": "^13.5.44"
},

@@ -27,0 +27,0 @@ "peerDependencies": {

@@ -7,2 +7,2 @@ # `@blocksuite/store`

WIP
TBD

@@ -17,3 +17,3 @@ /* eslint-disable @typescript-eslint/no-restricted-imports */

import { ListBlockModel } from '../../../blocks/src/list-block/list-model.js';
import { GroupBlockModel } from '../../../blocks/src/group-block/group-model.js';
import { FrameBlockModel } from '../../../blocks/src/frame-block/frame-model.js';
import { DividerBlockModel } from '../../../blocks/src/divider-block/divider-model.js';

@@ -33,3 +33,3 @@ import type { PageMeta } from '../workspace/index.js';

'affine:list': ListBlockModel,
'affine:group': GroupBlockModel,
'affine:frame': FrameBlockModel,
'affine:divider': DividerBlockModel,

@@ -72,3 +72,3 @@ } as const;

describe.concurrent('basic', () => {
it('can init store', async () => {
it('can init workspace', async () => {
const options = createTestOptions();

@@ -346,4 +346,4 @@ const workspace = new Workspace(options);

// Inline snapshot is not supported under describe.parallel config
describe('store.toJSXElement works', async () => {
it('store matches snapshot', async () => {
describe('workspace.exportJSX works', async () => {
it('workspace matches snapshot', async () => {
const options = createTestOptions();

@@ -355,3 +355,3 @@ const workspace = new Workspace(options).register(BlockSchema);

expect(workspace.toJSXElement()).toMatchInlineSnapshot(`
expect(workspace.exportJSX()).toMatchInlineSnapshot(`
<affine:page

@@ -363,3 +363,3 @@ prop:title="hello"

it('empty store matches snapshot', async () => {
it('empty workspace matches snapshot', async () => {
const options = createTestOptions();

@@ -369,6 +369,6 @@ const workspace = new Workspace(options).register(BlockSchema);

expect(workspace.toJSXElement()).toMatchInlineSnapshot('null');
expect(workspace.exportJSX()).toMatchInlineSnapshot('null');
});
it('store with multiple blocks children matches snapshot', async () => {
it('workspace with multiple blocks children matches snapshot', async () => {
const options = createTestOptions();

@@ -382,3 +382,3 @@ const workspace = new Workspace(options).register(BlockSchema);

expect(workspace.toJSXElement()).toMatchInlineSnapshot(/* xml */ `
expect(workspace.exportJSX()).toMatchInlineSnapshot(/* xml */ `
<affine:page>

@@ -396,4 +396,4 @@ <affine:paragraph

describe.concurrent('store.search works', async () => {
it('store search matching', async () => {
describe.concurrent('workspace.search works', async () => {
it('workspace search matching', async () => {
const options = createTestOptions();

@@ -400,0 +400,0 @@ const workspace = new Workspace(options).register(BlockSchema);

@@ -11,15 +11,7 @@ import type { Page } from './workspace/index.js';

export interface IBaseBlockProps {
flavour: string;
type: string;
id: string;
children: IBaseBlockProps[];
// TODO use schema
text?: TextType;
}
export class BaseBlockModel implements IBaseBlockProps {
export class BaseBlockModel<Props = unknown>
implements BlockSuiteInternal.IBaseBlockProps
{
static version: number;
flavour!: string;
flavour!: keyof BlockSuiteInternal.BlockModels & string;
tag!: StaticValue;

@@ -39,5 +31,8 @@ id: string;

constructor(page: Page, props: Partial<IBaseBlockProps>) {
constructor(
page: Page,
props: Pick<BlockSuiteInternal.IBaseBlockProps, 'id'>
) {
this.page = page;
this.id = props.id as string;
this.id = props.id;
this.children = [];

@@ -44,0 +39,0 @@ }

@@ -24,4 +24,6 @@ export * from './space.js';

? window
: typeof global !== 'undefined'
? global
: // @ts-ignore
typeof global !== 'undefined'
? // @ts-ignore
global
: {};

@@ -28,0 +30,0 @@ const importIdentifier = '__ $BLOCKSUITE_STORE$ __';

@@ -104,13 +104,6 @@ import type { Space } from './space.js';

/**
* @internal Only for testing
*/
serializeDoc() {
return serializeYDoc(this.doc) as unknown as SerializedStore;
}
/**
* @internal Only for testing, 'page0' should be replaced by props 'spaceId'
*/
toJSXElement(id = '0') {
const json = this.serializeDoc();
exportJSX(id = '0') {
const json = serializeYDoc(this.doc) as unknown as SerializedStore;
if (!('space:page0' in json)) {

@@ -117,0 +110,0 @@ throw new Error("Failed to convert to JSX: 'space:page0' not found");

@@ -24,3 +24,3 @@ import { AbstractType, Doc, Map, Text, Array } from 'yjs';

const isValidRecord = (data: unknown): data is DocRecord => {
function isValidRecord(data: unknown): data is DocRecord {
if (typeof data !== 'object' || data === null) {

@@ -31,10 +31,10 @@ return false;

return true;
};
}
const IGNORE_PROPS = ['sys:id', 'sys:flavour', 'sys:children'];
export const yDocToJSXNode = (
export function yDocToJSXNode(
serializedDoc: Record<string, unknown>,
nodeId: string
): JSXElement => {
): JSXElement {
if (!isValidRecord(serializedDoc)) {

@@ -67,5 +67,5 @@ throw new Error('Failed to parse doc record! Invalid data.');

};
};
}
export const serializeYDoc = (doc: Doc) => {
export function serializeYDoc(doc: Doc) {
const json: Record<string, unknown> = {};

@@ -80,5 +80,5 @@ doc.share.forEach((value, key) => {

return json;
};
}
const serializeYMap = (map: Map<unknown>): unknown => {
function serializeYMap(map: Map<unknown>) {
const json: Record<string, unknown> = {};

@@ -99,3 +99,3 @@ map.forEach((value, key) => {

return json;
};
}

@@ -107,8 +107,8 @@ type DeltaText = {

const serializeYText = (text: Text): DeltaText => {
function serializeYText(text: Text): DeltaText {
const delta = text.toDelta();
return delta;
};
}
const parseDelta = (text: DeltaText) => {
function parseDelta(text: DeltaText) {
if (!text.length) {

@@ -139,2 +139,2 @@ return undefined;

};
};
}

@@ -34,4 +34,10 @@ import * as Y from 'yjs';

export function matchFlavours(model: BaseBlockModel, expected: string[]) {
return expected.includes(model.flavour);
export function matchFlavours<
Key extends keyof BlockSuiteInternal.BlockModels &
string = keyof BlockSuiteInternal.BlockModels & string
>(
model: BaseBlockModel,
expected: Key[]
): boolean /* model is BlockModels[Key] */ {
return expected.includes(model.flavour as Key);
}

@@ -99,3 +105,3 @@

}
if (props.flavour === 'affine:group' && !yBlock.has('prop:xywh')) {
if (props.flavour === 'affine:frame' && !yBlock.has('prop:xywh')) {
yBlock.set('prop:xywh', props.xywh ?? '[0,0,720,480]');

@@ -102,0 +108,0 @@ }

@@ -25,2 +25,3 @@ import * as Y from 'yjs';

import type { BlockSuiteDoc } from '../yjs/index.js';
import { tryMigrate } from './migrations.js';

@@ -58,3 +59,3 @@ export type YBlock = Y.Map<unknown>;

private _history!: Y.UndoManager;
private _root: BaseBlockModel | null = null;
private _root: BaseBlockModel | BaseBlockModel[] | null = null;
private _blockMap = new Map<string, BaseBlockModel>();

@@ -66,3 +67,4 @@ private _splitSet = new Set<Text | PrelimText>();

private _ignoredKeys = new Set<string>(
Object.keys(new BaseBlockModel(this, {}))
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Object.keys(new BaseBlockModel(this, { id: null! }))
);

@@ -72,4 +74,4 @@

historyUpdated: new Signal(),
rootAdded: new Signal<BaseBlockModel>(),
rootDeleted: new Signal<string>(),
rootAdded: new Signal<BaseBlockModel | BaseBlockModel[]>(),
rootDeleted: new Signal<string | string[]>(),
textUpdated: new Signal<Y.YTextEvent>(),

@@ -105,5 +107,9 @@ updated: new Signal(),

get root() {
return this._root;
return Array.isArray(this._root) ? this._root[0] : this._root;
}
get rootLayer() {
return Array.isArray(this._root) ? this._root[1] : null;
}
get isEmpty() {

@@ -168,5 +174,5 @@ return this._yBlocks.size === 0;

getParent(block: BaseBlockModel) {
if (!this._root) return null;
if (!this.root) return null;
return this.getParentById(this._root.id, block);
return this.getParentById(this.root.id, block);
}

@@ -230,5 +236,31 @@

public addBlockByFlavour<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ALLProps extends Record<string, any> = BlockSuiteModelProps.ALL,
Flavour extends keyof ALLProps & string = keyof ALLProps & string
>(
flavour: Flavour,
blockProps: Partial<
ALLProps[Flavour] &
Omit<BlockSuiteInternal.IBaseBlockProps, 'flavour' | 'id'>
> = {},
parent?: BaseBlockModel | string | null,
parentIndex?: number
) {
return this.addBlock(
{
flavour,
...blockProps,
},
parent,
parentIndex
);
}
/**
* @deprecated use `addBlockByFlavour`
*/
addBlock<T extends BlockProps>(
blockProps: Partial<T>,
parent?: BaseBlockModel | string,
parent?: BaseBlockModel | string | null,
parentIndex?: number

@@ -240,7 +272,7 @@ ): string {

if (blockProps.flavour === 'affine:shape') {
if (parent != null || parentIndex != null) {
throw new Error('Shape block should only be appear under page');
}
}
// if (blockProps.flavour === 'affine:shape') {
// if (parent != null || parentIndex != null) {
// throw new Error('Shape block should only be appear under page');
// }
// }

@@ -263,3 +295,3 @@ const clonedProps: Partial<BlockProps> = { ...blockProps };

const parentId = parent?.id ?? this._root?.id;
const parentId = parent === null ? null : parent?.id ?? this.root?.id;

@@ -283,2 +315,28 @@ if (parentId) {

moveBlock(model: BaseBlockModel, targetModel: BaseBlockModel, top = true) {
const currentParentModel = this.getParent(model);
const nextParentModel = this.getParent(targetModel);
if (currentParentModel === null || nextParentModel === null) {
throw new Error('cannot find parent model');
}
this.transact(() => {
const yParentA = this._yBlocks.get(currentParentModel.id) as YBlock;
const yChildrenA = yParentA.get('sys:children') as Y.Array<string>;
const idx = yChildrenA.toArray().findIndex(id => id === model.id);
yChildrenA.delete(idx);
const yParentB = this._yBlocks.get(nextParentModel.id) as YBlock;
const yChildrenB = yParentB.get('sys:children') as Y.Array<string>;
const nextIdx = yChildrenB
.toArray()
.findIndex(id => id === targetModel.id);
if (top) {
yChildrenB.insert(nextIdx, [model.id]);
} else {
yChildrenB.insert(nextIdx + 1, [model.id]);
}
});
currentParentModel.propsUpdated.emit();
nextParentModel.propsUpdated.emit();
}
updateBlock<T extends Partial<BlockProps>>(model: BaseBlockModel, props: T) {

@@ -376,2 +434,4 @@ const yBlock = this._yBlocks.get(model.id) as YBlock;

tryMigrate(this.doc);
this._handleVersion();

@@ -461,5 +521,10 @@ this._initYBlocks();

throw new Error(`Block flavour ${props.flavour} is not registered`);
} else if (!props.id) {
throw new Error('Block id is not defined');
}
const blockModel = new BlockModelCtor(this, props);
const blockModel = new BlockModelCtor(
this,
props as PropsWithId<Omit<BlockProps, 'children'>>
);
return blockModel;

@@ -471,2 +536,3 @@ }

const isRoot = this._blockMap.size === 0;
let isSurface = false;

@@ -476,2 +542,5 @@ const prefixedProps = yBlock.toJSON() as PrefixedBlockProps;

const model = this._createBlockModel({ ...props, id });
if (model.flavour === 'affine:surface') {
isSurface = true;
}
this._blockMap.set(props.id, model);

@@ -518,2 +587,5 @@

this.signals.rootAdded.emit(model);
} else if (isSurface) {
this._root = [this.root as BaseBlockModel, model];
this.signals.rootAdded.emit(this._root);
} else {

@@ -520,0 +592,0 @@ const parent = this.getParent(model);

@@ -334,6 +334,2 @@ import * as Y from 'yjs';

serializeDoc() {
return this._store.serializeDoc();
}
search(query: QueryContent) {

@@ -343,5 +339,24 @@ return this._indexer.search(query);

toJSXElement(id = '0') {
return this._store.toJSXElement(id);
/**
* @internal Only for testing
*/
exportYDoc() {
const binary = Y.encodeStateAsUpdate(this.doc);
const file = new Blob([binary], { type: 'application/octet-stream' });
const fileUrl = URL.createObjectURL(file);
const link = document.createElement('a');
link.href = fileUrl;
link.download = 'workspace.ydoc';
link.click();
URL.revokeObjectURL(fileUrl);
}
/**
* @internal Only for testing
*/
exportJSX(id = '0') {
return this._store.exportJSX(id);
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc