refactor(editor): remove gfx tool global type (#12116)

Closes: BS-2650
This commit is contained in:
Saul-Mirone
2025-05-04 13:53:26 +00:00
parent f3b5c36cf7
commit 30a2e5b4fb
95 changed files with 664 additions and 521 deletions
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import { BookmarkBlockSchema } from '@blocksuite/affine-model'; import { BookmarkBlockSchema } from '@blocksuite/affine-model';
import { import {
@@ -5,6 +6,7 @@ import {
SlashMenuConfigIdentifier, SlashMenuConfigIdentifier,
} from '@blocksuite/affine-widget-slash-menu'; } from '@blocksuite/affine-widget-slash-menu';
import { LinkIcon } from '@blocksuite/icons/lit'; import { LinkIcon } from '@blocksuite/icons/lit';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import type { ExtensionType } from '@blocksuite/store'; import type { ExtensionType } from '@blocksuite/store';
import { LinkTooltip } from './tooltips'; import { LinkTooltip } from './tooltips';
@@ -33,7 +35,13 @@ const bookmarkSlashMenuConfig: SlashMenuConfig = {
host, host,
'Links', 'Links',
'The added link will be displayed as a card view.', 'The added link will be displayed as a card view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
) )
.then(() => { .then(() => {
if (model.text?.length === 0) { if (model.text?.length === 0) {
@@ -13,6 +13,7 @@
"@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-gfx-pointer": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*", "@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*", "@blocksuite/affine-rich-text": "workspace:*",
@@ -1,4 +1,5 @@
import { import {
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
SurfaceBlockComponent, SurfaceBlockComponent,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
@@ -82,10 +83,7 @@ export function insertEmbedCard(
surfaceBlock.model surfaceBlock.model
); );
gfx.tool.setTool( gfx.tool.setTool(DefaultTool);
// @ts-expect-error FIXME: resolve after gfx tool refactor
'default'
);
gfx.selection.set({ gfx.selection.set({
elements: [cardId], elements: [cardId],
editing: false, editing: false,
@@ -1,6 +1,8 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu'; import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { FigmaDuotoneIcon } from '@blocksuite/icons/lit'; import { FigmaDuotoneIcon } from '@blocksuite/icons/lit';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { FigmaTooltip } from './tooltips'; import { FigmaTooltip } from './tooltips';
@@ -29,7 +31,13 @@ export const embedFigmaSlashMenuConfig: SlashMenuConfig = {
host, host,
'Figma', 'Figma',
'The added Figma link will be displayed as an embed view.', 'The added Figma link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) std.store.deleteBlock(model); if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error); })().catch(console.error);
@@ -1,6 +1,8 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu'; import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { GithubDuotoneIcon } from '@blocksuite/icons/lit'; import { GithubDuotoneIcon } from '@blocksuite/icons/lit';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { GithubRepoTooltip } from './tooltips'; import { GithubRepoTooltip } from './tooltips';
@@ -29,7 +31,13 @@ export const embedGithubSlashMenuConfig: SlashMenuConfig = {
host, host,
'GitHub', 'GitHub',
'The added GitHub issue or pull request link will be displayed as a card view.', 'The added GitHub issue or pull request link will be displayed as a card view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) std.store.deleteBlock(model); if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error); })().catch(console.error);
@@ -1,4 +1,5 @@
import { import {
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
SurfaceBlockComponent, SurfaceBlockComponent,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
@@ -90,10 +91,7 @@ export const insertEmbedIframeWithUrlCommand: Command<
surfaceBlock.model surfaceBlock.model
); );
gfx.tool.setTool( gfx.tool.setTool(DefaultTool);
// @ts-expect-error FIXME: resolve after gfx tool refactor
'default'
);
gfx.selection.set({ gfx.selection.set({
elements: [newBlockId], elements: [newBlockId],
@@ -1,6 +1,8 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu'; import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { LoomLogoDuotoneIcon } from '@blocksuite/icons/lit'; import { LoomLogoDuotoneIcon } from '@blocksuite/icons/lit';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { LoomTooltip } from './tooltips'; import { LoomTooltip } from './tooltips';
@@ -29,7 +31,13 @@ export const embedLoomSlashMenuConfig: SlashMenuConfig = {
host, host,
'Loom', 'Loom',
'The added Loom video link will be displayed as an embed view.', 'The added Loom video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) std.store.deleteBlock(model); if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error); })().catch(console.error);
@@ -1,6 +1,8 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu'; import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { YoutubeDuotoneIcon } from '@blocksuite/icons/lit'; import { YoutubeDuotoneIcon } from '@blocksuite/icons/lit';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { YoutubeVideoTooltip } from './tooltips'; import { YoutubeVideoTooltip } from './tooltips';
@@ -29,7 +31,13 @@ export const embedYoutubeSlashMenuConfig: SlashMenuConfig = {
host, host,
'YouTube', 'YouTube',
'The added YouTube video link will be displayed as an embed view.', 'The added YouTube video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) std.store.deleteBlock(model); if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error); })().catch(console.error);
@@ -10,6 +10,7 @@
{ "path": "../surface" }, { "path": "../surface" },
{ "path": "../../components" }, { "path": "../../components" },
{ "path": "../../ext-loader" }, { "path": "../../ext-loader" },
{ "path": "../../gfx/pointer" },
{ "path": "../../inlines/reference" }, { "path": "../../inlines/reference" },
{ "path": "../../model" }, { "path": "../../model" },
{ "path": "../../rich-text" }, { "path": "../../rich-text" },
@@ -13,6 +13,7 @@
"@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-gfx-pointer": "workspace:*",
"@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*", "@blocksuite/affine-shared": "workspace:*",
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*", "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
@@ -1,29 +1,30 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { menu } from '@blocksuite/affine-components/context-menu'; import { menu } from '@blocksuite/affine-components/context-menu';
import type { DenseMenuBuilder } from '@blocksuite/affine-widget-edgeless-toolbar'; import type { DenseMenuBuilder } from '@blocksuite/affine-widget-edgeless-toolbar';
import { FrameIcon } from '@blocksuite/icons/lit'; import { FrameIcon } from '@blocksuite/icons/lit';
import { EdgelessFrameManagerIdentifier } from '../frame-manager.js'; import { EdgelessFrameManagerIdentifier } from '../frame-manager.js';
import { FrameTool } from '../frame-tool';
import { FrameConfig } from './config.js'; import { FrameConfig } from './config.js';
export const buildFrameDenseMenu: DenseMenuBuilder = (edgeless, gfx) => export const buildFrameDenseMenu: DenseMenuBuilder = (edgeless, gfx) =>
menu.subMenu({ menu.subMenu({
name: 'Frame', name: 'Frame',
prefix: FrameIcon({ width: '20px', height: '20px' }), prefix: FrameIcon({ width: '20px', height: '20px' }),
select: () => gfx.tool.setTool({ type: 'frame' }), select: () => gfx.tool.setTool(FrameTool),
isSelected: gfx.tool.currentToolName$.peek() === 'frame', isSelected: gfx.tool.currentToolName$.peek() === 'frame',
options: { options: {
items: [ items: [
menu.action({ menu.action({
name: 'Custom', name: 'Custom',
select: () => gfx.tool.setTool({ type: 'frame' }), select: () => gfx.tool.setTool(FrameTool),
}), }),
...FrameConfig.map(config => ...FrameConfig.map(config =>
menu.action({ menu.action({
name: `Slide ${config.name}`, name: `Slide ${config.name}`,
select: () => { select: () => {
const frame = edgeless.std.get(EdgelessFrameManagerIdentifier); const frame = edgeless.std.get(EdgelessFrameManagerIdentifier);
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
frame.createFrameOnViewportCenter(config.wh); frame.createFrameOnViewportCenter(config.wh);
}, },
}) })
@@ -1,9 +1,10 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import { EdgelessFrameManagerIdentifier } from '../frame-manager.js'; import { EdgelessFrameManagerIdentifier } from '../frame-manager.js';
import { FrameTool } from '../frame-tool';
import { FrameConfig } from './config.js'; import { FrameConfig } from './config.js';
export class EdgelessFrameMenu extends EdgelessToolbarToolMixin(LitElement) { export class EdgelessFrameMenu extends EdgelessToolbarToolMixin(LitElement) {
@@ -65,7 +66,7 @@ export class EdgelessFrameMenu extends EdgelessToolbarToolMixin(LitElement) {
} }
`; `;
override type: GfxToolsFullOptionValue['type'] = 'frame'; override type = FrameTool;
get frameManager() { get frameManager() {
return this.edgeless.std.get(EdgelessFrameManagerIdentifier); return this.edgeless.std.get(EdgelessFrameManagerIdentifier);
@@ -84,8 +85,7 @@ export class EdgelessFrameMenu extends EdgelessToolbarToolMixin(LitElement) {
(item, index) => html` (item, index) => html`
<div <div
@click=${() => { @click=${() => {
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
frameManager.createFrameOnViewportCenter(item.wh); frameManager.createFrameOnViewportCenter(item.wh);
}} }}
class="frame-add-button ${index}" class="frame-add-button ${index}"
@@ -1,8 +1,9 @@
import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import { FrameIcon } from '@blocksuite/icons/lit'; import { FrameIcon } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { FrameTool } from '../frame-tool';
export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) { export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) {
static override styles = css` static override styles = css`
:host { :host {
@@ -10,7 +11,7 @@ export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) {
} }
`; `;
override type: GfxToolsFullOptionValue['type'] = 'frame'; override type = FrameTool;
private _toggleFrameMenu() { private _toggleFrameMenu() {
if (this.tryDisposePopper()) return; if (this.tryDisposePopper()) return;
@@ -20,7 +21,7 @@ export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) {
} }
override render() { override render() {
const type = this.edgelessTool?.type; const type = this.edgelessTool?.toolType?.toolName;
return html` return html`
<edgeless-tool-icon-button <edgeless-tool-icon-button
class="edgeless-frame-button" class="edgeless-frame-button"
@@ -37,7 +38,7 @@ export class EdgelessFrameToolButton extends QuickToolMixin(LitElement) {
@click=${() => { @click=${() => {
// don't update tool before toggling menu // don't update tool before toggling menu
this._toggleFrameMenu(); this._toggleFrameMenu();
this.setEdgelessTool({ type: 'frame' }); this.setEdgelessTool(FrameTool);
}} }}
> >
${FrameIcon()} ${FrameIcon()}
@@ -1,5 +1,9 @@
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
EdgelessLegacySlotIdentifier,
} from '@blocksuite/affine-block-surface';
import { toast } from '@blocksuite/affine-components/toast'; import { toast } from '@blocksuite/affine-components/toast';
import { PanTool } from '@blocksuite/affine-gfx-pointer';
import type { FrameBlockModel } from '@blocksuite/affine-model'; import type { FrameBlockModel } from '@blocksuite/affine-model';
import { import {
EditPropsStore, EditPropsStore,
@@ -16,7 +20,7 @@ import {
StopAiIcon, StopAiIcon,
} from '@blocksuite/icons/lit'; } from '@blocksuite/icons/lit';
import type { BlockComponent } from '@blocksuite/std'; import type { BlockComponent } from '@blocksuite/std';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx'; import type { ToolOptions } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { cssVar } from '@toeverything/theme'; import { cssVar } from '@toeverything/theme';
import { css, html, LitElement, nothing, type PropertyValues } from 'lit'; import { css, html, LitElement, nothing, type PropertyValues } from 'lit';
@@ -27,6 +31,7 @@ import {
isFrameBlock, isFrameBlock,
type NavigatorMode, type NavigatorMode,
} from '../frame-manager'; } from '../frame-manager';
import { PresentTool } from '../present-tool';
export class PresentationToolbar extends EdgelessToolbarToolMixin( export class PresentationToolbar extends EdgelessToolbarToolMixin(
SignalWatcher(LitElement) SignalWatcher(LitElement)
@@ -114,7 +119,7 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
private _timer?: ReturnType<typeof setTimeout>; private _timer?: ReturnType<typeof setTimeout>;
override type: GfxToolsFullOptionValue['type'] = 'frameNavigator'; override type = PresentTool;
private get _cachedPresentHideToolbar() { private get _cachedPresentHideToolbar() {
return !!this.edgeless.std return !!this.edgeless.std
@@ -151,7 +156,7 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
private _bindHotKey() { private _bindHotKey() {
const handleKeyIfFrameNavigator = (action: () => void) => () => { const handleKeyIfFrameNavigator = (action: () => void) => () => {
if (this.edgelessTool.type === 'frameNavigator') { if (this.edgelessTool.toolType === PresentTool) {
action(); action();
} }
}; };
@@ -171,11 +176,11 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
private _exitPresentation() { private _exitPresentation() {
// When exit presentation mode, we need to set the tool to default or pan // When exit presentation mode, we need to set the tool to default or pan
// And exit fullscreen // And exit fullscreen
const tool = this.edgeless.doc.readonly if (this.edgeless.doc.readonly) {
? { type: 'pan', panning: false } this.setEdgelessTool(PanTool, { panning: false });
: { type: 'default' }; } else {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool(tool); }
if (document.fullscreenElement) { if (document.fullscreenElement) {
document.exitFullscreen().catch(console.error); document.exitFullscreen().catch(console.error);
@@ -261,9 +266,11 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
const currentTool = this.gfx.tool.currentToolOption$.value; const currentTool = this.gfx.tool.currentToolOption$.value;
const selection = this.gfx.selection; const selection = this.gfx.selection;
if (currentTool?.type === 'frameNavigator') { if (currentTool?.toolType === PresentTool) {
this._cachedIndex = this._currentFrameIndex; this._cachedIndex = this._currentFrameIndex;
this._navigatorMode = currentTool.mode ?? this._navigatorMode; this._navigatorMode =
(currentTool.options as ToolOptions<PresentTool>)?.mode ??
this._navigatorMode;
if (isFrameBlock(selection.selectedElements[0])) { if (isFrameBlock(selection.selectedElements[0])) {
this._cachedIndex = this._frames.findIndex( this._cachedIndex = this._frames.findIndex(
frame => frame.id === selection.selectedElements[0].id frame => frame.id === selection.selectedElements[0].id
@@ -306,14 +313,14 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
// When exit fullscreen, we need to clear the timer // When exit fullscreen, we need to clear the timer
clearTimeout(this._timer); clearTimeout(this._timer);
if ( if (
this.edgelessTool.type === 'frameNavigator' && this.edgelessTool.toolType === PresentTool &&
this._fullScreenMode this._fullScreenMode
) { ) {
const tool = this.edgeless.doc.readonly if (this.edgeless.doc.readonly) {
? { type: 'pan', panning: false } this.setEdgelessTool(PanTool, { panning: false });
: { type: 'default' }; } else {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool(tool); }
} }
} }
@@ -425,7 +432,7 @@ export class PresentationToolbar extends EdgelessToolbarToolMixin(
protected override updated(changedProperties: PropertyValues) { protected override updated(changedProperties: PropertyValues) {
if ( if (
changedProperties.has('_currentFrameIndex') && changedProperties.has('_currentFrameIndex') &&
this.edgelessTool.type === 'frameNavigator' this.edgelessTool.toolType === PresentTool
) { ) {
this._moveToCurrentFrame(); this._moveToCurrentFrame();
} }
@@ -1,4 +1,7 @@
import { OverlayIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
OverlayIdentifier,
} from '@blocksuite/affine-block-surface';
import type { FrameBlockModel } from '@blocksuite/affine-model'; import type { FrameBlockModel } from '@blocksuite/affine-model';
import { import {
EditPropsStore, EditPropsStore,
@@ -39,8 +42,7 @@ export class FrameTool extends BaseTool {
if (this._frame) { if (this._frame) {
const frame = this._frame; const frame = this._frame;
frame.pop('xywh'); frame.pop('xywh');
// @ts-expect-error TODO: refactor gfx tool this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.gfx.selection.set({ this.gfx.selection.set({
elements: [frame.id], elements: [frame.id],
editing: false, editing: false,
+2 -2
View File
@@ -1,5 +1,5 @@
import type { FrameTool } from './frame-tool'; import type { FrameTool } from './frame-tool';
import type { PresentTool, PresentToolOption } from './preset-tool'; import type { PresentTool, PresentToolOption } from './present-tool';
export * from './edgeless-clipboard-config'; export * from './edgeless-clipboard-config';
export * from './edgeless-toolbar'; export * from './edgeless-toolbar';
@@ -9,7 +9,7 @@ export * from './frame-manager';
export * from './frame-spec'; export * from './frame-spec';
export * from './frame-tool'; export * from './frame-tool';
export * from './frame-toolbar'; export * from './frame-toolbar';
export * from './preset-tool'; export * from './present-tool';
declare module '@blocksuite/std/gfx' { declare module '@blocksuite/std/gfx' {
interface GfxToolsMap { interface GfxToolsMap {
@@ -9,6 +9,8 @@ import { css, html, nothing } from 'lit';
import { state } from 'lit/decorators.js'; import { state } from 'lit/decorators.js';
import { literal, unsafeStatic } from 'lit/static-html.js'; import { literal, unsafeStatic } from 'lit/static-html.js';
import { PresentTool } from '../present-tool';
export const EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET = export const EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET =
'edgeless-navigator-black-background'; 'edgeless-navigator-black-background';
export class EdgelessNavigatorBlackBackgroundWidget extends WidgetComponent<RootBlockModel> { export class EdgelessNavigatorBlackBackgroundWidget extends WidgetComponent<RootBlockModel> {
@@ -59,7 +61,7 @@ export class EdgelessNavigatorBlackBackgroundWidget extends WidgetComponent<Root
this.show = this.show =
blackBackground && blackBackground &&
this.gfx.tool.currentToolOption$.peek().type === 'frameNavigator'; this.gfx.tool.currentToolOption$.peek().toolType === PresentTool;
} }
}) })
); );
@@ -3,9 +3,10 @@ import {
QuickToolMixin, QuickToolMixin,
} from '@blocksuite/affine-widget-edgeless-toolbar'; } from '@blocksuite/affine-widget-edgeless-toolbar';
import { PresentationIcon } from '@blocksuite/icons/lit'; import { PresentationIcon } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { PresentTool } from '../present-tool';
export class EdgelessPresentButton extends QuickToolMixin( export class EdgelessPresentButton extends QuickToolMixin(
EdgelessToolbarToolMixin(LitElement) EdgelessToolbarToolMixin(LitElement)
) { ) {
@@ -19,7 +20,7 @@ export class EdgelessPresentButton extends QuickToolMixin(
} }
`; `;
override type: GfxToolsFullOptionValue['type'] = 'frameNavigator'; override type = PresentTool;
override render() { override render() {
return html`<edgeless-tool-icon-button return html`<edgeless-tool-icon-button
@@ -29,9 +30,7 @@ export class EdgelessPresentButton extends QuickToolMixin(
.iconContainerPadding=${6} .iconContainerPadding=${6}
.iconSize=${'24px'} .iconSize=${'24px'}
@click=${() => { @click=${() => {
this.setEdgelessTool({ this.setEdgelessTool(PresentTool);
type: 'frameNavigator',
});
}} }}
> >
${PresentationIcon()} ${PresentationIcon()}
+1 -1
View File
@@ -11,7 +11,7 @@ import { FrameBlockSpec } from './frame-spec';
import { FrameTool } from './frame-tool'; import { FrameTool } from './frame-tool';
import { frameToolbarExtension } from './frame-toolbar'; import { frameToolbarExtension } from './frame-toolbar';
import { edgelessNavigatorBgWidget } from './present/navigator-bg-widget'; import { edgelessNavigatorBgWidget } from './present/navigator-bg-widget';
import { PresentTool } from './preset-tool'; import { PresentTool } from './present-tool';
export class FrameViewExtension extends ViewExtensionProvider { export class FrameViewExtension extends ViewExtensionProvider {
override name = 'affine-frame-block'; override name = 'affine-frame-block';
@@ -10,6 +10,7 @@
{ "path": "../surface" }, { "path": "../surface" },
{ "path": "../../components" }, { "path": "../../components" },
{ "path": "../../ext-loader" }, { "path": "../../ext-loader" },
{ "path": "../../gfx/pointer" },
{ "path": "../../model" }, { "path": "../../model" },
{ "path": "../../shared" }, { "path": "../../shared" },
{ "path": "../../widgets/edgeless-toolbar" }, { "path": "../../widgets/edgeless-toolbar" },
@@ -2,6 +2,7 @@ import { addAttachments } from '@blocksuite/affine-block-attachment';
import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame'; import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame';
import { addImages } from '@blocksuite/affine-block-image'; import { addImages } from '@blocksuite/affine-block-image';
import { import {
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
ExportManager, ExportManager,
getSurfaceComponent, getSurfaceComponent,
@@ -608,7 +609,7 @@ export class EdgelessClipboardController extends PageClipboard {
elements: [noteId], elements: [noteId],
editing: false, editing: false,
}); });
this.gfx.tool.setTool('default'); this.gfx.tool.setTool(DefaultTool);
} }
copy() { copy() {
@@ -1,7 +1,7 @@
import { import {
DefaultModeDragType, DefaultModeDragType,
DefaultTool, DefaultTool,
} from '@blocksuite/affine-gfx-pointer'; } from '@blocksuite/affine-block-surface';
import type { RootBlockModel } from '@blocksuite/affine-model'; import type { RootBlockModel } from '@blocksuite/affine-model';
import { WidgetComponent } from '@blocksuite/std'; import { WidgetComponent } from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx'; import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
@@ -41,6 +41,7 @@ export class EdgelessDraggingAreaRectWidget extends WidgetComponent<RootBlockMod
if ( if (
rect.w === 0 || rect.w === 0 ||
rect.h === 0 || rect.h === 0 ||
!tool ||
!(tool instanceof DefaultTool) || !(tool instanceof DefaultTool) ||
tool.dragType !== DefaultModeDragType.Selecting tool.dragType !== DefaultModeDragType.Selecting
) )
@@ -3,6 +3,7 @@ import {
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
getSurfaceComponent, getSurfaceComponent,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { ConnectorTool } from '@blocksuite/affine-gfx-connector';
import { import {
createGroupCommand, createGroupCommand,
createGroupFromSelectedCommand, createGroupFromSelectedCommand,
@@ -196,9 +197,9 @@ export const builtinMiscToolbarConfig = {
const point = ctx.gfx.viewport.toViewCoordFromClientCoord([x, y]); const point = ctx.gfx.viewport.toViewCoordFromClientCoord([x, y]);
ctx.store.captureSync(); ctx.store.captureSync();
ctx.gfx.tool.setTool('connector', { mode: DEFAULT_CONNECTOR_MODE }); ctx.gfx.tool.setTool(ConnectorTool, { mode: DEFAULT_CONNECTOR_MODE });
const ctc = ctx.gfx.tool.get('connector'); const ctc = ctx.gfx.tool.get(ConnectorTool);
ctc.quickConnect(point, models[0]); ctc.quickConnect(point, models[0]);
}; };
@@ -1,8 +1,17 @@
import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark'; import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark';
import { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text'; import { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text';
import { isNoteBlock } from '@blocksuite/affine-block-surface'; import { FrameTool } from '@blocksuite/affine-block-frame';
import { DefaultTool, isNoteBlock } from '@blocksuite/affine-block-surface';
import { toast } from '@blocksuite/affine-components/toast'; import { toast } from '@blocksuite/affine-components/toast';
import { mountConnectorLabelEditor } from '@blocksuite/affine-gfx-connector'; import {
BrushTool,
EraserTool,
HighlighterTool,
} from '@blocksuite/affine-gfx-brush';
import {
ConnectorTool,
mountConnectorLabelEditor,
} from '@blocksuite/affine-gfx-connector';
import { import {
createGroupFromSelectedCommand, createGroupFromSelectedCommand,
ungroupCommand, ungroupCommand,
@@ -12,7 +21,10 @@ import {
isElementOutsideViewport, isElementOutsideViewport,
isSingleMindMapNode, isSingleMindMapNode,
} from '@blocksuite/affine-gfx-mindmap'; } from '@blocksuite/affine-gfx-mindmap';
import { NoteTool } from '@blocksuite/affine-gfx-note';
import { PanTool } from '@blocksuite/affine-gfx-pointer';
import { mountShapeTextEditor, ShapeTool } from '@blocksuite/affine-gfx-shape'; import { mountShapeTextEditor, ShapeTool } from '@blocksuite/affine-gfx-shape';
import { TextTool } from '@blocksuite/affine-gfx-text';
import { import {
ConnectorElementModel, ConnectorElementModel,
ConnectorMode, ConnectorMode,
@@ -33,11 +45,12 @@ import { IS_MAC } from '@blocksuite/global/env';
import { Bound, getCommonBound } from '@blocksuite/global/gfx'; import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import { SurfaceSelection, TextSelection } from '@blocksuite/std'; import { SurfaceSelection, TextSelection } from '@blocksuite/std';
import { import {
type BaseTool,
GfxBlockElementModel, GfxBlockElementModel,
type GfxPrimitiveElementModel, type GfxPrimitiveElementModel,
type GfxToolsMap,
type GfxToolsOption,
isGfxGroupCompatibleModel, isGfxGroupCompatibleModel,
type ToolOptions,
type ToolType,
} from '@blocksuite/std/gfx'; } from '@blocksuite/std/gfx';
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js'; import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
@@ -61,38 +74,38 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
this.rootComponent.bindHotKey( this.rootComponent.bindHotKey(
{ {
v: () => { v: () => {
this._setEdgelessTool('default'); this._setEdgelessTool(DefaultTool);
}, },
t: () => { t: () => {
this._setEdgelessTool('text'); this._setEdgelessTool(TextTool);
}, },
c: () => { c: () => {
const mode = ConnectorMode.Curve; const mode = ConnectorMode.Curve;
rootComponent.std.get(EditPropsStore).recordLastProps('connector', { rootComponent.std.get(EditPropsStore).recordLastProps('connector', {
mode, mode,
}); });
this._setEdgelessTool('connector', { mode }); this._setEdgelessTool(ConnectorTool, { mode });
}, },
h: () => { h: () => {
this._setEdgelessTool('pan', { this._setEdgelessTool(PanTool, {
panning: false, panning: false,
}); });
}, },
n: () => { n: () => {
this._setEdgelessTool('affine:note', { this._setEdgelessTool(NoteTool, {
childFlavour: DEFAULT_NOTE_CHILD_FLAVOUR, childFlavour: DEFAULT_NOTE_CHILD_FLAVOUR,
childType: DEFAULT_NOTE_CHILD_TYPE, childType: DEFAULT_NOTE_CHILD_TYPE,
tip: DEFAULT_NOTE_TIP, tip: DEFAULT_NOTE_TIP,
}); });
}, },
p: () => { p: () => {
this._setEdgelessTool('brush'); this._setEdgelessTool(BrushTool);
}, },
'Shift-p': () => { 'Shift-p': () => {
this._setEdgelessTool('highlighter'); this._setEdgelessTool(HighlighterTool);
}, },
e: () => { e: () => {
this._setEdgelessTool('eraser'); this._setEdgelessTool(EraserTool);
}, },
k: () => { k: () => {
if (this.rootComponent.service.locked) return; if (this.rootComponent.service.locked) return;
@@ -128,7 +141,7 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
}); });
rootComponent.surface.fitToViewport(Bound.deserialize(frame.xywh)); rootComponent.surface.fitToViewport(Bound.deserialize(frame.xywh));
} else if (!this.rootComponent.service.selection.editing) { } else if (!this.rootComponent.service.selection.editing) {
this._setEdgelessTool('frame'); this._setEdgelessTool(FrameTool);
} }
}, },
'-': () => { '-': () => {
@@ -184,7 +197,7 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
} }
const { shapeName } = controller.activatedOption; const { shapeName } = controller.activatedOption;
const nextShapeName = getNextShapeType(shapeName); const nextShapeName = getNextShapeType(shapeName);
this._setEdgelessTool('shape', { this._setEdgelessTool(ShapeTool, {
shapeName: nextShapeName, shapeName: nextShapeName,
}); });
@@ -633,11 +646,9 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
}); });
} }
private _setEdgelessTool<K extends keyof GfxToolsMap>( private _setEdgelessTool<T extends BaseTool>(
toolName: K, toolType: ToolType<T>,
...options: K extends keyof GfxToolsOption ...options: [options?: ToolOptions<T>, ignoreActiveState?: boolean]
? [option: GfxToolsOption[K], ignoreActiveState?: boolean]
: [option: void, ignoreActiveState?: boolean]
) { ) {
const ignoreActiveState = const ignoreActiveState =
typeof options === 'boolean' typeof options === 'boolean'
@@ -651,9 +662,8 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
return; return;
} }
this.rootComponent.gfx.tool.setTool<K>( this.rootComponent.gfx.tool.setTool(
toolName, toolType,
// @ts-expect-error FIXME: ts error
options[0] !== undefined && typeof options[0] !== 'boolean' options[0] !== undefined && typeof options[0] !== 'boolean'
? options[0] ? options[0]
: undefined : undefined
@@ -678,8 +688,7 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
const revertToPrevTool = (ev: KeyboardEvent) => { const revertToPrevTool = (ev: KeyboardEvent) => {
if (ev.code === 'Space') { if (ev.code === 'Space') {
this._setEdgelessTool( this._setEdgelessTool(
// @ts-expect-error FIXME: ts error (currentTool as DefaultTool).constructor as typeof DefaultTool,
currentTool.toolName,
currentTool?.activatedOption currentTool?.activatedOption
); );
selection.set(currentSel); selection.set(currentSel);
@@ -694,7 +703,7 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
) { ) {
return; return;
} }
this._setEdgelessTool('pan', { panning: false }); this._setEdgelessTool(PanTool, { panning: false });
edgeless.dispatcher.disposables.addFromEvent( edgeless.dispatcher.disposables.addFromEvent(
document, document,
@@ -1,14 +1,14 @@
import { NoteConfigExtension } from '@blocksuite/affine-block-note'; import { NoteConfigExtension } from '@blocksuite/affine-block-note';
import type {
SurfaceBlockComponent,
SurfaceBlockModel,
} from '@blocksuite/affine-block-surface';
import { import {
DefaultTool,
EdgelessLegacySlotIdentifier, EdgelessLegacySlotIdentifier,
getBgGridGap, getBgGridGap,
normalizeWheelDeltaY, normalizeWheelDeltaY,
type SurfaceBlockComponent,
type SurfaceBlockModel,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { isSingleMindMapNode } from '@blocksuite/affine-gfx-mindmap'; import { isSingleMindMapNode } from '@blocksuite/affine-gfx-mindmap';
import { PanTool } from '@blocksuite/affine-gfx-pointer';
import { mountShapeTextEditor } from '@blocksuite/affine-gfx-shape'; import { mountShapeTextEditor } from '@blocksuite/affine-gfx-shape';
import { import {
NoteBlockModel, NoteBlockModel,
@@ -468,9 +468,9 @@ export class EdgelessRootBlockComponent extends BlockComponent<
this._initPinchEvent(); this._initPinchEvent();
if (this.doc.readonly) { if (this.doc.readonly) {
this.gfx.tool.setTool('pan', { panning: true }); this.gfx.tool.setTool(PanTool, { panning: true });
} else { } else {
this.gfx.tool.setTool('default'); this.gfx.tool.setTool(DefaultTool);
} }
this.gfx.viewport.elementReady.next(this.gfxViewportElm); this.gfx.viewport.elementReady.next(this.gfxViewportElm);
@@ -1,4 +1,5 @@
import type { CanvasElementWithText } from '@blocksuite/affine-block-surface'; import type { CanvasElementWithText } from '@blocksuite/affine-block-surface';
import type { PanTool } from '@blocksuite/affine-gfx-pointer';
import { import {
type AttachmentBlockModel, type AttachmentBlockModel,
type BookmarkBlockModel, type BookmarkBlockModel,
@@ -26,7 +27,7 @@ import { Bound } from '@blocksuite/global/gfx';
import type { import type {
GfxModel, GfxModel,
GfxPrimitiveElementModel, GfxPrimitiveElementModel,
GfxToolsFullOptionValue, ToolOptionWithType,
} from '@blocksuite/std/gfx'; } from '@blocksuite/std/gfx';
import type { BlockModel } from '@blocksuite/store'; import type { BlockModel } from '@blocksuite/store';
@@ -191,15 +192,17 @@ export function isConnectable(
} }
// https://developer.mozilla.org/en-US/docs/Web/CSS/cursor // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
export function getCursorMode(edgelessTool: GfxToolsFullOptionValue | null) { export function getCursorMode(edgelessTool: ToolOptionWithType) {
if (!edgelessTool) { if (!edgelessTool) {
return 'default'; return 'default';
} }
switch (edgelessTool.type) { switch (edgelessTool.toolType?.toolName) {
case 'default': case 'default':
return 'default'; return 'default';
case 'pan': case 'pan':
return edgelessTool.panning ? 'grabbing' : 'grab'; return (edgelessTool as ToolOptionWithType<PanTool>).options?.panning
? 'grabbing'
: 'grab';
case 'brush': case 'brush':
case 'highlighter': case 'highlighter':
return drawingCursor; return drawingCursor;
@@ -32,9 +32,8 @@ export {
PageSurfaceBlockSpec, PageSurfaceBlockSpec,
} from './surface-spec.js'; } from './surface-spec.js';
export { SurfaceBlockTransformer } from './surface-transformer.js'; export { SurfaceBlockTransformer } from './surface-transformer.js';
export * from './tool/default-tool.js';
export { export {
addNote,
addNoteAtPoint,
generateElementId, generateElementId,
getBgGridGap, getBgGridGap,
getLastPropsKey, getLastPropsKey,
@@ -10,7 +10,7 @@ import {
} from '@blocksuite/std/gfx'; } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { calPanDelta } from '../utils/panning-utils.js'; import { calPanDelta } from './panning-utils.js';
export enum DefaultModeDragType { export enum DefaultModeDragType {
/** Moving selected contents */ /** Moving selected contents */
@@ -1,137 +0,0 @@
import {
DEFAULT_NOTE_HEIGHT,
DEFAULT_NOTE_WIDTH,
NOTE_MIN_HEIGHT,
type NoteBlockModel,
NoteDisplayMode,
} from '@blocksuite/affine-model';
import { focusTextModel } from '@blocksuite/affine-rich-text';
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
import { handleNativeRangeAtPoint } from '@blocksuite/affine-shared/utils';
import { type IPoint, type Point, serializeXYWH } from '@blocksuite/global/gfx';
import type { BlockStdScope } from '@blocksuite/std';
import {
type GfxBlockElementModel,
GfxControllerIdentifier,
} from '@blocksuite/std/gfx';
import { DEFAULT_NOTE_OFFSET_X, DEFAULT_NOTE_OFFSET_Y } from '../consts';
import { EdgelessCRUDIdentifier } from '../extensions/crud-extension';
export function addNoteAtPoint(
std: BlockStdScope,
/**
* The point is in browser coordinate
*/
point: IPoint,
options: {
width?: number;
height?: number;
parentId?: string;
noteIndex?: number;
offsetX?: number;
offsetY?: number;
scale?: number;
} = {}
) {
const gfx = std.get(GfxControllerIdentifier);
const crud = std.get(EdgelessCRUDIdentifier);
const {
width = DEFAULT_NOTE_WIDTH,
height = DEFAULT_NOTE_HEIGHT,
offsetX = DEFAULT_NOTE_OFFSET_X,
offsetY = DEFAULT_NOTE_OFFSET_Y,
parentId = gfx.doc.root?.id,
noteIndex,
scale = 1,
} = options;
const [x, y] = gfx.viewport.toModelCoord(point.x, point.y);
const blockId = crud.addBlock(
'affine:note',
{
xywh: serializeXYWH(
x - offsetX * scale,
y - offsetY * scale,
width,
height
),
displayMode: NoteDisplayMode.EdgelessOnly,
},
parentId,
noteIndex
);
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
control: 'canvas:draw',
page: 'whiteboard editor',
module: 'toolbar',
segment: 'toolbar',
type: 'note',
});
return blockId;
}
type NoteOptions = {
childFlavour: NoteChildrenFlavour;
childType: string | null;
collapse: boolean;
};
export function addNote(
std: BlockStdScope,
point: Point,
options: NoteOptions,
width = DEFAULT_NOTE_WIDTH,
height = DEFAULT_NOTE_HEIGHT
) {
const noteId = addNoteAtPoint(std, point, {
width,
height,
});
const gfx = std.get(GfxControllerIdentifier);
const doc = std.store;
const blockId = doc.addBlock(
options.childFlavour,
{ type: options.childType },
noteId
);
if (options.collapse && height > NOTE_MIN_HEIGHT) {
const note = doc.getModelById(noteId) as NoteBlockModel;
doc.updateBlock(note, () => {
note.props.edgeless.collapse = true;
note.props.edgeless.collapsedHeight = height;
});
}
gfx.tool.setTool(
// @ts-expect-error FIXME: resolve after gfx tool refactor
'default'
);
// Wait for edgelessTool updated
requestAnimationFrame(() => {
const blocks =
(doc.root?.children.filter(
child => child.flavour === 'affine:note'
) as GfxBlockElementModel[]) ?? [];
const element = blocks.find(b => b.id === noteId);
if (element) {
gfx.selection.set({
elements: [element.id],
editing: true,
});
// Waiting dom updated, `note mask` is removed
if (blockId) {
focusTextModel(gfx.std, blockId);
} else {
// Cannot reuse `handleNativeRangeClick` directly here,
// since `retargetClick` will re-target to pervious editor
handleNativeRangeAtPoint(point.x, point.y);
}
}
});
}
@@ -33,7 +33,6 @@ export function normalizeWheelDeltaY(delta: number, zoom = 1) {
return newZoom; return newZoom;
} }
export { addNote, addNoteAtPoint } from './add-note';
export { getBgGridGap } from './get-bg-grip-gap'; export { getBgGridGap } from './get-bg-grip-gap';
export { getLastPropsKey } from './get-last-props-key'; export { getLastPropsKey } from './get-last-props-key';
export * from './get-surface-block'; export * from './get-surface-block';
@@ -12,6 +12,7 @@ import {
EditPropsMiddlewareBuilder, EditPropsMiddlewareBuilder,
} from './extensions'; } from './extensions';
import { ExportManagerExtension } from './extensions/export-manager/export-manager'; import { ExportManagerExtension } from './extensions/export-manager/export-manager';
import { DefaultTool } from './tool/default-tool';
export class SurfaceViewExtension extends ViewExtensionProvider { export class SurfaceViewExtension extends ViewExtensionProvider {
override name = 'affine-surface-block'; override name = 'affine-surface-block';
@@ -30,6 +31,7 @@ export class SurfaceViewExtension extends ViewExtensionProvider {
ExportManagerExtension, ExportManagerExtension,
]); ]);
if (this.isEdgeless(context.scope)) { if (this.isEdgeless(context.scope)) {
context.register(DefaultTool);
context.register( context.register(
BlockViewExtension('affine:surface', literal`affine-surface`) BlockViewExtension('affine:surface', literal`affine-surface`)
); );
@@ -62,13 +62,8 @@ export class EmbedCardCreateModal extends SignalWatcher(
} }
this.createOptions.onSave(url); this.createOptions.onSave(url);
gfx.tool.setTool(
// @ts-expect-error FIXME: resolve after gfx tool refactor
'default'
);
} }
this.onConfirm(); this.onConfirm({ mode });
this.remove(); this.remove();
}; };
@@ -176,7 +171,7 @@ export class EmbedCardCreateModal extends SignalWatcher(
accessor input!: HTMLInputElement; accessor input!: HTMLInputElement;
@property({ attribute: false }) @property({ attribute: false })
accessor onConfirm!: () => void; accessor onConfirm!: (options: { mode: 'edgeless' | 'page' }) => void;
@property({ attribute: false }) @property({ attribute: false })
accessor titleText!: string; accessor titleText!: string;
@@ -195,7 +190,8 @@ export async function toggleEmbedCardCreateModal(
| { | {
mode: 'edgeless'; mode: 'edgeless';
onSave: (url: string) => void; onSave: (url: string) => void;
} },
onConfirm: (options: { mode: 'page' | 'edgeless' }) => void
): Promise<void> { ): Promise<void> {
host.selection.clear(); host.selection.clear();
@@ -208,7 +204,10 @@ export async function toggleEmbedCardCreateModal(
document.body.append(embedCardCreateModal); document.body.append(embedCardCreateModal);
return new Promise(resolve => { return new Promise(resolve => {
embedCardCreateModal.onConfirm = () => resolve(); embedCardCreateModal.onConfirm = options => {
onConfirm(options);
resolve();
};
}); });
} }
@@ -1,4 +1,7 @@
import type { NavigatorMode } from '@blocksuite/affine-block-frame'; import {
type NavigatorMode,
PresentTool,
} from '@blocksuite/affine-block-frame';
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
import { import {
DocModeProvider, DocModeProvider,
@@ -124,8 +127,7 @@ export class FramePanelHeader extends WithDisposable(LitElement) {
} }
setTimeout(() => { setTimeout(() => {
this._gfx.tool.setTool({ this._gfx.tool.setTool(PresentTool, {
type: 'frameNavigator',
mode: this._navigatorMode, mode: this._navigatorMode,
}); });
}, 100); }, 100);
@@ -1,8 +1,9 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { EraserTool } from '../../../eraser-tool';
import { EdgelessEraserDarkIcon, EdgelessEraserLightIcon } from './icons.js'; import { EdgelessEraserDarkIcon, EdgelessEraserLightIcon } from './icons.js';
export class EdgelessEraserToolButton extends EdgelessToolbarToolMixin( export class EdgelessEraserToolButton extends EdgelessToolbarToolMixin(
@@ -33,16 +34,15 @@ export class EdgelessEraserToolButton extends EdgelessToolbarToolMixin(
override enableActiveBackground = true; override enableActiveBackground = true;
override type: GfxToolsFullOptionValue['type'] = 'eraser'; override type = EraserTool;
override firstUpdated() { override firstUpdated() {
this.disposables.add( this.disposables.add(
this.edgeless.bindHotKey( this.edgeless.bindHotKey(
{ {
Escape: () => { Escape: () => {
if (this.edgelessTool.type === 'eraser') { if (this.edgelessTool.toolType === EraserTool) {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
} }
}, },
}, },
@@ -52,7 +52,7 @@ export class EdgelessEraserToolButton extends EdgelessToolbarToolMixin(
} }
override render() { override render() {
const type = this.edgelessTool?.type; const type = this.edgelessTool?.toolType;
const appTheme = this.edgeless.std.get(ThemeProvider).app$.value; const appTheme = this.edgeless.std.get(ThemeProvider).app$.value;
const icon = const icon =
appTheme === 'dark' ? EdgelessEraserDarkIcon : EdgelessEraserLightIcon; appTheme === 'dark' ? EdgelessEraserDarkIcon : EdgelessEraserLightIcon;
@@ -65,8 +65,8 @@ export class EdgelessEraserToolButton extends EdgelessToolbarToolMixin(
data-shortcut="${'E'}" data-shortcut="${'E'}"
></affine-tooltip-content-with-shortcut>`} ></affine-tooltip-content-with-shortcut>`}
.tooltipOffset=${4} .tooltipOffset=${4}
.active=${type === 'eraser'} .active=${type === EraserTool}
@click=${() => this.setEdgelessTool({ type: 'eraser' })} @click=${() => this.setEdgelessTool(EraserTool)}
> >
<div class="eraser-button">${icon}</div> <div class="eraser-button">${icon}</div>
</edgeless-toolbar-button> </edgeless-toolbar-button>
@@ -16,6 +16,8 @@ import { css, html, LitElement, type TemplateResult } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
import { BrushTool } from '../../../brush-tool';
import { HighlighterTool } from '../../../highlighter-tool';
import { penInfoMap } from './consts'; import { penInfoMap } from './consts';
import type { Pen, PenMap } from './types'; import type { Pen, PenMap } from './types';
@@ -80,7 +82,11 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
private readonly _onPickPen = (tool: Pen) => { private readonly _onPickPen = (tool: Pen) => {
this.pen$.value = tool; this.pen$.value = tool;
this.setEdgelessTool(tool); if (tool === 'brush') {
this.setEdgelessTool(BrushTool);
} else {
this.setEdgelessTool(HighlighterTool);
}
}; };
private readonly _onPickColor = (e: ColorEvent) => { private readonly _onPickColor = (e: ColorEvent) => {
@@ -91,7 +97,7 @@ export class EdgelessPenMenu extends EdgelessToolbarToolMixin(
this.onChange({ color }); this.onChange({ color });
}; };
override type: Pen[] = ['brush', 'highlighter']; override type = [BrushTool, HighlighterTool];
override render() { override render() {
const { const {
@@ -10,6 +10,8 @@ import { css, html, LitElement, nothing } from 'lit';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
import { when } from 'lit/directives/when.js'; import { when } from 'lit/directives/when.js';
import { BrushTool } from '../../../brush-tool';
import { HighlighterTool } from '../../../highlighter-tool';
import { penIconMap, penInfoMap } from './consts'; import { penIconMap, penInfoMap } from './consts';
import type { Pen } from './types'; import type { Pen } from './types';
@@ -97,19 +99,19 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
override enableActiveBackground = true; override enableActiveBackground = true;
override type: Pen[] = ['brush', 'highlighter']; override type = [BrushTool, HighlighterTool];
override firstUpdated() { override firstUpdated() {
this.disposables.add( this.disposables.add(
this.gfx.tool.currentToolName$.subscribe(name => { this.gfx.tool.currentToolName$.subscribe(name => {
const tool = this.type.find(t => t === name); const tool = this.type.find(t => t.toolName === name);
if (!tool) { if (!tool) {
this.tryDisposePopper(); this.tryDisposePopper();
return; return;
} }
if (tool !== this.pen$.peek()) { if (tool.toolName !== this.pen$.peek()) {
this.pen$.value = tool; this.pen$.value = tool.toolName as Pen;
} }
if (this.active) return; if (this.active) return;
@@ -121,7 +123,17 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
private _togglePenMenu() { private _togglePenMenu() {
if (this.tryDisposePopper()) return; if (this.tryDisposePopper()) return;
!this.active && this.setEdgelessTool(this.pen$.peek()); const setPenByType = (pen: Pen) => {
if (pen === 'brush') {
this.setEdgelessTool(BrushTool);
} else {
this.setEdgelessTool(HighlighterTool);
}
};
if (!this.active) {
const pen = this.pen$.peek();
setPenByType(pen);
}
const menu = this.createPopper('edgeless-pen-menu', this); const menu = this.createPopper('edgeless-pen-menu', this);
Object.assign(menu.element, { Object.assign(menu.element, {
colors$: this.colors$, colors$: this.colors$,
@@ -132,7 +144,7 @@ export class EdgelessPenToolButton extends EdgelessToolbarToolMixin(
onChange: (props: Record<string, unknown>) => { onChange: (props: Record<string, unknown>) => {
const pen = this.pen$.peek(); const pen = this.pen$.peek();
this.edgeless.std.get(EditPropsStore).recordLastProps(pen, props); this.edgeless.std.get(EditPropsStore).recordLastProps(pen, props);
this.setEdgelessTool(pen); setPenByType(pen);
}, },
}); });
} }
@@ -1,8 +1,3 @@
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx'; export type Pen = 'brush' | 'highlighter';
export type Pen = Extract<
GfxToolsFullOptionValue['type'],
'brush' | 'highlighter'
>;
export type PenMap<T> = Record<Pen, T>; export type PenMap<T> = Record<Pen, T>;
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
OverlayIdentifier, OverlayIdentifier,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import type { import type {
@@ -104,8 +105,7 @@ export class ConnectorTool extends BaseTool<ConnectorToolOptions> {
this._allowCancel = true; this._allowCancel = true;
} }
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.gfx.selection.set({ elements: [focusedId] }); this.gfx.selection.set({ elements: [focusedId] });
} }
@@ -132,8 +132,8 @@ export class ConnectorTool extends BaseTool<ConnectorToolOptions> {
const connector = this._connector; const connector = this._connector;
this.doc.captureSync(); this.doc.captureSync();
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.gfx.tool.setTool('default'); this.gfx.tool.setTool(DefaultTool);
this.gfx.selection.set({ elements: [connector.id] }); this.gfx.selection.set({ elements: [connector.id] });
} }
@@ -1,4 +1,7 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
EdgelessCRUDIdentifier,
} from '@blocksuite/affine-block-surface';
import { getLineHeight } from '@blocksuite/affine-gfx-text'; import { getLineHeight } from '@blocksuite/affine-gfx-text';
import type { ConnectorElementModel } from '@blocksuite/affine-model'; import type { ConnectorElementModel } from '@blocksuite/affine-model';
import type { RichText } from '@blocksuite/affine-rich-text'; import type { RichText } from '@blocksuite/affine-rich-text';
@@ -40,8 +43,7 @@ export function mountConnectorLabelEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error default tool should be migrated to std gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [connector.id], elements: [connector.id],
editing: true, editing: true,
@@ -1,4 +1,7 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
EdgelessCRUDIdentifier,
} from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model'; import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { IVec } from '@blocksuite/global/gfx'; import type { IVec } from '@blocksuite/global/gfx';
@@ -24,8 +27,7 @@ export function mountConnectorLabelEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [connector.id], elements: [connector.id],
editing: true, editing: true,
@@ -8,6 +8,8 @@ import {
ConnectorLIcon, ConnectorLIcon,
} from '@blocksuite/icons/lit'; } from '@blocksuite/icons/lit';
import { ConnectorTool } from '../connector-tool';
export const buildConnectorDenseMenu: DenseMenuBuilder = (edgeless, gfx) => { export const buildConnectorDenseMenu: DenseMenuBuilder = (edgeless, gfx) => {
const prevMode = const prevMode =
edgeless.std.get(EditPropsStore).lastProps$.value.connector.mode; edgeless.std.get(EditPropsStore).lastProps$.value.connector.mode;
@@ -17,7 +19,7 @@ export const buildConnectorDenseMenu: DenseMenuBuilder = (edgeless, gfx) => {
const createSelect = const createSelect =
(mode: ConnectorMode, record = true) => (mode: ConnectorMode, record = true) =>
() => { () => {
gfx.tool.setTool('connector', { gfx.tool.setTool(ConnectorTool, {
mode, mode,
}); });
record && record &&
@@ -16,11 +16,12 @@ import {
ConnectorEIcon, ConnectorEIcon,
ConnectorLIcon, ConnectorLIcon,
} from '@blocksuite/icons/lit'; } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import { ConnectorTool } from '../connector-tool';
function ConnectorModeButtonGroup( function ConnectorModeButtonGroup(
mode: ConnectorMode, mode: ConnectorMode,
setConnectorMode: (props: Record<string, unknown>) => void setConnectorMode: (props: Record<string, unknown>) => void
@@ -110,7 +111,7 @@ export class EdgelessConnectorMenu extends EdgelessToolbarToolMixin(
return this.edgeless.std.get(ThemeProvider).theme$.value; return this.edgeless.std.get(ThemeProvider).theme$.value;
}); });
override type: GfxToolsFullOptionValue['type'] = 'connector'; override type = ConnectorTool;
override render() { override render() {
const { stroke, strokeWidth, mode } = this._props$.value; const { stroke, strokeWidth, mode } = this._props$.value;
@@ -10,6 +10,8 @@ import {
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { ConnectorTool } from '../connector-tool';
const IcomMap = { const IcomMap = {
[ConnectorMode.Straight]: ConnectorLIcon(), [ConnectorMode.Straight]: ConnectorLIcon(),
[ConnectorMode.Orthogonal]: ConnectorEIcon(), [ConnectorMode.Orthogonal]: ConnectorEIcon(),
@@ -30,7 +32,7 @@ export class EdgelessConnectorToolButton extends QuickToolMixin(
.mode; .mode;
}); });
override type = 'connector' as const; override type = ConnectorTool;
private _toggleMenu() { private _toggleMenu() {
if (this.tryDisposePopper()) return; if (this.tryDisposePopper()) return;
@@ -64,7 +66,7 @@ export class EdgelessConnectorToolButton extends QuickToolMixin(
@click=${() => { @click=${() => {
// don't update tool before toggling menu // don't update tool before toggling menu
this._toggleMenu(); this._toggleMenu();
this.gfx.tool.setTool('connector', { this.gfx.tool.setTool(ConnectorTool, {
mode, mode,
}); });
}} }}
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import type { GroupElementModel } from '@blocksuite/affine-model'; import type { GroupElementModel } from '@blocksuite/affine-model';
import type { RichText } from '@blocksuite/affine-rich-text'; import type { RichText } from '@blocksuite/affine-rich-text';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
@@ -36,8 +37,7 @@ export function mountGroupTitleEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [group.id], elements: [group.id],
editing: true, editing: true,
+2 -2
View File
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import type { GroupElementModel } from '@blocksuite/affine-model'; import type { GroupElementModel } from '@blocksuite/affine-model';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { BlockComponent } from '@blocksuite/std'; import type { BlockComponent } from '@blocksuite/std';
@@ -19,8 +20,7 @@ export function mountGroupTitleEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [group.id], elements: [group.id],
editing: true, editing: true,
@@ -1,14 +1,13 @@
import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark'; import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark';
import { insertEmbedCard } from '@blocksuite/affine-block-embed'; import { insertEmbedCard } from '@blocksuite/affine-block-embed';
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import { LinkIcon } from '@blocksuite/affine-components/icons'; import { LinkIcon } from '@blocksuite/affine-components/icons';
import type * as PointerEffect from '@blocksuite/affine-gfx-pointer';
import { TelemetryProvider } from '@blocksuite/affine-shared/services'; import { TelemetryProvider } from '@blocksuite/affine-shared/services';
import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
declare type _GLOBAL_ = typeof PointerEffect;
export class EdgelessLinkToolButton extends QuickToolMixin(LitElement) { export class EdgelessLinkToolButton extends QuickToolMixin(LitElement) {
static override styles = css` static override styles = css`
.link-icon, .link-icon,
@@ -18,7 +17,7 @@ export class EdgelessLinkToolButton extends QuickToolMixin(LitElement) {
} }
`; `;
override type = 'default' as const; override type = DefaultTool;
private _onClick() { private _onClick() {
const [success, { insertedLinkType }] = this.edgeless.std.command.exec( const [success, { insertedLinkType }] = this.edgeless.std.command.exec(
@@ -40,6 +39,12 @@ export class EdgelessLinkToolButton extends QuickToolMixin(LitElement) {
props: { url }, props: { url },
}); });
}, },
},
({ mode }) => {
if (mode === 'edgeless') {
const gfx = this.edgeless.std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
} }
).catch(console.error); ).catch(console.error);
return; return;
@@ -17,6 +17,7 @@
"@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-gfx-connector": "workspace:*", "@blocksuite/affine-gfx-connector": "workspace:*",
"@blocksuite/affine-gfx-pointer": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*", "@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*", "@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-model": "workspace:*",
@@ -1,4 +1,6 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { toast } from '@blocksuite/affine-components/toast'; import { toast } from '@blocksuite/affine-components/toast';
import { EmptyTool } from '@blocksuite/affine-gfx-pointer';
import type { MindmapStyle } from '@blocksuite/affine-model'; import type { MindmapStyle } from '@blocksuite/affine-model';
import { import {
EditPropsStore, EditPropsStore,
@@ -123,8 +125,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
ToolbarMindmapItem | TextItem | ImportItem | MediaItem ToolbarMindmapItem | TextItem | ImportItem | MediaItem
>; >;
// @ts-expect-error FIXME: resolve after gfx tool refactor override type = EmptyTool;
override type = 'empty' as const;
get mindMaps() { get mindMaps() {
return getMindMaps(this.theme); return getMindMaps(this.theme);
@@ -223,8 +224,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
this.onActiveStyleChange?.(element.data.style); this.onActiveStyleChange?.(element.data.style);
} }
// a workaround to active mindmap, so that menu cannot be closed by `Escape` // a workaround to active mindmap, so that menu cannot be closed by `Escape`
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(EmptyTool);
this.setEdgelessTool({ type: 'empty' });
}, },
onDrop: (element, bound) => { onDrop: (element, bound) => {
if ('render' in element.data) { if ('render' in element.data) {
@@ -234,8 +234,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
if (!id) return; if (!id) return;
if (element.data.type === 'mindmap') { if (element.data.type === 'mindmap') {
this.onActiveStyleChange?.(element.data.style); this.onActiveStyleChange?.(element.data.style);
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({ this.gfx.selection.set({
elements: [id], elements: [id],
editing: false, editing: false,
@@ -244,8 +243,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
element.data.type === 'text' || element.data.type === 'text' ||
element.data.type === 'media' element.data.type === 'media'
) { ) {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
} }
}) })
.catch(console.error); .catch(console.error);
@@ -1,4 +1,9 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
EdgelessCRUDIdentifier,
} from '@blocksuite/affine-block-surface';
import { EmptyTool } from '@blocksuite/affine-gfx-pointer';
import { TextTool } from '@blocksuite/affine-gfx-text';
import type { import type {
MindmapElementModel, MindmapElementModel,
MindmapStyle, MindmapStyle,
@@ -14,7 +19,6 @@ import {
} from '@blocksuite/affine-widget-edgeless-toolbar'; } from '@blocksuite/affine-widget-edgeless-toolbar';
import type { Bound } from '@blocksuite/global/gfx'; import type { Bound } from '@blocksuite/global/gfx';
import { SignalWatcher } from '@blocksuite/global/lit'; import { SignalWatcher } from '@blocksuite/global/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { css, html, LitElement, nothing } from 'lit'; import { css, html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js'; import { property, query, state } from 'lit/decorators.js';
@@ -150,8 +154,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
override enableActiveBackground = true; override enableActiveBackground = true;
// @ts-expect-error FIXME: resolve after gfx tool refactor override type = [EmptyTool, TextTool];
override type: GfxToolsFullOptionValue['type'][] = ['empty', 'text'];
get draggableTools(): DraggableTool[] { get draggableTools(): DraggableTool[] {
const style = this._style$.value; const style = this._style$.value;
@@ -192,8 +195,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
private _toggleMenu() { private _toggleMenu() {
if (this.tryDisposePopper()) return; if (this.tryDisposePopper()) return;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
const menu = this.createPopper('edgeless-mindmap-menu', this); const menu = this.createPopper('edgeless-mindmap-menu', this);
Object.assign(menu.element, { Object.assign(menu.element, {
@@ -213,8 +215,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
const element = this.crud.getElementById(id) as MindmapElementModel; const element = this.crud.getElementById(id) as MindmapElementModel;
this.tryDisposePopper(); this.tryDisposePopper();
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({ this.gfx.selection.set({
elements: [element.tree.id], elements: [element.tree.id],
editing: false, editing: false,
@@ -274,15 +275,13 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
if (!id) return; if (!id) return;
this.readyToDrop = false; this.readyToDrop = false;
if (el.data.name === 'mindmap') { if (el.data.name === 'mindmap') {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({ this.gfx.selection.set({
elements: [id], elements: [id],
editing: false, editing: false,
}); });
} else if (el.data.name === 'text') { } else if (el.data.name === 'text') {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool({ type: 'default' });
} }
}) })
.catch(console.error); .catch(console.error);
@@ -314,8 +313,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
}); });
return; return;
} }
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(EmptyTool);
this.setEdgelessTool({ type: 'empty' });
const icon = this.mindmapElement; const icon = this.mindmapElement;
const { x, y } = gfx.tool.lastMousePos$.peek(); const { x, y } = gfx.tool.lastMousePos$.peek();
const { viewport } = this.edgeless.std.get(ViewportElementProvider); const { viewport } = this.edgeless.std.get(ViewportElementProvider);
@@ -14,6 +14,7 @@
{ "path": "../../components" }, { "path": "../../components" },
{ "path": "../../ext-loader" }, { "path": "../../ext-loader" },
{ "path": "../connector" }, { "path": "../connector" },
{ "path": "../pointer" },
{ "path": "../shape" }, { "path": "../shape" },
{ "path": "../text" }, { "path": "../text" },
{ "path": "../../model" }, { "path": "../../model" },
+137 -7
View File
@@ -1,18 +1,35 @@
import type { SurfaceBlockComponent } from '@blocksuite/affine-block-surface';
import { import {
addNote, DEFAULT_NOTE_OFFSET_X,
DEFAULT_NOTE_OFFSET_Y,
DefaultTool,
EdgelessCRUDIdentifier,
EXCLUDING_MOUSE_OUT_CLASS_LIST, EXCLUDING_MOUSE_OUT_CLASS_LIST,
type SurfaceBlockComponent,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { import {
DEFAULT_NOTE_HEIGHT, DEFAULT_NOTE_HEIGHT,
DEFAULT_NOTE_WIDTH, DEFAULT_NOTE_WIDTH,
NOTE_MIN_HEIGHT,
type NoteBlockModel,
NoteDisplayMode,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { EditPropsStore } from '@blocksuite/affine-shared/services'; import { focusTextModel } from '@blocksuite/affine-rich-text';
import {
EditPropsStore,
TelemetryProvider,
} from '@blocksuite/affine-shared/services';
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types'; import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
import { hasClassNameInList } from '@blocksuite/affine-shared/utils'; import {
import { Point } from '@blocksuite/global/gfx'; handleNativeRangeAtPoint,
import type { PointerEventState } from '@blocksuite/std'; hasClassNameInList,
import { BaseTool } from '@blocksuite/std/gfx'; } from '@blocksuite/affine-shared/utils';
import { type IPoint, Point, serializeXYWH } from '@blocksuite/global/gfx';
import type { BlockStdScope, PointerEventState } from '@blocksuite/std';
import {
BaseTool,
type GfxBlockElementModel,
GfxControllerIdentifier,
} from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { DraggingNoteOverlay, NoteOverlay } from './overlay'; import { DraggingNoteOverlay, NoteOverlay } from './overlay';
@@ -210,3 +227,116 @@ declare module '@blocksuite/std/gfx' {
'affine:note': NoteToolOption; 'affine:note': NoteToolOption;
} }
} }
type NoteOptions = {
childFlavour: NoteChildrenFlavour;
childType: string | null;
collapse: boolean;
};
function addNote(
std: BlockStdScope,
point: Point,
options: NoteOptions,
width = DEFAULT_NOTE_WIDTH,
height = DEFAULT_NOTE_HEIGHT
) {
const noteId = addNoteAtPoint(std, point, {
width,
height,
});
const gfx = std.get(GfxControllerIdentifier);
const doc = std.store;
const blockId = doc.addBlock(
options.childFlavour,
{ type: options.childType },
noteId
);
if (options.collapse && height > NOTE_MIN_HEIGHT) {
const note = doc.getModelById(noteId) as NoteBlockModel;
doc.updateBlock(note, () => {
note.props.edgeless.collapse = true;
note.props.edgeless.collapsedHeight = height;
});
}
gfx.tool.setTool(DefaultTool);
// Wait for edgelessTool updated
requestAnimationFrame(() => {
const blocks =
(doc.root?.children.filter(
child => child.flavour === 'affine:note'
) as GfxBlockElementModel[]) ?? [];
const element = blocks.find(b => b.id === noteId);
if (element) {
gfx.selection.set({
elements: [element.id],
editing: true,
});
// Waiting dom updated, `note mask` is removed
if (blockId) {
focusTextModel(gfx.std, blockId);
} else {
// Cannot reuse `handleNativeRangeClick` directly here,
// since `retargetClick` will re-target to pervious editor
handleNativeRangeAtPoint(point.x, point.y);
}
}
});
}
function addNoteAtPoint(
std: BlockStdScope,
/**
* The point is in browser coordinate
*/
point: IPoint,
options: {
width?: number;
height?: number;
parentId?: string;
noteIndex?: number;
offsetX?: number;
offsetY?: number;
scale?: number;
} = {}
) {
const gfx = std.get(GfxControllerIdentifier);
const crud = std.get(EdgelessCRUDIdentifier);
const {
width = DEFAULT_NOTE_WIDTH,
height = DEFAULT_NOTE_HEIGHT,
offsetX = DEFAULT_NOTE_OFFSET_X,
offsetY = DEFAULT_NOTE_OFFSET_Y,
parentId = gfx.doc.root?.id,
noteIndex,
scale = 1,
} = options;
const [x, y] = gfx.viewport.toModelCoord(point.x, point.y);
const blockId = crud.addBlock(
'affine:note',
{
xywh: serializeXYWH(
x - offsetX * scale,
y - offsetY * scale,
width,
height
),
displayMode: NoteDisplayMode.EdgelessOnly,
},
parentId,
noteIndex
);
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
control: 'canvas:draw',
page: 'whiteboard editor',
module: 'toolbar',
segment: 'toolbar',
type: 'note',
});
return blockId;
}
@@ -5,10 +5,11 @@ import {
import { type Color, DefaultTheme } from '@blocksuite/affine-model'; import { type Color, DefaultTheme } from '@blocksuite/affine-model';
import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { ThemeProvider } from '@blocksuite/affine-shared/services';
import type { XYWH } from '@blocksuite/global/gfx'; import type { XYWH } from '@blocksuite/global/gfx';
import type { GfxController, GfxToolsMap } from '@blocksuite/std/gfx'; import type { GfxController } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import type { NoteTool } from '../note-tool';
import { import {
NOTE_OVERLAY_CORNER_RADIUS, NOTE_OVERLAY_CORNER_RADIUS,
NOTE_OVERLAY_HEIGHT, NOTE_OVERLAY_HEIGHT,
@@ -33,8 +34,7 @@ export class NoteOverlay extends ToolOverlay {
effect(() => { effect(() => {
// when change note child type, update overlay text // when change note child type, update overlay text
if (this.gfx.tool.currentToolName$.value !== 'affine:note') return; if (this.gfx.tool.currentToolName$.value !== 'affine:note') return;
const tool = const tool = this.gfx.tool.currentTool$.peek() as NoteTool;
this.gfx.tool.currentTool$.peek() as GfxToolsMap['affine:note'];
this.text = this._getOverlayText(tool.activatedOption.tip); this.text = this._getOverlayText(tool.activatedOption.tip);
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh(); (this.gfx.surfaceComponent as SurfaceBlockComponent).refresh();
}) })
@@ -1,6 +1,7 @@
import { addAttachments } from '@blocksuite/affine-block-attachment'; import { addAttachments } from '@blocksuite/affine-block-attachment';
import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark'; import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark';
import { addImages } from '@blocksuite/affine-block-image'; import { addImages } from '@blocksuite/affine-block-image';
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { MAX_IMAGE_WIDTH } from '@blocksuite/affine-model'; import { MAX_IMAGE_WIDTH } from '@blocksuite/affine-model';
import { TelemetryProvider } from '@blocksuite/affine-shared/services'; import { TelemetryProvider } from '@blocksuite/affine-shared/services';
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types'; import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
@@ -10,13 +11,13 @@ import {
} from '@blocksuite/affine-shared/utils'; } from '@blocksuite/affine-shared/utils';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import { AttachmentIcon, ImageIcon, LinkIcon } from '@blocksuite/icons/lit'; import { AttachmentIcon, ImageIcon, LinkIcon } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx'; import type { ToolOptions } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { property, state } from 'lit/decorators.js'; import { property, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import type { NoteToolOption } from '../note-tool.js'; import { NoteTool, type NoteToolOption } from '../note-tool.js';
import { NOTE_MENU_ITEMS } from './note-menu-config.js'; import { NOTE_MENU_ITEMS } from './note-menu-config.js';
export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) { export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
@@ -51,7 +52,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
} }
`; `;
override type: GfxToolsFullOptionValue['type'] = 'affine:note'; override type = NoteTool;
private async _addImages() { private async _addImages() {
this._imageLoading = true; this._imageLoading = true;
@@ -60,8 +61,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
maxWidth: MAX_IMAGE_WIDTH, maxWidth: MAX_IMAGE_WIDTH,
}); });
this._imageLoading = false; this._imageLoading = false;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.gfx.selection.set({ elements: ids }); this.gfx.selection.set({ elements: ids });
} }
@@ -96,10 +96,11 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
effect(() => { effect(() => {
const tool = this.gfx.tool.currentToolOption$.value; const tool = this.gfx.tool.currentToolOption$.value;
if (tool?.type !== 'affine:note') return; if (tool?.toolType !== NoteTool) return;
this.childFlavour = tool.childFlavour; const options = tool.options as ToolOptions<NoteTool>;
this.childType = tool.childType; this.childFlavour = options.childFlavour;
this.tip = tool.tip; this.childType = options.childType;
this.tip = options.tip;
}) })
); );
} }
@@ -141,8 +142,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
const file = await openFileOrFiles(); const file = await openFileOrFiles();
if (!file) return; if (!file) return;
await addAttachments(this.edgeless.std, [file]); await addAttachments(this.edgeless.std, [file]);
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.edgeless.std this.edgeless.std
.getOptional(TelemetryProvider) .getOptional(TelemetryProvider)
?.track('CanvasElementAdded', { ?.track('CanvasElementAdded', {
@@ -13,7 +13,7 @@ import { computed } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { state } from 'lit/decorators.js'; import { state } from 'lit/decorators.js';
import type { NoteToolOption } from '../note-tool.js'; import { NoteTool, type NoteToolOption } from '../note-tool.js';
import { toShapeNotToAdapt } from './icon.js'; import { toShapeNotToAdapt } from './icon.js';
export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin( export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
@@ -138,15 +138,14 @@ export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
override enableActiveBackground = true; override enableActiveBackground = true;
override type = 'affine:note' as const; override type = NoteTool;
private _toggleNoteMenu() { private _toggleNoteMenu() {
if (this.tryDisposePopper()) return; if (this.tryDisposePopper()) return;
const { edgeless, childFlavour, childType, tip } = this; const { edgeless, childFlavour, childType, tip } = this;
this.setEdgelessTool({ this.setEdgelessTool(NoteTool, {
type: 'affine:note',
childFlavour, childFlavour,
childType, childType,
tip, tip,
@@ -171,8 +170,7 @@ export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
Object.assign(this, { [key]: props[key] }); Object.assign(this, { [key]: props[key] });
} }
}); });
this.setEdgelessTool({ this.setEdgelessTool(NoteTool, {
type: 'affine:note',
childFlavour: this.childFlavour, childFlavour: this.childFlavour,
childType: this.childType, childType: this.childType,
tip: this.tip, tip: this.tip,
@@ -4,12 +4,11 @@ import {
QuickToolMixin, QuickToolMixin,
} from '@blocksuite/affine-widget-edgeless-toolbar'; } from '@blocksuite/affine-widget-edgeless-toolbar';
import { PageIcon } from '@blocksuite/icons/lit'; import { PageIcon } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { state } from 'lit/decorators.js'; import { state } from 'lit/decorators.js';
import type { NoteToolOption } from '../note-tool.js'; import { NoteTool, type NoteToolOption } from '../note-tool.js';
import type { EdgelessNoteMenu } from './note-menu.js'; import type { EdgelessNoteMenu } from './note-menu.js';
export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) { export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
@@ -23,7 +22,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
private readonly _states = ['childFlavour', 'childType', 'tip'] as const; private readonly _states = ['childFlavour', 'childType', 'tip'] as const;
override type: GfxToolsFullOptionValue['type'] = 'affine:note'; override type = NoteTool;
private _disposeMenu() { private _disposeMenu() {
this._noteMenu?.dispose(); this._noteMenu?.dispose();
@@ -35,7 +34,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
this._disposeMenu(); this._disposeMenu();
this.requestUpdate(); this.requestUpdate();
} else { } else {
this.gfx.tool.setTool('affine:note', { this.gfx.tool.setTool(NoteTool, {
childFlavour: this.childFlavour, childFlavour: this.childFlavour,
childType: this.childType, childType: this.childType,
tip: this.tip, tip: this.tip,
@@ -59,7 +58,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
Object.assign(this, { [key]: props[key] }); Object.assign(this, { [key]: props[key] });
} }
}); });
this.gfx.tool.setTool('affine:note', { this.gfx.tool.setTool(NoteTool, {
childFlavour: this.childFlavour, childFlavour: this.childFlavour,
childType: this.childType, childType: this.childType,
tip: this.tip, tip: this.tip,
@@ -1,10 +1,12 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { QuickToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import { HandIcon, SelectIcon } from '@blocksuite/icons/lit'; import { HandIcon, SelectIcon } from '@blocksuite/icons/lit';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { query } from 'lit/decorators.js'; import { query } from 'lit/decorators.js';
import { PanTool } from '../tools';
export class EdgelessDefaultToolButton extends QuickToolMixin(LitElement) { export class EdgelessDefaultToolButton extends QuickToolMixin(LitElement) {
static override styles = css` static override styles = css`
.current-icon { .current-icon {
@@ -17,19 +19,19 @@ export class EdgelessDefaultToolButton extends QuickToolMixin(LitElement) {
} }
`; `;
override type: GfxToolsFullOptionValue['type'][] = ['default', 'pan']; override type = [DefaultTool, PanTool];
private _changeTool() { private _changeTool() {
if (this.toolbar.activePopper) { if (this.toolbar.activePopper) {
// click manually always closes the popper // click manually always closes the popper
this.toolbar.activePopper.dispose(); this.toolbar.activePopper.dispose();
} }
const type = this.edgelessTool?.type; const type = this.edgelessTool?.toolType?.toolName;
if (type !== 'default' && type !== 'pan') { if (type !== 'default' && type !== 'pan') {
if (localStorage.defaultTool === 'default') { if (localStorage.defaultTool === 'default') {
this.setEdgelessTool('default'); this.setEdgelessTool(DefaultTool);
} else if (localStorage.defaultTool === 'pan') { } else if (localStorage.defaultTool === 'pan') {
this.setEdgelessTool('pan', { panning: false }); this.setEdgelessTool(PanTool, { panning: false });
} }
return; return;
} }
@@ -37,9 +39,9 @@ export class EdgelessDefaultToolButton extends QuickToolMixin(LitElement) {
// wait for animation to finish // wait for animation to finish
setTimeout(() => { setTimeout(() => {
if (type === 'default') { if (type === 'default') {
this.setEdgelessTool('pan', { panning: false }); this.setEdgelessTool(PanTool, { panning: false });
} else if (type === 'pan') { } else if (type === 'pan') {
this.setEdgelessTool('default'); this.setEdgelessTool(DefaultTool);
} }
this._fadeIn(); this._fadeIn();
}, 100); }, 100);
@@ -71,7 +73,7 @@ export class EdgelessDefaultToolButton extends QuickToolMixin(LitElement) {
} }
override render() { override render() {
const type = this.edgelessTool?.type; const type = this.edgelessTool?.toolType?.toolName;
const { active } = this; const { active } = this;
const tipInfo = const tipInfo =
type === 'pan' type === 'pan'
@@ -1,3 +1,2 @@
export * from './default-tool.js';
export * from './empty-tool.js'; export * from './empty-tool.js';
export * from './pan-tool.js'; export * from './pan-tool.js';
@@ -56,11 +56,14 @@ export class PanTool extends BaseTool<PanToolOption> {
const selection = this.gfx.selection.surfaceSelections; const selection = this.gfx.selection.surfaceSelections;
const currentTool = this.controller.currentToolOption$.peek(); const currentTool = this.controller.currentToolOption$.peek();
const restoreToPrevious = () => { const restoreToPrevious = () => {
this.controller.setTool(currentTool); const { toolType, options } = currentTool;
this.gfx.selection.set(selection); if (toolType && options) {
this.controller.setTool(toolType, options);
this.gfx.selection.set(selection);
}
}; };
this.controller.setTool('pan', { this.controller.setTool(PanTool, {
panning: true, panning: true,
}); });
+1 -2
View File
@@ -7,7 +7,7 @@ import { effects } from './effects';
import { defaultQuickTool } from './quick-tool/quick-tool'; import { defaultQuickTool } from './quick-tool/quick-tool';
import { SnapExtension } from './snap/snap-manager'; import { SnapExtension } from './snap/snap-manager';
import { SnapOverlay } from './snap/snap-overlay'; import { SnapOverlay } from './snap/snap-overlay';
import { DefaultTool, EmptyTool, PanTool } from './tools'; import { EmptyTool, PanTool } from './tools';
export class PointerViewExtension extends ViewExtensionProvider { export class PointerViewExtension extends ViewExtensionProvider {
override name = 'affine-pointer-gfx'; override name = 'affine-pointer-gfx';
@@ -20,7 +20,6 @@ export class PointerViewExtension extends ViewExtensionProvider {
override setup(context: ViewExtensionContext) { override setup(context: ViewExtensionContext) {
super.setup(context); super.setup(context);
context.register(EmptyTool); context.register(EmptyTool);
context.register(DefaultTool);
context.register(PanTool); context.register(PanTool);
if (this.isEdgeless(context.scope)) { if (this.isEdgeless(context.scope)) {
context.register(defaultQuickTool); context.register(defaultQuickTool);
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { import {
@@ -137,7 +138,7 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
draggingShape: DraggableShape['name'] = 'roundedRect'; draggingShape: DraggableShape['name'] = 'roundedRect';
override type = 'shape' as const; override type = ShapeTool;
get crud() { get crud() {
return this.edgeless.std.get(EdgelessCRUDIdentifier); return this.edgeless.std.get(EdgelessCRUDIdentifier);
@@ -169,8 +170,7 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
this.draggableController.states.draggingElement?.data.name; this.draggableController.states.draggingElement?.data.name;
if (!shapeName) return; if (!shapeName) return;
this.setEdgelessTool({ this.setEdgelessTool(ShapeTool, {
type: 'shape',
shapeName, shapeName,
}); });
const controller = this.gfx.tool.currentTool$.peek(); const controller = this.gfx.tool.currentTool$.peek();
@@ -206,8 +206,7 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
this._setShapeOverlayLock(false); this._setShapeOverlayLock(false);
this.readyToDrop = false; this.readyToDrop = false;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.gfx.selection.set({ this.gfx.selection.set({
elements: [id], elements: [id],
editing: false, editing: false,
@@ -265,7 +264,7 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
const clientPos = { x: x + left, y: y + top }; const clientPos = { x: x + left, y: y + top };
this.draggableController.dragAndMoveTo(el, clientPos); this.draggableController.dragAndMoveTo(el, clientPos);
} else { } else {
this.setEdgelessTool('shape', { this.setEdgelessTool(ShapeTool, {
shapeName: this.draggingShape, shapeName: this.draggingShape,
}); });
} }
@@ -15,12 +15,16 @@ import type { ColorEvent } from '@blocksuite/affine-shared/utils';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit'; import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import { StyleGeneralIcon, StyleScribbleIcon } from '@blocksuite/icons/lit'; import { StyleGeneralIcon, StyleScribbleIcon } from '@blocksuite/icons/lit';
import type { BlockComponent } from '@blocksuite/std'; import type { BlockComponent } from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx'; import {
GfxControllerIdentifier,
type ToolOptionWithType,
} from '@blocksuite/std/gfx';
import { computed, effect, type Signal, signal } from '@preact/signals-core'; import { computed, effect, type Signal, signal } from '@preact/signals-core';
import { css, html, LitElement } from 'lit'; import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js'; import { when } from 'lit/directives/when.js';
import { ShapeTool } from '../shape-tool';
import { ShapeComponentConfig } from '../toolbar'; import { ShapeComponentConfig } from '../toolbar';
export class EdgelessShapeMenu extends SignalWatcher( export class EdgelessShapeMenu extends SignalWatcher(
@@ -115,8 +119,12 @@ export class EdgelessShapeMenu extends SignalWatcher(
effect(() => { effect(() => {
const value = gfx.tool.currentToolOption$.value; const value = gfx.tool.currentToolOption$.value;
if (value && value.type === 'shape') { if (value && value.toolType === ShapeTool) {
this._shapeName$.value = value.shapeName; const shapeName = (value as ToolOptionWithType<ShapeTool>).options
?.shapeName;
if (shapeName) {
this._shapeName$.value = shapeName;
}
} }
}) })
); );
@@ -38,7 +38,7 @@ export class EdgelessShapeToolButton extends EdgelessToolbarToolMixin(
if (!this.popper) this._toggleMenu(); if (!this.popper) this._toggleMenu();
}; };
override type = 'shape' as const; override type = ShapeTool;
private _toggleMenu() { private _toggleMenu() {
this.createPopper('edgeless-shape-menu', this, { this.createPopper('edgeless-shape-menu', this, {
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import { import {
@@ -109,8 +110,7 @@ export class EdgelessShapeToolElement extends WithDisposable(LitElement) {
return; return;
} }
this._dragging = false; this._dragging = false;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
if (this._isOutside) { if (this._isOutside) {
const rect = this._shapeElement.getBoundingClientRect(); const rect = this._shapeElement.getBoundingClientRect();
this._backupShapeElement.style.setProperty('transition', 'none'); this._backupShapeElement.style.setProperty('transition', 'none');
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
EXCLUDING_MOUSE_OUT_CLASS_LIST, EXCLUDING_MOUSE_OUT_CLASS_LIST,
type SurfaceBlockComponent, type SurfaceBlockComponent,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
@@ -180,8 +181,7 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
const element = this.gfx.getElementById(id); const element = this.gfx.getElementById(id);
if (!element) return; if (!element) return;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
this.gfx.selection.set({ this.gfx.selection.set({
elements: [element.id], elements: [element.id],
editing: false, editing: false,
@@ -257,8 +257,7 @@ export class ShapeTool extends BaseTool<ShapeToolOption> {
const element = this.gfx.getElementById(id); const element = this.gfx.getElementById(id);
if (!element) return; if (!element) return;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.controller.setTool(DefaultTool);
this.controller.setTool('default');
this.gfx.selection.set({ this.gfx.selection.set({
elements: [element.id], elements: [element.id],
}); });
@@ -1,4 +1,5 @@
import { import {
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
TextUtils, TextUtils,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
@@ -49,8 +50,7 @@ export function mountShapeTextEditor(
return; return;
} }
// @ts-expect-error FIXME: resolve after gfx tool refactor gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [shapeElement.id], elements: [shapeElement.id],
editing: true, editing: true,
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { import {
darkToolbarStyles, darkToolbarStyles,
lightToolbarStyles, lightToolbarStyles,
@@ -314,8 +315,7 @@ export class EdgelessTemplatePanel extends WithDisposable(LitElement) {
} }
} finally { } finally {
this._loadingTemplate = null; this._loadingTemplate = null;
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
} }
} }
@@ -1,7 +1,8 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import { ArrowDownSmallIcon } from '@blocksuite/affine-components/icons'; import { ArrowDownSmallIcon } from '@blocksuite/affine-components/icons';
import { once } from '@blocksuite/affine-shared/utils'; import { once } from '@blocksuite/affine-shared/utils';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx'; import type { ToolOptionWithType } from '@blocksuite/std/gfx';
import { import {
arrow, arrow,
autoUpdate, autoUpdate,
@@ -14,6 +15,7 @@ import { state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js'; import { classMap } from 'lit/directives/class-map.js';
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import { TemplateTool } from '../template-tool';
import { TemplateCard1, TemplateCard2, TemplateCard3 } from './cards.js'; import { TemplateCard1, TemplateCard2, TemplateCard3 } from './cards.js';
import type { EdgelessTemplatePanel } from './template-panel.js'; import type { EdgelessTemplatePanel } from './template-panel.js';
@@ -115,11 +117,11 @@ export class EdgelessTemplateButton extends EdgelessToolbarToolMixin(
private _cleanup: (() => void) | null = null; private _cleanup: (() => void) | null = null;
private _prevTool: GfxToolsFullOptionValue | null = null; private _prevTool: ToolOptionWithType | null = null;
override enableActiveBackground = true; override enableActiveBackground = true;
override type: GfxToolsFullOptionValue['type'] = 'template'; override type = TemplateTool;
get cards() { get cards() {
const { theme } = this; const { theme } = this;
@@ -134,12 +136,15 @@ export class EdgelessTemplateButton extends EdgelessToolbarToolMixin(
this._cleanup = null; this._cleanup = null;
this.requestUpdate(); this.requestUpdate();
if (this._prevTool && this._prevTool.type !== 'template') { if (
this.setEdgelessTool(this._prevTool); this._prevTool &&
this._prevTool.toolType &&
this._prevTool.toolType !== TemplateTool
) {
this.setEdgelessTool(this._prevTool.toolType, this._prevTool.options);
this._prevTool = null; this._prevTool = null;
} else { } else {
// @ts-expect-error FIXME: resolve after gfx tool refactor this.setEdgelessTool(DefaultTool);
this.setEdgelessTool('default');
} }
} }
} }
@@ -147,8 +152,8 @@ export class EdgelessTemplateButton extends EdgelessToolbarToolMixin(
private _togglePanel() { private _togglePanel() {
if (this._openedPanel) { if (this._openedPanel) {
this._closePanel(); this._closePanel();
if (this._prevTool) { if (this._prevTool && this._prevTool.toolType) {
this.setEdgelessTool(this._prevTool); this.setEdgelessTool(this._prevTool.toolType, this._prevTool.options);
this._prevTool = null; this._prevTool = null;
} }
return; return;
@@ -156,7 +161,7 @@ export class EdgelessTemplateButton extends EdgelessToolbarToolMixin(
this._prevTool = this.edgelessTool ? { ...this.edgelessTool } : null; this._prevTool = this.edgelessTool ? { ...this.edgelessTool } : null;
this.setEdgelessTool('template'); this.setEdgelessTool(TemplateTool);
const panel = document.createElement('edgeless-templates-panel'); const panel = document.createElement('edgeless-templates-panel');
panel.edgeless = this.edgeless; panel.edgeless = this.edgeless;
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
getSurfaceBlock, getSurfaceBlock,
type IModelCoord, type IModelCoord,
@@ -53,8 +54,7 @@ export function mountTextElementEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error TODO: refactor gfx tool gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [textElement.id], elements: [textElement.id],
editing: true, editing: true,
@@ -1,5 +1,6 @@
import { import {
CanvasElementType, CanvasElementType,
DefaultTool,
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
type IModelCoord, type IModelCoord,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
@@ -37,8 +38,7 @@ export function mountTextElementEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error TODO: refactor gfx tool gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [textElement.id], elements: [textElement.id],
editing: true, editing: true,
+2 -2
View File
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import type { TextElementModel } from '@blocksuite/affine-model'; import type { TextElementModel } from '@blocksuite/affine-model';
import { import {
FeatureFlagService, FeatureFlagService,
@@ -49,8 +50,7 @@ export class TextTool extends BaseTool {
if (textFlag) { if (textFlag) {
const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y); const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y);
this.gfx.std.command.exec(insertEdgelessTextCommand, { x, y }); this.gfx.std.command.exec(insertEdgelessTextCommand, { x, y });
// @ts-expect-error TODO: refactor gfx tool this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
} else { } else {
addText(this.gfx, e); addText(this.gfx, e);
} }
@@ -2,11 +2,12 @@ import { DefaultTheme } from '@blocksuite/affine-model';
import { ThemeProvider } from '@blocksuite/affine-shared/services'; import { ThemeProvider } from '@blocksuite/affine-shared/services';
import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import type { ColorEvent } from '@blocksuite/affine-shared/utils';
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar'; import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { css, html, LitElement, nothing } from 'lit'; import { css, html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import { TextTool } from '../tool';
export class EdgelessTextMenu extends EdgelessToolbarToolMixin(LitElement) { export class EdgelessTextMenu extends EdgelessToolbarToolMixin(LitElement) {
static override styles = css` static override styles = css`
:host { :host {
@@ -20,10 +21,10 @@ export class EdgelessTextMenu extends EdgelessToolbarToolMixin(LitElement) {
return this.edgeless.std.get(ThemeProvider).theme$.value; return this.edgeless.std.get(ThemeProvider).theme$.value;
}); });
override type: GfxToolsFullOptionValue['type'] = 'text'; override type = TextTool;
override render() { override render() {
if (this.edgelessTool.type !== 'text') return nothing; if (this.edgelessTool.toolType !== TextTool) return nothing;
return html` return html`
<edgeless-slide-menu> <edgeless-slide-menu>
@@ -3,7 +3,7 @@ import { getSelectedRect } from '@blocksuite/affine-shared/utils';
import { type IVec, Rect } from '@blocksuite/global/gfx'; import { type IVec, Rect } from '@blocksuite/global/gfx';
import { import {
GfxControllerIdentifier, GfxControllerIdentifier,
type GfxToolsFullOptionValue, type ToolOptionWithType,
} from '@blocksuite/std/gfx'; } from '@blocksuite/std/gfx';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
@@ -22,10 +22,9 @@ import type { AffineDragHandleWidget } from '../drag-handle.js';
*/ */
export class EdgelessWatcher { export class EdgelessWatcher {
private readonly _handleEdgelessToolUpdated = ( private readonly _handleEdgelessToolUpdated = (
newTool: GfxToolsFullOptionValue newTool: ToolOptionWithType
) => { ) => {
// @ts-expect-error GfxToolsFullOptionValue is extended in other packages if (newTool.toolType?.toolName === 'default') {
if (newTool.type === 'default') {
this.updateAnchorElement(); this.updateAnchorElement();
} else { } else {
this.widget.hide(); this.widget.hide();
@@ -1,5 +1,8 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */ /* oxlint-disable @typescript-eslint/no-non-null-assertion */
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import {
DefaultTool,
EdgelessLegacySlotIdentifier,
} from '@blocksuite/affine-block-surface';
import { import {
type MenuHandler, type MenuHandler,
popMenu, popMenu,
@@ -430,8 +433,7 @@ export class EdgelessToolbarWidget extends WidgetComponent<RootBlockModel> {
} }
get edgelessTool() { get edgelessTool() {
// FIXME: maybe we need to fix this type return this.gfx.tool.currentToolName$.value;
return this.gfx.tool.currentToolOption$.value as { type: string };
} }
get gfx() { get gfx() {
@@ -439,7 +441,7 @@ export class EdgelessToolbarWidget extends WidgetComponent<RootBlockModel> {
} }
get isPresentMode() { get isPresentMode() {
return this.edgelessTool.type === 'frameNavigator'; return this.edgelessTool === 'frameNavigator';
} }
get scrollSeniorToolSize() { get scrollSeniorToolSize() {
@@ -523,7 +525,7 @@ export class EdgelessToolbarWidget extends WidgetComponent<RootBlockModel> {
@click=${this._openMoreQuickToolsMenu} @click=${this._openMoreQuickToolsMenu}
?active=${this._quickTools ?active=${this._quickTools
.slice(this._visibleQuickToolSize) .slice(this._visibleQuickToolSize)
.some(tool => tool.type === this.edgelessTool?.type)} .some(tool => tool.type === this.edgelessTool)}
> >
${MoreHorizontalIcon({ width: '20px', height: '20px' })} ${MoreHorizontalIcon({ width: '20px', height: '20px' })}
<affine-tooltip tip-position="top" .offset=${25}> <affine-tooltip tip-position="top" .offset=${25}>
@@ -602,16 +604,15 @@ export class EdgelessToolbarWidget extends WidgetComponent<RootBlockModel> {
{ {
Escape: () => { Escape: () => {
if (this.gfx.selection.editing) return; if (this.gfx.selection.editing) return;
if (this.edgelessTool.type === 'frameNavigator') return; if (this.edgelessTool === 'frameNavigator') return;
if (this.edgelessTool.type === 'default') { if (this.edgelessTool === 'default') {
if (this.activePopper) { if (this.activePopper) {
this.activePopper.dispose(); this.activePopper.dispose();
this.activePopper = null; this.activePopper = null;
} }
return; return;
} }
// @ts-expect-error FIXME: resolve after gfx tool refactor this.gfx.tool.setTool(DefaultTool);
this.gfx.tool.setTool('default');
}, },
}, },
{ global: true } { global: true }
@@ -658,7 +659,7 @@ export class EdgelessToolbarWidget extends WidgetComponent<RootBlockModel> {
} }
override render() { override render() {
const { type } = this.edgelessTool || {}; const type = this.edgelessTool;
if (this.doc.readonly && type !== 'frameNavigator') { if (this.doc.readonly && type !== 'frameNavigator') {
return nothing; return nothing;
} }
@@ -1,12 +1,12 @@
import type { MenuConfig } from '@blocksuite/affine-components/context-menu'; import type { MenuConfig } from '@blocksuite/affine-components/context-menu';
import { createIdentifier } from '@blocksuite/global/di'; import { createIdentifier } from '@blocksuite/global/di';
import type { BlockComponent } from '@blocksuite/std'; import type { BlockComponent } from '@blocksuite/std';
import type { GfxController, GfxToolsMap } from '@blocksuite/std/gfx'; import type { GfxController } from '@blocksuite/std/gfx';
import type { ExtensionType } from '@blocksuite/store'; import type { ExtensionType } from '@blocksuite/store';
import { type TemplateResult } from 'lit'; import { type TemplateResult } from 'lit';
export interface QuickTool { export interface QuickTool {
type?: keyof GfxToolsMap; type?: string;
enable?: boolean; enable?: boolean;
content: TemplateResult; content: TemplateResult;
/** /**
@@ -9,9 +9,9 @@ import type { BlockComponent } from '@blocksuite/std';
import { import {
type GfxController, type GfxController,
GfxControllerIdentifier, GfxControllerIdentifier,
type GfxToolsFullOption,
type GfxToolsFullOptionValue,
type ToolController, type ToolController,
type ToolOptionWithType,
type ToolType,
} from '@blocksuite/std/gfx'; } from '@blocksuite/std/gfx';
import { consume } from '@lit/context'; import { consume } from '@lit/context';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
@@ -28,8 +28,6 @@ import {
import { createPopper, type MenuPopper } from '../create-popper'; import { createPopper, type MenuPopper } from '../create-popper';
import type { EdgelessToolbarWidget } from '../edgeless-toolbar'; import type { EdgelessToolbarWidget } from '../edgeless-toolbar';
type ValueOf<T> = T[keyof T];
export declare abstract class EdgelessToolbarToolClass extends DisposableClass { export declare abstract class EdgelessToolbarToolClass extends DisposableClass {
active: boolean; active: boolean;
@@ -37,7 +35,7 @@ export declare abstract class EdgelessToolbarToolClass extends DisposableClass {
edgeless: BlockComponent; edgeless: BlockComponent;
edgelessTool: GfxToolsFullOptionValue; edgelessTool: ToolOptionWithType;
enableActiveBackground?: boolean; enableActiveBackground?: boolean;
@@ -58,9 +56,7 @@ export declare abstract class EdgelessToolbarToolClass extends DisposableClass {
*/ */
tryDisposePopper: () => boolean; tryDisposePopper: () => boolean;
abstract type: abstract type: ToolType | ToolType[];
| GfxToolsFullOptionValue['type']
| GfxToolsFullOptionValue['type'][];
accessor toolbar: EdgelessToolbarWidget; accessor toolbar: EdgelessToolbarWidget;
} }
@@ -71,19 +67,15 @@ export const EdgelessToolbarToolMixin = <T extends Constructor<LitElement>>(
abstract class DerivedClass extends WithDisposable(SuperClass) { abstract class DerivedClass extends WithDisposable(SuperClass) {
enableActiveBackground = false; enableActiveBackground = false;
abstract type: abstract type: ToolType | ToolType[];
| GfxToolsFullOptionValue['type']
| GfxToolsFullOptionValue['type'][];
get active() { get active() {
const { type } = this; const { type } = this;
// @ts-expect-error FIXME: we need to fix the type of edgelessTool const activeType = this.edgelessTool?.toolType;
const activeType = this.edgelessTool?.type;
return activeType return activeType
? Array.isArray(type) ? Array.isArray(type)
? // @ts-expect-error FIXME: we need to fix the type of edgelessTool ? type.includes(activeType)
type.includes(activeType)
: activeType === type : activeType === type
: false; : false;
} }
@@ -93,12 +85,7 @@ export const EdgelessToolbarToolMixin = <T extends Constructor<LitElement>>(
} }
get setEdgelessTool() { get setEdgelessTool() {
return (...args: Parameters<ToolController['setTool']>) => { return this.gfx.tool.setTool;
this.gfx.tool.setTool(
// @ts-expect-error FIXME: ts error
...args
);
};
} }
private _applyActiveStyle() { private _applyActiveStyle() {
@@ -162,7 +149,7 @@ export const EdgelessToolbarToolMixin = <T extends Constructor<LitElement>>(
accessor edgeless!: BlockComponent; accessor edgeless!: BlockComponent;
@state() @state()
accessor edgelessTool!: ValueOf<GfxToolsFullOption> | null; accessor edgelessTool!: ToolOptionWithType | null;
@state() @state()
public accessor popper: MenuPopper<HTMLElement> | null = null; public accessor popper: MenuPopper<HTMLElement> | null = null;
@@ -10,6 +10,7 @@
"author": "toeverything", "author": "toeverything",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*", "@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-model": "workspace:*",
@@ -1,3 +1,4 @@
import { DefaultTool } from '@blocksuite/affine-block-surface';
import type { FrameBlockModel } from '@blocksuite/affine-model'; import type { FrameBlockModel } from '@blocksuite/affine-model';
import { BlockSuiteError } from '@blocksuite/global/exceptions'; import { BlockSuiteError } from '@blocksuite/global/exceptions';
import type { BlockComponent } from '@blocksuite/std'; import type { BlockComponent } from '@blocksuite/std';
@@ -19,8 +20,7 @@ export function mountFrameTitleEditor(
const gfx = edgeless.std.get(GfxControllerIdentifier); const gfx = edgeless.std.get(GfxControllerIdentifier);
// @ts-expect-error TODO: refactor gfx tool gfx.tool.setTool(DefaultTool);
gfx.tool.setTool('default');
gfx.selection.set({ gfx.selection.set({
elements: [frame.id], elements: [frame.id],
editing: true, editing: true,
@@ -7,6 +7,7 @@
}, },
"include": ["./src"], "include": ["./src"],
"references": [ "references": [
{ "path": "../../blocks/surface" },
{ "path": "../../components" }, { "path": "../../components" },
{ "path": "../../ext-loader" }, { "path": "../../ext-loader" },
{ "path": "../../model" }, { "path": "../../model" },
@@ -16,7 +16,7 @@ import {
dedentParagraphCommand, dedentParagraphCommand,
indentParagraphCommand, indentParagraphCommand,
} from '@blocksuite/affine-block-paragraph'; } from '@blocksuite/affine-block-paragraph';
import { getSurfaceBlock } from '@blocksuite/affine-block-surface'; import { DefaultTool, getSurfaceBlock } from '@blocksuite/affine-block-surface';
import { insertSurfaceRefBlockCommand } from '@blocksuite/affine-block-surface-ref'; import { insertSurfaceRefBlockCommand } from '@blocksuite/affine-block-surface-ref';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal'; import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import { toast } from '@blocksuite/affine-components/toast'; import { toast } from '@blocksuite/affine-components/toast';
@@ -101,6 +101,7 @@ import {
type BlockStdScope, type BlockStdScope,
ConfigExtensionFactory, ConfigExtensionFactory,
} from '@blocksuite/std'; } from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { cssVarV2 } from '@toeverything/theme/v2'; import { cssVarV2 } from '@toeverything/theme/v2';
import type { TemplateResult } from 'lit'; import type { TemplateResult } from 'lit';
@@ -393,7 +394,13 @@ const contentMediaToolGroup: KeyboardToolPanelGroup = {
std.host, std.host,
'Links', 'Links',
'The added link will be displayed as a card view.', 'The added link will be displayed as a card view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) { if (model.text?.length === 0) {
std.store.deleteBlock(model); std.store.deleteBlock(model);
@@ -486,7 +493,13 @@ const embedToolGroup: KeyboardToolPanelGroup = {
std.host, std.host,
'YouTube', 'YouTube',
'The added YouTube video link will be displayed as an embed view.', 'The added YouTube video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) { if (model.text?.length === 0) {
std.store.deleteBlock(model); std.store.deleteBlock(model);
@@ -513,7 +526,13 @@ const embedToolGroup: KeyboardToolPanelGroup = {
std.host, std.host,
'GitHub', 'GitHub',
'The added GitHub issue or pull request link will be displayed as a card view.', 'The added GitHub issue or pull request link will be displayed as a card view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) { if (model.text?.length === 0) {
std.store.deleteBlock(model); std.store.deleteBlock(model);
@@ -541,7 +560,13 @@ const embedToolGroup: KeyboardToolPanelGroup = {
std.host, std.host,
'Figma', 'Figma',
'The added Figma link will be displayed as an embed view.', 'The added Figma link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) { if (model.text?.length === 0) {
std.store.deleteBlock(model); std.store.deleteBlock(model);
@@ -568,7 +593,13 @@ const embedToolGroup: KeyboardToolPanelGroup = {
std.host, std.host,
'Loom', 'Loom',
'The added Loom video link will be displayed as an embed view.', 'The added Loom video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index } { mode: 'page', parentModel, index },
({ mode }) => {
if (mode === 'edgeless') {
const gfx = std.get(GfxControllerIdentifier);
gfx.tool.setTool(DefaultTool);
}
}
); );
if (model.text?.length === 0) { if (model.text?.length === 0) {
std.store.deleteBlock(model); std.store.deleteBlock(model);
@@ -94,6 +94,9 @@ export {
type GfxToolsFullOptionValue, type GfxToolsFullOptionValue,
type GfxToolsMap, type GfxToolsMap,
type GfxToolsOption, type GfxToolsOption,
type ToolOptions,
type ToolOptionWithType,
type ToolType,
} from './tool/tool.js'; } from './tool/tool.js';
export { MouseButton, ToolController } from './tool/tool-controller.js'; export { MouseButton, ToolController } from './tool/tool-controller.js';
export { export {
@@ -10,10 +10,10 @@ import type { GfxController } from '../controller.js';
import { GfxExtension, GfxExtensionIdentifier } from '../extension.js'; import { GfxExtension, GfxExtensionIdentifier } from '../extension.js';
import { import {
type BaseTool, type BaseTool,
type GfxToolsFullOptionValue,
type GfxToolsMap,
type GfxToolsOption,
ToolIdentifier, ToolIdentifier,
type ToolOptions,
type ToolOptionWithType,
type ToolType,
} from './tool.js'; } from './tool.js';
type BuiltInHookEvent<T> = { type BuiltInHookEvent<T> = {
@@ -23,9 +23,9 @@ type BuiltInHookEvent<T> = {
type BuiltInEventMap = { type BuiltInEventMap = {
beforeToolUpdate: BuiltInHookEvent<{ beforeToolUpdate: BuiltInHookEvent<{
toolName: keyof GfxToolsMap; toolName: string;
}>; }>;
toolUpdate: BuiltInHookEvent<{ toolName: keyof GfxToolsMap }>; toolUpdate: BuiltInHookEvent<{ toolName: string }>;
}; };
type BuiltInSlotContext = { type BuiltInSlotContext = {
@@ -84,13 +84,11 @@ export class ToolController extends GfxExtension {
private readonly _disposableGroup = new DisposableGroup(); private readonly _disposableGroup = new DisposableGroup();
private readonly _toolOption$ = new Signal<GfxToolsFullOptionValue>( private readonly _toolOption$ = new Signal<ToolOptionWithType>({});
{} as GfxToolsFullOptionValue
);
private readonly _tools = new Map<string, BaseTool>(); private readonly _tools = new Map<string, BaseTool>();
readonly currentToolName$ = new Signal<keyof GfxToolsMap>(); readonly currentToolName$ = new Signal<string>();
readonly dragging$ = new Signal<boolean>(false); readonly dragging$ = new Signal<boolean>(false);
@@ -157,23 +155,11 @@ export class ToolController extends GfxExtension {
return { return {
peek() { peek() {
const option = self._toolOption$.peek() as unknown as { type: string }; return self._toolOption$.peek();
if (!option.type) {
option.type = '';
}
return option as GfxToolsFullOptionValue;
}, },
get value(): GfxToolsFullOptionValue { get value() {
const option = self._toolOption$.value as unknown as { type: string }; return self._toolOption$.value;
if (!option.type) {
option.type = '';
}
return option as GfxToolsFullOptionValue;
}, },
}; };
} }
@@ -481,9 +467,16 @@ export class ToolController extends GfxExtension {
tools.mounted(); tools.mounted();
} }
get<K extends keyof GfxToolsMap>(key: K): GfxToolsMap[K] { get = <T extends BaseTool>(type: ToolType<T>): T => {
return this._tools.get(key) as GfxToolsMap[K]; const instance = this._tools.get(type.toolName) as T | undefined;
} if (!instance) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
`Trying to get tool "${type.toolName}" is not registered`
);
}
return instance;
};
override mounted(): void { override mounted(): void {
const { addHook } = this._initializeEvents(); const { addHook } = this._initializeEvents();
@@ -499,24 +492,11 @@ export class ToolController extends GfxExtension {
}); });
} }
setTool(toolName: GfxToolsFullOptionValue, ...args: [void]): void; setTool = <T extends BaseTool>(
setTool<K extends keyof GfxToolsMap>( toolType: ToolType<T>,
toolName: K, options?: ToolOptions<T>
...args: K extends keyof GfxToolsOption ): void => {
? [option: GfxToolsOption[K]] const toolNameStr = toolType.toolName;
: [void]
): void;
setTool<K extends keyof GfxToolsMap>(
toolName: K | GfxToolsFullOptionValue,
...args: K extends keyof GfxToolsOption
? [option: GfxToolsOption[K]]
: [void]
): void {
const option = typeof toolName === 'string' ? args[0] : toolName;
const toolNameStr =
typeof toolName === 'string'
? toolName
: ((toolName as { type: string }).type as K);
const beforeUpdateCtx = this._createBuiltInHookCtx('beforeToolUpdate', { const beforeUpdateCtx = this._createBuiltInHookCtx('beforeToolUpdate', {
toolName: toolNameStr, toolName: toolNameStr,
@@ -541,18 +521,18 @@ export class ToolController extends GfxExtension {
); );
} }
currentTool.activatedOption = option ?? {}; currentTool.activatedOption = options ?? {};
this._toolOption$.value = { this._toolOption$.value = {
...currentTool.activatedOption, toolType,
type: toolNameStr, options: currentTool.activatedOption,
} as GfxToolsFullOptionValue; };
currentTool.activate(currentTool.activatedOption); currentTool.activate(currentTool.activatedOption);
const afterUpdateCtx = this._createBuiltInHookCtx('toolUpdate', { const afterUpdateCtx = this._createBuiltInHookCtx('toolUpdate', {
toolName: toolNameStr, toolName: toolNameStr,
}); });
this._builtInHookSlot.next(afterUpdateCtx.slotCtx); this._builtInHookSlot.next(afterUpdateCtx.slotCtx);
} };
override unmounted(): void { override unmounted(): void {
this.currentTool$.peek()?.deactivate(); this.currentTool$.peek()?.deactivate();
@@ -111,6 +111,19 @@ export abstract class BaseTool<
export const ToolIdentifier = createIdentifier<BaseTool>('GfxTool'); export const ToolIdentifier = createIdentifier<BaseTool>('GfxTool');
export type ToolType<T extends BaseTool = BaseTool> = {
new (gfx: GfxController): T;
toolName: string;
};
export type ToolOptions<T extends BaseTool> =
T extends BaseTool<infer O> ? O : never;
export type ToolOptionWithType<T extends BaseTool = BaseTool> = {
toolType?: ToolType<T>;
options?: ToolOptions<T>;
};
export interface GfxToolsMap {} export interface GfxToolsMap {}
export interface GfxToolsOption {} export interface GfxToolsOption {}
@@ -2,6 +2,7 @@ import '@toeverything/theme/style.css';
import '@blocksuite/affine/gfx/pointer'; import '@blocksuite/affine/gfx/pointer';
import type { EdgelessRootBlockComponent } from '@blocksuite/affine/blocks/root'; import type { EdgelessRootBlockComponent } from '@blocksuite/affine/blocks/root';
import { DefaultTool } from '@blocksuite/affine/blocks/surface';
import { ColorScheme } from '@blocksuite/affine/model'; import { ColorScheme } from '@blocksuite/affine/model';
import { ThemeProvider } from '@blocksuite/affine/shared/services'; import { ThemeProvider } from '@blocksuite/affine/shared/services';
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from 'vitest';
@@ -17,7 +18,7 @@ describe('theme service', () => {
edgeless = getDocRootBlock(doc, editor, 'edgeless'); edgeless = getDocRootBlock(doc, editor, 'edgeless');
edgeless.gfx.tool.setTool('default'); edgeless.gfx.tool.setTool(DefaultTool);
const themeService = edgeless.gfx.std.get(ThemeProvider); const themeService = edgeless.gfx.std.get(ThemeProvider);
themeService.theme$.value = ColorScheme.Light; themeService.theme$.value = ColorScheme.Light;
@@ -1,5 +1,8 @@
import type { EdgelessRootBlockComponent } from '@blocksuite/affine/blocks/root'; import type { EdgelessRootBlockComponent } from '@blocksuite/affine/blocks/root';
import type { SurfaceBlockComponent } from '@blocksuite/affine/blocks/surface'; import {
DefaultTool,
type SurfaceBlockComponent,
} from '@blocksuite/affine/blocks/surface';
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from 'vitest';
import { click, drag, wait } from '../utils/common.js'; import { click, drag, wait } from '../utils/common.js';
@@ -18,7 +21,7 @@ describe('default tool', () => {
surface = getSurface(window.doc, window.editor); surface = getSurface(window.doc, window.editor);
service = edgeless.service; service = edgeless.service;
edgeless.gfx.tool.setTool('default'); edgeless.gfx.tool.setTool(DefaultTool);
return cleanup; return cleanup;
}); });
@@ -16,6 +16,7 @@ import '@shoelace-style/shoelace/dist/themes/light.css';
import '@shoelace-style/shoelace/dist/themes/dark.css'; import '@shoelace-style/shoelace/dist/themes/dark.css';
import './left-side-panel.js'; import './left-side-panel.js';
import { PresentTool } from '@blocksuite/affine/blocks/frame';
import { ExportManager } from '@blocksuite/affine/blocks/surface'; import { ExportManager } from '@blocksuite/affine/blocks/surface';
import { toast } from '@blocksuite/affine/components/toast'; import { toast } from '@blocksuite/affine/components/toast';
import { StoreExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader'; import { StoreExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
@@ -554,7 +555,7 @@ export class StarterDebugMenu extends ShadowlessElement {
private _present() { private _present() {
if (!this.editor.std || !this.editor.host) return; if (!this.editor.std || !this.editor.host) return;
const gfx = this.editor.std.get(GfxControllerIdentifier); const gfx = this.editor.std.get(GfxControllerIdentifier);
gfx.tool.setTool('frameNavigator', { gfx.tool.setTool(PresentTool, {
mode: 'fit', mode: 'fit',
}); });
} }
@@ -1,4 +1,5 @@
import { splitElements } from '@blocksuite/affine/blocks/root'; import { splitElements } from '@blocksuite/affine/blocks/root';
import { DefaultTool } from '@blocksuite/affine/blocks/surface';
import type * as PointerEffect from '@blocksuite/affine/gfx/pointer'; import type * as PointerEffect from '@blocksuite/affine/gfx/pointer';
import { import {
CodeBlockModel, CodeBlockModel,
@@ -358,7 +359,7 @@ function updateEdgelessAIPanelConfig<
config.hideCallback = () => { config.hideCallback = () => {
aiPanel.updateComplete aiPanel.updateComplete
.finally(() => { .finally(() => {
edgelessCopilot.gfx.tool.setTool('default'); edgelessCopilot.gfx.tool.setTool(DefaultTool);
edgelessCopilot.gfx.selection.set({ edgelessCopilot.gfx.selection.set({
elements: [], elements: [],
editing: false, editing: false,
@@ -431,7 +432,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
if (!referenceElement) { if (!referenceElement) {
const gfx = host.std.get(GfxControllerIdentifier); const gfx = host.std.get(GfxControllerIdentifier);
gfx?.tool.setTool({ type: 'default' }); gfx?.tool.setTool(DefaultTool);
edgelessCopilot.lockToolbar(false); edgelessCopilot.lockToolbar(false);
return; return;
} }
@@ -1,4 +1,5 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */ /* oxlint-disable @typescript-eslint/no-non-null-assertion */
import { DefaultTool } from '@blocksuite/affine/blocks/surface';
import { IS_MAC } from '@blocksuite/affine/global/env'; import { IS_MAC } from '@blocksuite/affine/global/env';
import { import {
Bound, Bound,
@@ -67,7 +68,7 @@ export class CopilotTool extends BaseTool {
this._dragging = false; this._dragging = false;
this.dragStartPoint = [0, 0]; this.dragStartPoint = [0, 0];
this.dragLastPoint = [0, 0]; this.dragLastPoint = [0, 0];
this.gfx.tool.setTool('default'); this.gfx.tool.setTool(DefaultTool);
} }
override activate(): void { override activate(): void {
@@ -129,7 +130,7 @@ export class CopilotTool extends BaseTool {
: evt.raw.ctrlKey); : evt.raw.ctrlKey);
if (useCopilot) { if (useCopilot) {
this.controller.setTool('copilot'); this.controller.setTool(CopilotTool);
return false; return false;
} }
@@ -143,7 +144,7 @@ export class CopilotTool extends BaseTool {
return; return;
} }
this.gfx.tool.setTool('default'); this.gfx.tool.setTool(DefaultTool);
} }
updateDragPointsWith(selectedElements: GfxModel[], padding = 0) { updateDragPointsWith(selectedElements: GfxModel[], padding = 0) {
@@ -10,7 +10,7 @@ import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import type { AIItemGroupConfig } from '../../components/ai-item/types'; import type { AIItemGroupConfig } from '../../components/ai-item/types';
import type { CopilotTool } from '../../tool/copilot-tool'; import { CopilotTool } from '../../tool/copilot-tool';
export class EdgelessCopilotToolbarEntry extends WithDisposable(LitElement) { export class EdgelessCopilotToolbarEntry extends WithDisposable(LitElement) {
static override styles = css` static override styles = css`
@@ -51,7 +51,7 @@ export class EdgelessCopilotToolbarEntry extends WithDisposable(LitElement) {
} }
}); });
this._gfx.tool.setTool('copilot'); this._gfx.tool.setTool(CopilotTool);
(this._gfx.tool.currentTool$.peek() as CopilotTool).updateSelectionWith( (this._gfx.tool.currentTool$.peek() as CopilotTool).updateSelectionWith(
Array.from(toBeSelected), Array.from(toBeSelected),
10 10
@@ -1,3 +1,4 @@
import { CopilotTool } from '@affine/core/blocksuite/ai/tool/copilot-tool';
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine/blocks/surface'; import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine/blocks/surface';
import { import {
Bound, Bound,
@@ -205,7 +206,7 @@ export class EdgelessCopilotWidget extends WidgetComponent<RootBlockModel> {
override connectedCallback(): void { override connectedCallback(): void {
super.connectedCallback(); super.connectedCallback();
const CopilotSelectionTool = this.gfx.tool.get('copilot'); const CopilotSelectionTool = this.gfx.tool.get(CopilotTool);
this._disposables.add( this._disposables.add(
CopilotSelectionTool.draggingAreaUpdated.subscribe(shouldShowPanel => { CopilotSelectionTool.draggingAreaUpdated.subscribe(shouldShowPanel => {
@@ -1,5 +1,7 @@
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor'; import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
import type { DefaultOpenProperty } from '@affine/core/components/doc-properties'; import type { DefaultOpenProperty } from '@affine/core/components/doc-properties';
import { PresentTool } from '@blocksuite/affine/blocks/frame';
import { DefaultTool } from '@blocksuite/affine/blocks/surface';
import type { DocTitle } from '@blocksuite/affine/fragments/doc-title'; import type { DocTitle } from '@blocksuite/affine/fragments/doc-title';
import type { DocMode, ReferenceParams } from '@blocksuite/affine/model'; import type { DocMode, ReferenceParams } from '@blocksuite/affine/model';
import { HighlightSelection } from '@blocksuite/affine/shared/selection'; import { HighlightSelection } from '@blocksuite/affine/shared/selection';
@@ -75,9 +77,11 @@ export class Editor extends Entity {
GfxControllerIdentifier GfxControllerIdentifier
); );
if (!gfx) return; if (!gfx) return;
gfx.tool.setTool({ if (!this.isPresenting$.value) {
type: !this.isPresenting$.value ? 'frameNavigator' : 'default', gfx.tool.setTool(PresentTool);
}); } else {
gfx.tool.setTool(DefaultTool);
}
} }
setSelector(selector: EditorSelector | undefined) { setSelector(selector: EditorSelector | undefined) {
+20 -11
View File
@@ -1,8 +1,11 @@
import '../declare-test-window.js'; import '../declare-test-window.js';
import type { NoteBlockModel, NoteDisplayMode } from '@blocksuite/affine-model'; import { ConnectorTool } from '@blocksuite/affine/gfx/connector';
import type { IPoint, IVec } from '@blocksuite/global/gfx'; import { ShapeTool } from '@blocksuite/affine/gfx/shape';
import { sleep } from '@blocksuite/global/utils'; import type { IPoint, IVec } from '@blocksuite/affine/global/gfx';
import { sleep } from '@blocksuite/affine/global/utils';
import type { NoteBlockModel, NoteDisplayMode } from '@blocksuite/affine/model';
import type { ToolOptions } from '@blocksuite/affine/std/gfx';
import type { Locator, Page } from '@playwright/test'; import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
@@ -394,21 +397,23 @@ export async function assertEdgelessShapeType(page: Page, type: ShapeName) {
throw new Error('Missing edgeless page'); throw new Error('Missing edgeless page');
} }
const tool = container.gfx.tool.currentToolOption$.peek(); const tool = container.gfx.tool.currentToolOption$.peek();
if (tool.type !== 'shape') throw new Error('Expected shape tool'); if (tool.toolType?.toolName !== 'shape')
throw new Error('Expected shape tool');
return tool.shapeName; return (tool.options as ToolOptions<ShapeTool>).shapeName;
}); });
expect(type).toEqual(curType); expect(type).toEqual(curType);
} }
export async function assertEdgelessTool(page: Page, mode: EdgelessTool) { export async function assertEdgelessTool(page: Page, mode: string) {
await page.waitForTimeout(1000);
const type = await page.evaluate(() => { const type = await page.evaluate(() => {
const container = document.querySelector('affine-edgeless-root'); const container = document.querySelector('affine-edgeless-root');
if (!container) { if (!container) {
throw new Error('Missing edgeless page'); throw new Error('Missing edgeless page');
} }
return container.gfx.tool.currentToolOption$.peek().type; return container.gfx.tool.currentTool$.peek()?.toolName;
}); });
expect(type).toEqual(mode); expect(type).toEqual(mode);
} }
@@ -417,17 +422,21 @@ export async function assertEdgelessConnectorToolMode(
page: Page, page: Page,
mode: ConnectorMode mode: ConnectorMode
) { ) {
const tool = await page.evaluate(() => { const [toolName, toolOptions] = await page.evaluate(() => {
const container = document.querySelector('affine-edgeless-root'); const container = document.querySelector('affine-edgeless-root');
if (!container) { if (!container) {
throw new Error('Missing edgeless page'); throw new Error('Missing edgeless page');
} }
return container.gfx.tool.currentToolOption$.peek(); const tool = container.gfx.tool.currentToolOption$.peek();
return [
tool.toolType?.toolName as string | undefined,
tool.options as ToolOptions<ConnectorTool>,
];
}); });
if (tool.type !== 'connector') { if (toolName !== 'connector') {
throw new Error('Expected connector tool'); throw new Error('Expected connector tool');
} }
expect(tool.mode).toEqual(mode); expect((toolOptions as ToolOptions<ConnectorTool>).mode).toEqual(mode);
} }
export async function getEdgelessBlockChild(page: Page) { export async function getEdgelessBlockChild(page: Page) {
+4
View File
@@ -212,6 +212,7 @@ export const PackageList = [
'blocksuite/affine/blocks/surface', 'blocksuite/affine/blocks/surface',
'blocksuite/affine/components', 'blocksuite/affine/components',
'blocksuite/affine/ext-loader', 'blocksuite/affine/ext-loader',
'blocksuite/affine/gfx/pointer',
'blocksuite/affine/inlines/reference', 'blocksuite/affine/inlines/reference',
'blocksuite/affine/model', 'blocksuite/affine/model',
'blocksuite/affine/rich-text', 'blocksuite/affine/rich-text',
@@ -247,6 +248,7 @@ export const PackageList = [
'blocksuite/affine/blocks/surface', 'blocksuite/affine/blocks/surface',
'blocksuite/affine/components', 'blocksuite/affine/components',
'blocksuite/affine/ext-loader', 'blocksuite/affine/ext-loader',
'blocksuite/affine/gfx/pointer',
'blocksuite/affine/model', 'blocksuite/affine/model',
'blocksuite/affine/shared', 'blocksuite/affine/shared',
'blocksuite/affine/widgets/edgeless-toolbar', 'blocksuite/affine/widgets/edgeless-toolbar',
@@ -598,6 +600,7 @@ export const PackageList = [
'blocksuite/affine/components', 'blocksuite/affine/components',
'blocksuite/affine/ext-loader', 'blocksuite/affine/ext-loader',
'blocksuite/affine/gfx/connector', 'blocksuite/affine/gfx/connector',
'blocksuite/affine/gfx/pointer',
'blocksuite/affine/gfx/shape', 'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text', 'blocksuite/affine/gfx/text',
'blocksuite/affine/model', 'blocksuite/affine/model',
@@ -886,6 +889,7 @@ export const PackageList = [
location: 'blocksuite/affine/widgets/frame-title', location: 'blocksuite/affine/widgets/frame-title',
name: '@blocksuite/affine-widget-frame-title', name: '@blocksuite/affine-widget-frame-title',
workspaceDependencies: [ workspaceDependencies: [
'blocksuite/affine/blocks/surface',
'blocksuite/affine/components', 'blocksuite/affine/components',
'blocksuite/affine/ext-loader', 'blocksuite/affine/ext-loader',
'blocksuite/affine/model', 'blocksuite/affine/model',
+4
View File
@@ -2668,6 +2668,7 @@ __metadata:
"@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-ext-loader": "workspace:*"
"@blocksuite/affine-gfx-pointer": "workspace:*"
"@blocksuite/affine-inline-reference": "workspace:*" "@blocksuite/affine-inline-reference": "workspace:*"
"@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-model": "workspace:*"
"@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-rich-text": "workspace:*"
@@ -2699,6 +2700,7 @@ __metadata:
"@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-ext-loader": "workspace:*"
"@blocksuite/affine-gfx-pointer": "workspace:*"
"@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-model": "workspace:*"
"@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-shared": "workspace:*"
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*"
@@ -3282,6 +3284,7 @@ __metadata:
"@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-ext-loader": "workspace:*"
"@blocksuite/affine-gfx-connector": "workspace:*" "@blocksuite/affine-gfx-connector": "workspace:*"
"@blocksuite/affine-gfx-pointer": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*" "@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*" "@blocksuite/affine-gfx-text": "workspace:*"
"@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-model": "workspace:*"
@@ -3843,6 +3846,7 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@blocksuite/affine-widget-frame-title@workspace:blocksuite/affine/widgets/frame-title" resolution: "@blocksuite/affine-widget-frame-title@workspace:blocksuite/affine/widgets/frame-title"
dependencies: dependencies:
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-ext-loader": "workspace:*"
"@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-model": "workspace:*"