mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(editor): unify block props api (#10888)
Closes: [BS-2707](https://linear.app/affine-design/issue/BS-2707/统一使用props获取和更新block-prop)
This commit is contained in:
@@ -287,7 +287,7 @@ const GenerateWithAIGroup: AIItemGroupConfig = {
|
||||
return selectedModels.every(
|
||||
model =>
|
||||
matchModels(model, [ParagraphBlockModel, ListBlockModel]) &&
|
||||
!model.type.startsWith('h')
|
||||
!model.props.type.startsWith('h')
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -9,12 +9,13 @@ import {
|
||||
EdgelessTextBlockModel,
|
||||
EmbedSyncedDocModel,
|
||||
ImageBlockModel,
|
||||
type ImageBlockProps,
|
||||
NoteBlockModel,
|
||||
ShapeElementModel,
|
||||
TextElementModel,
|
||||
} from '@blocksuite/affine/model';
|
||||
import { matchModels } from '@blocksuite/affine/shared/utils';
|
||||
import { Slice } from '@blocksuite/affine/store';
|
||||
import { type BlockModel, Slice } from '@blocksuite/affine/store';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
import { getContentFromSlice } from '../../utils';
|
||||
@@ -87,8 +88,9 @@ export async function getContentFromSelected(
|
||||
|
||||
function isImageWithCaption(
|
||||
el: ImageBlockModel
|
||||
): el is RemoveUndefinedKey<ImageBlockModel, 'caption'> {
|
||||
return el.caption !== undefined && el.caption.length !== 0;
|
||||
): el is ImageBlockModel &
|
||||
BlockModel<RemoveUndefinedKey<ImageBlockProps, 'caption'>> {
|
||||
return el.props.caption !== undefined && el.props.caption.length !== 0;
|
||||
}
|
||||
|
||||
const { notes, texts, shapes, images, edgelessTexts, embedSyncedDocs } =
|
||||
@@ -96,7 +98,7 @@ export async function getContentFromSelected(
|
||||
notes: NoteBlockModel[];
|
||||
texts: TextElementModel[];
|
||||
shapes: RemoveUndefinedKey<ShapeElementModel, 'text'>[];
|
||||
images: RemoveUndefinedKey<ImageBlockModel, 'caption'>[];
|
||||
images: RemoveUndefinedKey<ImageBlockProps, 'caption'>[];
|
||||
edgelessTexts: EdgelessTextBlockModel[];
|
||||
embedSyncedDocs: EmbedSyncedDocModel[];
|
||||
}>(
|
||||
@@ -108,7 +110,7 @@ export async function getContentFromSelected(
|
||||
} else if (cur instanceof ShapeElementModel && isShapeWithText(cur)) {
|
||||
pre.shapes.push(cur);
|
||||
} else if (cur instanceof ImageBlockModel && isImageWithCaption(cur)) {
|
||||
pre.images.push(cur);
|
||||
pre.images.push(cur.props);
|
||||
} else if (cur instanceof EdgelessTextBlockModel) {
|
||||
pre.edgelessTexts.push(cur);
|
||||
} else if (cur instanceof EmbedSyncedDocModel) {
|
||||
|
||||
@@ -18,7 +18,7 @@ export class AIChatBlockComponent extends BlockComponent<AIChatBlockModel> {
|
||||
|
||||
// Deserialize messages from JSON string and verify the type using zod
|
||||
private readonly _deserializeChatMessages = computed(() => {
|
||||
const messages = this.model.messages$.value;
|
||||
const messages = this.model.props.messages$.value;
|
||||
try {
|
||||
const result = ChatMessagesSchema.safeParse(JSON.parse(messages));
|
||||
if (result.success) {
|
||||
|
||||
@@ -9,8 +9,8 @@ export class EdgelessAIChatBlockComponent extends toGfxBlockComponent(
|
||||
AIChatBlockComponent
|
||||
) {
|
||||
override renderGfxBlock() {
|
||||
const bound = Bound.deserialize(this.model.xywh$.value);
|
||||
const scale = this.model.scale$.value;
|
||||
const bound = Bound.deserialize(this.model.props.xywh$.value);
|
||||
const scale = this.model.props.scale$.value;
|
||||
const width = bound.w / scale;
|
||||
const height = bound.h / scale;
|
||||
const style = {
|
||||
|
||||
@@ -12,7 +12,7 @@ class AIParagraphBlockWatcher extends LifeCycleWatcher {
|
||||
super.mounted();
|
||||
const service = this.std.get(ParagraphBlockService);
|
||||
service.placeholderGenerator = model => {
|
||||
if (model.type === 'text') {
|
||||
if (model.props.type === 'text') {
|
||||
return "Type '/' for commands, 'space' for AI";
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class AIParagraphBlockWatcher extends LifeCycleWatcher {
|
||||
h6: 'Heading 6',
|
||||
quote: '',
|
||||
};
|
||||
return placeholders[model.type];
|
||||
return placeholders[model.props.type];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +44,11 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
}
|
||||
|
||||
private get parentSessionId() {
|
||||
return this.parentModel.sessionId;
|
||||
return this.parentModel.props.sessionId;
|
||||
}
|
||||
|
||||
private get historyMessagesString() {
|
||||
return this.parentModel.messages;
|
||||
return this.parentModel.props.messages;
|
||||
}
|
||||
|
||||
private get parentChatBlockId() {
|
||||
@@ -56,11 +56,11 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
}
|
||||
|
||||
private get parentRootDocId() {
|
||||
return this.parentModel.rootDocId;
|
||||
return this.parentModel.props.rootDocId;
|
||||
}
|
||||
|
||||
private get parentRootWorkspaceId() {
|
||||
return this.parentModel.rootWorkspaceId;
|
||||
return this.parentModel.props.rootWorkspaceId;
|
||||
}
|
||||
|
||||
private _textRendererOptions: TextRendererOptions = {};
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function extractPageAll(
|
||||
const blobs = await Promise.all(
|
||||
blockModels.map(async s => {
|
||||
if (s.flavour !== 'affine:image') return null;
|
||||
const sourceId = (s as ImageBlockModel)?.sourceId;
|
||||
const sourceId = (s as ImageBlockModel)?.props.sourceId;
|
||||
if (!sourceId) return null;
|
||||
const blob = await (sourceId ? host.doc.blobSync.get(sourceId) : null);
|
||||
if (!blob) return null;
|
||||
@@ -190,7 +190,7 @@ function getNoteBlockModels(doc: Store) {
|
||||
.getBlocksByFlavour('affine:note')
|
||||
.filter(
|
||||
note =>
|
||||
(note.model as NoteBlockModel).displayMode !==
|
||||
(note.model as NoteBlockModel).props.displayMode !==
|
||||
NoteDisplayMode.EdgelessOnly
|
||||
)
|
||||
.map(note => note.model as NoteBlockModel);
|
||||
|
||||
@@ -263,7 +263,7 @@ export const getSelectedImagesAsBlobs = async (host: EditorHost) => {
|
||||
|
||||
const blobs = await Promise.all(
|
||||
data.selectedBlocks?.map(async b => {
|
||||
const sourceId = (b.model as ImageBlockModel).sourceId;
|
||||
const sourceId = (b.model as ImageBlockModel).props.sourceId;
|
||||
if (!sourceId) return null;
|
||||
const blob = await host.doc.blobSync.get(sourceId);
|
||||
if (!blob) return null;
|
||||
@@ -295,9 +295,9 @@ export const imageCustomInput = async (host: EditorHost) => {
|
||||
|
||||
const imageBlock = selectedElements[0];
|
||||
if (!(imageBlock instanceof ImageBlockModel)) return;
|
||||
if (!imageBlock.sourceId) return;
|
||||
if (!imageBlock.props.sourceId) return;
|
||||
|
||||
const blob = await host.doc.blobSync.get(imageBlock.sourceId);
|
||||
const blob = await host.doc.blobSync.get(imageBlock.props.sourceId);
|
||||
if (!blob) return;
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,9 +16,10 @@ export function patchForAttachmentEmbedViews(
|
||||
di.override(AttachmentEmbedConfigIdentifier('pdf'), () => ({
|
||||
name: 'pdf',
|
||||
check: (model, maxFileSize) =>
|
||||
model.type === 'application/pdf' && model.size <= maxFileSize,
|
||||
model.props.type === 'application/pdf' &&
|
||||
model.props.size <= maxFileSize,
|
||||
action: model => {
|
||||
const bound = Bound.deserialize(model.xywh);
|
||||
const bound = Bound.deserialize(model.props.xywh);
|
||||
bound.w = 537 + 24 + 2;
|
||||
bound.h = 759 + 46 + 24 + 2;
|
||||
model.doc.updateBlock(model, {
|
||||
|
||||
@@ -410,7 +410,7 @@ function createExternalLinkableToolbarConfig(
|
||||
)?.model;
|
||||
if (!model) return;
|
||||
|
||||
const { url } = model;
|
||||
const { url } = model.props;
|
||||
|
||||
navigator.clipboard.writeText(url).catch(console.error);
|
||||
toast(ctx.host, 'Copied link to clipboard');
|
||||
@@ -523,7 +523,7 @@ function createOpenDocActionGroup(
|
||||
return {
|
||||
...action,
|
||||
disabled: shouldOpenInActiveView
|
||||
? component.model.pageId === ctx.store.id
|
||||
? component.model.props.pageId === ctx.store.id
|
||||
: false,
|
||||
when:
|
||||
allowed &&
|
||||
@@ -590,7 +590,7 @@ const embedLinkedDocToolbarConfig = {
|
||||
);
|
||||
if (!model) return;
|
||||
|
||||
const { pageId, params } = model;
|
||||
const { pageId, params } = model.props;
|
||||
|
||||
const url = ctx.std
|
||||
.getOptional(GenerateDocUrlProvider)
|
||||
@@ -625,7 +625,7 @@ const embedLinkedDocToolbarConfig = {
|
||||
ctx.hide();
|
||||
|
||||
const model = component.model;
|
||||
const doc = ctx.workspace.getDoc(model.pageId);
|
||||
const doc = ctx.workspace.getDoc(model.props.pageId);
|
||||
const abortController = new AbortController();
|
||||
abortController.signal.onabort = () => ctx.show();
|
||||
|
||||
@@ -683,7 +683,7 @@ const embedSyncedDocToolbarConfig = {
|
||||
);
|
||||
if (!model) return;
|
||||
|
||||
const { pageId, params } = model;
|
||||
const { pageId, params } = model.props;
|
||||
|
||||
const url = ctx.std
|
||||
.getOptional(GenerateDocUrlProvider)
|
||||
@@ -718,7 +718,7 @@ const embedSyncedDocToolbarConfig = {
|
||||
ctx.hide();
|
||||
|
||||
const model = component.model;
|
||||
const doc = ctx.workspace.getDoc(model.pageId);
|
||||
const doc = ctx.workspace.getDoc(model.props.pageId);
|
||||
const abortController = new AbortController();
|
||||
abortController.signal.onabort = () => ctx.show();
|
||||
|
||||
@@ -920,7 +920,7 @@ const embedIframeToolbarConfig = {
|
||||
)?.model;
|
||||
if (!model) return;
|
||||
|
||||
const { url } = model;
|
||||
const { url } = model.props;
|
||||
|
||||
navigator.clipboard.writeText(url).catch(console.error);
|
||||
toast(ctx.host, 'Copied link to clipboard');
|
||||
|
||||
@@ -86,7 +86,7 @@ class MobileSpecsPatches extends LifeCycleWatcher {
|
||||
h6: 'Heading 6',
|
||||
quote: '',
|
||||
};
|
||||
return placeholders[model.type];
|
||||
return placeholders[model.props.type];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import * as styles from './edgeless-note-header.css';
|
||||
|
||||
const EdgelessNoteToggleButton = ({ note }: { note: NoteBlockModel }) => {
|
||||
const t = useI18n();
|
||||
const [collapsed, setCollapsed] = useState(note.edgeless.collapse);
|
||||
const [collapsed, setCollapsed] = useState(note.props.edgeless.collapse);
|
||||
const editor = useService(EditorService).editor;
|
||||
const editorContainer = useLiveData(editor.editorContainer$);
|
||||
const gfx = editorContainer?.std.get(GfxControllerIdentifier);
|
||||
@@ -39,7 +39,7 @@ const EdgelessNoteToggleButton = ({ note }: { note: NoteBlockModel }) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return note.edgeless$.subscribe(({ collapse, collapsedHeight }) => {
|
||||
return note.props.edgeless$.subscribe(({ collapse, collapsedHeight }) => {
|
||||
if (
|
||||
collapse &&
|
||||
collapsedHeight &&
|
||||
@@ -50,7 +50,7 @@ const EdgelessNoteToggleButton = ({ note }: { note: NoteBlockModel }) => {
|
||||
setCollapsed(false);
|
||||
}
|
||||
});
|
||||
}, [note.edgeless$]);
|
||||
}, [note.props.edgeless$]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!gfx) return;
|
||||
@@ -60,7 +60,7 @@ const EdgelessNoteToggleButton = ({ note }: { note: NoteBlockModel }) => {
|
||||
const dispose = selection.slots.updated.subscribe(() => {
|
||||
if (selection.has(note.id) && selection.editing) {
|
||||
note.doc.transact(() => {
|
||||
note.edgeless.collapse = false;
|
||||
note.props.edgeless.collapse = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -74,13 +74,13 @@ const EdgelessNoteToggleButton = ({ note }: { note: NoteBlockModel }) => {
|
||||
});
|
||||
note.doc.transact(() => {
|
||||
if (collapsed) {
|
||||
note.edgeless.collapse = false;
|
||||
note.props.edgeless.collapse = false;
|
||||
} else {
|
||||
const bound = Bound.deserialize(note.xywh);
|
||||
bound.h = styles.headerHeight * (note.edgeless.scale ?? 1);
|
||||
note.xywh = bound.serialize();
|
||||
note.edgeless.collapse = true;
|
||||
note.edgeless.collapsedHeight = styles.headerHeight;
|
||||
const bound = Bound.deserialize(note.props.xywh);
|
||||
bound.h = styles.headerHeight * (note.props.edgeless.scale ?? 1);
|
||||
note.props.xywh = bound.serialize();
|
||||
note.props.edgeless.collapse = true;
|
||||
note.props.edgeless.collapsedHeight = styles.headerHeight;
|
||||
gfx?.selection.clear();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ interface ErrorProps {
|
||||
|
||||
export const Error = ({ model, ext }: ErrorProps) => {
|
||||
const t = useI18n();
|
||||
const Icon = FILE_ICONS[model.type] ?? FileIcon;
|
||||
const Icon = FILE_ICONS[model.props.type] ?? FileIcon;
|
||||
const title = t['com.affine.attachment.preview.error.title']();
|
||||
const subtitle = `.${ext} ${t['com.affine.attachment.preview.error.subtitle']()}`;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export const AttachmentViewerView = ({ model }: AttachmentViewerProps) => {
|
||||
};
|
||||
|
||||
const AttachmentViewerInner = (props: PDFViewerProps) => {
|
||||
return props.model.type.endsWith('pdf') ? (
|
||||
return props.model.props.type.endsWith('pdf') ? (
|
||||
<AttachmentPreviewErrorBoundary>
|
||||
<PDFViewer {...props} />
|
||||
</AttachmentPreviewErrorBoundary>
|
||||
|
||||
@@ -67,7 +67,7 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) {
|
||||
useMemo(() => (pageEntity ? pageEntity.page.bitmap$ : null), [pageEntity])
|
||||
);
|
||||
|
||||
const [name, setName] = useState(model.name);
|
||||
const [name, setName] = useState(model.props.name);
|
||||
const [cursor, setCursor] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [visibility, setVisibility] = useState(false);
|
||||
@@ -108,7 +108,7 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) {
|
||||
};
|
||||
}, [cursor, meta, peek]);
|
||||
|
||||
useEffect(() => model.name$.subscribe(val => setName(val)), [model]);
|
||||
useEffect(() => model.props.name$.subscribe(val => setName(val)), [model]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { downloadBlob } from '../../utils/resource';
|
||||
import type { PDFViewerProps } from './types';
|
||||
|
||||
export async function getAttachmentBlob(model: AttachmentBlockModel) {
|
||||
const sourceId = model.sourceId;
|
||||
const sourceId = model.props.sourceId;
|
||||
if (!sourceId) {
|
||||
return null;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export async function getAttachmentBlob(model: AttachmentBlockModel) {
|
||||
let blob = await doc.blobSync.get(sourceId);
|
||||
|
||||
if (blob) {
|
||||
blob = new Blob([blob], { type: model.type });
|
||||
blob = new Blob([blob], { type: model.props.type });
|
||||
}
|
||||
|
||||
return blob;
|
||||
@@ -25,16 +25,16 @@ export async function download(model: AttachmentBlockModel) {
|
||||
const blob = await getAttachmentBlob(model);
|
||||
if (!blob) return;
|
||||
|
||||
await downloadBlob(blob, model.name);
|
||||
await downloadBlob(blob, model.props.name);
|
||||
}
|
||||
|
||||
export function buildAttachmentProps(
|
||||
model: AttachmentBlockModel
|
||||
): PDFViewerProps {
|
||||
const pieces = model.name.split('.');
|
||||
const pieces = model.props.name.split('.');
|
||||
const ext = pieces.pop() || '';
|
||||
const name = pieces.join('.');
|
||||
const size = filesize(model.size);
|
||||
const size = filesize(model.props.size);
|
||||
return { model, name, ext, size };
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,10 @@ export const AttachmentPage = ({
|
||||
if (doc && model) {
|
||||
return (
|
||||
<FrameworkScope scope={doc.scope}>
|
||||
<ViewTitle title={model.name} />
|
||||
<ViewIcon icon={model.type.endsWith('pdf') ? 'pdf' : 'attachment'} />
|
||||
<ViewTitle title={model.props.name} />
|
||||
<ViewIcon
|
||||
icon={model.props.type.endsWith('pdf') ? 'pdf' : 'attachment'}
|
||||
/>
|
||||
<AttachmentViewerView model={model} />
|
||||
</FrameworkScope>
|
||||
);
|
||||
|
||||
@@ -98,7 +98,7 @@ export class DocDatabaseBacklinksService extends Service {
|
||||
doc: docRef.doc,
|
||||
docId: backlink.docId,
|
||||
databaseId: dbModel.id,
|
||||
databaseName: dbModel.title.yText.toString(),
|
||||
databaseName: dbModel.props.title.yText.toString(),
|
||||
dataSource: dataSource,
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -90,8 +90,8 @@ export class Doc extends Entity {
|
||||
?.model as RootBlockModel | undefined;
|
||||
if (pageBlock) {
|
||||
this.blockSuiteDoc.transact(() => {
|
||||
pageBlock.title.delete(0, pageBlock.title.length);
|
||||
pageBlock.title.insert(newTitle, 0);
|
||||
pageBlock.props.title.delete(0, pageBlock.props.title.length);
|
||||
pageBlock.props.title.insert(newTitle, 0);
|
||||
});
|
||||
this.record.setMeta({ title: newTitle });
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ function generateMarkdownPreviewBuilder(
|
||||
);
|
||||
|
||||
return {
|
||||
...props,
|
||||
props,
|
||||
id: yblock.get('sys:id') as string,
|
||||
flavour,
|
||||
children: [],
|
||||
@@ -147,7 +147,7 @@ function generateMarkdownPreviewBuilder(
|
||||
keys: Array.from(yblock.keys())
|
||||
.filter(key => key.startsWith('prop:'))
|
||||
.map(key => key.substring(5)),
|
||||
} as DraftModel;
|
||||
} as unknown as DraftModel;
|
||||
}
|
||||
|
||||
const titleMiddleware: TransformerMiddleware = ({ adapterConfigs }) => {
|
||||
@@ -300,12 +300,12 @@ function generateMarkdownPreviewBuilder(
|
||||
|
||||
const info = ['an image block'];
|
||||
|
||||
if (model.sourceId) {
|
||||
info.push(`file id ${model.sourceId}`);
|
||||
if (model.props.sourceId) {
|
||||
info.push(`file id ${model.props.sourceId}`);
|
||||
}
|
||||
|
||||
if (model.caption) {
|
||||
info.push(`with caption ${model.caption}`);
|
||||
if (model.props.caption) {
|
||||
info.push(`with caption ${model.props.caption}`);
|
||||
}
|
||||
|
||||
return info.join(', ') + '\n';
|
||||
@@ -353,8 +353,8 @@ function generateMarkdownPreviewBuilder(
|
||||
if (!isBookmarkModel(draftModel)) {
|
||||
return null;
|
||||
}
|
||||
const title = draftModel.title;
|
||||
const url = draftModel.url;
|
||||
const title = draftModel.props.title;
|
||||
const url = draftModel.props.url;
|
||||
return `[${title}](${url})\n`;
|
||||
};
|
||||
|
||||
@@ -370,7 +370,7 @@ function generateMarkdownPreviewBuilder(
|
||||
return null;
|
||||
}
|
||||
|
||||
return `[${draftModel.name}](${draftModel.sourceId})\n`;
|
||||
return `[${draftModel.props.name}](${draftModel.props.sourceId})\n`;
|
||||
};
|
||||
|
||||
const generateTableMarkdownPreview = (block: BlockDocumentInfo) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AttachmentBlockModel } from '@blocksuite/affine/model';
|
||||
|
||||
export async function downloadBlobToBuffer(model: AttachmentBlockModel) {
|
||||
const sourceId = model.sourceId;
|
||||
const sourceId = model.props.sourceId;
|
||||
if (!sourceId) {
|
||||
throw new Error('Attachment not found');
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ function resolvePeekInfoFromPeekTarget(
|
||||
isEmbedLinkedDocModel(blockModel) ||
|
||||
isEmbedSyncedDocModel(blockModel)
|
||||
) {
|
||||
const { pageId: docId, params } = blockModel;
|
||||
const { pageId: docId, params } = blockModel.props;
|
||||
const info: DocPeekViewInfo = {
|
||||
type: 'doc',
|
||||
docRef: { docId, ...params },
|
||||
@@ -174,7 +174,7 @@ function resolvePeekInfoFromPeekTarget(
|
||||
docRef: {
|
||||
docId: blockModel.doc.id,
|
||||
blockIds: [blockModel.id],
|
||||
filetype: blockModel.type,
|
||||
filetype: blockModel.props.type,
|
||||
},
|
||||
};
|
||||
} else if (isImageBlockModel(blockModel)) {
|
||||
|
||||
@@ -75,7 +75,9 @@ function useImageBlob(
|
||||
return null;
|
||||
}
|
||||
const blockModel = block.model as ImageBlockModel;
|
||||
return await docCollection.blobSync.get(blockModel.sourceId as string);
|
||||
return await docCollection.blobSync.get(
|
||||
blockModel.props.sourceId as string
|
||||
);
|
||||
},
|
||||
suspense: false,
|
||||
}
|
||||
@@ -154,8 +156,8 @@ const ImagePreviewModalImpl = ({
|
||||
return block.model as ImageBlockModel;
|
||||
}, [blockId, blocksuiteDoc]);
|
||||
const caption = useMemo(() => {
|
||||
return blockModel?.caption ?? '';
|
||||
}, [blockModel?.caption]);
|
||||
return blockModel?.props.caption ?? '';
|
||||
}, [blockModel?.props.caption]);
|
||||
const [blocks, setBlocks] = useState<ImageBlockModel[]>([]);
|
||||
const [cursor, setCursor] = useState(0);
|
||||
const zoomRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
Reference in New Issue
Block a user