flutter_rte 0.4.3 copy "flutter_rte: ^0.4.3" to clipboard
flutter_rte: ^0.4.3 copied to clipboard

HTML WYSIWYG rich text editor for Flutter with built-in speech-to-text.

Flutter Rich Text Editor #

Easy to use WYSIWYG HTML editor for Flutter with built-in voice-to-text. Try it here

Flutter Rich Text Editor Web


Under the Hood #

This plugin is a reworked html_editor_enhanced with a few differences:

  • Widget height: wrap content, expand, or explicit, with height ChangeNotifier.
  • Summernote and jQuery replaced with Squire and DOMPurify for stricter security, HTML5 compatibility, features, performance and size.
  • in_app_webview replaced with Flutter's own webview_flutter.

Basic Implementation #

Basic implementation of this editor doesn't require a controller. For simplicity and ease of use, [HtmlEditor] gives you access to the following top-level attributes:

  • height (double) - sets explicit height of the widget
  • minHeight (double) - sets minimum height of the widget
  • expandFullHeight (bool) - sizes widget to take all available height
  • hint (String) - Displays hint when the field is empty
  • initialValue (String) - initial HTML or text
  • onChanged (String) - top-level shortcut to onChanged callback
  • isReadOnly (bool) - locks the editor and removes the toolbar
  • enableDictation (bool) - yay or nay to voice-to-text feature
import 'package:flutter_rte/flutter_rte.dart';

// ...

// 1. Define a var to store changes within parent class or a provider etc...
String result = 'Hello world!';

// ...

// 2. Add HtmlEditor to your build method
@override
Widget build(BuildContext context) =>
    HtmlEditor(initalValue: result, onChanged:(s)=> result = s ?? '');


Advanced Implementation #

To take advantage of the entire API you'll need to create and configure an instance of [HtmlEditorController]. That instance provides access to the following groups of features:

  • Styling options group (all things CSS, HTML and sanitizing)
  • Toolbar options group (all things toolbar)
  • Editor options group (all things editor)

When controller is provided, contents of the editor could be tried and accessed syncronously via a getter:


    if(controller.contentIsNotEmpty){
        Navigator.of(context).pop(controller.content);
    }


HTML Styling Options #

The stylingOptions parameter of [HtmlEditorController] class defines the look of generated HTML. Here you can select which tag to use for paragraphs and how your tags are styled.


var stylingOptions = HtmlStylingOptions(

    // Adding global style is optional, but could be set in two ways:
    // 1. by providing a CSS string to the parameter `globalStyleSheet`:
    globalStyleSheet: '/* Your CSS string contents of style.css file */',

    // This defines which tag to use for paragraphs.
    // The default value is `p`, however the `div` is also acceptable.
    blockTag: 'p',

    // defines `style` and `class` attributes of a block tag
    blockTagAttributes: HtmlTagAttributes(

        // this is added as inline CSS for every tag
        inlineStyle: 'text-indent:3.5em; text-align:justify;',

        // defines `class` attribute value of every tag
        cssClass: 'my-custom-pgf'),

    // next we can define attributes for other tags (li, ul, ol, a etc):
    li: HtmlTagAttributes(
        inlineStyle: 'margin: .5em 1em  .5em .5em',
        cssClass: 'my-custom-li-class'),

    // ... other HTML tag definitions ... //

    code: HtmlTagAttributes(
        inlineStyle: 'padding: .5em 1em;', cssClass: 'my-custom-li-class'),

    // when sanitizeOnPaste is `true` - editor will strip all 
    // HTML pasted into the editor down to plain text
    sanitizeOnPaste: true,
    );

    // 2. another way to add global CSS is to call this async method:
    await stylingOptions.importCssFromFile('path/to/style.css');

    // ...

    // Now create the editor passing the styling options
    return HtmlEditor(
      controller: HtmlEditorController(stylingOptions: stylingOptions),
      onChanged: (p0) => (p0) {/* TODO */},
      initialValue: '' /* TODO */,
    );

The code above should result in the following HTML being generated for each paragraph:


<p style="text-indent:3.5em; text-align:justify;" class="my-custom-pgf"></p>

Sizing and Constraints #

