rich_text_controller

Text editing controller highlighting words, prefixes and suffixes based on RegExps and Strings.

  • User callback for all matched highlights.
  • User callback for tapped highlights
  • User callback for selected highlights
  • Deletes highlights on backspace.
  • Exact word, prefix, postfix matching
  • Disable highlighting dynamically

Installation

flutter pub add rich_text_controllerx

Quick Start

MatchTargetItem defines words or paterns to match and the TextStyle for matched words or patterns.

The optional function onSelected is invoked when a matched words is selected.

The optional function onTapInto is invoked when a matched words is tapped into. The needed minimum difference in cursor position is two chars.

Combining onSelected and onTapInto might not be useful.

The optional function onMatch is invoked everytime the set of matched words change.

Highlighting, onTapInto and onSelected can be toggled during runtime via exposed attributes. Disabling highlighting in general disables onTapInto and onSelected implicitly.

final controller = RichTextController( ... );

controller.enableHighlight =  true / false
controller.enableOnTapInto =  true / false
controller.enableOnSelected =  true / false

RichTextController

late final RichTextController controller = RichTextController(
    text:
        'Home sweet home! Do good homework and housework at home. The happyness of an ending.',
    sortTargetsByPatternLength: true,
    mergeOverlappingStyles: true,
    deleteOnBack: true,
    enableHighlight: true,
    enableOnTapInto: true,
    enableOnSelected: true,
    onMatch: (List<MatchResultItem> matches) {
      for (final MatchResultItem match in matches) {
        log(match.toString());
      }
    },
    targets: [
      // --------------------------------------------------------------
      // SINGLE STRING
      // --------------------------------------------------------------

      MatchTargetItem.string(
        'homework',
        style:
            const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
        stringMatch: StringMatch.exact,
        caseSensitive: false,
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      MatchTargetItem.string(
        'Home',
        style: const TextStyle(color: Colors.red),
        stringMatch: StringMatch.any,
        caseSensitive: false,
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      // Prefix

      MatchTargetItem.string(
        'happy',
        style: const TextStyle(color: Colors.blue),
        stringMatch: StringMatch.prefix,
        caseSensitive: false,
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      // Postfix

      MatchTargetItem.string(
        'ing',
        style: const TextStyle(color: Colors.blue),
        stringMatch: StringMatch.postfix,
        caseSensitive: false,
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      // --------------------------------------------------------------
      // MULTIPLE STRINGS
      // --------------------------------------------------------------

      MatchTargetItem.strings(
        ['do', 'at'],
        style: const TextStyle(color: Colors.pink),
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      // --------------------------------------------------------------
      // SINGLE REGEXP
      // --------------------------------------------------------------

      MatchTargetItem.regex(
        RegExp(r'sweet'),
        style: const TextStyle(color: Colors.indigo),
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),

      // --------------------------------------------------------------
      // MUTIPLE REGEXPs
      // --------------------------------------------------------------

      MatchTargetItem.regexes(
        [RegExp(r'good'), RegExp(r'and')],
        style: const TextStyle(
          decoration: TextDecoration.underline,
          decorationStyle: TextDecorationStyle.wavy,
          decorationColor: Colors.indigo,
          decorationThickness: 3,
        ),
        onSelected: (MatchResultItem match) => _onWordMatchTap(match),
        onTapInto: (MatchResultItem match) => _onWordMatchTap(match),
      ),
    ],
  );

// ...

TextField(controller: controller)

RichWrapper

RichWrapper(
  initialText: 'Good morning and good night at Github',
  targets: [
    MatchTargetItem.string('good',
        style: const TextStyle(color: Colors.red)),
    MatchTargetItem.strings(['morning', 'night'],
        style: const TextStyle(color: Colors.blue)),
    MatchTargetItem.regex(RegExp(r'and'),
        style: const TextStyle(color: Colors.orange)),
    MatchTargetItem.regexs([RegExp(r'at'), RegExp(r'Github')],
        style: const TextStyle(color: Colors.indigo)),
  ],
  child: (controller) => TextField(controller: controller),
)

Example

See example page and example app for code.

Inspiration

This package is a rewrite of .

License

This project is licensed under the MIT License - see the LICENSE.md file for details