Adds handle toggling
This commit is contained in:
parent
283e678a4d
commit
1a31dd6697
10 changed files with 105 additions and 20 deletions
|
@ -23,7 +23,7 @@ export function useHandleEvents(id: string) {
|
||||||
if (e.button !== 0) return
|
if (e.button !== 0) return
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
const isDoubleClick = inputs.isDoubleClick()
|
const isDoubleClick = inputs.isDoubleClick()
|
||||||
const info = inputs.pointerUp(e, 'bounds')
|
const info = inputs.pointerUp(e, id)
|
||||||
|
|
||||||
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
||||||
e.currentTarget?.releasePointerCapture(e.pointerId)
|
e.currentTarget?.releasePointerCapture(e.pointerId)
|
||||||
|
|
|
@ -6,9 +6,7 @@ export function create(data: Data, shapes: TLDrawShape[]): Command {
|
||||||
id: 'toggle_shapes',
|
id: 'toggle_shapes',
|
||||||
before: {
|
before: {
|
||||||
page: {
|
page: {
|
||||||
shapes: Object.fromEntries(
|
shapes: Object.fromEntries(shapes.map((shape) => [shape.id, undefined])),
|
||||||
shapes.map((shape) => [shape.id, undefined])
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
pageState: {
|
pageState: {
|
||||||
selectedIds: [...data.pageState.selectedIds],
|
selectedIds: [...data.pageState.selectedIds],
|
||||||
|
|
|
@ -51,7 +51,6 @@ export function deleteShapes(data: Data, ids: string[]): Command {
|
||||||
after: {
|
after: {
|
||||||
page: {
|
page: {
|
||||||
shapes: {
|
shapes: {
|
||||||
...Object.fromEntries(ids.map((id) => [id, undefined])),
|
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
shapesWithBindingsToUpdate.map((shape) => {
|
shapesWithBindingsToUpdate.map((shape) => {
|
||||||
for (const id in shape.handles) {
|
for (const id in shape.handles) {
|
||||||
|
@ -64,6 +63,7 @@ export function deleteShapes(data: Data, ids: string[]): Command {
|
||||||
return [shape.id, shape]
|
return [shape.id, shape]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
...Object.fromEntries(ids.map((id) => [id, undefined])),
|
||||||
},
|
},
|
||||||
bindings: Object.fromEntries(bindingIdsToDelete.map((id) => [id, undefined])),
|
bindings: Object.fromEntries(bindingIdsToDelete.map((id) => [id, undefined])),
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,3 +10,4 @@ export * from './style'
|
||||||
export * from './toggle'
|
export * from './toggle'
|
||||||
export * from './translate'
|
export * from './translate'
|
||||||
export * from './flip'
|
export * from './flip'
|
||||||
|
export * from './toggle-decoration'
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './toggle-decoration.command'
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { TLDR } from '../../tldr'
|
||||||
|
import { TLDrawState } from '../../tlstate'
|
||||||
|
import { mockDocument } from '../../test-helpers'
|
||||||
|
import { ArrowShape, Decoration, TLDrawShape } from '../../../shape'
|
||||||
|
|
||||||
|
describe('Handle command', () => {
|
||||||
|
const tlstate = new TLDrawState()
|
||||||
|
|
||||||
|
it('does, undoes and redoes command', () => {
|
||||||
|
tlstate
|
||||||
|
.loadDocument(mockDocument)
|
||||||
|
.create(
|
||||||
|
TLDR.getShapeUtils({ type: 'arrow' } as TLDrawShape).create({
|
||||||
|
id: 'arrow1',
|
||||||
|
parentId: 'page1',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.select('arrow1')
|
||||||
|
|
||||||
|
expect(tlstate.getShape<ArrowShape>('arrow1').decorations?.end).toBe(Decoration.Arrow)
|
||||||
|
|
||||||
|
tlstate.toggleDecoration('end')
|
||||||
|
|
||||||
|
expect(tlstate.getShape<ArrowShape>('arrow1').decorations?.end).toBe(undefined)
|
||||||
|
|
||||||
|
tlstate.undo()
|
||||||
|
|
||||||
|
expect(tlstate.getShape<ArrowShape>('arrow1').decorations?.end).toBe(Decoration.Arrow)
|
||||||
|
|
||||||
|
tlstate.redo()
|
||||||
|
|
||||||
|
expect(tlstate.getShape<ArrowShape>('arrow1').decorations?.end).toBe(undefined)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { Decoration } from '../../../shape'
|
||||||
|
import type { ArrowShape } from '../../../shape'
|
||||||
|
import type { Command, Data } from '../../state-types'
|
||||||
|
import { TLDR } from '../../tldr'
|
||||||
|
|
||||||
|
export function toggleDecoration(data: Data, ids: string[], handleId: 'start' | 'end'): Command {
|
||||||
|
const { before, after } = TLDR.mutateShapes<ArrowShape>(data, ids, (shape) => {
|
||||||
|
const decorations = shape.decorations
|
||||||
|
? {
|
||||||
|
...shape.decorations,
|
||||||
|
[handleId]: shape.decorations[handleId] ? undefined : Decoration.Arrow,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
[handleId]: Decoration.Arrow,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
decorations,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: 'toggle_decorations',
|
||||||
|
before: {
|
||||||
|
page: {
|
||||||
|
shapes: {
|
||||||
|
...before,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
after: {
|
||||||
|
page: {
|
||||||
|
shapes: {
|
||||||
|
...after,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,9 +85,14 @@ export class ArrowSession implements Session {
|
||||||
const rayPoint = Vec.add(nextPoint, shape.point)
|
const rayPoint = Vec.add(nextPoint, shape.point)
|
||||||
const rayDirection = Vec.uni(Vec.sub(rayPoint, rayOrigin))
|
const rayDirection = Vec.uni(Vec.sub(rayPoint, rayOrigin))
|
||||||
|
|
||||||
|
const oppositeBinding = oppositeHandle.bindingId
|
||||||
|
? data.page.bindings[oppositeHandle.bindingId]
|
||||||
|
: undefined
|
||||||
|
|
||||||
// From all bindable shapes on the page...
|
// From all bindable shapes on the page...
|
||||||
for (const id of this.bindableShapeIds) {
|
for (const id of this.bindableShapeIds) {
|
||||||
if (id === initialShape.id) continue
|
if (id === initialShape.id) continue
|
||||||
|
if (id === oppositeBinding?.toId) continue
|
||||||
|
|
||||||
const target = TLDR.getShape(data, id)
|
const target = TLDR.getShape(data, id)
|
||||||
|
|
||||||
|
|
|
@ -345,29 +345,26 @@ export class TLDR {
|
||||||
this.setSelectedIds(data, [])
|
this.setSelectedIds(data, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
static mutateShapes(
|
static mutateShapes<T extends TLDrawShape>(
|
||||||
data: Data,
|
data: Data,
|
||||||
ids: string[],
|
ids: string[],
|
||||||
fn: (shape: TLDrawShape, i: number) => Partial<TLDrawShape>
|
fn: (shape: T, i: number) => Partial<T>
|
||||||
): {
|
): {
|
||||||
before: Record<string, Partial<TLDrawShape>>
|
before: Record<string, Partial<T>>
|
||||||
after: Record<string, Partial<TLDrawShape>>
|
after: Record<string, Partial<T>>
|
||||||
data: Data
|
data: Data
|
||||||
} {
|
} {
|
||||||
const beforeShapes: Record<string, Partial<TLDrawShape>> = {}
|
const beforeShapes: Record<string, Partial<T>> = {}
|
||||||
const afterShapes: Record<string, Partial<TLDrawShape>> = {}
|
const afterShapes: Record<string, Partial<T>> = {}
|
||||||
|
|
||||||
ids.forEach((id, i) => {
|
ids.forEach((id, i) => {
|
||||||
const shape = data.page.shapes[id]
|
const shape = this.getShape<T>(data, id)
|
||||||
const change = fn(shape, i)
|
const change = fn(shape, i)
|
||||||
beforeShapes[id] = Object.fromEntries(
|
beforeShapes[id] = Object.fromEntries(
|
||||||
Object.keys(change).map((key) => [key, shape[key as keyof TLDrawShape]])
|
Object.keys(change).map((key) => [key, shape[key as keyof T]])
|
||||||
) as Partial<TLDrawShape>
|
) as Partial<T>
|
||||||
afterShapes[id] = change
|
afterShapes[id] = change
|
||||||
data.page.shapes[id] = this.getShapeUtils(shape).mutate(
|
data.page.shapes[id] = this.getShapeUtils(shape).mutate(shape as T, change as Partial<T>)
|
||||||
shape as TLDrawShape,
|
|
||||||
change as Partial<TLDrawShape>
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const dataWithChildrenChanges = ids.reduce<Data>((cData, id) => {
|
const dataWithChildrenChanges = ids.reduce<Data>((cData, id) => {
|
||||||
|
|
|
@ -796,6 +796,16 @@ export class TLDrawState implements TLCallbacks {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleDecoration = (handleId: string, ids?: string[]) => {
|
||||||
|
if (handleId === 'start' || handleId === 'end') {
|
||||||
|
const data = this.store.getState()
|
||||||
|
const idsToMutate = ids ? ids : data.pageState.selectedIds
|
||||||
|
this.do(commands.toggleDecoration(data, idsToMutate, handleId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
rotate = (delta = Math.PI * -0.5, ids?: string[]) => {
|
rotate = (delta = Math.PI * -0.5, ids?: string[]) => {
|
||||||
const data = this.store.getState()
|
const data = this.store.getState()
|
||||||
const idsToMutate = ids ? ids : data.pageState.selectedIds
|
const idsToMutate = ids ? ids : data.pageState.selectedIds
|
||||||
|
@ -1612,8 +1622,8 @@ export class TLDrawState implements TLCallbacks {
|
||||||
this.setStatus('pointingHandle')
|
this.setStatus('pointingHandle')
|
||||||
}
|
}
|
||||||
|
|
||||||
onDoubleClickHandle: TLPointerEventHandler = () => {
|
onDoubleClickHandle: TLPointerEventHandler = (info) => {
|
||||||
// TODO
|
this.toggleDecoration(info.target)
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightPointHandle: TLPointerEventHandler = () => {
|
onRightPointHandle: TLPointerEventHandler = () => {
|
||||||
|
|
Loading…
Reference in a new issue