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],
}),