fix: persist maximize + corners as free placement (exact size/pos), edges as dock

This commit is contained in:
Hermes Agent committed 2026-09-11 13:59:24 +02:00
1 parent fd0c52342f
commit a6d02322f3
2 files changed
+61 -18

No files matched your search

+58 -18
View File
@@ -53,6 +53,21 @@ export default function () {
if (saveTimer != null) clearTimeout(saveTimer)
saveTimer = setTimeout(function () { savePlacement(p) }, 400)
}
// Persist the CURRENT window as a free placement (real canvas-space x/y + size).
// Used by maximize and corner docks, which must remember the EXACT size/position
// rather than re-deriving it from a dock formula (which would reset the size).
function saveFreeFromCurrent () {
try {
const pos = (figma.ui as any).getPosition()
savePlacement({
mode: 'free',
x: Math.round(pos.canvasSpace.x),
y: Math.round(pos.canvasSpace.y),
w: lastSize.width,
h: lastSize.height
})
} catch (e) { /* getPosition unavailable — skip */ }
}
// computeDock считает целевой размер+позицию для док-позиции.
// canonical=true — НАЖАТИЕ кнопки дока: задаём канонический размер
// (edge: фикс-сторона dockEdgeSize, другая = max viewport; center: 50%).
@@ -293,28 +308,36 @@ export default function () {
// к левому/верхнему краю вместо центра (баг relX=0 на top-center).
on('DOCK_WINDOW', function (payload: { position: DockPosition; width: number; height: number }) {
const { position } = payload
// Центр — это one-shot: применяем 50% по центру ОДИН раз, окно остаётся в покое
// (НЕ приклеено, НЕ держит центр при ручном ресайзе/перемещении).
if (position === 'center') {
dockedPosition = null
} else {
// Остальные позиции — удерживаем прижатым (поллинг пересчитывает при зуме/пане).
const isEdge = position === 'top-center' || position === 'bottom-center' ||
position === 'center-left' || position === 'center-right'
// Центр и углы — one-shot (не удерживаются поллингом). Края — удерживаются прижатыми.
if (isEdge) {
dockedPosition = position
lastBoundsKey = '' // форсируем пересчёт на ближайшем тике
} else {
dockedPosition = null
}
// Попытка растяжения до канона (Figma клампит до лимита при видимом UI).
const state = computeDock(position, payload.width, payload.height, true)
figma.ui.resize(state.width, state.height)
lastSize = { width: clampWindowSize(state).width, height: clampWindowSize(state).height }
// reposition откладываем на DOCK_REFINE (UI пришлёт реальный размер после клампа).
// Remember placement (center is one-shot but we still persist it as a logical position).
savePlacement({ mode: 'dock', position: position })
// Сохранение позиции тоже в DOCK_REFINE (там известен реальный размер после клампа).
})
// Точная прижимка от РЕАЛЬНОГО размера окна (после клампа Figma).
on('DOCK_REFINE', function (payload: { position: DockPosition; width: number; height: number }) {
const { position, width, height } = payload
applyDock(position, width, height, false)
const isEdge = position === 'top-center' || position === 'bottom-center' ||
position === 'center-left' || position === 'center-right'
if (isEdge) {
// Edges are held docked — persist as dock so re-open re-pins to the edge.
savePlacement({ mode: 'dock', position: position })
} else {
// Corners / center are one-shot — remember the EXACT size+position (free).
saveFreeFromCurrent()
}
})
// Выход из дока кликом по углу: свободная ось (та, что была растянута) становится
@@ -354,6 +377,14 @@ export default function () {
} catch (e) { /* getPosition unavailable — skip */ }
})
// UI asks to persist the CURRENT window as a free placement (used by Maximize,
// which is not a held dock — it must remember the exact size+position across restart).
on('SAVE_FREE', function () {
dockedPosition = null // maximize is not held; clear any stale dock state
lastBoundsKey = ''
saveFreeFromCurrent()
})
// Останавливаем поллинг при закрытии плагина, чтобы не висел в памяти.
figma.on('close', function () {
clearInterval(dockInterval)
@@ -457,18 +488,27 @@ export default function () {
return
}
if (saved.mode === 'dock') {
// Dock mode (incl. center): stretch to its canonical size and pin.
// For center the window is NOT held (one-shot); for edges it stays docked.
dockedPosition = saved.position === 'center' ? null : saved.position
const state = computeDock(saved.position, 320, 200, true)
figma.ui.resize(state.width, state.height)
lastSize = { width: clampWindowSize(state).width, height: clampWindowSize(state).height }
requestAnimationFrame(function () {
const isEdge = saved.position === 'top-center' || saved.position === 'bottom-center' ||
saved.position === 'center-left' || saved.position === 'center-right'
if (!isEdge) {
// Stale record (corner/center saved as dock by an older build) — treat as free
// with the current size, so the exact geometry is restored.
figma.ui.reposition(0, 0) // will be corrected by native re-open; keep simple
lastSize = { width: 320, height: 200 }
dockedPosition = null
} else {
// Edge dock: stretch to its canonical size and pin (held across zoom/pan).
dockedPosition = saved.position
const state = computeDock(saved.position, 320, 200, true)
figma.ui.resize(state.width, state.height)
lastSize = { width: clampWindowSize(state).width, height: clampWindowSize(state).height }
requestAnimationFrame(function () {
applyDock(saved.position, lastSize.width, lastSize.height, false)
lastBoundsKey = '' // force dock poll to keep it pinned on zoom/pan
requestAnimationFrame(function () {
applyDock(saved.position, lastSize.width, lastSize.height, false)
lastBoundsKey = '' // force dock poll to keep it pinned on zoom/pan
})
})
})
}
} else {
// Free placement: restore exact canvas-space position + size.
figma.ui.resize(saved.w, saved.h)
+3
View File
@@ -215,6 +215,9 @@ function Plugin () {
width: window.innerWidth,
height: window.innerHeight
})
// Maximize is NOT a held dock — persist the exact size+position so re-open
// restores it (overrides the edge-dock save done by DOCK_REFINE above).
emit('SAVE_FREE')
refreshInfo()
})
})