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
|
||||
e.stopPropagation()
|
||||
const isDoubleClick = inputs.isDoubleClick()
|
||||
const info = inputs.pointerUp(e, 'bounds')
|
||||
const info = inputs.pointerUp(e, id)
|
||||
|
||||
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
||||
e.currentTarget?.releasePointerCapture(e.pointerId)
|
||||
|
|
|
@ -6,9 +6,7 @@ export function create(data: Data, shapes: TLDrawShape[]): Command {
|
|||
id: 'toggle_shapes',
|
||||
before: {
|
||||
page: {
|
||||
shapes: Object.fromEntries(
|
||||
shapes.map((shape) => [shape.id, undefined])
|
||||
),
|
||||
shapes: Object.fromEntries(shapes.map((shape) => [shape.id, undefined])),
|
||||
},
|
||||
pageState: {
|
||||
selectedIds: [...data.pageState.selectedIds],
|
||||
|
|
|
@ -51,7 +51,6 @@ export function deleteShapes(data: Data, ids: string[]): Command {
|
|||
after: {
|
||||
page: {
|
||||
shapes: {
|
||||
...Object.fromEntries(ids.map((id) => [id, undefined])),
|
||||
...Object.fromEntries(
|
||||
shapesWithBindingsToUpdate.map((shape) => {
|
||||
for (const id in shape.handles) {
|
||||
|
@ -64,6 +63,7 @@ export function deleteShapes(data: Data, ids: string[]): Command {
|
|||
return [shape.id, shape]
|
||||
})
|
||||
),
|
||||
...Object.fromEntries(ids.map((id) => [id, undefined])),
|
||||
},
|
||||
bindings: Object.fromEntries(bindingIdsToDelete.map((id) => [id, undefined])),
|
||||
},
|
||||
|
|
|
@ -10,3 +10,4 @@ export * from './style'
|
|||
export * from './toggle'
|
||||
export * from './translate'
|
||||
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 rayDirection = Vec.uni(Vec.sub(rayPoint, rayOrigin))
|
||||
|
||||
const oppositeBinding = oppositeHandle.bindingId
|
||||
? data.page.bindings[oppositeHandle.bindingId]
|
||||
: undefined
|
||||
|
||||
// From all bindable shapes on the page...
|
||||
for (const id of this.bindableShapeIds) {
|
||||
if (id === initialShape.id) continue
|
||||
if (id === oppositeBinding?.toId) continue
|
||||
|
||||
const target = TLDR.getShape(data, id)
|
||||
|
||||
|
|
|
@ -345,29 +345,26 @@ export class TLDR {
|
|||
this.setSelectedIds(data, [])
|
||||
}
|
||||
|
||||
static mutateShapes(
|
||||
static mutateShapes<T extends TLDrawShape>(
|
||||
data: Data,
|
||||
ids: string[],
|
||||
fn: (shape: TLDrawShape, i: number) => Partial<TLDrawShape>
|
||||
fn: (shape: T, i: number) => Partial<T>
|
||||
): {
|
||||
before: Record<string, Partial<TLDrawShape>>
|
||||
after: Record<string, Partial<TLDrawShape>>
|
||||
before: Record<string, Partial<T>>
|
||||
after: Record<string, Partial<T>>
|
||||
data: Data
|
||||
} {
|
||||
const beforeShapes: Record<string, Partial<TLDrawShape>> = {}
|
||||
const afterShapes: Record<string, Partial<TLDrawShape>> = {}
|
||||
const beforeShapes: Record<string, Partial<T>> = {}
|
||||
const afterShapes: Record<string, Partial<T>> = {}
|
||||
|
||||
ids.forEach((id, i) => {
|
||||
const shape = data.page.shapes[id]
|
||||
const shape = this.getShape<T>(data, id)
|
||||
const change = fn(shape, i)
|
||||
beforeShapes[id] = Object.fromEntries(
|
||||
Object.keys(change).map((key) => [key, shape[key as keyof TLDrawShape]])
|
||||
) as Partial<TLDrawShape>
|
||||
Object.keys(change).map((key) => [key, shape[key as keyof T]])
|
||||
) as Partial<T>
|
||||
afterShapes[id] = change
|
||||
data.page.shapes[id] = this.getShapeUtils(shape).mutate(
|
||||
shape as TLDrawShape,
|
||||
change as Partial<TLDrawShape>
|
||||
)
|
||||
data.page.shapes[id] = this.getShapeUtils(shape).mutate(shape as T, change as Partial<T>)
|
||||
})
|
||||
|
||||
const dataWithChildrenChanges = ids.reduce<Data>((cData, id) => {
|
||||
|
|
|
@ -796,6 +796,16 @@ export class TLDrawState implements TLCallbacks {
|
|||
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[]) => {
|
||||
const data = this.store.getState()
|
||||
const idsToMutate = ids ? ids : data.pageState.selectedIds
|
||||
|
@ -1612,8 +1622,8 @@ export class TLDrawState implements TLCallbacks {
|
|||
this.setStatus('pointingHandle')
|
||||
}
|
||||
|
||||
onDoubleClickHandle: TLPointerEventHandler = () => {
|
||||
// TODO
|
||||
onDoubleClickHandle: TLPointerEventHandler = (info) => {
|
||||
this.toggleDecoration(info.target)
|
||||
}
|
||||
|
||||
onRightPointHandle: TLPointerEventHandler = () => {
|
||||
|
|
Loading…
Reference in a new issue