From ab6a2e879f1f15e7841ed1f44fcf7fdfd7bc7ffd Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 9 Sep 2026 19:10:48 +0200 Subject: [PATCH] feat: edge fix-size editable via manual resize; center one-shot; corners keep size --- src/main.ts | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main.ts b/src/main.ts index ebec673..afd48ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,12 +26,13 @@ export default function () { const PLUGIN_HEADER_PX = 38 // Вычислить целевое состояние окна для позиции докинга: - // - Лево/Право: ширина 320px, высота = макс (весь viewport по вертикали минус шапка) - // - Верх/Низ: высота 320px, ширина = макс (весь viewport по горизонтали) - // - Углы: НЕ меняют размер, только прижимают к соответствующему углу viewport - // - Центр: размер = 50% viewport (по ширине и высоте), центрируется + // - Лево/Право: ширина = dockEdgeSize (редактируемая, по умолч. 320), высота = макс (весь viewport по вертикали минус шапка) + // - Верх/Низ: высота = dockEdgeSize, ширина = макс (весь viewport по горизонтали) + // - Углы: размер НЕ фиксируется (редактируется вручную), только прижимают к углу (с клампом в пределах viewport) + // - Центр: размер = 50% viewport (по ширине и высоте), центрируется (one-shot, не удерживает) // Возвращает размер (экранные px) и позицию (canvas-space, прижатую к нужному краю). - const DOCK_EDGE_SIZE = 320 + const DEFAULT_DOCK_EDGE = 320 + let dockEdgeSize = DEFAULT_DOCK_EDGE // редактируемая фикс-сторона для edge-позиций (320 по умолч.) function computeDock (position: DockPosition, currentWidth: number, currentHeight: number) { const b = figma.viewport.bounds const zoom = figma.viewport.zoom || 1 @@ -39,22 +40,25 @@ export default function () { const maxH = Math.round(b.height * zoom) - PLUGIN_HEADER_PX const isLeftRight = position === 'center-left' || position === 'center-right' const isTopBottom = position === 'top-center' || position === 'bottom-center' + const isCorner = position === 'top-left' || position === 'top-right' || position === 'bottom-left' || position === 'bottom-right' const isCenter = position === 'center' let targetW = currentWidth let targetH = currentHeight if (isLeftRight) { - targetW = DOCK_EDGE_SIZE + targetW = dockEdgeSize targetH = maxH } else if (isTopBottom) { targetW = maxW - targetH = DOCK_EDGE_SIZE + targetH = dockEdgeSize } else if (isCenter) { targetW = Math.round(maxW / 2) targetH = Math.round(maxH / 2) + } else if (isCorner) { + // размер редактируется вручную, только клампим в пределы viewport + targetW = Math.min(currentWidth, maxW) + targetH = Math.min(currentHeight, maxH) } - // Углы (top-left/right, bottom-left/right): размер НЕ меняем (targetW/targetH = current), - // только позиция прижимается к соответствующему углу viewport. // canvas-units от целевого размера const wCanvas = targetW / zoom const hCanvas = (PLUGIN_HEADER_PX + targetH) / zoom @@ -117,18 +121,32 @@ export default function () { const { width, height } = clampWindowSize(windowSize) lastSize = { width, height } figma.ui.resize(width, height) - // Если окно задокено — держим прижатым к краю при смене размера + // Если окно задокено — держим прижатым к краю при смене размера. + // При этом фикс-сторона edge-позиции (dockEdgeSize) ОБНОВЛЯЕТСЯ из ручного + // ресайза, чтобы пользователь мог менять её (а не была заблокирована на 320). if (dockedPosition !== null) { + const isLeftRight = dockedPosition === 'center-left' || dockedPosition === 'center-right' + const isTopBottom = dockedPosition === 'top-center' || dockedPosition === 'bottom-center' + if (isLeftRight) dockEdgeSize = width + else if (isTopBottom) dockEdgeSize = height applyDock(dockedPosition, width, height) } }) // Эмуляция докинга: растянуть окно на зону и прижать к её краю (9 позиций). on('DOCK_WINDOW', function (payload: { position: DockPosition; width: number; height: number }) { - const { position } = payload + const { position, width, height } = payload + // Центр — это one-shot: применяем 50% по центру ОДИН раз, НЕ включаем поллинг + // (окно не "приклеено", ручной ресайз/драг работают свободно после). + if (position === 'center') { + dockedPosition = null + applyDock('center', width, height) + return + } + // Остальные позиции — удерживаем прижатым (поллинг пересчитывает при зуме/пане). dockedPosition = position lastBoundsKey = '' // форсируем пересчёт на ближайшем тике - applyDock(position, payload.width, payload.height) + applyDock(position, width, height) }) // Останавливаем поллинг при закрытии плагина, чтобы не висел в памяти.