diff --git a/src/main.ts b/src/main.ts index 89200d4..766b8d4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -213,21 +213,37 @@ export default function () { }) // Эмуляция докинга: растянуть окно на зону и прижать к её краю (9 позиций). + // Двухэтапно, чтобы позиция считалась от РЕАЛЬНОГО размера, который Figma + // фактически отрисовала (она клампит resize до своего лимита при видимом UI). + // 1) DOCK_WINDOW: resize(канон) — попытка растяжения + запоминаем режим. reposition НЕ делаем. + // 2) UI через 2 кадра шлёт DOCK_REFINE с реальным размером (window.innerWidth/Height + // после клампа Figma) -> applyDock(..., false) только reposition от реального размера. + // Без этого этапа окно позиционировалось бы от запрошенного канона (906) и прижималось + // к левому/верхнему краю вместо центра (баг relX=0 на top-center). on('DOCK_WINDOW', function (payload: { position: DockPosition; width: number; height: number }) { - const { position, width, height } = payload + const { position } = payload // Центр — это one-shot: применяем 50% по центру ОДИН раз, НЕ включаем поллинг // (окно не "приклеено"), но включаем centerLocked — ручной ресайз держит центр. if (position === 'center') { dockedPosition = null centerLocked = true - applyDock('center', width, height, true) - return + } else { + // Остальные позиции — удерживаем прижатым (поллинг пересчитывает при зуме/пане). + centerLocked = false + dockedPosition = position + lastBoundsKey = '' // форсируем пересчёт на ближайшем тике } - // Остальные позиции — удерживаем прижатым (поллинг пересчитывает при зуме/пане). - centerLocked = false - dockedPosition = position - lastBoundsKey = '' // форсируем пересчёт на ближайшем тике - applyDock(position, width, height, true) + // Попытка растяжения до канона (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 пришлёт реальный размер после клампа). + }) + + // Точная прижимка от РЕАЛЬНОГО размера окна (после клампа Figma). + on('DOCK_REFINE', function (payload: { position: DockPosition; width: number; height: number }) { + const { position, width, height } = payload + applyDock(position, width, height, false) }) // Останавливаем поллинг при закрытии плагина, чтобы не висел в памяти. diff --git a/src/ui.tsx b/src/ui.tsx index c091ad7..466f70a 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -243,12 +243,26 @@ function Plugin () { | 'bottom-left' | 'bottom-center' | 'bottom-right' function dockWindow (position: DockPosition) { + // Этап 1: просим main растянуть (попытка до канона) и запомнить режим. + // main НЕ позиционирует сразу — позиция считается на этапе 2 от РЕАЛЬНОГО + // размера, который Figma отрисует после клампа (видимый UI режет запрос). emit('DOCK_WINDOW', { position, - width: currentWindowSize.width, - height: currentWindowSize.height + width: window.innerWidth, + height: window.innerHeight + }) + // Этап 2: через 2 кадра Figma уже применила resize и кламп — читаем реальный + // размер из iframe и шлём на точную прижимку (reposition от реального размера). + requestAnimationFrame(function () { + requestAnimationFrame(function () { + emit('DOCK_REFINE', { + position, + width: window.innerWidth, + height: window.innerHeight + }) + refreshInfo() + }) }) - refreshInfo() } const max = windowInfo != null ? windowInfo.maxViewport : null