mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-06 03:49:56 +08:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import type {
|
||||
GfxCommonBlockProps,
|
||||
GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { GfxCompatible } from '@blocksuite/block-std/gfx';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../utils/index.js';
|
||||
import { AttachmentBlockTransformer } from './attachment-transformer.js';
|
||||
|
||||
/**
|
||||
* When the attachment is uploading, the `sourceId` is `undefined`.
|
||||
* And we can query the upload status by the `isAttachmentLoading` function.
|
||||
*
|
||||
* Other collaborators will see an error attachment block when the blob has not finished uploading.
|
||||
* This issue can be resolve by sync the upload status through the awareness system in the future.
|
||||
*
|
||||
* When the attachment is uploaded, the `sourceId` is the id of the blob.
|
||||
*
|
||||
* If there are no `sourceId` and the `isAttachmentLoading` function returns `false`,
|
||||
* it means that the attachment is failed to upload.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
type BackwardCompatibleUndefined = undefined;
|
||||
|
||||
export const AttachmentBlockStyles: EmbedCardStyle[] = [
|
||||
'cubeThick',
|
||||
'horizontalThin',
|
||||
'pdf',
|
||||
] as const;
|
||||
|
||||
export type AttachmentBlockProps = {
|
||||
name: string;
|
||||
size: number;
|
||||
/**
|
||||
* MIME type
|
||||
*/
|
||||
type: string;
|
||||
caption?: string;
|
||||
// `loadingKey` was used to indicate whether the attachment is loading,
|
||||
// which is currently unused but no breaking change is needed.
|
||||
// The `loadingKey` and `sourceId` should not be existed at the same time.
|
||||
// loadingKey?: string | null;
|
||||
sourceId?: string;
|
||||
/**
|
||||
* Whether to show the attachment as an embed view.
|
||||
*/
|
||||
embed: boolean | BackwardCompatibleUndefined;
|
||||
|
||||
style?: (typeof AttachmentBlockStyles)[number];
|
||||
} & Omit<GfxCommonBlockProps, 'scale'>;
|
||||
|
||||
export const defaultAttachmentProps: AttachmentBlockProps = {
|
||||
name: '',
|
||||
size: 0,
|
||||
type: 'application/octet-stream',
|
||||
sourceId: undefined,
|
||||
caption: undefined,
|
||||
embed: false,
|
||||
style: AttachmentBlockStyles[1],
|
||||
index: 'a0',
|
||||
xywh: '[0,0,0,0]',
|
||||
lockedBySelf: false,
|
||||
rotate: 0,
|
||||
};
|
||||
|
||||
export const AttachmentBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:attachment',
|
||||
props: (): AttachmentBlockProps => defaultAttachmentProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:surface',
|
||||
'affine:edgeless-text',
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
],
|
||||
},
|
||||
transformer: () => new AttachmentBlockTransformer(),
|
||||
toModel: () => new AttachmentBlockModel(),
|
||||
});
|
||||
|
||||
export class AttachmentBlockModel
|
||||
extends GfxCompatible<AttachmentBlockProps>(BlockModel)
|
||||
implements GfxElementGeometry {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:attachment': AttachmentBlockModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:attachment': AttachmentBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { FromSnapshotPayload, SnapshotNode } from '@blocksuite/store';
|
||||
import { BaseBlockTransformer } from '@blocksuite/store';
|
||||
|
||||
import type { AttachmentBlockProps } from './attachment-model.js';
|
||||
|
||||
export class AttachmentBlockTransformer extends BaseBlockTransformer<AttachmentBlockProps> {
|
||||
override async fromSnapshot(
|
||||
payload: FromSnapshotPayload
|
||||
): Promise<SnapshotNode<AttachmentBlockProps>> {
|
||||
const snapshotRet = await super.fromSnapshot(payload);
|
||||
const sourceId = snapshotRet.props.sourceId;
|
||||
if (!payload.assets.isEmpty() && sourceId)
|
||||
await payload.assets.writeToBlob(sourceId);
|
||||
|
||||
return snapshotRet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './attachment-model.js';
|
||||
export * from './attachment-transformer.js';
|
||||
@@ -0,0 +1,70 @@
|
||||
import type {
|
||||
GfxCommonBlockProps,
|
||||
GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { GfxCompatible } from '@blocksuite/block-std/gfx';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle, LinkPreviewData } from '../../utils/index.js';
|
||||
|
||||
export const BookmarkStyles: EmbedCardStyle[] = [
|
||||
'vertical',
|
||||
'horizontal',
|
||||
'list',
|
||||
'cube',
|
||||
] as const;
|
||||
|
||||
export type BookmarkBlockProps = {
|
||||
style: (typeof BookmarkStyles)[number];
|
||||
url: string;
|
||||
caption: string | null;
|
||||
} & LinkPreviewData &
|
||||
Omit<GfxCommonBlockProps, 'scale'>;
|
||||
|
||||
const defaultBookmarkProps: BookmarkBlockProps = {
|
||||
style: BookmarkStyles[1],
|
||||
url: '',
|
||||
caption: null,
|
||||
|
||||
description: null,
|
||||
icon: null,
|
||||
image: null,
|
||||
title: null,
|
||||
|
||||
index: 'a0',
|
||||
xywh: '[0,0,0,0]',
|
||||
lockedBySelf: false,
|
||||
rotate: 0,
|
||||
};
|
||||
|
||||
export const BookmarkBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:bookmark',
|
||||
props: (): BookmarkBlockProps => defaultBookmarkProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:surface',
|
||||
'affine:edgeless-text',
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
],
|
||||
},
|
||||
toModel: () => new BookmarkBlockModel(),
|
||||
});
|
||||
|
||||
export class BookmarkBlockModel
|
||||
extends GfxCompatible<BookmarkBlockProps>(BlockModel)
|
||||
implements GfxElementGeometry {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:bookmark': BookmarkBlockModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:bookmark': BookmarkBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './bookmark-model.js';
|
||||
@@ -0,0 +1,44 @@
|
||||
import {
|
||||
defineBlockSchema,
|
||||
type SchemaToModel,
|
||||
type Text,
|
||||
} from '@blocksuite/store';
|
||||
|
||||
interface CodeBlockProps {
|
||||
text: Text;
|
||||
language: string | null;
|
||||
wrap: boolean;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
export const CodeBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:code',
|
||||
props: internal =>
|
||||
({
|
||||
text: internal.Text(),
|
||||
language: null,
|
||||
wrap: false,
|
||||
caption: '',
|
||||
}) as CodeBlockProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
'affine:edgeless-text',
|
||||
],
|
||||
children: [],
|
||||
},
|
||||
});
|
||||
|
||||
export type CodeBlockModel = SchemaToModel<typeof CodeBlockSchema>;
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:code': CodeBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './code-model.js';
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Text } from '@blocksuite/store';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import type { Column, SerializedCells, ViewBasicDataType } from './types.js';
|
||||
|
||||
export type DatabaseBlockProps = {
|
||||
views: ViewBasicDataType[];
|
||||
title: Text;
|
||||
cells: SerializedCells;
|
||||
columns: Array<Column>;
|
||||
};
|
||||
|
||||
export class DatabaseBlockModel extends BlockModel<DatabaseBlockProps> {}
|
||||
|
||||
export const DatabaseBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:database',
|
||||
props: (internal): DatabaseBlockProps => ({
|
||||
views: [],
|
||||
title: internal.Text(),
|
||||
cells: Object.create(null),
|
||||
columns: [],
|
||||
}),
|
||||
metadata: {
|
||||
role: 'hub',
|
||||
version: 3,
|
||||
parent: ['affine:note'],
|
||||
children: ['affine:paragraph', 'affine:list'],
|
||||
},
|
||||
toModel: () => new DatabaseBlockModel(),
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './database-model.js';
|
||||
export * from './types.js';
|
||||
@@ -0,0 +1,21 @@
|
||||
export interface Column<
|
||||
Data extends Record<string, unknown> = Record<string, unknown>,
|
||||
> {
|
||||
id: string;
|
||||
type: string;
|
||||
name: string;
|
||||
data: Data;
|
||||
}
|
||||
|
||||
export type ColumnUpdater<T extends Column = Column> = (data: T) => Partial<T>;
|
||||
export type Cell<ValueType = unknown> = {
|
||||
columnId: Column['id'];
|
||||
value: ValueType;
|
||||
};
|
||||
|
||||
export type SerializedCells = Record<string, Record<string, Cell>>;
|
||||
export type ViewBasicDataType = {
|
||||
id: string;
|
||||
name: string;
|
||||
mode: string;
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { defineBlockSchema, type SchemaToModel } from '@blocksuite/store';
|
||||
|
||||
export const DividerBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:divider',
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
children: [],
|
||||
},
|
||||
});
|
||||
|
||||
export type DividerBlockModel = SchemaToModel<typeof DividerBlockSchema>;
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:divider': DividerBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './divider-model.js';
|
||||
@@ -0,0 +1,74 @@
|
||||
import type {
|
||||
GfxCommonBlockProps,
|
||||
GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { GfxCompatible } from '@blocksuite/block-std/gfx';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import {
|
||||
FontFamily,
|
||||
FontStyle,
|
||||
FontWeight,
|
||||
TextAlign,
|
||||
type TextStyleProps,
|
||||
} from '../../consts/index.js';
|
||||
|
||||
type EdgelessTextProps = {
|
||||
hasMaxWidth: boolean;
|
||||
} & Omit<TextStyleProps, 'fontSize'> &
|
||||
GfxCommonBlockProps;
|
||||
|
||||
export const EdgelessTextBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:edgeless-text',
|
||||
props: (): EdgelessTextProps => ({
|
||||
xywh: '[0,0,16,16]',
|
||||
index: 'a0',
|
||||
lockedBySelf: false,
|
||||
color: '#000000',
|
||||
fontFamily: FontFamily.Inter,
|
||||
fontStyle: FontStyle.Normal,
|
||||
fontWeight: FontWeight.Regular,
|
||||
textAlign: TextAlign.Left,
|
||||
scale: 1,
|
||||
rotate: 0,
|
||||
hasMaxWidth: false,
|
||||
}),
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'hub',
|
||||
parent: ['affine:surface'],
|
||||
children: [
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
'affine:code',
|
||||
'affine:image',
|
||||
'affine:bookmark',
|
||||
'affine:attachment',
|
||||
'affine:embed-!(synced-doc)',
|
||||
'affine:latex',
|
||||
],
|
||||
},
|
||||
toModel: () => {
|
||||
return new EdgelessTextBlockModel();
|
||||
},
|
||||
});
|
||||
|
||||
export class EdgelessTextBlockModel
|
||||
extends GfxCompatible<EdgelessTextProps>(BlockModel)
|
||||
implements GfxElementGeometry {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:edgeless-text': EdgelessTextBlockModel;
|
||||
}
|
||||
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:edgeless-text': EdgelessTextBlockModel;
|
||||
}
|
||||
|
||||
interface EdgelessTextModelMap {
|
||||
'edgeless-text': EdgelessTextBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './edgeless-text-model.js';
|
||||
@@ -0,0 +1,32 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export type EmbedFigmaBlockUrlData = {
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
};
|
||||
|
||||
export const EmbedFigmaStyles: EmbedCardStyle[] = ['figma'] as const;
|
||||
|
||||
export type EmbedFigmaBlockProps = {
|
||||
style: (typeof EmbedFigmaStyles)[number];
|
||||
url: string;
|
||||
caption: string | null;
|
||||
} & EmbedFigmaBlockUrlData;
|
||||
|
||||
export class EmbedFigmaModel extends defineEmbedModel<EmbedFigmaBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-figma': EmbedFigmaModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-figma': EmbedFigmaModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedFigmaBlockProps,
|
||||
EmbedFigmaModel,
|
||||
EmbedFigmaStyles,
|
||||
} from './figma-model.js';
|
||||
|
||||
const defaultEmbedFigmaProps: EmbedFigmaBlockProps = {
|
||||
style: EmbedFigmaStyles[0],
|
||||
url: '',
|
||||
caption: null,
|
||||
|
||||
title: null,
|
||||
description: null,
|
||||
};
|
||||
|
||||
export const EmbedFigmaBlockSchema = createEmbedBlockSchema({
|
||||
name: 'figma',
|
||||
version: 1,
|
||||
toModel: () => new EmbedFigmaModel(),
|
||||
props: (): EmbedFigmaBlockProps => defaultEmbedFigmaProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './figma-model.js';
|
||||
export * from './figma-schema.js';
|
||||
@@ -0,0 +1,46 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export type EmbedGithubBlockUrlData = {
|
||||
image: string | null;
|
||||
status: string | null;
|
||||
statusReason: string | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
createdAt: string | null;
|
||||
assignees: string[] | null;
|
||||
};
|
||||
|
||||
export const EmbedGithubStyles: EmbedCardStyle[] = [
|
||||
'vertical',
|
||||
'horizontal',
|
||||
'list',
|
||||
'cube',
|
||||
] as const;
|
||||
|
||||
export type EmbedGithubBlockProps = {
|
||||
style: (typeof EmbedGithubStyles)[number];
|
||||
owner: string;
|
||||
repo: string;
|
||||
githubType: 'issue' | 'pr';
|
||||
githubId: string;
|
||||
url: string;
|
||||
caption: string | null;
|
||||
} & EmbedGithubBlockUrlData;
|
||||
|
||||
export class EmbedGithubModel extends defineEmbedModel<EmbedGithubBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-github': EmbedGithubModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-github': EmbedGithubModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedGithubBlockProps,
|
||||
EmbedGithubModel,
|
||||
EmbedGithubStyles,
|
||||
} from './github-model.js';
|
||||
|
||||
const defaultEmbedGithubProps: EmbedGithubBlockProps = {
|
||||
style: EmbedGithubStyles[1],
|
||||
owner: '',
|
||||
repo: '',
|
||||
githubType: 'issue',
|
||||
githubId: '',
|
||||
url: '',
|
||||
caption: null,
|
||||
|
||||
image: null,
|
||||
status: null,
|
||||
statusReason: null,
|
||||
title: null,
|
||||
description: null,
|
||||
createdAt: null,
|
||||
assignees: null,
|
||||
};
|
||||
|
||||
export const EmbedGithubBlockSchema = createEmbedBlockSchema({
|
||||
name: 'github',
|
||||
version: 1,
|
||||
toModel: () => new EmbedGithubModel(),
|
||||
props: (): EmbedGithubBlockProps => defaultEmbedGithubProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './github-model.js';
|
||||
export * from './github-schema.js';
|
||||
@@ -0,0 +1,28 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export const EmbedHtmlStyles: EmbedCardStyle[] = ['html'] as const;
|
||||
|
||||
export type EmbedHtmlBlockProps = {
|
||||
style: (typeof EmbedHtmlStyles)[number];
|
||||
caption: string | null;
|
||||
html?: string;
|
||||
design?: string;
|
||||
};
|
||||
|
||||
export class EmbedHtmlModel extends defineEmbedModel<EmbedHtmlBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-html': EmbedHtmlModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-html': EmbedHtmlModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedHtmlBlockProps,
|
||||
EmbedHtmlModel,
|
||||
EmbedHtmlStyles,
|
||||
} from './html-model.js';
|
||||
|
||||
const defaultEmbedHtmlProps: EmbedHtmlBlockProps = {
|
||||
style: EmbedHtmlStyles[0],
|
||||
caption: null,
|
||||
html: undefined,
|
||||
design: undefined,
|
||||
};
|
||||
|
||||
export const EmbedHtmlBlockSchema = createEmbedBlockSchema({
|
||||
name: 'html',
|
||||
version: 1,
|
||||
toModel: () => new EmbedHtmlModel(),
|
||||
props: (): EmbedHtmlBlockProps => defaultEmbedHtmlProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './html-model.js';
|
||||
export * from './html-schema.js';
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './figma/index.js';
|
||||
export * from './github/index.js';
|
||||
export * from './html/index.js';
|
||||
export * from './linked-doc/index.js';
|
||||
export * from './loom/index.js';
|
||||
export * from './synced-doc/index.js';
|
||||
export * from './youtube/index.js';
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './linked-doc-model.js';
|
||||
export * from './linked-doc-schema.js';
|
||||
@@ -0,0 +1,33 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { ReferenceInfo } from '../../../consts/doc.js';
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export const EmbedLinkedDocStyles: EmbedCardStyle[] = [
|
||||
'vertical',
|
||||
'horizontal',
|
||||
'list',
|
||||
'cube',
|
||||
'horizontalThin',
|
||||
];
|
||||
|
||||
export type EmbedLinkedDocBlockProps = {
|
||||
style: EmbedCardStyle;
|
||||
caption: string | null;
|
||||
} & ReferenceInfo;
|
||||
|
||||
export class EmbedLinkedDocModel extends defineEmbedModel<EmbedLinkedDocBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-linked-doc': EmbedLinkedDocModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-linked-doc': EmbedLinkedDocModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedLinkedDocBlockProps,
|
||||
EmbedLinkedDocModel,
|
||||
EmbedLinkedDocStyles,
|
||||
} from './linked-doc-model.js';
|
||||
|
||||
const defaultEmbedLinkedDocBlockProps: EmbedLinkedDocBlockProps = {
|
||||
pageId: '',
|
||||
style: EmbedLinkedDocStyles[1],
|
||||
caption: null,
|
||||
// title & description aliases
|
||||
title: undefined,
|
||||
description: undefined,
|
||||
};
|
||||
|
||||
export const EmbedLinkedDocBlockSchema = createEmbedBlockSchema({
|
||||
name: 'linked-doc',
|
||||
version: 1,
|
||||
toModel: () => new EmbedLinkedDocModel(),
|
||||
props: (): EmbedLinkedDocBlockProps => defaultEmbedLinkedDocBlockProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './loom-model.js';
|
||||
export * from './loom-schema.js';
|
||||
@@ -0,0 +1,34 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export type EmbedLoomBlockUrlData = {
|
||||
videoId: string | null;
|
||||
image: string | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
};
|
||||
|
||||
export const EmbedLoomStyles: EmbedCardStyle[] = ['video'] as const;
|
||||
|
||||
export type EmbedLoomBlockProps = {
|
||||
style: (typeof EmbedLoomStyles)[number];
|
||||
url: string;
|
||||
caption: string | null;
|
||||
} & EmbedLoomBlockUrlData;
|
||||
|
||||
export class EmbedLoomModel extends defineEmbedModel<EmbedLoomBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-loom': EmbedLoomModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-loom': EmbedLoomModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedLoomBlockProps,
|
||||
EmbedLoomModel,
|
||||
EmbedLoomStyles,
|
||||
} from './loom-model.js';
|
||||
|
||||
const defaultEmbedLoomProps: EmbedLoomBlockProps = {
|
||||
style: EmbedLoomStyles[0],
|
||||
url: '',
|
||||
caption: null,
|
||||
|
||||
image: null,
|
||||
title: null,
|
||||
description: null,
|
||||
videoId: null,
|
||||
};
|
||||
|
||||
export const EmbedLoomBlockSchema = createEmbedBlockSchema({
|
||||
name: 'loom',
|
||||
version: 1,
|
||||
toModel: () => new EmbedLoomModel(),
|
||||
props: (): EmbedLoomBlockProps => defaultEmbedLoomProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './synced-doc-model.js';
|
||||
export * from './synced-doc-schema.js';
|
||||
@@ -0,0 +1,28 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { ReferenceInfo } from '../../../consts/doc.js';
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export const EmbedSyncedDocStyles: EmbedCardStyle[] = ['syncedDoc'];
|
||||
|
||||
export type EmbedSyncedDocBlockProps = {
|
||||
style: EmbedCardStyle;
|
||||
caption?: string | null;
|
||||
scale?: number;
|
||||
} & ReferenceInfo;
|
||||
|
||||
export class EmbedSyncedDocModel extends defineEmbedModel<EmbedSyncedDocBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-synced-doc': EmbedSyncedDocModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-synced-doc': EmbedSyncedDocModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedSyncedDocBlockProps,
|
||||
EmbedSyncedDocModel,
|
||||
EmbedSyncedDocStyles,
|
||||
} from './synced-doc-model.js';
|
||||
|
||||
export const defaultEmbedSyncedDocBlockProps: EmbedSyncedDocBlockProps = {
|
||||
pageId: '',
|
||||
style: EmbedSyncedDocStyles[0],
|
||||
caption: undefined,
|
||||
scale: undefined,
|
||||
// title & description aliases
|
||||
title: undefined,
|
||||
description: undefined,
|
||||
};
|
||||
|
||||
export const EmbedSyncedDocBlockSchema = createEmbedBlockSchema({
|
||||
name: 'synced-doc',
|
||||
version: 1,
|
||||
toModel: () => new EmbedSyncedDocModel(),
|
||||
props: (): EmbedSyncedDocBlockProps => defaultEmbedSyncedDocBlockProps,
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './youtube-model.js';
|
||||
export * from './youtube-schema.js';
|
||||
@@ -0,0 +1,37 @@
|
||||
import { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { EmbedCardStyle } from '../../../utils/index.js';
|
||||
import { defineEmbedModel } from '../../../utils/index.js';
|
||||
|
||||
export type EmbedYoutubeBlockUrlData = {
|
||||
videoId: string | null;
|
||||
image: string | null;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
creator: string | null;
|
||||
creatorUrl: string | null;
|
||||
creatorImage: string | null;
|
||||
};
|
||||
|
||||
export const EmbedYoutubeStyles: EmbedCardStyle[] = ['video'] as const;
|
||||
|
||||
export type EmbedYoutubeBlockProps = {
|
||||
style: (typeof EmbedYoutubeStyles)[number];
|
||||
url: string;
|
||||
caption: string | null;
|
||||
} & EmbedYoutubeBlockUrlData;
|
||||
|
||||
export class EmbedYoutubeModel extends defineEmbedModel<EmbedYoutubeBlockProps>(
|
||||
BlockModel
|
||||
) {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:embed-youtube': EmbedYoutubeModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:embed-youtube': EmbedYoutubeModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { createEmbedBlockSchema } from '../../../utils/index.js';
|
||||
import {
|
||||
type EmbedYoutubeBlockProps,
|
||||
EmbedYoutubeModel,
|
||||
EmbedYoutubeStyles,
|
||||
} from './youtube-model.js';
|
||||
|
||||
const defaultEmbedYoutubeProps: EmbedYoutubeBlockProps = {
|
||||
style: EmbedYoutubeStyles[0],
|
||||
url: '',
|
||||
caption: null,
|
||||
|
||||
image: null,
|
||||
title: null,
|
||||
description: null,
|
||||
creator: null,
|
||||
creatorUrl: null,
|
||||
creatorImage: null,
|
||||
videoId: null,
|
||||
};
|
||||
|
||||
export const EmbedYoutubeBlockSchema = createEmbedBlockSchema({
|
||||
name: 'youtube',
|
||||
version: 1,
|
||||
toModel: () => new EmbedYoutubeModel(),
|
||||
props: (): EmbedYoutubeBlockProps => defaultEmbedYoutubeProps,
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
import type {
|
||||
GfxBlockElementModel,
|
||||
GfxCompatibleProps,
|
||||
GfxElementGeometry,
|
||||
GfxGroupCompatibleInterface,
|
||||
GfxModel,
|
||||
PointTestOptions,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import {
|
||||
canSafeAddToContainer,
|
||||
descendantElementsImpl,
|
||||
generateKeyBetweenV2,
|
||||
GfxCompatible,
|
||||
gfxGroupCompatibleSymbol,
|
||||
hasDescendantElementImpl,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import { BlockModel, defineBlockSchema, type Text } from '@blocksuite/store';
|
||||
|
||||
import type { Color } from '../../consts/index.js';
|
||||
|
||||
export type FrameBlockProps = {
|
||||
title: Text;
|
||||
background: Color;
|
||||
childElementIds?: Record<string, boolean>;
|
||||
presentationIndex?: string;
|
||||
} & GfxCompatibleProps;
|
||||
|
||||
export const FrameBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:frame',
|
||||
props: (internal): FrameBlockProps => ({
|
||||
title: internal.Text(),
|
||||
background: '--affine-palette-transparent',
|
||||
xywh: `[0,0,100,100]`,
|
||||
index: 'a0',
|
||||
childElementIds: Object.create(null),
|
||||
presentationIndex: generateKeyBetweenV2(null, null),
|
||||
lockedBySelf: false,
|
||||
}),
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: ['affine:surface'],
|
||||
children: [],
|
||||
},
|
||||
toModel: () => {
|
||||
return new FrameBlockModel();
|
||||
},
|
||||
});
|
||||
|
||||
export class FrameBlockModel
|
||||
extends GfxCompatible<FrameBlockProps>(BlockModel)
|
||||
implements GfxElementGeometry, GfxGroupCompatibleInterface
|
||||
{
|
||||
[gfxGroupCompatibleSymbol] = true as const;
|
||||
|
||||
get childElements() {
|
||||
if (!this.surface) return [];
|
||||
|
||||
const elements: GfxModel[] = [];
|
||||
|
||||
for (const key of this.childIds) {
|
||||
const element =
|
||||
this.surface.getElementById(key) ||
|
||||
(this.surface.doc.getBlockById(key) as GfxBlockElementModel);
|
||||
|
||||
element && elements.push(element);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
get childIds() {
|
||||
return this.childElementIds ? Object.keys(this.childElementIds) : [];
|
||||
}
|
||||
|
||||
get descendantElements(): GfxModel[] {
|
||||
return descendantElementsImpl(this);
|
||||
}
|
||||
|
||||
addChild(element: GfxModel) {
|
||||
if (!canSafeAddToContainer(this, element)) return;
|
||||
|
||||
this.doc.transact(() => {
|
||||
this.childElementIds = { ...this.childElementIds, [element.id]: true };
|
||||
});
|
||||
}
|
||||
|
||||
addChildren(elements: GfxModel[]): void {
|
||||
elements = [...new Set(elements)].filter(element =>
|
||||
canSafeAddToContainer(this, element)
|
||||
);
|
||||
|
||||
const newChildren: Record<string, boolean> = {};
|
||||
for (const element of elements) {
|
||||
const id = typeof element === 'string' ? element : element.id;
|
||||
newChildren[id] = true;
|
||||
}
|
||||
|
||||
this.doc.transact(() => {
|
||||
this.childElementIds = {
|
||||
...this.childElementIds,
|
||||
...newChildren,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
override containsBound(bound: Bound): boolean {
|
||||
return this.elementBound.contains(bound);
|
||||
}
|
||||
|
||||
hasChild(element: GfxModel): boolean {
|
||||
return this.childElementIds ? element.id in this.childElementIds : false;
|
||||
}
|
||||
|
||||
hasDescendant(element: GfxModel): boolean {
|
||||
return hasDescendantElementImpl(this, element);
|
||||
}
|
||||
|
||||
override includesPoint(x: number, y: number, _: PointTestOptions): boolean {
|
||||
const bound = Bound.deserialize(this.xywh);
|
||||
return bound.isPointInBound([x, y]);
|
||||
}
|
||||
|
||||
override intersectsBound(selectedBound: Bound): boolean {
|
||||
const bound = Bound.deserialize(this.xywh);
|
||||
return (
|
||||
bound.isIntersectWithBound(selectedBound) || selectedBound.contains(bound)
|
||||
);
|
||||
}
|
||||
|
||||
removeChild(element: GfxModel): void {
|
||||
this.doc.transact(() => {
|
||||
this.childElementIds && delete this.childElementIds[element.id];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:frame': FrameBlockModel;
|
||||
}
|
||||
interface BlockModels {
|
||||
'affine:frame': FrameBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './frame-model.js';
|
||||
@@ -0,0 +1,55 @@
|
||||
import type {
|
||||
GfxCommonBlockProps,
|
||||
GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { GfxCompatible } from '@blocksuite/block-std/gfx';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import { ImageBlockTransformer } from './image-transformer.js';
|
||||
|
||||
export type ImageBlockProps = {
|
||||
caption?: string;
|
||||
sourceId?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
rotate: number;
|
||||
size?: number;
|
||||
} & Omit<GfxCommonBlockProps, 'scale'>;
|
||||
|
||||
const defaultImageProps: ImageBlockProps = {
|
||||
caption: '',
|
||||
sourceId: '',
|
||||
width: 0,
|
||||
height: 0,
|
||||
index: 'a0',
|
||||
xywh: '[0,0,0,0]',
|
||||
lockedBySelf: false,
|
||||
rotate: 0,
|
||||
size: -1,
|
||||
};
|
||||
|
||||
export const ImageBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:image',
|
||||
props: () => defaultImageProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
},
|
||||
transformer: () => new ImageBlockTransformer(),
|
||||
toModel: () => new ImageBlockModel(),
|
||||
});
|
||||
|
||||
export class ImageBlockModel
|
||||
extends GfxCompatible<ImageBlockProps>(BlockModel)
|
||||
implements GfxElementGeometry {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:image': ImageBlockModel;
|
||||
}
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:image': ImageBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { FromSnapshotPayload, SnapshotNode } from '@blocksuite/store';
|
||||
import { BaseBlockTransformer } from '@blocksuite/store';
|
||||
|
||||
import type { ImageBlockProps } from './image-model.js';
|
||||
|
||||
export class ImageBlockTransformer extends BaseBlockTransformer<ImageBlockProps> {
|
||||
override async fromSnapshot(
|
||||
payload: FromSnapshotPayload
|
||||
): Promise<SnapshotNode<ImageBlockProps>> {
|
||||
const snapshotRet = await super.fromSnapshot(payload);
|
||||
const sourceId = snapshotRet.props.sourceId;
|
||||
if (!payload.assets.isEmpty() && sourceId && !sourceId.startsWith('/'))
|
||||
await payload.assets.writeToBlob(sourceId);
|
||||
|
||||
return snapshotRet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './image-model.js';
|
||||
export * from './image-transformer.js';
|
||||
@@ -0,0 +1,15 @@
|
||||
export * from './attachment/index.js';
|
||||
export * from './bookmark/index.js';
|
||||
export * from './code/index.js';
|
||||
export * from './database/index.js';
|
||||
export * from './divider/index.js';
|
||||
export * from './edgeless-text/index.js';
|
||||
export * from './embed/index.js';
|
||||
export * from './frame/index.js';
|
||||
export * from './image/index.js';
|
||||
export * from './latex/index.js';
|
||||
export * from './list/index.js';
|
||||
export * from './note/index.js';
|
||||
export * from './paragraph/index.js';
|
||||
export * from './root/index.js';
|
||||
export * from './surface-ref/index.js';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './latex-model.js';
|
||||
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
type GfxCommonBlockProps,
|
||||
GfxCompatible,
|
||||
type GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
export type LatexProps = {
|
||||
latex: string;
|
||||
} & GfxCommonBlockProps;
|
||||
|
||||
export const LatexBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:latex',
|
||||
props: (): LatexProps => ({
|
||||
xywh: '[0,0,16,16]',
|
||||
index: 'a0',
|
||||
lockedBySelf: false,
|
||||
scale: 1,
|
||||
rotate: 0,
|
||||
latex: '',
|
||||
}),
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:edgeless-text',
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
],
|
||||
},
|
||||
toModel: () => {
|
||||
return new LatexBlockModel();
|
||||
},
|
||||
});
|
||||
|
||||
export class LatexBlockModel
|
||||
extends GfxCompatible<LatexProps>(BlockModel)
|
||||
implements GfxElementGeometry {}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:latex': LatexBlockModel;
|
||||
}
|
||||
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:latex': LatexBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './list-model.js';
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { SchemaToModel, Text } from '@blocksuite/store';
|
||||
import { defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
// `toggle` type has been deprecated, do not use it
|
||||
export type ListType = 'bulleted' | 'numbered' | 'todo' | 'toggle';
|
||||
|
||||
export interface ListProps {
|
||||
type: ListType;
|
||||
text: Text;
|
||||
checked: boolean;
|
||||
collapsed: boolean;
|
||||
order: number | null;
|
||||
}
|
||||
|
||||
export const ListBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:list',
|
||||
props: internal =>
|
||||
({
|
||||
type: 'bulleted',
|
||||
text: internal.Text(),
|
||||
checked: false,
|
||||
collapsed: false,
|
||||
|
||||
// number type only for numbered list
|
||||
order: null,
|
||||
}) as ListProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:database',
|
||||
'affine:list',
|
||||
'affine:paragraph',
|
||||
'affine:edgeless-text',
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export type ListBlockModel = SchemaToModel<typeof ListBlockSchema>;
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:list': ListBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './note-model.js';
|
||||
@@ -0,0 +1,126 @@
|
||||
import type {
|
||||
GfxCompatibleProps,
|
||||
GfxElementGeometry,
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import { GfxCompatible } from '@blocksuite/block-std/gfx';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
import {
|
||||
type Color,
|
||||
DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
DEFAULT_NOTE_BORDER_SIZE,
|
||||
DEFAULT_NOTE_BORDER_STYLE,
|
||||
DEFAULT_NOTE_CORNER,
|
||||
DEFAULT_NOTE_HEIGHT,
|
||||
DEFAULT_NOTE_SHADOW,
|
||||
DEFAULT_NOTE_WIDTH,
|
||||
NoteDisplayMode,
|
||||
type StrokeStyle,
|
||||
} from '../../consts/index.js';
|
||||
|
||||
export const NoteBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:note',
|
||||
props: (): NoteProps => ({
|
||||
xywh: `[0,0,${DEFAULT_NOTE_WIDTH},${DEFAULT_NOTE_HEIGHT}]`,
|
||||
background: DEFAULT_NOTE_BACKGROUND_COLOR,
|
||||
index: 'a0',
|
||||
lockedBySelf: false,
|
||||
hidden: false,
|
||||
displayMode: NoteDisplayMode.DocAndEdgeless,
|
||||
edgeless: {
|
||||
style: {
|
||||
borderRadius: DEFAULT_NOTE_CORNER,
|
||||
borderSize: DEFAULT_NOTE_BORDER_SIZE,
|
||||
borderStyle: DEFAULT_NOTE_BORDER_STYLE,
|
||||
shadowType: DEFAULT_NOTE_SHADOW,
|
||||
},
|
||||
},
|
||||
}),
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'hub',
|
||||
parent: ['affine:page'],
|
||||
children: [
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
'affine:code',
|
||||
'affine:divider',
|
||||
'affine:database',
|
||||
'affine:data-view',
|
||||
'affine:image',
|
||||
'affine:bookmark',
|
||||
'affine:attachment',
|
||||
'affine:surface-ref',
|
||||
'affine:embed-*',
|
||||
'affine:latex',
|
||||
],
|
||||
},
|
||||
toModel: () => {
|
||||
return new NoteBlockModel();
|
||||
},
|
||||
});
|
||||
|
||||
export type NoteProps = {
|
||||
background: Color;
|
||||
displayMode: NoteDisplayMode;
|
||||
edgeless: NoteEdgelessProps;
|
||||
/**
|
||||
* @deprecated
|
||||
* use `displayMode` instead
|
||||
* hidden:true -> displayMode:NoteDisplayMode.EdgelessOnly:
|
||||
* means the note is visible only in the edgeless mode
|
||||
* hidden:false -> displayMode:NoteDisplayMode.DocAndEdgeless:
|
||||
* means the note is visible in the doc and edgeless mode
|
||||
*/
|
||||
hidden: boolean;
|
||||
} & GfxCompatibleProps;
|
||||
|
||||
export type NoteEdgelessProps = {
|
||||
style: {
|
||||
borderRadius: number;
|
||||
borderSize: number;
|
||||
borderStyle: StrokeStyle;
|
||||
shadowType: string;
|
||||
};
|
||||
collapse?: boolean;
|
||||
collapsedHeight?: number;
|
||||
scale?: number;
|
||||
};
|
||||
|
||||
export class NoteBlockModel
|
||||
extends GfxCompatible<NoteProps>(BlockModel)
|
||||
implements GfxElementGeometry
|
||||
{
|
||||
private _isSelectable(): boolean {
|
||||
return this.displayMode !== NoteDisplayMode.DocOnly;
|
||||
}
|
||||
|
||||
override containsBound(bounds: Bound): boolean {
|
||||
if (!this._isSelectable()) return false;
|
||||
return super.containsBound(bounds);
|
||||
}
|
||||
|
||||
override includesPoint(x: number, y: number): boolean {
|
||||
if (!this._isSelectable()) return false;
|
||||
|
||||
const bound = Bound.deserialize(this.xywh);
|
||||
return bound.isPointInBound([x, y], 0);
|
||||
}
|
||||
|
||||
override intersectsBound(bound: Bound): boolean {
|
||||
if (!this._isSelectable()) return false;
|
||||
return super.intersectsBound(bound);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:note': NoteBlockModel;
|
||||
}
|
||||
interface EdgelessBlockModelMap {
|
||||
'affine:note': NoteBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './paragraph-model.js';
|
||||
@@ -0,0 +1,52 @@
|
||||
import { BlockModel, defineBlockSchema, type Text } from '@blocksuite/store';
|
||||
|
||||
export type ParagraphType =
|
||||
| 'text'
|
||||
| 'quote'
|
||||
| 'h1'
|
||||
| 'h2'
|
||||
| 'h3'
|
||||
| 'h4'
|
||||
| 'h5'
|
||||
| 'h6';
|
||||
|
||||
export type ParagraphProps = {
|
||||
type: ParagraphType;
|
||||
text: Text;
|
||||
collapsed: boolean;
|
||||
};
|
||||
|
||||
export const ParagraphBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:paragraph',
|
||||
props: (internal): ParagraphProps => ({
|
||||
type: 'text',
|
||||
text: internal.Text(),
|
||||
collapsed: false,
|
||||
}),
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: [
|
||||
'affine:note',
|
||||
'affine:database',
|
||||
'affine:paragraph',
|
||||
'affine:list',
|
||||
'affine:edgeless-text',
|
||||
],
|
||||
},
|
||||
toModel: () => new ParagraphBlockModel(),
|
||||
});
|
||||
|
||||
export class ParagraphBlockModel extends BlockModel<ParagraphProps> {
|
||||
override flavour!: 'affine:paragraph';
|
||||
|
||||
override text!: Text;
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:paragraph': ParagraphBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './root-block-model.js';
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { Text } from '@blocksuite/store';
|
||||
import { BlockModel, defineBlockSchema } from '@blocksuite/store';
|
||||
|
||||
export type RootBlockProps = {
|
||||
title: Text;
|
||||
};
|
||||
|
||||
export class RootBlockModel extends BlockModel<RootBlockProps> {
|
||||
constructor() {
|
||||
super();
|
||||
this.created.once(() => {
|
||||
this.doc.slots.rootAdded.on(id => {
|
||||
const model = this.doc.getBlockById(id);
|
||||
if (model instanceof RootBlockModel) {
|
||||
const newDocMeta = this.doc.collection.meta.getDocMeta(model.doc.id);
|
||||
if (!newDocMeta || newDocMeta.title !== model.title.toString()) {
|
||||
this.doc.collection.setDocMeta(model.doc.id, {
|
||||
title: model.title.toString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const RootBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:page',
|
||||
props: (internal): RootBlockProps => ({
|
||||
title: internal.Text(),
|
||||
}),
|
||||
metadata: {
|
||||
version: 2,
|
||||
role: 'root',
|
||||
},
|
||||
toModel: () => new RootBlockModel(),
|
||||
});
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:page': RootBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './surface-ref-model.js';
|
||||
@@ -0,0 +1,31 @@
|
||||
import { defineBlockSchema, type SchemaToModel } from '@blocksuite/store';
|
||||
|
||||
export type SurfaceRefProps = {
|
||||
reference: string;
|
||||
caption: string;
|
||||
refFlavour: string;
|
||||
};
|
||||
|
||||
export const SurfaceRefBlockSchema = defineBlockSchema({
|
||||
flavour: 'affine:surface-ref',
|
||||
props: () =>
|
||||
({
|
||||
reference: '',
|
||||
caption: '',
|
||||
}) as SurfaceRefProps,
|
||||
metadata: {
|
||||
version: 1,
|
||||
role: 'content',
|
||||
parent: ['affine:note', 'affine:paragraph', 'affine:list'],
|
||||
},
|
||||
});
|
||||
|
||||
export type SurfaceRefBlockModel = SchemaToModel<typeof SurfaceRefBlockSchema>;
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface BlockModels {
|
||||
'affine:surface-ref': SurfaceRefBlockModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user