UNPKG

tldraw

Version:

A tiny little drawing editor.

107 lines (98 loc) 2.71 kB
import { Box, Editor, TLFrameShape, canonicalizeRotation, last, toDomPrecision, } from '@tldraw/editor' import { TLCreateTextJsxFromSpansOpts } from '../shared/createTextJsxFromSpans' import { defaultEmptyAs } from './FrameShapeUtil' export function getFrameHeadingSide(editor: Editor, shape: TLFrameShape): 0 | 1 | 2 | 3 { const pageRotation = canonicalizeRotation(editor.getShapePageTransform(shape.id)!.rotation()) const offsetRotation = pageRotation + Math.PI / 4 const scaledRotation = (offsetRotation * (2 / Math.PI) + 4) % 4 return Math.floor(scaledRotation) as 0 | 1 | 2 | 3 } /** * Get the frame heading info (size and text) for a frame shape. * * @param editor The editor instance. * @param shape The frame shape. * @param opts The text measurement options. * * @returns The frame heading's size (as a Box) and JSX text spans. */ export function getFrameHeadingInfo( editor: Editor, shape: TLFrameShape, opts: TLCreateTextJsxFromSpansOpts ) { if (process.env.NODE_ENV === 'test') { // can't really measure text in tests return { box: new Box(0, -opts.height, shape.props.w, opts.height), spans: [], } } const spans = editor.textMeasure.measureTextSpans( defaultEmptyAs(shape.props.name, 'Frame') + String.fromCharCode(8203), opts ) const firstSpan = spans[0] const lastSpan = last(spans)! const labelTextWidth = lastSpan.box.w + lastSpan.box.x - firstSpan.box.x return { box: new Box(0, -opts.height, labelTextWidth, opts.height), spans, } } export function getFrameHeadingOpts( shape: TLFrameShape, color: string ): TLCreateTextJsxFromSpansOpts { return { fontSize: 12, fontFamily: 'Inter, sans-serif', textAlign: 'start' as const, width: shape.props.w, height: 32, padding: 0, lineHeight: 1, fontStyle: 'normal', fontWeight: 'normal', overflow: 'truncate-ellipsis' as const, verticalTextAlign: 'middle' as const, fill: color, offsetY: -(32 + 2), offsetX: 2, } } export function getFrameHeadingTranslation( shape: TLFrameShape, side: 0 | 1 | 2 | 3, isSvg: boolean ) { const u = isSvg ? '' : 'px' const r = isSvg ? '' : 'deg' let labelTranslate: string switch (side) { case 0: // top labelTranslate = `` break case 3: // right labelTranslate = `translate(${toDomPrecision(shape.props.w)}${u}, 0${u}) rotate(90${r})` break case 2: // bottom labelTranslate = `translate(${toDomPrecision(shape.props.w)}${u}, ${toDomPrecision( shape.props.h )}${u}) rotate(180${r})` break case 1: // left labelTranslate = `translate(0${u}, ${toDomPrecision(shape.props.h)}${u}) rotate(270${r})` break default: throw Error('labelSide out of bounds') } return labelTranslate }