-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Observable types #8431
Observable types #8431
Changes from 21 commits
7dd2dec
853cdb4
cabf258
9af645e
a77e0fa
a80fa3d
abe7c5b
a10df06
ce34790
8b58223
ef73d35
586350c
f627e24
2159c8b
1fc674a
8602748
356d1a4
e7a4ddc
8dc94f1
6f2b877
4b2c1c6
ce006dc
2f4c681
63c8ef0
5975caf
6509e20
c83c7c6
d3ff302
6e6cdab
c1a0615
15e09bd
fca0374
152925d
683188c
c5ddb70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
import type { Control } from './controls/control.class'; | ||
import type { Point } from './point.class'; | ||
import type { FabricObject } from './shapes/fabricObject.class'; | ||
import type { Group } from './shapes/group.class'; | ||
import type { TOriginX, TOriginY, TRadian } from './typedefs'; | ||
import type { saveObjectTransform } from './util/misc/objectTransforms'; | ||
import type { Canvas } from './__types__'; | ||
|
||
export type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey'; | ||
|
||
export type TPointerEvent = MouseEvent | TouchEvent; | ||
|
||
export type TransformAction<T extends Transform = Transform, R = void> = ( | ||
eventData: TPointerEvent, | ||
transform: T, | ||
x: number, | ||
y: number | ||
) => R; | ||
|
||
export type TransformActionHandler<T extends Transform = Transform> = | ||
TransformAction<T, boolean>; | ||
|
||
export type ControlCallback<R = void> = ( | ||
eventData: TPointerEvent, | ||
control: Control, | ||
fabricObject: FabricObject | ||
) => R; | ||
|
||
export type ControlCursorCallback = ControlCallback<string>; | ||
|
||
/** | ||
* relative to target's containing coordinate plane | ||
* both agree on every point | ||
*/ | ||
export type Transform = { | ||
target: FabricObject; | ||
action: string; | ||
actionHandler: TransformActionHandler; | ||
corner: string; | ||
scaleX: number; | ||
scaleY: number; | ||
skewX: number; | ||
skewY: number; | ||
offsetX: number; | ||
offsetY: number; | ||
originX: TOriginX; | ||
originY: TOriginY; | ||
ex: number; | ||
ey: number; | ||
lastX: number; | ||
lastY: number; | ||
theta: TRadian; | ||
width: number; | ||
height: number; | ||
shiftKey: boolean; | ||
altKey: boolean; | ||
original: ReturnType<typeof saveObjectTransform>; | ||
}; | ||
|
||
export type TEvent<E extends Event = TPointerEvent> = { | ||
e: E; | ||
}; | ||
|
||
export type BasicTransformEvent<E extends Event = TPointerEvent> = TEvent<E> & { | ||
transform: Transform; | ||
pointer: Point; | ||
}; | ||
|
||
export type TModificationEvents = | ||
| 'moving' | ||
| 'scaling' | ||
| 'rotating' | ||
| 'skewing' | ||
| 'resizing'; | ||
|
||
type ObjectModifiedEvents = Record<TModificationEvents, BasicTransformEvent> & { | ||
modified: BasicTransformEvent | never; | ||
}; | ||
|
||
type CanvasModifiedEvents = Record< | ||
`object:${keyof ObjectModifiedEvents}`, | ||
BasicTransformEvent & { target: FabricObject } | ||
>; | ||
|
||
export type TransformEvent<T extends Event = TPointerEvent> = | ||
BasicTransformEvent<T> & { | ||
target: FabricObject; | ||
subTargets: FabricObject[]; | ||
button: number; | ||
isClick: boolean; | ||
pointer: Point; | ||
absolutePointer: Point; | ||
}; | ||
|
||
type SimpleEventHandler<T extends Event = TPointerEvent> = TEvent<T> & { | ||
target: FabricObject; | ||
subTargets: FabricObject[]; | ||
}; | ||
|
||
type InEvent = { | ||
previousTarget?: FabricObject; | ||
}; | ||
|
||
type OutEvent = { | ||
nextTarget?: FabricObject; | ||
}; | ||
|
||
type DragEventData = TEvent<DragEvent> & { | ||
target: FabricObject; | ||
subTargets?: FabricObject[]; | ||
dragSource?: FabricObject; | ||
canDrop?: boolean; | ||
dropTarget?: FabricObject; | ||
}; | ||
|
||
type DropEventData = DragEventData & { pointer: Point }; | ||
|
||
type DnDEvents = { | ||
dragstart: TEvent<DragEvent> & { target: FabricObject }; | ||
drag: DragEventData; | ||
dragover: DragEventData; | ||
dragenter: DragEventData & InEvent; | ||
dragleave: DragEventData & OutEvent; | ||
dragend: DragEventData; | ||
'drop:before': DropEventData; | ||
drop: DropEventData; | ||
'drop:after': DropEventData; | ||
}; | ||
|
||
type CanvasDnDEvents = DnDEvents & { | ||
'drag:enter': DragEventData & InEvent; | ||
'drag:leave': DragEventData & OutEvent; | ||
}; | ||
|
||
type CanvasSelectionEvents = { | ||
'selection:created': TEvent & { | ||
selected: FabricObject[]; | ||
}; | ||
'selection:updated': TEvent & { | ||
selected: FabricObject[]; | ||
deselected: FabricObject[]; | ||
}; | ||
'before:selection:cleared': Partial<TEvent> & { | ||
deselected: FabricObject[]; | ||
}; | ||
'selection:cleared': Partial<TEvent> & { | ||
deselected: FabricObject[]; | ||
}; | ||
}; | ||
|
||
type BeforeSuffix<T extends string> = `${T}:before`; | ||
type WithBeforeSuffix<T extends string> = T | BeforeSuffix<T>; | ||
|
||
type TPointerEvents<Prefix extends string, E = Record<string, never>> = Record< | ||
`${Prefix}${ | ||
| WithBeforeSuffix<'down'> | ||
| WithBeforeSuffix<'move'> | ||
| WithBeforeSuffix<'up'> | ||
| 'dblclick'}`, | ||
TransformEvent & E | ||
> & | ||
Record<`${Prefix}wheel`, TransformEvent<WheelEvent> & E> & | ||
Record<`${Prefix}over`, TransformEvent & InEvent & E> & | ||
Record<`${Prefix}out`, TransformEvent & OutEvent & E>; | ||
|
||
export type ObjectPointerEvents = TPointerEvents<'mouse'>; | ||
export type CanvasPointerEvents = TPointerEvents<'mouse:'>; | ||
|
||
export type ObjectEvents = ObjectPointerEvents & | ||
DnDEvents & | ||
ObjectModifiedEvents & { | ||
// selection | ||
selected: never; | ||
deselected: never; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to me looks like that selected and deselected do get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recall that the object is fired without context There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As opposed to the events fired on canvas There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I verified and added e + target. |
||
|
||
// tree | ||
added: { target: Group | Canvas }; | ||
removed: { target: Group | Canvas }; | ||
|
||
// erasing | ||
'erasing:end': { path: FabricObject }; | ||
}; | ||
|
||
export type CanvasEvents = CanvasPointerEvents & | ||
CanvasDnDEvents & | ||
CanvasModifiedEvents & | ||
CanvasSelectionEvents & { | ||
// tree | ||
'object:added': { target: FabricObject }; | ||
'object:removed': { target: FabricObject }; | ||
'canvas:cleared': never; | ||
|
||
// rendering | ||
'before:render': { ctx: CanvasRenderingContext2D }; | ||
'after:render': { ctx: CanvasRenderingContext2D }; | ||
|
||
// brushes | ||
'before:path:created': { path: FabricObject }; | ||
'path:created': { path: FabricObject }; | ||
|
||
// erasing | ||
'erasing:start': never; | ||
'erasing:end': | ||
| never | ||
| { | ||
path: FabricObject; | ||
targets: FabricObject[]; | ||
subTargets: FabricObject[]; | ||
drawables: { | ||
backgroundImage?: FabricObject; | ||
overlayImage?: FabricObject; | ||
}; | ||
}; | ||
|
||
// IText | ||
'text:selection:changed': { target: FabricObject }; | ||
'text:changed': { target: FabricObject }; | ||
|
||
// misc | ||
'contextmenu:before': SimpleEventHandler<Event>; | ||
contextmenu: SimpleEventHandler<Event>; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is useful, yes, but needs to be a suggestion and not a lockdown.
I didn't try the branch, is this possible or locked? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TS will complain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that if we accept string in addition to the event names TS won't show autocomplete. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
import { dragHandler, getActionFromCorner } from './controls/actions'; | ||
import { Point } from './point.class'; | ||
import { FabricObject } from './shapes/fabricObject.class'; | ||
import { Transform } from './typedefs'; | ||
import { Transform } from './EventTypeDefs'; | ||
import { saveObjectTransform } from './util/misc/objectTransforms'; | ||
|
||
(function (global) { | ||
|
@@ -441,10 +441,12 @@ import { saveObjectTransform } from './util/misc/objectTransforms'; | |
this._objectsToRender = undefined; | ||
// removing active object should fire "selection:cleared" events | ||
if (obj === this._activeObject) { | ||
this.fire('before:selection:cleared', { target: obj }); | ||
this.fire('before:selection:cleared', { deselected: [obj] }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So here i m thorn between deselected and maybeDeselected or something like that. Ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I get your point. A good point indeed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MaybeDeselcted is bad naming. Target or deselectionTarget are better |
||
this._discardActiveObject(); | ||
this.fire('selection:cleared', { target: obj }); | ||
obj.fire('deselected'); | ||
this.fire('selection:cleared', { deselected: [obj] }); | ||
obj.fire('deselected', { | ||
target: obj, | ||
}); | ||
} | ||
if (obj === this._hoveredTarget) { | ||
this._hoveredTarget = null; | ||
|
@@ -548,7 +550,7 @@ import { saveObjectTransform } from './util/misc/objectTransforms'; | |
var ctx = this.contextTop; | ||
this.clearContext(ctx); | ||
this.renderTopLayer(ctx); | ||
this.fire('after:render'); | ||
this.fire('after:render', { ctx }); | ||
return this; | ||
}, | ||
|
||
|
@@ -1363,7 +1365,10 @@ import { saveObjectTransform } from './util/misc/objectTransforms'; | |
var currentActives = this.getActiveObjects(), | ||
activeObject = this.getActiveObject(); | ||
if (currentActives.length) { | ||
this.fire('before:selection:cleared', { target: activeObject, e: e }); | ||
this.fire('before:selection:cleared', { | ||
e, | ||
deselected: [activeObject], | ||
}); | ||
} | ||
this._discardActiveObject(e); | ||
this._fireSelectionEvents(currentActives, e); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Up to here are types from typedefs