From 846410cdb616b11af7659d4b013908fa5e85f9e8 Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Mon, 21 Apr 2025 13:18:34 +0000 Subject: [PATCH] feat(editor): note extension (#11856) Closes: BS-3200 Closes: BS-3201 --- blocksuite/affine/all/package.json | 8 ++- .../all/src/blocks/{note.ts => note/index.ts} | 0 .../affine/all/src/blocks/note/store.ts | 1 + blocksuite/affine/all/src/blocks/note/view.ts | 1 + .../{paragraph.ts => paragraph/index.ts} | 0 .../affine/all/src/blocks/paragraph/store.ts | 1 + .../affine/all/src/blocks/paragraph/view.ts | 1 + blocksuite/affine/blocks/image/src/store.ts | 4 +- blocksuite/affine/blocks/note/package.json | 5 +- blocksuite/affine/blocks/note/src/store.ts | 36 ++++++++++ blocksuite/affine/blocks/note/src/view.ts | 47 +++++++++++++ blocksuite/affine/blocks/note/tsconfig.json | 1 + .../affine/blocks/paragraph/package.json | 5 +- .../affine/blocks/paragraph/src/store.ts | 17 +++++ .../affine/blocks/paragraph/src/view.ts | 67 +++++++++++++++++++ .../affine/blocks/paragraph/tsconfig.json | 1 + .../core/src/blocksuite/manager/store.ts | 4 ++ .../core/src/blocksuite/manager/view.ts | 4 ++ tools/utils/src/workspace.gen.ts | 2 + yarn.lock | 2 + 20 files changed, 202 insertions(+), 5 deletions(-) rename blocksuite/affine/all/src/blocks/{note.ts => note/index.ts} (100%) create mode 100644 blocksuite/affine/all/src/blocks/note/store.ts create mode 100644 blocksuite/affine/all/src/blocks/note/view.ts rename blocksuite/affine/all/src/blocks/{paragraph.ts => paragraph/index.ts} (100%) create mode 100644 blocksuite/affine/all/src/blocks/paragraph/store.ts create mode 100644 blocksuite/affine/all/src/blocks/paragraph/view.ts create mode 100644 blocksuite/affine/blocks/note/src/store.ts create mode 100644 blocksuite/affine/blocks/note/src/view.ts create mode 100644 blocksuite/affine/blocks/paragraph/src/store.ts create mode 100644 blocksuite/affine/blocks/paragraph/src/view.ts diff --git a/blocksuite/affine/all/package.json b/blocksuite/affine/all/package.json index b9e36418f..42956c040 100644 --- a/blocksuite/affine/all/package.json +++ b/blocksuite/affine/all/package.json @@ -127,8 +127,12 @@ "./blocks/list": "./src/blocks/list/index.ts", "./blocks/list/store": "./src/blocks/list/store.ts", "./blocks/list/view": "./src/blocks/list/view.ts", - "./blocks/note": "./src/blocks/note.ts", - "./blocks/paragraph": "./src/blocks/paragraph.ts", + "./blocks/note": "./src/blocks/note/index.ts", + "./blocks/note/store": "./src/blocks/note/store.ts", + "./blocks/note/view": "./src/blocks/note/view.ts", + "./blocks/paragraph": "./src/blocks/paragraph/index.ts", + "./blocks/paragraph/store": "./src/blocks/paragraph/store.ts", + "./blocks/paragraph/view": "./src/blocks/paragraph/view.ts", "./blocks/root": "./src/blocks/root.ts", "./blocks/surface": "./src/blocks/surface.ts", "./blocks/surface-ref": "./src/blocks/surface-ref.ts", diff --git a/blocksuite/affine/all/src/blocks/note.ts b/blocksuite/affine/all/src/blocks/note/index.ts similarity index 100% rename from blocksuite/affine/all/src/blocks/note.ts rename to blocksuite/affine/all/src/blocks/note/index.ts diff --git a/blocksuite/affine/all/src/blocks/note/store.ts b/blocksuite/affine/all/src/blocks/note/store.ts new file mode 100644 index 000000000..1da7d674d --- /dev/null +++ b/blocksuite/affine/all/src/blocks/note/store.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-block-note/store'; diff --git a/blocksuite/affine/all/src/blocks/note/view.ts b/blocksuite/affine/all/src/blocks/note/view.ts new file mode 100644 index 000000000..3d85f988d --- /dev/null +++ b/blocksuite/affine/all/src/blocks/note/view.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-block-note/view'; diff --git a/blocksuite/affine/all/src/blocks/paragraph.ts b/blocksuite/affine/all/src/blocks/paragraph/index.ts similarity index 100% rename from blocksuite/affine/all/src/blocks/paragraph.ts rename to blocksuite/affine/all/src/blocks/paragraph/index.ts diff --git a/blocksuite/affine/all/src/blocks/paragraph/store.ts b/blocksuite/affine/all/src/blocks/paragraph/store.ts new file mode 100644 index 000000000..dfbe3d035 --- /dev/null +++ b/blocksuite/affine/all/src/blocks/paragraph/store.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-block-paragraph/store'; diff --git a/blocksuite/affine/all/src/blocks/paragraph/view.ts b/blocksuite/affine/all/src/blocks/paragraph/view.ts new file mode 100644 index 000000000..b7b202844 --- /dev/null +++ b/blocksuite/affine/all/src/blocks/paragraph/view.ts @@ -0,0 +1 @@ +export * from '@blocksuite/affine-block-paragraph/view'; diff --git a/blocksuite/affine/blocks/image/src/store.ts b/blocksuite/affine/blocks/image/src/store.ts index d1e07dd3f..c99499ab3 100644 --- a/blocksuite/affine/blocks/image/src/store.ts +++ b/blocksuite/affine/blocks/image/src/store.ts @@ -13,7 +13,9 @@ const ImageStoreExtensionOptionsSchema = z.object({ imageProxyURL: z.string().optional(), }); -export class ImageStoreExtension extends StoreExtensionProvider { +export class ImageStoreExtension extends StoreExtensionProvider< + z.infer +> { override name = 'affine-image-block'; override schema = ImageStoreExtensionOptionsSchema; diff --git a/blocksuite/affine/blocks/note/package.json b/blocksuite/affine/blocks/note/package.json index fe05a8001..c6fa8eab3 100644 --- a/blocksuite/affine/blocks/note/package.json +++ b/blocksuite/affine/blocks/note/package.json @@ -13,6 +13,7 @@ "@blocksuite/affine-block-embed": "workspace:*", "@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-components": "workspace:*", + "@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-fragment-doc-title": "workspace:*", "@blocksuite/affine-gfx-turbo-renderer": "workspace:*", "@blocksuite/affine-inline-preset": "workspace:*", @@ -39,7 +40,9 @@ "exports": { ".": "./src/index.ts", "./effects": "./src/effects.ts", - "./turbo-painter": "./src/turbo/note-painter.worker.ts" + "./turbo-painter": "./src/turbo/note-painter.worker.ts", + "./store": "./src/store.ts", + "./view": "./src/view.ts" }, "files": [ "src", diff --git a/blocksuite/affine/blocks/note/src/store.ts b/blocksuite/affine/blocks/note/src/store.ts new file mode 100644 index 000000000..374a5801c --- /dev/null +++ b/blocksuite/affine/blocks/note/src/store.ts @@ -0,0 +1,36 @@ +import { + type StoreExtensionContext, + StoreExtensionProvider, +} from '@blocksuite/affine-ext-loader'; +import { NoteBlockSchemaExtension } from '@blocksuite/affine-model'; +import { z } from 'zod'; + +import { + DocNoteBlockAdapterExtensions, + EdgelessNoteBlockAdapterExtensions, +} from './adapters'; + +const optionsSchema = z.object({ + mode: z.enum(['doc', 'edgeless']).optional(), +}); + +export class NoteStoreExtension extends StoreExtensionProvider< + z.infer +> { + override name = 'affine-note-block'; + + override schema = optionsSchema; + + override setup( + context: StoreExtensionContext, + options?: z.infer + ) { + super.setup(context); + context.register(NoteBlockSchemaExtension); + if (options?.mode === 'edgeless') { + context.register(EdgelessNoteBlockAdapterExtensions); + } else { + context.register(DocNoteBlockAdapterExtensions); + } + } +} diff --git a/blocksuite/affine/blocks/note/src/view.ts b/blocksuite/affine/blocks/note/src/view.ts new file mode 100644 index 000000000..39bc71b0a --- /dev/null +++ b/blocksuite/affine/blocks/note/src/view.ts @@ -0,0 +1,47 @@ +import { + type ViewExtensionContext, + ViewExtensionProvider, +} from '@blocksuite/affine-ext-loader'; +import { NoteBlockSchema } from '@blocksuite/affine-model'; +import { BlockViewExtension, FlavourExtension } from '@blocksuite/std'; +import { literal } from 'lit/static-html.js'; + +import { NoteSlashMenuConfigExtension } from './configs/slash-menu'; +import { createBuiltinToolbarConfigExtension } from './configs/toolbar'; +import { effects } from './effects'; +import { NoteKeymapExtension } from './note-keymap'; + +const flavour = NoteBlockSchema.model.flavour; + +export class NoteViewExtension extends ViewExtensionProvider { + override name = 'affine-note-block'; + + override effect() { + super.effect(); + effects(); + } + + override setup(context: ViewExtensionContext) { + super.setup(context); + context.register([ + FlavourExtension(flavour), + NoteSlashMenuConfigExtension, + NoteKeymapExtension, + ]); + + const scope = context.scope; + const isEdgeless = + scope === 'edgeless' || + scope === 'preview-edgeless' || + scope === 'mobile-edgeless'; + + if (isEdgeless) { + context.register( + BlockViewExtension(flavour, literal`affine-edgeless-note`) + ); + context.register(createBuiltinToolbarConfigExtension(flavour)); + } else { + context.register(BlockViewExtension(flavour, literal`affine-note`)); + } + } +} diff --git a/blocksuite/affine/blocks/note/tsconfig.json b/blocksuite/affine/blocks/note/tsconfig.json index 60ff8f32d..522a01874 100644 --- a/blocksuite/affine/blocks/note/tsconfig.json +++ b/blocksuite/affine/blocks/note/tsconfig.json @@ -10,6 +10,7 @@ { "path": "../embed" }, { "path": "../surface" }, { "path": "../../components" }, + { "path": "../../ext-loader" }, { "path": "../../fragments/doc-title" }, { "path": "../../gfx/turbo-renderer" }, { "path": "../../inlines/preset" }, diff --git a/blocksuite/affine/blocks/paragraph/package.json b/blocksuite/affine/blocks/paragraph/package.json index 79886af2c..180022d1d 100644 --- a/blocksuite/affine/blocks/paragraph/package.json +++ b/blocksuite/affine/blocks/paragraph/package.json @@ -11,6 +11,7 @@ "license": "MIT", "dependencies": { "@blocksuite/affine-components": "workspace:*", + "@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-gfx-turbo-renderer": "workspace:*", "@blocksuite/affine-inline-preset": "workspace:*", "@blocksuite/affine-model": "workspace:*", @@ -32,7 +33,9 @@ "exports": { ".": "./src/index.ts", "./effects": "./src/effects.ts", - "./turbo-painter": "./src/turbo/paragraph-painter.worker.ts" + "./turbo-painter": "./src/turbo/paragraph-painter.worker.ts", + "./store": "./src/store.ts", + "./view": "./src/view.ts" }, "files": [ "src", diff --git a/blocksuite/affine/blocks/paragraph/src/store.ts b/blocksuite/affine/blocks/paragraph/src/store.ts new file mode 100644 index 000000000..231600332 --- /dev/null +++ b/blocksuite/affine/blocks/paragraph/src/store.ts @@ -0,0 +1,17 @@ +import { + type StoreExtensionContext, + StoreExtensionProvider, +} from '@blocksuite/affine-ext-loader'; +import { ParagraphBlockSchemaExtension } from '@blocksuite/affine-model'; + +import { ParagraphBlockAdapterExtensions } from './adapters/extension'; + +export class ParagraphStoreExtension extends StoreExtensionProvider { + override name = 'affine-paragraph-block'; + + override setup(context: StoreExtensionContext) { + super.setup(context); + context.register(ParagraphBlockSchemaExtension); + context.register(ParagraphBlockAdapterExtensions); + } +} diff --git a/blocksuite/affine/blocks/paragraph/src/view.ts b/blocksuite/affine/blocks/paragraph/src/view.ts new file mode 100644 index 000000000..87883b4d8 --- /dev/null +++ b/blocksuite/affine/blocks/paragraph/src/view.ts @@ -0,0 +1,67 @@ +import { + type ViewExtensionContext, + ViewExtensionProvider, +} from '@blocksuite/affine-ext-loader'; +import { BlockViewExtension, FlavourExtension } from '@blocksuite/std'; +import { literal } from 'lit/static-html.js'; + +import { ParagraphBlockConfigExtension } from './paragraph-block-config.js'; +import { + ParagraphKeymapExtension, + ParagraphTextKeymapExtension, +} from './paragraph-keymap.js'; + +const placeholders = { + text: "Type '/' for commands", + h1: 'Heading 1', + h2: 'Heading 2', + h3: 'Heading 3', + h4: 'Heading 4', + h5: 'Heading 5', + h6: 'Heading 6', + quote: '', +}; + +import { ParagraphBlockModel } from '@blocksuite/affine-model'; +import { z } from 'zod'; + +import { effects } from './effects'; + +const optionsSchema = z.object({ + getPlaceholder: z + .function() + .args(z.instanceof(ParagraphBlockModel)) + .returns(z.string()), +}); + +export class ParagraphViewExtension extends ViewExtensionProvider< + z.infer +> { + override name = 'affine-paragraph-block'; + + override schema = optionsSchema; + + override effect(): void { + super.effect(); + effects(); + } + + override setup( + context: ViewExtensionContext, + options?: z.infer + ) { + super.setup(context); + const getPlaceholder = + options?.getPlaceholder ?? (model => placeholders[model.props.type]); + + context.register([ + FlavourExtension('affine:paragraph'), + BlockViewExtension('affine:paragraph', literal`affine-paragraph`), + ParagraphTextKeymapExtension, + ParagraphKeymapExtension, + ParagraphBlockConfigExtension({ + getPlaceholder, + }), + ]); + } +} diff --git a/blocksuite/affine/blocks/paragraph/tsconfig.json b/blocksuite/affine/blocks/paragraph/tsconfig.json index 5a8a2133e..4d94611b1 100644 --- a/blocksuite/affine/blocks/paragraph/tsconfig.json +++ b/blocksuite/affine/blocks/paragraph/tsconfig.json @@ -8,6 +8,7 @@ "include": ["./src"], "references": [ { "path": "../../components" }, + { "path": "../../ext-loader" }, { "path": "../../gfx/turbo-renderer" }, { "path": "../../inlines/preset" }, { "path": "../../model" }, diff --git a/packages/frontend/core/src/blocksuite/manager/store.ts b/packages/frontend/core/src/blocksuite/manager/store.ts index 777f6eae3..6b6c21a40 100644 --- a/packages/frontend/core/src/blocksuite/manager/store.ts +++ b/packages/frontend/core/src/blocksuite/manager/store.ts @@ -11,6 +11,8 @@ import { FrameStoreExtension } from '@blocksuite/affine/blocks/frame/store'; import { ImageStoreExtension } from '@blocksuite/affine/blocks/image/store'; import { LatexStoreExtension } from '@blocksuite/affine/blocks/latex/store'; import { ListStoreExtension } from '@blocksuite/affine/blocks/list/store'; +import { NoteStoreExtension } from '@blocksuite/affine/blocks/note/store'; +import { ParagraphStoreExtension } from '@blocksuite/affine/blocks/paragraph/store'; import { StoreExtensionManager } from '@blocksuite/affine/ext-loader'; export function createStoreManager() { @@ -28,6 +30,8 @@ export function createStoreManager() { ImageStoreExtension, LatexStoreExtension, ListStoreExtension, + NoteStoreExtension, + ParagraphStoreExtension, ]); return manager; diff --git a/packages/frontend/core/src/blocksuite/manager/view.ts b/packages/frontend/core/src/blocksuite/manager/view.ts index 896d02f71..56112f966 100644 --- a/packages/frontend/core/src/blocksuite/manager/view.ts +++ b/packages/frontend/core/src/blocksuite/manager/view.ts @@ -11,6 +11,8 @@ import { FrameViewExtension } from '@blocksuite/affine/blocks/frame/view'; import { ImageViewExtension } from '@blocksuite/affine/blocks/image/view'; import { LatexViewExtension } from '@blocksuite/affine/blocks/latex/view'; import { ListViewExtension } from '@blocksuite/affine/blocks/list/view'; +import { NoteViewExtension } from '@blocksuite/affine/blocks/note/view'; +import { ParagraphViewExtension } from '@blocksuite/affine/blocks/paragraph/view'; import { ViewExtensionManager } from '@blocksuite/affine/ext-loader'; export function createViewManager() { @@ -28,6 +30,8 @@ export function createViewManager() { ImageViewExtension, LatexViewExtension, ListViewExtension, + NoteViewExtension, + ParagraphViewExtension, ]); return manager; diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index 21eb51053..f41e026c2 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -287,6 +287,7 @@ export const PackageList = [ 'blocksuite/affine/blocks/embed', 'blocksuite/affine/blocks/surface', 'blocksuite/affine/components', + 'blocksuite/affine/ext-loader', 'blocksuite/affine/fragments/doc-title', 'blocksuite/affine/gfx/turbo-renderer', 'blocksuite/affine/inlines/preset', @@ -304,6 +305,7 @@ export const PackageList = [ name: '@blocksuite/affine-block-paragraph', workspaceDependencies: [ 'blocksuite/affine/components', + 'blocksuite/affine/ext-loader', 'blocksuite/affine/gfx/turbo-renderer', 'blocksuite/affine/inlines/preset', 'blocksuite/affine/model', diff --git a/yarn.lock b/yarn.lock index 9c38034c6..9f41b4c09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2745,6 +2745,7 @@ __metadata: "@blocksuite/affine-block-embed": "workspace:*" "@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-fragment-doc-title": "workspace:*" "@blocksuite/affine-gfx-turbo-renderer": "workspace:*" "@blocksuite/affine-inline-preset": "workspace:*" @@ -2775,6 +2776,7 @@ __metadata: resolution: "@blocksuite/affine-block-paragraph@workspace:blocksuite/affine/blocks/paragraph" dependencies: "@blocksuite/affine-components": "workspace:*" + "@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-gfx-turbo-renderer": "workspace:*" "@blocksuite/affine-inline-preset": "workspace:*" "@blocksuite/affine-model": "workspace:*"