fix(editor): hide noop auto-layout drag indicators

This commit is contained in:
Danila Poyarkov 2026-05-13 04:52:40 +03:00
parent 419c77d8de
commit fb01bcb433
2 changed files with 102 additions and 6 deletions

View file

@ -64,12 +64,17 @@ export function computeIndicatorPosition(
return (prevAbs.y + prev.height + nextAbs.y) / 2
}
export function filteredToRealIndex(parentId: string, insertIndex: number, editor: Editor): number {
export function filteredToRealIndex(
parentId: string,
insertIndex: number,
editor: Editor,
movingIds = editor.state.selectedIds
): number {
const allChildren = editor.graph.getChildren(parentId)
let realIndex = 0
let filteredCount = 0
for (const child of allChildren) {
if (editor.state.selectedIds.has(child.id)) continue
if (movingIds.has(child.id)) continue
if (child.layoutPositioning === 'ABSOLUTE') {
realIndex++
continue
@ -85,11 +90,12 @@ export function computeAutoLayoutIndicatorForFrame(
parent: SceneNode,
cx: number,
cy: number,
editor: Editor
editor: Editor,
movingIds = editor.state.selectedIds
) {
const children = editor.graph
.getChildren(parent.id)
.filter((c) => c.layoutPositioning !== 'ABSOLUTE' && !editor.state.selectedIds.has(c.id))
.filter((c) => c.layoutPositioning !== 'ABSOLUTE' && !movingIds.has(c.id))
const parentAbs = editor.graph.getAbsolutePosition(parent.id)
const isRow = parent.layoutMode === 'HORIZONTAL'
@ -107,6 +113,17 @@ export function computeAutoLayoutIndicatorForFrame(
}
}
const realIndex = filteredToRealIndex(parent.id, insertIndex, editor, movingIds)
if (movingIds.size === 1) {
const movingId = [...movingIds][0]
const movingNode = editor.graph.getNode(movingId)
const currentIndex = parent.childIds.indexOf(movingId)
if (movingNode?.parentId === parent.id && realIndex === currentIndex) {
editor.setLayoutInsertIndicator(null)
return
}
}
const indicatorPos = computeIndicatorPosition(
children,
insertIndex,
@ -122,7 +139,7 @@ export function computeAutoLayoutIndicatorForFrame(
editor.setLayoutInsertIndicator({
parentId: parent.id,
index: filteredToRealIndex(parent.id, insertIndex, editor),
index: realIndex,
x: isRow ? indicatorPos : crossStart,
y: isRow ? crossStart : indicatorPos,
length: crossLength,
@ -134,5 +151,5 @@ export function computeAutoLayoutIndicator(d: DragMove, cx: number, cy: number,
if (!d.autoLayoutParentId) return
const parent = editor.graph.getNode(d.autoLayoutParentId)
if (!parent || parent.layoutMode === 'NONE') return
computeAutoLayoutIndicatorForFrame(parent, cx, cy, editor)
computeAutoLayoutIndicatorForFrame(parent, cx, cy, editor, new Set(d.originals.keys()))
}

View file

@ -82,3 +82,82 @@ test('dragging selected nested instance content reorders its auto-layout item',
expect(childIds).toEqual([ids.second, ids.first])
canvas.assertNoErrors()
})
test('auto-layout drag does not show an insert indicator before order changes', async ({ page }) => {
await page.goto('/')
const canvas = new CanvasHelper(page)
await canvas.waitForInit()
canvas.errors.length = 0
await canvas.clearCanvas()
const ids = await page.evaluate(() => {
const store = window.openPencil?.getStore?.()
if (!store) throw new Error('OpenPencil store not initialized')
const pageId = store.state.currentPageId
const frame = store.graph.createNode('FRAME', pageId, {
name: 'Auto Row',
x: 100,
y: 100,
width: 360,
height: 80,
layoutMode: 'HORIZONTAL',
itemSpacing: 20,
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
paddingLeft: 10
})
const first = store.graph.createNode('INSTANCE', frame.id, {
name: 'First item',
x: 110,
y: 110,
width: 120,
height: 60
})
const second = store.graph.createNode('INSTANCE', frame.id, {
name: 'Second item',
x: 250,
y: 110,
width: 120,
height: 60
})
const secondText = store.graph.createNode('TEXT', second.id, {
name: 'Second label',
text: 'Second',
x: 8,
y: 8,
width: 80,
height: 24
})
store.select([secondText.id])
store.requestRender()
return { frame: frame.id, first: first.id, second: second.id }
})
await canvas.waitForRender()
const box = await canvas.canvas.boundingBox()
if (!box) throw new Error('Canvas has no bounding box')
await page.mouse.move(box.x + 370, box.y + 228)
await page.mouse.down()
await page.mouse.move(box.x + 365, box.y + 228, { steps: 3 })
await canvas.waitForRender()
const indicator = await page.evaluate(() => {
const store = window.openPencil?.getStore?.()
if (!store) throw new Error('OpenPencil store not initialized')
return store.state.layoutInsertIndicator
})
await page.mouse.up()
expect(indicator).toBeNull()
const childIds = await page.evaluate((frameId) => {
const store = window.openPencil?.getStore?.()
if (!store) throw new Error('OpenPencil store not initialized')
return store.graph.getNode(frameId)?.childIds ?? []
}, ids.frame)
expect(childIds).toEqual([ids.first, ids.second])
canvas.assertNoErrors()
})