- Preserve parent-local movement during Control bypass - Route native snapping menu actions through persisted preferences - Harden guide alignment, lifecycle rendering, and transformed resize behavior - Update preference descriptions and fractional position display
109 lines
3.8 KiB
TypeScript
109 lines
3.8 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
|
|
import { createEditor } from '@open-pencil/core/editor'
|
|
|
|
import { applyResize, commitResizePreview } from '#vue/shared/input/resize'
|
|
import type { DragResize } from '#vue/shared/input/types'
|
|
|
|
function setup(handle: DragResize['handle'] = 'se') {
|
|
const editor = createEditor()
|
|
const pageId = editor.state.currentPageId
|
|
const node = editor.graph.createNode('RECTANGLE', pageId, {
|
|
x: 10.25,
|
|
y: 20.25,
|
|
width: 100,
|
|
height: 80
|
|
})
|
|
editor.select([node.id])
|
|
const drag: DragResize = {
|
|
type: 'resize',
|
|
handle,
|
|
startX: handle.includes('w') ? node.x : node.x + node.width,
|
|
startY: handle.includes('n') ? node.y : node.y + node.height,
|
|
origRect: { x: node.x, y: node.y, width: node.width, height: node.height },
|
|
nodeId: node.id,
|
|
origVectorNetwork: null,
|
|
origFillGeometry: [],
|
|
origStrokeGeometry: [],
|
|
origDerivedTextGlyphs: null,
|
|
origStrokes: [],
|
|
origTextPathData: null,
|
|
origTextPathBox: null,
|
|
origChildren: null
|
|
}
|
|
return { editor, nodeId: node.id, drag }
|
|
}
|
|
|
|
describe('resize snapping preferences', () => {
|
|
test('preserves fractional edges when pixel snapping is disabled', () => {
|
|
const { editor, nodeId, drag } = setup()
|
|
editor.state.snappingPreferences = { geometry: true, objects: false, pixelGrid: false }
|
|
|
|
applyResize(drag, drag.startX + 6.3, drag.startY + 7.4, false, editor)
|
|
commitResizePreview(drag, editor)
|
|
|
|
expect(editor.graph.getNode(nodeId)).toMatchObject({ width: 106.3, height: 87.4 })
|
|
})
|
|
|
|
test('snaps east and south edges to whole pixels', () => {
|
|
const { editor, nodeId, drag } = setup()
|
|
editor.state.snappingPreferences = { geometry: true, objects: false, pixelGrid: true }
|
|
|
|
applyResize(drag, drag.startX + 6.3, drag.startY + 7.4, false, editor)
|
|
commitResizePreview(drag, editor)
|
|
|
|
expect(editor.graph.getNode(nodeId)).toMatchObject({ width: 106.75, height: 87.75 })
|
|
})
|
|
|
|
test('snaps west edge while preserving the opposite edge', () => {
|
|
const { editor, nodeId, drag } = setup('w')
|
|
editor.state.snappingPreferences = { geometry: true, objects: false, pixelGrid: true }
|
|
|
|
applyResize(drag, drag.startX + 4.3, drag.startY, false, editor)
|
|
commitResizePreview(drag, editor)
|
|
|
|
const resized = editor.graph.getNode(nodeId)
|
|
expect(resized?.x).toBeCloseTo(15)
|
|
expect(resized?.width).toBeCloseTo(95.25)
|
|
})
|
|
|
|
test('Control bypass preserves fractional resize geometry', () => {
|
|
const { editor, nodeId, drag } = setup()
|
|
editor.state.snappingPreferences = { geometry: true, objects: true, pixelGrid: true }
|
|
|
|
applyResize(drag, drag.startX + 6.3, drag.startY + 7.4, false, editor, true)
|
|
commitResizePreview(drag, editor)
|
|
|
|
expect(editor.graph.getNode(nodeId)).toMatchObject({ width: 106.3, height: 87.4 })
|
|
expect(editor.state.snapGuides).toEqual([])
|
|
})
|
|
|
|
test('does not apply axis-aligned snapping to rotated resize geometry', () => {
|
|
const { editor, nodeId, drag } = setup('e')
|
|
editor.updateNode(nodeId, { rotation: 30 })
|
|
editor.graph.createNode('RECTANGLE', editor.state.currentPageId, {
|
|
x: 150,
|
|
y: 0,
|
|
width: 50,
|
|
height: 50
|
|
})
|
|
|
|
applyResize(drag, 148, drag.startY, false, editor)
|
|
commitResizePreview(drag, editor)
|
|
|
|
expect(editor.graph.getNode(nodeId)?.width).toBeCloseTo(137.75)
|
|
expect(editor.state.snapGuides).toEqual([])
|
|
})
|
|
|
|
test('object edges take priority over the pixel grid', () => {
|
|
const { editor, nodeId, drag } = setup('e')
|
|
const pageId = editor.state.currentPageId
|
|
editor.graph.createNode('RECTANGLE', pageId, { x: 150.4, y: 0, width: 50, height: 50 })
|
|
|
|
applyResize(drag, 148, drag.startY, false, editor)
|
|
commitResizePreview(drag, editor)
|
|
|
|
expect(editor.graph.getNode(nodeId)).toMatchObject({ width: 140.15 })
|
|
})
|
|
})
|