/
guselnikov
/
inst
Обзор
Документация
Войти
/
guselnikov
/
inst
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
admin/src/components/post-editor/textLayout.ts
129 строк
4 KB
Viktor Guselnikov
new
26 июл 2026, 18:42
26 июл 2026, 18:42
322e1f1
Код
Авторство
О чём код?
import type { LayerTransform, PostDesignDocument, TextLayer, TextStyle } from './design-types'; import { layoutV1TextLines, measureV1TextLayout, } from '@inst/design-core/browser'; export const TEXT_SAFE_PADDING = 48; const MIN_TEXT_WIDTH = 48; const MIN_TEXT_HEIGHT = 24; function canvasContext(style: TextStyle): CanvasRenderingContext2D | null { if (typeof document === 'undefined') return null; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) return null; ctx.font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`; return ctx; } export function layoutTextLines(content: string, style: TextStyle, maxWidth: number): string[] { const ctx = canvasContext(style); if (!ctx || maxWidth <= 0) { const display = content; return display ? display.split('\n') : ['']; } return layoutV1TextLines(content, style, maxWidth, (text) => ctx.measureText(text).width); } export function measureTextLayout( content: string, style: TextStyle, width: number, ): { lines: string[]; height: number; lineHeightPx: number } { const ctx = canvasContext(style); if (!ctx) { return { lines: [content], height: MIN_TEXT_HEIGHT, lineHeightPx: style.fontSize * style.lineHeight }; } return measureV1TextLayout(content, style, width, (text) => ctx.measureText(text).width); } export function maxTextWidth( artboard: PostDesignDocument['artboard'], x = TEXT_SAFE_PADDING, ): number { return Math.max(MIN_TEXT_WIDTH, artboard.width - x - TEXT_SAFE_PADDING); } export function clampTextTransform( transform: LayerTransform, artboard: PostDesignDocument['artboard'], ): LayerTransform { const minWidth = MIN_TEXT_WIDTH; let { x, y, width, height, rotation } = transform; x = Math.max(0, Math.min(x, artboard.width - minWidth)); width = Math.max(minWidth, Math.min(width, artboard.width - x)); const layoutHeight = Math.max(MIN_TEXT_HEIGHT, height); y = Math.max(0, Math.min(y, artboard.height - MIN_TEXT_HEIGHT)); return { x: Math.round(x), y: Math.round(y), width: Math.round(width), height: Math.round(layoutHeight), rotation }; } export function fitTextLayer( layer: TextLayer, artboard: PostDesignDocument['artboard'], ): TextLayer { const transform = clampTextTransform(layer.transform, artboard); if (layer.autoResize !== 'height') { return { ...layer, transform }; } const { height } = measureTextLayout(layer.content, layer.style, transform.width); return { ...layer, transform: { ...transform, height: Math.ceil(height), }, }; } export function expandTextToSafeWidth( layer: TextLayer, artboard: PostDesignDocument['artboard'], ): TextLayer { const width = maxTextWidth(artboard, TEXT_SAFE_PADDING); return fitTextLayer( { ...layer, transform: { ...layer.transform, x: TEXT_SAFE_PADDING, width, }, }, artboard, ); } export function isTextLayerOutOfArtboard( layer: TextLayer, artboard: PostDesignDocument['artboard'], ): boolean { const { x, y, width, height } = layer.transform; return ( x < 0 || y < 0 || x + width > artboard.width + 0.5 || y + height > artboard.height + 0.5 ); } export function applyTextLayerPatch( layer: TextLayer, artboard: PostDesignDocument['artboard'], patch: Partial<TextLayer>, ): TextLayer { return fitTextLayer({ ...layer, ...patch, style: { ...layer.style, ...patch.style } }, artboard); } export function normalizeDocumentText(document: PostDesignDocument): PostDesignDocument { return { ...document, layers: document.layers.map((layer) => layer.type === 'text' ? fitTextLayer(layer, document.artboard) : layer, ), }; }