val_latex_flutter 0.1.2 copy "val_latex_flutter: ^0.1.2" to clipboard
val_latex_flutter: ^0.1.2 copied to clipboard

Render LaTeX math in Flutter: formula widgets, math inside text and Markdown, line wrapping, selection, screen readers, theming and streaming LLM output.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'demos/accessibility.dart';
import 'demos/background.dart';
import 'demos/basics.dart';
import 'demos/canvas.dart';
import 'demos/chemistry.dart';
import 'demos/compat.dart';
import 'demos/core.dart';
import 'demos/equations.dart';
import 'demos/errors.dart';
import 'demos/interaction.dart';
import 'demos/lists.dart';
import 'demos/macros.dart';
import 'demos/math_span.dart';
import 'demos/overflow.dart';
import 'demos/rtl.dart';
import 'demos/scripts.dart';
import 'demos/streaming.dart';
import 'demos/tables.dart';
import 'demos/text_with_math.dart';
import 'demos/theme.dart';
import 'demos/wrapping.dart';
import 'tour.dart';

void main() => runApp(const ExampleApp());

/// Every feature, in the order shown.
final List<Feature> features = [
  Feature(
    id: 'basics',
    title: 'Formulas',
    description:
        'Math.tex renders a formula, inline or in display style, at any '
        'size and colour.',
    file: 'basics.dart',
    demo: (_) => const BasicsDemo(),
  ),
  Feature(
    id: 'text',
    title: 'Text with formulas (Markdown)',
    description:
        r'MathText renders text with $…$ and $$…$$ formulas in it — what a '
        'Markdown or chat renderer needs.',
    file: 'text_with_math.dart',
    demo: (_) => const TextWithMathDemo(),
  ),
  Feature(
    id: 'span',
    title: 'Formulas in rich text',
    description:
        'MathSpan puts a formula inside Text.rich, sitting on the text '
        'baseline.',
    file: 'math_span.dart',
    demo: (_) => const MathSpanDemo(),
  ),
  Feature(
    id: 'streaming',
    title: 'Streaming text',
    description:
        'Text that is still arriving renders without flashing raw TeX: '
        'unfinished formulas show as far as they go.',
    file: 'streaming.dart',
    demo: (_) => const StreamingDemo(),
  ),
  Feature(
    id: 'wrapping',
    title: 'Line wrapping',
    description:
        'Display formulas break to the width they get, at the places a '
        'person would. Drag the width.',
    file: 'wrapping.dart',
    demo: (_) => const WrappingDemo(),
  ),
  Feature(
    id: 'overflow',
    title: 'Overflow',
    description:
        'What a formula that does not wrap does when it is too wide: '
        'scroll, shrink or clip.',
    file: 'overflow.dart',
    demo: (_) => const OverflowDemo(),
  ),
  Feature(
    id: 'equations',
    title: 'Equations, numbers, matrices',
    description:
        'align, gather, equation and friends, numbered or tagged; cases, '
        'matrices and arrays.',
    file: 'equations.dart',
    demo: (_) => const EquationsDemo(),
  ),
  Feature(
    id: 'errors',
    title: 'Errors and unfinished input',
    description:
        'Bad input never throws: mistakes show in place, or your own '
        'fallback; unfinished input renders what exists.',
    file: 'errors.dart',
    demo: (_) => const ErrorsDemo(),
  ),
  Feature(
    id: 'theme',
    title: 'Theming',
    description:
        r'MathTheme sets colours, styles parts marked with \htmlClass, and '
        'can draw a layout debug overlay.',
    file: 'theme.dart',
    demo: (_) => const ThemeDemo(),
  ),
  Feature(
    id: 'interaction',
    title: 'Taps, highlights, selection',
    description:
        'Find out which part was tapped, highlight parts of the source, '
        'and select and copy formulas as LaTeX.',
    file: 'interaction.dart',
    demo: (_) => const InteractionDemo(),
  ),
  Feature(
    id: 'accessibility',
    title: 'Accessibility',
    description:
        'Screen readers hear the formula spoken (English or Arabic), part '
        'by part; keyboard users can move through it.',
    file: 'accessibility.dart',
    demo: (_) => const AccessibilityDemo(),
  ),
  Feature(
    id: 'scripts',
    title: 'Text in any script',
    description:
        r'\text{…} is shaped by Flutter: Arabic joins, Indic conjuncts form, '
        'CJK and emoji work.',
    file: 'scripts.dart',
    demo: (_) => const ScriptsDemo(),
  ),
  Feature(
    id: 'rtl',
    title: 'Right-to-left math',
    description:
        'Arabic notation: mirrored layout, Arabic-Indic digits, Arabic '
        'operator names.',
    file: 'rtl.dart',
    demo: (_) => const RtlDemo(),
  ),
  Feature(
    id: 'chemistry',
    title: 'Chemistry, units, physics',
    description:
        r'\ce, \SI and physics (\dv, \pdv, \expval…) work out of the box; '
        r'the full physics package is one option away.',
    file: 'chemistry.dart',
    demo: (_) => const ChemistryDemo(),
  ),
  Feature(
    id: 'tables',
    title: 'Tables',
    description:
        r'tabular, tabularx and table with \caption; booktabs rules '
        r'(\toprule, \midrule, \cmidrule) and \multicolumn.',
    file: 'tables.dart',
    demo: (_) => const TablesDemo(),
  ),
  Feature(
    id: 'lists',
    title: 'Lists and package commands',
    description:
        r'itemize, enumerate, description, \intertext, cases*; and \abs, '
        r'\dv, \sfrac, \vv, \celsius… without loading a package.',
    file: 'lists.dart',
    demo: (_) => const ListsDemo(),
  ),
  Feature(
    id: 'macros',
    title: 'Shared macros',
    description:
        r'Define \R or \norm once and use them in every formula that gets '
        'the same macro table.',
    file: 'macros.dart',
    demo: (_) => const MacrosDemo(),
  ),
  Feature(
    id: 'canvas',
    title: 'Paint on a canvas',
    description:
        'Lay a formula out once and draw it yourself with MathPainter, in '
        'any CustomPainter.',
    file: 'canvas.dart',
    demo: (_) => const CanvasDemo(),
  ),
  Feature(
    id: 'core',
    title: 'The pure-Dart core',
    description:
        'Parse, measure, normalise, speak and find formulas in text without '
        'any widget — also on a server or in an isolate.',
    file: 'core.dart',
    demo: (_) => const CoreDemo(),
  ),
  Feature(
    id: 'background',
    title: 'Background layout',
    description:
        'Very large formulas can be laid out in a background isolate, so '
        'the UI never stutters.',
    file: 'background.dart',
    demo: (_) => const BackgroundDemo(),
  ),
  Feature(
    id: 'compat',
    title: 'Moving from flutter_math_fork',
    description:
        'Change one import and keep your code: the compat layer has '
        "flutter_math_fork's API.",
    file: 'compat.dart',
    demo: (_) => const CompatDemo(),
  ),
];

