StateNode atoms (#2213)
This PR extracts some improvements from #2198 into a separate PR. ### Release Notes - adds computed `StateNode.getPath` - adds computed StateNode.getCurrent` - adds computed StateNode.getIsActive` - adds computed `Editor.getPath()` - makes transition's second property optional ### Change Type - [x] `minor` — New feature ### Test Plan - [x] Unit Tests - [x] End to end tests
This commit is contained in:
parent
6f872c796a
commit
7186368f0d
60 changed files with 562 additions and 468 deletions
|
@ -5,18 +5,6 @@ export function sleep(ms: number) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
// export async function expectPathToBe(page: Page, path: string) {
|
|
||||||
// expect(await page.evaluate(() => editor.root.path.value)).toBe(path)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export async function expectToHaveNShapes(page: Page, numberOfShapes: number) {
|
|
||||||
// expect(await page.evaluate(() => editor.currentPageShapes.length)).toBe(numberOfShapes)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export async function expectToHaveNSelectedShapes(page: Page, numberOfSelectedShapes: number) {
|
|
||||||
// expect(await page.evaluate(() => editor.selectedShapeIds.length)).toBe(numberOfSelectedShapes)
|
|
||||||
// }
|
|
||||||
|
|
||||||
declare const editor: Editor
|
declare const editor: Editor
|
||||||
|
|
||||||
export async function setup({ page }: PlaywrightTestArgs & PlaywrightWorkerArgs) {
|
export async function setup({ page }: PlaywrightTestArgs & PlaywrightWorkerArgs) {
|
||||||
|
|
|
@ -711,6 +711,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
getPage(page: TLPage | TLPageId): TLPage | undefined;
|
getPage(page: TLPage | TLPageId): TLPage | undefined;
|
||||||
getPageShapeIds(page: TLPage | TLPageId): Set<TLShapeId>;
|
getPageShapeIds(page: TLPage | TLPageId): Set<TLShapeId>;
|
||||||
getPageStates(): TLInstancePageState[];
|
getPageStates(): TLInstancePageState[];
|
||||||
|
getPath(): string;
|
||||||
getPointInParentSpace(shape: TLShape | TLShapeId, point: VecLike): Vec2d;
|
getPointInParentSpace(shape: TLShape | TLShapeId, point: VecLike): Vec2d;
|
||||||
getPointInShapeSpace(shape: TLShape | TLShapeId, point: VecLike): Vec2d;
|
getPointInShapeSpace(shape: TLShape | TLShapeId, point: VecLike): Vec2d;
|
||||||
getSelectedShapeAtPoint(point: VecLike): TLShape | undefined;
|
getSelectedShapeAtPoint(point: VecLike): TLShape | undefined;
|
||||||
|
@ -1848,8 +1849,6 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
children?: Record<string, StateNode>;
|
children?: Record<string, StateNode>;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
current: Atom<StateNode | undefined>;
|
|
||||||
// (undocumented)
|
|
||||||
get currentToolIdMask(): string | undefined;
|
get currentToolIdMask(): string | undefined;
|
||||||
set currentToolIdMask(id: string | undefined);
|
set currentToolIdMask(id: string | undefined);
|
||||||
_currentToolIdMask: Atom<string | undefined, unknown>;
|
_currentToolIdMask: Atom<string | undefined, unknown>;
|
||||||
|
@ -1859,6 +1858,9 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
enter: (info: any, from: string) => void;
|
enter: (info: any, from: string) => void;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
exit: (info: any, from: string) => void;
|
exit: (info: any, from: string) => void;
|
||||||
|
getCurrent(): StateNode | undefined;
|
||||||
|
getIsActive(): boolean;
|
||||||
|
getPath(): string;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
handleEvent: (info: Exclude<TLEventInfo, TLPinchEventInfo>) => void;
|
handleEvent: (info: Exclude<TLEventInfo, TLPinchEventInfo>) => void;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -1870,8 +1872,6 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
initial?: string;
|
initial?: string;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
isActive: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
onCancel?: TLEventHandlers['onCancel'];
|
onCancel?: TLEventHandlers['onCancel'];
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
onComplete?: TLEventHandlers['onComplete'];
|
onComplete?: TLEventHandlers['onComplete'];
|
||||||
|
@ -1908,11 +1908,10 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
parent: StateNode;
|
parent: StateNode;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
path: Computed<string>;
|
_path: Computed<string>;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
shapeType?: string;
|
shapeType?: string;
|
||||||
// (undocumented)
|
transition: (id: string, info?: any) => this;
|
||||||
transition: (id: string, info: any) => this;
|
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
type: TLStateNodeType;
|
type: TLStateNodeType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11223,6 +11223,37 @@
|
||||||
"isAbstract": false,
|
"isAbstract": false,
|
||||||
"name": "getPageStates"
|
"name": "getPageStates"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "Method",
|
||||||
|
"canonicalReference": "@tldraw/editor!Editor#getPath:member(1)",
|
||||||
|
"docComment": "/**\n * The editor's current path of active states.\n *\n * @example\n * ```ts\n * editor.path // \"select.idle\"\n * ```\n *\n * @public\n */\n",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "getPath(): "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isStatic": false,
|
||||||
|
"returnTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 2
|
||||||
|
},
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"isProtected": false,
|
||||||
|
"overloadIndex": 1,
|
||||||
|
"parameters": [],
|
||||||
|
"isOptional": false,
|
||||||
|
"isAbstract": false,
|
||||||
|
"name": "getPath"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "Method",
|
"kind": "Method",
|
||||||
"canonicalReference": "@tldraw/editor!Editor#getPointInParentSpace:member(1)",
|
"canonicalReference": "@tldraw/editor!Editor#getPointInParentSpace:member(1)",
|
||||||
|
@ -34285,6 +34316,41 @@
|
||||||
"isProtected": false,
|
"isProtected": false,
|
||||||
"isAbstract": false
|
"isAbstract": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "Property",
|
||||||
|
"canonicalReference": "@tldraw/editor!StateNode#_path:member",
|
||||||
|
"docComment": "",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "_path: "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Reference",
|
||||||
|
"text": "Computed",
|
||||||
|
"canonicalReference": "@tldraw/state!Computed:interface"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "<string>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isReadonly": false,
|
||||||
|
"isOptional": false,
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"name": "_path",
|
||||||
|
"propertyTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 3
|
||||||
|
},
|
||||||
|
"isStatic": false,
|
||||||
|
"isProtected": false,
|
||||||
|
"isAbstract": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "Constructor",
|
"kind": "Constructor",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode:constructor(1)",
|
"canonicalReference": "@tldraw/editor!StateNode:constructor(1)",
|
||||||
|
@ -34418,50 +34484,6 @@
|
||||||
"isProtected": false,
|
"isProtected": false,
|
||||||
"isAbstract": false
|
"isAbstract": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"kind": "Property",
|
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#current:member",
|
|
||||||
"docComment": "",
|
|
||||||
"excerptTokens": [
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "current: "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Reference",
|
|
||||||
"text": "Atom",
|
|
||||||
"canonicalReference": "@tldraw/state!Atom:interface"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "<"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Reference",
|
|
||||||
"text": "StateNode",
|
|
||||||
"canonicalReference": "@tldraw/editor!StateNode:class"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": " | undefined>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": ";"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isReadonly": false,
|
|
||||||
"isOptional": false,
|
|
||||||
"releaseTag": "Public",
|
|
||||||
"name": "current",
|
|
||||||
"propertyTypeTokenRange": {
|
|
||||||
"startIndex": 1,
|
|
||||||
"endIndex": 5
|
|
||||||
},
|
|
||||||
"isStatic": false,
|
|
||||||
"isProtected": false,
|
|
||||||
"isAbstract": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "Property",
|
"kind": "Property",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#currentToolIdMask:member",
|
"canonicalReference": "@tldraw/editor!StateNode#currentToolIdMask:member",
|
||||||
|
@ -34583,6 +34605,104 @@
|
||||||
"isProtected": false,
|
"isProtected": false,
|
||||||
"isAbstract": false
|
"isAbstract": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"kind": "Method",
|
||||||
|
"canonicalReference": "@tldraw/editor!StateNode#getCurrent:member(1)",
|
||||||
|
"docComment": "/**\n * This node's current active child node, if any.\n *\n * @public\n */\n",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "getCurrent(): "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Reference",
|
||||||
|
"text": "StateNode",
|
||||||
|
"canonicalReference": "@tldraw/editor!StateNode:class"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": " | undefined"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isStatic": false,
|
||||||
|
"returnTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 3
|
||||||
|
},
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"isProtected": false,
|
||||||
|
"overloadIndex": 1,
|
||||||
|
"parameters": [],
|
||||||
|
"isOptional": false,
|
||||||
|
"isAbstract": false,
|
||||||
|
"name": "getCurrent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Method",
|
||||||
|
"canonicalReference": "@tldraw/editor!StateNode#getIsActive:member(1)",
|
||||||
|
"docComment": "/**\n * Whether this node is active.\n *\n * @public\n */\n",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "getIsActive(): "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isStatic": false,
|
||||||
|
"returnTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 2
|
||||||
|
},
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"isProtected": false,
|
||||||
|
"overloadIndex": 1,
|
||||||
|
"parameters": [],
|
||||||
|
"isOptional": false,
|
||||||
|
"isAbstract": false,
|
||||||
|
"name": "getIsActive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Method",
|
||||||
|
"canonicalReference": "@tldraw/editor!StateNode#getPath:member(1)",
|
||||||
|
"docComment": "/**\n * This node's path of active state nodes\n *\n * @public\n */\n",
|
||||||
|
"excerptTokens": [
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "getPath(): "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "Content",
|
||||||
|
"text": ";"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isStatic": false,
|
||||||
|
"returnTypeTokenRange": {
|
||||||
|
"startIndex": 1,
|
||||||
|
"endIndex": 2
|
||||||
|
},
|
||||||
|
"releaseTag": "Public",
|
||||||
|
"isProtected": false,
|
||||||
|
"overloadIndex": 1,
|
||||||
|
"parameters": [],
|
||||||
|
"isOptional": false,
|
||||||
|
"isAbstract": false,
|
||||||
|
"name": "getPath"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"kind": "Property",
|
"kind": "Property",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#handleEvent:member",
|
"canonicalReference": "@tldraw/editor!StateNode#handleEvent:member",
|
||||||
|
@ -34760,36 +34880,6 @@
|
||||||
"isProtected": false,
|
"isProtected": false,
|
||||||
"isAbstract": false
|
"isAbstract": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"kind": "Property",
|
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#isActive:member",
|
|
||||||
"docComment": "",
|
|
||||||
"excerptTokens": [
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "isActive: "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": ";"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isReadonly": false,
|
|
||||||
"isOptional": false,
|
|
||||||
"releaseTag": "Public",
|
|
||||||
"name": "isActive",
|
|
||||||
"propertyTypeTokenRange": {
|
|
||||||
"startIndex": 1,
|
|
||||||
"endIndex": 2
|
|
||||||
},
|
|
||||||
"isStatic": false,
|
|
||||||
"isProtected": false,
|
|
||||||
"isAbstract": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "Property",
|
"kind": "Property",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#onCancel:member",
|
"canonicalReference": "@tldraw/editor!StateNode#onCancel:member",
|
||||||
|
@ -35408,41 +35498,6 @@
|
||||||
"isProtected": false,
|
"isProtected": false,
|
||||||
"isAbstract": false
|
"isAbstract": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"kind": "Property",
|
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#path:member",
|
|
||||||
"docComment": "",
|
|
||||||
"excerptTokens": [
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "path: "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Reference",
|
|
||||||
"text": "Computed",
|
|
||||||
"canonicalReference": "@tldraw/state!Computed:interface"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": "<string>"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "Content",
|
|
||||||
"text": ";"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isReadonly": false,
|
|
||||||
"isOptional": false,
|
|
||||||
"releaseTag": "Public",
|
|
||||||
"name": "path",
|
|
||||||
"propertyTypeTokenRange": {
|
|
||||||
"startIndex": 1,
|
|
||||||
"endIndex": 3
|
|
||||||
},
|
|
||||||
"isStatic": false,
|
|
||||||
"isProtected": false,
|
|
||||||
"isAbstract": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "Property",
|
"kind": "Property",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#shapeType:member",
|
"canonicalReference": "@tldraw/editor!StateNode#shapeType:member",
|
||||||
|
@ -35476,7 +35531,7 @@
|
||||||
{
|
{
|
||||||
"kind": "Property",
|
"kind": "Property",
|
||||||
"canonicalReference": "@tldraw/editor!StateNode#transition:member",
|
"canonicalReference": "@tldraw/editor!StateNode#transition:member",
|
||||||
"docComment": "",
|
"docComment": "/**\n * Transition to a new active child state node.\n *\n * @param id - The id of the child state node to transition to.\n *\n * @param info - Any data to pass to the `onEnter` and `onExit` handlers.\n *\n * @example\n * ```ts\n * parentState.transition('childStateA')\n * parentState.transition('childStateB', { myData: 4 })\n * ```\n *\n * @public\n */\n",
|
||||||
"excerptTokens": [
|
"excerptTokens": [
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
|
@ -35484,7 +35539,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
"text": "(id: string, info: any) => this"
|
"text": "(id: string, info?: any) => this"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kind": "Content",
|
"kind": "Content",
|
||||||
|
|
|
@ -1008,7 +1008,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
willCrashApp,
|
willCrashApp,
|
||||||
},
|
},
|
||||||
extras: {
|
extras: {
|
||||||
activeStateNode: this.root.path.get(),
|
activeStateNode: this.root.getPath(),
|
||||||
selectedShapes: this.getSelectedShapes(),
|
selectedShapes: this.getSelectedShapes(),
|
||||||
editingShape: editingShapeId ? this.getShape(editingShapeId) : undefined,
|
editingShape: editingShapeId ? this.getShape(editingShapeId) : undefined,
|
||||||
inputs: this.inputs,
|
inputs: this.inputs,
|
||||||
|
@ -1051,6 +1051,20 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
|
|
||||||
/* ------------------- Statechart ------------------- */
|
/* ------------------- Statechart ------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The editor's current path of active states.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* editor.path // "select.idle"
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
@computed getPath() {
|
||||||
|
return this.root.getPath().split('root.')[1]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether a certain tool (or other state node) is currently active.
|
* Get whether a certain tool (or other state node) is currently active.
|
||||||
*
|
*
|
||||||
|
@ -1070,7 +1084,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
while (ids.length > 0) {
|
while (ids.length > 0) {
|
||||||
const id = ids.pop()
|
const id = ids.pop()
|
||||||
if (!id) return true
|
if (!id) return true
|
||||||
const current = state.current.get()
|
const current = state.getCurrent()
|
||||||
if (current?.id === id) {
|
if (current?.id === id) {
|
||||||
if (ids.length === 0) return true
|
if (ids.length === 0) return true
|
||||||
state = current
|
state = current
|
||||||
|
@ -1119,7 +1133,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@computed getCurrentTool(): StateNode | undefined {
|
@computed getCurrentTool(): StateNode | undefined {
|
||||||
return this.root.current.get()
|
return this.root.getCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7476,7 +7490,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
||||||
|
|
||||||
// If the current tool is associated with a shape, return the styles for that shape.
|
// If the current tool is associated with a shape, return the styles for that shape.
|
||||||
// Otherwise, just return an empty map.
|
// Otherwise, just return an empty map.
|
||||||
const currentTool = this.root.current.get()!
|
const currentTool = this.root.getCurrent()!
|
||||||
const styles = new SharedStyleMap()
|
const styles = new SharedStyleMap()
|
||||||
if (currentTool.shapeType) {
|
if (currentTool.shapeType) {
|
||||||
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
||||||
|
|
|
@ -112,13 +112,13 @@ export class Pointing extends StateNode {
|
||||||
this.editor.setSelectedShapes([id])
|
this.editor.setSelectedShapes([id])
|
||||||
|
|
||||||
if (this.editor.getInstanceState().isToolLocked) {
|
if (this.editor.getInstanceState().isToolLocked) {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCurrentTool('select.idle')
|
this.editor.setCurrentTool('select.idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,12 @@ export class RootState extends StateNode {
|
||||||
static override children = () => []
|
static override children = () => []
|
||||||
|
|
||||||
override onKeyDown: TLEventHandlers['onKeyDown'] = (info) => {
|
override onKeyDown: TLEventHandlers['onKeyDown'] = (info) => {
|
||||||
|
// todo: move this logic up to the @tldraw/tldraw library, as the "zoom" tool only exists there
|
||||||
switch (info.code) {
|
switch (info.code) {
|
||||||
case 'KeyZ': {
|
case 'KeyZ': {
|
||||||
if (!(info.shiftKey || info.ctrlKey)) {
|
if (!(info.shiftKey || info.ctrlKey)) {
|
||||||
const currentTool = this.current.get()
|
const currentTool = this.getCurrent()
|
||||||
if (currentTool && currentTool.current.get()?.id === 'idle') {
|
if (currentTool && currentTool.getCurrent()?.id === 'idle') {
|
||||||
if (this.children!['zoom']) {
|
if (this.children!['zoom']) {
|
||||||
this.editor.setCurrentTool('zoom', { ...info, onInteractionEnd: currentTool.id })
|
this.editor.setCurrentTool('zoom', { ...info, onInteractionEnd: currentTool.id })
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,12 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
const { id, children, initial } = this.constructor as TLStateNodeConstructor
|
const { id, children, initial } = this.constructor as TLStateNodeConstructor
|
||||||
|
|
||||||
this.id = id
|
this.id = id
|
||||||
this.current = atom<StateNode | undefined>('toolState' + this.id, undefined)
|
this._isActive = atom<boolean>('toolIsActive' + this.id, false)
|
||||||
|
this._current = atom<StateNode | undefined>('toolState' + this.id, undefined)
|
||||||
|
|
||||||
this.path = computed('toolPath' + this.id, () => {
|
this._path = computed('toolPath' + this.id, () => {
|
||||||
const current = this.current.get()
|
const current = this.getCurrent()
|
||||||
return this.id + (current ? `.${current.path.get()}` : '')
|
return this.id + (current ? `.${current.getPath()}` : '')
|
||||||
})
|
})
|
||||||
|
|
||||||
this.parent = parent ?? ({} as any)
|
this.parent = parent ?? ({} as any)
|
||||||
|
@ -41,7 +42,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
this.children = Object.fromEntries(
|
this.children = Object.fromEntries(
|
||||||
children().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])
|
children().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])
|
||||||
)
|
)
|
||||||
this.current.set(this.children[this.initial])
|
this._current.set(this.children[this.initial])
|
||||||
} else {
|
} else {
|
||||||
this.type = 'leaf'
|
this.type = 'leaf'
|
||||||
}
|
}
|
||||||
|
@ -53,35 +54,74 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
this.children = Object.fromEntries(
|
this.children = Object.fromEntries(
|
||||||
children().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])
|
children().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])
|
||||||
)
|
)
|
||||||
this.current.set(this.children[this.initial])
|
this._current.set(this.children[this.initial])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path: Computed<string>
|
|
||||||
|
|
||||||
static id: string
|
static id: string
|
||||||
static initial?: string
|
static initial?: string
|
||||||
static children?: () => TLStateNodeConstructor[]
|
static children?: () => TLStateNodeConstructor[]
|
||||||
|
|
||||||
id: string
|
id: string
|
||||||
current: Atom<StateNode | undefined>
|
|
||||||
type: TLStateNodeType
|
type: TLStateNodeType
|
||||||
shapeType?: string
|
shapeType?: string
|
||||||
initial?: string
|
initial?: string
|
||||||
children?: Record<string, StateNode>
|
children?: Record<string, StateNode>
|
||||||
parent: StateNode
|
parent: StateNode
|
||||||
|
|
||||||
isActive = false
|
/**
|
||||||
|
* This node's path of active state nodes
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
@computed getPath() {
|
||||||
|
return this._path.get()
|
||||||
|
}
|
||||||
|
_path: Computed<string>
|
||||||
|
|
||||||
transition = (id: string, info: any) => {
|
/**
|
||||||
|
* This node's current active child node, if any.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
@computed getCurrent() {
|
||||||
|
return this._current.get()
|
||||||
|
}
|
||||||
|
private _current: Atom<StateNode | undefined>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this node is active.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
@computed getIsActive() {
|
||||||
|
return this._isActive.get()
|
||||||
|
}
|
||||||
|
private _isActive: Atom<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transition to a new active child state node.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* parentState.transition('childStateA')
|
||||||
|
* parentState.transition('childStateB', { myData: 4 })
|
||||||
|
*```
|
||||||
|
*
|
||||||
|
* @param id - The id of the child state node to transition to.
|
||||||
|
* @param info - Any data to pass to the `onEnter` and `onExit` handlers.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
transition = (id: string, info: any = {}) => {
|
||||||
const path = id.split('.')
|
const path = id.split('.')
|
||||||
|
|
||||||
let currState = this as StateNode
|
let currState = this as StateNode
|
||||||
|
|
||||||
for (let i = 0; i < path.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
const id = path[i]
|
const id = path[i]
|
||||||
const prevChildState = currState.current.get()
|
const prevChildState = currState.getCurrent()
|
||||||
const nextChildState = currState.children?.[id]
|
const nextChildState = currState.children?.[id]
|
||||||
|
|
||||||
if (!nextChildState) {
|
if (!nextChildState) {
|
||||||
|
@ -90,9 +130,9 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
|
|
||||||
if (prevChildState?.id !== nextChildState.id) {
|
if (prevChildState?.id !== nextChildState.id) {
|
||||||
prevChildState?.exit(info, id)
|
prevChildState?.exit(info, id)
|
||||||
currState.current.set(nextChildState)
|
currState._current.set(nextChildState)
|
||||||
nextChildState.enter(info, prevChildState?.id || 'initial')
|
nextChildState.enter(info, prevChildState?.id || 'initial')
|
||||||
if (!nextChildState.isActive) break
|
if (!nextChildState.getIsActive()) break
|
||||||
}
|
}
|
||||||
|
|
||||||
currState = nextChildState
|
currState = nextChildState
|
||||||
|
@ -103,28 +143,30 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
||||||
|
|
||||||
handleEvent = (info: Exclude<TLEventInfo, TLPinchEventInfo>) => {
|
handleEvent = (info: Exclude<TLEventInfo, TLPinchEventInfo>) => {
|
||||||
const cbName = EVENT_NAME_MAP[info.name]
|
const cbName = EVENT_NAME_MAP[info.name]
|
||||||
const x = this.current.get()
|
const x = this.getCurrent()
|
||||||
this[cbName]?.(info as any)
|
this[cbName]?.(info as any)
|
||||||
if (this.current.get() === x && this.isActive) {
|
if (this.getCurrent() === x && this.getIsActive()) {
|
||||||
x?.handleEvent(info)
|
x?.handleEvent(info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: move this logic into transition
|
||||||
enter = (info: any, from: string) => {
|
enter = (info: any, from: string) => {
|
||||||
this.isActive = true
|
this._isActive.set(true)
|
||||||
this.onEnter?.(info, from)
|
this.onEnter?.(info, from)
|
||||||
if (this.children && this.initial && this.isActive) {
|
if (this.children && this.initial && this.getIsActive()) {
|
||||||
const initial = this.children[this.initial]
|
const initial = this.children[this.initial]
|
||||||
this.current.set(initial)
|
this._current.set(initial)
|
||||||
initial.enter(info, from)
|
initial.enter(info, from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: move this logic into transition
|
||||||
exit = (info: any, from: string) => {
|
exit = (info: any, from: string) => {
|
||||||
this.isActive = false
|
this._isActive.set(false)
|
||||||
this.onExit?.(info, from)
|
this.onExit?.(info, from)
|
||||||
if (!this.isActive) {
|
if (!this.getIsActive()) {
|
||||||
this.current.get()?.exit(info, from)
|
this.getCurrent()?.exit(info, from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function useDocumentEvents() {
|
||||||
if (
|
if (
|
||||||
e.altKey &&
|
e.altKey &&
|
||||||
// todo: When should we allow the alt key to be used? Perhaps states should declare which keys matter to them?
|
// todo: When should we allow the alt key to be used? Perhaps states should declare which keys matter to them?
|
||||||
(editor.isIn('zoom') || !editor.root.path.get().endsWith('.idle')) &&
|
(editor.isIn('zoom') || !editor.root.getPath().endsWith('.idle')) &&
|
||||||
!isFocusingInput()
|
!isFocusingInput()
|
||||||
) {
|
) {
|
||||||
// On windows the alt key opens the menu bar.
|
// On windows the alt key opens the menu bar.
|
||||||
|
|
|
@ -34,7 +34,7 @@ beforeEach(() => {
|
||||||
it('enters the arrow state', () => {
|
it('enters the arrow state', () => {
|
||||||
editor.setCurrentTool('arrow')
|
editor.setCurrentTool('arrow')
|
||||||
expect(editor.getCurrentToolId()).toBe('arrow')
|
expect(editor.getCurrentToolId()).toBe('arrow')
|
||||||
editor.expectPathToBe('root.arrow.idle')
|
editor.expectToBeIn('arrow.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When in the idle state', () => {
|
describe('When in the idle state', () => {
|
||||||
|
@ -43,7 +43,7 @@ describe('When in the idle state', () => {
|
||||||
editor.setCurrentTool('arrow').pointerDown(0, 0)
|
editor.setCurrentTool('arrow').pointerDown(0, 0)
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
editor.expectPathToBe('root.arrow.pointing')
|
editor.expectToBeIn('arrow.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to select on cancel', () => {
|
it('returns to select on cancel', () => {
|
||||||
|
@ -60,7 +60,7 @@ describe('When in the pointing state', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore)
|
expect(shapesAfter).toBe(shapesBefore)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.arrow.idle')
|
editor.expectToBeIn('arrow.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('bails on cancel', () => {
|
it('bails on cancel', () => {
|
||||||
|
@ -69,12 +69,12 @@ describe('When in the pointing state', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore)
|
expect(shapesAfter).toBe(shapesBefore)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.arrow.idle')
|
editor.expectToBeIn('arrow.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('enters the dragging state on pointer move', () => {
|
it('enters the dragging state on pointer move', () => {
|
||||||
editor.setCurrentTool('arrow').pointerDown(0, 0).pointerMove(10, 10)
|
editor.setCurrentTool('arrow').pointerDown(0, 0).pointerMove(10, 10)
|
||||||
editor.expectPathToBe('root.select.dragging_handle')
|
editor.expectToBeIn('select.dragging_handle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ describe('When dragging the arrow', () => {
|
||||||
end: { type: 'point', x: 10, y: 10 },
|
end: { type: 'point', x: 10, y: 10 },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
editor.expectPathToBe('root.select.dragging_handle')
|
editor.expectToBeIn('select.dragging_handle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to select.idle, keeping shape, on pointer up', () => {
|
it('returns to select.idle, keeping shape, on pointer up', () => {
|
||||||
|
@ -102,7 +102,7 @@ describe('When dragging the arrow', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to arrow.idle, keeping shape, on pointer up when tool lock is active', () => {
|
it('returns to arrow.idle, keeping shape, on pointer up when tool lock is active', () => {
|
||||||
|
@ -112,7 +112,7 @@ describe('When dragging the arrow', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.arrow.idle')
|
editor.expectToBeIn('arrow.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('bails on cancel', () => {
|
it('bails on cancel', () => {
|
||||||
|
@ -120,7 +120,7 @@ describe('When dragging the arrow', () => {
|
||||||
editor.setCurrentTool('arrow').pointerDown(0, 0).pointerMove(10, 10).cancel()
|
editor.setCurrentTool('arrow').pointerDown(0, 0).pointerMove(10, 10).cancel()
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore)
|
expect(shapesAfter).toBe(shapesBefore)
|
||||||
editor.expectPathToBe('root.arrow.idle')
|
editor.expectToBeIn('arrow.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -409,10 +409,10 @@ describe('reparenting issue', () => {
|
||||||
handle: { id: 'end', type: 'vertex', index: 'a0', x: 100, y: 100 },
|
handle: { id: 'end', type: 'vertex', index: 'a0', x: 100, y: 100 },
|
||||||
shape: editor.getShape(arrowId)!,
|
shape: editor.getShape(arrowId)!,
|
||||||
})
|
})
|
||||||
editor.expectPathToBe('root.select.pointing_handle')
|
editor.expectToBeIn('select.pointing_handle')
|
||||||
|
|
||||||
editor.pointerMove(320, 320) // over box 2
|
editor.pointerMove(320, 320) // over box 2
|
||||||
editor.expectPathToBe('root.select.dragging_handle')
|
editor.expectToBeIn('select.dragging_handle')
|
||||||
editor.expectShapeToMatch({
|
editor.expectShapeToMatch({
|
||||||
id: arrowId,
|
id: arrowId,
|
||||||
index: 'a3V',
|
index: 'a3V',
|
||||||
|
|
|
@ -379,7 +379,7 @@ describe('resizing', () => {
|
||||||
.pointerDown(150, 300, { target: 'selection', handle: 'bottom' })
|
.pointerDown(150, 300, { target: 'selection', handle: 'bottom' })
|
||||||
.pointerMove(150, 600)
|
.pointerMove(150, 600)
|
||||||
|
|
||||||
.expectPathToBe('root.select.resizing')
|
.expectToBeIn('select.resizing')
|
||||||
|
|
||||||
expect(editor.getShape(arrow1.id)).toMatchObject({
|
expect(editor.getShape(arrow1.id)).toMatchObject({
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -436,7 +436,7 @@ describe('resizing', () => {
|
||||||
.pointerDown(150, 300, { target: 'selection', handle: 'bottom' })
|
.pointerDown(150, 300, { target: 'selection', handle: 'bottom' })
|
||||||
.pointerMove(150, -300)
|
.pointerMove(150, -300)
|
||||||
|
|
||||||
.expectPathToBe('root.select.resizing')
|
.expectToBeIn('select.resizing')
|
||||||
|
|
||||||
expect(editor.getShape(arrow1.id)).toCloselyMatchObject({
|
expect(editor.getShape(arrow1.id)).toCloselyMatchObject({
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class Idle extends StateNode {
|
||||||
) {
|
) {
|
||||||
this.editor.setCurrentTool('select')
|
this.editor.setCurrentTool('select')
|
||||||
this.editor.setEditingShape(onlySelectedShape.id)
|
this.editor.setEditingShape(onlySelectedShape.id)
|
||||||
this.editor.root.current.get()!.transition('editing_shape', {
|
this.editor.root.getCurrent()!.transition('editing_shape', {
|
||||||
...info,
|
...info,
|
||||||
target: 'shape',
|
target: 'shape',
|
||||||
shape: onlySelectedShape,
|
shape: onlySelectedShape,
|
||||||
|
|
|
@ -75,7 +75,7 @@ export class Pointing extends StateNode {
|
||||||
this.editor.bailToMark(this.markId)
|
this.editor.bailToMark(this.markId)
|
||||||
}
|
}
|
||||||
this.editor.setHintingShapes([])
|
this.editor.setHintingShapes([])
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
createArrowShape() {
|
createArrowShape() {
|
||||||
|
@ -180,7 +180,7 @@ export class Pointing extends StateNode {
|
||||||
private didTimeout = false
|
private didTimeout = false
|
||||||
private startPreciseTimeout() {
|
private startPreciseTimeout() {
|
||||||
this.preciseTimeout = window.setTimeout(() => {
|
this.preciseTimeout = window.setTimeout(() => {
|
||||||
if (!this.isActive) return
|
if (!this.getIsActive()) return
|
||||||
this.didTimeout = true
|
this.didTimeout = true
|
||||||
}, 320)
|
}, 320)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,15 @@ describe(DrawShapeTool, () => {
|
||||||
describe('When in the idle state', () => {
|
describe('When in the idle state', () => {
|
||||||
it('Returns to select on cancel', () => {
|
it('Returns to select on cancel', () => {
|
||||||
editor.setCurrentTool('draw')
|
editor.setCurrentTool('draw')
|
||||||
editor.expectPathToBe('root.draw.idle')
|
editor.expectToBeIn('draw.idle')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the drawing state on pointer down', () => {
|
it('Enters the drawing state on pointer down', () => {
|
||||||
editor.setCurrentTool('draw')
|
editor.setCurrentTool('draw')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.draw.drawing')
|
editor.expectToBeIn('draw.drawing')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -34,19 +34,19 @@ describe('When in the drawing state', () => {
|
||||||
editor.setCurrentTool('draw')
|
editor.setCurrentTool('draw')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.draw.idle')
|
editor.expectToBeIn('draw.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to idle on complete', () => {
|
it('Returns to idle on complete', () => {
|
||||||
editor.setCurrentTool('draw')
|
editor.setCurrentTool('draw')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.draw.idle')
|
editor.expectToBeIn('draw.idle')
|
||||||
|
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.pointerMove(60, 60)
|
editor.pointerMove(60, 60)
|
||||||
editor.pointerUp(60, 60)
|
editor.pointerUp(60, 60)
|
||||||
editor.expectPathToBe('root.draw.idle')
|
editor.expectToBeIn('draw.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -713,7 +713,7 @@ export class Drawing extends StateNode {
|
||||||
{ id: initialShape.id, type: initialShape.type, props: { isComplete: true } },
|
{ id: initialShape.id, type: initialShape.type, props: { isComplete: true } },
|
||||||
])
|
])
|
||||||
|
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe(FrameShapeTool, () => {
|
||||||
describe('When selecting the tool', () => {
|
describe('When selecting the tool', () => {
|
||||||
it('selects the tool and enters the idle state', () => {
|
it('selects the tool and enters the idle state', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ describe('When in the idle state', () => {
|
||||||
it('Enters pointing state on pointer down', () => {
|
it('Enters pointing state on pointer down', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(100, 100)
|
editor.pointerDown(100, 100)
|
||||||
editor.expectPathToBe('root.frame.pointing')
|
editor.expectToBeIn('frame.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Switches back to select tool on cancel', () => {
|
it('Switches back to select tool on cancel', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Does nothing on interrupt', () => {
|
it('Does nothing on interrupt', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -84,25 +84,25 @@ describe('When in the pointing state', () => {
|
||||||
it('Switches back to idle on cancel', () => {
|
it('Switches back to idle on cancel', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.frame.pointing')
|
editor.expectToBeIn('frame.pointing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the select.resizing state on drag start', () => {
|
it('Enters the select.resizing state on drag start', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(51, 51) // not far enough!
|
editor.pointerMove(51, 51) // not far enough!
|
||||||
editor.expectPathToBe('root.frame.pointing')
|
editor.expectToBeIn('frame.pointing')
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the select.resizing state on pointer move', () => {
|
it('Enters the select.resizing state on pointer move', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the frame state on cancel', () => {
|
it('Returns to the frame state on cancel', () => {
|
||||||
|
@ -110,7 +110,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Creates a frame and returns to select tool on pointer up', () => {
|
it('Creates a frame and returns to select tool on pointer up', () => {
|
||||||
|
@ -118,7 +118,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -138,9 +138,9 @@ describe('When in the resizing state', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to select.idle on complete', () => {
|
it('Returns to select.idle on complete', () => {
|
||||||
|
@ -148,7 +148,7 @@ describe('When in the resizing state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to frame.idle on complete if tool lock is enabled', () => {
|
it('Returns to frame.idle on complete if tool lock is enabled', () => {
|
||||||
|
@ -157,7 +157,7 @@ describe('When in the resizing state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -165,5 +165,5 @@ it('Returns to the idle state on interrupt', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.frame.idle')
|
editor.expectToBeIn('frame.idle')
|
||||||
})
|
})
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe(GeoShapeTool, () => {
|
||||||
describe('When selecting the tool', () => {
|
describe('When selecting the tool', () => {
|
||||||
it('selects the tool and enters the idle state', () => {
|
it('selects the tool and enters the idle state', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ describe('When in the idle state', () => {
|
||||||
it('Enters pointing state on pointer down', () => {
|
it('Enters pointing state on pointer down', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(100, 100)
|
editor.pointerDown(100, 100)
|
||||||
editor.expectPathToBe('root.geo.pointing')
|
editor.expectToBeIn('geo.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Switches back to select tool on cancel', () => {
|
it('Switches back to select tool on cancel', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Does nothing on interrupt', () => {
|
it('Does nothing on interrupt', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters edit shape state on "Enter" key up when we have one geo shape', () => {
|
it('Enters edit shape state on "Enter" key up when we have one geo shape', () => {
|
||||||
|
@ -86,7 +86,7 @@ describe('When in the idle state', () => {
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
|
|
||||||
editor.keyUp('Enter')
|
editor.keyUp('Enter')
|
||||||
editor.expectPathToBe('root.select.editing_shape')
|
editor.expectToBeIn('select.editing_shape')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Does not enter edit shape state on "Enter" key up when multiple geo shapes are selected', () => {
|
it('Does not enter edit shape state on "Enter" key up when multiple geo shapes are selected', () => {
|
||||||
|
@ -106,7 +106,7 @@ describe('When in the idle state', () => {
|
||||||
expect(editor.getSelectedShapes().length).toBe(2)
|
expect(editor.getSelectedShapes().length).toBe(2)
|
||||||
|
|
||||||
editor.keyUp('Enter')
|
editor.keyUp('Enter')
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -114,32 +114,32 @@ describe('When in the pointing state', () => {
|
||||||
it('Switches back to idle on cancel', () => {
|
it('Switches back to idle on cancel', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.geo.pointing')
|
editor.expectToBeIn('geo.pointing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the select.resizing state on drag start', () => {
|
it('Enters the select.resizing state on drag start', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(51, 51) // not far enough!
|
editor.pointerMove(51, 51) // not far enough!
|
||||||
editor.expectPathToBe('root.geo.pointing')
|
editor.expectToBeIn('geo.pointing')
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the select.resizing state on pointer move', () => {
|
it('Enters the select.resizing state on pointer move', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the idle state on interrupt', () => {
|
it('Returns to the idle state on interrupt', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Creates a geo and returns to select tool on pointer up', () => {
|
it('Creates a geo and returns to select tool on pointer up', () => {
|
||||||
|
@ -147,7 +147,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -167,9 +167,9 @@ describe('When in the resizing state while creating a geo shape', () => {
|
||||||
editor.setCurrentTool('geo')
|
editor.setCurrentTool('geo')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to select.idle on complete', () => {
|
it('Returns to select.idle on complete', () => {
|
||||||
|
@ -177,7 +177,7 @@ describe('When in the resizing state while creating a geo shape', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to geo.idle on complete if tool lock is enabled', () => {
|
it('Returns to geo.idle on complete if tool lock is enabled', () => {
|
||||||
|
@ -186,6 +186,6 @@ describe('When in the resizing state while creating a geo shape', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
editor.expectPathToBe('root.geo.idle')
|
editor.expectToBeIn('geo.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,7 +23,7 @@ export class Idle extends StateNode {
|
||||||
) {
|
) {
|
||||||
this.editor.setCurrentTool('select')
|
this.editor.setCurrentTool('select')
|
||||||
this.editor.setEditingShape(onlySelectedShape.id)
|
this.editor.setEditingShape(onlySelectedShape.id)
|
||||||
this.editor.root.current.get()!.transition('editing_shape', {
|
this.editor.root.getCurrent()!.transition('editing_shape', {
|
||||||
...info,
|
...info,
|
||||||
target: 'shape',
|
target: 'shape',
|
||||||
shape: onlySelectedShape,
|
shape: onlySelectedShape,
|
||||||
|
|
|
@ -118,7 +118,7 @@ export class Pointing extends StateNode {
|
||||||
])
|
])
|
||||||
|
|
||||||
if (this.editor.getInstanceState().isToolLocked) {
|
if (this.editor.getInstanceState().isToolLocked) {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCurrentTool('select', {})
|
this.editor.setCurrentTool('select', {})
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,6 @@ export class Pointing extends StateNode {
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
// we should not have created any shapes yet, so no need to bail
|
// we should not have created any shapes yet, so no need to bail
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ beforeEach(() => {
|
||||||
it('enters the line state', () => {
|
it('enters the line state', () => {
|
||||||
editor.setCurrentTool('line')
|
editor.setCurrentTool('line')
|
||||||
expect(editor.getCurrentToolId()).toBe('line')
|
expect(editor.getCurrentToolId()).toBe('line')
|
||||||
editor.expectPathToBe('root.line.idle')
|
editor.expectToBeIn('line.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When in the idle state', () => {
|
describe('When in the idle state', () => {
|
||||||
|
@ -19,7 +19,7 @@ describe('When in the idle state', () => {
|
||||||
editor.setCurrentTool('line').pointerDown(0, 0, { target: 'canvas' })
|
editor.setCurrentTool('line').pointerDown(0, 0, { target: 'canvas' })
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
editor.expectPathToBe('root.line.pointing')
|
editor.expectToBeIn('line.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to select on cancel', () => {
|
it('returns to select on cancel', () => {
|
||||||
|
@ -36,7 +36,7 @@ describe('When in the pointing state', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.line.idle')
|
editor.expectToBeIn('line.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('bails on cancel', () => {
|
it('bails on cancel', () => {
|
||||||
|
@ -45,12 +45,12 @@ describe('When in the pointing state', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore)
|
expect(shapesAfter).toBe(shapesBefore)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.line.idle')
|
editor.expectToBeIn('line.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('enters the dragging state on pointer move', () => {
|
it('enters the dragging state on pointer move', () => {
|
||||||
editor.setCurrentTool('line').pointerDown(0, 0, { target: 'canvas' }).pointerMove(10, 10)
|
editor.setCurrentTool('line').pointerDown(0, 0, { target: 'canvas' }).pointerMove(10, 10)
|
||||||
editor.expectPathToBe('root.select.dragging_handle')
|
editor.expectToBeIn('select.dragging_handle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ describe('When dragging the line', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
editor.expectPathToBe('root.select.dragging_handle')
|
editor.expectToBeIn('select.dragging_handle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to select.idle, keeping shape, on pointer up', () => {
|
it('returns to select.idle, keeping shape, on pointer up', () => {
|
||||||
|
@ -84,7 +84,7 @@ describe('When dragging the line', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns to line.idle, keeping shape, on pointer up if tool lock is enabled', () => {
|
it('returns to line.idle, keeping shape, on pointer up if tool lock is enabled', () => {
|
||||||
|
@ -98,7 +98,7 @@ describe('When dragging the line', () => {
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore + 1)
|
expect(shapesAfter).toBe(shapesBefore + 1)
|
||||||
expect(editor.getHintingShapeIds().length).toBe(0)
|
expect(editor.getHintingShapeIds().length).toBe(0)
|
||||||
editor.expectPathToBe('root.line.idle')
|
editor.expectToBeIn('line.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('bails on cancel', () => {
|
it('bails on cancel', () => {
|
||||||
|
@ -110,7 +110,7 @@ describe('When dragging the line', () => {
|
||||||
.cancel()
|
.cancel()
|
||||||
const shapesAfter = editor.currentPageShapes.length
|
const shapesAfter = editor.currentPageShapes.length
|
||||||
expect(shapesAfter).toBe(shapesBefore)
|
expect(shapesAfter).toBe(shapesBefore)
|
||||||
editor.expectPathToBe('root.line.idle')
|
editor.expectToBeIn('line.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ describe('Misc', () => {
|
||||||
editor
|
editor
|
||||||
.pointerDown(150, 0, { target: 'selection', handle: 'bottom' })
|
.pointerDown(150, 0, { target: 'selection', handle: 'bottom' })
|
||||||
.pointerMove(150, 600) // Resize shape by 0, 600
|
.pointerMove(150, 600) // Resize shape by 0, 600
|
||||||
.expectPathToBe('root.select.resizing')
|
.expectToBeIn('select.resizing')
|
||||||
|
|
||||||
expect(editor.getShape(id)!).toMatchSnapshot('line shape after resize')
|
expect(editor.getShape(id)!).toMatchSnapshot('line shape after resize')
|
||||||
})
|
})
|
||||||
|
|
|
@ -147,7 +147,7 @@ export class Pointing extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
override onInterrupt: TLInterruptEvent = () => {
|
override onInterrupt: TLInterruptEvent = () => {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
if (this.markId) this.editor.bailToMark(this.markId)
|
if (this.markId) this.editor.bailToMark(this.markId)
|
||||||
this.editor.snaps.clear()
|
this.editor.snaps.clear()
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ describe(NoteShapeTool, () => {
|
||||||
describe('When selecting the tool', () => {
|
describe('When selecting the tool', () => {
|
||||||
it('selects the tool and enters the idle state', () => {
|
it('selects the tool and enters the idle state', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -67,19 +67,19 @@ describe('When in the idle state', () => {
|
||||||
it('Enters pointing state on pointer down', () => {
|
it('Enters pointing state on pointer down', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(100, 100)
|
editor.pointerDown(100, 100)
|
||||||
editor.expectPathToBe('root.note.pointing')
|
editor.expectToBeIn('note.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Switches back to select tool on cancel', () => {
|
it('Switches back to select tool on cancel', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Does nothing on interrupt', () => {
|
it('Does nothing on interrupt', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -87,18 +87,18 @@ describe('When in the pointing state', () => {
|
||||||
it('Switches back to idle on cancel', () => {
|
it('Switches back to idle on cancel', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.note.pointing')
|
editor.expectToBeIn('note.pointing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the select.translating state on drag start', () => {
|
it('Enters the select.translating state on drag start', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(51, 51) // not far enough!
|
editor.pointerMove(51, 51) // not far enough!
|
||||||
editor.expectPathToBe('root.note.pointing')
|
editor.expectToBeIn('note.pointing')
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.select.translating')
|
editor.expectToBeIn('select.translating')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the note tool on cancel from translating', () => {
|
it('Returns to the note tool on cancel from translating', () => {
|
||||||
|
@ -106,7 +106,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the note tool on complete from translating when tool lock is enabled', () => {
|
it('Returns to the note tool on complete from translating when tool lock is enabled', () => {
|
||||||
|
@ -115,14 +115,14 @@ describe('When in the pointing state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the idle state on interrupt', () => {
|
it('Returns to the idle state on interrupt', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Creates a note and begins editing on pointer up', () => {
|
it('Creates a note and begins editing on pointer up', () => {
|
||||||
|
@ -130,7 +130,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.select.editing_shape')
|
editor.expectToBeIn('select.editing_shape')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ describe('When in the pointing state', () => {
|
||||||
editor.setCurrentTool('note')
|
editor.setCurrentTool('note')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerUp(50, 50)
|
editor.pointerUp(50, 50)
|
||||||
editor.expectPathToBe('root.note.idle')
|
editor.expectToBeIn('note.idle')
|
||||||
expect(editor.currentPageShapes.length).toBe(1)
|
expect(editor.currentPageShapes.length).toBe(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -63,7 +63,7 @@ export class Pointing extends StateNode {
|
||||||
private complete() {
|
private complete() {
|
||||||
if (this.wasFocusedOnEnter) {
|
if (this.wasFocusedOnEnter) {
|
||||||
if (this.editor.getInstanceState().isToolLocked) {
|
if (this.editor.getInstanceState().isToolLocked) {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
} else {
|
} else {
|
||||||
this.editor.setEditingShape(this.shape.id)
|
this.editor.setEditingShape(this.shape.id)
|
||||||
this.editor.setCurrentTool('select.editing_shape', {
|
this.editor.setCurrentTool('select.editing_shape', {
|
||||||
|
|
|
@ -32,7 +32,7 @@ export class Idle extends StateNode {
|
||||||
) {
|
) {
|
||||||
this.editor.setCurrentTool('select')
|
this.editor.setCurrentTool('select')
|
||||||
this.editor.setEditingShape(onlySelectedShape.id)
|
this.editor.setEditingShape(onlySelectedShape.id)
|
||||||
this.editor.root.current.get()!.transition('editing_shape', {
|
this.editor.root.getCurrent()!.transition('editing_shape', {
|
||||||
...info,
|
...info,
|
||||||
target: 'shape',
|
target: 'shape',
|
||||||
shape: onlySelectedShape,
|
shape: onlySelectedShape,
|
||||||
|
|
|
@ -90,11 +90,11 @@ export class Pointing extends StateNode {
|
||||||
|
|
||||||
this.editor.setEditingShape(id)
|
this.editor.setEditingShape(id)
|
||||||
this.editor.setCurrentTool('select')
|
this.editor.setCurrentTool('select')
|
||||||
this.editor.root.current.get()?.transition('editing_shape', {})
|
this.editor.root.getCurrent()?.transition('editing_shape')
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
this.editor.bailToMark(this.markId)
|
this.editor.bailToMark(this.markId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ export class Erasing extends StateNode {
|
||||||
complete() {
|
complete() {
|
||||||
this.editor.deleteShapes(this.editor.getCurrentPageState().erasingShapeIds)
|
this.editor.deleteShapes(this.editor.getCurrentPageState().erasingShapeIds)
|
||||||
this.editor.setErasingShapes([])
|
this.editor.setErasingShapes([])
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
|
|
|
@ -83,11 +83,11 @@ export class Pointing extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editor.setErasingShapes([])
|
this.editor.setErasingShapes([])
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.editor.setErasingShapes([])
|
this.editor.setErasingShapes([])
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,6 @@ export class Dragging extends StateNode {
|
||||||
friction: CAMERA_SLIDE_FRICTION,
|
friction: CAMERA_SLIDE_FRICTION,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ export class Pointing extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private complete() {
|
private complete() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,10 @@ export class Lasering extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private complete() {
|
private complete() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ export class Brushing extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private complete() {
|
private complete() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private hitTestShapes() {
|
private hitTestShapes() {
|
||||||
|
|
|
@ -209,7 +209,7 @@ export class Cropping extends StateNode {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCroppingShape(null)
|
this.editor.setCroppingShape(null)
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ export class Cropping extends StateNode {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCroppingShape(null)
|
this.editor.setCroppingShape(null)
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ export class DraggingHandle extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.exactTimeout = setTimeout(() => {
|
this.exactTimeout = setTimeout(() => {
|
||||||
if (this.isActive && !this.isPrecise) {
|
if (this.getIsActive() && !this.isPrecise) {
|
||||||
this.isPrecise = true
|
this.isPrecise = true
|
||||||
this.isPreciseId = this.pointingId
|
this.isPreciseId = this.pointingId
|
||||||
this.update()
|
this.update()
|
||||||
|
@ -186,7 +186,7 @@ export class DraggingHandle extends StateNode {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
|
@ -201,7 +201,7 @@ export class DraggingHandle extends StateNode {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private update() {
|
private update() {
|
||||||
|
|
|
@ -32,10 +32,10 @@ export class PointingCanvas extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
override onInterrupt = () => {
|
override onInterrupt = () => {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private complete() {
|
private complete() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class PointingCropHandle extends StateNode {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCroppingShape(null)
|
this.editor.setCroppingShape(null)
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ export class PointingCropHandle extends StateNode {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
||||||
} else {
|
} else {
|
||||||
this.editor.setCroppingShape(null)
|
this.editor.setCroppingShape(null)
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,6 @@ export class PointingHandle extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ export class PointingResizeHandle extends StateNode {
|
||||||
if (this.info.onInteractionEnd) {
|
if (this.info.onInteractionEnd) {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export class PointingResizeHandle extends StateNode {
|
||||||
if (this.info.onInteractionEnd) {
|
if (this.info.onInteractionEnd) {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ export class PointingRotateHandle extends StateNode {
|
||||||
if (this.info.onInteractionEnd) {
|
if (this.info.onInteractionEnd) {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ export class PointingRotateHandle extends StateNode {
|
||||||
if (this.info.onInteractionEnd) {
|
if (this.info.onInteractionEnd) {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ export class PointingSelection extends StateNode {
|
||||||
|
|
||||||
if (hitShape) {
|
if (hitShape) {
|
||||||
// todo: extract the double click shape logic from idle so that we can share it here
|
// todo: extract the double click shape logic from idle so that we can share it here
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
this.parent.onDoubleClick?.({
|
this.parent.onDoubleClick?.({
|
||||||
...info,
|
...info,
|
||||||
target: 'shape',
|
target: 'shape',
|
||||||
|
@ -66,6 +66,6 @@ export class PointingSelection extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,6 @@ export class PointingShape extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ export class Resizing extends StateNode {
|
||||||
if (this.info.onInteractionEnd) {
|
if (this.info.onInteractionEnd) {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
this.editor.setCurrentTool(this.info.onInteractionEnd, {})
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ export class Resizing extends StateNode {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleResizeStart() {
|
private handleResizeStart() {
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class ScribbleBrushing extends StateNode {
|
||||||
|
|
||||||
override onKeyUp = () => {
|
override onKeyUp = () => {
|
||||||
if (!this.editor.inputs.altKey) {
|
if (!this.editor.inputs.altKey) {
|
||||||
this.parent.transition('brushing', {})
|
this.parent.transition('brushing')
|
||||||
} else {
|
} else {
|
||||||
this.updateScribbleSelection(false)
|
this.updateScribbleSelection(false)
|
||||||
}
|
}
|
||||||
|
@ -157,11 +157,11 @@ export class ScribbleBrushing extends StateNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
private complete() {
|
private complete() {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
|
|
||||||
private cancel() {
|
private cancel() {
|
||||||
this.editor.setSelectedShapes([...this.initialSelectedShapeIds], { squashing: true })
|
this.editor.setSelectedShapes([...this.initialSelectedShapeIds], { squashing: true })
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ export class Translating extends StateNode {
|
||||||
this.editor.setCurrentTool('select.editing_shape')
|
this.editor.setCurrentTool('select.editing_shape')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('idle', {})
|
this.parent.transition('idle')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export class ZoomTool extends StateNode {
|
||||||
if (this.info.onInteractionEnd && this.info.onInteractionEnd !== 'select') {
|
if (this.info.onInteractionEnd && this.info.onInteractionEnd !== 'select') {
|
||||||
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
this.editor.setCurrentTool(this.info.onInteractionEnd, this.info)
|
||||||
} else {
|
} else {
|
||||||
this.parent.transition('select', {})
|
this.parent.transition('select')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ export const DebugPanel = React.memo(function DebugPanel({
|
||||||
|
|
||||||
const CurrentState = track(function CurrentState() {
|
const CurrentState = track(function CurrentState() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
return <div className="tlui-debug-panel__current-state">{editor.root.path.get()}</div>
|
return <div className="tlui-debug-panel__current-state">{editor.root.getPath()}</div>
|
||||||
})
|
})
|
||||||
|
|
||||||
const ShapeCount = function ShapeCount() {
|
const ShapeCount = function ShapeCount() {
|
||||||
|
|
|
@ -279,12 +279,12 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
||||||
readonlyOk: true,
|
readonlyOk: true,
|
||||||
kbd: 'z',
|
kbd: 'z',
|
||||||
onSelect(source) {
|
onSelect(source) {
|
||||||
if (editor.root.current.get()?.id === 'zoom') return
|
if (editor.root.getCurrent()?.id === 'zoom') return
|
||||||
|
|
||||||
trackEvent('zoom-tool', { source })
|
trackEvent('zoom-tool', { source })
|
||||||
if (!(editor.inputs.shiftKey || editor.inputs.ctrlKey)) {
|
if (!(editor.inputs.shiftKey || editor.inputs.ctrlKey)) {
|
||||||
const currentTool = editor.root.current.get()
|
const currentTool = editor.root.getCurrent()
|
||||||
if (currentTool && currentTool.current.get()?.id === 'idle') {
|
if (currentTool && currentTool.getCurrent()?.id === 'idle') {
|
||||||
editor.setCurrentTool('zoom', { onInteractionEnd: currentTool.id, maskAs: 'zoom' })
|
editor.setCurrentTool('zoom', { onInteractionEnd: currentTool.id, maskAs: 'zoom' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ export function useRelevantStyles(): {
|
||||||
() => {
|
() => {
|
||||||
const styles = new SharedStyleMap(editor.sharedStyles)
|
const styles = new SharedStyleMap(editor.sharedStyles)
|
||||||
const hasShape =
|
const hasShape =
|
||||||
editor.getSelectedShapeIds().length > 0 || !!editor.root.current.get()?.shapeType
|
editor.getSelectedShapeIds().length > 0 || !!editor.root.getCurrent()?.shapeType
|
||||||
|
|
||||||
if (styles.size === 0 && editor.isIn('select') && editor.getSelectedShapeIds().length === 0) {
|
if (styles.size === 0 && editor.isIn('select') && editor.getSelectedShapeIds().length === 0) {
|
||||||
for (const style of selectToolStyles) {
|
for (const style of selectToolStyles) {
|
||||||
|
|
|
@ -322,7 +322,7 @@ describe('currentToolId', () => {
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
|
|
||||||
expect(editor.getCurrentToolId()).toBe('geo')
|
expect(editor.getCurrentToolId()).toBe('geo')
|
||||||
expect(editor.root.path.get()).toBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('reverts back to select if we finish the interaction', () => {
|
it('reverts back to select if we finish the interaction', () => {
|
||||||
|
@ -333,7 +333,7 @@ describe('currentToolId', () => {
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
|
|
||||||
expect(editor.getCurrentToolId()).toBe('geo')
|
expect(editor.getCurrentToolId()).toBe('geo')
|
||||||
expect(editor.root.path.get()).toBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
|
|
||||||
editor.pointerUp(100, 100)
|
editor.pointerUp(100, 100)
|
||||||
|
|
||||||
|
@ -348,7 +348,7 @@ describe('currentToolId', () => {
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
|
|
||||||
expect(editor.getCurrentToolId()).toBe('geo')
|
expect(editor.getCurrentToolId()).toBe('geo')
|
||||||
expect(editor.root.path.get()).toBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
|
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
|
|
||||||
|
|
|
@ -97,14 +97,14 @@ describe('When clicking', () => {
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
|
|
||||||
// Starts in idle
|
// Starts in idle
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
const shapesBeforeCount = editor.currentPageShapes.length
|
const shapesBeforeCount = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.pointerDown(0, 0) // near enough to box1
|
editor.pointerDown(0, 0) // near enough to box1
|
||||||
|
|
||||||
// Enters the pointing state
|
// Enters the pointing state
|
||||||
editor.expectPathToBe('root.eraser.pointing')
|
editor.expectToBeIn('eraser.pointing')
|
||||||
|
|
||||||
// Sets the erasingShapeIds array
|
// Sets the erasingShapeIds array
|
||||||
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
||||||
|
@ -121,7 +121,7 @@ describe('When clicking', () => {
|
||||||
expect(editor.getErasingShapeIds()).toEqual([])
|
expect(editor.getErasingShapeIds()).toEqual([])
|
||||||
|
|
||||||
// Returns to idle
|
// Returns to idle
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
|
||||||
|
@ -240,12 +240,12 @@ describe('When clicking', () => {
|
||||||
|
|
||||||
it('Clears erasing ids and does not erase shapes on cancel', () => {
|
it('Clears erasing ids and does not erase shapes on cancel', () => {
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
const shapesBeforeCount = editor.currentPageShapes.length
|
const shapesBeforeCount = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.pointerDown(0, 0) // in box1
|
editor.pointerDown(0, 0) // in box1
|
||||||
editor.expectPathToBe('root.eraser.pointing')
|
editor.expectToBeIn('eraser.pointing')
|
||||||
|
|
||||||
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ describe('When clicking', () => {
|
||||||
|
|
||||||
const shapesAfterCount = editor.currentPageShapes.length
|
const shapesAfterCount = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
// Does NOT erase the shape
|
// Does NOT erase the shape
|
||||||
expect(editor.getErasingShapeIds()).toEqual([])
|
expect(editor.getErasingShapeIds()).toEqual([])
|
||||||
|
@ -265,12 +265,12 @@ describe('When clicking', () => {
|
||||||
|
|
||||||
it('Clears erasing ids and does not erase shapes on interrupt', () => {
|
it('Clears erasing ids and does not erase shapes on interrupt', () => {
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
const shapesBeforeCount = editor.currentPageShapes.length
|
const shapesBeforeCount = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.pointerDown(0, 0) // near to box1
|
editor.pointerDown(0, 0) // near to box1
|
||||||
editor.expectPathToBe('root.eraser.pointing')
|
editor.expectToBeIn('eraser.pointing')
|
||||||
|
|
||||||
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ describe('When clicking', () => {
|
||||||
|
|
||||||
const shapesAfterCount = editor.currentPageShapes.length
|
const shapesAfterCount = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
// Does NOT erase the shape
|
// Does NOT erase the shape
|
||||||
expect(editor.getErasingShapeIds()).toEqual([])
|
expect(editor.getErasingShapeIds()).toEqual([])
|
||||||
|
@ -293,16 +293,16 @@ describe('When clicking and dragging', () => {
|
||||||
it('Enters erasing state on pointer move, adds contacted shapes to the apps.erasingShapeIds array, deletes them and clears erasingShapeIds on pointer up, restores shapes on undo and deletes again on redo', () => {
|
it('Enters erasing state on pointer move, adds contacted shapes to the apps.erasingShapeIds array, deletes them and clears erasingShapeIds on pointer up, restores shapes on undo and deletes again on redo', () => {
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
|
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
|
|
||||||
editor.pointerDown(-100, -100) // outside of any shapes
|
editor.pointerDown(-100, -100) // outside of any shapes
|
||||||
|
|
||||||
editor.expectPathToBe('root.eraser.pointing')
|
editor.expectToBeIn('eraser.pointing')
|
||||||
expect(editor.getInstanceState().scribbles.length).toBe(0)
|
expect(editor.getInstanceState().scribbles.length).toBe(0)
|
||||||
|
|
||||||
editor.pointerMove(50, 50) // inside of box1
|
editor.pointerMove(50, 50) // inside of box1
|
||||||
|
|
||||||
editor.expectPathToBe('root.eraser.erasing')
|
editor.expectToBeIn('eraser.erasing')
|
||||||
|
|
||||||
jest.advanceTimersByTime(16)
|
jest.advanceTimersByTime(16)
|
||||||
expect(editor.getInstanceState().scribbles.length).toBe(1)
|
expect(editor.getInstanceState().scribbles.length).toBe(1)
|
||||||
|
@ -310,7 +310,7 @@ describe('When clicking and dragging', () => {
|
||||||
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
||||||
|
|
||||||
// editor.pointerUp()
|
// editor.pointerUp()
|
||||||
// editor.expectPathToBe('root.eraser.idle')
|
// editor.expectToBeIn('eraser.idle')
|
||||||
// expect(editor.erasingShapeIds).toEqual([])
|
// expect(editor.erasingShapeIds).toEqual([])
|
||||||
// expect(editor.getShape(ids.box1)).not.toBeDefined()
|
// expect(editor.getShape(ids.box1)).not.toBeDefined()
|
||||||
|
|
||||||
|
@ -327,14 +327,14 @@ describe('When clicking and dragging', () => {
|
||||||
|
|
||||||
it('Clears erasing ids and does not erase shapes on cancel', () => {
|
it('Clears erasing ids and does not erase shapes on cancel', () => {
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
editor.pointerDown(-100, -100) // outside of any shapes
|
editor.pointerDown(-100, -100) // outside of any shapes
|
||||||
editor.pointerMove(50, 50) // inside of box1
|
editor.pointerMove(50, 50) // inside of box1
|
||||||
jest.advanceTimersByTime(16)
|
jest.advanceTimersByTime(16)
|
||||||
expect(editor.getInstanceState().scribbles.length).toBe(1)
|
expect(editor.getInstanceState().scribbles.length).toBe(1)
|
||||||
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
expect(editor.getErasingShapeIds()).toEqual([ids.box1])
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
expect(editor.getErasingShapeIds()).toEqual([])
|
expect(editor.getErasingShapeIds()).toEqual([])
|
||||||
expect(editor.getShape(ids.box1)).toBeDefined()
|
expect(editor.getShape(ids.box1)).toBeDefined()
|
||||||
})
|
})
|
||||||
|
@ -342,7 +342,7 @@ describe('When clicking and dragging', () => {
|
||||||
it('Excludes a group if it was hovered when the drag started', () => {
|
it('Excludes a group if it was hovered when the drag started', () => {
|
||||||
editor.groupShapes([ids.box2, ids.box3], ids.group1)
|
editor.groupShapes([ids.box2, ids.box3], ids.group1)
|
||||||
editor.setCurrentTool('eraser')
|
editor.setCurrentTool('eraser')
|
||||||
editor.expectPathToBe('root.eraser.idle')
|
editor.expectToBeIn('eraser.idle')
|
||||||
editor.pointerDown(275, 275) // in between box2 AND box3, so over of the new group
|
editor.pointerDown(275, 275) // in between box2 AND box3, so over of the new group
|
||||||
editor.pointerMove(280, 280) // still outside of the new group
|
editor.pointerMove(280, 280) // still outside of the new group
|
||||||
jest.advanceTimersByTime(16)
|
jest.advanceTimersByTime(16)
|
||||||
|
@ -394,7 +394,7 @@ describe('When clicking and dragging', () => {
|
||||||
editor.pointerDown(-100, -100)
|
editor.pointerDown(-100, -100)
|
||||||
editor.pointerMove(50, 50)
|
editor.pointerMove(50, 50)
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.eraser.erasing')
|
editor.expectToBeIn('eraser.erasing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Starts a scribble on pointer down, updates it on pointer move, stops it on exit', () => {
|
it('Starts a scribble on pointer down, updates it on pointer move, stops it on exit', () => {
|
||||||
|
@ -439,8 +439,8 @@ describe('When shift clicking', () => {
|
||||||
describe('When in the idle state', () => {
|
describe('When in the idle state', () => {
|
||||||
it('Returns to select on cancel', () => {
|
it('Returns to select on cancel', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -74,16 +74,16 @@ describe(HandTool, () => {
|
||||||
describe('When in the idle state', () => {
|
describe('When in the idle state', () => {
|
||||||
it('Returns to select on cancel', () => {
|
it('Returns to select on cancel', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When selecting the tool', () => {
|
describe('When selecting the tool', () => {
|
||||||
it('selects the tool and enters the idle state', () => {
|
it('selects the tool and enters the idle state', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -91,19 +91,19 @@ describe('When in the idle state', () => {
|
||||||
it('Enters pointing state on pointer down', () => {
|
it('Enters pointing state on pointer down', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.pointerDown(100, 100)
|
editor.pointerDown(100, 100)
|
||||||
editor.expectPathToBe('root.hand.pointing')
|
editor.expectToBeIn('hand.pointing')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Switches back to select tool on cancel', () => {
|
it('Switches back to select tool on cancel', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Does nothing on interrupt', () => {
|
it('Does nothing on interrupt', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -111,32 +111,32 @@ describe('When in the pointing state', () => {
|
||||||
it('Switches back to idle on cancel', () => {
|
it('Switches back to idle on cancel', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.hand.pointing')
|
editor.expectToBeIn('hand.pointing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Enters the dragging state on drag start', () => {
|
it('Enters the dragging state on drag start', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(51, 51) // not far enough!
|
editor.pointerMove(51, 51) // not far enough!
|
||||||
editor.expectPathToBe('root.hand.pointing')
|
editor.expectToBeIn('hand.pointing')
|
||||||
editor.pointerMove(55, 55)
|
editor.pointerMove(55, 55)
|
||||||
editor.expectPathToBe('root.hand.dragging')
|
editor.expectToBeIn('hand.dragging')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the idle state on cancel', () => {
|
it('Returns to the idle state on cancel', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Returns to the idle state on interrupt', () => {
|
it('Returns to the idle state on interrupt', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.interrupt()
|
editor.interrupt()
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -146,11 +146,11 @@ describe('When in the dragging state', () => {
|
||||||
expect(editor.getCamera().x).toBe(0)
|
expect(editor.getCamera().x).toBe(0)
|
||||||
expect(editor.getCamera().y).toBe(0)
|
expect(editor.getCamera().y).toBe(0)
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.expectPathToBe('root.hand.pointing')
|
editor.expectToBeIn('hand.pointing')
|
||||||
editor.pointerMove(75, 75)
|
editor.pointerMove(75, 75)
|
||||||
expect(editor.getCamera().x).toBe(25)
|
expect(editor.getCamera().x).toBe(25)
|
||||||
expect(editor.getCamera().y).toBe(25)
|
expect(editor.getCamera().y).toBe(25)
|
||||||
editor.expectPathToBe('root.hand.dragging')
|
editor.expectToBeIn('hand.dragging')
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
expect(editor.getCamera().x).toBe(50)
|
expect(editor.getCamera().x).toBe(50)
|
||||||
expect(editor.getCamera().y).toBe(50)
|
expect(editor.getCamera().y).toBe(50)
|
||||||
|
@ -186,6 +186,6 @@ describe('When in the dragging state', () => {
|
||||||
editor.pointerDown(50, 50)
|
editor.pointerDown(50, 50)
|
||||||
editor.pointerMove(100, 100)
|
editor.pointerMove(100, 100)
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -189,12 +189,7 @@ export class TestEditor extends Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectToBeIn = (path: string) => {
|
expectToBeIn = (path: string) => {
|
||||||
expect(this.root.current.get()!.path.get()).toBe(path)
|
expect(this.getPath()).toBe(path)
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
expectPathToBe = (path: string) => {
|
|
||||||
expect(this.root.path.get()).toBe(path)
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,11 @@ afterEach(() => {
|
||||||
describe('Set selected tool', () => {
|
describe('Set selected tool', () => {
|
||||||
it('Selects a tool by its name', () => {
|
it('Selects a tool by its name', () => {
|
||||||
editor.setCurrentTool('hand')
|
editor.setCurrentTool('hand')
|
||||||
editor.expectPathToBe('root.hand.idle')
|
editor.expectToBeIn('hand.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Selects a tool by its deep path', () => {
|
it('Selects a tool by its deep path', () => {
|
||||||
editor.setCurrentTool('hand.pointing')
|
editor.setCurrentTool('hand.pointing')
|
||||||
editor.expectPathToBe('root.hand.pointing')
|
editor.expectToBeIn('hand.pointing')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -90,12 +90,12 @@ describe('When in the select.idle state', () => {
|
||||||
it('double clicking an image should transition to select.crop', () => {
|
it('double clicking an image should transition to select.crop', () => {
|
||||||
editor.select(ids.boxA)
|
editor.select(ids.boxA)
|
||||||
|
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.boxA])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.boxA])
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
|
|
||||||
editor.doubleClick(550, 550, ids.imageB)
|
editor.doubleClick(550, 550, ids.imageB)
|
||||||
editor.expectPathToBe('root.select.crop.idle')
|
editor.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
|
@ -103,14 +103,14 @@ describe('When in the select.idle state', () => {
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
|
||||||
// first selection should have been a mark
|
// first selection should have been a mark
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
|
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
|
||||||
// back to start
|
// back to start
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.boxA])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.boxA])
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ describe('When in the select.idle state', () => {
|
||||||
.redo() // select again
|
.redo() // select again
|
||||||
.redo() // crop again
|
.redo() // crop again
|
||||||
|
|
||||||
editor.expectPathToBe('root.select.crop.idle')
|
editor.expectToBeIn('select.crop.idle')
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
})
|
})
|
||||||
|
@ -128,49 +128,49 @@ describe('When in the select.idle state', () => {
|
||||||
|
|
||||||
// corner (two shapes)
|
// corner (two shapes)
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageA, ids.imageB)
|
.select(ids.imageA, ids.imageB)
|
||||||
.doubleClick(550, 550, {
|
.doubleClick(550, 550, {
|
||||||
target: 'selection',
|
target: 'selection',
|
||||||
handle: 'bottom_right',
|
handle: 'bottom_right',
|
||||||
})
|
})
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
|
|
||||||
// edge (two shapes)
|
// edge (two shapes)
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, {
|
.doubleClick(550, 550, {
|
||||||
target: 'selection',
|
target: 'selection',
|
||||||
handle: 'bottom',
|
handle: 'bottom',
|
||||||
})
|
})
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
|
|
||||||
// corner (one shape)
|
// corner (one shape)
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.doubleClick(550, 550, {
|
.doubleClick(550, 550, {
|
||||||
target: 'selection',
|
target: 'selection',
|
||||||
handle: 'bottom_right',
|
handle: 'bottom_right',
|
||||||
})
|
})
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
|
|
||||||
// edge (one shape)
|
// edge (one shape)
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, {
|
.doubleClick(550, 550, {
|
||||||
target: 'selection',
|
target: 'selection',
|
||||||
handle: 'bottom',
|
handle: 'bottom',
|
||||||
})
|
})
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
})
|
})
|
||||||
|
@ -178,19 +178,19 @@ describe('When in the select.idle state', () => {
|
||||||
it('when only an image is selected pressing enter should transition to select.crop', () => {
|
it('when only an image is selected pressing enter should transition to select.crop', () => {
|
||||||
// two shapes
|
// two shapes
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageA, ids.imageB)
|
.select(ids.imageA, ids.imageB)
|
||||||
.keyDown('Enter')
|
.keyDown('Enter')
|
||||||
.keyUp('Enter')
|
.keyUp('Enter')
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
// one image
|
// one image
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.keyDown('Enter')
|
.keyDown('Enter')
|
||||||
.keyUp('Enter')
|
.keyUp('Enter')
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
})
|
})
|
||||||
|
@ -199,101 +199,101 @@ describe('When in the select.idle state', () => {
|
||||||
// two shapes / edge
|
// two shapes / edge
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageA, ids.imageB)
|
.select(ids.imageA, ids.imageB)
|
||||||
.pointerDown(500, 550, { target: 'selection', handle: 'bottom', ctrlKey: true })
|
.pointerDown(500, 550, { target: 'selection', handle: 'bottom', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.brushing')
|
.expectToBeIn('select.brushing')
|
||||||
|
|
||||||
// two shapes / corner
|
// two shapes / corner
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageA, ids.imageB)
|
.select(ids.imageA, ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.brushing')
|
.expectToBeIn('select.brushing')
|
||||||
|
|
||||||
// one shape / edge
|
// one shape / edge
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 550, { target: 'selection', handle: 'bottom', ctrlKey: true })
|
.pointerDown(500, 550, { target: 'selection', handle: 'bottom', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
|
|
||||||
// one shape / corner
|
// one shape / corner
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When in the crop.idle state', () => {
|
describe('When in the crop.idle state', () => {
|
||||||
it('pressing escape should transition to select.idle', () => {
|
it('pressing escape should transition to select.idle', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('pressing enter should transition to select.idle', () => {
|
it('pressing enter should transition to select.idle', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.keyDown('Enter')
|
.keyDown('Enter')
|
||||||
.keyUp('Enter')
|
.keyUp('Enter')
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('pointing the canvas should point canvas', () => {
|
it('pointing the canvas should point canvas', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.pointerMove(-100, -100)
|
.pointerMove(-100, -100)
|
||||||
.pointerDown()
|
.pointerDown()
|
||||||
.expectPathToBe('root.select.pointing_canvas')
|
.expectToBeIn('select.pointing_canvas')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('pointing some other shape should start pointing the shape', () => {
|
it('pointing some other shape should start pointing the shape', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.pointerMove(550, 500)
|
.pointerMove(550, 500)
|
||||||
.pointerDown()
|
.pointerDown()
|
||||||
.expectPathToBe('root.select.pointing_shape')
|
.expectToBeIn('select.pointing_shape')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('pointing a selection handle should enter the select.pointing_crop_handle state', () => {
|
it('pointing a selection handle should enter the select.pointing_crop_handle state', () => {
|
||||||
// corner
|
// corner
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: false })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: false })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
|
|
||||||
//reset
|
//reset
|
||||||
editor.cancel().cancel()
|
editor.cancel().cancel()
|
||||||
|
|
||||||
// edge
|
// edge
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('pointing the cropping image should enter the select.crop.translating_crop state', () => {
|
it('pointing the cropping image should enter the select.crop.translating_crop state', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(500, 600, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageB])
|
||||||
|
@ -301,11 +301,11 @@ describe('When in the crop.idle state', () => {
|
||||||
|
|
||||||
it('clicking another image shape should set that shape as the new cropping shape and transition to pointing_crop', () => {
|
it('clicking another image shape should set that shape as the new cropping shape and transition to pointing_crop', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(100, 100, { target: 'shape', shape: editor.getShape(ids.imageA) })
|
.pointerDown(100, 100, { target: 'shape', shape: editor.getShape(ids.imageA) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageA)
|
expect(editor.croppingShapeId).toBe(ids.imageA)
|
||||||
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageA])
|
expect(editor.getSelectedShapeIds()).toMatchObject([ids.imageA])
|
||||||
|
@ -313,22 +313,22 @@ describe('When in the crop.idle state', () => {
|
||||||
|
|
||||||
it('rotating will return to select.crop.idle', () => {
|
it('rotating will return to select.crop.idle', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'top_left_rotate' })
|
.pointerDown(500, 600, { target: 'selection', handle: 'top_left_rotate' })
|
||||||
.expectPathToBe('root.select.pointing_rotate_handle')
|
.expectToBeIn('select.pointing_rotate_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.rotating')
|
.expectToBeIn('select.rotating')
|
||||||
.pointerUp()
|
.pointerUp()
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('nudges the cropped image', () => {
|
it('nudges the cropped image', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
const crop = () => editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const crop = () => editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
|
||||||
|
@ -374,34 +374,34 @@ describe('When in the crop.idle state', () => {
|
||||||
describe('When in the select.crop.pointing_crop state', () => {
|
describe('When in the select.crop.pointing_crop state', () => {
|
||||||
it('pressing escape / cancel returns to select.crop.idle', () => {
|
it('pressing escape / cancel returns to select.crop.idle', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
})
|
})
|
||||||
it('dragging enters select.crop.translating_crop', () => {
|
it('dragging enters select.crop.translating_crop', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
.pointerMove(560, 560)
|
.pointerMove(560, 560)
|
||||||
.expectPathToBe('root.select.crop.translating_crop')
|
.expectToBeIn('select.crop.translating_crop')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When in the select.crop.translating_crop state', () => {
|
describe('When in the select.crop.translating_crop state', () => {
|
||||||
it('moving the pointer should adjust the crop', () => {
|
it('moving the pointer should adjust the crop', () => {
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
|
|
||||||
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ describe('When in the select.crop.translating_crop state', () => {
|
||||||
// Move the pointer to the left
|
// Move the pointer to the left
|
||||||
editor
|
editor
|
||||||
.pointerMove(550 - imageWidth / 4, 550 - imageHeight / 4)
|
.pointerMove(550 - imageWidth / 4, 550 - imageHeight / 4)
|
||||||
.expectPathToBe('root.select.crop.translating_crop')
|
.expectToBeIn('select.crop.translating_crop')
|
||||||
|
|
||||||
// Update should have run right away
|
// Update should have run right away
|
||||||
const afterFirst = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const afterFirst = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
@ -456,7 +456,7 @@ describe('When in the select.crop.translating_crop state', () => {
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.keyDown('Shift')
|
.keyDown('Shift')
|
||||||
.pointerMove(550 - imageWidth / 8, 550 - imageHeight / 8)
|
.pointerMove(550 - imageWidth / 8, 550 - imageHeight / 8)
|
||||||
.expectPathToBe('root.select.crop.translating_crop')
|
.expectToBeIn('select.crop.translating_crop')
|
||||||
|
|
||||||
// Update should have run right away
|
// Update should have run right away
|
||||||
const afterShiftDown = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const afterShiftDown = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
@ -487,17 +487,17 @@ describe('When in the select.crop.translating_crop state', () => {
|
||||||
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
.pointerMove(250, 250)
|
.pointerMove(250, 250)
|
||||||
.expectPathToBe('root.select.crop.translating_crop')
|
.expectToBeIn('select.crop.translating_crop')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
|
|
||||||
editor.cancel().expectPathToBe('root.select.crop.idle')
|
editor.cancel().expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
||||||
})
|
})
|
||||||
|
@ -506,17 +506,17 @@ describe('When in the select.crop.translating_crop state', () => {
|
||||||
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
const before = editor.getShape<TLImageShape>(ids.imageB)!.props.crop!
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
.pointerDown(550, 550, { target: 'shape', shape: editor.getShape(ids.imageB) })
|
||||||
.expectPathToBe('root.select.crop.pointing_crop')
|
.expectToBeIn('select.crop.pointing_crop')
|
||||||
.pointerMove(250, 250)
|
.pointerMove(250, 250)
|
||||||
.expectPathToBe('root.select.crop.translating_crop')
|
.expectToBeIn('select.crop.translating_crop')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
|
|
||||||
editor.keyDown('Enter').keyUp('Enter').expectPathToBe('root.select.crop.idle')
|
editor.keyDown('Enter').keyUp('Enter').expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
})
|
})
|
||||||
|
@ -526,24 +526,24 @@ describe('When in the select.pointing_crop_handle state', () => {
|
||||||
it('moving the pointer should transition to select.cropping', () => {
|
it('moving the pointer should transition to select.cropping', () => {
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('when entered from select.idle, pressing escape / cancel should return to idle and clear cropping idle', () => {
|
it('when entered from select.idle, pressing escape / cancel should return to idle and clear cropping idle', () => {
|
||||||
// coming from select.idle
|
// coming from select.idle
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(null)
|
expect(editor.croppingShapeId).toBe(null)
|
||||||
})
|
})
|
||||||
|
@ -552,13 +552,13 @@ describe('When in the select.pointing_crop_handle state', () => {
|
||||||
// coming from idle
|
// coming from idle
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: false })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: false })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.croppingShapeId).toBe(ids.imageB)
|
expect(editor.croppingShapeId).toBe(ids.imageB)
|
||||||
})
|
})
|
||||||
|
@ -570,12 +570,12 @@ describe('When in the select.cropping state', () => {
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
})
|
})
|
||||||
|
@ -585,14 +585,14 @@ describe('When in the select.cropping state', () => {
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
||||||
})
|
})
|
||||||
|
@ -602,15 +602,15 @@ describe('When in the select.cropping state', () => {
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).toMatchObject(before)
|
||||||
})
|
})
|
||||||
|
@ -620,15 +620,15 @@ describe('When in the select.cropping state', () => {
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.doubleClick(550, 550, ids.imageB)
|
.doubleClick(550, 550, ids.imageB)
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom', ctrlKey: false })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
.pointerUp()
|
.pointerUp()
|
||||||
.expectPathToBe('root.select.crop.idle')
|
.expectToBeIn('select.crop.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
@ -642,14 +642,14 @@ describe('When in the select.cropping state', () => {
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.cancel()
|
.cancel()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
.select(ids.imageB)
|
.select(ids.imageB)
|
||||||
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
.pointerDown(500, 600, { target: 'selection', handle: 'bottom_left', ctrlKey: true })
|
||||||
.expectPathToBe('root.select.pointing_crop_handle')
|
.expectToBeIn('select.pointing_crop_handle')
|
||||||
.pointerMove(510, 590)
|
.pointerMove(510, 590)
|
||||||
.expectPathToBe('root.select.cropping')
|
.expectToBeIn('select.cropping')
|
||||||
.pointerUp()
|
.pointerUp()
|
||||||
.expectPathToBe('root.select.idle')
|
.expectToBeIn('select.idle')
|
||||||
|
|
||||||
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
expect(editor.getShape<TLImageShape>(ids.imageB)!.props.crop!).not.toMatchObject(before)
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
|
|
@ -49,7 +49,7 @@ describe('creating frames', () => {
|
||||||
it('can be canceled while dragging', () => {
|
it('can be canceled while dragging', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(100, 100).pointerMove(200, 200)
|
editor.pointerDown(100, 100).pointerMove(200, 200)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
editor.cancel()
|
editor.cancel()
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getOnlySelectedShape()?.type).toBe(undefined)
|
expect(editor.getOnlySelectedShape()?.type).toBe(undefined)
|
||||||
|
@ -139,7 +139,7 @@ describe('creating frames', () => {
|
||||||
it('switches back to the select tool after creating', () => {
|
it('switches back to the select tool after creating', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(100, 100).pointerMove(49, 149).pointerUp()
|
editor.pointerDown(100, 100).pointerMove(49, 149).pointerUp()
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ describe('frame shapes', () => {
|
||||||
// select from outside the frame
|
// select from outside the frame
|
||||||
editor.setCurrentTool('select')
|
editor.setCurrentTool('select')
|
||||||
editor.pointerDown(50, 50).pointerMove(150, 150)
|
editor.pointerDown(50, 50).pointerMove(150, 150)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
|
|
||||||
expect(editor.getSelectedShapeIds()).toHaveLength(0)
|
expect(editor.getSelectedShapeIds()).toHaveLength(0)
|
||||||
|
|
||||||
|
@ -547,13 +547,13 @@ describe('frame shapes', () => {
|
||||||
it('can be selected with scribble brushing only if the drag starts outside the frame', () => {
|
it('can be selected with scribble brushing only if the drag starts outside the frame', () => {
|
||||||
editor.setCurrentTool('frame')
|
editor.setCurrentTool('frame')
|
||||||
editor.pointerDown(100, 100).pointerMove(200, 200).pointerUp(200, 200)
|
editor.pointerDown(100, 100).pointerMove(200, 200).pointerUp(200, 200)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
|
|
||||||
// select from inside the frame
|
// select from inside the frame
|
||||||
editor.selectNone()
|
editor.selectNone()
|
||||||
editor.setCurrentTool('select')
|
editor.setCurrentTool('select')
|
||||||
editor.pointerDown(150, 150).pointerMove(250, 250)
|
editor.pointerDown(150, 150).pointerMove(250, 250)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
|
|
||||||
expect(editor.getSelectedShapeIds()).toHaveLength(0)
|
expect(editor.getSelectedShapeIds()).toHaveLength(0)
|
||||||
})
|
})
|
||||||
|
@ -590,7 +590,7 @@ describe('frame shapes', () => {
|
||||||
editor.keyDown('alt').pointerDown(500, 500).pointerMove(300, 300)
|
editor.keyDown('alt').pointerDown(500, 500).pointerMove(300, 300)
|
||||||
|
|
||||||
// Check if in scribble brushing mode
|
// Check if in scribble brushing mode
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
|
|
||||||
// Check if the inner box was selected
|
// Check if the inner box was selected
|
||||||
editor.pointerUp(300, 300)
|
editor.pointerUp(300, 300)
|
||||||
|
|
|
@ -1034,7 +1034,7 @@ describe('the select tool', () => {
|
||||||
// it('should work while focused in a group if you start the drag from within the group', () => {
|
// it('should work while focused in a group if you start the drag from within the group', () => {
|
||||||
// editor.select(ids.boxA)
|
// editor.select(ids.boxA)
|
||||||
// editor.pointerDown(15, 5, groupAId).pointerMove(25, 9, ids.boxB)
|
// editor.pointerDown(15, 5, groupAId).pointerMove(25, 9, ids.boxB)
|
||||||
// expect(editor.root.path.value).toBe(`root.select.brushing`)
|
// expect(editor.getPath()).toBe(`select.brushing`)
|
||||||
// expect(editor.selectedShapeIds.includes(ids.boxA)).toBe(false)
|
// expect(editor.selectedShapeIds.includes(ids.boxA)).toBe(false)
|
||||||
// expect(editor.selectedShapeIds.includes(ids.boxB)).toBe(true)
|
// expect(editor.selectedShapeIds.includes(ids.boxB)).toBe(true)
|
||||||
|
|
||||||
|
@ -1048,7 +1048,7 @@ describe('the select tool', () => {
|
||||||
expect(editor.getShapesAtPoint({ x: -305, y: -5 })).toMatchObject([])
|
expect(editor.getShapesAtPoint({ x: -305, y: -5 })).toMatchObject([])
|
||||||
editor.pointerDown(-305, -5, { target: 'canvas' }).pointerMove(35, 9, ids.boxB)
|
editor.pointerDown(-305, -5, { target: 'canvas' }).pointerMove(35, 9, ids.boxB)
|
||||||
|
|
||||||
expect(editor.root.path.get()).toBe(`root.select.brushing`)
|
editor.expectToBeIn(`select.brushing`)
|
||||||
expect(editor.getSelectedShapeIds().includes(ids.boxA)).toBe(true)
|
expect(editor.getSelectedShapeIds().includes(ids.boxA)).toBe(true)
|
||||||
expect(editor.getSelectedShapeIds().includes(ids.boxB)).toBe(true)
|
expect(editor.getSelectedShapeIds().includes(ids.boxB)).toBe(true)
|
||||||
|
|
||||||
|
|
|
@ -862,7 +862,7 @@ describe('When resizing a shape with children', () => {
|
||||||
handle: 'top_left',
|
handle: 'top_left',
|
||||||
})
|
})
|
||||||
.pointerMove(0, 0)
|
.pointerMove(0, 0)
|
||||||
.expectPathToBe('root.select.resizing')
|
.expectToBeIn('select.resizing')
|
||||||
// A's model should have changed by the offset
|
// A's model should have changed by the offset
|
||||||
.expectShapeToMatch({
|
.expectShapeToMatch({
|
||||||
id: ids.boxA,
|
id: ids.boxA,
|
||||||
|
@ -926,7 +926,7 @@ describe('When resizing a shape with children', () => {
|
||||||
})
|
})
|
||||||
.pointerMove(0, 0)
|
.pointerMove(0, 0)
|
||||||
// .pointerMove(10, 10)
|
// .pointerMove(10, 10)
|
||||||
.expectPathToBe('root.select.resizing')
|
.expectToBeIn('select.resizing')
|
||||||
// A's model should have changed by the offset
|
// A's model should have changed by the offset
|
||||||
.expectShapeToMatch({
|
.expectShapeToMatch({
|
||||||
id: ids.boxB,
|
id: ids.boxB,
|
||||||
|
|
|
@ -19,7 +19,7 @@ describe(SelectTool, () => {
|
||||||
editor._transformPointerDownSpy.mockRestore()
|
editor._transformPointerDownSpy.mockRestore()
|
||||||
editor._transformPointerUpSpy.mockRestore()
|
editor._transformPointerUpSpy.mockRestore()
|
||||||
editor.setCurrentTool('select')
|
editor.setCurrentTool('select')
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
editor.doubleClick(50, 50, shapeId)
|
editor.doubleClick(50, 50, shapeId)
|
||||||
|
|
||||||
expect(editor.getCurrentPageState().editingShapeId).toBe(shapeId)
|
expect(editor.getCurrentPageState().editingShapeId).toBe(shapeId)
|
||||||
|
@ -37,7 +37,7 @@ describe(SelectTool, () => {
|
||||||
|
|
||||||
editor.pointerDown(150, 150).pointerUp()
|
editor.pointerDown(150, 150).pointerUp()
|
||||||
expect(editor.getCurrentPageState().editingShapeId).toBe(null)
|
expect(editor.getCurrentPageState().editingShapeId).toBe(null)
|
||||||
expect(editor.root.path.get()).toEqual('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('does not allow pressing undo to end up in the editing state', () => {
|
it('does not allow pressing undo to end up in the editing state', () => {
|
||||||
|
@ -55,7 +55,7 @@ describe(SelectTool, () => {
|
||||||
|
|
||||||
editor.pointerDown(150, 150).pointerUp()
|
editor.pointerDown(150, 150).pointerUp()
|
||||||
expect(editor.getCurrentPageState().editingShapeId).toBe(null)
|
expect(editor.getCurrentPageState().editingShapeId).toBe(null)
|
||||||
expect(editor.root.path.get()).toEqual('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
|
|
||||||
editor.undo()
|
editor.undo()
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ describe('When brushing arrows', () => {
|
||||||
editor.setCurrentTool('select')
|
editor.setCurrentTool('select')
|
||||||
editor.pointerDown(0, 45)
|
editor.pointerDown(0, 45)
|
||||||
editor.pointerMove(100, 55)
|
editor.pointerMove(100, 55)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
expect(editor.getSelectedShapeIds()).toStrictEqual([ids.arrow1])
|
expect(editor.getSelectedShapeIds()).toStrictEqual([ids.arrow1])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ describe('When brushing arrows', () => {
|
||||||
editor.setCurrentTool('select')
|
editor.setCurrentTool('select')
|
||||||
editor.pointerDown(55, 45)
|
editor.pointerDown(55, 45)
|
||||||
editor.pointerMove(45, 55)
|
editor.pointerMove(45, 55)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
expect(editor.getSelectedShapeIds()).toStrictEqual([])
|
expect(editor.getSelectedShapeIds()).toStrictEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -663,7 +663,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(160, 160)
|
editor.pointerMove(160, 160)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([])
|
expect(editor.getSelectedShapeIds()).toEqual([])
|
||||||
})
|
})
|
||||||
|
@ -673,7 +673,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(30, 30)
|
editor.pointerMove(30, 30)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
||||||
})
|
})
|
||||||
|
@ -683,7 +683,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(30, 30)
|
editor.pointerMove(30, 30)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
||||||
})
|
})
|
||||||
|
@ -696,7 +696,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(99, 99)
|
editor.pointerMove(99, 99)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.box1, ids.box2])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1, ids.box2])
|
||||||
})
|
})
|
||||||
|
@ -709,7 +709,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(150, 150)
|
editor.pointerMove(150, 150)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.box1, ids.box2])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1, ids.box2])
|
||||||
})
|
})
|
||||||
|
@ -722,7 +722,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(150, 150)
|
editor.pointerMove(150, 150)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.frame1])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.frame1])
|
||||||
})
|
})
|
||||||
|
@ -732,7 +732,7 @@ describe('when a frame has multiple children', () => {
|
||||||
expect(editor.getHoveredShapeId()).toBe(null)
|
expect(editor.getHoveredShapeId()).toBe(null)
|
||||||
editor.pointerDown()
|
editor.pointerDown()
|
||||||
editor.pointerMove(150, 150)
|
editor.pointerMove(150, 150)
|
||||||
editor.expectPathToBe('root.select.brushing')
|
editor.expectToBeIn('select.brushing')
|
||||||
editor.pointerUp()
|
editor.pointerUp()
|
||||||
expect(editor.getSelectedShapeIds()).toEqual([ids.frame1])
|
expect(editor.getSelectedShapeIds()).toEqual([ids.frame1])
|
||||||
})
|
})
|
||||||
|
|
|
@ -122,12 +122,12 @@ describe('When interacting with a shape...', () => {
|
||||||
handle: 'bottom_right',
|
handle: 'bottom_right',
|
||||||
})
|
})
|
||||||
|
|
||||||
editor.expectPathToBe('root.select.pointing_resize_handle')
|
editor.expectToBeIn('select.pointing_resize_handle')
|
||||||
editor.pointerMove(200, 200)
|
editor.pointerMove(200, 200)
|
||||||
editor.expectPathToBe('root.select.resizing')
|
editor.expectToBeIn('select.resizing')
|
||||||
editor.pointerMove(200, 210)
|
editor.pointerMove(200, 210)
|
||||||
editor.pointerUp(200, 210)
|
editor.pointerUp(200, 210)
|
||||||
editor.expectPathToBe('root.select.idle')
|
editor.expectToBeIn('select.idle')
|
||||||
|
|
||||||
// Once on start (for frame only)
|
// Once on start (for frame only)
|
||||||
expect(fnStart).toHaveBeenCalledTimes(1)
|
expect(fnStart).toHaveBeenCalledTimes(1)
|
||||||
|
|
|
@ -280,15 +280,15 @@ describe('When cloning...', () => {
|
||||||
const count1 = editor.currentPageShapes.length
|
const count1 = editor.currentPageShapes.length
|
||||||
|
|
||||||
editor.pointerDown(50, 50, { shape: editor.getShape(groupId)!, target: 'shape' })
|
editor.pointerDown(50, 50, { shape: editor.getShape(groupId)!, target: 'shape' })
|
||||||
editor.expectPathToBe('root.select.pointing_shape')
|
editor.expectToBeIn('select.pointing_shape')
|
||||||
|
|
||||||
editor.pointerMove(199, 199)
|
editor.pointerMove(199, 199)
|
||||||
editor.expectPathToBe('root.select.translating')
|
editor.expectToBeIn('select.translating')
|
||||||
expect(editor.currentPageShapes.length).toBe(count1) // 2 new box and group
|
expect(editor.currentPageShapes.length).toBe(count1) // 2 new box and group
|
||||||
|
|
||||||
editor.keyDown('Alt')
|
editor.keyDown('Alt')
|
||||||
|
|
||||||
editor.expectPathToBe('root.select.translating')
|
editor.expectToBeIn('select.translating')
|
||||||
expect(editor.currentPageShapes.length).toBe(count1 + 3) // 2 new box and group
|
expect(editor.currentPageShapes.length).toBe(count1 + 3) // 2 new box and group
|
||||||
|
|
||||||
editor.keyUp('Alt')
|
editor.keyUp('Alt')
|
||||||
|
|
Loading…
Reference in a new issue