diff --git a/blocksuite/affine/block-attachment/src/attachment-block.ts b/blocksuite/affine/block-attachment/src/attachment-block.ts index 31f0c0e6c0..f9e5130433 100644 --- a/blocksuite/affine/block-attachment/src/attachment-block.ts +++ b/blocksuite/affine/block-attachment/src/attachment-block.ts @@ -13,6 +13,11 @@ import { } from '@blocksuite/affine-model'; import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { humanFileSize } from '@blocksuite/affine-shared/utils'; +import { + BlockSelection, + SurfaceSelection, + TextSelection, +} from '@blocksuite/block-std'; import { Slice } from '@blocksuite/store'; import { flip, offset } from '@floating-ui/dom'; import { html, nothing } from 'lit'; @@ -44,7 +49,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent< this, ({ abortController }) => { const selection = this.host.selection; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if ( !!textSelection && (!!textSelection.to || !!textSelection.from.length) @@ -52,7 +57,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent< return null; } - const blockSelections = selection.filter('block'); + const blockSelections = selection.filter(BlockSelection); if ( blockSelections.length > 1 || (blockSelections.length === 1 && @@ -126,7 +131,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent< private _selectBlock() { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); @@ -167,7 +172,8 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent< this.disposables.add( this.std.selection.slots.changed.on(() => { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-bookmark/src/bookmark-block.ts b/blocksuite/affine/block-bookmark/src/bookmark-block.ts index 5908c63423..ab2d52a8b9 100644 --- a/blocksuite/affine/block-bookmark/src/bookmark-block.ts +++ b/blocksuite/affine/block-bookmark/src/bookmark-block.ts @@ -4,6 +4,7 @@ import { } from '@blocksuite/affine-components/caption'; import type { BookmarkBlockModel } from '@blocksuite/affine-model'; import { DocModeProvider } from '@blocksuite/affine-shared/services'; +import { BlockSelection } from '@blocksuite/block-std'; import { html } from 'lit'; import { property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -73,7 +74,7 @@ export class BookmarkBlockComponent extends CaptionedBlockComponent< } override renderBlock() { - const selected = !!this.selected?.is('block'); + const selected = !!this.selected?.is(BlockSelection); return html`
{ this._isSelected = - !!this.bookmark.selected?.is('block') || - !!this.bookmark.selected?.is('surface'); + !!this.bookmark.selected?.is(BlockSelection) || + !!this.bookmark.selected?.is(SurfaceSelection); }) ); } diff --git a/blocksuite/affine/block-code/src/code-block.ts b/blocksuite/affine/block-code/src/code-block.ts index a782c5902b..6f9d0adb34 100644 --- a/blocksuite/affine/block-code/src/code-block.ts +++ b/blocksuite/affine/block-code/src/code-block.ts @@ -11,7 +11,11 @@ import { } from '@blocksuite/affine-shared/services'; import { getViewportElement } from '@blocksuite/affine-shared/utils'; import type { BlockComponent } from '@blocksuite/block-std'; -import { getInlineRangeProvider } from '@blocksuite/block-std'; +import { + BlockSelection, + getInlineRangeProvider, + TextSelection, +} from '@blocksuite/block-std'; import { IS_MAC } from '@blocksuite/global/env'; import { noop } from '@blocksuite/global/utils'; import { @@ -178,7 +182,7 @@ export class CodeBlockComponent extends CaptionedBlockComponent< this.bindHotKey({ Backspace: ctx => { const state = ctx.get('keyboardState'); - const textSelection = selectionManager.find('text'); + const textSelection = selectionManager.find(TextSelection); if (!textSelection) { state.raw.preventDefault(); return; @@ -189,7 +193,7 @@ export class CodeBlockComponent extends CaptionedBlockComponent< if (from.index === 0 && from.length === 0) { state.raw.preventDefault(); selectionManager.setGroup('note', [ - selectionManager.create('block', { blockId: this.blockId }), + selectionManager.create(BlockSelection, { blockId: this.blockId }), ]); return true; } diff --git a/blocksuite/affine/block-code/src/code-toolbar/config.ts b/blocksuite/affine/block-code/src/code-toolbar/config.ts index 2a916b044a..ac490dbcf5 100644 --- a/blocksuite/affine/block-code/src/code-toolbar/config.ts +++ b/blocksuite/affine/block-code/src/code-toolbar/config.ts @@ -8,6 +8,7 @@ import { } from '@blocksuite/affine-components/icons'; import type { MenuItemGroup } from '@blocksuite/affine-components/toolbar'; import { isInsidePageEditor } from '@blocksuite/affine-shared/utils'; +import { BlockSelection } from '@blocksuite/block-std'; import { noop, sleep } from '@blocksuite/global/utils'; import { html } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; @@ -134,7 +135,7 @@ export const clipboardGroup: MenuItemGroup = { host.updateComplete .then(() => { host.selection.setGroup('note', [ - host.selection.create('block', { + host.selection.create(BlockSelection, { blockId: codeId, }), ]); diff --git a/blocksuite/affine/block-code/src/code-toolbar/index.ts b/blocksuite/affine/block-code/src/code-toolbar/index.ts index e0413bde2d..140af99286 100644 --- a/blocksuite/affine/block-code/src/code-toolbar/index.ts +++ b/blocksuite/affine/block-code/src/code-toolbar/index.ts @@ -9,7 +9,11 @@ import { } from '@blocksuite/affine-components/toolbar'; import type { CodeBlockModel } from '@blocksuite/affine-model'; import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts'; -import { WidgetComponent } from '@blocksuite/block-std'; +import { + BlockSelection, + TextSelection, + WidgetComponent, +} from '@blocksuite/block-std'; import { limitShift, shift } from '@floating-ui/dom'; import { html } from 'lit'; @@ -34,7 +38,7 @@ export class AffineCodeToolbarWidget extends WidgetComponent< const codeBlock = this.block; const selection = this.host.selection; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if ( !!textSelection && (!!textSelection.to || !!textSelection.from.length) @@ -42,7 +46,7 @@ export class AffineCodeToolbarWidget extends WidgetComponent< return null; } - const blockSelections = selection.filter('block'); + const blockSelections = selection.filter(BlockSelection); if ( blockSelections.length > 1 || (blockSelections.length === 1 && diff --git a/blocksuite/affine/block-divider/src/divider-block.ts b/blocksuite/affine/block-divider/src/divider-block.ts index 74b746a523..bc51fb295f 100644 --- a/blocksuite/affine/block-divider/src/divider-block.ts +++ b/blocksuite/affine/block-divider/src/divider-block.ts @@ -1,6 +1,7 @@ import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption'; import type { DividerBlockModel } from '@blocksuite/affine-model'; import { BLOCK_CHILDREN_CONTAINER_PADDING_LEFT } from '@blocksuite/affine-shared/consts'; +import { BlockSelection } from '@blocksuite/block-std'; import { html } from 'lit'; import { dividerBlockStyles } from './styles.js'; @@ -15,7 +16,7 @@ export class DividerBlockComponent extends CaptionedBlockComponent { this.host.selection.setGroup('note', [ - this.host.selection.create('block', { + this.host.selection.create(BlockSelection, { blockId: this.blockId, }), ]); diff --git a/blocksuite/affine/block-edgeless-text/src/edgeless-text-block.ts b/blocksuite/affine/block-edgeless-text/src/edgeless-text-block.ts index 5eeb322310..cddb00e458 100644 --- a/blocksuite/affine/block-edgeless-text/src/edgeless-text-block.ts +++ b/blocksuite/affine/block-edgeless-text/src/edgeless-text-block.ts @@ -3,7 +3,11 @@ import type { EdgelessTextBlockModel } from '@blocksuite/affine-model'; import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; import type { BlockComponent } from '@blocksuite/block-std'; -import { GfxBlockComponent } from '@blocksuite/block-std'; +import { + BlockSelection, + GfxBlockComponent, + TextSelection, +} from '@blocksuite/block-std'; import { Bound } from '@blocksuite/global/utils'; import { css, html } from 'lit'; import { query, state } from 'lit/decorators.js'; @@ -88,7 +92,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent { const command = this.std.command; const blockSelections = this.model.children.map(child => - this.std.selection.create('block', { + this.std.selection.create(BlockSelection, { blockId: child.id, }) ); @@ -178,7 +182,7 @@ export class EdgelessTextBlockComponent extends GfxBlockComponent { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-embed/src/embed-github-block/embed-github-block.ts b/blocksuite/affine/block-embed/src/embed-github-block/embed-github-block.ts index 64ae159051..45ddbe6991 100644 --- a/blocksuite/affine/block-embed/src/embed-github-block/embed-github-block.ts +++ b/blocksuite/affine/block-embed/src/embed-github-block/embed-github-block.ts @@ -4,6 +4,7 @@ import type { EmbedGithubStyles, } from '@blocksuite/affine-model'; import { ThemeProvider } from '@blocksuite/affine-shared/services'; +import { BlockSelection, SurfaceSelection } from '@blocksuite/block-std'; import { html, nothing } from 'lit'; import { property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -61,7 +62,7 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent< private _selectBlock() { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); @@ -111,7 +112,8 @@ export class EmbedGithubBlockComponent extends EmbedBlockComponent< this.disposables.add( this.selection.slots.changed.on(() => { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); }) ); } diff --git a/blocksuite/affine/block-embed/src/embed-html-block/embed-html-block.ts b/blocksuite/affine/block-embed/src/embed-html-block/embed-html-block.ts index a9b4cf588f..9122ede660 100644 --- a/blocksuite/affine/block-embed/src/embed-html-block/embed-html-block.ts +++ b/blocksuite/affine/block-embed/src/embed-html-block/embed-html-block.ts @@ -1,4 +1,5 @@ import type { EmbedHtmlModel, EmbedHtmlStyles } from '@blocksuite/affine-model'; +import { BlockSelection, SurfaceSelection } from '@blocksuite/block-std'; import { html } from 'lit'; import { query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -35,7 +36,7 @@ export class EmbedHtmlBlockComponent extends EmbedBlockComponent private _selectBlock() { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); @@ -54,7 +55,8 @@ export class EmbedHtmlBlockComponent extends EmbedBlockComponent this.disposables.add( this.std.selection.slots.changed.on(() => { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts index 7279cf1bfa..32e68e88d3 100644 --- a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts @@ -21,6 +21,7 @@ import { matchFlavours, referenceToNode, } from '@blocksuite/affine-shared/utils'; +import { BlockSelection } from '@blocksuite/block-std'; import { Bound, throttle } from '@blocksuite/global/utils'; import { Text } from '@blocksuite/store'; import { computed } from '@preact/signals-core'; @@ -107,7 +108,7 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); diff --git a/blocksuite/affine/block-embed/src/embed-loom-block/embed-loom-block.ts b/blocksuite/affine/block-embed/src/embed-loom-block/embed-loom-block.ts index f324347752..7ee1e2fa6d 100644 --- a/blocksuite/affine/block-embed/src/embed-loom-block/embed-loom-block.ts +++ b/blocksuite/affine/block-embed/src/embed-loom-block/embed-loom-block.ts @@ -1,6 +1,7 @@ import { OpenIcon } from '@blocksuite/affine-components/icons'; import type { EmbedLoomModel, EmbedLoomStyles } from '@blocksuite/affine-model'; import { ThemeProvider } from '@blocksuite/affine-shared/services'; +import { BlockSelection, SurfaceSelection } from '@blocksuite/block-std'; import { html } from 'lit'; import { property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -46,7 +47,7 @@ export class EmbedLoomBlockComponent extends EmbedBlockComponent< private _selectBlock() { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); @@ -93,7 +94,8 @@ export class EmbedLoomBlockComponent extends EmbedBlockComponent< this.disposables.add( this.std.selection.slots.changed.on(() => { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/components/embed-synced-doc-card.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/components/embed-synced-doc-card.ts index 2a04ee1eea..b86b83ef35 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/components/embed-synced-doc-card.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/components/embed-synced-doc-card.ts @@ -1,5 +1,9 @@ import { ThemeProvider } from '@blocksuite/affine-shared/services'; -import { isGfxBlockComponent, ShadowlessElement } from '@blocksuite/block-std'; +import { + BlockSelection, + isGfxBlockComponent, + ShadowlessElement, +} from '@blocksuite/block-std'; import { throttle, WithDisposable } from '@blocksuite/global/utils'; import { html, nothing } from 'lit'; import { property, queryAsync } from 'lit/decorators.js'; @@ -64,7 +68,7 @@ export class EmbedSyncedDocCard extends WithDisposable(ShadowlessElement) { private _selectBlock() { const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.block.blockId, }); selectionManager.setGroup('note', [blockSelection]); diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts index 9e8ccd20a3..a1a00698f0 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts @@ -8,7 +8,7 @@ import { ThemeExtensionIdentifier, ThemeProvider, } from '@blocksuite/affine-shared/services'; -import { BlockStdScope } from '@blocksuite/block-std'; +import { BlockSelection, BlockStdScope } from '@blocksuite/block-std'; import { assertExists, Bound } from '@blocksuite/global/utils'; import { html } from 'lit'; import { choose } from 'lit/directives/choose.js'; @@ -52,7 +52,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock( } const theme = this.isPageMode ? appTheme : edgelessTheme; - const isSelected = !!this.selected?.is('block'); + const isSelected = !!this.selected?.is(BlockSelection); const scale = this.model.scale ?? 1; this.dataset.nestedEditor = ''; 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 738ff45d36..be6e9a54b1 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 @@ -19,6 +19,7 @@ import { SpecProvider, } from '@blocksuite/affine-shared/utils'; import { + BlockSelection, BlockServiceWatcher, BlockStdScope, type EditorHost, @@ -164,7 +165,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent { this._isSelected = - !!this.selected?.is('block') || !!this.selected?.is('surface'); + !!this.selected?.is(BlockSelection) || + !!this.selected?.is(SurfaceSelection); this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-image/src/components/page-image-block.ts b/blocksuite/affine/block-image/src/components/page-image-block.ts index e9e07e684a..8961bfd41f 100644 --- a/blocksuite/affine/block-image/src/components/page-image-block.ts +++ b/blocksuite/affine/block-image/src/components/page-image-block.ts @@ -1,5 +1,10 @@ +import { ImageSelection } from '@blocksuite/affine-shared/selection'; import type { BaseSelection, UIEventStateContext } from '@blocksuite/block-std'; -import { ShadowlessElement } from '@blocksuite/block-std'; +import { + BlockSelection, + ShadowlessElement, + TextSelection, +} from '@blocksuite/block-std'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, type PropertyValues } from 'lit'; import { property, query, state } from 'lit/decorators.js'; @@ -66,9 +71,9 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { selection.update(selList => selList - .filter(sel => !sel.is('image')) + .filter(sel => !sel.is(ImageSelection)) .concat( - selection.create('text', { + selection.create(TextSelection, { from: { blockId, index: 0, @@ -86,9 +91,11 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { selection.update(selList => { return selList.map(sel => { const current = - sel.is('image') && sel.blockId === this.block.blockId; + sel.is(ImageSelection) && sel.blockId === this.block.blockId; if (current) { - return selection.create('block', { blockId: this.block.blockId }); + return selection.create(BlockSelection, { + blockId: this.block.blockId, + }); } return sel; }); @@ -119,7 +126,7 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { const std = this._host.std; // If the selection is not image selection, we should not handle it. - if (!std.selection.find('image')) { + if (!std.selection.find(ImageSelection)) { return false; } @@ -145,7 +152,7 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { // If the selection is not image selection, we should not handle it. - if (!std.selection.find('image')) { + if (!std.selection.find(ImageSelection)) { return false; } @@ -178,7 +185,7 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { this._disposables.add( selection.slots.changed.on(selList => { this._isSelected = selList.some( - sel => sel.blockId === this.block.blockId && sel.is('image') + sel => sel.blockId === this.block.blockId && sel.is(ImageSelection) ); }) ); @@ -200,7 +207,9 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { selection.update(selList => { return selList .filter(sel => !['block', 'image', 'text'].includes(sel.type)) - .concat(selection.create('image', { blockId: this.block.blockId })); + .concat( + selection.create(ImageSelection, { blockId: this.block.blockId }) + ); }); return true; } @@ -213,7 +222,8 @@ export class ImageBlockPageComponent extends WithDisposable(ShadowlessElement) { selection.update(selList => selList.filter( - sel => !(sel.is('image') && sel.blockId === this.block.blockId) + sel => + !(sel.is(ImageSelection) && sel.blockId === this.block.blockId) ) ); }, diff --git a/blocksuite/affine/block-image/src/image-block.ts b/blocksuite/affine/block-image/src/image-block.ts index 3925006727..1511b29b75 100644 --- a/blocksuite/affine/block-image/src/image-block.ts +++ b/blocksuite/affine/block-image/src/image-block.ts @@ -1,6 +1,7 @@ import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption'; import { Peekable } from '@blocksuite/affine-components/peek'; import type { ImageBlockModel } from '@blocksuite/affine-model'; +import { BlockSelection } from '@blocksuite/block-std'; import { IS_MOBILE } from '@blocksuite/global/env'; import { html } from 'lit'; import { property, query, state } from 'lit/decorators.js'; @@ -51,7 +52,7 @@ export class ImageBlockComponent extends CaptionedBlockComponent< event.stopPropagation(); const selectionManager = this.host.selection; - const blockSelection = selectionManager.create('block', { + const blockSelection = selectionManager.create(BlockSelection, { blockId: this.blockId, }); selectionManager.setGroup('note', [blockSelection]); diff --git a/blocksuite/affine/block-latex/src/latex-block.ts b/blocksuite/affine/block-latex/src/latex-block.ts index 8329dff9cf..9a3b77c421 100644 --- a/blocksuite/affine/block-latex/src/latex-block.ts +++ b/blocksuite/affine/block-latex/src/latex-block.ts @@ -1,6 +1,7 @@ import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption'; import { createLitPortal } from '@blocksuite/affine-components/portal'; import type { LatexBlockModel } from '@blocksuite/affine-model'; +import { BlockSelection } from '@blocksuite/block-std'; import type { Placement } from '@floating-ui/dom'; import { effect } from '@preact/signals-core'; import katex from 'katex'; @@ -19,7 +20,7 @@ export class LatexBlockComponent extends CaptionedBlockComponent selection.blockId === this.model.id ); diff --git a/blocksuite/affine/block-list/src/commands/dedent-list.ts b/blocksuite/affine/block-list/src/commands/dedent-list.ts index 6d6c15c509..7735750718 100644 --- a/blocksuite/affine/block-list/src/commands/dedent-list.ts +++ b/blocksuite/affine/block-list/src/commands/dedent-list.ts @@ -1,6 +1,6 @@ import type { IndentContext } from '@blocksuite/affine-shared/types'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; import { correctNumberedListsOrderToPrev } from './utils.js'; @@ -13,7 +13,7 @@ export const canDedentListCommand: Command< const { std } = ctx; const { selection, doc } = std; if (!blockId) { - const text = selection.find('text'); + const text = selection.find(TextSelection); /** * Do nothing if the selection: * - is not a text selection @@ -148,7 +148,7 @@ export const dedentListCommand: Command<'indentContext'> = (ctx, next) => { doc.moveBlocks([model], grandParent, parent, false); correctNumberedListsOrderToPrev(doc, model); - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-list/src/commands/indent-list.ts b/blocksuite/affine/block-list/src/commands/indent-list.ts index ec9d721a8c..a6eaabdd57 100644 --- a/blocksuite/affine/block-list/src/commands/indent-list.ts +++ b/blocksuite/affine/block-list/src/commands/indent-list.ts @@ -3,7 +3,7 @@ import { getNearestHeadingBefore, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; import { correctNumberedListsOrderToPrev } from './utils.js'; @@ -16,7 +16,7 @@ export const canIndentListCommand: Command< const { std } = ctx; const { selection, doc } = std; if (!blockId) { - const text = selection.find('text'); + const text = selection.find(TextSelection); /** * Do nothing if the selection: * - is not a text selection @@ -133,7 +133,7 @@ export const indentListCommand: Command<'indentContext', never> = ( }); } - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-list/src/list-block.ts b/blocksuite/affine/block-list/src/list-block.ts index 95f98a6727..06396e97c6 100644 --- a/blocksuite/affine/block-list/src/list-block.ts +++ b/blocksuite/affine/block-list/src/list-block.ts @@ -15,7 +15,11 @@ import { import { DocModeProvider } from '@blocksuite/affine-shared/services'; import { getViewportElement } from '@blocksuite/affine-shared/utils'; import type { BaseSelection, BlockComponent } from '@blocksuite/block-std'; -import { getInlineRangeProvider } from '@blocksuite/block-std'; +import { + BlockSelection, + getInlineRangeProvider, + TextSelection, +} from '@blocksuite/block-std'; import type { InlineRangeProvider } from '@blocksuite/inline'; import { effect } from '@preact/signals-core'; import { html, nothing, type TemplateResult } from 'lit'; @@ -95,8 +99,10 @@ export class ListBlockComponent extends CaptionedBlockComponent const selection = this.host.selection; selection.update(selList => { return selList - .filter(sel => !sel.is('text') && !sel.is('block')) - .concat(selection.create('block', { blockId: this.blockId })); + .filter( + sel => !sel.is(TextSelection) && !sel.is(BlockSelection) + ) + .concat(selection.create(BlockSelection, { blockId: this.blockId })); }); } diff --git a/blocksuite/affine/block-list/src/list-keymap.ts b/blocksuite/affine/block-list/src/list-keymap.ts index 6913058d01..f172cf9b5d 100644 --- a/blocksuite/affine/block-list/src/list-keymap.ts +++ b/blocksuite/affine/block-list/src/list-keymap.ts @@ -3,7 +3,7 @@ import { textKeymap, } from '@blocksuite/affine-components/rich-text'; import { ListBlockSchema } from '@blocksuite/affine-model'; -import { KeymapExtension } from '@blocksuite/block-std'; +import { KeymapExtension, TextSelection } from '@blocksuite/block-std'; import { IS_MAC } from '@blocksuite/global/env'; import { forwardDelete } from './utils/forward-delete.js'; @@ -12,7 +12,7 @@ export const ListKeymapExtension = KeymapExtension( std => { return { Enter: ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return false; ctx.get('keyboardState').raw.preventDefault(); @@ -23,7 +23,7 @@ export const ListKeymapExtension = KeymapExtension( return true; }, 'Mod-Enter': ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return false; ctx.get('keyboardState').raw.preventDefault(); @@ -40,7 +40,7 @@ export const ListKeymapExtension = KeymapExtension( if (selectedModels?.length !== 1) { return false; } - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return false; ctx.get('keyboardState').raw.preventDefault(); @@ -61,7 +61,7 @@ export const ListKeymapExtension = KeymapExtension( if (selectedModels?.length !== 1) { return; } - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return false; ctx.get('keyboardState').raw.preventDefault(); @@ -76,7 +76,7 @@ export const ListKeymapExtension = KeymapExtension( return true; }, Backspace: ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return false; const isCollapsed = text.isCollapsed(); const isStart = isCollapsed && text.from.index === 0; diff --git a/blocksuite/affine/block-list/src/utils/forward-delete.ts b/blocksuite/affine/block-list/src/utils/forward-delete.ts index 87d4a37d92..6874df900a 100644 --- a/blocksuite/affine/block-list/src/utils/forward-delete.ts +++ b/blocksuite/affine/block-list/src/utils/forward-delete.ts @@ -2,7 +2,7 @@ import { getNextContentBlock, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { BlockStdScope } from '@blocksuite/block-std'; +import { type BlockStdScope, TextSelection } from '@blocksuite/block-std'; import type { Text } from '@blocksuite/store'; // When deleting at line end of a list block, @@ -20,7 +20,7 @@ import type { Text } from '@blocksuite/store'; - Line9 */ export function forwardDelete(std: BlockStdScope): true | undefined { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const isCollapsed = text.isCollapsed(); const doc = std.doc; diff --git a/blocksuite/affine/block-note/src/commands/block-type.ts b/blocksuite/affine/block-note/src/commands/block-type.ts index 8c09aeffa6..7f182b05aa 100644 --- a/blocksuite/affine/block-note/src/commands/block-type.ts +++ b/blocksuite/affine/block-note/src/commands/block-type.ts @@ -8,7 +8,11 @@ import { mergeToCodeModel, transformModel, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { + BlockSelection, + type Command, + TextSelection, +} from '@blocksuite/block-std'; import type { BlockModel } from '@blocksuite/store'; type UpdateBlockConfig = { @@ -108,11 +112,11 @@ export const updateBlockType: Command< onModelTextUpdated(host, model) ); const selectionManager = host.selection; - const textSelection = selectionManager.find('text'); + const textSelection = selectionManager.find(TextSelection); if (!textSelection) { return false; } - const newTextSelection = selectionManager.create('text', { + const newTextSelection = selectionManager.create(TextSelection, { from: { blockId: firstNewModel.id, index: textSelection.from.index, @@ -143,13 +147,13 @@ export const updateBlockType: Command< const selectionManager = host.selection; - const blockSelections = selectionManager.filter('block'); + const blockSelections = selectionManager.filter(BlockSelection); if (blockSelections.length === 0) { return false; } requestAnimationFrame(() => { const selections = updatedBlocks.map(model => { - return selectionManager.create('block', { + return selectionManager.create(BlockSelection, { blockId: model.id, }); }); diff --git a/blocksuite/affine/block-note/src/commands/dedent-blocks-to-root.ts b/blocksuite/affine/block-note/src/commands/dedent-blocks-to-root.ts index 4ae3bb3547..4f2ca3e931 100644 --- a/blocksuite/affine/block-note/src/commands/dedent-blocks-to-root.ts +++ b/blocksuite/affine/block-note/src/commands/dedent-blocks-to-root.ts @@ -1,5 +1,5 @@ import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const dedentBlocksToRoot: Command< never, @@ -13,7 +13,7 @@ export const dedentBlocksToRoot: Command< const { std, stopCapture = true } = ctx; const { doc } = std; if (!blockIds || !blockIds.length) { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (text) { // If the text selection is not at the beginning of the block, use default behavior if (text.from.index !== 0) return; diff --git a/blocksuite/affine/block-note/src/commands/dedent-blocks.ts b/blocksuite/affine/block-note/src/commands/dedent-blocks.ts index d98536bd80..9e5c3ef146 100644 --- a/blocksuite/affine/block-note/src/commands/dedent-blocks.ts +++ b/blocksuite/affine/block-note/src/commands/dedent-blocks.ts @@ -2,7 +2,7 @@ import { calculateCollapsedSiblings, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const dedentBlocks: Command< never, @@ -75,7 +75,7 @@ export const dedentBlocks: Command< std.command.exec('dedentBlock', { blockId: id, stopCapture: false }); }); - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-note/src/commands/focus-block-end.ts b/blocksuite/affine/block-note/src/commands/focus-block-end.ts index a59a36f5d7..6a81962979 100644 --- a/blocksuite/affine/block-note/src/commands/focus-block-end.ts +++ b/blocksuite/affine/block-note/src/commands/focus-block-end.ts @@ -1,4 +1,4 @@ -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const focusBlockEnd: Command<'focusBlock'> = (ctx, next) => { const { focusBlock, std } = ctx; @@ -7,7 +7,7 @@ export const focusBlockEnd: Command<'focusBlock'> = (ctx, next) => { const { selection } = std; selection.setGroup('note', [ - selection.create('text', { + selection.create(TextSelection, { from: { blockId: focusBlock.blockId, index: focusBlock.model.text.length, diff --git a/blocksuite/affine/block-note/src/commands/focus-block-start.ts b/blocksuite/affine/block-note/src/commands/focus-block-start.ts index 7a66a6dc74..904f1de2c8 100644 --- a/blocksuite/affine/block-note/src/commands/focus-block-start.ts +++ b/blocksuite/affine/block-note/src/commands/focus-block-start.ts @@ -1,4 +1,4 @@ -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const focusBlockStart: Command<'focusBlock'> = (ctx, next) => { const { focusBlock, std } = ctx; @@ -7,7 +7,7 @@ export const focusBlockStart: Command<'focusBlock'> = (ctx, next) => { const { selection } = std; selection.setGroup('note', [ - selection.create('text', { + selection.create(TextSelection, { from: { blockId: focusBlock.blockId, index: 0, length: 0 }, to: null, }), diff --git a/blocksuite/affine/block-note/src/commands/indent-blocks.ts b/blocksuite/affine/block-note/src/commands/indent-blocks.ts index 3a4f2f27f0..c8cc90cbf3 100644 --- a/blocksuite/affine/block-note/src/commands/indent-blocks.ts +++ b/blocksuite/affine/block-note/src/commands/indent-blocks.ts @@ -3,7 +3,7 @@ import { getNearestHeadingBefore, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const indentBlocks: Command< never, @@ -117,7 +117,7 @@ export const indentBlocks: Command< } } - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-note/src/commands/select-block.ts b/blocksuite/affine/block-note/src/commands/select-block.ts index 658f6919c7..0fa4d3967f 100644 --- a/blocksuite/affine/block-note/src/commands/select-block.ts +++ b/blocksuite/affine/block-note/src/commands/select-block.ts @@ -1,4 +1,4 @@ -import type { Command } from '@blocksuite/block-std'; +import { BlockSelection, type Command } from '@blocksuite/block-std'; export const selectBlock: Command<'focusBlock'> = (ctx, next) => { const { focusBlock, std } = ctx; @@ -9,7 +9,7 @@ export const selectBlock: Command<'focusBlock'> = (ctx, next) => { const { selection } = std; selection.setGroup('note', [ - selection.create('block', { blockId: focusBlock.blockId }), + selection.create(BlockSelection, { blockId: focusBlock.blockId }), ]); return next(); diff --git a/blocksuite/affine/block-note/src/commands/select-blocks-between.ts b/blocksuite/affine/block-note/src/commands/select-blocks-between.ts index f4d1d55a3e..7ae46ded72 100644 --- a/blocksuite/affine/block-note/src/commands/select-blocks-between.ts +++ b/blocksuite/affine/block-note/src/commands/select-blocks-between.ts @@ -1,4 +1,4 @@ -import type { Command } from '@blocksuite/block-std'; +import { BlockSelection, type Command } from '@blocksuite/block-std'; export const selectBlocksBetween: Command< 'focusBlock' | 'anchorBlock', @@ -14,7 +14,7 @@ export const selectBlocksBetween: Command< // In same block if (anchorBlock.blockId === focusBlock.blockId) { const blockId = focusBlock.blockId; - selection.setGroup('note', [selection.create('block', { blockId })]); + selection.setGroup('note', [selection.create(BlockSelection, { blockId })]); return next(); } @@ -23,11 +23,11 @@ export const selectBlocksBetween: Command< if (selections.every(sel => sel.blockId !== focusBlock.blockId)) { if (tail) { selections.push( - selection.create('block', { blockId: focusBlock.blockId }) + selection.create(BlockSelection, { blockId: focusBlock.blockId }) ); } else { selections.unshift( - selection.create('block', { blockId: focusBlock.blockId }) + selection.create(BlockSelection, { blockId: focusBlock.blockId }) ); } } diff --git a/blocksuite/affine/block-note/src/move-block.ts b/blocksuite/affine/block-note/src/move-block.ts index 266255283a..36e0da8348 100644 --- a/blocksuite/affine/block-note/src/move-block.ts +++ b/blocksuite/affine/block-note/src/move-block.ts @@ -1,17 +1,21 @@ -import type { BlockSelection, BlockStdScope } from '@blocksuite/block-std'; +import { + BlockSelection, + type BlockStdScope, + TextSelection, +} from '@blocksuite/block-std'; const getSelection = (std: BlockStdScope) => std.selection; function getBlockSelectionBySide(std: BlockStdScope, tail: boolean) { const selection = getSelection(std); - const selections = selection.filter('block'); + const selections = selection.filter(BlockSelection); const sel = selections.at(tail ? -1 : 0) as BlockSelection | undefined; return sel ?? null; } function getTextSelection(std: BlockStdScope) { const selection = getSelection(std); - return selection.find('text'); + return selection.find(TextSelection); } const pathToBlock = (std: BlockStdScope, blockId: string) => diff --git a/blocksuite/affine/block-note/src/note-edgeless-block.ts b/blocksuite/affine/block-note/src/note-edgeless-block.ts index 589c47ac1c..8284cd596b 100644 --- a/blocksuite/affine/block-note/src/note-edgeless-block.ts +++ b/blocksuite/affine/block-note/src/note-edgeless-block.ts @@ -15,7 +15,11 @@ import { stopPropagation, } from '@blocksuite/affine-shared/utils'; import type { BlockComponent, EditorHost } from '@blocksuite/block-std'; -import { ShadowlessElement, toGfxBlockComponent } from '@blocksuite/block-std'; +import { + ShadowlessElement, + TextSelection, + toGfxBlockComponent, +} from '@blocksuite/block-std'; import { almostEqual, Bound, @@ -305,7 +309,7 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent( this.updateComplete .then(() => { this.std.selection.setGroup('note', [ - this.std.selection.create('text', { + this.std.selection.create(TextSelection, { from: { blockId: pId, index: 0, diff --git a/blocksuite/affine/block-note/src/note-service.ts b/blocksuite/affine/block-note/src/note-service.ts index 4d0ab19665..83d520f4a9 100644 --- a/blocksuite/affine/block-note/src/note-service.ts +++ b/blocksuite/affine/block-note/src/note-service.ts @@ -4,9 +4,10 @@ import { matchFlavours } from '@blocksuite/affine-shared/utils'; import { type BaseSelection, type BlockComponent, - type BlockSelection, + BlockSelection, BlockService, type BlockStdScope, + TextSelection, type UIEventHandler, type UIEventStateContext, } from '@blocksuite/block-std'; @@ -95,7 +96,7 @@ export class NoteBlockService extends BlockService { const [codeModel] = newModels; onModelElementUpdated(ctx.std, codeModel, codeElement => { this._std.selection.setGroup('note', [ - this._std.selection.create('text', { + this._std.selection.create(TextSelection, { from: { blockId: codeElement.blockId, index: 0, @@ -439,7 +440,7 @@ export class NoteBlockService extends BlockService { const blockId = doc.addBlock('affine:paragraph', {}, parent, index + 1); - const sel = selection.create('text', { + const sel = selection.create(TextSelection, { from: { blockId, index: 0, @@ -469,7 +470,7 @@ export class NoteBlockService extends BlockService { } ctx.std.selection.update(selList => { - return selList.filter(sel => !sel.is('block')); + return selList.filter(sel => !sel.is(BlockSelection)); }); return next(); @@ -481,7 +482,7 @@ export class NoteBlockService extends BlockService { private readonly _onSelectAll: UIEventHandler = ctx => { const selection = this._std.selection; - const block = selection.find('block'); + const block = selection.find(BlockSelection); if (!block) { return; } @@ -492,13 +493,13 @@ export class NoteBlockService extends BlockService { ctx.get('defaultState').event.preventDefault(); const children = note.children; const blocks: BlockSelection[] = children.map(child => { - return selection.create('block', { + return selection.create(BlockSelection, { blockId: child.id, }); }); selection.update(selList => { return selList - .filter(sel => !sel.is('block')) + .filter(sel => !sel.is(BlockSelection)) .concat(blocks); }); }; diff --git a/blocksuite/affine/block-paragraph/src/commands/add-paragraph.ts b/blocksuite/affine/block-paragraph/src/commands/add-paragraph.ts index 1bbf1c5a4d..a3634f8ea7 100644 --- a/blocksuite/affine/block-paragraph/src/commands/add-paragraph.ts +++ b/blocksuite/affine/block-paragraph/src/commands/add-paragraph.ts @@ -1,5 +1,5 @@ import { focusTextModel } from '@blocksuite/affine-components/rich-text'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; /** * Add a paragraph next to the current block. @@ -17,7 +17,7 @@ export const addParagraphCommand: Command< let blockId = ctx.blockId; if (!blockId) { - const text = selection.find('text'); + const text = selection.find(TextSelection); blockId = text?.blockId; } if (!blockId) return; diff --git a/blocksuite/affine/block-paragraph/src/commands/dedent-paragraph.ts b/blocksuite/affine/block-paragraph/src/commands/dedent-paragraph.ts index 5154073ba6..02a310fa13 100644 --- a/blocksuite/affine/block-paragraph/src/commands/dedent-paragraph.ts +++ b/blocksuite/affine/block-paragraph/src/commands/dedent-paragraph.ts @@ -3,7 +3,7 @@ import { calculateCollapsedSiblings, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const canDedentParagraphCommand: Command< never, @@ -13,7 +13,7 @@ export const canDedentParagraphCommand: Command< let { blockId, inlineIndex } = ctx; const { std } = ctx; const { selection, doc } = std; - const text = selection.find('text'); + const text = selection.find(TextSelection); if (!blockId) { /** @@ -97,7 +97,7 @@ export const dedentParagraphCommand: Command<'indentContext'> = (ctx, next) => { doc.moveBlocks([model], grandParent, parent, false); } - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-paragraph/src/commands/indent-paragraph.ts b/blocksuite/affine/block-paragraph/src/commands/indent-paragraph.ts index b21c18a26a..3bbb5f2cd4 100644 --- a/blocksuite/affine/block-paragraph/src/commands/indent-paragraph.ts +++ b/blocksuite/affine/block-paragraph/src/commands/indent-paragraph.ts @@ -5,7 +5,7 @@ import { getNearestHeadingBefore, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const canIndentParagraphCommand: Command< never, @@ -18,7 +18,7 @@ export const canIndentParagraphCommand: Command< const { schema } = doc; if (!blockId) { - const text = selection.find('text'); + const text = selection.find(TextSelection); /** * Do nothing if the selection: * - is not a text selection @@ -140,7 +140,7 @@ export const indentParagraphCommand: Command<'indentContext'> = (ctx, next) => { } as Partial); } - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (textSelection) { host.updateComplete .then(() => { diff --git a/blocksuite/affine/block-paragraph/src/commands/split-paragraph.ts b/blocksuite/affine/block-paragraph/src/commands/split-paragraph.ts index 68b0a8aa27..69ec50437e 100644 --- a/blocksuite/affine/block-paragraph/src/commands/split-paragraph.ts +++ b/blocksuite/affine/block-paragraph/src/commands/split-paragraph.ts @@ -3,7 +3,7 @@ import { getInlineEditorByModel, } from '@blocksuite/affine-components/rich-text'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const splitParagraphCommand: Command< never, @@ -16,7 +16,7 @@ export const splitParagraphCommand: Command< const { doc, host, selection } = std; let blockId = ctx.blockId; if (!blockId) { - const text = selection.find('text'); + const text = selection.find(TextSelection); blockId = text?.blockId; } if (!blockId) return; diff --git a/blocksuite/affine/block-paragraph/src/paragraph-block.ts b/blocksuite/affine/block-paragraph/src/paragraph-block.ts index 4f7fb00896..0623354e77 100644 --- a/blocksuite/affine/block-paragraph/src/paragraph-block.ts +++ b/blocksuite/affine/block-paragraph/src/paragraph-block.ts @@ -16,7 +16,7 @@ import { getViewportElement, } from '@blocksuite/affine-shared/utils'; import type { BlockComponent } from '@blocksuite/block-std'; -import { getInlineRangeProvider } from '@blocksuite/block-std'; +import { getInlineRangeProvider, TextSelection } from '@blocksuite/block-std'; import type { InlineRangeProvider } from '@blocksuite/inline'; import { effect, signal } from '@preact/signals-core'; import { html, nothing, type TemplateResult } from 'lit'; @@ -119,7 +119,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent< this._displayPlaceholder.value = false; return; } - const textSelection = this.host.selection.find('text'); + const textSelection = this.host.selection.find(TextSelection); const isCollapsed = textSelection?.isCollapsed() ?? false; if (!this.selected || !isCollapsed) { this._displayPlaceholder.value = false; @@ -159,7 +159,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent< // reset text selection when selected block is collapsed if (this.model.type.startsWith('h') && collapsed) { const collapsedSiblings = this.collapsedSiblings; - const textSelection = this.host.selection.find('text'); + const textSelection = this.host.selection.find(TextSelection); if ( textSelection && diff --git a/blocksuite/affine/block-paragraph/src/paragraph-keymap.ts b/blocksuite/affine/block-paragraph/src/paragraph-keymap.ts index abe9628a04..63abee9dbd 100644 --- a/blocksuite/affine/block-paragraph/src/paragraph-keymap.ts +++ b/blocksuite/affine/block-paragraph/src/paragraph-keymap.ts @@ -9,7 +9,7 @@ import { calculateCollapsedSiblings, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import { KeymapExtension } from '@blocksuite/block-std'; +import { KeymapExtension, TextSelection } from '@blocksuite/block-std'; import { IS_MAC } from '@blocksuite/global/env'; import { forwardDelete } from './utils/forward-delete.js'; @@ -19,7 +19,7 @@ export const ParagraphKeymapExtension = KeymapExtension( std => { return { Backspace: ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const isCollapsed = text.isCollapsed(); const isStart = isCollapsed && text.from.index === 0; @@ -52,7 +52,7 @@ export const ParagraphKeymapExtension = KeymapExtension( }, 'Mod-Enter': ctx => { const { doc } = std; - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const model = doc.getBlock(text.from.blockId)?.model; if (!model || !matchFlavours(model, ['affine:paragraph'])) return; @@ -79,7 +79,7 @@ export const ParagraphKeymapExtension = KeymapExtension( }, Enter: ctx => { const { doc } = std; - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const model = doc.getBlock(text.from.blockId)?.model; if (!model || !matchFlavours(model, ['affine:paragraph'])) return; diff --git a/blocksuite/affine/block-paragraph/src/utils/forward-delete.ts b/blocksuite/affine/block-paragraph/src/utils/forward-delete.ts index 8534546dcf..aed1e576bb 100644 --- a/blocksuite/affine/block-paragraph/src/utils/forward-delete.ts +++ b/blocksuite/affine/block-paragraph/src/utils/forward-delete.ts @@ -3,11 +3,15 @@ import { getNextContentBlock, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { BlockStdScope } from '@blocksuite/block-std'; +import { + BlockSelection, + type BlockStdScope, + TextSelection, +} from '@blocksuite/block-std'; export function forwardDelete(std: BlockStdScope) { const { doc, host } = std; - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const isCollapsed = text.isCollapsed(); const model = doc.getBlock(text.from.blockId)?.model; @@ -30,7 +34,7 @@ export function forwardDelete(std: BlockStdScope) { if (matchFlavours(nextSibling, ignoreForwardDeleteFlavourList)) { std.selection.setGroup('note', [ - std.selection.create('block', { blockId: nextSibling.id }), + std.selection.create(BlockSelection, { blockId: nextSibling.id }), ]); return true; } @@ -61,7 +65,7 @@ export function forwardDelete(std: BlockStdScope) { if (nextBlock) { std.selection.setGroup('note', [ - std.selection.create('block', { blockId: nextBlock.id }), + std.selection.create(BlockSelection, { blockId: nextBlock.id }), ]); } return true; diff --git a/blocksuite/affine/block-paragraph/src/utils/merge-with-prev.ts b/blocksuite/affine/block-paragraph/src/utils/merge-with-prev.ts index c5d66115d4..4e268ca6b9 100644 --- a/blocksuite/affine/block-paragraph/src/utils/merge-with-prev.ts +++ b/blocksuite/affine/block-paragraph/src/utils/merge-with-prev.ts @@ -11,7 +11,7 @@ import { getPrevContentBlock, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { EditorHost } from '@blocksuite/block-std'; +import { BlockSelection, type EditorHost } from '@blocksuite/block-std'; import type { BlockModel, Text } from '@blocksuite/store'; /** @@ -72,7 +72,7 @@ export function mergeWithPrev(editorHost: EditorHost, model: BlockModel) { ...EMBED_BLOCK_FLAVOUR_LIST, ]) ) { - const selection = editorHost.selection.create('block', { + const selection = editorHost.selection.create(BlockSelection, { blockId: prevBlock.id, }); editorHost.selection.setGroup('note', [selection]); 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 dc17d4896a..1a587c682e 100644 --- a/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts +++ b/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts @@ -28,10 +28,12 @@ import { import { type BaseSelection, BlockComponent, + BlockSelection, BlockServiceWatcher, BlockStdScope, type EditorHost, LifeCycleWatcher, + TextSelection, } from '@blocksuite/block-std'; import { GfxBlockElementModel, @@ -267,7 +269,7 @@ export class SurfaceRefBlockComponent extends BlockComponent { - return [this.selection.create('block', { blockId: this.blockId })]; + return [this.selection.create(BlockSelection, { blockId: this.blockId })]; }); } @@ -287,9 +289,9 @@ export class SurfaceRefBlockComponent extends BlockComponent { selection.update(selList => { return selList - .filter(sel => !sel.is('block')) + .filter(sel => !sel.is(BlockSelection)) .concat( - selection.create('text', { + selection.create(TextSelection, { from: { blockId: model.id, index: 0, @@ -415,7 +417,7 @@ export class SurfaceRefBlockComponent extends BlockComponent { this._focused = selList.some( - sel => sel.blockId === this.blockId && sel.is('block') + sel => sel.blockId === this.blockId && sel.is(BlockSelection) ); }) ); diff --git a/blocksuite/affine/components/src/block-selection/index.ts b/blocksuite/affine/components/src/block-selection/index.ts index b0715a4332..d919aec936 100644 --- a/blocksuite/affine/components/src/block-selection/index.ts +++ b/blocksuite/affine/components/src/block-selection/index.ts @@ -1,4 +1,7 @@ -import type { BlockComponent } from '@blocksuite/block-std'; +import { + type BlockComponent, + BlockSelection as StdBlockSelection, +} from '@blocksuite/block-std'; import { SignalWatcher } from '@blocksuite/global/utils'; import { css, LitElement, type PropertyValues } from 'lit'; import { property } from 'lit/decorators.js'; @@ -55,7 +58,9 @@ export class BlockSelection extends SignalWatcher(LitElement) { protected override updated(_changedProperties: PropertyValues): void { super.updated(_changedProperties); if (this.block) { - this.style.display = this.block.selected?.is('block') ? 'block' : 'none'; + this.style.display = this.block.selected?.is(StdBlockSelection) + ? 'block' + : 'none'; } } diff --git a/blocksuite/affine/components/src/rich-text/dom.ts b/blocksuite/affine/components/src/rich-text/dom.ts index 29ae4b1a19..341eed6aa4 100644 --- a/blocksuite/affine/components/src/rich-text/dom.ts +++ b/blocksuite/affine/components/src/rich-text/dom.ts @@ -3,7 +3,11 @@ import { getCurrentNativeRange, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { BlockStdScope, EditorHost } from '@blocksuite/block-std'; +import { + type BlockStdScope, + type EditorHost, + TextSelection, +} from '@blocksuite/block-std'; import type { InlineEditor, InlineRange } from '@blocksuite/inline'; import { BlockModel } from '@blocksuite/store'; @@ -81,7 +85,7 @@ export function selectTextModel( ) { const { selection } = std; selection.setGroup('note', [ - selection.create('text', { + selection.create(TextSelection, { from: { blockId: id, index, length }, to: null, }), diff --git a/blocksuite/affine/components/src/rich-text/format/delete-text.ts b/blocksuite/affine/components/src/rich-text/format/delete-text.ts index 829c7db3cf..5b1425f74d 100644 --- a/blocksuite/affine/components/src/rich-text/format/delete-text.ts +++ b/blocksuite/affine/components/src/rich-text/format/delete-text.ts @@ -1,5 +1,5 @@ import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { Command, TextSelection } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; import type { Text } from '@blocksuite/store'; export const deleteTextCommand: Command< @@ -36,7 +36,7 @@ export const deleteTextCommand: Command< if (!to) { fromText.delete(from.index, from.length); ctx.std.selection.setGroup('note', [ - ctx.std.selection.create('text', { + ctx.std.selection.create(TextSelection, { from: { blockId: from.blockId, index: from.index, @@ -69,7 +69,7 @@ export const deleteTextCommand: Command< }); ctx.std.selection.setGroup('note', [ - ctx.std.selection.create('text', { + ctx.std.selection.create(TextSelection, { from: { blockId: from.blockId, index: from.index, diff --git a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/affine-link.ts b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/affine-link.ts index ba39a90a7f..fbaac9e5f6 100644 --- a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/affine-link.ts +++ b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/affine-link.ts @@ -2,7 +2,12 @@ import type { ReferenceInfo } from '@blocksuite/affine-model'; import { ParseDocUrlProvider } from '@blocksuite/affine-shared/services'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { BlockComponent } from '@blocksuite/block-std'; -import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/block-std'; +import { + BLOCK_ID_ATTR, + BlockSelection, + ShadowlessElement, + TextSelection, +} from '@blocksuite/block-std'; import { type DeltaInsert, INLINE_ROOT_ATTR, @@ -69,12 +74,12 @@ export class AffineLink extends ShadowlessElement { } const selection = this.std?.selection; - const textSelection = selection?.find('text'); + const textSelection = selection?.find(TextSelection); if (!!textSelection && !textSelection.isCollapsed()) { return null; } - const blockSelections = selection?.filter('block'); + const blockSelections = selection?.filter(BlockSelection); if (blockSelections?.length) { return null; } diff --git a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/link-popup/link-popup.ts b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/link-popup/link-popup.ts index b3b1bd4616..9517ac60dc 100644 --- a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/link-popup/link-popup.ts +++ b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/link-node/link-popup/link-popup.ts @@ -15,6 +15,7 @@ import { BLOCK_ID_ATTR, type BlockComponent, type BlockStdScope, + TextSelection, } from '@blocksuite/block-std'; import { WithDisposable } from '@blocksuite/global/utils'; import type { InlineRange } from '@blocksuite/inline/types'; @@ -438,7 +439,7 @@ export class LinkPopup extends WithDisposable(LitElement) { reference: null, }); this.inlineEditor.setInlineRange(this.targetInlineRange); - const textSelection = this.host?.selection.find('text'); + const textSelection = this.host?.selection.find(TextSelection); if (!textSelection) return; this.std?.range.syncTextSelectionToRange(textSelection); @@ -452,7 +453,7 @@ export class LinkPopup extends WithDisposable(LitElement) { index: this.targetInlineRange.index, length: text.length, }); - const textSelection = this.host?.selection.find('text'); + const textSelection = this.host?.selection.find(TextSelection); if (!textSelection) return; this.std?.range.syncTextSelectionToRange(textSelection); diff --git a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-node.ts b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-node.ts index 4b0fa57cdb..78280dee1e 100644 --- a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-node.ts +++ b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-node.ts @@ -12,7 +12,9 @@ import { import { BLOCK_ID_ATTR, type BlockComponent, + BlockSelection, ShadowlessElement, + TextSelection, } from '@blocksuite/block-std'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { WithDisposable } from '@blocksuite/global/utils'; @@ -108,12 +110,12 @@ export class AffineReference extends WithDisposable(ShadowlessElement) { if (!selection) { return null; } - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (!!textSelection && !textSelection.isCollapsed()) { return null; } - const blockSelections = selection.filter('block'); + const blockSelections = selection.filter(BlockSelection); if (blockSelections.length) { return null; } diff --git a/blocksuite/affine/components/src/rich-text/keymap/basic.ts b/blocksuite/affine/components/src/rich-text/keymap/basic.ts index 296cff4e85..c56ae18546 100644 --- a/blocksuite/affine/components/src/rich-text/keymap/basic.ts +++ b/blocksuite/affine/components/src/rich-text/keymap/basic.ts @@ -1,4 +1,9 @@ -import type { BlockStdScope, UIEventHandler } from '@blocksuite/block-std'; +import { + BlockSelection, + type BlockStdScope, + TextSelection, + type UIEventHandler, +} from '@blocksuite/block-std'; import { focusTextModel, @@ -11,21 +16,21 @@ export const textCommonKeymap = ( ): Record => { return { ArrowUp: () => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const inline = getInlineEditorByModel(std.host, text.from.blockId); if (!inline) return; return !inline.isFirstLine(inline.getInlineRange()); }, ArrowDown: () => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const inline = getInlineEditorByModel(std.host, text.from.blockId); if (!inline) return; return !inline.isLastLine(inline.getInlineRange()); }, Escape: ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; selectBlock(std, text.from.blockId); @@ -33,7 +38,7 @@ export const textCommonKeymap = ( return true; }, 'Mod-a': ctx => { - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) return; const model = std.doc.getBlock(text.from.blockId)?.model; @@ -53,7 +58,7 @@ export const textCommonKeymap = ( return true; }, Enter: ctx => { - const blocks = std.selection.filter('block'); + const blocks = std.selection.filter(BlockSelection); const blockId = blocks.at(-1)?.blockId; if (!blockId) return; @@ -68,5 +73,7 @@ export const textCommonKeymap = ( }; function selectBlock(std: BlockStdScope, blockId: string) { - std.selection.setGroup('note', [std.selection.create('block', { blockId })]); + std.selection.setGroup('note', [ + std.selection.create(BlockSelection, { blockId }), + ]); } diff --git a/blocksuite/affine/components/src/rich-text/keymap/bracket.ts b/blocksuite/affine/components/src/rich-text/keymap/bracket.ts index f0ac8d1742..a8b27c6859 100644 --- a/blocksuite/affine/components/src/rich-text/keymap/bracket.ts +++ b/blocksuite/affine/components/src/rich-text/keymap/bracket.ts @@ -3,7 +3,11 @@ import { createDefaultDoc, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { BlockStdScope, UIEventHandler } from '@blocksuite/block-std'; +import { + type BlockStdScope, + TextSelection, + type UIEventHandler, +} from '@blocksuite/block-std'; import type { InlineEditor } from '@blocksuite/inline'; import { getInlineEditorByModel } from '../dom.js'; @@ -20,7 +24,7 @@ export const bracketKeymap = ( const { doc, selection } = std; if (doc.readonly) return; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (!textSelection) return; const model = doc.getBlock(textSelection.from.blockId)?.model; if (!model) return; @@ -46,7 +50,7 @@ export const bracketKeymap = ( const { doc, selection } = std; if (doc.readonly) return; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (!textSelection) return; const model = doc.getBlock(textSelection.from.blockId)?.model; if (!model) return; @@ -97,7 +101,7 @@ export const bracketKeymap = ( const { doc, selection } = std; if (doc.readonly) return; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (!textSelection || textSelection.isCollapsed()) return; if (!textSelection.isInSameBlock()) return; const model = doc.getBlock(textSelection.from.blockId)?.model; diff --git a/blocksuite/affine/components/src/rich-text/keymap/format.ts b/blocksuite/affine/components/src/rich-text/keymap/format.ts index c51d31b68c..94984a8d30 100644 --- a/blocksuite/affine/components/src/rich-text/keymap/format.ts +++ b/blocksuite/affine/components/src/rich-text/keymap/format.ts @@ -1,4 +1,8 @@ -import type { BlockStdScope, UIEventHandler } from '@blocksuite/block-std'; +import { + type BlockStdScope, + TextSelection, + type UIEventHandler, +} from '@blocksuite/block-std'; import { textFormatConfigs } from '../format/index.js'; @@ -13,7 +17,7 @@ export const textFormatKeymap = (std: BlockStdScope) => const { doc, selection } = std; if (doc.readonly) return; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if (!textSelection) return; config.action(std.host); diff --git a/blocksuite/affine/components/src/rich-text/markdown/markdown-input.ts b/blocksuite/affine/components/src/rich-text/markdown/markdown-input.ts index a97b36bfb4..7978ce1edd 100644 --- a/blocksuite/affine/components/src/rich-text/markdown/markdown-input.ts +++ b/blocksuite/affine/components/src/rich-text/markdown/markdown-input.ts @@ -2,7 +2,7 @@ import { isMarkdownPrefix, matchFlavours, } from '@blocksuite/affine-shared/utils'; -import type { BlockStdScope } from '@blocksuite/block-std'; +import { type BlockStdScope, TextSelection } from '@blocksuite/block-std'; import { getInlineEditorByModel } from '../dom.js'; import { toDivider } from './divider.js'; @@ -17,7 +17,7 @@ export function markdownInput( ): string | undefined { if (!id) { const selection = std.selection; - const text = selection.find('text'); + const text = selection.find(TextSelection); id = text?.from.blockId; } if (!id) return; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/copy.ts b/blocksuite/affine/shared/src/adapters/middlewares/copy.ts index f5123fc694..7418c69f12 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/copy.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/copy.ts @@ -1,7 +1,8 @@ -import type { - BlockStdScope, - EditorHost, - TextRangePoint, +import { + type BlockStdScope, + type EditorHost, + type TextRangePoint, + TextSelection, } from '@blocksuite/block-std'; import type { BlockSnapshot, @@ -38,7 +39,7 @@ const sliceText = (slots: JobSlots, std: EditorHost['std']) => { const snapshot = payload.snapshot; const model = payload.model; - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (text && text.from.blockId === model.id) { handlePoint(text.from, snapshot, model); return; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts index 2e1242c532..01398ac3ce 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts @@ -7,9 +7,10 @@ import { import { BLOCK_ID_ATTR, type BlockComponent, + BlockSelection, type EditorHost, type TextRangePoint, - type TextSelection, + TextSelection, } from '@blocksuite/block-std'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { assertExists } from '@blocksuite/global/utils'; @@ -25,6 +26,7 @@ import { import * as Y from 'yjs'; import { REFERENCE_NODE } from '../../consts'; +import { ImageSelection } from '../../selection'; import { ParseDocUrlProvider, type ParseDocUrlService, @@ -290,19 +292,19 @@ class PasteTr { } if (!cursorModel.text) { if (matchFlavours(cursorModel, ['affine:image'])) { - const selection = this.std.selection.create('image', { + const selection = this.std.selection.create(ImageSelection, { blockId: target.blockId, }); this.std.selection.setGroup('note', [selection]); return; } - const selection = this.std.selection.create('block', { + const selection = this.std.selection.create(BlockSelection, { blockId: target.blockId, }); this.std.selection.setGroup('note', [selection]); return; } - const selection = this.std.selection.create('text', { + const selection = this.std.selection.create(TextSelection, { from: { blockId: target.blockId, index: cursorModel.text ? this.lastIndex : 0, @@ -511,7 +513,7 @@ export const pasteMiddleware = (std: EditorHost['std']): JobMiddleware => { const { snapshot } = payload; flatNote(snapshot); - const text = std.selection.find('text'); + const text = std.selection.find(TextSelection); if (!text) { return; } diff --git a/blocksuite/affine/shared/src/commands/block-crud/get-selected-blocks.ts b/blocksuite/affine/shared/src/commands/block-crud/get-selected-blocks.ts index 4522223fd0..9c8914016f 100644 --- a/blocksuite/affine/shared/src/commands/block-crud/get-selected-blocks.ts +++ b/blocksuite/affine/shared/src/commands/block-crud/get-selected-blocks.ts @@ -16,7 +16,7 @@ export const getSelectedBlocksCommand: Command< blockSelections?: BlockSelection[]; imageSelections?: ImageSelection[]; filter?: (el: BlockComponent) => boolean; - types?: Extract[]; + types?: Array<'image' | 'text' | 'block'>; roles?: RoleType[]; mode?: 'all' | 'flat' | 'highest'; } diff --git a/blocksuite/affine/shared/src/commands/model-crud/clear-and-select-first-model.ts b/blocksuite/affine/shared/src/commands/model-crud/clear-and-select-first-model.ts index 317c8678c8..9b1bfda0bd 100644 --- a/blocksuite/affine/shared/src/commands/model-crud/clear-and-select-first-model.ts +++ b/blocksuite/affine/shared/src/commands/model-crud/clear-and-select-first-model.ts @@ -1,4 +1,4 @@ -import type { Command } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const clearAndSelectFirstModelCommand: Command<'selectedModels'> = ( ctx, @@ -17,7 +17,7 @@ export const clearAndSelectFirstModelCommand: Command<'selectedModels'> = ( const firstModel = models[0]; if (firstModel.text) { firstModel.text.clear(); - const selection = ctx.std.selection.create('text', { + const selection = ctx.std.selection.create(TextSelection, { from: { blockId: firstModel.id, index: 0, diff --git a/blocksuite/affine/shared/src/commands/model-crud/get-selected-models.ts b/blocksuite/affine/shared/src/commands/model-crud/get-selected-models.ts index c7bb5c068a..5f72cad3f0 100644 --- a/blocksuite/affine/shared/src/commands/model-crud/get-selected-models.ts +++ b/blocksuite/affine/shared/src/commands/model-crud/get-selected-models.ts @@ -32,7 +32,7 @@ export const getSelectedModelsCommand: Command< never, 'selectedModels', { - types?: Extract[]; + types?: Array<'image' | 'text' | 'block'>; mode?: 'all' | 'flat' | 'highest'; } > = (ctx, next) => { diff --git a/blocksuite/affine/shared/src/commands/selection/get-block-selections.ts b/blocksuite/affine/shared/src/commands/selection/get-block-selections.ts index 63d7ebdcb7..0a94bfce39 100644 --- a/blocksuite/affine/shared/src/commands/selection/get-block-selections.ts +++ b/blocksuite/affine/shared/src/commands/selection/get-block-selections.ts @@ -1,10 +1,10 @@ -import type { BlockSelection, Command } from '@blocksuite/block-std'; +import { BlockSelection, type Command } from '@blocksuite/block-std'; export const getBlockSelectionsCommand: Command< never, 'currentBlockSelections' > = (ctx, next) => { - const currentBlockSelections = ctx.std.selection.filter('block'); + const currentBlockSelections = ctx.std.selection.filter(BlockSelection); if (currentBlockSelections.length === 0) return; next({ currentBlockSelections }); diff --git a/blocksuite/affine/shared/src/commands/selection/get-image-selections.ts b/blocksuite/affine/shared/src/commands/selection/get-image-selections.ts index 28b80e60ca..39f1a83114 100644 --- a/blocksuite/affine/shared/src/commands/selection/get-image-selections.ts +++ b/blocksuite/affine/shared/src/commands/selection/get-image-selections.ts @@ -1,12 +1,12 @@ import type { Command } from '@blocksuite/block-std'; -import type { ImageSelection } from '../../selection/index.js'; +import { ImageSelection } from '../../selection/index.js'; export const getImageSelectionsCommand: Command< never, 'currentImageSelections' > = (ctx, next) => { - const currentImageSelections = ctx.std.selection.filter('image'); + const currentImageSelections = ctx.std.selection.filter(ImageSelection); if (currentImageSelections.length === 0) return; next({ currentImageSelections }); diff --git a/blocksuite/affine/shared/src/commands/selection/get-text-selection.ts b/blocksuite/affine/shared/src/commands/selection/get-text-selection.ts index a68e2f305b..1c86f53271 100644 --- a/blocksuite/affine/shared/src/commands/selection/get-text-selection.ts +++ b/blocksuite/affine/shared/src/commands/selection/get-text-selection.ts @@ -1,10 +1,10 @@ -import type { Command, TextSelection } from '@blocksuite/block-std'; +import { type Command, TextSelection } from '@blocksuite/block-std'; export const getTextSelectionCommand: Command = ( ctx, next ) => { - const currentTextSelection = ctx.std.selection.find('text'); + const currentTextSelection = ctx.std.selection.find(TextSelection); if (!currentTextSelection) return; next({ currentTextSelection }); diff --git a/blocksuite/affine/widget-drag-handle/src/helpers/selection-helper.ts b/blocksuite/affine/widget-drag-handle/src/helpers/selection-helper.ts index b206e3f397..8399df3fca 100644 --- a/blocksuite/affine/widget-drag-handle/src/helpers/selection-helper.ts +++ b/blocksuite/affine/widget-drag-handle/src/helpers/selection-helper.ts @@ -1,5 +1,10 @@ import { findNoteBlockModel } from '@blocksuite/affine-shared/utils'; -import type { BlockComponent } from '@blocksuite/block-std'; +import { + type BlockComponent, + BlockSelection, + SurfaceSelection, + TextSelection, +} from '@blocksuite/block-std'; import type { AffineDragHandleWidget } from '../drag-handle.js'; @@ -15,7 +20,7 @@ export class SelectionHelper { setSelectedBlocks = (blocks: BlockComponent[], noteId?: string) => { const { selection } = this; const selections = blocks.map(block => - selection.create('block', { + selection.create(BlockSelection, { blockId: block.blockId, }) ); @@ -28,7 +33,7 @@ export class SelectionHelper { : findNoteBlockModel(blocks[0].model)?.id; if (!surfaceElementId) return; const surfaceSelection = selection.create( - 'surface', + SurfaceSelection, blocks[0]!.blockId, [surfaceElementId], true @@ -49,9 +54,9 @@ export class SelectionHelper { get selectedBlocks() { const selection = this.selection; - return selection.find('text') - ? selection.filter('text') - : selection.filter('block'); + return selection.find(TextSelection) + ? selection.filter(TextSelection) + : selection.filter(BlockSelection); } get selection() { diff --git a/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts b/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts index 8f8f1ee1e2..18aa53b607 100644 --- a/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts +++ b/blocksuite/affine/widget-drag-handle/src/watchers/drag-event-watcher.ts @@ -23,6 +23,7 @@ import { } from '@blocksuite/affine-shared/utils'; import { type BlockComponent, + BlockSelection, type DndEventState, isGfxBlockComponent, type UIEventHandler, @@ -158,7 +159,7 @@ export class DragEventWatcher { const selectBlockAndStartDragging = () => { this._std.selection.setGroup('note', [ - this._std.selection.create('block', { + this._std.selection.create(BlockSelection, { blockId: hoverBlock.blockId, }), ]); diff --git a/blocksuite/affine/widget-remote-selection/src/doc/doc-remote-selection.ts b/blocksuite/affine/widget-remote-selection/src/doc/doc-remote-selection.ts index ae4d2cfc0c..279d71eac2 100644 --- a/blocksuite/affine/widget-remote-selection/src/doc/doc-remote-selection.ts +++ b/blocksuite/affine/widget-remote-selection/src/doc/doc-remote-selection.ts @@ -101,7 +101,7 @@ export class AffineDocRemoteSelectionWidget extends WidgetComponent { if (textSelection) { const range = this.std.range.textSelectionToRange( - this._selectionManager.create('text', { + this._selectionManager.create(TextSelection, { from: { blockId: textSelection.to ? textSelection.to.blockId diff --git a/blocksuite/affine/widget-scroll-anchoring/src/scroll-anchoring.ts b/blocksuite/affine/widget-scroll-anchoring/src/scroll-anchoring.ts index e96632eadb..d8cf2f19c1 100644 --- a/blocksuite/affine/widget-scroll-anchoring/src/scroll-anchoring.ts +++ b/blocksuite/affine/widget-scroll-anchoring/src/scroll-anchoring.ts @@ -1,6 +1,5 @@ -import '@blocksuite/affine-shared/selection'; - import type { DocMode } from '@blocksuite/affine-model'; +import { HighlightSelection } from '@blocksuite/affine-shared/selection'; import { WidgetComponent } from '@blocksuite/block-std'; import { GfxControllerIdentifier, @@ -65,7 +64,7 @@ export class AffineScrollAnchoringWidget extends WidgetComponent { anchorBounds$ = signal(null); highlighted$ = computed(() => - this.service.selectionManager.find('highlight') + this.service.selectionManager.find(HighlightSelection) ); #getBoundsInEdgeless() { diff --git a/blocksuite/blocks/src/index.ts b/blocksuite/blocks/src/index.ts index 51359e8eef..0345339a9c 100644 --- a/blocksuite/blocks/src/index.ts +++ b/blocksuite/blocks/src/index.ts @@ -114,6 +114,7 @@ export { PlainTextAdapterFactoryExtension, PlainTextAdapterFactoryIdentifier, } from '@blocksuite/affine-shared/adapters'; +export { HighlightSelection } from '@blocksuite/affine-shared/selection'; export * from '@blocksuite/affine-shared/services'; export { scrollbarStyle } from '@blocksuite/affine-shared/styles'; export { diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts index 5c32e34129..59395525ca 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts @@ -16,6 +16,7 @@ import { } from '@blocksuite/affine-shared/services'; import { LassoMode } from '@blocksuite/affine-shared/types'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; +import { SurfaceSelection, TextSelection } from '@blocksuite/block-std'; import { GfxBlockElementModel, type GfxToolsMap, @@ -167,8 +168,8 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { const std = this.rootComponent.std; if ( std.selection.getGroup('note').length > 0 || - std.selection.find('text') || - Boolean(std.selection.find('surface')?.editing) + std.selection.find(TextSelection) || + Boolean(std.selection.find(SurfaceSelection)?.editing) ) { return; } diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts index b651763bff..aa244c95d2 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts @@ -22,12 +22,12 @@ import { requestConnectedFrame, requestThrottledConnectedFrame, } from '@blocksuite/affine-shared/utils'; -import type { - GfxBlockComponent, +import { + BlockComponent, + type GfxBlockComponent, SurfaceSelection, - UIEventHandler, + type UIEventHandler, } from '@blocksuite/block-std'; -import { BlockComponent } from '@blocksuite/block-std'; import { GfxControllerIdentifier, type GfxViewportElement, @@ -454,7 +454,7 @@ export class EdgelessRootBlockComponent extends BlockComponent< this.handleEvent('selectionChange', () => { const surface = this.host.selection.value.find( - (sel): sel is SurfaceSelection => sel.is('surface') + (sel): sel is SurfaceSelection => sel.is(SurfaceSelection) ); if (!surface) return; diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts index efb669a0d0..55ad584dfd 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-preview-block.ts @@ -9,11 +9,11 @@ import { ThemeProvider, } from '@blocksuite/affine-shared/services'; import { requestThrottledConnectedFrame } from '@blocksuite/affine-shared/utils'; -import type { - GfxBlockComponent, +import { + BlockComponent, + type GfxBlockComponent, SurfaceSelection, } from '@blocksuite/block-std'; -import { BlockComponent } from '@blocksuite/block-std'; import type { GfxViewportElement } from '@blocksuite/block-std/gfx'; import { assertExists } from '@blocksuite/global/utils'; import { css, html } from 'lit'; @@ -181,7 +181,7 @@ export class EdgelessRootPreviewBlockComponent this.handleEvent('selectionChange', () => { const surface = this.host.selection.value.find( - (sel): sel is SurfaceSelection => sel.is('surface') + (sel): sel is SurfaceSelection => sel.is(SurfaceSelection) ); if (!surface) return; diff --git a/blocksuite/blocks/src/root-block/keyboard/keyboard-manager.ts b/blocksuite/blocks/src/root-block/keyboard/keyboard-manager.ts index da87f578b8..2cf5368274 100644 --- a/blocksuite/blocks/src/root-block/keyboard/keyboard-manager.ts +++ b/blocksuite/blocks/src/root-block/keyboard/keyboard-manager.ts @@ -6,14 +6,18 @@ import { } from '@blocksuite/affine-block-embed'; import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std'; +import { + type BlockComponent, + BlockSelection, + type UIEventHandler, +} from '@blocksuite/block-std'; import { IS_MAC, IS_WINDOWS } from '@blocksuite/global/env'; export class PageKeyboardManager { private readonly _handleDelete: UIEventHandler = ctx => { const event = ctx.get('keyboardState').raw; const blockSelections = this._currentSelection.filter(sel => - sel.is('block') + sel.is(BlockSelection) ); if (blockSelections.length === 0) { return; diff --git a/blocksuite/blocks/src/root-block/page/page-root-block.ts b/blocksuite/blocks/src/root-block/page/page-root-block.ts index fc0986d2e7..2da800b5f6 100644 --- a/blocksuite/blocks/src/root-block/page/page-root-block.ts +++ b/blocksuite/blocks/src/root-block/page/page-root-block.ts @@ -10,7 +10,11 @@ import { matchFlavours, } from '@blocksuite/affine-shared/utils'; import type { PointerEventState } from '@blocksuite/block-std'; -import { BlockComponent } from '@blocksuite/block-std'; +import { + BlockComponent, + BlockSelection, + TextSelection, +} from '@blocksuite/block-std'; import type { BlockModel, Text } from '@blocksuite/store'; import { css, html } from 'lit'; import { query } from 'lit/decorators.js'; @@ -236,7 +240,7 @@ export class PageRootBlockComponent extends BlockComponent< }) .flatMap(model => { return model.children.map(child => { - return this.std.selection.create('block', { + return this.std.selection.create(BlockSelection, { blockId: child.id, }); }); @@ -247,7 +251,7 @@ export class PageRootBlockComponent extends BlockComponent< ArrowUp: () => { const selection = this.host.selection; const sel = selection.value.find( - sel => sel.is('text') || sel.is('block') + sel => sel.is(TextSelection) || sel.is(BlockSelection) ); if (!sel) return; let model: BlockModel | null = null; @@ -262,8 +266,8 @@ export class PageRootBlockComponent extends BlockComponent< if (!model) return; const prevNote = this.doc.getPrev(model); if (!prevNote || prevNote.flavour !== 'affine:note') { - const isFirstText = sel.is('text') && sel.start.index === 0; - const isBlock = sel.is('block'); + const isFirstText = sel.is(TextSelection) && sel.start.index === 0; + const isBlock = sel.is(BlockSelection); if (isBlock || isFirstText) { focusTitle(this.host); } @@ -361,7 +365,7 @@ export class PageRootBlockComponent extends BlockComponent< .then(() => { if (!newTextSelectionId) return; this.host.selection.setGroup('note', [ - this.host.selection.create('text', { + this.host.selection.create(TextSelection, { from: { blockId: newTextSelectionId, index: 0, diff --git a/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts b/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts index cc571adc97..d4657c6687 100644 --- a/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts +++ b/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts @@ -52,7 +52,12 @@ import { ThemeProvider, } from '@blocksuite/affine-shared/services'; import { getHostName, referenceToNode } from '@blocksuite/affine-shared/utils'; -import { type BlockStdScope, WidgetComponent } from '@blocksuite/block-std'; +import { + BlockSelection, + type BlockStdScope, + TextSelection, + WidgetComponent, +} from '@blocksuite/block-std'; import { type BlockModel, Text } from '@blocksuite/store'; import { autoUpdate, computePosition, flip, offset } from '@floating-ui/dom'; import { html, nothing, type TemplateResult } from 'lit'; @@ -709,13 +714,13 @@ export class EmbedCardToolbar extends WidgetComponent< this.disposables.add( this._selection.slots.changed.on(() => { - const hasTextSelection = this._selection.find('text'); + const hasTextSelection = this._selection.find(TextSelection); if (hasTextSelection) { this._hide(); return; } - const blockSelections = this._selection.filter('block'); + const blockSelections = this._selection.filter(BlockSelection); if (!blockSelections || blockSelections.length !== 1) { this._hide(); return; diff --git a/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts b/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts index 5c7541d552..4d373903e9 100644 --- a/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts +++ b/blocksuite/blocks/src/root-block/widgets/format-bar/format-bar.ts @@ -8,12 +8,15 @@ import { } from '@blocksuite/affine-components/toolbar'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; -import type { - BaseSelection, - BlockComponent, +import { + type BaseSelection, + type BlockComponent, + BlockSelection, CursorSelection, + TextSelection, + WidgetComponent, } from '@blocksuite/block-std'; -import { WidgetComponent } from '@blocksuite/block-std'; +import { DatabaseSelection } from '@blocksuite/data-view'; import { assertExists, DisposableGroup, @@ -129,11 +132,12 @@ export class AffineFormatBarWidget extends WidgetComponent { this.disposables.add( this._selectionManager.slots.changed.on(() => { const update = async () => { - const textSelection = rootComponent.selection.find('text'); - const blockSelections = rootComponent.selection.filter('block'); + const textSelection = rootComponent.selection.find(TextSelection); + const blockSelections = + rootComponent.selection.filter(BlockSelection); // Should not re-render format bar when only cursor selection changed in edgeless - const cursorSelection = rootComponent.selection.find('cursor'); + const cursorSelection = rootComponent.selection.find(CursorSelection); if (cursorSelection) { if (!this._lastCursor) { this._lastCursor = cursorSelection; @@ -202,7 +206,7 @@ export class AffineFormatBarWidget extends WidgetComponent { this.disposables.addFromEvent(document, 'selectionchange', () => { if (!this.host.event.active) return; - const databaseSelection = this.host.selection.find('database'); + const databaseSelection = this.host.selection.find(DatabaseSelection); if (!databaseSelection) { return; } diff --git a/blocksuite/blocks/src/root-block/widgets/image-toolbar/index.ts b/blocksuite/blocks/src/root-block/widgets/image-toolbar/index.ts index e2abf26529..f2467a8b62 100644 --- a/blocksuite/blocks/src/root-block/widgets/image-toolbar/index.ts +++ b/blocksuite/blocks/src/root-block/widgets/image-toolbar/index.ts @@ -10,7 +10,11 @@ import { } from '@blocksuite/affine-components/toolbar'; import type { ImageBlockModel } from '@blocksuite/affine-model'; import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts'; -import { WidgetComponent } from '@blocksuite/block-std'; +import { + BlockSelection, + TextSelection, + WidgetComponent, +} from '@blocksuite/block-std'; import { limitShift, shift } from '@floating-ui/dom'; import { html } from 'lit'; @@ -35,7 +39,7 @@ export class AffineImageToolbarWidget extends WidgetComponent< const imageBlock = this.block; const selection = this.host.selection; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if ( !!textSelection && (!!textSelection.to || !!textSelection.from.length) @@ -43,7 +47,7 @@ export class AffineImageToolbarWidget extends WidgetComponent< return null; } - const blockSelections = selection.filter('block'); + const blockSelections = selection.filter(BlockSelection); if ( blockSelections.length > 1 || (blockSelections.length === 1 && diff --git a/blocksuite/blocks/src/root-block/widgets/image-toolbar/utils.ts b/blocksuite/blocks/src/root-block/widgets/image-toolbar/utils.ts index e7810c9895..4893f47571 100644 --- a/blocksuite/blocks/src/root-block/widgets/image-toolbar/utils.ts +++ b/blocksuite/blocks/src/root-block/widgets/image-toolbar/utils.ts @@ -3,6 +3,7 @@ import { getBlockProps, isInsidePageEditor, } from '@blocksuite/affine-shared/utils'; +import { BlockSelection } from '@blocksuite/block-std'; import { assertExists } from '@blocksuite/global/utils'; export function duplicate( @@ -38,7 +39,7 @@ export function duplicate( .then(() => { const { selection } = editorHost; selection.setGroup('note', [ - selection.create('block', { + selection.create(BlockSelection, { blockId: duplicateId, }), ]); diff --git a/blocksuite/blocks/src/root-block/widgets/page-dragging-area/page-dragging-area.ts b/blocksuite/blocks/src/root-block/widgets/page-dragging-area/page-dragging-area.ts index 588c73fe6c..fb785f50b0 100644 --- a/blocksuite/blocks/src/root-block/widgets/page-dragging-area/page-dragging-area.ts +++ b/blocksuite/blocks/src/root-block/widgets/page-dragging-area/page-dragging-area.ts @@ -7,6 +7,7 @@ import { import { BLOCK_ID_ATTR, BlockComponent, + BlockSelection, type PointerEventState, WidgetComponent, } from '@blocksuite/block-std'; @@ -188,7 +189,7 @@ export class AffinePageDraggingAreaWidget extends WidgetComponent< this._allBlocksWithRect, userRect ).map(blockPath => { - return this.host.selection.create('block', { + return this.host.selection.create(BlockSelection, { blockId: blockPath, }); }); diff --git a/blocksuite/blocks/src/root-block/widgets/slash-menu/index.ts b/blocksuite/blocks/src/root-block/widgets/slash-menu/index.ts index e177f22039..e083653995 100644 --- a/blocksuite/blocks/src/root-block/widgets/slash-menu/index.ts +++ b/blocksuite/blocks/src/root-block/widgets/slash-menu/index.ts @@ -7,7 +7,7 @@ import { matchFlavours, } from '@blocksuite/affine-shared/utils'; import type { UIEventStateContext } from '@blocksuite/block-std'; -import { WidgetComponent } from '@blocksuite/block-std'; +import { TextSelection, WidgetComponent } from '@blocksuite/block-std'; import { assertExists, assertType, @@ -122,7 +122,7 @@ export class AffineSlashMenuWidget extends WidgetComponent { } } - const textSelection = this.host.selection.find('text'); + const textSelection = this.host.selection.find(TextSelection); if (!textSelection) return; const model = this.host.doc.getBlock(textSelection.blockId)?.model; @@ -149,7 +149,7 @@ export class AffineSlashMenuWidget extends WidgetComponent { assertType(rootComponent); inlineRangeApplyCallback(() => { - const textSelection = this.host.selection.find('text'); + const textSelection = this.host.selection.find(TextSelection); if (!textSelection) return; const model = this.host.doc.getBlock(textSelection.blockId)?.model; diff --git a/blocksuite/blocks/src/root-block/widgets/slash-menu/utils.ts b/blocksuite/blocks/src/root-block/widgets/slash-menu/utils.ts index e9011f6174..3170cc27b0 100644 --- a/blocksuite/blocks/src/root-block/widgets/slash-menu/utils.ts +++ b/blocksuite/blocks/src/root-block/widgets/slash-menu/utils.ts @@ -3,6 +3,7 @@ import type { TextFormatConfig, } from '@blocksuite/affine-components/rich-text'; import { isInsideBlockByFlavour } from '@blocksuite/affine-shared/utils'; +import { BlockSelection } from '@blocksuite/block-std'; import { assertType } from '@blocksuite/global/utils'; import type { BlockModel } from '@blocksuite/store'; @@ -128,7 +129,7 @@ export function createTextFormatItem( .chain() .formatBlock({ blockSelections: [ - std.selection.create('block', { + std.selection.create(BlockSelection, { blockId: model.id, }), ], diff --git a/blocksuite/blocks/src/root-block/widgets/surface-ref-toolbar/surface-ref-toolbar.ts b/blocksuite/blocks/src/root-block/widgets/surface-ref-toolbar/surface-ref-toolbar.ts index be4e345f36..2d9e715ba2 100644 --- a/blocksuite/blocks/src/root-block/widgets/surface-ref-toolbar/surface-ref-toolbar.ts +++ b/blocksuite/blocks/src/root-block/widgets/surface-ref-toolbar/surface-ref-toolbar.ts @@ -19,7 +19,11 @@ import { } from '@blocksuite/affine-components/toolbar'; import type { SurfaceRefBlockModel } from '@blocksuite/affine-model'; import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts'; -import { WidgetComponent } from '@blocksuite/block-std'; +import { + BlockSelection, + TextSelection, + WidgetComponent, +} from '@blocksuite/block-std'; import { offset, shift } from '@floating-ui/dom'; import { html, nothing } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; @@ -48,7 +52,7 @@ export class AffineSurfaceRefToolbar extends WidgetComponent< const surfaceRefBlock = this.block; const selection = this.host.selection; - const textSelection = selection.find('text'); + const textSelection = selection.find(TextSelection); if ( !!textSelection && (!!textSelection.to || !!textSelection.from.length) @@ -56,7 +60,7 @@ export class AffineSurfaceRefToolbar extends WidgetComponent< return null; } - const blockSelections = selection.filter('block'); + const blockSelections = selection.filter(BlockSelection); if ( blockSelections.length > 1 || (blockSelections.length === 1 && diff --git a/blocksuite/framework/block-std/src/gfx/selection.ts b/blocksuite/framework/block-std/src/gfx/selection.ts index 387e3c5c12..ae9509916f 100644 --- a/blocksuite/framework/block-std/src/gfx/selection.ts +++ b/blocksuite/framework/block-std/src/gfx/selection.ts @@ -7,7 +7,12 @@ import { Slot, } from '@blocksuite/global/utils'; -import type { CursorSelection, SurfaceSelection } from '../selection/index.js'; +import { + BlockSelection, + CursorSelection, + SurfaceSelection, + TextSelection, +} from '../selection/index.js'; import type { GfxController } from './controller.js'; import { GfxExtension, GfxExtensionIdentifier } from './extension.js'; import type { GfxModel } from './model/model.js'; @@ -215,9 +220,9 @@ export class GfxSelectionManager extends GfxExtension { this.disposable.add( this.stdSelection.slots.changed.on(selections => { const { cursor = [], surface = [] } = groupBy(selections, sel => { - if (sel.is('surface')) { + if (sel.is(SurfaceSelection)) { return 'surface'; - } else if (sel.is('cursor')) { + } else if (sel.is(CursorSelection)) { return 'cursor'; } @@ -261,15 +266,15 @@ export class GfxSelectionManager extends GfxExtension { let hasBlockSelection = false; selections.forEach(selection => { - if (selection.is('text')) { + if (selection.is(TextSelection)) { hasTextSelection = true; } - if (selection.is('block')) { + if (selection.is(BlockSelection)) { hasBlockSelection = true; } - if (selection.is('surface')) { + if (selection.is(SurfaceSelection)) { const surfaceSelections = surfaceMap.get(id) ?? []; surfaceSelections.push(selection); surfaceMap.set(id, surfaceSelections); @@ -277,7 +282,7 @@ export class GfxSelectionManager extends GfxExtension { selection.elements.forEach(id => selectedSet.add(id)); } - if (selection.is('cursor')) { + if (selection.is(CursorSelection)) { cursorMap.set(id, selection); } }); @@ -318,7 +323,7 @@ export class GfxSelectionManager extends GfxExtension { if (elements.length > 0 && this.surfaceModel) { instances.push( this.stdSelection.create( - 'surface', + SurfaceSelection, this.surfaceModel.id, elements, selection.editing ?? false, @@ -331,7 +336,7 @@ export class GfxSelectionManager extends GfxExtension { instances = instances.concat( blocks.map(blockId => this.stdSelection.create( - 'surface', + SurfaceSelection, blockId, [blockId], selection.editing ?? false, @@ -368,7 +373,11 @@ export class GfxSelectionManager extends GfxExtension { } setCursor(cursor: CursorSelection | IPoint) { - const instance = this.stdSelection.create('cursor', cursor.x, cursor.y); + const instance = this.stdSelection.create( + CursorSelection, + cursor.x, + cursor.y + ); this.stdSelection.setGroup('gfx', [...this.surfaceSelections, instance]); } diff --git a/blocksuite/framework/block-std/src/range/inline-range-provider.ts b/blocksuite/framework/block-std/src/range/inline-range-provider.ts index 53902b7fbb..90280f9dae 100644 --- a/blocksuite/framework/block-std/src/range/inline-range-provider.ts +++ b/blocksuite/framework/block-std/src/range/inline-range-provider.ts @@ -1,7 +1,7 @@ import type { InlineRange, InlineRangeProvider } from '@blocksuite/inline'; import { signal } from '@preact/signals-core'; -import type { TextSelection } from '../selection/index.js'; +import { TextSelection } from '../selection/index.js'; import type { BlockComponent } from '../view/element/block-component.js'; export const getInlineRangeProvider: ( @@ -40,7 +40,7 @@ export const getInlineRangeProvider: ( } const elementRange = rangeManager.textSelectionToRange( - selectionManager.create('text', { + selectionManager.create(TextSelection, { from: { index: 0, blockId: element.blockId, @@ -72,7 +72,7 @@ export const getInlineRangeProvider: ( if (!inlineRange) { selectionManager.clear(['text']); } else { - const textSelection = selectionManager.create('text', { + const textSelection = selectionManager.create(TextSelection, { from: { blockId: element.blockId, index: inlineRange.index, diff --git a/blocksuite/framework/block-std/src/range/range-binding.ts b/blocksuite/framework/block-std/src/range/range-binding.ts index d7c9d704da..849fa1c2c1 100644 --- a/blocksuite/framework/block-std/src/range/range-binding.ts +++ b/blocksuite/framework/block-std/src/range/range-binding.ts @@ -1,7 +1,7 @@ import { throttle } from '@blocksuite/global/utils'; import type { BlockModel } from '@blocksuite/store'; -import type { BaseSelection, TextSelection } from '../selection/index.js'; +import { type BaseSelection, TextSelection } from '../selection/index.js'; import type { BlockComponent } from '../view/element/block-component.js'; import { BLOCK_ID_ATTR } from '../view/index.js'; import { RANGE_SYNC_EXCLUDE_ATTR } from './consts.js'; @@ -30,7 +30,7 @@ export class RangeBinding { }; private readonly _onBeforeInput = (event: InputEvent) => { - const selection = this.selectionManager.find('text'); + const selection = this.selectionManager.find(TextSelection); if (!selection) return; if (event.isComposing) return; @@ -74,7 +74,7 @@ export class RangeBinding { }); }); - const newSelection = this.selectionManager.create('text', { + const newSelection = this.selectionManager.create(TextSelection, { from: { blockId: from.blockId, index: from.index + (event.data?.length ?? 0), @@ -95,7 +95,7 @@ export class RangeBinding { }; private readonly _onCompositionStart = () => { - const selection = this.selectionManager.find('text'); + const selection = this.selectionManager.find(TextSelection); if (!selection) return; const { from, to } = selection; @@ -153,7 +153,7 @@ export class RangeBinding { await this.host.updateComplete; - const selection = this.selectionManager.create('text', { + const selection = this.selectionManager.create(TextSelection, { from: { blockId: from.blockId, index: from.index + (event.data?.length ?? 0), @@ -249,7 +249,7 @@ export class RangeBinding { private readonly _onStdSelectionChanged = (selections: BaseSelection[]) => { const text = selections.find((selection): selection is TextSelection => - selection.is('text') + selection.is(TextSelection) ) ?? null; if (text === this._prevTextSelection) { diff --git a/blocksuite/framework/block-std/src/range/range-manager.ts b/blocksuite/framework/block-std/src/range/range-manager.ts index 3c5125c359..c647e4d018 100644 --- a/blocksuite/framework/block-std/src/range/range-manager.ts +++ b/blocksuite/framework/block-std/src/range/range-manager.ts @@ -1,7 +1,7 @@ import { INLINE_ROOT_ATTR, type InlineRootElement } from '@blocksuite/inline'; import { LifeCycleWatcher } from '../extension/index.js'; -import type { TextSelection } from '../selection/index.js'; +import { TextSelection } from '../selection/index.js'; import type { BlockComponent } from '../view/element/block-component.js'; import { BLOCK_ID_ATTR } from '../view/index.js'; import { RANGE_QUERY_EXCLUDE_ATTR, RANGE_SYNC_EXCLUDE_ATTR } from './consts.js'; @@ -163,7 +163,7 @@ export class RangeManager extends LifeCycleWatcher { return null; } - return this.std.host.selection.create('text', { + return this.std.host.selection.create(TextSelection, { from: { blockId: startBlock.blockId, index: startInlineRange.index, diff --git a/blocksuite/framework/block-std/src/selection/base.ts b/blocksuite/framework/block-std/src/selection/base.ts index 012b39f5f5..b2433ccbbd 100644 --- a/blocksuite/framework/block-std/src/selection/base.ts +++ b/blocksuite/framework/block-std/src/selection/base.ts @@ -1,10 +1,6 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -type SelectionConstructor = { - type: string; - group: string; - new (...args: unknown[]): T; -}; +import type { SelectionConstructor } from './manager'; export type BaseSelectionOptions = { blockId: string; @@ -21,9 +17,8 @@ export abstract class BaseSelection { return (this.constructor as SelectionConstructor).group; } - get type(): BlockSuite.SelectionType { - return (this.constructor as SelectionConstructor) - .type as BlockSuite.SelectionType; + get type(): string { + return (this.constructor as SelectionConstructor).type as string; } constructor({ blockId }: BaseSelectionOptions) { @@ -39,10 +34,10 @@ export abstract class BaseSelection { abstract equals(other: BaseSelection): boolean; - is( + is( type: T - ): this is BlockSuite.SelectionInstance[T] { - return this.type === type; + ): this is T extends SelectionConstructor ? U : never { + return this.type === type.type; } abstract toJSON(): Record; diff --git a/blocksuite/framework/block-std/src/selection/index.ts b/blocksuite/framework/block-std/src/selection/index.ts index dd335a9b90..cdb6841fb7 100644 --- a/blocksuite/framework/block-std/src/selection/index.ts +++ b/blocksuite/framework/block-std/src/selection/index.ts @@ -1,27 +1,3 @@ -import type { - BlockSelection, - CursorSelection, - SurfaceSelection, - TextSelection, -} from './variants/index.js'; - export * from './base.js'; export * from './manager.js'; export * from './variants/index.js'; - -declare global { - namespace BlockSuite { - interface Selection { - block: typeof BlockSelection; - cursor: typeof CursorSelection; - surface: typeof SurfaceSelection; - text: typeof TextSelection; - } - - type SelectionType = keyof Selection; - - type SelectionInstance = { - [P in SelectionType]: InstanceType; - }; - } -} diff --git a/blocksuite/framework/block-std/src/selection/manager.ts b/blocksuite/framework/block-std/src/selection/manager.ts index be66a5c0dd..2137bda8a5 100644 --- a/blocksuite/framework/block-std/src/selection/manager.ts +++ b/blocksuite/framework/block-std/src/selection/manager.ts @@ -8,11 +8,12 @@ import { SelectionIdentifier } from '../identifier.js'; import type { BlockStdScope } from '../scope/index.js'; import type { BaseSelection } from './base.js'; -export interface SelectionConstructor { +export interface SelectionConstructor { type: string; + group: string; - new (...args: any[]): BaseSelection; - fromJSON(json: Record): BaseSelection; + new (...args: any[]): T; + fromJSON(json: Record): T; } export class SelectionManager extends LifeCycleWatcher { @@ -143,18 +144,11 @@ export class SelectionManager extends LifeCycleWatcher { } } - create( - type: T, - ...args: ConstructorParameters - ): BlockSuite.SelectionInstance[T] { - const ctor = this._selectionConstructors[type]; - if (!ctor) { - throw new BlockSuiteError( - ErrorCode.SelectionError, - `Unknown selection type: ${type}` - ); - } - return new ctor(...args) as BlockSuite.SelectionInstance[T]; + create( + Type: T, + ...args: ConstructorParameters + ): InstanceType { + return new Type(...args) as InstanceType; } dispose() { @@ -162,27 +156,23 @@ export class SelectionManager extends LifeCycleWatcher { this.disposables.dispose(); } - filter(type: T) { + filter(type: T) { return this.filter$(type).value; } - filter$(type: T) { + filter$(type: T) { return computed(() => - this.value.filter((sel): sel is BlockSuite.SelectionInstance[T] => - sel.is(type) - ) + this.value.filter((sel): sel is InstanceType => sel.is(type)) ); } - find(type: T) { + find(type: T) { return this.find$(type).value; } - find$(type: T) { + find$(type: T) { return computed(() => - this.value.find((sel): sel is BlockSuite.SelectionInstance[T] => - sel.is(type) - ) + this.value.find((sel): sel is InstanceType => sel.is(type)) ); } diff --git a/blocksuite/presets/src/fragments/comment/comment-input.ts b/blocksuite/presets/src/fragments/comment/comment-input.ts index aa72746254..93e933661e 100644 --- a/blocksuite/presets/src/fragments/comment/comment-input.ts +++ b/blocksuite/presets/src/fragments/comment/comment-input.ts @@ -1,5 +1,4 @@ -import type { TextSelection } from '@blocksuite/block-std'; -import { ShadowlessElement } from '@blocksuite/block-std'; +import { ShadowlessElement, TextSelection } from '@blocksuite/block-std'; import type { RichText } from '@blocksuite/blocks'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, nothing } from 'lit'; @@ -69,7 +68,7 @@ export class CommentInput extends WithDisposable(ShadowlessElement) { } override render() { - const textSelection = this.host.selection.find('text'); + const textSelection = this.host.selection.find(TextSelection); if (!textSelection) { this.remove(); return nothing; diff --git a/blocksuite/presets/src/fragments/comment/comment-panel.ts b/blocksuite/presets/src/fragments/comment/comment-panel.ts index 095a07801c..1a2f86ab89 100644 --- a/blocksuite/presets/src/fragments/comment/comment-panel.ts +++ b/blocksuite/presets/src/fragments/comment/comment-panel.ts @@ -1,4 +1,4 @@ -import { ShadowlessElement } from '@blocksuite/block-std'; +import { ShadowlessElement, TextSelection } from '@blocksuite/block-std'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html } from 'lit'; import { property, query } from 'lit/decorators.js'; @@ -60,7 +60,7 @@ export class CommentPanel extends WithDisposable(ShadowlessElement) { commentManager: CommentManager | null = null; private _addComment() { - const textSelection = this.editor.host?.selection.find('text'); + const textSelection = this.editor.host?.selection.find(TextSelection); if (!textSelection) return; const commentInput = new CommentInput(); diff --git a/blocksuite/tests-legacy/utils/asserts.ts b/blocksuite/tests-legacy/utils/asserts.ts index 9a5a88f642..07de81c25b 100644 --- a/blocksuite/tests-legacy/utils/asserts.ts +++ b/blocksuite/tests-legacy/utils/asserts.ts @@ -11,7 +11,11 @@ import { DEFAULT_NOTE_WIDTH, DefaultTheme, } from '@blocksuite/affine-model'; -import type { BlockComponent, EditorHost } from '@blocksuite/block-std'; +import type { + BlockComponent, + EditorHost, + TextSelection, +} from '@blocksuite/block-std'; import { BLOCK_ID_ATTR } from '@blocksuite/block-std'; import { assertExists } from '@blocksuite/global/utils'; import type { InlineRootElement } from '@inline/inline-editor.js'; @@ -1180,7 +1184,7 @@ export async function assertBlockSelections(page: Page, paths: string[]) { if (!host) { throw new Error('editor-host host not found'); } - return host.selection.filter('block'); + return host.selection.value.filter(b => b.type === 'block'); }); const actualPaths = selections.map(selection => selection.blockId); expect(actualPaths).toEqual(paths); @@ -1199,13 +1203,13 @@ export async function assertTextSelection( length: number; } ) { - const selection = await page.evaluate(() => { + const selection = (await page.evaluate(() => { const host = document.querySelector('editor-host'); if (!host) { throw new Error('editor-host host not found'); } - return host.selection.find('text'); - }); + return host.selection.value.find(b => b.type === 'text'); + })) as TextSelection | undefined; if (!from && !to) { expect(selection).toBeUndefined(); diff --git a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts index 678dbbddf3..bf6a0a2605 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts @@ -1,7 +1,7 @@ import { WorkspaceImpl } from '@affine/core/modules/workspace/impls/workspace'; -import type { - EditorHost, - TextRangePoint, +import { + type EditorHost, + type TextRangePoint, TextSelection, } from '@blocksuite/affine/block-std'; import { @@ -68,7 +68,7 @@ function processSnapshot( */ function processTextInSnapshot(snapshot: SliceSnapshot, host: EditorHost) { const { content } = snapshot; - const text = host.selection.find('text'); + const text = host.selection.find(TextSelection); if (!content.length || !text) return; content.forEach(snapshot => processSnapshot(snapshot, text, host)); 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 bc53ffed29..ec4b30a37e 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 @@ -1,7 +1,7 @@ import { ChatHistoryOrder } from '@affine/graphql'; -import type { +import { BlockSelection, - EditorHost, + type EditorHost, TextSelection, } from '@blocksuite/affine/block-std'; import type { @@ -198,8 +198,8 @@ const REPLACE_SELECTION = { icon: ReplaceIcon, title: 'Replace selection', showWhen: (host: EditorHost) => { - const textSelection = host.selection.find('text'); - const blockSelections = host.selection.filter('block'); + const textSelection = host.selection.find(TextSelection); + const blockSelections = host.selection.filter(BlockSelection); if ( (!textSelection || textSelection.from.length === 0) && blockSelections?.length === 0 diff --git a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-toolbar.ts b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-toolbar.ts index 71e821cdc2..43915fd3ff 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-toolbar.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/_common/components/ask-ai-toolbar.ts @@ -1,4 +1,8 @@ -import type { EditorHost } from '@blocksuite/affine/block-std'; +import { + BlockSelection, + type EditorHost, + TextSelection, +} from '@blocksuite/affine/block-std'; import { type AffineAIPanelWidgetConfig, type AIItemGroupConfig, @@ -92,8 +96,8 @@ export class AskAIToolbarButton extends WithDisposable(LitElement) { this._panelRoot.style.visibility = text ? 'hidden' : 'visible'; }; - const textSelection = this.host.selection.find('text'); - const blockSelections = this.host.selection.filter('block'); + const textSelection = this.host.selection.find(TextSelection); + const blockSelections = this.host.selection.filter(BlockSelection); let lastBlockId: string | undefined; if (textSelection) { lastBlockId = textSelection.to?.blockId ?? textSelection.blockId; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts index 8560053d26..060adf8131 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts @@ -1,4 +1,4 @@ -import type { EditorHost } from '@blocksuite/affine/block-std'; +import { type EditorHost, TextSelection } from '@blocksuite/affine/block-std'; import type { AffineAIPanelWidget, AffineAIPanelWidgetConfig, @@ -209,7 +209,7 @@ export function actionToHandler( export function handleInlineAskAIAction(host: EditorHost) { const panel = getAIPanelWidget(host); - const selection = host.selection.find('text'); + const selection = host.selection.find(TextSelection); const lastBlockPath = selection ? (selection.to?.blockId ?? selection.blockId) : null; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/page-response.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/page-response.ts index 48b81f4dc7..d5c1387a00 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/page-response.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/page-response.ts @@ -1,4 +1,4 @@ -import type { EditorHost } from '@blocksuite/affine/block-std'; +import { type EditorHost, TextSelection } from '@blocksuite/affine/block-std'; import { GfxBlockElementModel, type GfxModel, @@ -214,7 +214,7 @@ async function insertMarkdownAbove(host: EditorHost) { } function getSelection(host: EditorHost) { - const textSelection = host.selection.find('text'); + const textSelection = host.selection.find(TextSelection); const mode = textSelection ? 'flat' : 'highest'; const { selectedBlocks } = getSelections(host, mode); if (!selectedBlocks) return; 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 109379e3c8..3428f6dfcd 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 @@ -9,6 +9,8 @@ const buttonOptions: AskAIButtonOptions = { panelWidth: 240, }; +import { BlockSelection } from '@blocksuite/affine/block-std'; + import type { AskAIButtonOptions } from '../../_common/components/ask-ai-button'; import { buildAICodeItemGroups } from '../../_common/config'; @@ -22,7 +24,9 @@ export function setupCodeToolbarAIEntry(codeToolbar: AffineCodeToolbarWidget) { action: () => { const { selection } = host; selection.setGroup('note', [ - selection.create('block', { blockId: blockComponent.blockId }), + selection.create(BlockSelection, { + blockId: blockComponent.blockId, + }), ]); }, render: item => 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 00e5269b84..407e977674 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,6 +1,9 @@ import '../../_common/components/ask-ai-button'; -import type { AffineImageToolbarWidget } from '@blocksuite/affine/blocks'; +import { + type AffineImageToolbarWidget, + ImageSelection, +} from '@blocksuite/affine/blocks'; import { html } from 'lit'; import type { AskAIButtonOptions } from '../../_common/components/ask-ai-button'; @@ -26,7 +29,9 @@ export function setupImageToolbarAIEntry( action: () => { const { selection } = host; selection.setGroup('note', [ - selection.create('image', { blockId: blockComponent.blockId }), + selection.create(ImageSelection, { + blockId: blockComponent.blockId, + }), ]); }, render: item => diff --git a/packages/frontend/core/src/blocksuite/presets/ai/entries/space/setup-space.ts b/packages/frontend/core/src/blocksuite/presets/ai/entries/space/setup-space.ts index 57b7aa8f85..84e35c7421 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/entries/space/setup-space.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/entries/space/setup-space.ts @@ -1,3 +1,4 @@ +import { TextSelection } from '@blocksuite/affine/block-std'; import type { AffineAIPanelWidget } from '@blocksuite/affine/blocks'; import { handleInlineAskAIAction } from '../../actions/doc-handler'; @@ -12,7 +13,7 @@ export function setupSpaceAIEntry(panel: AffineAIPanelWidget) { keyboardState.raw.key === ' ' && !keyboardState.raw.isComposing ) { - const selection = host.selection.find('text'); + const selection = host.selection.find(TextSelection); if (selection && selection.isCollapsed() && selection.from.index === 0) { const block = host.view.getBlock(selection.blockId); if (!block?.model?.text || block.model.text?.length > 0) return; diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts index 0cc176b6b6..5cf05c6b07 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts @@ -1,7 +1,9 @@ -import type { - BlockComponent, - EditorHost, - TextSelection, +import { + type BlockComponent, + BlockSelection, + type EditorHost, + SurfaceSelection, + type TextSelection, } from '@blocksuite/affine/block-std'; import type { AffineAIPanelWidget } from '@blocksuite/affine/blocks'; import { isInsideEdgelessEditor } from '@blocksuite/affine/blocks'; @@ -32,12 +34,12 @@ const setBlockSelection = ( ) => { const selections = models .map(model => model.id) - .map(blockId => host.selection.create('block', { blockId })); + .map(blockId => host.selection.create(BlockSelection, { blockId })); if (isInsideEdgelessEditor(host)) { const surfaceElementId = getNoteId(parent); const surfaceSelection = host.selection.create( - 'surface', + SurfaceSelection, selections[0].blockId, [surfaceElementId], true 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 51c3fe3b79..bc48324ba7 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 @@ -1,4 +1,4 @@ -import type { EditorHost } from '@blocksuite/affine/block-std'; +import { type EditorHost, TextSelection } from '@blocksuite/affine/block-std'; import { BlocksUtils, type CopilotTool, @@ -174,7 +174,7 @@ export async function selectAboveBlocks(editorHost: EditorHost, num = 10) { const { selection } = editorHost; selection.set([ - selection.create('text', { + selection.create(TextSelection, { from: { blockId: startBlock.id, index: 0, @@ -183,7 +183,7 @@ export async function selectAboveBlocks(editorHost: EditorHost, num = 10) { to: { blockId: lastLeafModel.id, index: 0, - length: selection.find('text')?.from.index ?? 0, + length: selection.find(TextSelection)?.from.index ?? 0, }, }), ]); diff --git a/packages/frontend/core/src/components/hooks/use-register-workspace-commands.ts b/packages/frontend/core/src/components/hooks/use-register-workspace-commands.ts index 160e930a2a..c8082ba8ca 100644 --- a/packages/frontend/core/src/components/hooks/use-register-workspace-commands.ts +++ b/packages/frontend/core/src/components/hooks/use-register-workspace-commands.ts @@ -5,6 +5,7 @@ import { I18nService } from '@affine/core/modules/i18n'; import { UrlService } from '@affine/core/modules/url'; import { WorkspaceService } from '@affine/core/modules/workspace'; import { useI18n } from '@affine/i18n'; +import { TextSelection } from '@blocksuite/affine/block-std'; import type { AffineEditorContainer } from '@blocksuite/affine/presets'; import { useService, useServiceOptional } from '@toeverything/infra'; import { useStore } from 'jotai'; @@ -29,7 +30,7 @@ import { useActiveBlocksuiteEditor } from './use-block-suite-editor'; import { useNavigateHelper } from './use-navigate-helper'; function hasLinkPopover(editor: AffineEditorContainer | null) { - const textSelection = editor?.host?.std.selection.find('text'); + const textSelection = editor?.host?.std.selection.find(TextSelection); if (editor && textSelection && textSelection.from.length > 0) { const formatBar = editor.host?.querySelector('affine-format-bar-widget'); if (formatBar) { diff --git a/packages/frontend/core/src/modules/editor/entities/editor.ts b/packages/frontend/core/src/modules/editor/entities/editor.ts index bc64e1f48c..347f92d378 100644 --- a/packages/frontend/core/src/modules/editor/entities/editor.ts +++ b/packages/frontend/core/src/modules/editor/entities/editor.ts @@ -2,6 +2,7 @@ import type { DefaultOpenProperty } from '@affine/core/components/doc-properties import { type DocMode, EdgelessRootService, + HighlightSelection, type ReferenceParams, } from '@blocksuite/affine/blocks'; import type { @@ -118,7 +119,6 @@ export class Editor extends Entity { const stablePrimaryMode = this.doc.getPrimaryMode(); - // eslint-disable-next-line rxjs/finnish const viewParams$ = view .queryString$( paramsParseOptions @@ -235,7 +235,7 @@ export class Editor extends Entity { if (mode === this.mode$.value) { selection?.setGroup('scene', [ - selection?.create('highlight', { + selection?.create(HighlightSelection, { mode, [key]: [id], }), @@ -290,7 +290,7 @@ export class Editor extends Entity { const { id, key, mode } = anchor; selection.setGroup('scene', [ - selection.create('highlight', { + selection.create(HighlightSelection, { mode, [key]: [id], }),