refactor(editor): add schema for value of database block properties (#10749)

This commit is contained in:
zzj3720
2025-03-11 02:12:40 +00:00
parent db707dff7f
commit 77e4b9aa8e
17 changed files with 198 additions and 172 deletions

View File

@@ -8,6 +8,5 @@ export * from './detail-panel/block-renderer';
export * from './detail-panel/note-renderer';
export * from './properties';
export * from './properties/rich-text/cell-renderer';
export * from './properties/utils';
export * from './selection.js';
export * from './utils/block-utils';

View File

@@ -1,8 +1,9 @@
import { propertyType, t } from '@blocksuite/data-view';
import zod from 'zod';
export const linkColumnType = propertyType('link');
export const linkPropertyModelConfig = linkColumnType.modelConfig<string>({
export const linkPropertyModelConfig = linkColumnType.modelConfig({
name: 'Link',
valueSchema: zod.string().optional(),
type: () => t.string.instance(),
defaultData: () => ({}),
cellToString: ({ value }) => value?.toString() ?? '',

View File

@@ -2,56 +2,68 @@ import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { propertyType, t } from '@blocksuite/data-view';
import type { DeltaInsert } from '@blocksuite/inline';
import { Text } from '@blocksuite/store';
import * as Y from 'yjs';
import zod from 'zod';
import { HostContextKey } from '../../context/host-context.js';
import { isLinkedDoc } from '../../utils/title-doc.js';
import { type RichTextCellType, toYText } from '../utils.js';
export const richTextColumnType = propertyType('rich-text');
export type RichTextCellType = Text | Text['yText'];
export const toYText = (text?: RichTextCellType): undefined | Text['yText'] => {
if (text instanceof Text) {
return text.yText;
}
return text;
};
export const richTextPropertyModelConfig =
richTextColumnType.modelConfig<RichTextCellType>({
name: 'Text',
type: () => t.richText.instance(),
defaultData: () => ({}),
cellToString: ({ value }) => value?.toString() ?? '',
cellFromString: ({ value }) => {
return {
value: new Text(value),
};
},
cellToJson: ({ value, dataSource }) => {
if (!value) return null;
const host = dataSource.contextGet(HostContextKey);
if (host) {
const collection = host.std.workspace;
const yText = toYText(value);
const deltas = yText.toDelta();
const text = deltas
.map((delta: DeltaInsert<AffineTextAttributes>) => {
if (isLinkedDoc(delta)) {
const linkedDocId = delta.attributes?.reference?.pageId as string;
return collection.getDoc(linkedDocId)?.meta?.title;
}
return delta.insert;
})
.join('');
return text;
}
return value?.toString() ?? null;
},
cellFromJson: ({ value }) =>
typeof value !== 'string' ? undefined : new Text(value),
onUpdate: ({ value, callback }) => {
export const richTextPropertyModelConfig = richTextColumnType.modelConfig({
name: 'Text',
valueSchema: zod
.custom<RichTextCellType>(
data => data instanceof Text || data instanceof Y.Text
)
.optional(),
type: () => t.richText.instance(),
defaultData: () => ({}),
cellToString: ({ value }) => value?.toString() ?? '',
cellFromString: ({ value }) => {
return {
value: new Text(value),
};
},
cellToJson: ({ value, dataSource }) => {
if (!value) return null;
const host = dataSource.contextGet(HostContextKey);
if (host) {
const collection = host.std.workspace;
const yText = toYText(value);
yText.observe(callback);
callback();
return {
dispose: () => {
yText.unobserve(callback);
},
};
},
isEmpty: ({ value }) => value == null || value.length === 0,
values: ({ value }) => (value?.toString() ? [value.toString()] : []),
});
const deltas = yText?.toDelta();
const text = deltas
.map((delta: DeltaInsert<AffineTextAttributes>) => {
if (isLinkedDoc(delta)) {
const linkedDocId = delta.attributes?.reference?.pageId as string;
return collection.getDoc(linkedDocId)?.meta?.title;
}
return delta.insert;
})
.join('');
return text;
}
return value?.toString() ?? null;
},
cellFromJson: ({ value }) =>
typeof value !== 'string' ? undefined : new Text(value),
onUpdate: ({ value, callback }) => {
const yText = toYText(value);
yText?.observe(callback);
callback();
return {
dispose: () => {
yText?.unobserve(callback);
},
};
},
isEmpty: ({ value }) => value == null || value.length === 0,
values: ({ value }) => (value?.toString() ? [value.toString()] : []),
});

View File

@@ -1,13 +1,15 @@
import { propertyType, t } from '@blocksuite/data-view';
import { Text } from '@blocksuite/store';
import zod from 'zod';
import { HostContextKey } from '../../context/host-context.js';
import { isLinkedDoc } from '../../utils/title-doc.js';
export const titleColumnType = propertyType('title');
export const titlePropertyModelConfig = titleColumnType.modelConfig<Text>({
export const titlePropertyModelConfig = titleColumnType.modelConfig({
name: 'Title',
valueSchema: zod.custom<Text>(data => data instanceof Text).optional(),
fixed: {
defaultData: {},
defaultShow: true,
@@ -42,22 +44,22 @@ export const titlePropertyModelConfig = titleColumnType.modelConfig<Text>({
cellFromJson: ({ value }) =>
typeof value !== 'string' ? undefined : new Text(value),
onUpdate: ({ value, callback }) => {
value.yText.observe(callback);
value?.yText.observe(callback);
callback();
return {
dispose: () => {
value.yText.unobserve(callback);
value?.yText.unobserve(callback);
},
};
},
valueUpdate: ({ value, newValue }) => {
const v = newValue as unknown;
if (typeof v === 'string') {
value.replace(0, value.length, v);
value?.replace(0, value.length, v);
return value;
}
if (v == null) {
value.replace(0, value.length, '');
value?.replace(0, value.length, '');
return value;
}
return newValue;

View File

@@ -1,9 +0,0 @@
import { Text } from '@blocksuite/store';
export type RichTextCellType = Text | Text['yText'];
export const toYText = (text: RichTextCellType): Text['yText'] => {
if (text instanceof Text) {
return text.yText;
}
return text;
};