diff --git a/src/main.ts b/src/main.ts
index ca845df..5bbf155 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -20,16 +20,19 @@ export default function () {
| 'center-left' | 'center' | 'center-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right'
+ // Высота шапки окна плагина (title bar Figma с крестиком), экранные px.
+ // Окно плагина = шапка (PLUGIN_HEADER_PX) + iframe (height px). getPosition().y — это
+ // верх шапки, поэтому полная высота окна = (PLUGIN_HEADER_PX + height) / zoom.
+ const PLUGIN_HEADER_PX = 38
+
// Прижать окно к краю видимой области canvas (bounds) в canvas-space.
// ВАЖНО: reposition()/getPosition() и bounds — в canvas-space (единицы документа),
- // а figma.ui.resize(width,height) — в ЭКРАННЫХ пикселях. Размер окна в canvas-units =
- // width / zoom. Без этого деления при zoom≠100% окно прижимается с ошибкой
- // (px-размер вычитается из canvas-ширины → уезжает пропорционально 1/zoom).
+ // а figma.ui.resize(width,height) — в ЭКРАННЫХ пикселях. Размер окна в canvas-units =\n // width / zoom (по ширине) и (PLUGIN_HEADER_PX + height) / zoom (по высоте, т.к. окно\n // включает шапку). Без учёта шапки прижатый к низу/центру окно висит на 38px выше нужного.
function applyDock (position: DockPosition, width: number, height: number) {
const b = figma.viewport.bounds
const zoom = figma.viewport.zoom || 1
const wCanvas = width / zoom
- const hCanvas = height / zoom
+ const hCanvas = (PLUGIN_HEADER_PX + height) / zoom
let x = b.x
let y = b.y
// По горизонтали
@@ -38,7 +41,7 @@ export default function () {
} else if (position === 'top-right' || position === 'center-right' || position === 'bottom-right') {
x = b.x + b.width - wCanvas
}
- // По вертикали
+ // По вертикали (hCanvas учитывает шапку окна)
if (position === 'center-left' || position === 'center' || position === 'center-right') {
y = b.y + (b.height - hCanvas) / 2
} else if (position === 'bottom-left' || position === 'bottom-center' || position === 'bottom-right') {
@@ -132,16 +135,16 @@ export default function () {
// Размер окна в ЭКРАННЫХ пикселях (w/h) переводим в canvas-units через zoom,
// чтобы корректно вычитать из canvas-ширины bounds при любом зуме.
const wCanvas = w / zoom
- const hCanvas = h / zoom
-
// Геометрия окна плагина относительно видимой области canvas (bounds).
- // gapL/gapR/gapT/gapB — отступы окна от левого/правого/верхнего/нижнего края canvas.
+ // Полная высота окна = шапка (PLUGIN_HEADER_PX) + iframe (h), поэтому по вертикали
+ // считаем от (PLUGIN_HEADER_PX + h)/zoom, а не от h/zoom (иначе gapB/center.y неверны).
+ const fullHCanvas = (PLUGIN_HEADER_PX + h) / zoom
const gapL = Math.round(x - b.x)
const gapT = Math.round(y - b.y)
const gapR = Math.round(b.x + b.width - (x + wCanvas))
- const gapB = Math.round(b.y + b.height - (y + hCanvas))
+ const gapB = Math.round(b.y + b.height - (y + fullHCanvas))
const cx = Math.round(x + wCanvas / 2)
- const cy = Math.round(y + hCanvas / 2)
+ const cy = Math.round(y + fullHCanvas / 2)
// Нормализованная позиция окна относительно видимого viewport (левый верхний угол
// окна в координатах bounds). relX = x − bounds.x, relY = y − bounds.y. Это те же
diff --git a/src/ui.tsx b/src/ui.tsx
index dace9c2..5d07041 100644
--- a/src/ui.tsx
+++ b/src/ui.tsx
@@ -313,8 +313,8 @@ function Plugin () {
/>