Skip to content

Commit

Permalink
fix: test
Browse files Browse the repository at this point in the history
  • Loading branch information
doouding committed Oct 11, 2024
1 parent aa1eace commit bf1aa32
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,12 @@ export class DefaultTool extends BaseTool {
}
})
);

this.addHook('beforeToolUpdate', ctx => {
if (ctx.data.toolName !== 'default') {
this.gfx.selection.clear();
}
});
}

override pointerMove(e: PointerEventState) {
Expand Down
128 changes: 112 additions & 16 deletions packages/framework/block-std/src/gfx/tool/tool-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,73 @@ const supportedEvents = [
'contextMenu',
] as const;

export interface ToolEventTarget {
addHook(
evtName: (typeof supportedEvents)[number],
handler: (evtState: PointerEventState) => undefined | boolean
): () => void;
const builtInHooks: (keyof BuiltInHooks)[] = ['beforeToolUpdate', 'toolUpdate'];

type BuiltInHookEvent<T> = {
evtName: keyof BuiltInHooks;
data: T;
preventDefault(): void;
};

type BuiltInHooks = {
beforeToolUpdate: BuiltInHookEvent<{
toolName: keyof BlockSuite.GfxToolsMap;
}>;
toolUpdate: BuiltInHookEvent<{ toolName: keyof BlockSuite.GfxToolsMap }>;
};

class MiniEventEmitter<T> {
private _listeners = new Map<keyof T, ((payload: T[keyof T]) => void)[]>();

destroy() {
this._listeners.clear();
}

emit<K extends keyof T>(event: K, payload: T[K]) {
this._listeners.get(event)?.forEach(listener => listener(payload));
}

off<K extends keyof T>(event: K, listener: (payload: T[K]) => void) {
const listeners = this._listeners.get(event) ?? [];
const idx = listeners.indexOf(listener as (payload: T[keyof T]) => void);

if (idx !== -1) {
listeners.splice(idx, 1);
}
}

on<K extends keyof T>(event: K, listener: (payload: T[K]) => void) {
this._listeners.set(event, this._listeners.get(event) ?? []);
this._listeners.get(event)!.push(listener as (payload: T[keyof T]) => void);

return () => {
this.off(event, listener);
};
}
}

export type SupportedEvents = (typeof supportedEvents)[number];

export interface ToolEventTarget {
addHook<K extends keyof BuiltInHooks | SupportedEvents>(
evtName: K,
handler: (
evtState: K extends keyof BuiltInHooks
? BuiltInHooks[K]
: PointerEventState
) => void | boolean
): void;
}

export const eventTarget = Symbol('eventTarget');

export class ToolController extends GfxExtension {
static override key = 'ToolController';

private _disposableGroup = new DisposableGroup();

private _eventEmitter = new MiniEventEmitter<BuiltInHooks>();

private _tools = new Map<string, BaseTool>();

readonly currentToolName$ = new Signal<keyof BlockSuite.GfxToolsMap>();
Expand Down Expand Up @@ -159,10 +210,33 @@ export class ToolController extends GfxExtension {
});
}

private _createBuiltInHookCtx<K extends keyof BuiltInHooks>(
eventName: K,
data: BuiltInHooks[K]['data']
): {
prevented: boolean;
evt: BuiltInHooks[K];
} {
const ctx = {
prevented: false,
evt: {
evtName: eventName,
data,
preventDefault() {
ctx.prevented = true;
},
},
};

return ctx;
}

private _initializeEvents() {
const hooks: Record<
string,
((evtState: PointerEventState) => undefined | boolean)[]
((
evtState: PointerEventState | BuiltInHooks[keyof BuiltInHooks]
) => undefined | boolean)[]
> = {};
const invokeToolHandler = (
evtName: SupportedEvents,
Expand All @@ -187,15 +261,20 @@ export class ToolController extends GfxExtension {
* @param evtName
* @param handler
*/
const addHook = (
evtName: (typeof supportedEvents)[number],
handler: (evtState: PointerEventState) => undefined | boolean
) => {
const addHook: ToolEventTarget['addHook'] = (evtName, handler) => {
hooks[evtName] = hooks[evtName] ?? [];
hooks[evtName].push(handler);
hooks[evtName].push(
handler as (
evtState: PointerEventState | BuiltInHooks[keyof BuiltInHooks]
) => undefined | boolean
);

return () => {
const idx = hooks[evtName].indexOf(handler);
const idx = hooks[evtName].indexOf(
handler as (
evtState: PointerEventState | BuiltInHooks[keyof BuiltInHooks]
) => undefined | boolean
);
if (idx !== -1) {
hooks[evtName].splice(idx, 1);
}
Expand Down Expand Up @@ -344,6 +423,12 @@ export class ToolController extends GfxExtension {
);
});

builtInHooks.forEach(name => {
this._eventEmitter.on(name, evt => {
hooks[name]?.forEach(hook => hook(evt));
});
});

return {
addHook,
};
Expand Down Expand Up @@ -393,23 +478,33 @@ export class ToolController extends GfxExtension {
? [option: BlockSuite.GfxToolsOption[K]]
: [void]
): void {
this.currentTool$.peek()?.deactivate();

const option = typeof toolName === 'string' ? args[0] : toolName;

this.currentToolName$.value =
const toolNameStr =
typeof toolName === 'string'
? toolName
: // @ts-ignore
(toolName.type as K);

const beforeUpdateCtx = this._createBuiltInHookCtx('beforeToolUpdate', {
toolName: toolNameStr,
});
this._eventEmitter.emit('beforeToolUpdate', beforeUpdateCtx.evt);

this.currentTool$.peek()?.deactivate();
this.currentToolName$.value = toolNameStr;

const currentTool = this.currentTool$.peek();
if (!currentTool) {
throw new Error(`Tool "${this.currentToolName$.value}" is not defined`);
}

currentTool.activatedOption = option ?? {};
currentTool.activate(currentTool.activatedOption);

const afterUpdateCtx = this._createBuiltInHookCtx('toolUpdate', {
toolName: toolNameStr,
});
this._eventEmitter.emit('toolUpdate', afterUpdateCtx.evt);
}

override unmounted(): void {
Expand All @@ -418,6 +513,7 @@ export class ToolController extends GfxExtension {
tool.onunload();
tool['disposable'].dispose();
});
this._eventEmitter.destroy();
}
}

Expand Down
13 changes: 5 additions & 8 deletions packages/framework/block-std/src/gfx/tool/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {

import type { PointerEventState } from '../../event/index.js';
import type { ExtensionType } from '../../extension/extension.js';
import type { SupportedEvents, ToolEventTarget } from './tool-controller.js';
import type { ToolEventTarget } from './tool-controller.js';

import { type GfxController, GfxControllerIdentifier } from '../controller.js';

Expand All @@ -19,6 +19,10 @@ export abstract class BaseTool<Option = Record<string, unknown>> {

activatedOption: Option = {} as Option;

addHook: ToolEventTarget['addHook'] = (evtName, handler) => {
this.eventTarget.addHook(evtName, handler);
};

/**
* The `disposable` will be disposed when the tool is unloaded.
*/
Expand Down Expand Up @@ -52,13 +56,6 @@ export abstract class BaseTool<Option = Record<string, unknown>> {
*/
activate(_: Option): void {}

addHook(
evtName: SupportedEvents,
handler: (evtState: PointerEventState) => undefined | boolean
): void {
this.eventTarget.addHook(evtName, handler);
}

click(_: PointerEventState): void {}

contextMenu(_: PointerEventState): void {}
Expand Down

0 comments on commit bf1aa32

Please sign in to comment.