import "package:flutter/widgets.dart"; // Renders text via TextPainter directly, bypassing any theme/font overrides // from shadcn or other inherited themes. Use this when you need a specific // font (e.g. google fonts) and the theme keeps clobbering it. class AnaText extends StatefulWidget { const AnaText( this.text, { required this.style, this.textAlign = TextAlign.left, this.maxLines, super.key, }); final String text; final TextStyle style; final TextAlign textAlign; final int? maxLines; @override State createState() => _AnaTextState(); } class _AnaTextState extends State { int _fontVersion = 0; @override void initState() { super.initState(); PaintingBinding.instance.systemFonts.addListener(_onFontChange); } void _onFontChange() { setState(() => _fontVersion++); } @override void dispose() { PaintingBinding.instance.systemFonts.removeListener(_onFontChange); super.dispose(); } @override Widget build(BuildContext context) { return CustomPaint( painter: _AnaTextPainter( text: widget.text, style: widget.style, textAlign: widget.textAlign, maxLines: widget.maxLines, textDirection: Directionality.of(context), fontVersion: _fontVersion, ), child: _AnaTextSizer( text: widget.text, style: widget.style, maxLines: widget.maxLines, textDirection: Directionality.of(context), fontVersion: _fontVersion, ), ); } } class _AnaTextPainter extends CustomPainter { _AnaTextPainter({ required this.text, required this.style, required this.textAlign, required this.textDirection, required this.fontVersion, this.maxLines, }); final String text; final TextStyle style; final TextAlign textAlign; final TextDirection textDirection; final int? maxLines; final int fontVersion; @override void paint(Canvas canvas, Size size) { final tp = TextPainter( text: TextSpan(text: text, style: style), textAlign: textAlign, textDirection: textDirection, maxLines: maxLines, )..layout(maxWidth: size.width); final dy = (size.height - tp.height) / 2; tp.paint(canvas, Offset(0, dy.clamp(0.0, double.infinity))); } @override bool shouldRepaint(_AnaTextPainter old) => old.text != text || old.style != style || old.textAlign != textAlign || old.maxLines != maxLines || old.fontVersion != fontVersion; } // Invisible child that reports the natural text size back to the layout system // so CustomPaint gets constrained correctly. class _AnaTextSizer extends LeafRenderObjectWidget { const _AnaTextSizer({ required this.text, required this.style, required this.textDirection, required this.fontVersion, this.maxLines, }); final String text; final TextStyle style; final TextDirection textDirection; final int? maxLines; final int fontVersion; @override RenderObject createRenderObject(BuildContext context) => _AnaTextSizerBox( text: text, style: style, textDirection: textDirection, maxLines: maxLines, fontVersion: fontVersion, ); @override void updateRenderObject(BuildContext context, _AnaTextSizerBox renderObject) { renderObject ..text = text ..style = style ..textDirection = textDirection ..maxLines = maxLines ..fontVersion = fontVersion; } } class _AnaTextSizerBox extends RenderBox { _AnaTextSizerBox({ required String text, required TextStyle style, required TextDirection textDirection, required int fontVersion, int? maxLines, }) : _text = text, _style = style, _textDirection = textDirection, _maxLines = maxLines, _fontVersion = fontVersion; String _text; TextStyle _style; TextDirection _textDirection; int? _maxLines; int _fontVersion; set text(String v) { if (_text == v) return; _text = v; markNeedsLayout(); } set style(TextStyle v) { if (_style == v) return; _style = v; markNeedsLayout(); } set textDirection(TextDirection v) { if (_textDirection == v) return; _textDirection = v; markNeedsLayout(); } set maxLines(int? v) { if (_maxLines == v) return; _maxLines = v; markNeedsLayout(); } set fontVersion(int v) { if (_fontVersion == v) return; _fontVersion = v; markNeedsLayout(); } TextPainter _buildPainter({double maxWidth = double.infinity}) { return TextPainter( text: TextSpan(text: _text, style: _style), textDirection: _textDirection, maxLines: _maxLines, )..layout(maxWidth: maxWidth); } @override double computeMinIntrinsicWidth(double height) => _buildPainter().width; @override double computeMaxIntrinsicWidth(double height) => _buildPainter().width; @override double computeMinIntrinsicHeight(double width) => _buildPainter(maxWidth: width).height; @override double computeMaxIntrinsicHeight(double width) => _buildPainter(maxWidth: width).height; @override void performLayout() { final tp = _buildPainter(); size = constraints.constrain(Size(tp.width, tp.height)); } @override void paint(PaintingContext context, Offset offset) {} }