From 2cf9a8f286ea82abde60ba918d59b47691b845ff Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Fri, 21 Feb 2025 14:25:35 +0000 Subject: [PATCH] refactor: reorganize specs and adapter extensions (#10359) ### TL;DR Refactored `SpecProvider` singleton access pattern and reorganized adapter/extension code structure. ### What changed? - Changed `SpecProvider.getInstance()` to `SpecProvider._` for cleaner singleton access - Moved adapter/extension code from `_common` directory to dedicated `adapters` and `extensions` folders - Consolidated adapter extensions into a single file - Removed unused dependencies from package.json - Deleted unnecessary schema files - Extracted `MobileSpecsPatches` class into the mobile patching code - Updated all references to use the new `SpecProvider._` accessor ### How to test? - Verify all specs are properly registered and accessible via `SpecProvider._` - Test adapter functionality for HTML, Markdown, Notion HTML and plain text - Check mobile-specific features and patches work correctly - Ensure preview functionality works in both page and edgeless modes ### Why make this change? - Improves code organization by properly separating adapters and extensions - Simplifies singleton access pattern - Removes unnecessary dependencies and files - Makes the codebase more maintainable by consolidating related functionality --- .../src/common/render-linked-doc.ts | 2 +- .../embed-synced-doc-block.ts | 2 +- .../components/frame/frame-preview.ts | 3 +- .../block-root/src/transformers/html.ts | 2 +- .../block-root/src/transformers/markdown.ts | 2 +- .../src/transformers/notion-html.ts | 2 +- .../block-surface-ref/src/portal/note.ts | 2 +- .../src/surface-ref-block.ts | 3 +- .../shared/src/utils/spec/spec-provider.ts | 2 +- .../src/helpers/preview-helper.ts | 2 +- blocksuite/blocks/package.json | 29 +------- blocksuite/blocks/schemas.d.ts | 2 - blocksuite/blocks/schemas.js | 3 - .../src/__tests__/adapters/html.unit.spec.ts | 17 +---- .../__tests__/adapters/markdown.unit.spec.ts | 18 +---- .../adapters/notion-html.unit.spec.ts | 14 +--- .../adapters/plain-text.unit.spec.ts | 13 +--- .../src/__tests__/utils/get-provider.ts | 15 ++++ .../blocks/src/_common/adapters/extension.ts | 22 ------ blocksuite/blocks/src/_specs/index.ts | 6 -- .../blocks/src/_specs/preset/adapters.ts | 31 -------- .../src/_specs/preset/edgeless-specs.ts | 9 --- .../blocks/src/_specs/preset/mobile-patch.ts | 74 ------------------- .../blocks/src/_specs/preset/page-specs.ts | 9 --- .../blocks/src/_specs/register-specs.ts | 23 ------ blocksuite/blocks/src/adapters/extension.ts | 57 ++++++++++++++ .../adapters/html/block-matcher.ts | 0 .../src/{_common => }/adapters/index.ts | 0 .../adapters/markdown/block-matcher.ts | 0 .../adapters/notion-html/block-matcher.ts | 0 .../adapters/plain-text/block-matcher.ts | 0 blocksuite/blocks/src/effects.ts | 3 +- .../src/{_specs => extensions}/common.ts | 6 +- .../blocks/src/extensions/editor-specs.ts | 20 +++++ blocksuite/blocks/src/extensions/index.ts | 3 + .../preset => extensions}/preview-specs.ts | 2 +- blocksuite/blocks/src/extensions/register.ts | 19 +++++ blocksuite/blocks/src/index.ts | 8 +- blocksuite/playground/apps/_common/helper.ts | 3 +- .../apps/starter/utils/collection.ts | 3 +- .../presets/ai/messages/slides-renderer.ts | 3 +- .../specs/custom/root-block.ts | 5 +- .../specs/custom/spec-patchers.tsx | 70 +++++++++++++++++- .../block-suite-editor/specs/edgeless.ts | 2 +- .../block-suite-editor/specs/page.ts | 2 +- .../block-suite-editor/specs/preview.ts | 4 +- .../editor/edgeless/snapshot.tsx | 2 +- .../core/src/modules/workspace/impls/doc.ts | 2 +- yarn.lock | 23 ------ 49 files changed, 224 insertions(+), 320 deletions(-) delete mode 100644 blocksuite/blocks/schemas.d.ts delete mode 100644 blocksuite/blocks/schemas.js create mode 100644 blocksuite/blocks/src/__tests__/utils/get-provider.ts delete mode 100644 blocksuite/blocks/src/_common/adapters/extension.ts delete mode 100644 blocksuite/blocks/src/_specs/index.ts delete mode 100644 blocksuite/blocks/src/_specs/preset/adapters.ts delete mode 100644 blocksuite/blocks/src/_specs/preset/edgeless-specs.ts delete mode 100644 blocksuite/blocks/src/_specs/preset/mobile-patch.ts delete mode 100644 blocksuite/blocks/src/_specs/preset/page-specs.ts delete mode 100644 blocksuite/blocks/src/_specs/register-specs.ts create mode 100644 blocksuite/blocks/src/adapters/extension.ts rename blocksuite/blocks/src/{_common => }/adapters/html/block-matcher.ts (100%) rename blocksuite/blocks/src/{_common => }/adapters/index.ts (100%) rename blocksuite/blocks/src/{_common => }/adapters/markdown/block-matcher.ts (100%) rename blocksuite/blocks/src/{_common => }/adapters/notion-html/block-matcher.ts (100%) rename blocksuite/blocks/src/{_common => }/adapters/plain-text/block-matcher.ts (100%) rename blocksuite/blocks/src/{_specs => extensions}/common.ts (96%) create mode 100644 blocksuite/blocks/src/extensions/editor-specs.ts create mode 100644 blocksuite/blocks/src/extensions/index.ts rename blocksuite/blocks/src/{_specs/preset => extensions}/preview-specs.ts (95%) create mode 100644 blocksuite/blocks/src/extensions/register.ts diff --git a/blocksuite/affine/block-embed/src/common/render-linked-doc.ts b/blocksuite/affine/block-embed/src/common/render-linked-doc.ts index a978d1982b..4178ac523b 100644 --- a/blocksuite/affine/block-embed/src/common/render-linked-doc.ts +++ b/blocksuite/affine/block-embed/src/common/render-linked-doc.ts @@ -197,7 +197,7 @@ async function renderNoteContent( match: ids.map(id => ({ id, viewType: 'display' })), }; const previewDoc = doc.doc.getStore({ query }); - const previewSpec = SpecProvider.getInstance().getSpec('preview:page'); + const previewSpec = SpecProvider._.getSpec('preview:page'); const previewStd = new BlockStdScope({ store: previewDoc, extensions: previewSpec.value, diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts index 32f9438ec3..5ecc8fd692 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts @@ -118,7 +118,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent { const nextDepth = this.depth + 1; - const previewSpecBuilder = SpecProvider.getInstance().getSpec(name); + const previewSpecBuilder = SpecProvider._.getSpec(name); const currentDisposables = this.disposables; const editorSetting = this.std.getOptional(EditorSettingProvider) ?? diff --git a/blocksuite/affine/block-root/src/edgeless/components/frame/frame-preview.ts b/blocksuite/affine/block-root/src/edgeless/components/frame/frame-preview.ts index 0154bd35a8..924f5767e6 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/frame/frame-preview.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/frame/frame-preview.ts @@ -80,8 +80,7 @@ export class FramePreview extends WithDisposable(ShadowlessElement) { private _previewDoc: Store | null = null; - private readonly _previewSpec = - SpecProvider.getInstance().getSpec('preview:edgeless'); + private readonly _previewSpec = SpecProvider._.getSpec('preview:edgeless'); private readonly _updateFrameViewportWH = () => { const [, , w, h] = deserializeXYWH(this.frame.xywh); diff --git a/blocksuite/affine/block-root/src/transformers/html.ts b/blocksuite/affine/block-root/src/transformers/html.ts index 4502bd2f5f..64ac059919 100644 --- a/blocksuite/affine/block-root/src/transformers/html.ts +++ b/blocksuite/affine/block-root/src/transformers/html.ts @@ -26,7 +26,7 @@ type ImportHTMLZipOptions = { function getProvider() { const container = new Container(); - const exts = SpecProvider.getInstance().getSpec('store').value; + const exts = SpecProvider._.getSpec('store').value; exts.forEach(ext => { ext.setup(container); }); diff --git a/blocksuite/affine/block-root/src/transformers/markdown.ts b/blocksuite/affine/block-root/src/transformers/markdown.ts index b31eefea01..ce620706b8 100644 --- a/blocksuite/affine/block-root/src/transformers/markdown.ts +++ b/blocksuite/affine/block-root/src/transformers/markdown.ts @@ -16,7 +16,7 @@ import { createAssetsArchive, download, Unzip } from './utils.js'; function getProvider() { const container = new Container(); - const exts = SpecProvider.getInstance().getSpec('store').value; + const exts = SpecProvider._.getSpec('store').value; exts.forEach(ext => { ext.setup(container); }); diff --git a/blocksuite/affine/block-root/src/transformers/notion-html.ts b/blocksuite/affine/block-root/src/transformers/notion-html.ts index 88e69d23cd..052d90999e 100644 --- a/blocksuite/affine/block-root/src/transformers/notion-html.ts +++ b/blocksuite/affine/block-root/src/transformers/notion-html.ts @@ -14,7 +14,7 @@ type ImportNotionZipOptions = { function getProvider() { const container = new Container(); - const exts = SpecProvider.getInstance().getSpec('store').value; + const exts = SpecProvider._.getSpec('store').value; exts.forEach(ext => { ext.setup(container); }); diff --git a/blocksuite/affine/block-surface-ref/src/portal/note.ts b/blocksuite/affine/block-surface-ref/src/portal/note.ts index 2beacca903..29890ba8ba 100644 --- a/blocksuite/affine/block-surface-ref/src/portal/note.ts +++ b/blocksuite/affine/block-surface-ref/src/portal/note.ts @@ -118,7 +118,7 @@ export class SurfaceRefNotePortal extends WithDisposable(ShadowlessElement) { query: this.query, readonly: true, }); - const previewSpec = SpecProvider.getInstance().getSpec('preview:page'); + const previewSpec = SpecProvider._.getSpec('preview:page'); return new BlockStdScope({ store: doc, extensions: previewSpec.value.slice(), diff --git a/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts b/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts index 507c49fcee..0c895a7ddd 100644 --- a/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts +++ b/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts @@ -239,8 +239,7 @@ export class SurfaceRefBlockComponent extends BlockComponent -// eslint-disable-next-line @typescript-eslint/no-restricted-imports -export * from './dist/schemas.js'; diff --git a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts index 313d1dcc79..3016e8a113 100644 --- a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts @@ -1,13 +1,8 @@ -import { - HtmlInlineToDeltaAdapterExtensions, - InlineDeltaToHtmlAdapterExtensions, -} from '@blocksuite/affine-components/rich-text'; import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; import { embedSyncedDocMiddleware, HtmlAdapter, } from '@blocksuite/affine-shared/adapters'; -import { Container } from '@blocksuite/global/di'; import type { BlockSnapshot, DocSnapshot, @@ -16,19 +11,11 @@ import type { import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { defaultBlockHtmlAdapterMatchers } from '../../_common/adapters/html/block-matcher.js'; import { createJob } from '../utils/create-job.js'; +import { getProvider } from '../utils/get-provider.js'; import { nanoidReplacement } from '../utils/nanoid-replacement.js'; -const container = new Container(); -[ - ...HtmlInlineToDeltaAdapterExtensions, - ...defaultBlockHtmlAdapterMatchers, - ...InlineDeltaToHtmlAdapterExtensions, -].forEach(ext => { - ext.setup(container); -}); -const provider = container.provider(); +const provider = getProvider(); describe('snapshot to html', () => { const template = (html: string, title?: string) => { diff --git a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts index 8313e0ee3d..0ba25b14cd 100644 --- a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts @@ -1,7 +1,3 @@ -import { - InlineDeltaToMarkdownAdapterExtensions, - MarkdownInlineToDeltaAdapterExtensions, -} from '@blocksuite/affine-components/rich-text'; import { DefaultTheme, NoteDisplayMode, @@ -11,7 +7,6 @@ import { embedSyncedDocMiddleware, MarkdownAdapter, } from '@blocksuite/affine-shared/adapters'; -import { Container } from '@blocksuite/global/di'; import type { BlockSnapshot, DocSnapshot, @@ -21,20 +16,11 @@ import type { import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { defaultBlockMarkdownAdapterMatchers } from '../../_common/adapters/markdown/block-matcher.js'; import { createJob } from '../utils/create-job.js'; +import { getProvider } from '../utils/get-provider.js'; import { nanoidReplacement } from '../utils/nanoid-replacement.js'; -const container = new Container(); -[ - ...MarkdownInlineToDeltaAdapterExtensions, - ...defaultBlockMarkdownAdapterMatchers, - ...InlineDeltaToMarkdownAdapterExtensions, -].forEach(ext => { - ext.setup(container); -}); - -const provider = container.provider(); +const provider = getProvider(); describe('snapshot to markdown', () => { test('code', async () => { diff --git a/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts index 51d2b62c0a..ba3de2a32c 100644 --- a/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/notion-html.unit.spec.ts @@ -1,7 +1,5 @@ -import { NotionHtmlInlineToDeltaAdapterExtensions } from '@blocksuite/affine-components/rich-text'; import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters'; -import { Container } from '@blocksuite/global/di'; import { AssetsManager, type BlockSnapshot, @@ -9,19 +7,11 @@ import { } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { defaultBlockNotionHtmlAdapterMatchers } from '../../_common/adapters/notion-html/block-matcher.js'; import { createJob } from '../utils/create-job.js'; +import { getProvider } from '../utils/get-provider.js'; import { nanoidReplacement } from '../utils/nanoid-replacement.js'; -const container = new Container(); -[ - ...NotionHtmlInlineToDeltaAdapterExtensions, - ...defaultBlockNotionHtmlAdapterMatchers, -].forEach(ext => { - ext.setup(container); -}); - -const provider = container.provider(); +const provider = getProvider(); describe('notion html to snapshot', () => { test('code', async () => { diff --git a/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts index e7038b2cb1..a565c8f58f 100644 --- a/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/plain-text.unit.spec.ts @@ -1,10 +1,8 @@ -import { InlineDeltaToPlainTextAdapterExtensions } from '@blocksuite/affine-components/rich-text'; import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; import { embedSyncedDocMiddleware, PlainTextAdapter, } from '@blocksuite/affine-shared/adapters'; -import { Container } from '@blocksuite/global/di'; import type { BlockSnapshot, DocSnapshot, @@ -12,17 +10,10 @@ import type { } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { defaultBlockPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/block-matcher.js'; import { createJob } from '../utils/create-job.js'; +import { getProvider } from '../utils/get-provider.js'; -const container = new Container(); -[ - ...defaultBlockPlainTextAdapterMatchers, - ...InlineDeltaToPlainTextAdapterExtensions, -].forEach(ext => { - ext.setup(container); -}); -const provider = container.provider(); +const provider = getProvider(); describe('snapshot to plain text', () => { test('paragraph', async () => { diff --git a/blocksuite/blocks/src/__tests__/utils/get-provider.ts b/blocksuite/blocks/src/__tests__/utils/get-provider.ts new file mode 100644 index 0000000000..dc93ff3681 --- /dev/null +++ b/blocksuite/blocks/src/__tests__/utils/get-provider.ts @@ -0,0 +1,15 @@ +import { SpecProvider } from '@blocksuite/affine-shared/utils'; +import { Container } from '@blocksuite/global/di'; + +import { registerSpecs } from '../../extensions/register'; + +registerSpecs(); + +export function getProvider() { + const container = new Container(); + const exts = SpecProvider._.getSpec('store').value; + exts.forEach(ext => { + ext.setup(container); + }); + return container.provider(); +} diff --git a/blocksuite/blocks/src/_common/adapters/extension.ts b/blocksuite/blocks/src/_common/adapters/extension.ts deleted file mode 100644 index 561fc44417..0000000000 --- a/blocksuite/blocks/src/_common/adapters/extension.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - AttachmentAdapterFactoryExtension, - HtmlAdapterFactoryExtension, - ImageAdapterFactoryExtension, - MarkdownAdapterFactoryExtension, - MixTextAdapterFactoryExtension, - NotionHtmlAdapterFactoryExtension, - NotionTextAdapterFactoryExtension, - PlainTextAdapterFactoryExtension, -} from '@blocksuite/affine-shared/adapters'; -import type { ExtensionType } from '@blocksuite/store'; - -export const AdapterFactoryExtensions: ExtensionType[] = [ - AttachmentAdapterFactoryExtension, - ImageAdapterFactoryExtension, - MarkdownAdapterFactoryExtension, - PlainTextAdapterFactoryExtension, - HtmlAdapterFactoryExtension, - NotionTextAdapterFactoryExtension, - NotionHtmlAdapterFactoryExtension, - MixTextAdapterFactoryExtension, -]; diff --git a/blocksuite/blocks/src/_specs/index.ts b/blocksuite/blocks/src/_specs/index.ts deleted file mode 100644 index 6d8620705d..0000000000 --- a/blocksuite/blocks/src/_specs/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './common.js'; -export * from './preset/edgeless-specs.js'; -export * from './preset/mobile-patch.js'; -export * from './preset/page-specs.js'; -export * from './preset/preview-specs.js'; -export { SpecBuilder, SpecProvider } from '@blocksuite/affine-shared/utils'; diff --git a/blocksuite/blocks/src/_specs/preset/adapters.ts b/blocksuite/blocks/src/_specs/preset/adapters.ts deleted file mode 100644 index 02c1510808..0000000000 --- a/blocksuite/blocks/src/_specs/preset/adapters.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - HtmlInlineToDeltaAdapterExtensions, - InlineDeltaToHtmlAdapterExtensions, - InlineDeltaToMarkdownAdapterExtensions, - MarkdownInlineToDeltaAdapterExtensions, - NotionHtmlInlineToDeltaAdapterExtensions, -} from '@blocksuite/affine-components/rich-text'; -import type { ExtensionType } from '@blocksuite/store'; - -import { - defaultBlockHtmlAdapterMatchers, - defaultBlockMarkdownAdapterMatchers, - defaultBlockNotionHtmlAdapterMatchers, -} from '../../_common/adapters'; - -export const HtmlAdapterExtension: ExtensionType[] = [ - ...HtmlInlineToDeltaAdapterExtensions, - ...defaultBlockHtmlAdapterMatchers, - ...InlineDeltaToHtmlAdapterExtensions, -]; - -export const MarkdownAdapterExtension: ExtensionType[] = [ - ...MarkdownInlineToDeltaAdapterExtensions, - ...defaultBlockMarkdownAdapterMatchers, - ...InlineDeltaToMarkdownAdapterExtensions, -]; - -export const NotionHtmlAdapterExtension: ExtensionType[] = [ - ...NotionHtmlInlineToDeltaAdapterExtensions, - ...defaultBlockNotionHtmlAdapterMatchers, -]; diff --git a/blocksuite/blocks/src/_specs/preset/edgeless-specs.ts b/blocksuite/blocks/src/_specs/preset/edgeless-specs.ts deleted file mode 100644 index 732dc01f01..0000000000 --- a/blocksuite/blocks/src/_specs/preset/edgeless-specs.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { EdgelessBuiltInSpecs } from '@blocksuite/affine-block-root'; -import type { ExtensionType } from '@blocksuite/store'; - -import { EdgelessFirstPartyBlockSpecs } from '../common'; - -export const EdgelessEditorBlockSpecs: ExtensionType[] = [ - EdgelessBuiltInSpecs, - EdgelessFirstPartyBlockSpecs, -].flat(); diff --git a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts b/blocksuite/blocks/src/_specs/preset/mobile-patch.ts deleted file mode 100644 index 34f516f5d6..0000000000 --- a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { CodeBlockConfig } from '@blocksuite/affine-block-code'; -import { ParagraphBlockService } from '@blocksuite/affine-block-paragraph'; -import { - type ReferenceNodeConfig, - ReferenceNodeConfigIdentifier, -} from '@blocksuite/affine-components/rich-text'; -import { FeatureFlagService } from '@blocksuite/affine-shared/services'; -import { - type BlockStdScope, - ConfigIdentifier, - LifeCycleWatcher, -} from '@blocksuite/block-std'; -import type { Container } from '@blocksuite/global/di'; - -export class MobileSpecsPatches extends LifeCycleWatcher { - static override key = 'mobile-patches'; - - constructor(std: BlockStdScope) { - super(std); - const featureFlagService = std.get(FeatureFlagService); - - featureFlagService.setFlag('enable_mobile_keyboard_toolbar', true); - featureFlagService.setFlag('enable_mobile_linked_doc_menu', true); - } - - static override setup(di: Container) { - super.setup(di); - - // Hide reference popup on mobile. - { - const prev = di.getFactory(ReferenceNodeConfigIdentifier); - di.override(ReferenceNodeConfigIdentifier, provider => { - return { - ...prev?.(provider), - hidePopup: true, - } satisfies ReferenceNodeConfig; - }); - } - - // Hide number lines for code block on mobile. - { - const codeConfigIdentifier = ConfigIdentifier('affine:code'); - const prev = di.getFactory(codeConfigIdentifier); - di.override(codeConfigIdentifier, provider => { - return { - ...prev?.(provider), - showLineNumbers: false, - } satisfies CodeBlockConfig; - }); - } - } - - override mounted() { - // remove slash placeholder for mobile: `type / ...` - { - const paragraphService = this.std.get(ParagraphBlockService); - if (!paragraphService) return; - - paragraphService.placeholderGenerator = model => { - const placeholders = { - text: '', - h1: 'Heading 1', - h2: 'Heading 2', - h3: 'Heading 3', - h4: 'Heading 4', - h5: 'Heading 5', - h6: 'Heading 6', - quote: '', - }; - return placeholders[model.type]; - }; - } - } -} diff --git a/blocksuite/blocks/src/_specs/preset/page-specs.ts b/blocksuite/blocks/src/_specs/preset/page-specs.ts deleted file mode 100644 index 366178fb09..0000000000 --- a/blocksuite/blocks/src/_specs/preset/page-specs.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { PageRootBlockSpec } from '@blocksuite/affine-block-root'; -import type { ExtensionType } from '@blocksuite/store'; - -import { PageFirstPartyBlockSpecs } from '../common.js'; - -export const PageEditorBlockSpecs: ExtensionType[] = [ - PageRootBlockSpec, - ...PageFirstPartyBlockSpecs, -].flat(); diff --git a/blocksuite/blocks/src/_specs/register-specs.ts b/blocksuite/blocks/src/_specs/register-specs.ts deleted file mode 100644 index 29ca74e9cb..0000000000 --- a/blocksuite/blocks/src/_specs/register-specs.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { SpecProvider } from '@blocksuite/affine-shared/utils'; - -import { StoreExtensions } from './common.js'; -import { EdgelessEditorBlockSpecs } from './preset/edgeless-specs.js'; -import { PageEditorBlockSpecs } from './preset/page-specs.js'; -import { - PreviewEdgelessEditorBlockSpecs, - PreviewPageEditorBlockSpecs, -} from './preset/preview-specs.js'; - -export function registerSpecs() { - SpecProvider.getInstance().addSpec('store', StoreExtensions); - SpecProvider.getInstance().addSpec('page', PageEditorBlockSpecs); - SpecProvider.getInstance().addSpec('edgeless', EdgelessEditorBlockSpecs); - SpecProvider.getInstance().addSpec( - 'preview:page', - PreviewPageEditorBlockSpecs - ); - SpecProvider.getInstance().addSpec( - 'preview:edgeless', - PreviewEdgelessEditorBlockSpecs - ); -} diff --git a/blocksuite/blocks/src/adapters/extension.ts b/blocksuite/blocks/src/adapters/extension.ts new file mode 100644 index 0000000000..1352c56add --- /dev/null +++ b/blocksuite/blocks/src/adapters/extension.ts @@ -0,0 +1,57 @@ +import { + HtmlInlineToDeltaAdapterExtensions, + InlineDeltaToHtmlAdapterExtensions, + InlineDeltaToMarkdownAdapterExtensions, + InlineDeltaToPlainTextAdapterExtensions, + MarkdownInlineToDeltaAdapterExtensions, + NotionHtmlInlineToDeltaAdapterExtensions, +} from '@blocksuite/affine-components/rich-text'; +import { + AttachmentAdapterFactoryExtension, + HtmlAdapterFactoryExtension, + ImageAdapterFactoryExtension, + MarkdownAdapterFactoryExtension, + MixTextAdapterFactoryExtension, + NotionHtmlAdapterFactoryExtension, + NotionTextAdapterFactoryExtension, + PlainTextAdapterFactoryExtension, +} from '@blocksuite/affine-shared/adapters'; +import type { ExtensionType } from '@blocksuite/store'; + +import { defaultBlockHtmlAdapterMatchers } from './html/block-matcher'; +import { defaultBlockMarkdownAdapterMatchers } from './markdown/block-matcher'; +import { defaultBlockNotionHtmlAdapterMatchers } from './notion-html/block-matcher'; +import { defaultBlockPlainTextAdapterMatchers } from './plain-text/block-matcher'; + +export const AdapterFactoryExtensions: ExtensionType[] = [ + AttachmentAdapterFactoryExtension, + ImageAdapterFactoryExtension, + MarkdownAdapterFactoryExtension, + PlainTextAdapterFactoryExtension, + HtmlAdapterFactoryExtension, + NotionTextAdapterFactoryExtension, + NotionHtmlAdapterFactoryExtension, + MixTextAdapterFactoryExtension, +]; + +export const HtmlAdapterExtension: ExtensionType[] = [ + ...HtmlInlineToDeltaAdapterExtensions, + ...defaultBlockHtmlAdapterMatchers, + ...InlineDeltaToHtmlAdapterExtensions, +]; + +export const MarkdownAdapterExtension: ExtensionType[] = [ + ...MarkdownInlineToDeltaAdapterExtensions, + ...defaultBlockMarkdownAdapterMatchers, + ...InlineDeltaToMarkdownAdapterExtensions, +]; + +export const NotionHtmlAdapterExtension: ExtensionType[] = [ + ...NotionHtmlInlineToDeltaAdapterExtensions, + ...defaultBlockNotionHtmlAdapterMatchers, +]; + +export const PlainTextAdapterExtension: ExtensionType[] = [ + ...defaultBlockPlainTextAdapterMatchers, + ...InlineDeltaToPlainTextAdapterExtensions, +]; diff --git a/blocksuite/blocks/src/_common/adapters/html/block-matcher.ts b/blocksuite/blocks/src/adapters/html/block-matcher.ts similarity index 100% rename from blocksuite/blocks/src/_common/adapters/html/block-matcher.ts rename to blocksuite/blocks/src/adapters/html/block-matcher.ts diff --git a/blocksuite/blocks/src/_common/adapters/index.ts b/blocksuite/blocks/src/adapters/index.ts similarity index 100% rename from blocksuite/blocks/src/_common/adapters/index.ts rename to blocksuite/blocks/src/adapters/index.ts diff --git a/blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts b/blocksuite/blocks/src/adapters/markdown/block-matcher.ts similarity index 100% rename from blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts rename to blocksuite/blocks/src/adapters/markdown/block-matcher.ts diff --git a/blocksuite/blocks/src/_common/adapters/notion-html/block-matcher.ts b/blocksuite/blocks/src/adapters/notion-html/block-matcher.ts similarity index 100% rename from blocksuite/blocks/src/_common/adapters/notion-html/block-matcher.ts rename to blocksuite/blocks/src/adapters/notion-html/block-matcher.ts diff --git a/blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts b/blocksuite/blocks/src/adapters/plain-text/block-matcher.ts similarity index 100% rename from blocksuite/blocks/src/_common/adapters/plain-text/block-matcher.ts rename to blocksuite/blocks/src/adapters/plain-text/block-matcher.ts diff --git a/blocksuite/blocks/src/effects.ts b/blocksuite/blocks/src/effects.ts index 0a84e30bd5..6b70844b68 100644 --- a/blocksuite/blocks/src/effects.ts +++ b/blocksuite/blocks/src/effects.ts @@ -45,7 +45,7 @@ import { effects as stdEffects } from '@blocksuite/block-std/effects'; import { effects as dataViewEffects } from '@blocksuite/data-view/effects'; import { effects as inlineEffects } from '@blocksuite/inline/effects'; -import { registerSpecs } from './_specs/register-specs.js'; +import { registerSpecs } from './extensions/register.js'; export function effects() { registerSpecs(); @@ -73,6 +73,7 @@ export function effects() { blockCodeEffects(); blockTableEffects(); blockRootEffects(); + componentCaptionEffects(); componentContextMenuEffects(); componentDatePickerEffects(); diff --git a/blocksuite/blocks/src/_specs/common.ts b/blocksuite/blocks/src/extensions/common.ts similarity index 96% rename from blocksuite/blocks/src/_specs/common.ts rename to blocksuite/blocks/src/extensions/common.ts index be108c9816..50d5caea88 100644 --- a/blocksuite/blocks/src/_specs/common.ts +++ b/blocksuite/blocks/src/extensions/common.ts @@ -55,12 +55,13 @@ import { } from '@blocksuite/block-std'; import type { ExtensionType } from '@blocksuite/store'; -import { AdapterFactoryExtensions } from '../_common/adapters/extension.js'; import { + AdapterFactoryExtensions, HtmlAdapterExtension, MarkdownAdapterExtension, NotionHtmlAdapterExtension, -} from './preset/adapters.js'; + PlainTextAdapterExtension, +} from '../adapters/extension.js'; export const CommonBlockSpecs: ExtensionType[] = [ DocDisplayMetaService, @@ -119,4 +120,5 @@ export const StoreExtensions: ExtensionType[] = [ HtmlAdapterExtension, MarkdownAdapterExtension, NotionHtmlAdapterExtension, + PlainTextAdapterExtension, ].flat(); diff --git a/blocksuite/blocks/src/extensions/editor-specs.ts b/blocksuite/blocks/src/extensions/editor-specs.ts new file mode 100644 index 0000000000..02727c26b2 --- /dev/null +++ b/blocksuite/blocks/src/extensions/editor-specs.ts @@ -0,0 +1,20 @@ +import { + EdgelessBuiltInSpecs, + PageRootBlockSpec, +} from '@blocksuite/affine-block-root'; +import type { ExtensionType } from '@blocksuite/store'; + +import { + EdgelessFirstPartyBlockSpecs, + PageFirstPartyBlockSpecs, +} from './common'; + +export const EdgelessEditorBlockSpecs: ExtensionType[] = [ + EdgelessBuiltInSpecs, + EdgelessFirstPartyBlockSpecs, +].flat(); + +export const PageEditorBlockSpecs: ExtensionType[] = [ + PageRootBlockSpec, + PageFirstPartyBlockSpecs, +].flat(); diff --git a/blocksuite/blocks/src/extensions/index.ts b/blocksuite/blocks/src/extensions/index.ts new file mode 100644 index 0000000000..4e1f407c37 --- /dev/null +++ b/blocksuite/blocks/src/extensions/index.ts @@ -0,0 +1,3 @@ +export * from './common.js'; +export * from './editor-specs.js'; +export * from './preview-specs.js'; diff --git a/blocksuite/blocks/src/_specs/preset/preview-specs.ts b/blocksuite/blocks/src/extensions/preview-specs.ts similarity index 95% rename from blocksuite/blocks/src/_specs/preset/preview-specs.ts rename to blocksuite/blocks/src/extensions/preview-specs.ts index 3412956002..9dc83768eb 100644 --- a/blocksuite/blocks/src/_specs/preset/preview-specs.ts +++ b/blocksuite/blocks/src/extensions/preview-specs.ts @@ -7,7 +7,7 @@ import type { ExtensionType } from '@blocksuite/store'; import { EdgelessFirstPartyBlockSpecs, PageFirstPartyBlockSpecs, -} from '../common.js'; +} from './common.js'; export const PreviewEdgelessEditorBlockSpecs: ExtensionType[] = [ PreviewEdgelessRootBlockSpec, diff --git a/blocksuite/blocks/src/extensions/register.ts b/blocksuite/blocks/src/extensions/register.ts new file mode 100644 index 0000000000..0fba57c9a3 --- /dev/null +++ b/blocksuite/blocks/src/extensions/register.ts @@ -0,0 +1,19 @@ +import { SpecProvider } from '@blocksuite/affine-shared/utils'; + +import { StoreExtensions } from './common.js'; +import { + EdgelessEditorBlockSpecs, + PageEditorBlockSpecs, +} from './editor-specs.js'; +import { + PreviewEdgelessEditorBlockSpecs, + PreviewPageEditorBlockSpecs, +} from './preview-specs.js'; + +export function registerSpecs() { + SpecProvider._.addSpec('store', StoreExtensions); + SpecProvider._.addSpec('page', PageEditorBlockSpecs); + SpecProvider._.addSpec('edgeless', EdgelessEditorBlockSpecs); + SpecProvider._.addSpec('preview:page', PreviewPageEditorBlockSpecs); + SpecProvider._.addSpec('preview:edgeless', PreviewEdgelessEditorBlockSpecs); +} diff --git a/blocksuite/blocks/src/index.ts b/blocksuite/blocks/src/index.ts index 2eb4756802..4b0d9f56e2 100644 --- a/blocksuite/blocks/src/index.ts +++ b/blocksuite/blocks/src/index.ts @@ -1,8 +1,5 @@ -/* oxlint-disable @typescript-eslint/triple-slash-reference */ -/// - -export * from './_common/adapters/index.js'; -export * from './_specs/index.js'; +export * from './adapters/index.js'; +export * from './extensions/index.js'; export * from './schemas.js'; export * from '@blocksuite/affine-block-attachment'; export * from '@blocksuite/affine-block-bookmark'; @@ -105,6 +102,7 @@ export { printToPdf, referenceToNode, type Signal, + SpecBuilder, SpecProvider, } from '@blocksuite/affine-shared/utils'; export type { DragBlockPayload } from '@blocksuite/affine-widget-drag-handle'; diff --git a/blocksuite/playground/apps/_common/helper.ts b/blocksuite/playground/apps/_common/helper.ts index 132775c9a5..6a0f72e4dc 100644 --- a/blocksuite/playground/apps/_common/helper.ts +++ b/blocksuite/playground/apps/_common/helper.ts @@ -5,8 +5,7 @@ import { TestWorkspace } from '@blocksuite/store/test'; export function createEmptyDoc() { const schema = new Schema().register(AffineSchemas); const collection = new TestWorkspace({ schema }); - collection.storeExtensions = - SpecProvider.getInstance().getSpec('store').value; + collection.storeExtensions = SpecProvider._.getSpec('store').value; collection.meta.initialize(); const doc = collection.createDoc(); diff --git a/blocksuite/playground/apps/starter/utils/collection.ts b/blocksuite/playground/apps/starter/utils/collection.ts index 4e9708aab8..57f944e123 100644 --- a/blocksuite/playground/apps/starter/utils/collection.ts +++ b/blocksuite/playground/apps/starter/utils/collection.ts @@ -56,8 +56,7 @@ export function createStarterDocCollection() { blobSources, }; const collection = new TestWorkspace(options); - collection.storeExtensions = - SpecProvider.getInstance().getSpec('store').value; + collection.storeExtensions = SpecProvider._.getSpec('store').value; collection.start(); // debug info 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 9f65195d2b..3fb2c337ca 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 @@ -208,8 +208,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) { > ${new BlockStdScope({ store: this._doc, - extensions: - SpecProvider.getInstance().getSpec('preview:edgeless').value, + extensions: SpecProvider._.getSpec('preview:edgeless').value, }).render()}
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 350ed3986b..fde584a3fd 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 @@ -244,11 +244,10 @@ export const extendEdgelessPreviewSpec = (function () { if (framework === _framework && _extension) { return _extension; } else { - _extension && - SpecProvider.getInstance().omitSpec('preview:edgeless', _extension); + _extension && SpecProvider._.omitSpec('preview:edgeless', _extension); _extension = getThemeExtension(framework); _framework = framework; - SpecProvider.getInstance().extendSpec('preview:edgeless', [_extension]); + SpecProvider._.extendSpec('preview:edgeless', [_extension]); return _extension; } }; 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 ed48e33790..d083b4ce64 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 @@ -32,11 +32,15 @@ import { I18n } from '@affine/i18n'; import { track } from '@affine/track'; import { BlockServiceWatcher, + type BlockStdScope, BlockViewIdentifier, + ConfigIdentifier, + LifeCycleWatcher, type WidgetComponent, } from '@blocksuite/affine/block-std'; import type { AffineReference, + CodeBlockConfig, DocMode, DocModeProvider, OpenDocConfig, @@ -44,6 +48,7 @@ import type { PeekOptions, PeekViewService as BSPeekViewService, QuickSearchResult, + ReferenceNodeConfig, RootBlockConfig, } from '@blocksuite/affine/blocks'; import { @@ -52,20 +57,23 @@ import { DocModeExtension, EdgelessRootBlockComponent, EmbedLinkedDocBlockComponent, + FeatureFlagService, GenerateDocUrlExtension, insertLinkByQuickSearchCommand, - MobileSpecsPatches, NativeClipboardExtension, NoteConfigExtension, NotificationExtension, OpenDocExtension, + ParagraphBlockService, ParseDocUrlExtension, PeekViewExtension, QuickSearchExtension, ReferenceNodeConfigExtension, + ReferenceNodeConfigIdentifier, RootBlockConfigExtension, SidebarExtension, } from '@blocksuite/affine/blocks'; +import type { Container } from '@blocksuite/affine/global/di'; import { Bound } from '@blocksuite/affine/global/utils'; import { type BlockSnapshot, @@ -602,6 +610,66 @@ export function patchForSharedPage() { } export function patchForMobile() { + class MobileSpecsPatches extends LifeCycleWatcher { + static override key = 'mobile-patches'; + + constructor(std: BlockStdScope) { + super(std); + const featureFlagService = std.get(FeatureFlagService); + + featureFlagService.setFlag('enable_mobile_keyboard_toolbar', true); + featureFlagService.setFlag('enable_mobile_linked_doc_menu', true); + } + + static override setup(di: Container) { + super.setup(di); + + // Hide reference popup on mobile. + { + const prev = di.getFactory(ReferenceNodeConfigIdentifier); + di.override(ReferenceNodeConfigIdentifier, provider => { + return { + ...prev?.(provider), + hidePopup: true, + } satisfies ReferenceNodeConfig; + }); + } + + // Hide number lines for code block on mobile. + { + const codeConfigIdentifier = ConfigIdentifier('affine:code'); + const prev = di.getFactory(codeConfigIdentifier); + di.override(codeConfigIdentifier, provider => { + return { + ...prev?.(provider), + showLineNumbers: false, + } satisfies CodeBlockConfig; + }); + } + } + + override mounted() { + // remove slash placeholder for mobile: `type / ...` + { + const paragraphService = this.std.get(ParagraphBlockService); + if (!paragraphService) return; + + paragraphService.placeholderGenerator = model => { + const placeholders = { + text: '', + h1: 'Heading 1', + h2: 'Heading 2', + h3: 'Heading 3', + h4: 'Heading 4', + h5: 'Heading 5', + h6: 'Heading 6', + quote: '', + }; + return placeholders[model.type]; + }; + } + } + } const extensions: ExtensionType[] = [ { setup: di => { 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 d57e015a33..5cb518d8b9 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 @@ -17,7 +17,7 @@ export function createEdgelessModeSpecs( ): SpecBuilder { const featureFlagService = framework.get(FeatureFlagService); const enableAI = featureFlagService.flags.enable_ai.value; - const edgelessSpec = SpecProvider.getInstance().getSpec('edgeless'); + const edgelessSpec = SpecProvider._.getSpec('edgeless'); enableAffineExtension(framework, edgelessSpec); if (enableAI) { enableAIExtension(edgelessSpec); 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 f59b2bbd23..dc8db33f64 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 @@ -12,7 +12,7 @@ import { enableAffineExtension, enableAIExtension } from './custom/root-block'; export function createPageModeSpecs(framework: FrameworkProvider): SpecBuilder { const featureFlagService = framework.get(FeatureFlagService); const enableAI = featureFlagService.flags.enable_ai.value; - const provider = SpecProvider.getInstance(); + const provider = SpecProvider._; const pageSpec = provider.getSpec('page'); enableAffineExtension(framework, pageSpec); if (enableAI) { 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 e8f0a73c5d..4818d705ab 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 @@ -33,7 +33,7 @@ function patchPreviewSpec( id: 'preview:edgeless' | 'preview:page', specs: ExtensionType[] ) { - const specProvider = SpecProvider.getInstance(); + const specProvider = SpecProvider._; specProvider.extendSpec(id, specs); } @@ -100,7 +100,7 @@ export function getPagePreviewThemeExtension(framework: FrameworkProvider) { export function createPageModePreviewSpecs( framework: FrameworkProvider ): SpecBuilder { - const specProvider = SpecProvider.getInstance(); + const specProvider = SpecProvider._; const pagePreviewSpec = specProvider.getSpec('preview:page'); // Enable theme extension, doc display meta extension and peek view service const peekViewService = framework.get(PeekViewService); diff --git a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx index 10ccba20a6..38c3878fb4 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/general-setting/editor/edgeless/snapshot.tsx @@ -92,7 +92,7 @@ export const EdgelessSnapshot = (props: Props) => { const editorHost = new BlockStdScope({ store: doc, extensions: [ - ...SpecProvider.getInstance().getSpec('preview:edgeless').value, + ...SpecProvider._.getSpec('preview:edgeless').value, getThemeExtension(framework), ], }).render(); diff --git a/packages/frontend/core/src/modules/workspace/impls/doc.ts b/packages/frontend/core/src/modules/workspace/impls/doc.ts index 6b607b3fcf..9da68e39bd 100644 --- a/packages/frontend/core/src/modules/workspace/impls/doc.ts +++ b/packages/frontend/core/src/modules/workspace/impls/doc.ts @@ -289,7 +289,7 @@ export class DocImpl implements Doc { return this._storeMap.get(key) as Store; } - const storeExtensions = SpecProvider.getInstance().getSpec('store'); + const storeExtensions = SpecProvider._.getSpec('store'); const extensionSet = new Set( storeExtensions.value.concat(extensions ?? []) ); diff --git a/yarn.lock b/yarn.lock index ce26071837..b541268d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4052,31 +4052,8 @@ __metadata: "@blocksuite/icons": "npm:^2.2.1" "@blocksuite/inline": "workspace:*" "@blocksuite/store": "workspace:*" - "@floating-ui/dom": "npm:^1.6.10" - "@lit/context": "npm:^1.1.2" - "@preact/signals-core": "npm:^1.8.0" - "@toeverything/theme": "npm:^1.1.11" - "@types/katex": "npm:^0.16.7" - "@types/lodash-es": "npm:^4.17.12" - "@vanilla-extract/css": "npm:^1.17.0" "@vanilla-extract/vite-plugin": "npm:^5.0.0" - date-fns: "npm:^4.0.0" - dompurify: "npm:^3.2.4" - fflate: "npm:^0.8.2" - file-type: "npm:^20.0.0" - fractional-indexing: "npm:^3.2.0" - html2canvas: "npm:^1.4.1" - katex: "npm:^0.16.11" - lit: "npm:^3.2.0" - lodash-es: "npm:^4.17.21" - lz-string: "npm:^1.5.0" - minimatch: "npm:^10.0.1" - nanoid: "npm:^5.0.7" - shiki: "npm:^2.0.0" - simple-xml-to-json: "npm:^1.2.2" vitest: "npm:3.0.6" - yjs: "npm:^13.6.21" - zod: "npm:^3.23.8" languageName: unknown linkType: soft