| 19 | |
| 20 | @nodeName('TxtLeaf') |
| 21 | export class TxtLeaf extends Shape { |
| 22 | @lazy(() => { |
| 23 | try { |
| 24 | return new (Intl as any).Segmenter(undefined, { |
| 25 | granularity: 'grapheme', |
| 26 | }); |
| 27 | } catch (e) { |
| 28 | return null; |
| 29 | } |
| 30 | }) |
| 31 | protected static readonly segmenter: any; |
| 32 | |
| 33 | @initial('') |
| 34 | @interpolation(textLerp) |
| 35 | @signal() |
| 36 | public declare readonly text: SimpleSignal<string, this>; |
| 37 | |
| 38 | public constructor({children, ...rest}: TxtLeafProps) { |
| 39 | super(rest); |
| 40 | if (children) { |
| 41 | this.text(children); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | @computed() |
| 46 | protected parentTxt() { |
| 47 | const parent = this.parent(); |
| 48 | if (!parent) { |
| 49 | return null; |
| 50 | } |
| 51 | |
| 52 | if (!(TXT_TYPE in parent)) { |
| 53 | return null; |
| 54 | } |
| 55 | |
| 56 | return parent; |
| 57 | } |
| 58 | |
| 59 | protected override async draw(context: CanvasRenderingContext2D) { |
| 60 | this.requestFontUpdate(); |
| 61 | this.applyStyle(context); |
| 62 | await document.fonts?.ready; |
| 63 | this.applyText(context); |
| 64 | context.font = this.styles.font; |
| 65 | context.textBaseline = 'bottom'; |
| 66 | if ('letterSpacing' in context) { |
| 67 | context.letterSpacing = `${this.letterSpacing()}px`; |
| 68 | } |
| 69 | const fontOffset = context.measureText('').fontBoundingBoxAscent; |
| 70 | |
| 71 | const parentRect = this.element.getBoundingClientRect(); |
| 72 | const {width, height} = this.size(); |
| 73 | const range = document.createRange(); |
| 74 | let line = ''; |
| 75 | const lineRect = new BBox(); |
| 76 | for (const childNode of this.element.childNodes) { |
| 77 | if (!childNode.textContent) { |
| 78 | continue; |
nothing calls this directly
no test coverage detected