By default, the widget occupies all available width and sizes its height based on the height of its content, but not less than the value of minHeight attribute of [HtmlEditor] widget.

    // since explicit height is not provided - the editor will size itself
    // based on content, but will be not less than 250px
    return HtmlEditor(
      controller: controller,
      // ...
      minHeight: 250, // should be not less than 64px
      // ...
    );

    // and here you can listen to changes in height of the editor
    ValueListenableBuilder<double>(
        valueListenable: controller.totalHeight,
        builder: (BuildContext context, double value, Widget? child) {
        return Text('Height changed to $value\n'
            'Toolbar height is ${controller.toolbarHeight}\n'
            'Content height is ${controller.contentHeight}\n' );
        });
    

If explicit `height` is provided - the widget will size it's height precisely to the value of `height` attribute. In this case, if content height is greater than the widget height - the content becomes scrollable.
    // here we've provided the height value, so the editor will always be
    // that height and the content will scroll if overflows the height.
    return HtmlEditor(
      height: 250,
    );

If `expandFullHeight` is set to `true` - the widget will take up all available height.

    return HtmlEditor(
      expandFullHeight: true,
    );

Toolbar Position #

All toolbar-related options are contained within [ToolbarOptions] of [HtmlEditorController] class. Toolbar could be positionned:

  • above, below the editor container, by setting the toolbarPosition attribute;

Above editor:

Toolbar above editor

Below editor:

Toolbar below editor

  • detached from the editor and located anywhere outside the [HtmlEditor]widget. This allows [ToolbarWidget] to be attached to several HtmlEditors. For this type of implementation please refer to the example within the package. Toolbar floating

  • scrollable, grid or expandable by setting the toolbarType attribute


Toolbar Contents and Custom Button Groups #

Toolbar button groups could be enabled/disabled via defaultToolbarButtons attribute of [HtmlToolbarOptions] class within the controller. You can customize the toolbar by overriding the default value of this attribute.

Adding your own button groups to the toolbar is very simple - just provide a list of [CustomButtonGroup] objects to the customButtonGroups attribute. Each button group will consist of a list of [CustomToolbarButton] objects, each with its own icon, tap callback and an isSelected flag to let the toolbar know if the icon button should be highlighted.

HtmlEditor(
    controller: HtmlEditorController()
        ..toolbarOptions.customButtonGroups = [
        CustomButtonGroup(
            index: 0, // place first
            buttons: [
            CustomToolbarButton(
                icon: Icons.save_outlined,
                action: () => /* TODO: implement your save method */,
                isSelected: false)
        ])
        ],
    ),

= Custom button


Voice to Text (Dictation) #

Voice-to-text feature is powered by speech_to_text package and comes enabled by default with this package. To disable voice-to-text feature - set the corresponding top-level enableDictation attribute within [HtmlEditor] constructor to false.

Overriding controller.toolbarOptions.defaultToolbarButtons value also overrides enableDictation flag (obviously), so you need to add const VoiceToTextButtons() in order to keep seeing the voice-to-text button.


Special Considerations and Gotchas #

  1. Due to some framework issues on Web, this plugin is only compatible with Flutter 3.3. If you want to use this plugin with earlier versions of Flutter - downgrade pointer_interceptor in this dependency to 0.9.0+1.

  2. Following needs to be done to make things work on each platform:

Android #

For speech recognition to work - place this to android > app > src > main > AndroidManifest.xml


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.example">

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    
   <application
    ...

iOS #

For speech recognition to work - add following permission to your Info.plist file:

<key>NSSpeechRecognitionUsageDescription</key>
<string>recognize speech</string>
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for uploading videos</string>

Web Platform #

To get the toolbar to scroll horizontally on Web, you will need to make sure you override the default scroll behavior:

  1. Add the following class override to your app:

    class MyCustomScrollBehavior extends MaterialScrollBehavior {
    @override
    Set<PointerDeviceKind> get dragDevices => {
            PointerDeviceKind.touch,
            PointerDeviceKind.mouse,
        };
    }
    
    
  2. Add the following attribute to the [MaterialApp] widget:

    return MaterialApp(
        // ...
        scrollBehavior: MyCustomScrollBehavior(),
        // ...
    );
    
    

Done. Now you should be able to drag the toolbar left and right on web.

19
likes
0
pub points
79%
popularity

Publisher

unverified uploader

HTML WYSIWYG rich text editor for Flutter with built-in speech-to-text.

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (LICENSE)

Dependencies

flex_color_picker, flutter, meta, numberpicker, pointer_interceptor, speech_to_text, webview_flutter

More

Packages that depend on flutter_rte