fluent_editor 1.0.4 copy "fluent_editor: ^1.0.4" to clipboard
fluent_editor: ^1.0.4 copied to clipboard

A powerful and feature-rich rich word processor for Flutter applications with support for rich text editing, tables, images, lists, and export to DOCX, ODT, and PDF formats.

[FluentEditor]

Fluent Editor

Flutter Version License Version Live Demo

A powerful and feature-rich rich word processor for Flutter applications, inspired by nature 🍃.

Features #

  • Rich Text Editing: Support for bold, italic, underline, strikethrough, and more
  • Paragraph Styles: Headings, normal text, and paragraph formatting
  • Lists: Ordered and unordered lists with nested sublists
  • Tables: Create and edit tables with cell spanning
  • Images: Insert and resize images with inline and block positioning
  • Links: Insert and manage hyperlinks
  • Colors: Text color and highlight color support
  • Alignment: Left, center, right, and justify text alignment
  • Export: Export to DOCX, ODT, and PDF formats
  • Undo/Redo: Full undo/redo history with intelligent action grouping
  • Selection: Mouse and keyboard selection support
  • Word Count: Real-time word and character count
  • Clipboard: Cut, copy, and paste with formatting support

Tested On #

  • Web: Chrome
  • Windows: Windows 11
  • Linux: Ubuntu, Debian, Fedora
  • macOS: macOS 13+
  • iOS: iOS 15+
  • Android: Android 12+

Plugins #

  • fluent_editor_spellcheck — Hunspell-based spell-check plugin with isolate-backed checking, and multi-language support. (WIP)
  • fluent_editor_comments - Comments and annotations plugin. (WIP)
  • fluent_editor_review - Review plugin for track changes and comments. (WIP)

Getting Started #

Add Fluent Editor to your pubspec.yaml:

dependencies:
  fluent_editor:
    git:
      url: https://github.com/exusr/fluent-editor.git

Usage #

import 'package:fluent_editor/fluent_editor.dart';

class MyEditor extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FluentEditor(
      document: FluentDocument(),
      labels: FluentEditorLabels( //translate labels
        file: 'File',
        edit: 'Edit',
        insert: 'Insert',
        format: 'Format',
      ),
    );
  }
}

Creating a Document #

final document = FluentDocument();

// Add a paragraph
final paragraph = Paragraph()
  ..fragments = [Fragment('Hello, World!')];
document.content.nodes.add(paragraph);

// Add a heading
final heading = Paragraph()
  ..styleName = 'heading1'
  ..fragments = [Fragment('Title')];
document.content.nodes.add(heading);

// Add a list
final listItem1 = ListItem(bulletType: 'ordered', indexList: [1])
  ..children = [Paragraph()..fragments = [Fragment('First item')]];
final listItem2 = ListItem(bulletType: 'ordered', indexList: [2])
  ..children = [Paragraph()..fragments = [Fragment('Second item')]];
final list = FluentList(listType: 'ordered')
  ..items = [listItem1, listItem2];
document.content.nodes.add(list);

// Add an image
final image = FluentImage(src: 'https://example.com/image.png')
  ..width = 300
  ..height = 200;
document.content.nodes.add(image);

// Add a table
final cell1 = FluentCell()..fragments = [Fragment('Cell 1')];
final cell2 = FluentCell()..fragments = [Fragment('Cell 2')];
final row = FluentRow()..cells = [cell1, cell2];
final table = FluentTable()..rows = [row];
document.content.nodes.add(table);

// Add a link
final link = Link(url: 'https://example.com')
  ..fragments = [Fragment('Click here')];
final linkParagraph = Paragraph()
  ..fragments = [Fragment('Visit '), link, Fragment(' for more info')];
document.content.nodes.add(linkParagraph);

// Add a horizontal line
final hr = HorizontalRule();
document.content.nodes.add(hr);

Working with Selection #

// Get the current cursor position
final cursor = document.cursor;
final fragmentId = cursor.anchorId;
final offset = cursor.anchorOffset;

// Check if there's a selection
if (cursor.isCollapsed) {
  // Cursor is collapsed (no selection)
  print('Cursor at $fragmentId:$offset');
} else {
  // There's a selection
  print('Selection from ${cursor.anchorId}:${cursor.anchorOffset} to ${cursor.focusId}:${cursor.focusOffset}');
}

// Move the cursor (collapses selection)
cursor.moveTo(fragmentId, offset);

// Extend selection (creates or updates selection)
cursor.focusTo(targetFragmentId, targetOffset);

// Get selection offsets for a specific fragment
final paragraph = document.content.nodes.first as Paragraph;
final fragment = paragraph.fragments.first;
final selectionOffsets = cursor.getOffsets(paragraph, fragment);
if (selectionOffsets.$1 != -1) {
  print('Selection in fragment: ${selectionOffsets.$1} to ${selectionOffsets.$2}');
}

Additional Information #

Documentation #

For more detailed documentation and examples, see the /example folder.

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

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

Issues #

If you find any bugs or have feature requests, please open an issue on GitHub.

0
likes
0
points
91
downloads

Publisher

unverified uploader

Weekly Downloads

A powerful and feature-rich rich word processor for Flutter applications with support for rich text editing, tables, images, lists, and export to DOCX, ODT, and PDF formats.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

archive, desktop_drop, file_picker, file_selector, flutter, google_fonts, json_annotation, json_serializable, nanoid, path_provider, pdf, shared_preferences, vector_math

More

Packages that depend on fluent_editor