diff --git a/src/main.ts b/src/main.ts index 36bb9f8..1de7e9d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,9 +51,24 @@ export default function () { } }, 250) + // Кламп размера окна: не меньше минимума и не больше видимого viewport. + // Видимый viewport в ЭКРАННЫХ пикселях = bounds * zoom (bounds — в canvas-space, + // zoom переводит в px). useWindowResize при drag даёт большие значения — main + // приводит к допустимому, чтобы окно не вылезало за canvas и не ломало Figma. + function clampWindowSize (size: { width: number; height: number }) { + const b = figma.viewport.bounds + const zoom = figma.viewport.zoom || 1 + const maxW = Math.max(320, Math.round(b.width * zoom)) + const maxH = Math.max(200, Math.round(b.height * zoom)) + return { + width: Math.max(320, Math.min(maxW, Math.round(size.width))), + height: Math.max(200, Math.min(maxH, Math.round(size.height))) + } + } + // Ресайз окна плагина (drag за угол в UI -> useWindowResize -> RESIZE_WINDOW) on('RESIZE_WINDOW', function (windowSize: { width: number; height: number }) { - const { width, height } = windowSize + const { width, height } = clampWindowSize(windowSize) lastSize = { width, height } figma.ui.resize(width, height) // Если окно задокено — держим прижатым к краю при смене размера @@ -64,7 +79,8 @@ export default function () { // Эмуляция докинга: прижать окно к краям canvas (left/right/center). on('DOCK_WINDOW', function (payload: { position: 'left' | 'right' | 'center'; width: number; height: number }) { - const { position, width, height } = payload + const { position } = payload + const { width, height } = clampWindowSize(payload) lastSize = { width, height } figma.ui.resize(width, height) dockedPosition = position @@ -109,6 +125,13 @@ export default function () { const cx = Math.round(x + wCanvas / 2) const cy = Math.round(y + hCanvas / 2) + // Максимальный размер окна (экранные px) = весь видимый viewport (bounds * zoom). + // Используется кнопкой "развернуть" в UI и как верхняя граница drag-ресайза. + const maxViewport = { + width: Math.max(320, Math.round(b.width * zoom)), + height: Math.max(200, Math.round(b.height * zoom)) + } + emit('WINDOW_INFO', { x, y, @@ -121,6 +144,7 @@ export default function () { width: Math.round(b.width), height: Math.round(b.height) }, + maxViewport, gapL, gapR, gapT, diff --git a/src/ui.tsx b/src/ui.tsx index 40ba797..ccc630e 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -17,7 +17,9 @@ import { h, Fragment } from 'preact' import { useState, useEffect } from 'preact/hooks' const MIN_WINDOW_SIZE = { width: 320, height: 200 } -const MAX_WINDOW_SIZE = { width: 800, height: 800 } +// Статичного максимума нет: "развернуть" целится в весь viewport (maxViewport из main), +// а верхняя граница drag-ресайза тоже приходит оттуда. useWindowResize ставим очень +// большой max — реальный кламп делает main через clampWindowSize (bounds*zoom). // Одна строка отладочного вывода: имя переменной из кода (как в main.ts), // опционально — формула расчёта, и само значение (моноширинное, по правому краю). @@ -49,6 +51,7 @@ function Plugin () { x: number; y: number; width: number; height: number zoom: number viewport: { x: number; y: number; width: number; height: number } + maxViewport: { width: number; height: number } gapL: number; gapR: number; gapT: number; gapB: number center: { x: number; y: number } } | null>(null) @@ -65,8 +68,10 @@ function Plugin () { }, { minWidth: 320, minHeight: 200, - maxWidth: 800, - maxHeight: 800 + // Верхний предел оставляем большим — реальный кламп (весь viewport) делает main + // через clampWindowSize (bounds * zoom), иначе на маленьком viewport окно не растянуть. + maxWidth: 100000, + maxHeight: 100000 }) // Слушаем ответ от main с актуальными x/y (canvas-space) и размерами окна @@ -75,6 +80,7 @@ function Plugin () { x: number; y: number; width: number; height: number zoom: number viewport: { x: number; y: number; width: number; height: number } + maxViewport: { width: number; height: number } gapL: number; gapR: number; gapT: number; gapB: number center: { x: number; y: number } }) { @@ -177,10 +183,12 @@ function Plugin () { }, []) function toggleWindowSize () { + const max = windowInfo != null + ? windowInfo.maxViewport + : { width: 800, height: 800 } const isMaximized = - currentWindowSize.width >= MAX_WINDOW_SIZE.width && - currentWindowSize.height >= MAX_WINDOW_SIZE.height - const next = isMaximized ? { ...MIN_WINDOW_SIZE } : { ...MAX_WINDOW_SIZE } + currentWindowSize.width >= max.width && currentWindowSize.height >= max.height + const next = isMaximized ? { ...MIN_WINDOW_SIZE } : { ...max } setCurrentWindowSize(next) emit('RESIZE_WINDOW', next) refreshInfo() @@ -195,9 +203,9 @@ function Plugin () { refreshInfo() } + const max = windowInfo != null ? windowInfo.maxViewport : { width: 800, height: 800 } const isMaximized = - currentWindowSize.width >= MAX_WINDOW_SIZE.width && - currentWindowSize.height >= MAX_WINDOW_SIZE.height + currentWindowSize.width >= max.width && currentWindowSize.height >= max.height return ( @@ -246,6 +254,7 @@ function Plugin () { + {/* Расчётные — посчитаны в main.ts из вышеперечисленных raw-значений */}