diff --git a/packages/common/env/package.json b/packages/common/env/package.json index 9272bc1e04..ca592cb86b 100644 --- a/packages/common/env/package.json +++ b/packages/common/env/package.json @@ -3,8 +3,8 @@ "private": true, "type": "module", "devDependencies": { - "@blocksuite/global": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/store": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/global": "0.0.0-canary-20240902070217", + "@blocksuite/store": "0.0.0-canary-20240902070217", "react": "18.3.1", "react-dom": "18.3.1", "vitest": "1.6.0" diff --git a/packages/common/infra/package.json b/packages/common/infra/package.json index 88334eb581..6c081a353d 100644 --- a/packages/common/infra/package.json +++ b/packages/common/infra/package.json @@ -14,10 +14,10 @@ "@affine/debug": "workspace:*", "@affine/env": "workspace:*", "@affine/templates": "workspace:*", - "@blocksuite/blocks": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/global": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/store": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/blocks": "0.0.0-canary-20240902070217", + "@blocksuite/global": "0.0.0-canary-20240902070217", + "@blocksuite/presets": "0.0.0-canary-20240902070217", + "@blocksuite/store": "0.0.0-canary-20240902070217", "@datastructures-js/binary-search-tree": "^5.3.2", "foxact": "^0.2.33", "fuse.js": "^7.0.0", @@ -34,8 +34,8 @@ "devDependencies": { "@affine-test/fixtures": "workspace:*", "@affine/templates": "workspace:*", - "@blocksuite/block-std": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/block-std": "0.0.0-canary-20240902070217", + "@blocksuite/presets": "0.0.0-canary-20240902070217", "@testing-library/react": "^16.0.0", "async-call-rpc": "^6.4.0", "fake-indexeddb": "^6.0.0", diff --git a/packages/common/infra/src/modules/doc/entities/doc.ts b/packages/common/infra/src/modules/doc/entities/doc.ts index 1e1cf473f8..ba14c73f05 100644 --- a/packages/common/infra/src/modules/doc/entities/doc.ts +++ b/packages/common/infra/src/modules/doc/entities/doc.ts @@ -1,10 +1,9 @@ -import type { RootBlockModel } from '@blocksuite/blocks'; +import type { DocMode, RootBlockModel } from '@blocksuite/blocks'; import { Entity } from '../../../framework'; import type { WorkspaceService } from '../../workspace'; import type { DocScope } from '../scopes/doc'; import type { DocsStore } from '../stores/docs'; -import type { DocMode } from './record'; export class Doc extends Entity { constructor( @@ -44,7 +43,7 @@ export class Doc extends Entity { togglePrimaryMode() { this.setPrimaryMode( - this.getPrimaryMode() === 'edgeless' ? 'page' : 'edgeless' + (this.getPrimaryMode() === 'edgeless' ? 'page' : 'edgeless') as DocMode ); } diff --git a/packages/common/infra/src/modules/doc/entities/record-list.ts b/packages/common/infra/src/modules/doc/entities/record-list.ts index 06ac29b984..1caa94f7aa 100644 --- a/packages/common/infra/src/modules/doc/entities/record-list.ts +++ b/packages/common/infra/src/modules/doc/entities/record-list.ts @@ -1,9 +1,10 @@ +import type { DocMode } from '@blocksuite/blocks'; import { map } from 'rxjs'; import { Entity } from '../../../framework'; import { LiveData } from '../../../livedata'; import type { DocsStore } from '../stores/docs'; -import { type DocMode, DocRecord } from './record'; +import { DocRecord } from './record'; export class DocRecordList extends Entity { constructor(private readonly store: DocsStore) { @@ -64,7 +65,9 @@ export class DocRecordList extends Entity { } public togglePrimaryMode(id: string) { - const mode = this.getPrimaryMode(id) === 'edgeless' ? 'page' : 'edgeless'; + const mode = ( + this.getPrimaryMode(id) === 'edgeless' ? 'page' : 'edgeless' + ) as DocMode; this.setPrimaryMode(id, mode); return this.getPrimaryMode(id); } diff --git a/packages/common/infra/src/modules/doc/entities/record.ts b/packages/common/infra/src/modules/doc/entities/record.ts index 991d396b39..ae582f7185 100644 --- a/packages/common/infra/src/modules/doc/entities/record.ts +++ b/packages/common/infra/src/modules/doc/entities/record.ts @@ -1,11 +1,10 @@ +import type { DocMode } from '@blocksuite/blocks'; import type { DocMeta } from '@blocksuite/store'; import { Entity } from '../../../framework'; import { LiveData } from '../../../livedata'; import type { DocsStore } from '../stores/docs'; -export type DocMode = 'edgeless' | 'page'; - /** * # DocRecord * @@ -28,8 +27,8 @@ export class DocRecord extends Entity<{ id: string }> { primaryMode$: LiveData = LiveData.from( this.docsStore.watchDocPrimaryModeSetting(this.id), - 'page' - ).map(mode => (mode === 'edgeless' ? 'edgeless' : 'page')); + 'page' as DocMode + ).map(mode => (mode === 'edgeless' ? 'edgeless' : 'page') as DocMode); setPrimaryMode(mode: DocMode) { return this.docsStore.setDocPrimaryModeSetting(this.id, mode); diff --git a/packages/common/infra/src/modules/doc/index.ts b/packages/common/infra/src/modules/doc/index.ts index 92b44465fb..ca03973c08 100644 --- a/packages/common/infra/src/modules/doc/index.ts +++ b/packages/common/infra/src/modules/doc/index.ts @@ -1,5 +1,4 @@ export { Doc } from './entities/doc'; -export type { DocMode } from './entities/record'; export { DocRecord } from './entities/record'; export { DocRecordList } from './entities/record-list'; export { DocScope } from './scopes/doc'; diff --git a/packages/common/infra/src/modules/doc/services/docs.ts b/packages/common/infra/src/modules/doc/services/docs.ts index 3b2f23eb82..679dda88b9 100644 --- a/packages/common/infra/src/modules/doc/services/docs.ts +++ b/packages/common/infra/src/modules/doc/services/docs.ts @@ -1,10 +1,10 @@ import { Unreachable } from '@affine/env/constant'; +import type { DocMode } from '@blocksuite/blocks'; import { Service } from '../../../framework'; import { initEmptyPage } from '../../../initialization'; import { ObjectPool } from '../../../utils'; import type { Doc } from '../entities/doc'; -import type { DocMode } from '../entities/record'; import { DocRecordList } from '../entities/record-list'; import { DocScope } from '../scopes/doc'; import type { DocsStore } from '../stores/docs'; diff --git a/packages/common/infra/src/modules/doc/stores/docs.ts b/packages/common/infra/src/modules/doc/stores/docs.ts index 8d7f2f2bb7..f7475a3f9e 100644 --- a/packages/common/infra/src/modules/doc/stores/docs.ts +++ b/packages/common/infra/src/modules/doc/stores/docs.ts @@ -1,10 +1,10 @@ +import type { DocMode } from '@blocksuite/blocks'; import { type DocMeta } from '@blocksuite/store'; import { isEqual } from 'lodash-es'; import { distinctUntilChanged, Observable } from 'rxjs'; import { Store } from '../../../framework'; import type { WorkspaceLocalState, WorkspaceService } from '../../workspace'; -import type { DocMode } from '../entities/record'; export class DocsStore extends Store { constructor( diff --git a/packages/common/infra/src/modules/feature-flag/constant.ts b/packages/common/infra/src/modules/feature-flag/constant.ts index 8ccb6c490d..b90025929c 100644 --- a/packages/common/infra/src/modules/feature-flag/constant.ts +++ b/packages/common/infra/src/modules/feature-flag/constant.ts @@ -12,13 +12,6 @@ export const AFFINE_FLAGS = { description: 'Allows adding notes to database attachments.', configurable: isNotStableBuild, }, - enable_database_statistics: { - category: 'blocksuite', - bsFlag: 'enable_database_statistics', - displayName: 'Database Block Statistics', - description: 'Shows statistics for database blocks.', - configurable: isNotStableBuild, - }, enable_block_query: { category: 'blocksuite', bsFlag: 'enable_block_query', diff --git a/packages/common/infra/src/modules/global-context/entities/global-context.ts b/packages/common/infra/src/modules/global-context/entities/global-context.ts index baa27f75ba..e350da46ec 100644 --- a/packages/common/infra/src/modules/global-context/entities/global-context.ts +++ b/packages/common/infra/src/modules/global-context/entities/global-context.ts @@ -1,7 +1,8 @@ +import type { DocMode } from '@blocksuite/blocks'; + import { Entity } from '../../../framework'; import { LiveData } from '../../../livedata'; import { MemoryMemento } from '../../../storage'; -import type { DocMode } from '../../doc'; export class GlobalContext extends Entity { memento = new MemoryMemento(); diff --git a/packages/frontend/component/package.json b/packages/frontend/component/package.json index 12f8b1cf19..97153bb91a 100644 --- a/packages/frontend/component/package.json +++ b/packages/frontend/component/package.json @@ -81,12 +81,12 @@ "zod": "^3.22.4" }, "devDependencies": { - "@blocksuite/block-std": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/blocks": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/global": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/block-std": "0.0.0-canary-20240902070217", + "@blocksuite/blocks": "0.0.0-canary-20240902070217", + "@blocksuite/global": "0.0.0-canary-20240902070217", "@blocksuite/icons": "2.1.66", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/store": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/presets": "0.0.0-canary-20240902070217", + "@blocksuite/store": "0.0.0-canary-20240902070217", "@chromatic-com/storybook": "^1", "@storybook/addon-actions": "^8.2.9", "@storybook/addon-essentials": "^8.2.9", diff --git a/packages/frontend/core/package.json b/packages/frontend/core/package.json index 3dfa227f83..b58985f872 100644 --- a/packages/frontend/core/package.json +++ b/packages/frontend/core/package.json @@ -15,13 +15,13 @@ "@affine/graphql": "workspace:*", "@affine/i18n": "workspace:*", "@affine/templates": "workspace:*", - "@blocksuite/block-std": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/blocks": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/global": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/block-std": "0.0.0-canary-20240902070217", + "@blocksuite/blocks": "0.0.0-canary-20240902070217", + "@blocksuite/global": "0.0.0-canary-20240902070217", "@blocksuite/icons": "2.1.66", - "@blocksuite/inline": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/store": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/inline": "0.0.0-canary-20240902070217", + "@blocksuite/presets": "0.0.0-canary-20240902070217", + "@blocksuite/store": "0.0.0-canary-20240902070217", "@dnd-kit/core": "^6.1.0", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts index 69b16c9be1..8defecc199 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/chat-actions-handle.ts @@ -4,11 +4,12 @@ import type { EditorHost, TextSelection, } from '@blocksuite/block-std'; -import type { - DocMode, - EdgelessRootService, - ImageSelection, - PageRootService, +import { + type DocMode, + DocModeProvider, + type EdgelessRootService, + type ImageSelection, + type PageRootService, } from '@blocksuite/blocks'; import { BlocksUtils, NoteDisplayMode } from '@blocksuite/blocks'; import { @@ -176,8 +177,7 @@ function addAIChatBlock( } export function promptDocTitle(host: EditorHost, autofill?: string) { - const notification = - host.std.spec.getService('affine:page').notificationService; + const notification = host.std.getService('affine:page').notificationService; if (!notification) return Promise.resolve(undefined); return notification.prompt({ @@ -297,11 +297,12 @@ const SAVE_CHAT_TO_BLOCK_ACTION: ChatAction = { return false; } - const rootService = host.spec.getService('affine:page'); - const surfaceService = host.spec.getService('affine:surface'); + const rootService = host.std.getService('affine:page'); + const surfaceService = host.std.getService('affine:surface'); if (!rootService || !surfaceService) return false; - const { docModeService, notificationService } = rootService; + const { notificationService } = rootService; + const docModeService = host.std.get(DocModeProvider); const { layer } = surfaceService; const curMode = docModeService.getMode(); const viewportCenter = getViewportCenter( @@ -312,7 +313,7 @@ const SAVE_CHAT_TO_BLOCK_ACTION: ChatAction = { // If current mode is not edgeless, switch to edgeless mode first if (curMode !== 'edgeless') { // Set mode to edgeless - docModeService.setMode('edgeless'); + docModeService.setMode('edgeless' as DocMode); // Notify user to switch to edgeless mode notificationService?.notify({ title: 'Save chat to a block', @@ -382,7 +383,7 @@ const ADD_TO_EDGELESS_AS_NOTE = { handler: async (host: EditorHost, content: string) => { reportResponse('result:add-note'); const { doc } = host; - const service = host.spec.getService('affine:page'); + const service = host.std.getService('affine:page'); const elements = service.selection.selectedElements; const props: { displayMode: NoteDisplayMode; xywh?: SerializedXYWH } = { @@ -423,8 +424,8 @@ const CREATE_AS_DOC = { newDoc.addBlock('affine:surface', {}, rootId); const noteId = newDoc.addBlock('affine:note', {}, rootId); - host.spec.getService('affine:page').slots.docLinkClicked.emit({ - docId: newDoc.id, + host.std.getService('affine:page').slots.docLinkClicked.emit({ + pageId: newDoc.id, }); let complete = false; (function addContent() { @@ -460,8 +461,9 @@ const CREATE_AS_LINKED_DOC = { return false; } - const service = host.spec.getService('affine:page'); - const mode = service.docModeService.getMode(); + const service = host.std.getService('affine:page'); + const docModeService = host.std.get(DocModeProvider); + const mode = docModeService.getMode(); if (mode !== 'edgeless') { return false; } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts index 25a60d4cd4..9a5f90c426 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-panel.ts @@ -1,6 +1,7 @@ import { type EditorHost, WithDisposable } from '@blocksuite/block-std'; import { type AIItemGroupConfig, + DocMode, EdgelessRootService, scrollbarStyle, } from '@blocksuite/blocks'; @@ -63,7 +64,7 @@ export class AskAIPanel extends WithDisposable(LitElement) { item.showWhen ? item.showWhen( this.host.command.chain(), - this._edgeless ? 'edgeless' : 'page', + this._edgeless ? DocMode.Edgeless : DocMode.Page, this.host ) : true diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/chat-action-list.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/chat-action-list.ts index 5a5050f716..a6766754f0 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/chat-action-list.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/chat-action-list.ts @@ -60,7 +60,7 @@ export class ChatActionList extends LitElement { } private get _rootService() { - return this.host.spec.getService('affine:page'); + return this.host.std.getService('affine:page'); } private get _currentTextSelection(): TextSelection | undefined { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts index 5d5590ed28..f670bf2b50 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/copy-more.ts @@ -73,7 +73,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) { `; private get _rootService() { - return this.host.spec.getService('affine:page'); + return this.host.std.getService('affine:page'); } private get _selectionValue() { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/selection-utils.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/selection-utils.ts index 4227b906c9..aceecde968 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/selection-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/selection-utils.ts @@ -12,7 +12,7 @@ import { Slice } from '@blocksuite/store'; import { getMarkdownFromSlice } from './markdown-utils'; export const getRootService = (host: EditorHost) => { - return host.std.spec.getService('affine:page'); + return host.std.getService('affine:page'); }; export function getEdgelessRootFromEditor(editor: EditorHost) { @@ -24,7 +24,7 @@ export function getEdgelessRootFromEditor(editor: EditorHost) { return edgelessRoot; } export function getEdgelessService(editor: EditorHost) { - const rootService = editor.std.spec.getService('affine:page'); + const rootService = editor.std.getService('affine:page'); if (rootService instanceof EdgelessRootService) { return rootService; } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts index acd8807753..be5caa1ce8 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts @@ -507,7 +507,7 @@ export const responses: { const contents = data.contents as unknown[]; if (!contents) return; const images = data.images as { url: string; id: string }[][]; - const service = host.spec.getService('affine:page'); + const service = host.std.getService('affine:page'); (async function () { for (let i = 0; i < contents.length - 1; i++) { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/ai-spec.ts b/packages/frontend/core/src/blocksuite/presets/ai/ai-spec.ts index f2efcc88a1..76a0cbab5a 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/ai-spec.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/ai-spec.ts @@ -1,4 +1,8 @@ -import type { BlockSpec } from '@blocksuite/block-std'; +import { + BlockServiceWatcher, + type ExtensionType, + WidgetViewMapIdentifier, +} from '@blocksuite/block-std'; import { AFFINE_AI_PANEL_WIDGET, AFFINE_EDGELESS_COPILOT_WIDGET, @@ -11,8 +15,10 @@ import { EdgelessCopilotWidget, EdgelessElementToolbarWidget, EdgelessRootBlockSpec, + edgelessRootWigetViewMap, ImageBlockSpec, PageRootBlockSpec, + pageRootWidgetViewMap, ParagraphBlockService, ParagraphBlockSpec, } from '@blocksuite/blocks'; @@ -30,56 +36,52 @@ import { setupImageToolbarEntry } from './entries/image-toolbar/setup-image-tool import { setupSlashMenuEntry } from './entries/slash-menu/setup-slash-menu'; import { setupSpaceEntry } from './entries/space/setup-space'; -export const AIPageRootBlockSpec: BlockSpec = { +class AIPageRootWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:page'; + + override mounted() { + super.mounted(); + this.blockService.specSlots.widgetConnected.on(view => { + if (view.component instanceof AffineAIPanelWidget) { + view.component.style.width = '630px'; + view.component.config = buildAIPanelConfig(view.component); + setupSpaceEntry(view.component); + } + + if (view.component instanceof AffineFormatBarWidget) { + setupFormatBarEntry(view.component); + } + + if (view.component instanceof AffineSlashMenuWidget) { + setupSlashMenuEntry(view.component); + } + }); + } +} + +export const AIPageRootBlockSpec: ExtensionType[] = [ ...PageRootBlockSpec, - view: { - ...PageRootBlockSpec.view, - widgets: { - ...PageRootBlockSpec.view.widgets, - [AFFINE_AI_PANEL_WIDGET]: literal`${unsafeStatic( - AFFINE_AI_PANEL_WIDGET - )}`, + AIPageRootWatcher, + { + setup: di => { + di.override(WidgetViewMapIdentifier('affine:page'), () => { + return { + ...pageRootWidgetViewMap, + [AFFINE_AI_PANEL_WIDGET]: literal`${unsafeStatic( + AFFINE_AI_PANEL_WIDGET + )}`, + }; + }); }, }, - setup: (slots, disposableGroup) => { - PageRootBlockSpec.setup?.(slots, disposableGroup); - disposableGroup.add( - slots.widgetConnected.on(view => { - if (view.component instanceof AffineAIPanelWidget) { - view.component.style.width = '630px'; - view.component.config = buildAIPanelConfig(view.component); - setupSpaceEntry(view.component); - } +]; - if (view.component instanceof AffineFormatBarWidget) { - setupFormatBarEntry(view.component); - } +class AIEdgelessRootWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:page'; - if (view.component instanceof AffineSlashMenuWidget) { - setupSlashMenuEntry(view.component); - } - }) - ); - }, -}; - -export const AIEdgelessRootBlockSpec: BlockSpec = { - ...EdgelessRootBlockSpec, - view: { - ...EdgelessRootBlockSpec.view, - widgets: { - ...EdgelessRootBlockSpec.view.widgets, - [AFFINE_EDGELESS_COPILOT_WIDGET]: literal`${unsafeStatic( - AFFINE_EDGELESS_COPILOT_WIDGET - )}`, - [AFFINE_AI_PANEL_WIDGET]: literal`${unsafeStatic( - AFFINE_AI_PANEL_WIDGET - )}`, - }, - }, - setup(slots, disposableGroup) { - EdgelessRootBlockSpec.setup?.(slots, disposableGroup); - slots.widgetConnected.on(view => { + override mounted() { + super.mounted(); + this.blockService.specSlots.widgetConnected.on(view => { if (view.component instanceof AffineAIPanelWidget) { view.component.style.width = '430px'; view.component.config = buildAIPanelConfig(view.component); @@ -102,55 +104,93 @@ export const AIEdgelessRootBlockSpec: BlockSpec = { setupSlashMenuEntry(view.component); } }); - }, -}; + } +} -export const AIParagraphBlockSpec: BlockSpec = { - ...ParagraphBlockSpec, - setup(slots, disposableGroup) { - ParagraphBlockSpec.setup?.(slots, disposableGroup); - slots.mounted.on(({ service }) => { - assertInstanceOf(service, ParagraphBlockService); - service.placeholderGenerator = model => { - if (model.type === 'text') { - return "Type '/' for commands, 'space' for AI"; - } - - const placeholders = { - h1: 'Heading 1', - h2: 'Heading 2', - h3: 'Heading 3', - h4: 'Heading 4', - h5: 'Heading 5', - h6: 'Heading 6', - quote: '', +export const AIEdgelessRootBlockSpec: ExtensionType[] = [ + ...EdgelessRootBlockSpec, + AIEdgelessRootWatcher, + { + setup: di => { + di.override(WidgetViewMapIdentifier('affine:page'), () => { + return { + ...edgelessRootWigetViewMap, + [AFFINE_EDGELESS_COPILOT_WIDGET]: literal`${unsafeStatic( + AFFINE_EDGELESS_COPILOT_WIDGET + )}`, + [AFFINE_AI_PANEL_WIDGET]: literal`${unsafeStatic( + AFFINE_AI_PANEL_WIDGET + )}`, }; - return placeholders[model.type]; - }; - }); + }); + }, }, -}; +]; -export const AICodeBlockSpec: BlockSpec = { - ...CodeBlockSpec, - setup(slots, disposableGroup) { - CodeBlockSpec.setup?.(slots, disposableGroup); - slots.widgetConnected.on(view => { +class AIParagraphBlockWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:paragraph'; + + override mounted() { + super.mounted(); + const service = this.blockService; + assertInstanceOf(service, ParagraphBlockService); + service.placeholderGenerator = model => { + if (model.type === 'text') { + return "Type '/' for commands, 'space' for AI"; + } + + const placeholders = { + h1: 'Heading 1', + h2: 'Heading 2', + h3: 'Heading 3', + h4: 'Heading 4', + h5: 'Heading 5', + h6: 'Heading 6', + quote: '', + }; + return placeholders[model.type]; + }; + } +} + +export const AIParagraphBlockSpec: ExtensionType[] = [ + ...ParagraphBlockSpec, + AIParagraphBlockWatcher, +]; + +class AICodeBlockWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:code'; + + override mounted() { + super.mounted(); + const service = this.blockService; + service.specSlots.widgetConnected.on(view => { if (view.component instanceof AffineCodeToolbarWidget) { setupCodeToolbarEntry(view.component); } }); - }, -}; + } +} -export const AIImageBlockSpec: BlockSpec = { - ...ImageBlockSpec, - setup(slots, disposableGroup) { - ImageBlockSpec.setup?.(slots, disposableGroup); - slots.widgetConnected.on(view => { +export const AICodeBlockSpec: ExtensionType[] = [ + ...CodeBlockSpec, + AICodeBlockWatcher, +]; + +class AIImageBlockWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:image'; + + override mounted() { + super.mounted(); + this.blockService.specSlots.widgetConnected.on(view => { if (view.component instanceof AffineImageToolbarWidget) { setupImageToolbarEntry(view.component); } }); - }, -}; + } +} + +export const AIImageBlockSpec: ExtensionType[] = [ + ...ImageBlockSpec, + AIImageBlockWatcher, +]; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts index 6e55c41b9d..42847750d2 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts @@ -17,6 +17,7 @@ import type { BaseSelection, EditorHost } from '@blocksuite/block-std'; import { ShadowlessElement, WithDisposable } from '@blocksuite/block-std'; import { type AIError, + DocModeProvider, isInsidePageEditor, PaymentRequiredError, UnauthorizedError, @@ -161,7 +162,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) { this._selectionValue = this.host.selection.value; }) ); - const { docModeService } = this.host.spec.getService('affine:page'); + const docModeService = this.host.std.get(DocModeProvider); disposables.add(docModeService.onModeChange(() => this.requestUpdate())); } } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/index.ts index 25e6caa9d3..2245c2bb6c 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/index.ts @@ -160,7 +160,7 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) { private readonly _cleanupHistories = async () => { const notification = - this.host.std.spec.getService('affine:page').notificationService; + this.host.std.getService('affine:page').notificationService; if (!notification) return; if ( diff --git a/packages/frontend/core/src/blocksuite/presets/ai/entries/code-toolbar/setup-code-toolbar.ts b/packages/frontend/core/src/blocksuite/presets/ai/entries/code-toolbar/setup-code-toolbar.ts index aef50611fb..3e4a64e9ea 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/entries/code-toolbar/setup-code-toolbar.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/entries/code-toolbar/setup-code-toolbar.ts @@ -1,9 +1,6 @@ import '../../_common/components/ask-ai-button'; -import type { - AffineCodeToolbarWidget, - CodeBlockComponent, -} from '@blocksuite/blocks'; +import type { AffineCodeToolbarWidget } from '@blocksuite/blocks'; import { html } from 'lit'; const AICodeItemGroups = buildAICodeItemGroups(); @@ -14,42 +11,34 @@ const buttonOptions: AskAIButtonOptions = { import type { AskAIButtonOptions } from '../../_common/components/ask-ai-button'; import { buildAICodeItemGroups } from '../../_common/config'; -import { AIStarIcon } from '../../_common/icons'; export function setupCodeToolbarEntry(codeToolbar: AffineCodeToolbarWidget) { - const onAskAIClick = () => { - const { host } = codeToolbar; - const { selection } = host; - const codeBlock = codeToolbar.block; - selection.setGroup('note', [ - selection.create('block', { blockId: codeBlock.blockId }), - ]); - }; - codeToolbar.setupDefaultConfig(); - codeToolbar.addItems( - [ - { - type: 'custom', - name: 'Ask AI', - tooltip: 'Ask AI', - icon: AIStarIcon, - showWhen: CodeBlockComponent => !CodeBlockComponent.doc.readonly, - render(codeBlock: CodeBlockComponent, onClick?: () => void) { - return html` { - e.stopPropagation(); - onAskAIClick(); - onClick?.(); - }} - >`; - }, + codeToolbar.addPrimaryItems([ + { + type: 'ask-ai', + when: ({ doc }) => !doc.readonly, + generate: ({ host, blockComponent }) => { + return { + action: () => { + const { selection } = host; + selection.setGroup('note', [ + selection.create('block', { blockId: blockComponent.blockId }), + ]); + }, + render: item => + html` { + e.stopPropagation(); + item.action(); + }} + >`, + }; }, - ], - 0 - ); + }, + ]); } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/entries/edgeless/index.ts b/packages/frontend/core/src/blocksuite/presets/ai/entries/edgeless/index.ts index 0b221d0b02..1bc00b80b7 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/entries/edgeless/index.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/entries/edgeless/index.ts @@ -1,5 +1,6 @@ import type { AIItemGroupConfig, + DocMode, EdgelessCopilotWidget, EdgelessElementToolbarWidget, EdgelessRootBlockComponent, @@ -27,7 +28,7 @@ export function setupEdgelessElementToolbarEntry( const chain = edgeless.service.std.command.chain(); const filteredGroups = edgelessActionGroups.reduce((pre, group) => { const filtered = group.items.filter(item => - item.showWhen?.(chain, 'edgeless', edgeless.host) + item.showWhen?.(chain, 'edgeless' as DocMode, edgeless.host) ); if (filtered.length > 0) pre.push({ ...group, items: filtered }); diff --git a/packages/frontend/core/src/blocksuite/presets/ai/entries/image-toolbar/setup-image-toolbar.ts b/packages/frontend/core/src/blocksuite/presets/ai/entries/image-toolbar/setup-image-toolbar.ts index d8f861ba77..f59c97e1d8 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/entries/image-toolbar/setup-image-toolbar.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/entries/image-toolbar/setup-image-toolbar.ts @@ -1,9 +1,6 @@ import '../../_common/components/ask-ai-button'; -import type { - AffineImageToolbarWidget, - ImageBlockComponent, -} from '@blocksuite/blocks'; +import type { AffineImageToolbarWidget } from '@blocksuite/blocks'; import { html } from 'lit'; import type { AskAIButtonOptions } from '../../_common/components/ask-ai-button'; @@ -17,34 +14,33 @@ const buttonOptions: AskAIButtonOptions = { }; export function setupImageToolbarEntry(imageToolbar: AffineImageToolbarWidget) { - const onAskAIClick = () => { - const { host } = imageToolbar; - const { selection } = host; - const imageBlock = imageToolbar.block; - selection.setGroup('note', [ - selection.create('image', { blockId: imageBlock.blockId }), - ]); - }; - imageToolbar.buildDefaultConfig(); - imageToolbar.addConfigItems( + imageToolbar.addPrimaryItems( [ { - type: 'custom', - render(imageBlock: ImageBlockComponent, onClick?: () => void) { - return html` { - e.stopPropagation(); - onAskAIClick(); - onClick?.(); - }} - >`; + type: 'ask-ai', + when: ({ doc }) => !doc.readonly, + generate: ({ host, blockComponent }) => { + return { + action: () => { + const { selection } = host; + selection.setGroup('note', [ + selection.create('image', { blockId: blockComponent.blockId }), + ]); + }, + render: item => + html` { + e.stopPropagation(); + item.action(); + }} + >`, + }; }, - showWhen: imageBlockComponent => !imageBlockComponent.doc.readonly, }, ], 0 diff --git a/packages/frontend/core/src/blocksuite/presets/ai/entries/slash-menu/setup-slash-menu.ts b/packages/frontend/core/src/blocksuite/presets/ai/entries/slash-menu/setup-slash-menu.ts index 785cf46c0c..501cdad470 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/entries/slash-menu/setup-slash-menu.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/entries/slash-menu/setup-slash-menu.ts @@ -1,10 +1,11 @@ -import type { - AffineAIPanelWidget, - AffineSlashMenuActionItem, - AffineSlashMenuContext, - AffineSlashMenuItem, - AffineSlashSubMenu, - AIItemConfig, +import { + type AffineAIPanelWidget, + type AffineSlashMenuActionItem, + type AffineSlashMenuContext, + type AffineSlashMenuItem, + type AffineSlashSubMenu, + type AIItemConfig, + DocModeProvider, } from '@blocksuite/blocks'; import { AFFINE_AI_PANEL_WIDGET, @@ -38,9 +39,8 @@ export function setupSlashMenuEntry(slashMenu: AffineSlashMenuWidget) { if (affineAIPanelWidget === null) return false; const chain = rootComponent.host.command.chain(); - const editorMode = rootComponent.service.docModeService.getMode( - rootComponent.doc.id - ); + const docModeService = rootComponent.std.get(DocModeProvider); + const editorMode = docModeService.getMode(rootComponent.doc.id); return item?.showWhen?.(chain, editorMode, rootComponent.host) ?? true; }; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/messages/slides-renderer.ts b/packages/frontend/core/src/blocksuite/presets/ai/messages/slides-renderer.ts index 7264b35e43..c412aabe4c 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/messages/slides-renderer.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/messages/slides-renderer.ts @@ -1,4 +1,4 @@ -import type { EditorHost } from '@blocksuite/block-std'; +import { BlockStdScope, type EditorHost } from '@blocksuite/block-std'; import { WithDisposable } from '@blocksuite/block-std'; import { type AffineAIPanelWidgetConfig, @@ -207,7 +207,10 @@ export class AISlidesRenderer extends WithDisposable(LitElement) { class="edgeless-container affine-edgeless-viewport" ${ref(this._editorContainer)} > - ${this.host.renderSpecPortal(this._doc, EdgelessEditorBlockSpecs)} + ${new BlockStdScope({ + doc: this._doc, + extensions: EdgelessEditorBlockSpecs, + }).render()}
`; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/messages/text.ts b/packages/frontend/core/src/blocksuite/presets/ai/messages/text.ts index 40dec4dc45..37aee626e0 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/messages/text.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/messages/text.ts @@ -1,7 +1,11 @@ -import { type EditorHost, WithDisposable } from '@blocksuite/block-std'; -import type { - AffineAIPanelState, - AffineAIPanelWidgetConfig, +import { + BlockStdScope, + type EditorHost, + WithDisposable, +} from '@blocksuite/block-std'; +import { + type AffineAIPanelState, + type AffineAIPanelWidgetConfig, } from '@blocksuite/blocks'; import { CodeBlockComponent, @@ -271,7 +275,10 @@ export class AIAnswerText extends WithDisposable(LitElement) { ${keyed( this._doc, html`
- ${this.host.renderSpecPortal(this._doc, CustomPageEditorBlockSpecs)} + ${new BlockStdScope({ + doc: this._doc, + extensions: CustomPageEditorBlockSpecs, + }).render()}
` )} diff --git a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts index 7cceab810a..27a4ee5037 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/peek-view/chat-block-peek-view.ts @@ -8,6 +8,7 @@ import { type AIError, CanvasElementType, ConnectorMode, + DocModeProvider, type EdgelessRootService, } from '@blocksuite/blocks'; import { @@ -37,11 +38,11 @@ export class AIChatBlockPeekView extends LitElement { static override styles = PeekViewStyles; private get _rootService() { - return this.host.spec.getService('affine:page'); + return this.host.std.getService('affine:page'); } private get _modeService() { - return this._rootService.docModeService; + return this.host.std.get(DocModeProvider); } private get parentSessionId() { diff --git a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts index 6acfba5282..26fc0dfe25 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/slides/index.ts @@ -12,7 +12,7 @@ import { } from './template'; export const PPTBuilder = (host: EditorHost) => { - const service = host.spec.getService('affine:page'); + const service = host.std.getService('affine:page'); const docs: PPTDoc[] = []; const contents: unknown[] = []; const allImages: TemplateImage[][] = []; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/custom-specs.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/custom-specs.ts index 2ea16c9842..f3a6d34ad3 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/custom-specs.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/custom-specs.ts @@ -1,3 +1,10 @@ +import { + BlockFlavourIdentifier, + BlockServiceIdentifier, + BlockViewIdentifier, + type ExtensionType, + StdIdentifier, +} from '@blocksuite/block-std'; import { PageEditorBlockSpecs, PageRootService } from '@blocksuite/blocks'; import { literal } from 'lit/static-html.js'; @@ -8,15 +15,19 @@ class CustomPageRootService extends PageRootService { override loadFonts() {} } -export const CustomPageEditorBlockSpecs = PageEditorBlockSpecs.map(spec => { - if (spec.schema.model.flavour === 'affine:page') { - return { - ...spec, - service: CustomPageRootService, - view: { - component: literal`affine-page-root`, - }, - }; - } - return spec; -}); +export const CustomPageEditorBlockSpecs: ExtensionType[] = [ + ...PageEditorBlockSpecs, + { + setup: di => { + di.override( + BlockServiceIdentifier('affine:page'), + CustomPageRootService, + [StdIdentifier, BlockFlavourIdentifier('affine:page')] + ); + di.override( + BlockViewIdentifier('affine:page'), + () => literal`affine-page-root` + ); + }, + }, +]; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts index 256b1ce7e6..2e8dc329b2 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/edgeless.ts @@ -40,7 +40,7 @@ export function isMindmapChild(ele: BlockSuite.EdgelessModel) { } export function getService(host: EditorHost) { - const edgelessService = host.spec.getService( + const edgelessService = host.std.getService( 'affine:page' ) as EdgelessRootService; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts index 59006d9545..8d6affbccf 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/selection-utils.ts @@ -18,7 +18,7 @@ import { getEdgelessCopilotWidget, getService } from './edgeless'; import { getContentFromSlice } from './markdown-utils'; export const getRootService = (host: EditorHost) => { - return host.std.spec.getService('affine:page'); + return host.std.getService('affine:page'); }; export function getEdgelessRootFromEditor(editor: EditorHost) { @@ -30,7 +30,7 @@ export function getEdgelessRootFromEditor(editor: EditorHost) { return edgelessRoot; } export function getEdgelessService(editor: EditorHost) { - const rootService = editor.std.spec.getService('affine:page'); + const rootService = editor.std.getService('affine:page'); if (rootService instanceof EdgelessRootService) { return rootService; } diff --git a/packages/frontend/core/src/bootstrap/first-app-data.ts b/packages/frontend/core/src/bootstrap/first-app-data.ts index 8ea7248e54..f0bddf356b 100644 --- a/packages/frontend/core/src/bootstrap/first-app-data.ts +++ b/packages/frontend/core/src/bootstrap/first-app-data.ts @@ -2,7 +2,7 @@ import { DebugLogger } from '@affine/debug'; import { DEFAULT_WORKSPACE_NAME } from '@affine/env/constant'; import { WorkspaceFlavour } from '@affine/env/workspace'; import onboardingUrl from '@affine/templates/onboarding.zip'; -import { ZipTransformer } from '@blocksuite/blocks'; +import { DocMode, ZipTransformer } from '@blocksuite/blocks'; import type { WorkspacesService } from '@toeverything/infra'; import { DocsService, initEmptyPage } from '@toeverything/infra'; @@ -31,7 +31,7 @@ export async function buildShowcaseWorkspace( ); if (defaultDoc) { - defaultDoc.setPrimaryMode('edgeless'); + defaultDoc.setPrimaryMode(DocMode.Edgeless); } dispose(); diff --git a/packages/frontend/core/src/commands/affine-creation.tsx b/packages/frontend/core/src/commands/affine-creation.tsx index 7e3ad99903..69d82498dc 100644 --- a/packages/frontend/core/src/commands/affine-creation.tsx +++ b/packages/frontend/core/src/commands/affine-creation.tsx @@ -1,4 +1,5 @@ import type { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { ImportIcon, PlusIcon } from '@blocksuite/icons/rc'; import type { usePageHelper } from '../components/blocksuite/block-suite-page-list/utils'; @@ -31,7 +32,7 @@ export function registerAffineCreationCommands({ run() { track.$.cmdk.creation.createDoc({ mode: 'page' }); - pageHelper.createPage('page'); + pageHelper.createPage('page' as DocMode); }, }) ); diff --git a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx index f939ca240b..6aa9cf04df 100644 --- a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx +++ b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx @@ -9,16 +9,12 @@ import { EditorService } from '@affine/core/modules/editor'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { i18nTime, Trans, useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { CloseIcon, ToggleCollapseIcon } from '@blocksuite/icons/rc'; import type { Doc as BlockSuiteDoc, DocCollection } from '@blocksuite/store'; import * as Collapsible from '@radix-ui/react-collapsible'; import type { DialogContentProps } from '@radix-ui/react-dialog'; -import { - type DocMode, - useLiveData, - useService, - WorkspaceService, -} from '@toeverything/infra'; +import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import { atom, useAtom, useSetAtom } from 'jotai'; import type { PropsWithChildren } from 'react'; import { diff --git a/packages/frontend/core/src/components/affine/reference-link/index.tsx b/packages/frontend/core/src/components/affine/reference-link/index.tsx index 8ccd70e49b..d3714327b4 100644 --- a/packages/frontend/core/src/components/affine/reference-link/index.tsx +++ b/packages/frontend/core/src/components/affine/reference-link/index.tsx @@ -6,23 +6,27 @@ import { } from '@affine/core/modules/peek-view'; import { WorkbenchLink } from '@affine/core/modules/workbench'; import { useI18n } from '@affine/i18n'; +import type { BlockStdScope } from '@blocksuite/block-std'; +import { DocMode } from '@blocksuite/blocks'; import { + BlockLinkIcon, DeleteIcon, LinkedEdgelessIcon, LinkedPageIcon, TodayIcon, } from '@blocksuite/icons/rc'; import type { DocCollection } from '@blocksuite/store'; +import { useService } from '@toeverything/infra'; import { - type DocMode, - DocsService, - LiveData, - useLiveData, - useService, -} from '@toeverything/infra'; -import { type PropsWithChildren, useCallback, useRef } from 'react'; + type PropsWithChildren, + useCallback, + useEffect, + useRef, + useState, +} from 'react'; import * as styles from './styles.css'; +import { scrollAnchoring } from './utils'; export interface PageReferenceRendererOptions { docMode: DocMode | null; @@ -31,6 +35,9 @@ export interface PageReferenceRendererOptions { pageMetaHelper: ReturnType; journalHelper: ReturnType; t: ReturnType; + // linking doc with block or element + blockIds?: string[]; + elementIds?: string[]; } // use a function to be rendered in the lit renderer export function pageReferenceRenderer({ @@ -39,30 +46,37 @@ export function pageReferenceRenderer({ pageMetaHelper, journalHelper, t, + blockIds, + elementIds, }: PageReferenceRendererOptions) { const { isPageJournal, getLocalizedJournalDateString } = journalHelper; const referencedPage = pageMetaHelper.getDocMeta(pageId); let title = referencedPage?.title ?? t['com.affine.editor.reference-not-found'](); - let icon = !referencedPage ? ( - - ) : docMode === 'page' || docMode === null ? ( - - ) : ( - - ); + let Icon = DeleteIcon; + + if (referencedPage) { + if (docMode === DocMode.Edgeless) { + Icon = LinkedEdgelessIcon; + } else { + Icon = LinkedPageIcon; + } + if (blockIds?.length || elementIds?.length) { + Icon = BlockLinkIcon; + } + } const isJournal = isPageJournal(pageId); const localizedJournalDate = getLocalizedJournalDateString(pageId); if (isJournal && localizedJournalDate) { title = localizedJournalDate; - icon = ; + Icon = TodayIcon; } return ( <> - {icon} + {title ? title : t['Untitled']()} @@ -74,32 +88,42 @@ export function AffinePageReference({ pageId, docCollection, wrapper: Wrapper, + mode = DocMode.Page, + params = {}, + isSameDoc = false, + std, }: { docCollection: DocCollection; pageId: string; wrapper?: React.ComponentType; + mode?: DocMode; + params?: { + mode?: DocMode; + blockIds?: string[]; + elementIds?: string[]; + }; + isSameDoc?: boolean; + std?: BlockStdScope; }) { const pageMetaHelper = useDocMetaHelper(docCollection); const journalHelper = useJournalHelper(docCollection); const t = useI18n(); + const [anchor, setAnchor] = useState<{ + mode: DocMode; + id: string; + } | null>(null); + + const { mode: linkedWithMode, blockIds, elementIds } = params; - const docsService = useService(DocsService); - const docPrimaryMode = useLiveData( - LiveData.computed(get => { - const primaryMode$ = get(docsService.list.doc$(pageId))?.primaryMode$; - if (!primaryMode$) { - return null; - } - return get(primaryMode$); - }) - ); const el = pageReferenceRenderer({ - docMode: docPrimaryMode, + docMode: linkedWithMode ?? mode, pageId, pageMetaHelper, journalHelper, docCollection, t, + blockIds, + elementIds, }); const ref = useRef(null); @@ -107,6 +131,18 @@ export function AffinePageReference({ const peekView = useService(PeekViewService).peekView; const isInPeekView = useInsidePeekView(); + useEffect(() => { + if (isSameDoc) { + if (mode === DocMode.Edgeless && elementIds?.length) { + setAnchor({ mode, id: elementIds[0] }); + } else if (blockIds?.length) { + setAnchor({ mode, id: blockIds[0] }); + } + } else { + setAnchor(null); + } + }, [std, isSameDoc, mode, blockIds, elementIds]); + const onClick = useCallback( (e: React.MouseEvent) => { if (e.shiftKey && ref.current) { @@ -114,18 +150,39 @@ export function AffinePageReference({ e.stopPropagation(); peekView.open(ref.current).catch(console.error); } - if (isInPeekView) { + + if (std && anchor) { + e.preventDefault(); + e.stopPropagation(); + const { mode, id } = anchor; + scrollAnchoring(std, mode, id); + } else if (isInPeekView) { peekView.close(); } + return; }, - [isInPeekView, peekView] + [isInPeekView, peekView, anchor, std] ); + // A block/element reference link + const search = new URLSearchParams(); + if (linkedWithMode) { + search.set('mode', linkedWithMode); + } + if (blockIds?.length) { + search.set('blockIds', blockIds.join(',')); + } + if (elementIds?.length) { + search.set('elementIds', elementIds.join(',')); + } + + const query = search.size > 0 ? `?${search.toString()}` : ''; + return ( diff --git a/packages/frontend/core/src/components/affine/reference-link/utils.ts b/packages/frontend/core/src/components/affine/reference-link/utils.ts new file mode 100644 index 0000000000..bf93ae3c41 --- /dev/null +++ b/packages/frontend/core/src/components/affine/reference-link/utils.ts @@ -0,0 +1,108 @@ +import type { BlockStdScope } from '@blocksuite/block-std'; +import { + DocMode, + type EdgelessRootService, + type PageRootService, +} from '@blocksuite/blocks'; +import { Bound, deserializeXYWH } from '@blocksuite/global/utils'; + +function scrollAnchoringInEdgelessMode( + service: EdgelessRootService, + id: string +) { + requestAnimationFrame(() => { + let isNotInNote = true; + let bounds: Bound | null = null; + + const blockComponent = service.std.view.getBlock(id); + + const parentComponent = blockComponent?.parentComponent; + if (parentComponent && parentComponent.flavour === 'affine:note') { + isNotInNote = false; + + const selection = parentComponent.std.selection; + if (!selection) return; + + selection.set([ + selection.create('block', { + blockId: id, + }), + ]); + + const { left: x, width: w } = parentComponent.getBoundingClientRect(); + const { top: y, height: h } = blockComponent.getBoundingClientRect(); + const coord = service.viewport.toModelCoordFromClientCoord([x, y]); + bounds = new Bound( + coord[0], + coord[1], + w / service.viewport.zoom, + h / service.viewport.zoom + ); + } else { + const model = service.getElementById(id); + if (!model) return; + + bounds = Bound.fromXYWH(deserializeXYWH(model.xywh)); + } + + if (!bounds) return; + + if (isNotInNote) { + service.selection.set({ + elements: [id], + editing: false, + }); + } + + const { zoom, centerX, centerY } = service.getFitToScreenData( + [20, 20, 20, 20], + [bounds] + ); + + service.viewport.setViewport(zoom, [centerX, centerY]); + + // const surfaceComponent = service.std.view.getBlock(service.surface.id); + // if (!surfaceComponent) return; + // (surfaceComponent as SurfaceBlockComponent).refresh(); + + // TODO(@fundon): toolbar should be hidden + }); +} + +function scrollAnchoringInPageMode(service: PageRootService, id: string) { + const blockComponent = service.std.view.getBlock(id); + if (!blockComponent || !blockComponent.path.length) return; + + blockComponent.scrollIntoView({ + behavior: 'instant', + block: 'center', + }); + + const selection = service.std.selection; + if (!selection) return; + + selection.set([ + selection.create('block', { + blockId: id, + }), + ]); + + // TODO(@fundon): toolbar should be hidden +} + +// TODO(@fundon): it should be a command +export function scrollAnchoring(std: BlockStdScope, mode: DocMode, id: string) { + if (mode === DocMode.Edgeless) { + const service = std.getService('affine:page'); + if (!service) return; + + scrollAnchoringInEdgelessMode(service, id); + + return; + } + + const service = std.getService('affine:page'); + if (!service) return; + + scrollAnchoringInPageMode(service, id); +} diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx index 0f199180dc..fa7c5fd6d5 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/editor/general.tsx @@ -23,8 +23,9 @@ import { SystemFontFamilyService, } from '@affine/core/modules/system-font-family'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { DoneIcon, SearchIcon } from '@blocksuite/icons/rc'; -import { type DocMode, useLiveData, useServices } from '@toeverything/infra'; +import { useLiveData, useServices } from '@toeverything/infra'; import clsx from 'clsx'; import { type ChangeEvent, diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx index 559b244342..2a388da344 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx @@ -12,6 +12,7 @@ import { ShareInfoService } from '@affine/core/modules/share-doc'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { PublicPageMode } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { BlockIcon, CollaborationIcon, @@ -158,10 +159,10 @@ export const AFFiNESharePage = (props: ShareMenuProps) => { }); const onCopyPageLink = useCallback(() => { - onClickCopyLink('page'); + onClickCopyLink('page' as DocMode); }, [onClickCopyLink]); const onCopyEdgelessLink = useCallback(() => { - onClickCopyLink('edgeless'); + onClickCopyLink('edgeless' as DocMode); }, [onClickCopyLink]); const onCopyBlockLink = useCallback(() => { // TODO(@JimmFly): handle frame diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/blocksuite-editor-container.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/blocksuite-editor-container.tsx index 2ed15c5a80..a637233b95 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/blocksuite-editor-container.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/blocksuite-editor-container.tsx @@ -1,15 +1,13 @@ -import type { BlockComponent } from '@blocksuite/block-std'; +import type { ReferenceInfo } from '@blocksuite/affine-model'; +import { DocMode } from '@blocksuite/blocks'; import type { AffineEditorContainer, EdgelessEditor, PageEditor, } from '@blocksuite/presets'; -import type { Doc } from '@blocksuite/store'; -import { Slot } from '@blocksuite/store'; -import { type DocMode } from '@toeverything/infra'; +import { type Doc, Slot } from '@blocksuite/store'; import clsx from 'clsx'; import type React from 'react'; -import type { RefObject } from 'react'; import { forwardRef, useEffect, @@ -19,6 +17,7 @@ import { useState, } from 'react'; +import { scrollAnchoring } from '../../affine/reference-link/utils'; import { BlocksuiteDocEditor, BlocksuiteEdgelessEditor } from './lit-adaper'; import * as styles from './styles.css'; @@ -43,7 +42,8 @@ interface BlocksuiteEditorContainerProps { shared?: boolean; className?: string; style?: React.CSSProperties; - defaultSelectedBlockId?: string; + blockIds?: string[]; + elementIds?: string[]; } // mimic the interface of the webcomponent and expose slots & host @@ -53,68 +53,36 @@ type BlocksuiteEditorContainerRef = Pick< > & HTMLDivElement; -function findBlockElementById(container: HTMLElement, blockId: string) { - const element = container.querySelector( - `[data-block-id="${blockId}"]` - ) as BlockComponent | null; - return element; -} - -// a workaround for returning the webcomponent for the given block id -// by iterating over the children of the rendered dom tree -const useBlockElementById = ( - containerRef: RefObject, - blockId: string | undefined, - timeout = 1000 -) => { - const [blockElement, setBlockElement] = useState(null); - useEffect(() => { - if (!blockId) { - return; - } - let canceled = false; - const start = Date.now(); - function run() { - if (canceled || !containerRef.current || !blockId) { - return; - } - const element = findBlockElementById(containerRef.current, blockId); - if (element) { - setBlockElement(element); - } else if (Date.now() - start < timeout) { - setTimeout(run, 100); - } - } - run(); - return () => { - canceled = true; - }; - }, [blockId, containerRef, timeout]); - return blockElement; -}; - export const BlocksuiteEditorContainer = forwardRef< AffineEditorContainer, BlocksuiteEditorContainerProps >(function AffineEditorContainer( - { page, mode, className, style, defaultSelectedBlockId, shared }, + { page, mode, className, style, shared, blockIds, elementIds }, ref ) { const scrolledRef = useRef(false); - const hashChangedRef = useRef(false); const rootRef = useRef(null); const docRef = useRef(null); const edgelessRef = useRef(null); + const [anchor, setAnchor] = useState(null); const slots: BlocksuiteEditorContainerRef['slots'] = useMemo(() => { return { - docLinkClicked: new Slot(), + docLinkClicked: new Slot(), editorModeSwitched: new Slot(), docUpdated: new Slot(), tagClicked: new Slot(), }; }, []); + useEffect(() => { + if (mode === DocMode.Edgeless && elementIds?.length) { + setAnchor(elementIds[0]); + } else if (blockIds?.length) { + setAnchor(blockIds[0]); + } + }, [blockIds, elementIds, mode]); + // forward the slot to the webcomponent useLayoutEffect(() => { requestAnimationFrame(() => { @@ -209,36 +177,22 @@ export const BlocksuiteEditorContainer = forwardRef< } }, [affineEditorContainerProxy, ref]); - const blockElement = useBlockElementById(rootRef, defaultSelectedBlockId); + // `scrolledRef` should be updated if blockElement is changed + useEffect(() => { + scrolledRef.current = false; + }, [anchor]); useEffect(() => { + if (!anchor) return; + let canceled = false; - const handleScrollToBlock = (blockElement: BlockComponent) => { - if (!mode || !blockElement) { - return; - } - blockElement.scrollIntoView({ - behavior: 'instant', - block: 'center', - }); - const selectManager = affineEditorContainerProxy.host?.selection; - if (!blockElement.path.length || !selectManager) { - return; - } - const newSelection = selectManager.create('block', { - blockId: blockElement.blockId, - }); - selectManager.set([newSelection]); - }; affineEditorContainerProxy.updateComplete .then(() => { - if ( - blockElement && - !scrolledRef.current && - !canceled && - !hashChangedRef.current - ) { - handleScrollToBlock(blockElement); + if (!scrolledRef.current && !canceled) { + const std = affineEditorContainerProxy.host?.std; + if (std) { + scrollAnchoring(std, mode, anchor); + } scrolledRef.current = true; } }) @@ -246,7 +200,7 @@ export const BlocksuiteEditorContainer = forwardRef< return () => { canceled = true; }; - }, [blockElement, affineEditorContainerProxy, mode]); + }, [anchor, affineEditorContainerProxy, mode]); return (
() => void; style?: CSSProperties; className?: string; + blockIds?: string[]; + elementIds?: string[]; }; function usePageRoot(page: Doc) { @@ -59,10 +61,11 @@ const BlockSuiteEditorImpl = forwardRef( mode, page, className, - defaultSelectedBlockId, onLoadEditor, shared, style, + blockIds, + elementIds, }, ref ) { @@ -113,7 +116,8 @@ const BlockSuiteEditorImpl = forwardRef( ref={onRefChange} className={className} style={style} - defaultSelectedBlockId={defaultSelectedBlockId} + blockIds={blockIds} + elementIds={elementIds} /> ); } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx index 076dbcdd3d..0f64f34733 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx @@ -7,7 +7,7 @@ import { useJournalInfoHelper } from '@affine/core/hooks/use-journal'; import { EditorSettingService } from '@affine/core/modules/editor-settting'; import { PeekViewService } from '@affine/core/modules/peek-view'; import { WorkbenchService } from '@affine/core/modules/workbench'; -import type { DocMode } from '@blocksuite/blocks'; +import { DocMode } from '@blocksuite/blocks'; import { DocTitle, EdgelessEditor, PageEditor } from '@blocksuite/presets'; import type { Doc } from '@blocksuite/store'; import { @@ -73,13 +73,26 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => { const framework = useFramework(); const referenceRenderer: ReferenceReactRenderer = useMemo(() => { return function customReference(reference) { - const pageId = reference.delta.attributes?.reference?.pageId; + const data = reference.delta.attributes?.reference; + if (!data) return ; + + const pageId = data.pageId; if (!pageId) return ; + + const isSameDoc = pageId === page.id; + return ( - + ); }; - }, [page.collection]); + }, [mode, page.collection, page.id]); const specs = useMemo(() => { return mode === 'edgeless' @@ -89,20 +102,19 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => { const confirmModal = useConfirmModal(); const patchedSpecs = useMemo(() => { - let patched = patchReferenceRenderer(specs, reactToLit, referenceRenderer); - patched = patchNotificationService( - patchReferenceRenderer(patched, reactToLit, referenceRenderer), - confirmModal + let patched = specs.concat( + patchReferenceRenderer(reactToLit, referenceRenderer) ); - patched = patchPeekViewService(patched, peekViewService); - patched = patchEdgelessClipboard(patched); + patched = patched.concat(patchNotificationService(confirmModal)); + patched = patched.concat(patchPeekViewService(peekViewService)); + patched = patched.concat(patchEdgelessClipboard()); if (!page.readonly) { - patched = patchQuickSearchService(patched, framework); + patched = patched.concat(patchQuickSearchService(framework)); } if (shared) { - patched = patchForSharedPage(patched); + patched = patched.concat(patchForSharedPage()); } - patched = patchDocModeService(patched, docService, docsService); + patched = patched.concat(patchDocModeService(docService, docsService)); return patched; }, [ confirmModal, @@ -179,7 +191,7 @@ export const BlocksuiteDocEditor = forwardRef< // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const [specs, portals] = usePatchSpecs(page, !!shared, 'page'); + const [specs, portals] = usePatchSpecs(page, !!shared, DocMode.Page); const settings = useLiveData(editorSettingService.editorSetting.settings$); @@ -219,7 +231,7 @@ export const BlocksuiteEdgelessEditor = forwardRef< EdgelessEditor, BlocksuiteEditorProps >(function BlocksuiteEdgelessEditor({ page, shared }, ref) { - const [specs, portals] = usePatchSpecs(page, !!shared, 'edgeless'); + const [specs, portals] = usePatchSpecs(page, !!shared, DocMode.Edgeless); const editorRef = useRef(null); const onDocRef = useCallback( diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/common.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/common.ts index c9eb3c67c2..22c81e0157 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/common.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/common.ts @@ -3,7 +3,7 @@ import { AIImageBlockSpec, AIParagraphBlockSpec, } from '@affine/core/blocksuite/presets/ai'; -import type { BlockSpec } from '@blocksuite/block-std'; +import type { ExtensionType } from '@blocksuite/block-std'; import { BookmarkBlockSpec, DatabaseBlockSpec, @@ -17,15 +17,12 @@ import { EmbedSyncedDocBlockSpec, EmbedYoutubeBlockSpec, ListBlockSpec, - NoteBlockSpec, } from '@blocksuite/blocks'; -import { AIChatBlockSpec, EdgelessAIChatBlockSpec } from '@blocksuite/presets'; import { CustomAttachmentBlockSpec } from './custom/attachment-block'; -export const CommonBlockSpecs: BlockSpec[] = [ +export const CommonBlockSpecs: ExtensionType[] = [ ListBlockSpec, - NoteBlockSpec, DatabaseBlockSpec, DataViewBlockSpec, DividerBlockSpec, @@ -42,6 +39,4 @@ export const CommonBlockSpecs: BlockSpec[] = [ AICodeBlockSpec, AIImageBlockSpec, AIParagraphBlockSpec, - AIChatBlockSpec, - EdgelessAIChatBlockSpec, -]; +].flat(); diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/attachment-block.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/attachment-block.ts index eb00c8889a..aa33403f02 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/attachment-block.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/attachment-block.ts @@ -1,4 +1,9 @@ -import type { BlockSpec } from '@blocksuite/block-std'; +import { + BlockFlavourIdentifier, + BlockServiceIdentifier, + type ExtensionType, + StdIdentifier, +} from '@blocksuite/block-std'; import { AttachmentBlockService, AttachmentBlockSpec, @@ -14,7 +19,15 @@ class CustomAttachmentBlockService extends AttachmentBlockService { } } -export const CustomAttachmentBlockSpec: BlockSpec = { +export const CustomAttachmentBlockSpec: ExtensionType[] = [ ...AttachmentBlockSpec, - service: CustomAttachmentBlockService, -}; + { + setup: di => { + di.override( + BlockServiceIdentifier('affine:attachment'), + CustomAttachmentBlockService, + [StdIdentifier, BlockFlavourIdentifier('affine:attachment')] + ); + }, + }, +]; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts index f346524ce9..fe1ddbd3f0 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/root-block.ts @@ -3,12 +3,14 @@ import { AIPageRootBlockSpec, } from '@affine/core/blocksuite/presets/ai'; import { mixpanel } from '@affine/core/mixpanel'; -import type { - EdgelessRootBlockSpecType, - PageRootBlockSpecType, - RootService, - TelemetryEventMap, -} from '@blocksuite/blocks'; +import { + BlockFlavourIdentifier, + BlockServiceIdentifier, + ConfigExtension, + type ExtensionType, + StdIdentifier, +} from '@blocksuite/block-std'; +import type { RootService, TelemetryEventMap } from '@blocksuite/blocks'; import { AffineCanvasTextFonts, EdgelessRootService, @@ -31,6 +33,7 @@ function customLoadFonts(service: RootService): void { } } +// TODO: make load fonts and telemetry service as BS extension function withAffineRootService(Service: typeof PageRootService) { return class extends Service { override loadFonts(): void { @@ -50,24 +53,40 @@ function withAffineRootService(Service: typeof PageRootService) { export function createPageRootBlockSpec( framework: FrameworkProvider -): PageRootBlockSpecType { - return { +): ExtensionType[] { + return [ ...AIPageRootBlockSpec, - service: withAffineRootService(PageRootService), - config: { - linkedWidget: createLinkedWidgetConfig(framework), + { + setup: di => { + di.override( + BlockServiceIdentifier('affine:page'), + withAffineRootService(PageRootService), + [StdIdentifier, BlockFlavourIdentifier('affine:page')] + ); + }, }, - }; + ConfigExtension('affine:page', { + linkedWidget: createLinkedWidgetConfig(framework), + }), + ]; } export function createEdgelessRootBlockSpec( framework: FrameworkProvider -): EdgelessRootBlockSpecType { - return { +): ExtensionType[] { + return [ ...AIEdgelessRootBlockSpec, - service: withAffineRootService(EdgelessRootService as never), - config: { - linkedWidget: createLinkedWidgetConfig(framework), + { + setup: di => { + di.override( + BlockServiceIdentifier('affine:page'), + withAffineRootService(EdgelessRootService as never), + [StdIdentifier, BlockFlavourIdentifier('affine:page')] + ); + }, }, - }; + ConfigExtension('affine:page', { + linkedWidget: createLinkedWidgetConfig(framework), + }), + ]; } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx index 2af9e9e273..f5c0d10cb2 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx @@ -20,20 +20,31 @@ import { RecentDocsQuickSearchSession, } from '@affine/core/modules/quicksearch'; import { DebugLogger } from '@affine/debug'; -import type { BlockSpec, WidgetComponent } from '@blocksuite/block-std'; import { - type AffineReference, + type BlockService, + BlockViewIdentifier, + type ExtensionType, + type WidgetComponent, +} from '@blocksuite/block-std'; +import { BlockServiceWatcher } from '@blocksuite/block-std'; +import type { + AffineReference, + DatabaseBlockService, + ListBlockService, + ParagraphBlockService, + RootService, +} from '@blocksuite/blocks'; +import { AffineSlashMenuWidget, + DocMode, + DocModeProvider, EdgelessRootBlockComponent, EmbedLinkedDocBlockComponent, - type ParagraphBlockService, - type RootService, } from '@blocksuite/blocks'; import { LinkIcon } from '@blocksuite/icons/rc'; import { AIChatBlockSchema } from '@blocksuite/presets'; import type { BlockSnapshot } from '@blocksuite/store'; import { - type DocMode, type DocService, DocsService, type FrameworkProvider, @@ -48,84 +59,62 @@ export type ReferenceReactRenderer = ( const logger = new DebugLogger('affine::spec-patchers'); -function patchSpecService( - spec: Spec, - onMounted: ( - service: Spec extends BlockSpec - ? BlockService - : never - ) => (() => void) | void, +function patchSpecService( + flavour: string, + onMounted: (service: Service) => (() => void) | void, onWidgetConnected?: (component: WidgetComponent) => void ) { - const oldSetup = spec.setup; - spec.setup = (slots, disposableGroup) => { - oldSetup?.(slots, disposableGroup); - disposableGroup.add( - slots.mounted.on(({ service }) => { - const disposable = onMounted(service as any); - if (disposable) { - disposableGroup.add(disposable); - } - }) - ); + class TempServiceWatcher extends BlockServiceWatcher { + static override readonly flavour = flavour; + override mounted() { + super.mounted(); + const disposable = onMounted(this.blockService as any); + const disposableGroup = this.blockService.disposables; + if (disposable) { + disposableGroup.add(disposable); + } - onWidgetConnected && - disposableGroup.add( - slots.widgetConnected.on(({ component }) => { - onWidgetConnected(component); - }) - ); - }; - return spec; + if (onWidgetConnected) { + disposableGroup.add( + this.blockService.specSlots.widgetConnected.on(({ component }) => { + onWidgetConnected(component); + }) + ); + } + } + } + return TempServiceWatcher; } /** * Patch the block specs with custom renderers. */ export function patchReferenceRenderer( - specs: BlockSpec[], reactToLit: (element: ElementOrFactory) => TemplateResult, reactRenderer: ReferenceReactRenderer -) { +): ExtensionType[] { const litRenderer = (reference: AffineReference) => { const node = reactRenderer(reference); return reactToLit(node); }; - return specs.map(spec => { - if ( - ['affine:paragraph', 'affine:list', 'affine:database'].includes( - spec.schema.model.flavour - ) - ) { - spec = patchSpecService( - spec as BlockSpec, - service => { - service.referenceNodeConfig.setCustomContent(litRenderer); - return () => { - service.referenceNodeConfig.setCustomContent(null); - }; - } - ); - } - - return spec; + return ['affine:paragraph', 'affine:list', 'affine:database'].map(flavour => { + return patchSpecService< + ParagraphBlockService | ListBlockService | DatabaseBlockService + >(flavour, service => { + service.referenceNodeConfig.setCustomContent(litRenderer); + return () => { + service.referenceNodeConfig.setCustomContent(null); + }; + }); }); } -export function patchNotificationService( - specs: BlockSpec[], - { closeConfirmModal, openConfirmModal }: ReturnType -) { - const rootSpec = specs.find( - spec => spec.schema.model.flavour === 'affine:page' - ) as BlockSpec; - - if (!rootSpec) { - return specs; - } - - patchSpecService(rootSpec, service => { +export function patchNotificationService({ + closeConfirmModal, + openConfirmModal, +}: ReturnType) { + return patchSpecService('affine:page', service => { service.notificationService = { confirm: async ({ title, message, confirmText, cancelText, abort }) => { return new Promise(resolve => { @@ -234,22 +223,10 @@ export function patchNotificationService( }, }; }); - return specs; } -export function patchPeekViewService( - specs: BlockSpec[], - service: PeekViewService -) { - const rootSpec = specs.find( - spec => spec.schema.model.flavour === 'affine:page' - ) as BlockSpec; - - if (!rootSpec) { - return specs; - } - - patchSpecService(rootSpec, pageService => { +export function patchPeekViewService(service: PeekViewService) { + return patchSpecService('affine:page', pageService => { pageService.peekViewService = { peek: (target: ActivePeekView['target'], template?: TemplateResult) => { logger.debug('center peek', target, template); @@ -257,75 +234,55 @@ export function patchPeekViewService( }, }; }); - - return specs; } export function patchDocModeService( - specs: BlockSpec[], docService: DocService, docsService: DocsService -) { - const rootSpec = specs.find( - spec => spec.schema.model.flavour === 'affine:page' - ) as BlockSpec; - - if (!rootSpec) { - return specs; +): ExtensionType { + const DEFAULT_MODE = 'page'; + class AffineDocModeService implements DocModeProvider { + setMode = (mode: DocMode, id?: string) => { + if (id) { + docsService.list.setPrimaryMode(id, mode); + } else { + docService.doc.setPrimaryMode(mode); + } + }; + getMode = (id?: string) => { + const mode = id + ? docsService.list.getPrimaryMode(id) + : docService.doc.getPrimaryMode(); + return (mode || DEFAULT_MODE) as DocMode; + }; + toggleMode = (id?: string) => { + const mode = id + ? docsService.list.togglePrimaryMode(id) + : docService.doc.togglePrimaryMode(); + return (mode || DEFAULT_MODE) as DocMode; + }; + onModeChange = (handler: (mode: DocMode) => void, id?: string) => { + // eslint-disable-next-line rxjs/finnish + const mode$ = id + ? docsService.list.primaryMode$(id) + : docService.doc.primaryMode$; + const sub = mode$.subscribe(m => handler((m || DEFAULT_MODE) as DocMode)); + return { + dispose: sub.unsubscribe, + }; + }; } - patchSpecService(rootSpec, pageService => { - const DEFAULT_MODE = 'page'; - pageService.docModeService = { - setMode: (mode: DocMode, id?: string) => { - if (id) { - docsService.list.setPrimaryMode(id, mode); - } else { - docService.doc.setPrimaryMode(mode); - } - }, - getMode: (id?: string) => { - const mode = id - ? docsService.list.getPrimaryMode(id) - : docService.doc.getPrimaryMode(); - return mode || DEFAULT_MODE; - }, - toggleMode: (id?: string) => { - const mode = id - ? docsService.list.togglePrimaryMode(id) - : docService.doc.togglePrimaryMode(); - return mode || DEFAULT_MODE; - }, - onModeChange: (handler: (mode: DocMode) => void, id?: string) => { - // eslint-disable-next-line rxjs/finnish - const mode$ = id - ? docsService.list.primaryMode$(id) - : docService.doc.primaryMode$; - const sub = mode$.subscribe(m => handler(m || DEFAULT_MODE)); - return { - dispose: sub.unsubscribe, - }; - }, - }; - }); + const docModeExtension: ExtensionType = { + setup: di => [di.override(DocModeProvider, AffineDocModeService)], + }; - return specs; + return docModeExtension; } -export function patchQuickSearchService( - specs: BlockSpec[], - framework: FrameworkProvider -) { - const rootSpec = specs.find( - spec => spec.schema.model.flavour === 'affine:page' - ) as BlockSpec; - - if (!rootSpec) { - return specs; - } - - patchSpecService( - rootSpec, +export function patchQuickSearchService(framework: FrameworkProvider) { + return patchSpecService( + 'affine:page', pageService => { pageService.quickSearchService = { async searchDoc(options) { @@ -409,8 +366,8 @@ export function patchQuickSearchService( const docsService = framework.get(DocsService); const mode = result.id === 'creation:create-edgeless' - ? 'edgeless' - : 'page'; + ? DocMode.Edgeless + : DocMode.Page; const newDoc = docsService.createDoc({ primaryMode: mode, title: result.payload.title, @@ -490,63 +447,56 @@ export function patchQuickSearchService( } } ); - - return specs; } -export function patchEdgelessClipboard(specs: BlockSpec[]) { - const rootSpec = specs.find( - spec => spec.schema.model.flavour === 'affine:page' - ) as BlockSpec; +export function patchEdgelessClipboard() { + class EdgelessClipboardWatcher extends BlockServiceWatcher { + static override readonly flavour = 'affine:page'; - if (!rootSpec) { - return specs; - } - - const oldSetup = rootSpec.setup; - rootSpec.setup = (slots, disposableGroup) => { - oldSetup?.(slots, disposableGroup); - disposableGroup.add( - slots.viewConnected.on(view => { - const component = view.component; - if (component instanceof EdgelessRootBlockComponent) { - const AIChatBlockFlavour = AIChatBlockSchema.model.flavour; - const createFunc = (blocks: BlockSnapshot[]) => { - const blockIds = blocks.map(({ props }) => { - const { - xywh, - scale, - messages, - sessionId, - rootDocId, - rootWorkspaceId, - } = props; - const blockId = component.service.addBlock( - AIChatBlockFlavour, - { + override mounted() { + super.mounted(); + this.blockService.disposables.add( + this.blockService.specSlots.viewConnected.on(view => { + const { component } = view; + if (component instanceof EdgelessRootBlockComponent) { + const AIChatBlockFlavour = AIChatBlockSchema.model.flavour; + const createFunc = (blocks: BlockSnapshot[]) => { + const blockIds = blocks.map(({ props }) => { + const { xywh, scale, messages, sessionId, rootDocId, rootWorkspaceId, - }, - component.surface.model.id - ); - return blockId; - }); - return blockIds; - }; - component.clipboardController.registerBlock( - AIChatBlockFlavour, - createFunc - ); - } - }) - ); - }; + } = props; + const blockId = component.service.addBlock( + AIChatBlockFlavour, + { + xywh, + scale, + messages, + sessionId, + rootDocId, + rootWorkspaceId, + }, + component.surface.model.id + ); + return blockId; + }); + return blockIds; + }; + component.clipboardController.registerBlock( + AIChatBlockFlavour, + createFunc + ); + } + }) + ); + } + } - return specs; + return EdgelessClipboardWatcher; } @customElement('affine-linked-doc-ref-block') @@ -557,22 +507,18 @@ export class LinkedDocBlockComponent extends EmbedLinkedDocBlockComponent { } } -export function patchForSharedPage(specs: BlockSpec[]) { - return specs.map(spec => { - const linkedDocNames = [ - 'affine:embed-linked-doc', - 'affine:embed-synced-doc', - ]; - - if (linkedDocNames.includes(spec.schema.model.flavour)) { - spec = { - ...spec, - view: { - component: literal`affine-linked-doc-ref-block`, - widgets: {}, - }, - }; - } - return spec; - }); +export function patchForSharedPage() { + const extension: ExtensionType = { + setup: di => { + di.override( + BlockViewIdentifier('affine:embed-linked-doc'), + () => literal`affine-linked-doc-ref-block` + ); + di.override( + BlockViewIdentifier('affine:embed-synced-doc'), + () => literal`affine-linked-doc-ref-block` + ); + }, + }; + return extension; } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/edgeless.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/edgeless.ts index 3e1d52f757..58dc933b2e 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/edgeless.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/edgeless.ts @@ -1,4 +1,4 @@ -import type { BlockSpec } from '@blocksuite/block-std'; +import type { ExtensionType } from '@blocksuite/block-std'; import { EdgelessNoteBlockSpec, EdgelessSurfaceBlockSpec, @@ -6,6 +6,7 @@ import { EdgelessTextBlockSpec, FrameBlockSpec, } from '@blocksuite/blocks'; +import { EdgelessAIChatBlockSpec } from '@blocksuite/presets'; import type { FrameworkProvider } from '@toeverything/infra'; import { CommonBlockSpecs } from './common'; @@ -13,7 +14,7 @@ import { createEdgelessRootBlockSpec } from './custom/root-block'; export function createEdgelessModeSpecs( framework: FrameworkProvider -): BlockSpec[] { +): ExtensionType[] { return [ ...CommonBlockSpecs, EdgelessSurfaceBlockSpec, @@ -21,7 +22,8 @@ export function createEdgelessModeSpecs( FrameBlockSpec, EdgelessTextBlockSpec, EdgelessNoteBlockSpec, + EdgelessAIChatBlockSpec, // special createEdgelessRootBlockSpec(framework), - ]; + ].flat(); } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/page.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/page.ts index 696cc1b3ee..4f9907badc 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/page.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/page.ts @@ -1,19 +1,25 @@ -import type { BlockSpec } from '@blocksuite/block-std'; +import type { ExtensionType } from '@blocksuite/block-std'; import { + NoteBlockSpec, PageSurfaceBlockSpec, PageSurfaceRefBlockSpec, } from '@blocksuite/blocks'; +import { AIChatBlockSpec } from '@blocksuite/presets'; import { type FrameworkProvider } from '@toeverything/infra'; import { CommonBlockSpecs } from './common'; import { createPageRootBlockSpec } from './custom/root-block'; -export function createPageModeSpecs(framework: FrameworkProvider): BlockSpec[] { +export function createPageModeSpecs( + framework: FrameworkProvider +): ExtensionType[] { return [ ...CommonBlockSpecs, PageSurfaceBlockSpec, PageSurfaceRefBlockSpec, + NoteBlockSpec, + AIChatBlockSpec, // special createPageRootBlockSpec(framework), - ]; + ].flat(); } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/preview.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/preview.ts index bec752a78f..222b2c491e 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/preview.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/preview.ts @@ -1,10 +1,10 @@ -import type { BlockSpec } from '@blocksuite/block-std'; +import type { ExtensionType } from '@blocksuite/block-std'; import { SpecProvider } from '@blocksuite/blocks'; -import { AIChatBlockSpec, EdgelessAIChatBlockSpec } from '@blocksuite/presets'; +import { EdgelessAIChatBlockSpec } from '@blocksuite/presets'; -const CustomSpecs: BlockSpec[] = [AIChatBlockSpec, EdgelessAIChatBlockSpec]; +const CustomSpecs: ExtensionType[] = [EdgelessAIChatBlockSpec].flat(); -function patchPreviewSpec(id: string, specs: BlockSpec[]) { +function patchPreviewSpec(id: string, specs: ExtensionType[]) { const specProvider = SpecProvider.getInstance(); specProvider.extendSpec(id, specs); } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts b/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts index a6614212e4..411c478bfc 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts @@ -14,7 +14,7 @@ export const usePresent = () => { // TODO(@catsjuice): use surfaceService subAtom const enterOrLeavePresentationMode = () => { - const edgelessRootService = editorHost.spec.getService( + const edgelessRootService = editorHost.std.getService( 'affine:page' ) as EdgelessRootService; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx index 9e2b0dd9a1..843f57432c 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx @@ -3,8 +3,9 @@ import { registerAffineCommand } from '@affine/core/commands'; import { track } from '@affine/core/mixpanel'; import { EditorService } from '@affine/core/modules/editor'; import { useI18n } from '@affine/i18n'; +import { DocMode } from '@blocksuite/blocks'; import { EdgelessIcon, PageIcon } from '@blocksuite/icons/rc'; -import { type DocMode, useLiveData, useService } from '@toeverything/infra'; +import { useLiveData, useService } from '@toeverything/infra'; import { useCallback, useEffect, useMemo } from 'react'; import { switchItem } from './style.css'; @@ -38,16 +39,16 @@ export const EditorModeSwitch = () => { const togglePage = useCallback(() => { if (currentMode === 'page' || isSharedMode || trash) return; - editor.setMode('page'); - editor.doc.setPrimaryMode('page'); + editor.setMode(DocMode.Page); + editor.doc.setPrimaryMode(DocMode.Page); toast(t['com.affine.toastMessage.pageMode']()); track.$.header.actions.switchPageMode({ mode: 'page' }); }, [currentMode, editor, isSharedMode, t, trash]); const toggleEdgeless = useCallback(() => { if (currentMode === 'edgeless' || isSharedMode || trash) return; - editor.setMode('edgeless'); - editor.doc.setPrimaryMode('edgeless'); + editor.setMode(DocMode.Edgeless); + editor.doc.setPrimaryMode(DocMode.Edgeless); toast(t['com.affine.toastMessage.edgelessMode']()); track.$.header.actions.switchPageMode({ mode: 'edgeless' }); }, [currentMode, editor, isSharedMode, t, trash]); @@ -78,7 +79,10 @@ export const EditorModeSwitch = () => { binding: 'Alt+KeyS', capture: true, }, - run: () => onModeChange(currentMode === 'edgeless' ? 'page' : 'edgeless'), + run: () => + onModeChange( + currentMode === 'edgeless' ? DocMode.Page : DocMode.Edgeless + ), }); }, [currentMode, isSharedMode, onModeChange, t, trash]); @@ -93,8 +97,8 @@ export const EditorModeSwitch = () => {
diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx index 1a8f2508e1..38bbf9988b 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx @@ -2,8 +2,8 @@ import { toast } from '@affine/component'; import { useDocCollectionHelper } from '@affine/core/hooks/use-block-suite-workspace-helper'; import { EditorSettingService } from '@affine/core/modules/editor-settting'; import { WorkbenchService } from '@affine/core/modules/workbench'; +import type { DocMode } from '@blocksuite/blocks'; import { - type DocMode, DocsService, initEmptyPage, useLiveData, @@ -29,7 +29,7 @@ export const usePageHelper = (docCollection: DocCollection) => { const page = createDoc(); initEmptyPage(page); const primaryMode = mode || settings.newDocDefaultMode; - docRecordList.doc$(page.id).value?.setPrimaryMode(primaryMode); + docRecordList.doc$(page.id).value?.setPrimaryMode(primaryMode as DocMode); if (open !== false) workbench.openDoc(page.id, { at: open === 'new-tab' ? 'new-tab' : 'active', @@ -41,7 +41,7 @@ export const usePageHelper = (docCollection: DocCollection) => { const createEdgelessAndOpen = useCallback( (open?: boolean | 'new-tab') => { - return createPageAndOpen('edgeless', open); + return createPageAndOpen('edgeless' as DocMode, open); }, [createPageAndOpen] ); diff --git a/packages/frontend/core/src/components/cloud/share-header-right-item/index.tsx b/packages/frontend/core/src/components/cloud/share-header-right-item/index.tsx index 68af19d881..4db381e371 100644 --- a/packages/frontend/core/src/components/cloud/share-header-right-item/index.tsx +++ b/packages/frontend/core/src/components/cloud/share-header-right-item/index.tsx @@ -1,5 +1,6 @@ import { AuthService } from '@affine/core/modules/cloud'; -import { type DocMode, useLiveData, useService } from '@toeverything/infra'; +import type { DocMode } from '@blocksuite/blocks'; +import { useLiveData, useService } from '@toeverything/infra'; import { PresentButton } from './present'; import { SignIn } from './sign-in'; diff --git a/packages/frontend/core/src/components/page-detail-editor.tsx b/packages/frontend/core/src/components/page-detail-editor.tsx index 612d0e2aef..fd152adbdc 100644 --- a/packages/frontend/core/src/components/page-detail-editor.tsx +++ b/packages/frontend/core/src/components/page-detail-editor.tsx @@ -1,15 +1,20 @@ import './page-detail-editor.css'; import { useDocCollectionPage } from '@affine/core/hooks/use-block-suite-workspace-page'; +import { ViewService } from '@affine/core/modules/workbench/services/view'; +import type { DocMode } from '@blocksuite/blocks'; import { DisposableGroup } from '@blocksuite/global/utils'; import type { AffineEditorContainer } from '@blocksuite/presets'; import type { Doc as BlockSuiteDoc, DocCollection } from '@blocksuite/store'; -import { type DocMode, useLiveData, useService } from '@toeverything/infra'; +import { + useLiveData, + useService, + useServiceOptional, +} from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; import clsx from 'clsx'; import type { CSSProperties } from 'react'; import { memo, Suspense, useCallback, useMemo } from 'react'; -import { useLocation } from 'react-router-dom'; import { EditorService } from '../modules/editor'; import { @@ -37,14 +42,27 @@ export interface PageDetailEditorProps { onLoad?: OnLoadEditor; } -function useRouterHash() { - return useLocation().hash.substring(1); -} - const PageDetailEditorMain = memo(function PageDetailEditorMain({ page, onLoad, }: PageDetailEditorProps & { page: BlockSuiteDoc }) { + const viewService = useServiceOptional(ViewService); + const params = useLiveData( + viewService?.view.queryString$<{ + mode?: string; + blockIds?: string[]; + elementIds?: string[]; + }>({ + // Cannot handle single id situation correctly: `blockIds=xxx` + arrayFormat: 'none', + types: { + mode: 'string', + blockIds: value => (value.length ? value.split(',') : []), + elementIds: value => (value.length ? value.split(',') : []), + }, + }) + ); + const editor = useService(EditorService).editor; const mode = useLiveData(editor.mode$); @@ -66,8 +84,6 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({ : fontStyle.value; }, [settings.customFontFamily, settings.fontFamily]); - const blockId = useRouterHash(); - const onLoadEditor = useCallback( (editor: AffineEditorContainer) => { // debug current detail editor @@ -106,7 +122,8 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({ mode={mode} page={page} shared={isSharedMode} - defaultSelectedBlockId={blockId} + blockIds={params?.blockIds} + elementIds={params?.elementIds} onLoadEditor={onLoadEditor} /> ); diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx index 1e7b04d7b8..3223c8e7d5 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx @@ -13,6 +13,7 @@ import { TagService } from '@affine/core/modules/tag'; import { isNewTabTrigger } from '@affine/core/utils'; import type { Collection } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { ArrowDownSmallIcon, SearchIcon, @@ -79,7 +80,7 @@ export const PageListHeader = () => { createEdgeless(isNewTabTrigger(e) ? 'new-tab' : true) } onCreatePage={e => - createPage('page', isNewTabTrigger(e) ? 'new-tab' : true) + createPage('page' as DocMode, isNewTabTrigger(e) ? 'new-tab' : true) } onCreateDoc={e => createPage(undefined, isNewTabTrigger(e) ? 'new-tab' : true) @@ -144,7 +145,10 @@ export const CollectionPageListHeader = ({ [openConfirmModal, t, createAndAddDocument] ); - const createPageModeDoc = useCallback(() => createPage('page'), [createPage]); + const createPageModeDoc = useCallback( + () => createPage('page' as DocMode), + [createPage] + ); const onCreateEdgeless = useCallback( () => onConfirmAddDocument(createEdgeless), diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index 9b7a2c6caf..7db22854e7 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -13,6 +13,7 @@ import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/service import { isNewTabTrigger } from '@affine/core/utils'; import { events } from '@affine/electron-api'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { AllDocsIcon, GithubIcon, @@ -110,7 +111,7 @@ export const RootAppSidebar = (): ReactElement => { const onClickNewPage = useAsyncCallback( async (e?: MouseEvent) => { const page = pageHelper.createPage( - settings.newDocDefaultMode, + settings.newDocDefaultMode as DocMode, isNewTabTrigger(e) ? 'new-tab' : true ); page.load(); diff --git a/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts b/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts index 12066322c8..143df51170 100644 --- a/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts +++ b/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts @@ -2,6 +2,7 @@ import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useDocMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta'; import { useDocCollectionHelper } from '@affine/core/hooks/use-block-suite-workspace-helper'; import { CollectionService } from '@affine/core/modules/collection'; +import type { DocMode } from '@blocksuite/blocks'; import { DocsService, useService } from '@toeverything/infra'; import { useCallback } from 'react'; import { applyUpdate, encodeStateAsUpdate } from 'yjs'; @@ -102,7 +103,7 @@ export function useBlockSuiteMetaHelper(docCollection: DocCollection) { pageRecordList .doc$(newPage.id) - .value?.setPrimaryMode(currentPagePrimaryMode || 'page'); + .value?.setPrimaryMode(currentPagePrimaryMode || ('page' as DocMode)); setDocTitle(newPage.id, newPageTitle); openPageAfterDuplication && openPage(docCollection.id, newPage.id); }, diff --git a/packages/frontend/core/src/hooks/affine/use-export-page.ts b/packages/frontend/core/src/hooks/affine/use-export-page.ts index 7d9e0da53e..8ffe666d76 100644 --- a/packages/frontend/core/src/hooks/affine/use-export-page.ts +++ b/packages/frontend/core/src/hooks/affine/use-export-page.ts @@ -36,7 +36,7 @@ async function exportHandler({ const editorRoot = document.querySelector('editor-host'); let pageService: PageRootService | null = null; if (editorRoot) { - pageService = editorRoot.spec.getService('affine:page'); + pageService = editorRoot.std.getService('affine:page'); } track.$.sharePanel.$.export({ type, diff --git a/packages/frontend/core/src/hooks/affine/use-is-shared-page.tsx b/packages/frontend/core/src/hooks/affine/use-is-shared-page.tsx index b1c0664531..d3488733d0 100644 --- a/packages/frontend/core/src/hooks/affine/use-is-shared-page.tsx +++ b/packages/frontend/core/src/hooks/affine/use-is-shared-page.tsx @@ -7,8 +7,9 @@ import { revokePublicPageMutation, } from '@affine/graphql'; import { type I18nKeys, useI18n } from '@affine/i18n'; +import { DocMode } from '@blocksuite/blocks'; import { SingleSelectSelectSolidIcon } from '@blocksuite/icons/rc'; -import type { DocMode, Workspace } from '@toeverything/infra'; +import { type Workspace } from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; import { useCallback, useMemo } from 'react'; @@ -85,7 +86,9 @@ export function useIsSharedPage( const isPageShared = !!publicPage; const currentShareMode: DocMode = - publicPage?.mode === PublicPageMode.Edgeless ? 'edgeless' : 'page'; + publicPage?.mode === PublicPageMode.Edgeless + ? DocMode.Edgeless + : DocMode.Page; return [isPageShared, currentShareMode]; }, [data?.workspace.publicPages, pageId]); @@ -210,7 +213,8 @@ export function usePublicPages(workspace: Workspace) { () => maybeData?.workspace.publicPages.map(i => ({ id: i.id, - mode: i.mode === PublicPageMode.Edgeless ? 'edgeless' : 'page', + mode: + i.mode === PublicPageMode.Edgeless ? DocMode.Edgeless : DocMode.Page, })) ?? [], [maybeData?.workspace.publicPages] ); diff --git a/packages/frontend/core/src/hooks/affine/use-share-url.ts b/packages/frontend/core/src/hooks/affine/use-share-url.ts index 9ed2b91a29..c7d35ac6ea 100644 --- a/packages/frontend/core/src/hooks/affine/use-share-url.ts +++ b/packages/frontend/core/src/hooks/affine/use-share-url.ts @@ -3,7 +3,7 @@ import { track } from '@affine/core/mixpanel'; import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch'; import { useI18n } from '@affine/i18n'; import type { BaseSelection } from '@blocksuite/block-std'; -import { type DocMode } from '@toeverything/infra'; +import type { DocMode } from '@blocksuite/blocks'; import { useCallback } from 'react'; import { useActiveBlocksuiteEditor } from '../use-block-suite-editor'; @@ -34,19 +34,18 @@ const generateUrl = ({ try { const url = new URL(`${baseUrl}/workspace/${workspaceId}/${pageId}`); + const search = url.searchParams; if (shareMode) { - url.searchParams.append('mode', shareMode); + search.append('mode', shareMode); } - // TODO(@JimmFly): use query string to handle blockIds if (blockIds && blockIds.length > 0) { - // hash is used to store blockIds - url.hash = blockIds.join(','); + search.append('blockIds', blockIds.join(',')); } if (elementIds && elementIds.length > 0) { - url.searchParams.append('element', elementIds.join(',')); + search.append('elementIds', elementIds.join(',')); } if (xywh) { - url.searchParams.append('xywh', xywh); + search.append('xywh', xywh); } return url.toString(); } catch { diff --git a/packages/frontend/core/src/hooks/use-navigate-helper.ts b/packages/frontend/core/src/hooks/use-navigate-helper.ts index c9c692f408..0cb4663e38 100644 --- a/packages/frontend/core/src/hooks/use-navigate-helper.ts +++ b/packages/frontend/core/src/hooks/use-navigate-helper.ts @@ -1,4 +1,5 @@ import type { WorkspaceSubPath } from '@affine/core/shared'; +import type { DocMode } from '@blocksuite/blocks'; import { createContext, useCallback, useContext, useMemo } from 'react'; import type { NavigateFunction, NavigateOptions } from 'react-router-dom'; @@ -40,10 +41,17 @@ export function useNavigateHelper() { ( workspaceId: string, pageId: string, - blockId: string, + mode?: DocMode, + blockIds?: string[], + elementIds?: string[], logic: RouteLogic = RouteLogic.PUSH ) => { - return navigate(`/workspace/${workspaceId}/${pageId}#${blockId}`, { + const search = new URLSearchParams(); + if (mode) search.append('mode', mode); + if (blockIds?.length) search.append('blockIds', blockIds.join(',')); + if (elementIds?.length) search.append('elementIds', elementIds.join(',')); + const query = search.size > 0 ? `?${search.toString()}` : ''; + return navigate(`/workspace/${workspaceId}/${pageId}${query}`, { replace: logic === RouteLogic.REPLACE, }); }, diff --git a/packages/frontend/core/src/layouts/workspace-layout.tsx b/packages/frontend/core/src/layouts/workspace-layout.tsx index 08db80f54a..dccad39806 100644 --- a/packages/frontend/core/src/layouts/workspace-layout.tsx +++ b/packages/frontend/core/src/layouts/workspace-layout.tsx @@ -4,9 +4,8 @@ import { resolveGlobalLoadingEventAtom, } from '@affine/component/global-loading'; import { useI18n } from '@affine/i18n'; -import { ZipTransformer } from '@blocksuite/blocks'; +import { type DocMode, ZipTransformer } from '@blocksuite/blocks'; import { - type DocMode, DocsService, effect, fromPromise, diff --git a/packages/frontend/core/src/modules/editor/entities/editor.ts b/packages/frontend/core/src/modules/editor/entities/editor.ts index 5feca7fafb..8521848cb8 100644 --- a/packages/frontend/core/src/modules/editor/entities/editor.ts +++ b/packages/frontend/core/src/modules/editor/entities/editor.ts @@ -1,4 +1,4 @@ -import type { DocMode } from '@blocksuite/blocks'; +import { DocMode } from '@blocksuite/blocks'; import type { AffineEditorContainer } from '@blocksuite/presets'; import type { DocService, WorkspaceService } from '@toeverything/infra'; import { Entity, LiveData } from '@toeverything/infra'; @@ -18,7 +18,9 @@ export class Editor extends Entity<{ defaultMode: DocMode }> { readonly editorContainer$ = new LiveData(null); toggleMode() { - this.mode$.next(this.mode$.value === 'edgeless' ? 'page' : 'edgeless'); + this.mode$.next( + this.mode$.value === 'edgeless' ? DocMode.Page : DocMode.Edgeless + ); } setMode(mode: DocMode) { diff --git a/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts b/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts index c8459202a5..489f15ef9e 100644 --- a/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts +++ b/packages/frontend/core/src/modules/navigation/__tests__/utils.spec.ts @@ -25,19 +25,19 @@ afterEach(() => { const testCases: [string, ReturnType][] = [ ['http://example.com/', null], [ - '/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx', + '/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', { workspaceId: '48__RTCSwASvWZxyAk3Jw', docId: '-Uge-K6SYcAbcNYfQ5U-j', - blockId: 'xxxx', + blockIds: ['xxxx'], }, ], [ - 'http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx', + 'http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', { workspaceId: '48__RTCSwASvWZxyAk3Jw', docId: '-Uge-K6SYcAbcNYfQ5U-j', - blockId: 'xxxx', + blockIds: ['xxxx'], }, ], ['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/all', null], @@ -45,19 +45,19 @@ const testCases: [string, ReturnType][] = [ ['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/tag', null], ['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/trash', null], [ - 'file//./workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx', + 'file//./workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', { workspaceId: '48__RTCSwASvWZxyAk3Jw', docId: '-Uge-K6SYcAbcNYfQ5U-j', - blockId: 'xxxx', + blockIds: ['xxxx'], }, ], [ - 'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx', + 'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx', { workspaceId: '48__RTCSwASvWZxyAk3Jw', docId: '-Uge-K6SYcAbcNYfQ5U-j', - blockId: 'xxxx', + blockIds: ['xxxx'], }, ], ]; diff --git a/packages/frontend/core/src/modules/navigation/utils.ts b/packages/frontend/core/src/modules/navigation/utils.ts index 8a434be8cc..858a010c54 100644 --- a/packages/frontend/core/src/modules/navigation/utils.ts +++ b/packages/frontend/core/src/modules/navigation/utils.ts @@ -1,3 +1,6 @@ +import type { DocMode } from '@blocksuite/blocks'; +import queryString from 'query-string'; + function maybeAffineOrigin(origin: string) { return ( origin.startsWith('file://') || @@ -73,9 +76,23 @@ const isRouteModulePath = ( export const resolveLinkToDoc = (href: string) => { const meta = resolveRouteLinkMeta(href); if (!meta || meta.moduleName !== 'doc') return null; + + const params: { + mode?: DocMode; + blockIds?: string[]; + elementIds?: string[]; + } = queryString.parse(meta.location.search, { + arrayFormat: 'none', + types: { + mode: value => (value === 'edgeless' ? 'edgeless' : 'page') as DocMode, + blockIds: value => value.split(','), + elementIds: value => value.split(','), + }, + }); + return { workspaceId: meta.workspaceId, docId: meta.docId, - blockId: meta.blockId, + ...params, }; }; diff --git a/packages/frontend/core/src/modules/peek-view/entities/peek-view.ts b/packages/frontend/core/src/modules/peek-view/entities/peek-view.ts index 1d1d5af5d2..9f0f261736 100644 --- a/packages/frontend/core/src/modules/peek-view/entities/peek-view.ts +++ b/packages/frontend/core/src/modules/peek-view/entities/peek-view.ts @@ -1,6 +1,7 @@ import type { BlockComponent, EditorHost } from '@blocksuite/block-std'; import { AffineReference, + type DocMode, type EmbedLinkedDocModel, type EmbedSyncedDocModel, type ImageBlockModel, @@ -9,7 +10,7 @@ import { } from '@blocksuite/blocks'; import type { AIChatBlockModel } from '@blocksuite/presets'; import type { BlockModel } from '@blocksuite/store'; -import { type DocMode, Entity, LiveData } from '@toeverything/infra'; +import { Entity, LiveData } from '@toeverything/infra'; import type { TemplateResult } from 'lit'; import { firstValueFrom, map, race } from 'rxjs'; @@ -21,20 +22,21 @@ export type PeekViewTarget = | BlockComponent | AffineReference | HTMLAnchorElement - | { docId: string; blockId?: string }; + | { docId: string; blockIds?: string[] }; export interface DocPeekViewInfo { type: 'doc'; docId: string; - blockId?: string; mode?: DocMode; + blockIds?: string[]; + elementIds?: string[]; xywh?: `[${number},${number},${number},${number}]`; } export type ImagePeekViewInfo = { type: 'image'; docId: string; - blockId: string; + blockIds: [string]; }; export type AIChatBlockPeekViewInfo = { @@ -58,15 +60,16 @@ export type ActivePeekView = { | AIChatBlockPeekViewInfo; }; -const EMBED_DOC_FLAVOURS = [ - 'affine:embed-linked-doc', - 'affine:embed-synced-doc', -]; - -const isEmbedDocModel = ( +const isEmbedLinkedDocModel = ( blockModel: BlockModel -): blockModel is EmbedSyncedDocModel | EmbedLinkedDocModel => { - return EMBED_DOC_FLAVOURS.includes(blockModel.flavour); +): blockModel is EmbedLinkedDocModel => { + return blockModel.flavour === 'affine:embed-linked-doc'; +}; + +const isEmbedSyncedDocModel = ( + blockModel: BlockModel +): blockModel is EmbedSyncedDocModel => { + return blockModel.flavour === 'affine:embed-synced-doc'; }; const isImageBlockModel = ( @@ -99,15 +102,26 @@ function resolvePeekInfoFromPeekTarget( } if (peekTarget instanceof AffineReference) { - if (peekTarget.refMeta) { - return { + const referenceInfo = peekTarget.referenceInfo; + if (referenceInfo) { + const { pageId: docId } = referenceInfo; + const info: DocPeekViewInfo = { type: 'doc', - docId: peekTarget.refMeta.id, + docId, }; + Object.assign(info, referenceInfo.params); + return info; } } else if ('model' in peekTarget) { const blockModel = peekTarget.model; - if (isEmbedDocModel(blockModel)) { + if (isEmbedLinkedDocModel(blockModel)) { + const info: DocPeekViewInfo = { + type: 'doc', + docId: blockModel.pageId, + }; + Object.assign(info, blockModel.params); + return info; + } else if (isEmbedSyncedDocModel(blockModel)) { return { type: 'doc', docId: blockModel.pageId, @@ -121,7 +135,7 @@ function resolvePeekInfoFromPeekTarget( return { type: 'doc', docId, - mode: 'edgeless', + mode: 'edgeless' as DocMode, xywh: refModel.xywh, }; } @@ -129,7 +143,7 @@ function resolvePeekInfoFromPeekTarget( return { type: 'image', docId: blockModel.doc.id, - blockId: blockModel.id, + blockIds: [blockModel.id], }; } else if (isAIChatBlockModel(blockModel)) { return { @@ -142,17 +156,28 @@ function resolvePeekInfoFromPeekTarget( } else if (peekTarget instanceof HTMLAnchorElement) { const maybeDoc = resolveLinkToDoc(peekTarget.href); if (maybeDoc) { - return { + const info: DocPeekViewInfo = { type: 'doc', docId: maybeDoc.docId, - blockId: maybeDoc.blockId, }; + + if (maybeDoc.mode) { + info.mode = maybeDoc.mode; + } + if (maybeDoc.blockIds?.length) { + info.blockIds = maybeDoc.blockIds; + } + if (maybeDoc.elementIds?.length) { + info.elementIds = maybeDoc.elementIds; + } + + return info; } } else if ('docId' in peekTarget) { return { type: 'doc', docId: peekTarget.docId, - blockId: peekTarget.blockId, + blockIds: peekTarget.blockIds, }; } return; diff --git a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx index 36fb67150e..589c494f7d 100644 --- a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx @@ -7,10 +7,9 @@ import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline- import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { PageNotFound } from '@affine/core/pages/404'; import { DebugLogger } from '@affine/debug'; -import { type EdgelessRootService } from '@blocksuite/blocks'; +import { DocMode, type EdgelessRootService } from '@blocksuite/blocks'; import { Bound, DisposableGroup } from '@blocksuite/global/utils'; import type { AffineEditorContainer } from '@blocksuite/presets'; -import type { DocMode } from '@toeverything/infra'; import { DocsService, FrameworkScope, useService } from '@toeverything/infra'; import clsx from 'clsx'; import { useCallback, useEffect, useState } from 'react'; @@ -32,7 +31,7 @@ function fitViewport( } const rootService = - editor.host.std.spec.getService('affine:page'); + editor.host.std.getService('affine:page'); rootService.viewport.onResize(); if (xywh) { @@ -60,12 +59,14 @@ function fitViewport( export function DocPeekPreview({ docId, - blockId, + blockIds, + elementIds, mode, xywh, }: { docId: string; - blockId?: string; + blockIds?: string[]; + elementIds?: string[]; mode?: DocMode; xywh?: `[${number},${number},${number},${number}]`; }) { @@ -97,7 +98,7 @@ export function DocPeekPreview({ useEffect(() => { if (!mode || !resolvedMode) { setResolvedMode( - docs.list.doc$(docId).value?.primaryMode$.value || 'page' + docs.list.doc$(docId).value?.primaryMode$.value || DocMode.Page ); } }, [docId, docs.list, resolvedMode, mode]); @@ -125,12 +126,17 @@ export function DocPeekPreview({ return; } - const rootService = - editorElement.host.std.spec.getService('affine:page'); + const rootService = editorElement.host.std.getService('affine:page'); // doc change event inside peek view should be handled by peek view disposableGroup.add( - rootService.slots.docLinkClicked.on(({ docId, blockId }) => { - peekView.open({ docId, blockId }).catch(console.error); + rootService.slots.docLinkClicked.on(options => { + peekView + .open({ + type: 'doc', + docId: options.pageId, + ...options.params, + }) + .catch(console.error); }) ); // TODO(@Peng): no tag peek view yet @@ -175,7 +181,8 @@ export function DocPeekPreview({ ref={onRef} className={styles.editor} mode={resolvedMode} - defaultSelectedBlockId={blockId} + blockIds={blockIds} + elementIds={elementIds} page={doc.blockSuiteDoc} /> diff --git a/packages/frontend/core/src/modules/peek-view/view/peek-view-controls.tsx b/packages/frontend/core/src/modules/peek-view/view/peek-view-controls.tsx index 33cf2dc412..3bf057f5b7 100644 --- a/packages/frontend/core/src/modules/peek-view/view/peek-view-controls.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/peek-view-controls.tsx @@ -1,12 +1,13 @@ import { IconButton } from '@affine/component'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { CloseIcon, ExpandFullIcon, OpenInNewIcon, SplitViewIcon, } from '@blocksuite/icons/rc'; -import { type DocMode, useService } from '@toeverything/infra'; +import { useService } from '@toeverything/infra'; import { clsx } from 'clsx'; import { type HTMLAttributes, diff --git a/packages/frontend/core/src/modules/peek-view/view/peek-view-manager.tsx b/packages/frontend/core/src/modules/peek-view/view/peek-view-manager.tsx index d9c3690890..febfbae8e4 100644 --- a/packages/frontend/core/src/modules/peek-view/view/peek-view-manager.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/peek-view-manager.tsx @@ -27,13 +27,16 @@ function renderPeekView({ info }: ActivePeekView) { mode={info.mode} xywh={info.xywh} docId={info.docId} - blockId={info.blockId} + blockIds={info.blockIds} + elementIds={info.elementIds} /> ); } if (info.type === 'image') { - return ; + return ( + + ); } if (info.type === 'ai-chat-block') { diff --git a/packages/frontend/core/src/modules/peek-view/view/utils.ts b/packages/frontend/core/src/modules/peek-view/view/utils.ts index d88e17d130..ec8f50a961 100644 --- a/packages/frontend/core/src/modules/peek-view/view/utils.ts +++ b/packages/frontend/core/src/modules/peek-view/view/utils.ts @@ -1,4 +1,5 @@ -import type { Doc, DocMode } from '@toeverything/infra'; +import type { DocMode } from '@blocksuite/blocks'; +import type { Doc } from '@toeverything/infra'; import { DocsService, useLiveData, diff --git a/packages/frontend/core/src/modules/quicksearch/impls/commands.ts b/packages/frontend/core/src/modules/quicksearch/impls/commands.ts index 57741827c0..d0f540d88d 100644 --- a/packages/frontend/core/src/modules/quicksearch/impls/commands.ts +++ b/packages/frontend/core/src/modules/quicksearch/impls/commands.ts @@ -4,7 +4,8 @@ import { type CommandCategory, PreconditionStrategy, } from '@affine/core/commands'; -import type { DocMode, GlobalContextService } from '@toeverything/infra'; +import type { DocMode } from '@blocksuite/blocks'; +import type { GlobalContextService } from '@toeverything/infra'; import { Entity, LiveData } from '@toeverything/infra'; import Fuse from 'fuse.js'; diff --git a/packages/frontend/core/src/modules/quicksearch/impls/creation.ts b/packages/frontend/core/src/modules/quicksearch/impls/creation.ts index 47e305e2a2..8f6dca5e6d 100644 --- a/packages/frontend/core/src/modules/quicksearch/impls/creation.ts +++ b/packages/frontend/core/src/modules/quicksearch/impls/creation.ts @@ -1,5 +1,6 @@ +import type { DocMode } from '@blocksuite/blocks'; import { EdgelessIcon, PageIcon } from '@blocksuite/icons/rc'; -import { type DocMode, Entity, LiveData } from '@toeverything/infra'; +import { Entity, LiveData } from '@toeverything/infra'; import type { QuickSearchSession } from '../providers/quick-search-provider'; import type { QuickSearchGroup } from '../types/group'; diff --git a/packages/frontend/core/src/modules/quicksearch/impls/docs.ts b/packages/frontend/core/src/modules/quicksearch/impls/docs.ts index 552b34897b..4f0bce51e6 100644 --- a/packages/frontend/core/src/modules/quicksearch/impls/docs.ts +++ b/packages/frontend/core/src/modules/quicksearch/impls/docs.ts @@ -66,7 +66,7 @@ export class DocsQuickSearchSession { docId: resolvedDoc.docId, score: 100, - blockId: resolvedDoc.blockId, + blockId: resolvedDoc.blockIds?.[0], blockContent: '', }, ...docs, diff --git a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts index 973bc608a3..9b57023617 100644 --- a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts +++ b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts @@ -1,4 +1,5 @@ import { track } from '@affine/core/mixpanel'; +import { DocMode } from '@blocksuite/blocks'; import type { DocsService } from '@toeverything/infra'; import { Service } from '@toeverything/infra'; @@ -67,13 +68,13 @@ export class CMDKQuickSearchService extends Service { } else if (result.source === 'creation') { if (result.id === 'creation:create-page') { const newDoc = this.docsService.createDoc({ - primaryMode: 'page', + primaryMode: DocMode.Page, title: result.payload.title, }); this.workbenchService.workbench.openDoc(newDoc.id); } else if (result.id === 'creation:create-edgeless') { const newDoc = this.docsService.createDoc({ - primaryMode: 'edgeless', + primaryMode: DocMode.Edgeless, title: result.payload.title, }); this.workbenchService.workbench.openDoc(newDoc.id); diff --git a/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts b/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts index 543bd13d90..5b16b07f77 100644 --- a/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts +++ b/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts @@ -1,6 +1,6 @@ import { UserFriendlyError } from '@affine/graphql'; +import type { DocMode } from '@blocksuite/blocks'; import { - type DocMode, effect, Entity, fromPromise, diff --git a/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts b/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts index 0f6397e34e..60132e7978 100644 --- a/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts +++ b/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts @@ -1,5 +1,6 @@ import { ErrorNames, UserFriendlyError } from '@affine/graphql'; -import { type DocMode, Store } from '@toeverything/infra'; +import type { DocMode } from '@blocksuite/blocks'; +import { Store } from '@toeverything/infra'; import { type FetchService, isBackendError } from '../../cloud'; diff --git a/packages/frontend/core/src/modules/workbench/entities/view.ts b/packages/frontend/core/src/modules/workbench/entities/view.ts index a0c04e3639..97a597f81d 100644 --- a/packages/frontend/core/src/modules/workbench/entities/view.ts +++ b/packages/frontend/core/src/modules/workbench/entities/view.ts @@ -1,6 +1,7 @@ import { Entity, LiveData } from '@toeverything/infra'; import type { Location, To } from 'history'; import { isEqual } from 'lodash-es'; +import type { ParseOptions } from 'query-string'; import queryString from 'query-string'; import { Observable } from 'rxjs'; @@ -79,15 +80,14 @@ export class View extends Entity<{ icon$ = new LiveData(this.props.icon ?? 'allDocs'); - queryString$>({ - parseNumbers = true, - }: { parseNumbers?: boolean } = {}) { + queryString$>( + options: ParseOptions = { + parseNumbers: true, + parseBooleans: true, + } + ) { return this.location$.map( - location => - queryString.parse(location.search, { - parseBooleans: true, - parseNumbers: parseNumbers, - }) as Partial + location => queryString.parse(location.search, options) as Partial ); } diff --git a/packages/frontend/core/src/modules/workbench/entities/workbench.ts b/packages/frontend/core/src/modules/workbench/entities/workbench.ts index 8c2c277bef..cdbad82a43 100644 --- a/packages/frontend/core/src/modules/workbench/entities/workbench.ts +++ b/packages/frontend/core/src/modules/workbench/entities/workbench.ts @@ -128,9 +128,15 @@ export class Workbench extends Entity { const docId = typeof id === 'string' ? id : id.docId; const blockId = typeof id === 'string' ? undefined : id.blockId; const mode = typeof id === 'string' ? undefined : id.mode; - const hash = blockId ? `#${blockId}` : ''; - const query = mode ? `?mode=${mode}` : ''; - this.open(`/${docId}${query}${hash}`, options); + let query = ''; + if (mode || blockId) { + const search = new URLSearchParams(); + if (mode) search.set('mode', mode); + if (blockId) search.set('blockIds', blockId); + query = `?${search.toString()}`; + } + + this.open(`/${docId}${query}`, options); } openCollections(options?: WorkbenchOpenOptions) { diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx index f7d4c55477..9765847385 100644 --- a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx @@ -10,6 +10,7 @@ import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { track } from '@affine/core/mixpanel'; import { isNewTabTrigger } from '@affine/core/utils'; import type { Filter } from '@affine/env/filter'; +import { DocMode } from '@blocksuite/blocks'; import { PlusIcon } from '@blocksuite/icons/rc'; import { useServices, WorkspaceService } from '@toeverything/infra'; import clsx from 'clsx'; @@ -67,7 +68,7 @@ export const AllPageHeader = ({ createEdgeless(isNewTabTrigger(e) ? 'new-tab' : true) } onCreatePage={e => - createPage('page', isNewTabTrigger(e) ? 'new-tab' : true) + createPage(DocMode.Page, isNewTabTrigger(e) ? 'new-tab' : true) } onCreateDoc={e => createPage(undefined, isNewTabTrigger(e) ? 'new-tab' : true) diff --git a/packages/frontend/core/src/pages/workspace/detail-page/detail-page-wrapper.tsx b/packages/frontend/core/src/pages/workspace/detail-page/detail-page-wrapper.tsx index c98f3f9ae6..917aa02014 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/detail-page-wrapper.tsx +++ b/packages/frontend/core/src/pages/workspace/detail-page/detail-page-wrapper.tsx @@ -63,7 +63,9 @@ const useLoadDoc = (pageId: string) => { } const editor = doc.scope .get(EditorsService) - .createEditor(initialQueryStringMode || doc.getPrimaryMode() || 'page'); + .createEditor( + initialQueryStringMode || doc.getPrimaryMode() || ('page' as DocMode) + ); setEditor(editor); return () => { editor.dispose(); diff --git a/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx b/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx index a35326e778..d176294a06 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx +++ b/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx @@ -210,14 +210,23 @@ const DetailPageImpl = memo(function DetailPageImpl() { // provide page mode and updated date to blocksuite const pageService = - editorHost?.std.spec.getService('affine:page'); + editorHost?.std.getService('affine:page'); const disposable = new DisposableGroup(); if (pageService) { disposable.add( - pageService.slots.docLinkClicked.on(({ docId, blockId }) => { - return blockId - ? jumpToPageBlock(docCollection.id, docId, blockId) - : openPage(docCollection.id, docId); + pageService.slots.docLinkClicked.on(({ pageId, params }) => { + if (params) { + const { mode, blockIds, elementIds } = params; + return jumpToPageBlock( + docCollection.id, + pageId, + mode, + blockIds, + elementIds + ); + } + + return openPage(docCollection.id, pageId); }) ); disposable.add( diff --git a/packages/frontend/core/src/pages/workspace/detail-page/tabs/chat.tsx b/packages/frontend/core/src/pages/workspace/detail-page/tabs/chat.tsx index 155cb2a82b..ad775b4ea2 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/tabs/chat.tsx +++ b/packages/frontend/core/src/pages/workspace/detail-page/tabs/chat.tsx @@ -1,4 +1,5 @@ import { ChatPanel } from '@affine/core/blocksuite/presets/ai'; +import { DocModeProvider } from '@blocksuite/blocks'; import { assertExists } from '@blocksuite/global/utils'; import type { AffineEditorContainer } from '@blocksuite/presets'; import { forwardRef, useCallback, useEffect, useRef } from 'react'; @@ -42,14 +43,16 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( useEffect(() => { if (!editor) return; - const pageService = editor.host?.spec.getService('affine:page'); + const pageService = editor.host?.std.getService('affine:page'); if (!pageService) return; + const docModeService = editor.host?.std.get(DocModeProvider); + if (!docModeService) return; const disposable = [ pageService.slots.docLinkClicked.on(() => { (chatPanelRef.current as ChatPanel).doc = editor.doc; }), - pageService.docModeService.onModeChange(() => { + docModeService.onModeChange(() => { if (!editor.host) return; (chatPanelRef.current as ChatPanel).host = editor.host; }), diff --git a/packages/frontend/core/src/pages/workspace/share/share-header.tsx b/packages/frontend/core/src/pages/workspace/share/share-header.tsx index 7782f36316..124d3c906c 100644 --- a/packages/frontend/core/src/pages/workspace/share/share-header.tsx +++ b/packages/frontend/core/src/pages/workspace/share/share-header.tsx @@ -2,8 +2,8 @@ import { BlocksuiteHeaderTitle } from '@affine/core/components/blocksuite/block- import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch'; import ShareHeaderRightItem from '@affine/core/components/cloud/share-header-right-item'; import { AuthModal } from '@affine/core/providers/modal-provider'; +import type { DocMode } from '@blocksuite/blocks'; import type { DocCollection } from '@blocksuite/store'; -import type { DocMode } from '@toeverything/infra'; import * as styles from './share-header.css'; diff --git a/packages/frontend/core/src/pages/workspace/share/share-page.tsx b/packages/frontend/core/src/pages/workspace/share/share-page.tsx index 2ae29632a7..6a6ea6f583 100644 --- a/packages/frontend/core/src/pages/workspace/share/share-page.tsx +++ b/packages/frontend/core/src/pages/workspace/share/share-page.tsx @@ -12,11 +12,12 @@ import { ShareReaderService } from '@affine/core/modules/share-doc'; import { CloudBlobStorage } from '@affine/core/modules/workspace-engine'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/blocks'; import { noop } from '@blocksuite/global/utils'; import { Logo1Icon } from '@blocksuite/icons/rc'; import type { AffineEditorContainer } from '@blocksuite/presets'; import type { Doc as BlockSuiteDoc } from '@blocksuite/store'; -import type { Doc, DocMode, Workspace } from '@toeverything/infra'; +import type { Doc, Workspace } from '@toeverything/infra'; import { DocsService, EmptyBlobStorage, @@ -96,7 +97,7 @@ const SharePageInner = ({ docId, workspaceBinary, docBinary, - publishMode = 'page', + publishMode = 'page' as DocMode, }: { workspaceId: string; docId: string; diff --git a/packages/frontend/electron/package.json b/packages/frontend/electron/package.json index a097a1c61d..f8bdb25c94 100644 --- a/packages/frontend/electron/package.json +++ b/packages/frontend/electron/package.json @@ -29,10 +29,10 @@ "@affine/env": "workspace:*", "@affine/i18n": "workspace:*", "@affine/native": "workspace:*", - "@blocksuite/block-std": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/blocks": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", - "@blocksuite/store": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/block-std": "0.0.0-canary-20240902070217", + "@blocksuite/blocks": "0.0.0-canary-20240902070217", + "@blocksuite/presets": "0.0.0-canary-20240902070217", + "@blocksuite/store": "0.0.0-canary-20240902070217", "@electron-forge/cli": "^7.3.0", "@electron-forge/core": "^7.3.0", "@electron-forge/core-utils": "^7.3.0", diff --git a/packages/frontend/mobile/src/pages/workspace/detail/mobile-detail-page.tsx b/packages/frontend/mobile/src/pages/workspace/detail/mobile-detail-page.tsx index de23e21331..15e9fac5f4 100644 --- a/packages/frontend/mobile/src/pages/workspace/detail/mobile-detail-page.tsx +++ b/packages/frontend/mobile/src/pages/workspace/detail/mobile-detail-page.tsx @@ -130,14 +130,23 @@ const DetailPageImpl = () => { // provide page mode and updated date to blocksuite const pageService = - editorHost?.std.spec.getService('affine:page'); + editorHost?.std.getService('affine:page'); const disposable = new DisposableGroup(); if (pageService) { disposable.add( - pageService.slots.docLinkClicked.on(({ docId, blockId }) => { - return blockId - ? jumpToPageBlock(docCollection.id, docId, blockId) - : openPage(docCollection.id, docId); + pageService.slots.docLinkClicked.on(({ pageId, params }) => { + if (params) { + const { mode, blockIds, elementIds } = params; + return jumpToPageBlock( + docCollection.id, + pageId, + mode, + blockIds, + elementIds + ); + } + + return openPage(docCollection.id, pageId); }) ); disposable.add( diff --git a/scripts/setup/vi-mock.ts b/scripts/setup/vi-mock.ts index bd9381c7c6..a3c0dac052 100644 --- a/scripts/setup/vi-mock.ts +++ b/scripts/setup/vi-mock.ts @@ -24,25 +24,6 @@ vi.mock('@blocksuite/presets', () => ({ EdgelessAIChatBlockSpec: {}, })); -vi.mock('@blocksuite/presets/ai', () => ({ - AIProvider: { - slots: new Proxy( - {}, - { - get: () => ({ - on: vi.fn(), - }), - } - ), - provide: vi.fn(), - }, - AIEdgelessRootBlockSpec: {}, - AICodeBlockSpec: {}, - AIImageBlockSpec: {}, - AIParagraphBlockSpec: {}, - AIPageRootBlockSpec: {}, -})); - if (typeof window !== 'undefined' && HTMLCanvasElement) { // @ts-expect-error HTMLCanvasElement.prototype.getContext = () => { diff --git a/tests/affine-local/e2e/quick-search.spec.ts b/tests/affine-local/e2e/quick-search.spec.ts index e65aa8aef1..50ab868d3f 100644 --- a/tests/affine-local/e2e/quick-search.spec.ts +++ b/tests/affine-local/e2e/quick-search.spec.ts @@ -481,17 +481,23 @@ test('can use @ to open quick search to search for doc and insert into canvas', // press enter to insert the page to canvas await page.keyboard.press('Enter'); - await expect(page.locator('affine-embed-linked-doc-block')).toBeVisible(); + await expect( + page.locator('affine-embed-edgeless-linked-doc-block') + ).toBeVisible(); await expect( page.locator('.affine-embed-linked-doc-content-title') ).toContainText('Write, Draw, Plan all at Once'); // focus on the note block await page.waitForTimeout(500); - await page.locator('affine-embed-linked-doc-block').click({ force: true }); + await page + .locator('affine-embed-edgeless-linked-doc-block') + .click({ force: true }); await page.waitForTimeout(500); // double clock to show peek view - await page.locator('affine-embed-linked-doc-block').dblclick({ force: true }); + await page + .locator('affine-embed-edgeless-linked-doc-block') + .dblclick({ force: true }); await expect(page.getByTestId('peek-view-modal')).toBeVisible(); }); diff --git a/tools/cli/package.json b/tools/cli/package.json index c948fdadd8..2392266db4 100644 --- a/tools/cli/package.json +++ b/tools/cli/package.json @@ -6,7 +6,7 @@ "@affine/env": "workspace:*", "@affine/templates": "workspace:*", "@aws-sdk/client-s3": "^3.620.0", - "@blocksuite/presets": "0.17.0-canary-202408191538-1511d04", + "@blocksuite/presets": "0.0.0-canary-20240902070217", "@clack/core": "^0.3.4", "@clack/prompts": "^0.7.0", "@magic-works/i18n-codegen": "^0.6.0", diff --git a/yarn.lock b/yarn.lock index c9484f4201..64cf1d97bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -252,7 +252,7 @@ __metadata: "@affine/env": "workspace:*" "@affine/templates": "workspace:*" "@aws-sdk/client-s3": "npm:^3.620.0" - "@blocksuite/presets": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/presets": "npm:0.0.0-canary-20240902070217" "@clack/core": "npm:^0.3.4" "@clack/prompts": "npm:^0.7.0" "@magic-works/i18n-codegen": "npm:^0.6.0" @@ -311,12 +311,12 @@ __metadata: "@affine/i18n": "workspace:*" "@atlaskit/pragmatic-drag-and-drop": "npm:^1.2.1" "@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/blocks": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/blocks": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" "@blocksuite/icons": "npm:2.1.66" - "@blocksuite/presets": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/presets": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" "@chromatic-com/storybook": "npm:^1" "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/modifiers": "npm:^7.0.0" @@ -413,13 +413,13 @@ __metadata: "@affine/graphql": "workspace:*" "@affine/i18n": "workspace:*" "@affine/templates": "workspace:*" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/blocks": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/blocks": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" "@blocksuite/icons": "npm:2.1.66" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/presets": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/presets": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/modifiers": "npm:^7.0.0" "@dnd-kit/sortable": "npm:^8.0.0" @@ -552,10 +552,10 @@ __metadata: "@affine/env": "workspace:*" "@affine/i18n": "workspace:*" "@affine/native": "workspace:*" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/blocks": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/presets": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/blocks": "npm:0.0.0-canary-20240902070217" + "@blocksuite/presets": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" "@electron-forge/cli": "npm:^7.3.0" "@electron-forge/core": "npm:^7.3.0" "@electron-forge/core-utils": "npm:^7.3.0" @@ -612,8 +612,8 @@ __metadata: version: 0.0.0-use.local resolution: "@affine/env@workspace:packages/common/env" dependencies: - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" lit: "npm:^3.1.2" react: "npm:18.3.1" react-dom: "npm:18.3.1" @@ -3475,139 +3475,165 @@ __metadata: languageName: node linkType: hard -"@blocksuite/affine-block-paragraph@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/affine-block-paragraph@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/affine-block-list@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/affine-block-list@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/affine-components": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-model": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-shared": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - "@floating-ui/dom": "npm:^1.6.8" + "@blocksuite/affine-components": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-model": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-shared": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" "@lit-labs/preact-signals": "npm:^1.0.2" "@lit/context": "npm:^1.1.2" - "@toeverything/theme": "npm:^1.0.2" - lit: "npm:^3.1.4" + "@toeverything/theme": "npm:^1.0.7" + lit: "npm:^3.2.0" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/691497f518f5b3cff09cda9ae206fdcf3652f355b2f0e711feac39bb4b5b7cde5444549ad96822427c697ae7eb746609781adca344519def3a2e73ec5578a23b + checksum: 10/57694021c251d4d6c54d844b6991a819b7304e738328e5b2ddfc4ad11e4381625df7a2377eb89b44824a88d4ba752b96e5df026b5a4c446c5da94662ff52adbd languageName: node linkType: hard -"@blocksuite/affine-components@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/affine-components@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/affine-block-paragraph@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/affine-block-paragraph@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/affine-model": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-shared": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/icons": "npm:^2.1.62" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - "@floating-ui/dom": "npm:^1.6.8" + "@blocksuite/affine-components": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-model": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-shared": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" "@lit-labs/preact-signals": "npm:^1.0.2" "@lit/context": "npm:^1.1.2" - "@toeverything/theme": "npm:^1.0.2" - lit: "npm:^3.1.4" - zod: "npm:^3.23.8" - checksum: 10/2da75f271eb1f5e91c545f0ba571a22d0c72f7fea41c5215953c55a7981607477dbf81ebda96952a676bdafa052560e3ea85dfad793b88adf9eec56534649604 - languageName: node - linkType: hard - -"@blocksuite/affine-model@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/affine-model@npm:0.17.0-canary-202408191538-1511d04" - dependencies: - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - zod: "npm:^3.23.8" - checksum: 10/28212de87f185151d8d81a3fb6bec08b81b681063ac4a7fd5333864ad91e3d583100ae455a8e92da5487d93074071d85e7b7d4816fd97aafacd230cf11ba1510 - languageName: node - linkType: hard - -"@blocksuite/affine-shared@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/affine-shared@npm:0.17.0-canary-202408191538-1511d04" - dependencies: - "@blocksuite/affine-model": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - "@floating-ui/dom": "npm:^1.6.8" - "@lit-labs/preact-signals": "npm:^1.0.2" - "@lit/context": "npm:^1.1.2" - "@toeverything/theme": "npm:^1.0.2" - lit: "npm:^3.1.4" + "@toeverything/theme": "npm:^1.0.7" + lit: "npm:^3.2.0" minimatch: "npm:^10.0.1" zod: "npm:^3.23.8" - checksum: 10/22d8656159b436f07c12a58f3fbc09d56ea54f72cd20f0175b1c980092f0f475eda6b5cc01371f5b640fa87d84753c200b626568edd6932410a515114ac1916f + checksum: 10/8a4e98ddf5481804b47765e22a7f262600f0828b5545b1f57bb14cd31caa30fa34f9795f3ea170ea7f0fcc3c636c70ee4f6471d6fefec2701dcf1132a80d2d48 languageName: node linkType: hard -"@blocksuite/block-std@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/block-std@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/affine-components@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/affine-components@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/affine-model": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-shared": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/icons": "npm:^2.1.66" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" + "@lit-labs/preact-signals": "npm:^1.0.2" + "@lit/context": "npm:^1.1.2" + "@lottiefiles/dotlottie-wc": "npm:^0.2.16" + "@toeverything/theme": "npm:^1.0.7" + katex: "npm:^0.16.11" + lit: "npm:^3.2.0" + shiki: "npm:^1.12.0" + zod: "npm:^3.23.8" + checksum: 10/030ce8d6c80c6733ec515161e61e3a7e11e6d7dece18715fc404cf3b32e533db7498095dca03d2cd6c3ed55954fe136e60f5cf7e4102c87ae2fe95878f0d3bdf + languageName: node + linkType: hard + +"@blocksuite/affine-model@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/affine-model@npm:0.0.0-canary-20240902070217" + dependencies: + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + zod: "npm:^3.23.8" + checksum: 10/3817634c3effbc7cc6008844438326cc17e818f4b3cddcd32f46e9ac9d00cff9e92777278d87ee37d05b73bbeb840ecbaf8df8996740efac89795d4b1296e86e + languageName: node + linkType: hard + +"@blocksuite/affine-shared@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/affine-shared@npm:0.0.0-canary-20240902070217" + dependencies: + "@blocksuite/affine-model": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" + "@lit-labs/preact-signals": "npm:^1.0.2" + "@lit/context": "npm:^1.1.2" + "@toeverything/theme": "npm:^1.0.7" + lit: "npm:^3.2.0" + minimatch: "npm:^10.0.1" + zod: "npm:^3.23.8" + checksum: 10/51c64bc02e7aa82b55ecf419e44d9a58cb3519e305f447563152b64e9abd10a4cfc29fce6921e3523b2d59682362cf92daa45e96219ec1936c924758e4afd1c3 + languageName: node + linkType: hard + +"@blocksuite/block-std@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/block-std@npm:0.0.0-canary-20240902070217" + dependencies: + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" "@lit-labs/preact-signals": "npm:^1.0.2" "@lit/context": "npm:^1.1.2" "@types/hast": "npm:^3.0.4" - lib0: "npm:^0.2.95" - lit: "npm:^3.1.4" + lib0: "npm:^0.2.97" + lit: "npm:^3.2.0" lz-string: "npm:^1.5.0" rehype-parse: "npm:^9.0.0" unified: "npm:^11.0.5" w3c-keyname: "npm:^2.2.8" zod: "npm:^3.23.8" peerDependencies: - "@blocksuite/inline": 0.17.0-canary-202408191538-1511d04 - "@blocksuite/store": 0.17.0-canary-202408191538-1511d04 - checksum: 10/03ea60144cfa2a23e9b92decb3f523503811c89c34e75fd9b966508ee6777aec501fd7021b73ccaf3871f88d53ee583064dded9fc477ecb8f9367f1941d53ece + "@blocksuite/inline": 0.0.0-canary-20240902070217 + "@blocksuite/store": 0.0.0-canary-20240902070217 + checksum: 10/37cd6a3ad4d43d3f962d64ed942cd2af692b4f90b1679ff6502d070fbb9617f8844dcc710b9435f522b00cab03556d3e088070dee122f09d26ec4fb730a5316d languageName: node linkType: hard -"@blocksuite/blocks@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/blocks@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/blocks@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/blocks@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/affine-block-paragraph": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-components": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-model": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/affine-shared": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/icons": "npm:^2.1.62" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - "@dotlottie/player-component": "npm:^2.7.12" - "@floating-ui/dom": "npm:^1.6.8" + "@blocksuite/affine-block-list": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-block-paragraph": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-components": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-model": "npm:0.0.0-canary-20240902070217" + "@blocksuite/affine-shared": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/icons": "npm:^2.1.66" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" "@lit-labs/preact-signals": "npm:^1.0.2" "@lit/context": "npm:^1.1.2" - "@toeverything/theme": "npm:^1.0.2" + "@toeverything/theme": "npm:^1.0.7" "@types/hast": "npm:^3.0.4" "@types/mdast": "npm:^4.0.4" "@types/sortablejs": "npm:^1.15.8" collapse-white-space: "npm:^2.1.0" date-fns: "npm:^3.6.0" dompurify: "npm:^3.1.6" + fflate: "npm:^0.8.2" figma-squircle: "npm:^0.3.1" - file-type: "npm:^19.3.0" + file-type: "npm:^19.4.1" fractional-indexing: "npm:^3.2.0" html2canvas: "npm:^1.4.1" - jszip: "npm:^3.10.1" - lit: "npm:^3.1.4" - mdast-util-gfm-autolink-literal: "npm:^2.0.0" + lit: "npm:^3.2.0" + lodash.isplainobject: "npm:^4.0.6" + lodash.merge: "npm:^4.6.2" + mdast-util-gfm-autolink-literal: "npm:^2.0.1" mdast-util-gfm-strikethrough: "npm:^2.0.0" mdast-util-gfm-table: "npm:^2.0.0" mdast-util-gfm-task-list-item: "npm:^2.0.0" - merge: "npm:^2.1.1" micromark-extension-gfm-autolink-literal: "npm:^2.1.0" micromark-extension-gfm-strikethrough: "npm:^2.1.0" micromark-extension-gfm-table: "npm:^2.1.0" @@ -3620,25 +3646,25 @@ __metadata: rehype-stringify: "npm:^10.0.0" remark-parse: "npm:^11.0.0" remark-stringify: "npm:^11.0.0" - shiki: "npm:^1.12.0" + shiki: "npm:^1.14.1" sortablejs: "npm:^1.15.2" unified: "npm:^11.0.5" zod: "npm:^3.23.8" - checksum: 10/ccbed0eda2a28b2d580b12fff4d58c78ce977bb853e20da9f6f114dedb3eddf3cafdf70bcb8e5b6b0236fd4a1e4f76b11741bc38fcc2b9a346a30b99a2d98275 + checksum: 10/811a2ad0cdfc1d50e6151a15e4329393d7db148b60932124e2995e0f4fbd7303c4bf0d2ec8e186f2637c6baee6669841a6ab7cfe931900f589a619e06210f82b languageName: node linkType: hard -"@blocksuite/global@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/global@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/global@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/global@npm:0.0.0-canary-20240902070217" dependencies: - lib0: "npm:^0.2.95" + lib0: "npm:^0.2.97" zod: "npm:^3.23.8" - checksum: 10/9e6f33646a964aab02384cd99472ad9b70dafce5d4778ea45142e719599bca2f4a94f992dcb647936428d9b14c73eb9ad1e631ea54482f7c34205ba9c8903c8a + checksum: 10/c5828ac58fbed02ec477c700be3c8fb86a88bd64d0dcaa3c1b77fb766c2e5312b2fa5d26ed0afa60e64e14bf1c1f48537abe69f8ea5fb565c909b7aae3a37a25 languageName: node linkType: hard -"@blocksuite/icons@npm:2.1.66, @blocksuite/icons@npm:^2.1.62, @blocksuite/icons@npm:^2.1.66": +"@blocksuite/icons@npm:2.1.66, @blocksuite/icons@npm:^2.1.66": version: 2.1.66 resolution: "@blocksuite/icons@npm:2.1.66" peerDependencies: @@ -3654,76 +3680,74 @@ __metadata: languageName: node linkType: hard -"@blocksuite/inline@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/inline@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/inline@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/inline@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" zod: "npm:^3.23.8" peerDependencies: lit: ^3.1.1 yjs: ^13.6.15 - checksum: 10/283197e25f9a112e69f0ad6bf26cdf163eb639e577b0c0f0d0aa93df6f6790cb83fc2c4ce39d31c11e12d4e09497875da0fa0e0b593fcc2a574b80d3cc227607 + checksum: 10/bd97ffef90c83c2641dc2479a6d2c49284393260dff5a41d3daddf3eb3b6e2d2ee520b219d5a3074991bc462babeea30dd8292654870fe5ee39687b389635be2 languageName: node linkType: hard -"@blocksuite/presets@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/presets@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/presets@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/presets@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/affine-shared": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/blocks": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" - "@dotlottie/player-component": "npm:^2.7.12" - "@fal-ai/serverless-client": "npm:^0.13.0" - "@floating-ui/dom": "npm:^1.6.8" + "@blocksuite/affine-shared": "npm:0.0.0-canary-20240902070217" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/blocks": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" + "@floating-ui/dom": "npm:^1.6.10" "@lit-labs/preact-signals": "npm:^1.0.2" - "@toeverything/theme": "npm:^1.0.2" - lit: "npm:^3.1.4" - openai: "npm:^4.53.2" + "@lottiefiles/dotlottie-wc": "npm:^0.2.16" + "@toeverything/theme": "npm:^1.0.7" + lit: "npm:^3.2.0" zod: "npm:^3.23.8" - checksum: 10/2136ab81953f83f9544efdef42935bdda8bc015d1a5cd4a3d90916e091f529323c1a641fed9f9cf59ed4f113700bab455ad03b772a2e90de8521fee762ee5f09 + checksum: 10/bbd1ea1b708ef058446350895f3d48377fc9c08af528521584b0950b02c2c1ea7f05a836fc88a8aacf9fed9f652be8ad124ac5fdce175322027edb539aa62c4b languageName: node linkType: hard -"@blocksuite/store@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/store@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/store@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/store@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/inline": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/sync": "npm:0.17.0-canary-202408191538-1511d04" - "@preact/signals-core": "npm:^1.7.0" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/inline": "npm:0.0.0-canary-20240902070217" + "@blocksuite/sync": "npm:0.0.0-canary-20240902070217" + "@preact/signals-core": "npm:^1.8.0" "@types/flexsearch": "npm:^0.7.6" "@types/lodash.ismatch": "npm:^4.4.9" flexsearch: "npm:0.7.43" - lib0: "npm:^0.2.95" + lib0: "npm:^0.2.97" lodash.ismatch: "npm:^4.4.0" - merge: "npm:^2.1.1" + lodash.merge: "npm:^4.6.2" minimatch: "npm:^10.0.1" nanoid: "npm:^5.0.7" y-protocols: "npm:^1.0.6" zod: "npm:^3.23.8" peerDependencies: yjs: ^13.6.15 - checksum: 10/99ba97b28690079ed0ac9f3f9f52934e369bc4cd712aca24cb5298e80c6b98f668ca07bb0153e062497ea21b6d6ab8b6c569ff2324af969edb36b24d0db8c04b + checksum: 10/6358b790fb190b5418719c35ef7acbff2ebc163b2098d88ec8f8c5f27a7581e799d92c752fb508e8d417d29dff89f4057ca41da8ed8613812e5f517353e7cd16 languageName: node linkType: hard -"@blocksuite/sync@npm:0.17.0-canary-202408191538-1511d04": - version: 0.17.0-canary-202408191538-1511d04 - resolution: "@blocksuite/sync@npm:0.17.0-canary-202408191538-1511d04" +"@blocksuite/sync@npm:0.0.0-canary-20240902070217": + version: 0.0.0-canary-20240902070217 + resolution: "@blocksuite/sync@npm:0.0.0-canary-20240902070217" dependencies: - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" idb: "npm:^8.0.0" idb-keyval: "npm:^6.2.1" y-protocols: "npm:^1.0.6" peerDependencies: yjs: ^13.6.15 - checksum: 10/485d9e2e6536dc63492550a09a27804d161229130e7be9d44e2b52fdcba5ec953cf9283f794a27f264ad4a5c62722c9c730a9778bb149dbacf493dc1c59abf26 + checksum: 10/b54f2acdf5c19337e3d24e5286ba9e57da79e182750a8c8624a90771b4a2d691fd516f1f7b736442472f49cfc0e37177f4f944f6622b048f6e1bf011bac3fcbc languageName: node linkType: hard @@ -5383,18 +5407,6 @@ __metadata: languageName: node linkType: hard -"@fal-ai/serverless-client@npm:^0.13.0": - version: 0.13.0 - resolution: "@fal-ai/serverless-client@npm:0.13.0" - dependencies: - "@msgpack/msgpack": "npm:^3.0.0-beta2" - eventsource-parser: "npm:^1.1.2" - robot3: "npm:^0.4.1" - uuid-random: "npm:^1.3.2" - checksum: 10/b8256f4d7af0c612314d2af3f01b0825d22a3689cc2b1d252872027b822128295c83da91b0dd53d14272034e615253b9086ca282e26f6ead03601510c4da80e0 - languageName: node - linkType: hard - "@fal-ai/serverless-client@npm:^0.14.0": version: 0.14.2 resolution: "@fal-ai/serverless-client@npm:0.14.2" @@ -5433,7 +5445,7 @@ __metadata: languageName: node linkType: hard -"@floating-ui/dom@npm:^1.0.0, @floating-ui/dom@npm:^1.6.5, @floating-ui/dom@npm:^1.6.8": +"@floating-ui/dom@npm:^1.0.0, @floating-ui/dom@npm:^1.6.10, @floating-ui/dom@npm:^1.6.5": version: 1.6.10 resolution: "@floating-ui/dom@npm:1.6.10" dependencies: @@ -6860,6 +6872,23 @@ __metadata: languageName: node linkType: hard +"@lottiefiles/dotlottie-wc@npm:^0.2.16": + version: 0.2.18 + resolution: "@lottiefiles/dotlottie-wc@npm:0.2.18" + dependencies: + "@lottiefiles/dotlottie-web": "npm:0.31.1" + lit: "npm:^3.1.0" + checksum: 10/5fa5f98c6c736fa940fe8f65b53bfc67103ff1da6b26d3344c73ff850caacf20c0f506f202e9eec25acf0b202b6021d6e3681d4c315f9405c00bf77f57452d67 + languageName: node + linkType: hard + +"@lottiefiles/dotlottie-web@npm:0.31.1": + version: 0.31.1 + resolution: "@lottiefiles/dotlottie-web@npm:0.31.1" + checksum: 10/c6b7bfb5e95561da8f227b14c0a77f4669800b418f802944609f4a29afb3978228649508221afc650c68987a2e4fd3f4c9f21f51535e631b33fba48fff5c90eb + languageName: node + linkType: hard + "@lukeed/csprng@npm:^1.0.0": version: 1.1.0 resolution: "@lukeed/csprng@npm:1.1.0" @@ -10057,10 +10086,10 @@ __metadata: languageName: node linkType: hard -"@preact/signals-core@npm:^1.2.3, @preact/signals-core@npm:^1.3.0, @preact/signals-core@npm:^1.7.0": - version: 1.7.0 - resolution: "@preact/signals-core@npm:1.7.0" - checksum: 10/a23ae8ef97dd3f98f6212353c770e37548f9fb1ef9f098bbd9352185725b6979f1daa9309ef29d0cb272887392fdbe86b361121c645fdbb983a07f0661544e5e +"@preact/signals-core@npm:^1.2.3, @preact/signals-core@npm:^1.3.0, @preact/signals-core@npm:^1.8.0": + version: 1.8.0 + resolution: "@preact/signals-core@npm:1.8.0" + checksum: 10/480c1aaf1bce6f8bd5544eec9fd92a70ccdfffa24c23d99aa8e3c13783cc6b06ec0a3d90578c5fd368d06121cbe0f8fbe81368aa45ddba11d8a28af15410a9dc languageName: node linkType: hard @@ -12430,12 +12459,20 @@ __metadata: languageName: node linkType: hard -"@shikijs/core@npm:1.12.0": - version: 1.12.0 - resolution: "@shikijs/core@npm:1.12.0" +"@shikijs/core@npm:1.16.1": + version: 1.16.1 + resolution: "@shikijs/core@npm:1.16.1" dependencies: + "@shikijs/vscode-textmate": "npm:^9.2.0" "@types/hast": "npm:^3.0.4" - checksum: 10/794d19b6f9840662021b8dd2a6921db09d1d2420ac1408a05767d850c54c4a57ec8a14beca2b710479719f15f86d2137c1b49bd1f5bdfcbcd563616ef2abc538 + checksum: 10/5f5ef7d9d5e84e0c21c3f60fcab87fa8ff384081d0fbea8bd89ecdd98ff54eae5bd758b84aa6102fb5ac41f278f4c60144adc1d28be4c9e7c7cf0f88fff8d579 + languageName: node + linkType: hard + +"@shikijs/vscode-textmate@npm:^9.2.0": + version: 9.2.0 + resolution: "@shikijs/vscode-textmate@npm:9.2.0" + checksum: 10/16e2521387bb60044919ec7a61359d75adc74daf7d03daefd074ccd4994b0fbd22923c3f258dcd3fd70d9a730920579462afeb3922a08b4e6549a4f43e059962 languageName: node linkType: hard @@ -13928,11 +13965,11 @@ __metadata: "@affine/debug": "workspace:*" "@affine/env": "workspace:*" "@affine/templates": "workspace:*" - "@blocksuite/block-std": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/blocks": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/global": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/presets": "npm:0.17.0-canary-202408191538-1511d04" - "@blocksuite/store": "npm:0.17.0-canary-202408191538-1511d04" + "@blocksuite/block-std": "npm:0.0.0-canary-20240902070217" + "@blocksuite/blocks": "npm:0.0.0-canary-20240902070217" + "@blocksuite/global": "npm:0.0.0-canary-20240902070217" + "@blocksuite/presets": "npm:0.0.0-canary-20240902070217" + "@blocksuite/store": "npm:0.0.0-canary-20240902070217" "@datastructures-js/binary-search-tree": "npm:^5.3.2" "@testing-library/react": "npm:^16.0.0" async-call-rpc: "npm:^6.4.0" @@ -13975,7 +14012,7 @@ __metadata: languageName: unknown linkType: soft -"@toeverything/theme@npm:^1.0.2, @toeverything/theme@npm:^1.0.7": +"@toeverything/theme@npm:^1.0.7": version: 1.0.7 resolution: "@toeverything/theme@npm:1.0.7" checksum: 10/86b46af255450ab7ea0a20faf41c27793129852759d23736e914876a696c40e6daa15b25cde7353cd56c673c6191d04cabe6b77f6131ba0b0862bb8d482d7a01 @@ -21817,7 +21854,7 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.1": +"fflate@npm:^0.8.1, fflate@npm:^0.8.2": version: 0.8.2 resolution: "fflate@npm:0.8.2" checksum: 10/2bd26ba6d235d428de793c6a0cd1aaa96a06269ebd4e21b46c8fd1bd136abc631acf27e188d47c3936db090bf3e1ede11d15ce9eae9bffdc4bfe1b9dc66ca9cb @@ -21858,7 +21895,7 @@ __metadata: languageName: node linkType: hard -"file-type@npm:^19.1.0, file-type@npm:^19.3.0": +"file-type@npm:^19.1.0, file-type@npm:^19.4.1": version: 19.4.1 resolution: "file-type@npm:19.4.1" dependencies: @@ -25410,6 +25447,17 @@ __metadata: languageName: node linkType: hard +"katex@npm:^0.16.11": + version: 0.16.11 + resolution: "katex@npm:0.16.11" + dependencies: + commander: "npm:^8.3.0" + bin: + katex: cli.js + checksum: 10/adfb95a70168f732c26f44a443d27df393ca641a3533aa9321f37b1b69134cf4b15142d533c187ec9a0b02c0bbfebab5ab26f15bd0cc08a57114e1f767f0d7ae + languageName: node + linkType: hard + "keyv@npm:*, keyv@npm:^4.0.0, keyv@npm:^4.5.3, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -25481,7 +25529,7 @@ __metadata: languageName: node linkType: hard -"lib0@npm:^0.2.85, lib0@npm:^0.2.86, lib0@npm:^0.2.93, lib0@npm:^0.2.95": +"lib0@npm:^0.2.85, lib0@npm:^0.2.86, lib0@npm:^0.2.93, lib0@npm:^0.2.95, lib0@npm:^0.2.97": version: 0.2.97 resolution: "lib0@npm:0.2.97" dependencies: @@ -25681,7 +25729,7 @@ __metadata: languageName: node linkType: hard -"lit@npm:^3.1.2, lit@npm:^3.1.3, lit@npm:^3.1.4": +"lit@npm:^3.1.0, lit@npm:^3.1.2, lit@npm:^3.1.3, lit@npm:^3.2.0": version: 3.2.0 resolution: "lit@npm:3.2.0" dependencies: @@ -26478,16 +26526,16 @@ __metadata: languageName: node linkType: hard -"mdast-util-gfm-autolink-literal@npm:^2.0.0": - version: 2.0.0 - resolution: "mdast-util-gfm-autolink-literal@npm:2.0.0" +"mdast-util-gfm-autolink-literal@npm:^2.0.0, mdast-util-gfm-autolink-literal@npm:^2.0.1": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" dependencies: "@types/mdast": "npm:^4.0.0" ccount: "npm:^2.0.0" devlop: "npm:^1.0.0" mdast-util-find-and-replace: "npm:^3.0.0" micromark-util-character: "npm:^2.0.0" - checksum: 10/08656ea3a5b53376a3a09082c7017e4887c1dde00b2c21aee68440d47d9151485347745db49cc05138ce3b6b7760d9700362212685a3644a170344dc4330b696 + checksum: 10/d933b42feb126bd094d4be4a4955326c4a9e727a5d0dbe3c824534a19d831996fcf16f67df3dd29550a7d2ac4ac568c80485bee380151ebb42c62848ab20dfa6 languageName: node linkType: hard @@ -26713,13 +26761,6 @@ __metadata: languageName: node linkType: hard -"merge@npm:^2.1.1": - version: 2.1.1 - resolution: "merge@npm:2.1.1" - checksum: 10/1875521a8e429ba8d82c6d24bf3f229b4b64a348873c41a1245851b422c0caa7fbeb958118c24fbfcbb71e416a29924b3b1c4518911529db175f49eb5bcb5e62 - languageName: node - linkType: hard - "meros@npm:^1.2.1": version: 1.3.0 resolution: "meros@npm:1.3.0" @@ -28541,7 +28582,7 @@ __metadata: languageName: node linkType: hard -"openai@npm:^4.33.0, openai@npm:^4.53.2": +"openai@npm:^4.33.0": version: 4.56.0 resolution: "openai@npm:4.56.0" dependencies: @@ -32343,13 +32384,14 @@ __metadata: languageName: node linkType: hard -"shiki@npm:^1.12.0, shiki@npm:^1.9.1": - version: 1.12.0 - resolution: "shiki@npm:1.12.0" +"shiki@npm:^1.12.0, shiki@npm:^1.14.1, shiki@npm:^1.9.1": + version: 1.16.1 + resolution: "shiki@npm:1.16.1" dependencies: - "@shikijs/core": "npm:1.12.0" + "@shikijs/core": "npm:1.16.1" + "@shikijs/vscode-textmate": "npm:^9.2.0" "@types/hast": "npm:^3.0.4" - checksum: 10/17c9769e0b996433a9131debdc47246fded316fdf529d91fb1b5641a38c21b47fa4781c7bbc53a31cd927d9c9aaab028e105344d6a373dbb772f10b304e9434a + checksum: 10/068359962e8812e238ed0e8bbc2e5c4c68875ca8098a36e8d641467027a4eb5539193659b08b2ad5277d73fc82ec1f4ee345066ac6bd11f51cb53b88bc8ee8b3 languageName: node linkType: hard @@ -35107,13 +35149,6 @@ __metadata: languageName: node linkType: hard -"uuid-random@npm:^1.3.2": - version: 1.3.2 - resolution: "uuid-random@npm:1.3.2" - checksum: 10/9070c876651e1893f9255dddab2edc177ba34196660065be074050e4143405382b7f0f5fb922b666ebfd0794a6ef7b9f6acb627865df7b2978edb0da6b448f1d - languageName: node - linkType: hard - "uuid@npm:10.0.0, uuid@npm:^10.0.0": version: 10.0.0 resolution: "uuid@npm:10.0.0"