Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- chore(TS): Fix event types and .once this binding [#9119](https://github.com/fabricjs/fabric.js/pull/9130)
- chore(TS): export types [#9129](https://github.com/fabricjs/fabric.js/pull/9129)
- ci(e2e): support relative imports [#9108](https://github.com/fabricjs/fabric.js/pull/9108)
- chore(TS): complete type check [#9119](https://github.com/fabricjs/fabric.js/pull/9119)
Expand Down
63 changes: 34 additions & 29 deletions src/EventTypeDefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,19 @@ export type Transform = {
actionPerformed: boolean;
};

export type TEvent<E extends Event = TPointerEvent> = {
export interface TEvent<E extends Event = TPointerEvent> {
e: E;
};
}

type TEventWithTarget<E extends Event = TPointerEvent> = TEvent<E> & {
interface TEventWithTarget<E extends Event = TPointerEvent> extends TEvent<E> {
target: FabricObject;
};
}

export type BasicTransformEvent<E extends Event = TPointerEvent> = TEvent<E> & {
export interface BasicTransformEvent<E extends Event = TPointerEvent>
extends TEvent<E> {
transform: Transform;
pointer: Point;
};
}

export type TModificationEvents =
| 'moving'
Expand All @@ -100,11 +101,12 @@ export type TModificationEvents =
| 'skewing'
| 'resizing';

export type ModifiedEvent<E extends Event = TPointerEvent> = TEvent<E> & {
export interface ModifiedEvent<E extends Event = TPointerEvent>
extends TEvent<E> {
transform: Transform;
target: FabricObject;
action: string;
};
}

type ModificationEventsSpec<
Prefix extends string = '',
Expand All @@ -123,42 +125,45 @@ type CanvasModificationEvents = ModificationEventsSpec<
'before:transform': TEvent & { transform: Transform };
};

export type TPointerEventInfo<E extends TPointerEvent = TPointerEvent> =
TEvent<E> & {
target?: FabricObject;
subTargets?: FabricObject[];
button?: number;
isClick: boolean;
pointer: Point;
transform?: Transform | null;
absolutePointer: Point;
currentSubTargets?: FabricObject[];
currentTarget?: FabricObject | null;
};
export interface TPointerEventInfo<E extends TPointerEvent = TPointerEvent>
extends TEvent<E> {
target?: FabricObject;
subTargets?: FabricObject[];
button?: number;
isClick: boolean;
pointer: Point;
transform?: Transform | null;
absolutePointer: Point;
currentSubTargets?: FabricObject[];
currentTarget?: FabricObject | null;
}

type SimpleEventHandler<T extends Event = TPointerEvent> = TEvent<T> & {
interface SimpleEventHandler<T extends Event = TPointerEvent>
extends TEvent<T> {
target?: FabricObject;
subTargets: FabricObject[];
};
}

type InEvent = {
interface InEvent {
previousTarget?: FabricObject;
};
}

type OutEvent = {
interface OutEvent {
nextTarget?: FabricObject;
};
}

export type DragEventData = TEvent<DragEvent> & {
export interface DragEventData extends TEvent<DragEvent> {
target?: FabricObject;
subTargets?: FabricObject[];
dragSource?: FabricObject;
canDrop?: boolean;
didDrop?: boolean;
dropTarget?: FabricObject;
};
}

export type DropEventData = DragEventData & { pointer: Point };
export interface DropEventData extends DragEventData {
pointer: Point;
}

interface DnDEvents {
dragstart: TEventWithTarget<DragEvent>;
Expand Down
60 changes: 25 additions & 35 deletions src/Observable.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
export type TEventCallback<T = any> = (options: T) => any;

type EventRegistryObject<
K extends string | number | symbol = string,
E = any
> = Record<K, TEventCallback<E>>;
type EventRegistryObject<E> = {
[K in keyof E]?: TEventCallback<E[K]>;
};

/**
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}
Expand All @@ -25,25 +24,19 @@ export class Observable<EventSpec> {
eventName: K,
handler: TEventCallback<E>
): VoidFunction;
on<K extends string, E>(
eventName: K,
handler: TEventCallback<E>
): VoidFunction;
on<K extends keyof EventSpec, E extends EventSpec[K]>(
handlers: EventRegistryObject<K, E>
): VoidFunction;
on(handlers: EventRegistryObject<EventSpec>): VoidFunction;
on<K extends keyof EventSpec, E extends EventSpec[K]>(
arg0: K | EventRegistryObject<K, E>,
arg0: K | EventRegistryObject<EventSpec>,
handler?: TEventCallback<E>
): VoidFunction {
if (!this.__eventListeners) {
this.__eventListeners = {} as Record<keyof EventSpec, TEventCallback[]>;
}
if (typeof arg0 === 'object') {
// one object with key/value pairs was passed
for (const eventName in arg0) {
this.on(eventName as K, arg0[eventName]);
}
Object.entries(arg0).forEach(([eventName, handler]) => {
this.on(eventName as K, handler as TEventCallback);
});
return () => this.off(arg0);
} else if (handler) {
const eventName = arg0;
Expand All @@ -70,29 +63,26 @@ export class Observable<EventSpec> {
eventName: K,
handler: TEventCallback<E>
): VoidFunction;
once<K extends string, E>(
eventName: K,
handler: TEventCallback<E>
): VoidFunction;
once<K extends keyof EventSpec, E extends EventSpec[K]>(
handlers: EventRegistryObject<K, E>
): VoidFunction;
once(handlers: EventRegistryObject<EventSpec>): VoidFunction;
once<K extends keyof EventSpec, E extends EventSpec[K]>(
arg0: K | EventRegistryObject<K, E>,
arg0: K | EventRegistryObject<EventSpec>,
handler?: TEventCallback<E>
): VoidFunction {
if (typeof arg0 === 'object') {
// one object with key/value pairs was passed
const disposers: VoidFunction[] = [];
for (const eventName in arg0) {
disposers.push(this.once(eventName as K, arg0[eventName]));
}
Object.entries(arg0).forEach(([eventName, handler]) => {
disposers.push(this.once(eventName as K, handler as TEventCallback));
});
return () => disposers.forEach((d) => d());
} else if (handler) {
const disposer = this.on<K, E>(arg0, (...args) => {
handler(...args);
disposer();
});
const disposer = this.on<K, E>(
arg0,
function onceHandler(this: Observable<EventSpec>, ...args) {
handler.call(this, ...args);
disposer();
}
);
return disposer;
} else {
// noop
Expand Down Expand Up @@ -132,13 +122,13 @@ export class Observable<EventSpec> {
* unsubscribe event listeners
* @param handlers handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
*/
off(handlers: EventRegistryObject): void;
off(handlers: EventRegistryObject<EventSpec>): void;
/**
* unsubscribe all event listeners
*/
off(): void;
off<K extends keyof EventSpec>(
arg0?: K | EventRegistryObject,
arg0?: K | EventRegistryObject<EventSpec>,
handler?: TEventCallback
) {
if (!this.__eventListeners) {
Expand All @@ -153,9 +143,9 @@ export class Observable<EventSpec> {
}
// one object with key/value pairs was passed
else if (typeof arg0 === 'object') {
for (const eventName in arg0) {
this._removeEventListener(eventName as K, arg0[eventName]);
}
Object.entries(arg0).forEach(([eventName, handler]) => {
this._removeEventListener(eventName as K, handler as TEventCallback);
});
} else {
this._removeEventListener(arg0, handler);
}
Expand Down
15 changes: 15 additions & 0 deletions test/unit/observable.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ QUnit.test('fire once', function (assert) {
assert.equal(eventFired, 1);
});

QUnit.test('fire once context', function (assert) {
var foo = new fabric.Observable();

var eventFired = false;
var context;
foo.once('bar:baz', function() {
context = this;
eventFired = true;
});

foo.fire('bar:baz');
assert.equal(eventFired, true);
assert.equal(context, foo);
});

QUnit.test('fire once multiple handlers', function (assert) {
var foo = new fabric.Observable();
var eventFired = 0;
Expand Down