Repository: motion-canvas/motion-canvas
File: packages/2d/src/components/Text.ts (TypeScript)

Code before:
          lineRect.width += rangeRect.width;
          line += childNode.textContent;
        } else {
          this.drawText(context, line, lineRect);
          lineRect.x = x;
          lineRect.y = y;
          lineRect.width = rangeRect.width;
          lineRect.height = rangeRect.height;
          line = childNode.textContent;
        }
      }

      this.drawText(context, line, lineRect);
    } else if (this.layout.element.firstChild) {
      range.selectNodeContents(this.layout.element.firstChild);
      const rangeRect = range.getBoundingClientRect();
      rangeRect.x = width / -2 + rangeRect.left - parentRect.left;
      rangeRect.y = height / -2 + rangeRect.top - parentRect.top;
      this.drawText(context, this.text(), rangeRect);
    }
  }

  protected drawText(
    context: CanvasRenderingContext2D,
    text: string,
    rect: Rect,
  ) {
    if (this.lineWidth() <= 0) {
      context.fillText(text, rect.x, rect.y + rect.height / 2, rect.width);
    } else if (this.strokeFirst()) {
      context.strokeText(text, rect.x, rect.y + rect.height / 2, rect.width);
      context.fillText(text, rect.x, rect.y + rect.height / 2, rect.width);
    } else {
      context.fillText(text, rect.x, rect.y + rect.height / 2, rect.width);
      context.strokeText(text, rect.x, rect.y + rect.height / 2, rect.width);
    }
  }

  protected override applyFontChanges() {
    super.applyFontChanges();
    const wrap = this.layout.styles.whiteSpace !== 'nowrap';
    const text = this.text();

    if (wrap && Text.segmenter) {
      this.layout.element.innerText = '';
      for (const word of Text.segmenter.segment(text)) {
        this.layout.element.appendChild(document.createTextNode(word.segment));
      }
    } else {
      this.layout.element.innerText = this.text();
    }

Review comment (suggestion):
You _might_ not want to set a text width here. The context can change the font or font-size to satisfy the constraint, which the browser won't do. It's possible that not having a fixed size will look better in more cases than having it.

Code after:
        this.drawText(context, line, lineRect);
        lineRect.x = x;
        lineRect.y = y;
        lineRect.width = rangeRect.width;
        lineRect.height = rangeRect.height;
        line = childNode.textContent;
      }
    }

    this.drawText(context, line, lineRect);
  }

  protected drawText(
    context: CanvasRenderingContext2D,
    text: string,
    rect: Rect,
  ) {
    if (this.lineWidth() <= 0) {
      context.fillText(text, rect.x, rect.y + rect.height / 2);
    } else if (this.strokeFirst()) {
      context.strokeText(text, rect.x, rect.y + rect.height / 2);
      context.fillText(text, rect.x, rect.y + rect.height / 2);
    } else {
      context.fillText(text, rect.x, rect.y + rect.height / 2);
      context.strokeText(text, rect.x, rect.y + rect.height / 2);
    }
  }

  protected override applyFontChanges() {
    super.applyFontChanges();
    const wrap = this.layout.styles.whiteSpace !== 'nowrap';
    const text = this.text();

    if (wrap && Text.segmenter) {
      this.layout.element.innerText = '';
      for (const word of Text.segmenter.segment(text)) {
        this.layout.element.appendChild(document.createTextNode(word.segment));
      }
    } else {
      this.layout.element.innerText = this.text();
    }

    if (wrap && !Text.segmenter) {
      console.error('Wrapping is not supported');
    }
  }
}