/// The tour of val_latex_flutter's features.
class ExampleApp extends StatefulWidget {
  /// Creates the app.
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  var _dark = false;

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'val_latex_flutter',
    debugShowCheckedModeBanner: false,
    theme: ThemeData(colorSchemeSeed: Colors.indigo),
    darkTheme: ThemeData(
      colorSchemeSeed: Colors.indigo,
      brightness: Brightness.dark,
    ),
    themeMode: _dark ? ThemeMode.dark : ThemeMode.light,
    home: TourPage(
      dark: _dark,
      onToggleDark: () => setState(() => _dark = !_dark),
    ),
  );
}

/// The features, one card each, with a list to jump between them.
class TourPage extends StatefulWidget {
  /// Creates the page.
  const TourPage({super.key, required this.dark, required this.onToggleDark});

  /// Whether the dark theme is on.
  final bool dark;

  /// Switches between light and dark.
  final VoidCallback onToggleDark;

  @override
  State<TourPage> createState() => _TourPageState();
}

class _TourPageState extends State<TourPage> {
  final _keys = {for (final f in features) f.id: GlobalKey()};

  void _jump(String id) {
    final context = _keys[id]!.currentContext;
    if (context != null) {
      Scrollable.ensureVisible(
        context,
        duration: const Duration(milliseconds: 300),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final wide = MediaQuery.sizeOf(context).width >= 1100;
    final list = ListView(
      padding: const EdgeInsets.symmetric(vertical: 8),
      children: [
        for (final f in features)
          ListTile(
            dense: true,
            title: Text(f.title),
            onTap: () {
              if (!wide) Navigator.of(context).pop();
              _jump(f.id);
            },
          ),
      ],
    );
    final content = SingleChildScrollView(
      padding: const EdgeInsets.all(24),
      child: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 1200),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const _Intro(),
              for (final f in features) ...[
                const SizedBox(height: 24),
                FeatureCard(f, key: _keys[f.id]),
              ],
            ],
          ),
        ),
      ),
    );
    return Scaffold(
      appBar: AppBar(
        title: const Text('val_latex_flutter'),
        actions: [
          IconButton(
            tooltip: widget.dark ? 'Light theme' : 'Dark theme',
            icon: Icon(widget.dark ? Icons.light_mode : Icons.dark_mode),
            onPressed: widget.onToggleDark,
          ),
        ],
      ),
      drawer: wide ? null : Drawer(child: SafeArea(child: list)),
      body: wide
          ? Row(
              children: [
                SizedBox(width: 260, child: list),
                const VerticalDivider(width: 1),
                Expanded(child: content),
              ],
            )
          : content,
    );
  }
}

class _Intro extends StatelessWidget {
  const _Intro();

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'TeX math for Flutter, in pure Dart',
          style: theme.textTheme.headlineSmall,
        ),
        const SizedBox(height: 8),
        Text(
          'Every feature of val_latex_flutter, live, with the code that '
          'makes it — copy any snippet with the button in its corner. Add '
          'the package and import it:',
          style: theme.textTheme.bodyLarge,
        ),
        const SizedBox(height: 8),
        const SnippetText(
          "import 'package:val_latex_flutter/val_latex_flutter.dart';",
        ),
      ],
    );
  }
}
4
likes
160
points
0
downloads

Documentation

API reference

Publisher

verified publisheruseval.io

Weekly Downloads

Render LaTeX math in Flutter: formula widgets, math inside text and Markdown, line wrapping, selection, screen readers, theming and streaming LLM output.

Homepage
View/report issues

Topics

#katex #latex #math #streaming #mathematics

License

BSD-3-Clause (license)

Dependencies

flutter, val_latex

More

Packages that depend on val_latex_flutter