Compare commits

...

99 Commits

Author SHA1 Message Date
Huy Panha f486278d99 Khmer language 7 months ago
Huy Panha d6dfea1c5b
Create quill_km.arb 7 months ago
singerdmx 008d262b70 chore(version): update to version 10.4.1 8 months ago
Cat 82308daa0e
Chore: improve Spell checker API to the example (#2133) 8 months ago
singerdmx f9bcf83aae chore(version): update to version 10.4.0 8 months ago
Cat 7ae1afe068
Feat: include spell checker for example app (#2127) 8 months ago
Łukasz Wiśniewski 11c8bc7d75
enhance stringToColor with a custom defined palette from `DefaultStyles` (#2095) 8 months ago
License name 2937dc8c95
Copy TapAndPanGestureRecognizer from TextField (#2128) 8 months ago
singerdmx bb29a50050 chore(version): update to version 10.3.2 8 months ago
AtlasAutocode dba979e2fe
Fix: Loss of style when backspace (#2125) 8 months ago
singerdmx b0ffb5f9fc chore(version): update to version 10.3.1 8 months ago
Cat da4f0efeaf
Chore: Move spellchecker service to extensions (#2120) 8 months ago
singerdmx b62f413bf7 chore(version): update to version 10.3.0 8 months ago
Cat 0d12456b5f
Feat: Spellchecker for Flutter Quill (#2118) 8 months ago
singerdmx 08856d147e chore(version): update to version 10.2.1 8 months ago
Cat dad352cbf2
Fix: unsafe operation while getting overlayEntry in text_selection (#2117) 8 months ago
Cat b894c5fdd6
Fix: context menu is visible even when selection is collapsed (#2116) 8 months ago
singerdmx 2342509737 chore(version): update to version 10.2.0 8 months ago
AtlasAutocode 56d7d48d57
Fix: Link selection and editing (#2114) 8 months ago
Ellet c7eca10955
docs: add const keyword for QuillSimpleToolbarConfigurations in README 8 months ago
Ellet cdcbd65530 chore: remove outdated TODO in flutter_quill_extensions 8 months ago
Ellet 7f9d5df8f6
refactor!: restructure project into modular architecture for flutter_quill_extensions (#2106) 8 months ago
singerdmx c40eaf465d chore(version): update to version 10.1.10 8 months ago
Hamed H. 9c79db83c8
Add Wasm support (#2103) 8 months ago
Cat ac573df0fb
Fix(example): image_cropper outdated version (#2100) 8 months ago
singerdmx f93ce63dcb chore(version): update to version 10.1.9 8 months ago
Michael Allen c739f6c12d
restore ability to pass in key to QuillEditor (#2093) 8 months ago
singerdmx 1cc6a7cdc1 chore(version): update to version 10.1.8 8 months ago
AtlasAutocode 40e18b2706
Enhancement: Search within Embed objects (#2090) 8 months ago
singerdmx 80ee3f4e30 chore(version): update to version 10.1.7 8 months ago
DeveloperBiz 4c04fcf90a
Swap order of shortcut map merging so that customShortcuts are added first and override existing duplicate trigger shortcuts by absorbing the input first (#2089) 8 months ago
singerdmx 23f66b38ae chore(version): update to version 10.1.6 8 months ago
Felix Lee 0a971932cf
fix: Double click to select text sometimes doesn't work. (#2086) 8 months ago
singerdmx 1013d03ed9 chore(version): update to version 10.1.5 8 months ago
Adil Hanney e11af21fba
ref: add `VerticalSpacing.zero` and `HorizontalSpacing.zero` named constants (#2083) 8 months ago
singerdmx 9a7421a53b chore(version): update to version 10.1.4 8 months ago
AtlasAutocode d1fb286803
Fix: collectStyles for lists and alignments (#2082) 8 months ago
singerdmx e9f30f5f16 chore(version): update to version 10.1.3 8 months ago
AtlasAutocode 23fbb43b76
Move Controller outside of configurations data class (#2078) 8 months ago
singerdmx 4d6380f028 chore(version): update to version 10.1.2 8 months ago
AtlasAutocode 6f8fa24470
Fix Multiline paste with attributes and embeds (#2074) 8 months ago
singerdmx 1c3ccf7a9a chore(version): update to version 10.1.1 8 months ago
Raman Rasliuk e028ccf59e
Toolbar dividers fixes + Docs updates (#2071) 8 months ago
singerdmx 8589b856e8 chore(version): update to version 10.1.0 8 months ago
Cat ac5a823440
Feat: support for customize copy and cut Embeddables to Clipboard (#2067) 8 months ago
singerdmx 88ec59ccb4 chore(version): update to version 10.0.10 8 months ago
Huan Du cbcc023f03
fix: hide toolbar if editor loses focus (#2066) 8 months ago
singerdmx 1e545ca298 chore(version): update to version 10.0.9 8 months ago
Cat 493bdbc54d
Fix: manual checking of directionality (#2063) 8 months ago
singerdmx 522cb3f1d4 chore(version): update to version 10.0.8 8 months ago
Huan Du 5526ea4feb
fix: invalid selection when tapping placeholder text (#2062) 8 months ago
Huan Du ab004b8755
feat: add callback to handle performAction (#2061) 8 months ago
singerdmx 964779be3d chore(version): update to version 10.0.7 8 months ago
Cat 2818d0fce0
Fix: RTL issues (#2060) 8 months ago
singerdmx 6ecd377b26 chore(version): update to version 10.0.6 8 months ago
Huan Du 2a297f20c7
fix: textInputAction is not set when creating QuillRawEditorConfigurations (#2057) 8 months ago
singerdmx 022495cb16 chore(version): update to version 10.0.5 8 months ago
AtlasAutocode 42d830f037
Add tests for PreserveInlineStylesRule and fix link editing. Other minor fixes. (#2058) 9 months ago
singerdmx faf8f558a8 chore(version): update to version 10.0.4 9 months ago
X Code d7f13a496b
Update translation.md 9 months ago
Alex Consel af2863b2f9
add catalan language (#2054) 9 months ago
Dimka fd69f614bc
Add ability to set up horizontal spacing for block style (#2051) 9 months ago
singerdmx 58ee571c9d chore(version): update to version 10.0.3 9 months ago
Michael Allen d6c74098d2
if magnifier removes toolbar, restore it when it is hidden (#2049) 9 months ago
Cat 9d6db48413
doc(attribute): added documentation about Attribute class and how create one (#2048) 9 months ago
Cat 689b8fde7c
doc(Delta): more documentation about Delta (#2042) 9 months ago
singerdmx 1fb757cb3f chore(version): update to version 10.0.2 9 months ago
Guillermo Bueno Vargas 8da8e059f1
Have the ability to create custom rules, closes #1162 (#2040) 9 months ago
Ellet eb38c51bf0
chore: update issue bug template 9 months ago
Ellet 5a9de8d883
chore: enable blank issues template in GitHub repo 9 months ago
Ellet 28c59444bc
chore(scripts): migrate the scripts from sh to dart (#2036) 9 months ago
EchoEllet af7e4048ed chore(version): update to version 10.0.1 9 months ago
Ellet acb15968d2
fix: require 10.0.0 as minimum version for quill packages (#2035) 9 months ago
singerdmx 179a44db2a chore(version): update to version 10.0.0 9 months ago
Ellet 7dc848a80e
chore: update GitHub PR template (#2033) 9 months ago
Ellet f5e0f8589b
refactor: use immutable annotation from flutter foundation instead of meta package in flutter_quill 9 months ago
Ellet 4a166e3d1d
chore: remove invalid docs comment in Leaf.splitAt() 9 months ago
Ellet 9764f75006
refactor: restructure project into modular architecture for flutter_quill (#2032) 9 months ago
singerdmx af3679840b chore(version): update to version 9.6.0 9 months ago
License name af691e69ed
[feature] : quill add magnifier (#2026) 9 months ago
singerdmx 0dbe4c4685 chore(version): update to version 9.5.23 9 months ago
Khoshbin Ali Ahmed 785529acdc
add untranslated Kurdish keys (#2029) 9 months ago
singerdmx 4bf2289a88 chore(version): update to version 9.5.22 9 months ago
Cat d2e3784b77
Fix(rule): PreserveInlineStyleRule assume the type of the operation data and throw stacktrace (#2028) 9 months ago
Cat eb29c3a7f6
Fix outdated contributor guide link on PR template (#2027) 9 months ago
singerdmx 8de8569b73 chore(version): update to version 9.5.21 9 months ago
AtlasAutocode f3a5e113f6
Fix: Key actions not being handled (#2025) 9 months ago
singerdmx 73911b7b75 chore(version): update to version 9.5.20 9 months ago
Cat 7c72967861
update delta_from_html package on pubspec.yaml (#2018) 9 months ago
Cat 236cad0708
removed unnecessary convertion from html to delta test file (#2017) 9 months ago
singerdmx d05d16ec29 chore(version): update to version 9.5.19 9 months ago
Felix Lee 492f25b0df
fixed #1835 Embed Reloads on Cmd Key Press (#2013) 9 months ago
singerdmx 5aca31f629 chore(version): update to version 9.5.18 9 months ago
Cat 7282e721dd
doc(rule): added documentation about rules (#2014) 9 months ago
Alspb 7ab6444520
Refactor: Moved core link button functions to link.dart (#2008) 9 months ago
singerdmx 429d1ca340 chore(version): update to version 9.5.17 9 months ago
Cat 480861b098
feat: added option to disable automatic list conversion (#2011) 9 months ago
singerdmx ab91df27e5 chore(version): update to version 9.5.16 9 months ago
Cat 9f7673c887
fix: delta_x tests fail (#2010) 9 months ago
  1. 39
      .github/ISSUE_TEMPLATE/1_bug.yml
  2. 2
      .github/ISSUE_TEMPLATE/config.yml
  3. 54
      .github/PULL_REQUEST_TEMPLATE.md
  4. 59
      .github/workflows/build.yml
  5. 6
      .github/workflows/main.yml
  6. 6
      .github/workflows/publish.yml
  7. 298
      CHANGELOG.md
  8. 2
      CHANGELOG_DATA.json
  9. 7
      CONTRIBUTING.md
  10. 79
      README.md
  11. 1
      analysis_options.yaml
  12. 298
      dart_quill_delta/CHANGELOG.md
  13. 2
      dart_quill_delta/pubspec.yaml
  14. 103
      doc/attribute_introduction.md
  15. 1
      doc/configurations/custom_buttons.md
  16. 68
      doc/configurations/search.md
  17. 6
      doc/custom_embed_blocks.md
  18. 252
      doc/delta_introduction.md
  19. 142
      doc/rules_introduction.md
  20. 8
      doc/translation.md
  21. 13
      example/lib/screens/home/widgets/home_screen.dart
  22. 12
      example/lib/screens/quill/my_quill_editor.dart
  23. 27
      example/lib/screens/quill/my_quill_toolbar.dart
  24. 31
      example/lib/screens/quill/quill_screen.dart
  25. 10
      example/lib/screens/simple/simple_screen.dart
  26. 14
      example/macos/Podfile.lock
  27. 2
      example/macos/Runner/AppDelegate.swift
  28. 12
      example/pubspec.yaml
  29. 298
      flutter_quill_extensions/CHANGELOG.md
  30. 11
      flutter_quill_extensions/README.md
  31. 12
      flutter_quill_extensions/lib/embeds/embed_types.dart
  32. 277
      flutter_quill_extensions/lib/embeds/others/image_video_utils.dart
  33. 537
      flutter_quill_extensions/lib/embeds/others/media_button/media_button.dart
  34. 19
      flutter_quill_extensions/lib/embeds/unknown/editor/unknown_embed.dart
  35. 86
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  36. 71
      flutter_quill_extensions/lib/models/config/media/media_button_configurations.dart
  37. 0
      flutter_quill_extensions/lib/src/common/extensions/attribute.dart
  38. 0
      flutter_quill_extensions/lib/src/common/extensions/controller_ext.dart
  39. 122
      flutter_quill_extensions/lib/src/common/image_video_utils.dart
  40. 0
      flutter_quill_extensions/lib/src/common/utils/dart_ui/dart_ui_fake.dart
  41. 1
      flutter_quill_extensions/lib/src/common/utils/dart_ui/dart_ui_real.dart
  42. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_shared_utils.dart
  43. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_utils.dart
  44. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_web_utils.dart
  45. 0
      flutter_quill_extensions/lib/src/common/utils/patterns.dart
  46. 0
      flutter_quill_extensions/lib/src/common/utils/quill_image_utils.dart
  47. 0
      flutter_quill_extensions/lib/src/common/utils/quill_table_utils.dart
  48. 0
      flutter_quill_extensions/lib/src/common/utils/string.dart
  49. 4
      flutter_quill_extensions/lib/src/common/utils/utils.dart
  50. 0
      flutter_quill_extensions/lib/src/editor/formula/formula_embed.dart
  51. 8
      flutter_quill_extensions/lib/src/editor/image/image_embed.dart
  52. 4
      flutter_quill_extensions/lib/src/editor/image/image_embed_types.dart
  53. 16
      flutter_quill_extensions/lib/src/editor/image/image_menu.dart
  54. 11
      flutter_quill_extensions/lib/src/editor/image/image_web_embed.dart
  55. 2
      flutter_quill_extensions/lib/src/editor/image/models/image_configurations.dart
  56. 0
      flutter_quill_extensions/lib/src/editor/image/models/image_web_configurations.dart
  57. 6
      flutter_quill_extensions/lib/src/editor/image/widgets/image.dart
  58. 0
      flutter_quill_extensions/lib/src/editor/image/widgets/image_resizer.dart
  59. 65
      flutter_quill_extensions/lib/src/editor/spell_checker/simple_spell_checker_service.dart
  60. 0
      flutter_quill_extensions/lib/src/editor/table/table_cell_embed.dart
  61. 2
      flutter_quill_extensions/lib/src/editor/table/table_embed.dart
  62. 0
      flutter_quill_extensions/lib/src/editor/table/table_models.dart
  63. 0
      flutter_quill_extensions/lib/src/editor/video/models/video_configurations.dart
  64. 0
      flutter_quill_extensions/lib/src/editor/video/models/video_web_configurations.dart
  65. 0
      flutter_quill_extensions/lib/src/editor/video/models/youtube_video_support_mode.dart
  66. 10
      flutter_quill_extensions/lib/src/editor/video/video_embed.dart
  67. 11
      flutter_quill_extensions/lib/src/editor/video/video_web_embed.dart
  68. 2
      flutter_quill_extensions/lib/src/editor/video/widgets/video_app.dart
  69. 2
      flutter_quill_extensions/lib/src/editor/video/widgets/youtube_video_app.dart
  70. 3
      flutter_quill_extensions/lib/src/editor_toolbar_controller_shared/clipboard/super_clipboard_service.dart
  71. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/image_options.dart
  72. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/image_picker.dart
  73. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/packages/image_picker.dart
  74. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/s_image_picker.dart
  75. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/exceptions.dart
  76. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/image_saver.dart
  77. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/packages/gal.dart
  78. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/s_image_saver.dart
  79. 4
      flutter_quill_extensions/lib/src/editor_toolbar_shared/shared_configurations.dart
  80. 36
      flutter_quill_extensions/lib/src/flutter_quill_embeds.dart
  81. 6
      flutter_quill_extensions/lib/src/toolbar/camera/camera_button.dart
  82. 4
      flutter_quill_extensions/lib/src/toolbar/camera/camera_types.dart
  83. 2
      flutter_quill_extensions/lib/src/toolbar/camera/models/camera_configurations.dart
  84. 0
      flutter_quill_extensions/lib/src/toolbar/camera/select_camera_action.dart
  85. 2
      flutter_quill_extensions/lib/src/toolbar/formula/formula_button.dart
  86. 0
      flutter_quill_extensions/lib/src/toolbar/formula/models/formula_configurations.dart
  87. 10
      flutter_quill_extensions/lib/src/toolbar/image/image_button.dart
  88. 2
      flutter_quill_extensions/lib/src/toolbar/image/models/image_configurations.dart
  89. 2
      flutter_quill_extensions/lib/src/toolbar/image/select_image_source.dart
  90. 0
      flutter_quill_extensions/lib/src/toolbar/table/models/table_configurations.dart
  91. 5
      flutter_quill_extensions/lib/src/toolbar/table/table_button.dart
  92. 4
      flutter_quill_extensions/lib/src/toolbar/video/models/video.dart
  93. 2
      flutter_quill_extensions/lib/src/toolbar/video/models/video_configurations.dart
  94. 2
      flutter_quill_extensions/lib/src/toolbar/video/select_video_source.dart
  95. 10
      flutter_quill_extensions/lib/src/toolbar/video/video_button.dart
  96. 1
      flutter_quill_extensions/lib/utils/dart_ui/dart_ui_real.dart
  97. 5
      flutter_quill_extensions/pubspec.yaml
  98. 298
      flutter_quill_test/CHANGELOG.md
  99. 4
      flutter_quill_test/pubspec.yaml
  100. 13
      lib/extensions.dart
  101. Some files were not shown because too many files have changed in this diff Show More

@ -18,19 +18,10 @@ body:
- type: input
attributes:
label: Flutter Quill version
description: Please tell us which version of `flutter_quill` that you are using.
placeholder: For example 9.0.0
description: The version of the project for the packages (e.g., `flutter_quill` and `flutter_quill_extensions`)
placeholder: (e.g., 10.0.0)
validations:
required: false
# - type: textarea
# attributes:
# label: Other Flutter Quill packages versions
# description: If you are using any other packages like `flutter_quill_extensions` or `flutter_quill_test` please mention the versions here
# placeholder: |
# flutter_quill_extensions: ^0.6.10
# flutter_quill_test: ^0.0.5
# validations:
# required: false
- type: textarea
attributes:
label: Steps to reproduce
@ -71,12 +62,16 @@ body:
</details>
validations:
required: true
required: false
- type: textarea
attributes:
label: Screenshots or Video
label: Additional Context
description: |
Upload any screenshots or video of the bug if applicable.
Include additional information such as Screenshots or Logs if needed.
If the logs are too large to be uploaded to GitHub, you may upload
them as a `txt` file or use online tools like https://pastebin.com to
share it.
value: |
<details>
<summary>Screenshots / Video demonstration</summary>
@ -84,24 +79,8 @@ body:
[Upload media here]
</details>
validations:
required: false
- type: textarea
attributes:
label: Logs
description: |
Include the full logs of the commands you are running between the lines
with the backticks below. If you are running any `flutter` commands,
please include the output of running them with `--verbose`; for example,
the output of running `flutter --verbose create foo`.
If the logs are too large to be uploaded to GitHub, you may upload
them as a `txt` file or use online tools like https://pastebin.com to
share it.
Note: Please do not upload screenshots of text. Instead, use code blocks
or the above mentioned ways to upload logs.
value: |
<details><summary>Logs</summary>
```console

@ -1 +1 @@
blank_issues_enabled: false
blank_issues_enabled: true

@ -1,38 +1,50 @@
<!--
Thank you for contributing.
Provide a description of your changes below and a general summary in the title.
Consider reading the Contributor Guide: https://github.com/singerdmx/flutter-quill/blob/master/CONTRIBUTING.md.
The changes of `CHANGELOG.md` and package version in `pubspec.yaml` are automated.
-->
## Description
*Replace this paragraph with a description of what this PR is doing. If you're modifying existing behavior, describe the existing behavior, how this PR is changing it, and what motivated the change.*
## Related Issues
*Replace this paragraph with a list of issues related to this PR from the [issue database](https://github.com/singerdmx/flutter-quill/issues). Indicate, which of these issues are resolved or fixed by this PR.*
<!--
*e.g.*
Replace this paragraph with a list of issues related to this PR from the [issue database](https://github.com/singerdmx/flutter-quill/issues). Indicate, which of these issues are resolved or fixed by this PR.
-->
<!-- *e.g.* -->
- *Fix #123*
- *Related #456*
## Improvements
<!-- Optional -->
## Type of Change
## Features
<!-- Optional -->
<!---
## Additional notes
<!-- Optional -->
Put an x in all the boxes that apply:
## Suggestions
<!-- Optional -->
- [x] **Example:**
## Checklist
-->
- [ ] I read the [Contributor Guide](../CONTRIBUTING.md) and followed the process outlined there for submitting PRs.
- [ ] I titled the PR using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0).
- [ ] I did not modify the `CHANGELOG.md` nor the package version in `pubspec.yaml` files.
- [ ] All existing and new tests are passing.
- [ ] I have run the commands in `./scripts/before_push.sh` and it all passed successfully
- [ ] ✨ **New feature:** Adds new functionality without breaking existing features.
- [ ] 🛠 **Bug fix:** Resolves an issue without altering current behavior.
- [ ] 🧹 **Code refactor:** Code restructuring that does not affect behavior.
- [ ] ❌ **Breaking change:** Alters existing functionality and requires updates.
- [ ] 🧪 **Tests:** Adds new tests or modifies existing tests.
- [ ] 📝 **Documentation:** Updates or additions to documentation.
- [ ] 🗑 **Chore:** Routine tasks, or maintenance.
- [ ] ✅ **Build configuration change:** Changes to build or deploy processes.
## Breaking Change
Does your PR require developers to manually update their apps to accommodate your change?
## Suggestions
- [ ] Yes, this is a breaking change (please indicate that with a `!` in the title as explained in [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0)).
- [ ] No, this is *not* a breaking change.
<!-- Optional -->

@ -24,12 +24,12 @@ jobs:
- name: 🔍 Verify Flutter installation
run: flutter --version
- name: 🚧 Enable local development environment (use the local packages)
run: ./scripts/enable_local_dev.sh
- name: 📥 Install Flutter dependencies
run: flutter pub get
- name: 🚧 Enable local development environment (use the local packages)
run: dart ./scripts/enable_local_dev.dart
- name: 🌐 Build Flutter Web Application
run: flutter build web --release --verbose --dart-define=CI=true
working-directory: ./example
@ -47,56 +47,3 @@ jobs:
- name: 🐧 Build Flutter Linux Desktop Application
run: flutter build linux --release --verbose --dart-define=CI=true
working-directory: ./example
# build_windows:
# name: Build Windows App
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v4
# - uses: subosito/flutter-action@v2
# with:
# channel: 'stable'
# cache: true
# - name: Check flutter version
# run: flutter --version
# # Sh scripts is not supported on windows
# - name: Enable Local Dev
# run: ./scripts/enable_local_dev.sh
# - name: Install dependencies
# run: flutter pub get
# - name: Flutter build windows
# run: flutter build windows --release --verbose --dart-define=CI=true
# working-directory: ./example
# build_macOS:
# name: Build macOS App
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v4
# - uses: subosito/flutter-action@v2
# with:
# channel: 'stable'
# cache: true
# - name: Check flutter version
# run: flutter --version
# - name: Enable Local Dev
# run: ./scripts/enable_local_dev.sh
# - name: Install dependencies
# run: flutter pub get
# - name: Flutter build macOS
# run: flutter build macos --release --verbose --dart-define=CI=true
# working-directory: ./example
# - name: Flutter build iOS
# run: flutter build ios --release --verbose --dart-define=CI=true
# working-directory: ./example

@ -24,12 +24,12 @@ jobs:
- name: 🔍 Verify Flutter installation
run: flutter --version
- name: 🚧 Enable local development environment (use the local packages)
run: ./scripts/enable_local_dev.sh
- name: 📥 Install Flutter dependencies
run: flutter pub get
- name: 🚧 Enable local development environment (use the local packages)
run: dart ./scripts/enable_local_dev.dart
- name: 📦 Install dart_quill_delta dependencies
run: flutter pub get -C dart_quill_delta

@ -37,12 +37,12 @@ jobs:
- name: 🔍 Verify Flutter installation
run: flutter --version
- name: 🚧 Enable local development environment (use the local packages)
run: ./scripts/enable_local_dev.sh
- name: 📥 Install Flutter dependencies
run: flutter pub get
- name: 🚧 Enable local development environment (use the local packages)
run: dart ./scripts/enable_local_dev.dart
# This is needed in order for the authentication to success
# dart pub token add https://pub.dev --env-var PUB_TOKEN

@ -4,6 +4,304 @@
All notable changes to this project will be documented in this file.
## 10.4.1
* Chore: improve Spell checker API to the example by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2133
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.4.0...v10.4.1
## 10.4.0
* Copy TapAndPanGestureRecognizer from TextField by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2128
* enhance stringToColor with a custom defined palette from `DefaultStyles` by @vishna in https://github.com/singerdmx/flutter-quill/pull/2095
* Feat: include spell checker for example app by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2127
## New Contributors
* @vishna made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2095
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.3...v10.4.0
## 10.3.2
* Fix: Loss of style when backspace by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2125
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.1...v10.3.2
## 10.3.1
* Chore: Move spellchecker service to extensions by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2120
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.0...v10.3.1
## 10.3.0
* Feat: Spellchecker for Flutter Quill by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2118
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.1...v10.3.0
## 10.2.1
* Fix: context menu is visible even when selection is collapsed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2116
* Fix: unsafe operation while getting overlayEntry in text_selection by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2117
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.0...v10.2.1
## 10.2.0
* refactor!: restructure project into modular architecture for flutter_quill_extensions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2106
* Fix: Link selection and editing by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2114
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.10...v10.2.0
## 10.1.10
* Fix(example): image_cropper outdated version by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2100
* Using dart.library.js_interop instead of dart.library.html by @h1376h in https://github.com/singerdmx/flutter-quill/pull/2103
## New Contributors
* @h1376h made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2103
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.9...v10.1.10
## 10.1.9
* restore ability to pass in key to QuillEditor by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2093
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.8...v10.1.9
## 10.1.8
* Enhancement: Search within Embed objects by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2090
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.7...v10.1.8
## 10.1.7
* Feature/allow shortcut override by @InstrinsicAutomations in https://github.com/singerdmx/flutter-quill/pull/2089
## New Contributors
* @InstrinsicAutomations made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2089
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.6...v10.1.7
## 10.1.6
* fixed #1295 Double click to select text sometimes doesn't work. by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2086
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.5...v10.1.6
## 10.1.5
* ref: add `VerticalSpacing.zero` and `HorizontalSpacing.zero` named constants by @adil192 in https://github.com/singerdmx/flutter-quill/pull/2083
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.4...v10.1.5
## 10.1.4
* Fix: collectStyles for lists and alignments by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2082
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.3...v10.1.4
## 10.1.3
* Move Controller outside of configurations data class by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2078
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.2...v10.1.3
## 10.1.2
* Fix Multiline paste with attributes and embeds by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2074
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.1...v10.1.2
## 10.1.1
* Toolbar dividers fixes + Docs updates by @troyanskiy in https://github.com/singerdmx/flutter-quill/pull/2071
## New Contributors
* @troyanskiy made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2071
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.0...v10.1.1
## 10.1.0
* Feat: support for customize copy and cut Embeddables to Clipboard by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2067
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.10...v10.1.0
## 10.0.10
* fix: Hide selection toolbar if editor loses focus by @huandu in https://github.com/singerdmx/flutter-quill/pull/2066
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.9...v10.0.10
## 10.0.9
* Fix: manual checking of directionality by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2063
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.8...v10.0.9
## 10.0.8
* feat: add callback to handle performAction by @huandu in https://github.com/singerdmx/flutter-quill/pull/2061
* fix: Invalid selection when tapping placeholder text by @huandu in https://github.com/singerdmx/flutter-quill/pull/2062
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.7...v10.0.8
## 10.0.7
* Fix: RTL issues by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2060
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.6...v10.0.7
## 10.0.6
* fix: textInputAction is not set when creating QuillRawEditorConfiguration by @huandu in https://github.com/singerdmx/flutter-quill/pull/2057
## New Contributors
* @huandu made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2057
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.5...v10.0.6
## 10.0.5
* Add tests for PreserveInlineStylesRule and fix link editing. Other minor fixes. by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2058
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.4...v10.0.5
## 10.0.4
* Add ability to set up horizontal spacing for block style by @dimkanovikov in https://github.com/singerdmx/flutter-quill/pull/2051
* add catalan language by @spilioio in https://github.com/singerdmx/flutter-quill/pull/2054
## New Contributors
* @dimkanovikov made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2051
* @spilioio made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2054
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.3...v10.0.4
## 10.0.3
* doc(Delta): more documentation about Delta by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2042
* doc(attribute): added documentation about Attribute class and how create one by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2048
* if magnifier removes toolbar, restore it when it is hidden by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2049
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.2...v10.0.3
## 10.0.2
* chore(scripts): migrate the scripts from sh to dart by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2036
* Have the ability to create custom rules, closes #1162 by @Guillergood in https://github.com/singerdmx/flutter-quill/pull/2040
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.1...v10.0.2
## 10.0.1
This release is identical to [10.0.0](https://github.com/singerdmx/flutter-quill/releases/tag/v10.0.0) with a fix that addresses issue #2034 by requiring `10.0.0` as the minimum version for quill related dependencies.
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.0...v10.0.1
## 10.0.0
* refactor: restructure project into modular architecture for flutter_quill by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2032
* chore: update GitHub PR template by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2033
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.6.0...v10.0.0
## 9.6.0
* [feature] : quill add magnifier by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2026
## New Contributors
* @demoYang made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2026
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.23...v9.6.0
## 9.5.23
* add untranslated Kurdish keys by @Xoshbin in https://github.com/singerdmx/flutter-quill/pull/2029
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.22...v9.5.23
## 9.5.22
* Fix outdated contributor guide link on PR template by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2027
* Fix(rule): PreserveInlineStyleRule assume the type of the operation data and throw stacktrace by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2028
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.21...v9.5.22
## 9.5.21
* Fix: Key actions not being handled by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2025
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.20...v9.5.21
## 9.5.20
* Remove useless delta_x_test by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2017
* Update flutter_quill_delta_from_html package on pubspec.yaml by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2018
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.19...v9.5.20
## 9.5.19
* fixed #1835 Embed Reloads on Cmd Key Press by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2013
## New Contributors
* @li8607 made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2013
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.18...v9.5.19
## 9.5.18
* Refactor: Moved core link button functions to link.dart by @Alspb in https://github.com/singerdmx/flutter-quill/pull/2008
* doc: more documentation about Rules by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2014
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.17...v9.5.18
## 9.5.17
* Feat(config): added option to disable automatic list conversion by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2011
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.16...v9.5.17
## 9.5.16
* chore: drop support for HTML, PDF, and Markdown converting functions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/1997
* docs(readme): update the extensions package to document the Rich Text Paste feature on web by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2001
* Fix(test): delta_x tests fail by wrong expected Delta for video embed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2010
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.15...v9.5.16
## 9.5.15
* Update delta_from_html to fix nested lists issues and more by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2000

File diff suppressed because one or more lines are too long

@ -58,14 +58,13 @@ You will need a GitHub account as well as Git installed and configured with your
cp pubspec_overrides.yaml.disabled pubspec_overrides.yaml
```
or save some time with the following script:
<!-- TODO: We should update this script to dart instead -->
```
./scripts/enable_local_dev.sh
dart ./scripts/enable_local_dev.dart
```
8. Test them in the [example](./example) and add changes in there if necessary
9. Run the following script if possible
```
./scripts/before_push.sh
```shell
dart ./scripts/before_push.dart
```
10. When you are done sending your pull request, run:
```

@ -64,6 +64,7 @@ You can join our [Slack Group] for discussion.
- [🛠 Using the embed blocks from `flutter_quill_extensions`](#-using-the-embed-blocks-from-flutter_quill_extensions)
- [🔗 Links](#-links-2)
- [🔄 Conversion to HTML](#-conversion-to-html)
- [📝 Spelling checker](#-Spelling-checker)
- [🌐 Translation](#-translation)
- [🧪 Testing](#-testing)
- [👥 Contributors](#-contributors)
@ -94,8 +95,9 @@ dependencies:
```yaml
dependencies:
flutter_quill:
git: https://github.com/singerdmx/flutter-quill.git
ref: v<latest-version-here>
git:
url: https://github.com/singerdmx/flutter-quill.git
ref: v<latest-version-here>
```
> [!TIP]
@ -107,7 +109,7 @@ dependencies:
## 🛠 Platform Specific Configurations
Before using the package, we must inform you the package uses the following plugins:
The `flutter_quill` package uses the following plugins:
1. [`url_launcher`](https://pub.dev/packages/url_launcher) to open links.
2. [`device_info_plus`](https://pub.dev/packages/device_info_plus) to view info about the current device.
@ -129,16 +131,18 @@ Instantiate a controller:
QuillController _controller = QuillController.basic();
```
Use the `QuillEditor`, and `QuillToolbar` widgets,
Use the `QuillEditor`, and `QuillSimpleToolbar` widgets,
and attach the `QuillController` to them:
```dart
QuillToolbar.simple(
configurations: QuillSimpleToolbarConfigurations(controller: _controller),
QuillSimpleToolbar(
controller: _controller,
configurations: const QuillSimpleToolbarConfigurations(),
),
Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(controller: _controller),
controller: _controller,
configurations: const QuillEditorConfigurations(),
),
)
```
@ -214,6 +218,7 @@ The `QuillToolbar` and `QuillEditor` widgets let you customize a lot of things
- [Font Size](./doc/configurations/font_size.md)
- [Font Family](#font-family)
- [Custom Toolbar buttons](./doc/configurations/custom_buttons.md)
- [Search](./doc/configurations/search.md)
### 🖋 Font Family
@ -278,6 +283,66 @@ The following packages can be used:
3. [`flutter_quill_to_pdf`](https://pub.dev/packages/flutter_quill_to_pdf): To convert **Delta** To **PDF**.
4. [`markdown_quill`](https://pub.dev/packages/markdown_quill): To convert **Markdown** To **Delta** and vice versa.
## 📝 Spelling checker
A spell checker is a software tool or feature integrated into various text processing applications that automatically identifies and corrects spelling errors in a written document. It works by comparing the words in the text against a built-in dictionary. If a word isn't found in the dictionary or doesn't match any known word patterns, the spell checker highlights it as a potential error.
#### Benefits of a spell checker include:
* Improved Accuracy: It helps writers avoid common spelling mistakes, ensuring that the text is free of errors.
* Time-Saving: Automatically detecting errors reduces the time needed for manual proofreading.
* Enhanced Professionalism: Correctly spelled words contribute to the overall professionalism of documents, which is crucial in academic, business, and formal writing.
* Multilingual Support: Many spell checkers support multiple languages, making it easier for users to write accurately in different languages.
> [!IMPORTANT]
> The spell checker usually does not work as expected in most cases. **Many translations are not supported** such as: `Chinese`, `Japanese`, `Korean`, `Hebrew`, `Arabic`, `Russian`, etc. For now it is a purely **experimental** feature that may have **code that will be modified** in future versions.
#### The translations supported so far are:
* **German** - `de` (may contain errors or missing words)
* **English** - `en` (currently adding missing translations)
* **Spanish** - `es` (currently adding missing translations)
* **French** - `fr` (may contain errors or missing words)
* **Italian** - `it` (currently adding missing translations)
* **Norwegian** - `no` (may contain errors or missing words)
* **Portuguese** - `pt` (may contain errors or missing words)
* **Swedish** - `sv` (may contain errors or missing words)
_**Note**: If you have knowledge about any of these available languages or the unsupported ones, you can make a pull request to add support or add words that are not currently in [simple_spell_checker](https://github.com/CatHood0/simple_spell_checker)_.
In order to activate this functionality you can use the following code:
```dart
// you can use the language of your preference or directly select the language of the operating system
final language = 'en'; // or Localizations.localeOf(context).languageCode
FlutterQuillExtensions.useSpellCheckerService(language);
```
When you no longer need to have the Spell checker activated you can simply use `dispose()` of the `SpellCheckerServiceProvider` class:
```dart
// dispose all service and it cannot be used after this
SpellCheckerServiceProvider.dispose();
```
If what we want is to **close the StreamControllers** without deleting the values that are already stored in it, we can set `onlyPartial` to `true`.
```dart
// it can be still used by the editor
SpellCheckerServiceProvider.dispose(onlyPartial: true);
```
One use of this would be having the opportunity to **activate and deactivate** the service when we want, we can see this in the example that we have in this package, in which you can see that on each screen, we have a button that dynamically activates and deactivates the service. To do this is pretty simple:
```dart
SpellCheckerServiceProvider.toggleState();
// use isServiceActive to get the state of the service
SpellCheckerServiceProvider.isServiceActive();
setState(() {});
```
Open this [page](https://pub.dev/packages/simple_spell_checker) for more information.
## 🌐 Translation
The package offers translations for the quill toolbar and editor, it will follow the system locale unless you set your

@ -12,7 +12,6 @@ linter:
avoid_empty_else: true
avoid_escaping_inner_quotes: true
avoid_print: true
avoid_redundant_argument_values: true
avoid_types_on_closure_parameters: true
avoid_void_async: true
cascade_invocations: true

@ -4,6 +4,304 @@
All notable changes to this project will be documented in this file.
## 10.4.1
* Chore: improve Spell checker API to the example by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2133
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.4.0...v10.4.1
## 10.4.0
* Copy TapAndPanGestureRecognizer from TextField by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2128
* enhance stringToColor with a custom defined palette from `DefaultStyles` by @vishna in https://github.com/singerdmx/flutter-quill/pull/2095
* Feat: include spell checker for example app by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2127
## New Contributors
* @vishna made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2095
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.3...v10.4.0
## 10.3.2
* Fix: Loss of style when backspace by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2125
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.1...v10.3.2
## 10.3.1
* Chore: Move spellchecker service to extensions by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2120
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.0...v10.3.1
## 10.3.0
* Feat: Spellchecker for Flutter Quill by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2118
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.1...v10.3.0
## 10.2.1
* Fix: context menu is visible even when selection is collapsed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2116
* Fix: unsafe operation while getting overlayEntry in text_selection by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2117
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.0...v10.2.1
## 10.2.0
* refactor!: restructure project into modular architecture for flutter_quill_extensions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2106
* Fix: Link selection and editing by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2114
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.10...v10.2.0
## 10.1.10
* Fix(example): image_cropper outdated version by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2100
* Using dart.library.js_interop instead of dart.library.html by @h1376h in https://github.com/singerdmx/flutter-quill/pull/2103
## New Contributors
* @h1376h made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2103
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.9...v10.1.10
## 10.1.9
* restore ability to pass in key to QuillEditor by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2093
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.8...v10.1.9
## 10.1.8
* Enhancement: Search within Embed objects by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2090
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.7...v10.1.8
## 10.1.7
* Feature/allow shortcut override by @InstrinsicAutomations in https://github.com/singerdmx/flutter-quill/pull/2089
## New Contributors
* @InstrinsicAutomations made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2089
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.6...v10.1.7
## 10.1.6
* fixed #1295 Double click to select text sometimes doesn't work. by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2086
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.5...v10.1.6
## 10.1.5
* ref: add `VerticalSpacing.zero` and `HorizontalSpacing.zero` named constants by @adil192 in https://github.com/singerdmx/flutter-quill/pull/2083
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.4...v10.1.5
## 10.1.4
* Fix: collectStyles for lists and alignments by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2082
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.3...v10.1.4
## 10.1.3
* Move Controller outside of configurations data class by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2078
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.2...v10.1.3
## 10.1.2
* Fix Multiline paste with attributes and embeds by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2074
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.1...v10.1.2
## 10.1.1
* Toolbar dividers fixes + Docs updates by @troyanskiy in https://github.com/singerdmx/flutter-quill/pull/2071
## New Contributors
* @troyanskiy made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2071
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.0...v10.1.1
## 10.1.0
* Feat: support for customize copy and cut Embeddables to Clipboard by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2067
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.10...v10.1.0
## 10.0.10
* fix: Hide selection toolbar if editor loses focus by @huandu in https://github.com/singerdmx/flutter-quill/pull/2066
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.9...v10.0.10
## 10.0.9
* Fix: manual checking of directionality by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2063
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.8...v10.0.9
## 10.0.8
* feat: add callback to handle performAction by @huandu in https://github.com/singerdmx/flutter-quill/pull/2061
* fix: Invalid selection when tapping placeholder text by @huandu in https://github.com/singerdmx/flutter-quill/pull/2062
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.7...v10.0.8
## 10.0.7
* Fix: RTL issues by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2060
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.6...v10.0.7
## 10.0.6
* fix: textInputAction is not set when creating QuillRawEditorConfiguration by @huandu in https://github.com/singerdmx/flutter-quill/pull/2057
## New Contributors
* @huandu made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2057
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.5...v10.0.6
## 10.0.5
* Add tests for PreserveInlineStylesRule and fix link editing. Other minor fixes. by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2058
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.4...v10.0.5
## 10.0.4
* Add ability to set up horizontal spacing for block style by @dimkanovikov in https://github.com/singerdmx/flutter-quill/pull/2051
* add catalan language by @spilioio in https://github.com/singerdmx/flutter-quill/pull/2054
## New Contributors
* @dimkanovikov made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2051
* @spilioio made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2054
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.3...v10.0.4
## 10.0.3
* doc(Delta): more documentation about Delta by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2042
* doc(attribute): added documentation about Attribute class and how create one by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2048
* if magnifier removes toolbar, restore it when it is hidden by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2049
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.2...v10.0.3
## 10.0.2
* chore(scripts): migrate the scripts from sh to dart by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2036
* Have the ability to create custom rules, closes #1162 by @Guillergood in https://github.com/singerdmx/flutter-quill/pull/2040
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.1...v10.0.2
## 10.0.1
This release is identical to [10.0.0](https://github.com/singerdmx/flutter-quill/releases/tag/v10.0.0) with a fix that addresses issue #2034 by requiring `10.0.0` as the minimum version for quill related dependencies.
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.0...v10.0.1
## 10.0.0
* refactor: restructure project into modular architecture for flutter_quill by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2032
* chore: update GitHub PR template by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2033
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.6.0...v10.0.0
## 9.6.0
* [feature] : quill add magnifier by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2026
## New Contributors
* @demoYang made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2026
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.23...v9.6.0
## 9.5.23
* add untranslated Kurdish keys by @Xoshbin in https://github.com/singerdmx/flutter-quill/pull/2029
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.22...v9.5.23
## 9.5.22
* Fix outdated contributor guide link on PR template by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2027
* Fix(rule): PreserveInlineStyleRule assume the type of the operation data and throw stacktrace by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2028
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.21...v9.5.22
## 9.5.21
* Fix: Key actions not being handled by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2025
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.20...v9.5.21
## 9.5.20
* Remove useless delta_x_test by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2017
* Update flutter_quill_delta_from_html package on pubspec.yaml by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2018
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.19...v9.5.20
## 9.5.19
* fixed #1835 Embed Reloads on Cmd Key Press by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2013
## New Contributors
* @li8607 made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2013
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.18...v9.5.19
## 9.5.18
* Refactor: Moved core link button functions to link.dart by @Alspb in https://github.com/singerdmx/flutter-quill/pull/2008
* doc: more documentation about Rules by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2014
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.17...v9.5.18
## 9.5.17
* Feat(config): added option to disable automatic list conversion by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2011
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.16...v9.5.17
## 9.5.16
* chore: drop support for HTML, PDF, and Markdown converting functions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/1997
* docs(readme): update the extensions package to document the Rich Text Paste feature on web by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2001
* Fix(test): delta_x tests fail by wrong expected Delta for video embed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2010
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.15...v9.5.16
## 9.5.15
* Update delta_from_html to fix nested lists issues and more by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2000

@ -1,6 +1,6 @@
name: dart_quill_delta
description: A port of quill-js-delta from typescript to dart
version: 9.5.15
version: 10.4.1
homepage: https://github.com/singerdmx/flutter-quill/tree/master/dart_quill_delta/
repository: https://github.com/singerdmx/flutter-quill/tree/master/dart_quill_delta/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/

@ -0,0 +1,103 @@
# What is an `Attribute`
An `attribute` is a property or characteristic that can be applied to text or a section of text within the editor to change its appearance or behavior. Attributes allow the user to style the text in various ways.
# How do attributes work?
An Attribute is applied to selected segments of text in the editor. Each attribute has an identifier and a value that determines how it should be applied to the text. For example, to apply bold to a text, an attribute with the identifier "bold" is used. When text is selected and an attribute is applied, the editor updates the visual representation of the text in real time.
# Scope of an `Attribute`
The attributes has an Scope that limit where start and end the `Attribute`. The Scope is called as `AttributeScope`. It has these options to be selected:
```dart
enum AttributeScope {
inline, // just the selected text will apply the attribute (like: bold, italic or strike)
block, // all the paragraph will apply the attribute (like: Header, Alignment or CodeBlock)
embeds, // the attr will be taked as a different part of any paragraph or line, working as a block (By now not works as an inline)
ignore, // the attribute can be applied, but on Retain operations will be ignored
}
```
# How looks a `Attribute`
The original `Attribute` class that you need to extend from if you want to create any custom attribute looks like:
```dart
class Attribute<T> {
const Attribute(
this.key,
this.scope,
this.value,
);
/// Unique key of this attribute.
final String key;
final AttributeScope scope;
final T value;
}
```
The key of any `Attribute` must be **unique** to avoid any conflict with the default implementations.
#### Why `Attribute` class contains a **Generic** as a value
This is the same reason why we can create `Block` styles, `Inline` styles and `Custom` styles. Having a **Generic** type value let us define any value as we want to recognize them later and apply it.
### Example of an default attribute
##### Inline Scope:
```dart
class BoldAttribute extends Attribute<bool> {
const BoldAttribute() : super('bold', AttributeScope.inline, true);
}
```
##### Block Scope:
```dart
class HeaderAttribute extends Attribute<int?> {
const HeaderAttribute({int? level})
: super('header', AttributeScope.block, level);
}
```
If you want to see an example of an embed implementation you can see it [here](https://github.com/singerdmx/flutter-quill/blob/master/doc/custom_embed_blocks.md)
### Example of a Custom Inline `Attribute`
##### The Attribute
```dart
import 'package:flutter_quill/flutter_quill.dart';
const String highlightKey = 'highlight';
const AttributeScope highlightScope = AttributeScope.inline;
class HighlightAttr extends Attribute<bool?> {
HighlightAttr(bool? value) : super(highlightKey, highlightScope, value);
}
```
##### Where should we add this `HighlightAttr`?
On `QuillEditor` or `QuillEditorConfigurations` **doesn't exist** a param that let us pass our `Attribute` implementations. To make this more easy, we can use just `customStyleBuilder` param from `QuillEditorConfigurations`, that let us define a function to return a `TextStyle`. With this, we can define now our `HighlightAttr`
##### The editor
```dart
QuillEditor.basic(
controller: controller,
configurations: QuillEditorConfigurations(
customStyleBuilder: (Attribute<dynamic> attribute) {
if (attribute.key.equals(highlightKey)) {
return TextStyle(color: Colors.black, backgroundColor: Colors.yellow);
}
//default paragraph style
return TextStyle();
},
),
);
```
Then, it should look as:
![HighlightAttr applied on the Quill Editor](https://github.com/user-attachments/assets/89c7bda5-f0de-4832-bcaa-8e0ccbe9be18)

@ -22,6 +22,7 @@ Each `QuillCustomButton` is used as part of the `customButtons` option as follow
```dart
QuillToolbar.simple(
controller: _controller,
configurations: QuillSimpleToolbarConfigurations(
customButtons: [
QuillToolbarCustomButtonOptions(

@ -0,0 +1,68 @@
# Search
You can search the text of your document using the search toolbar button.
Enter the text and use the up/down buttons to move to the previous/next selection.
Use the 3 vertical dots icon to turn on case-sensitivity or whole word constraints.
## Search configuration options
By default, the content of Embed objects are not searched.
You can enable search by setting the [searchEmbedMode] in searchConfigurations:
```dart
MyQuillEditor(
controller: _controller,
configurations: QuillEditorConfigurations(
searchConfigurations: const QuillSearchConfigurations(
searchEmbedMode: SearchEmbedMode.plainText,
),
),
...
),
```
### SearchEmbedMode.none (default option)
Embed objects will not be included in searches.
### SearchEmbedMode.rawData
This is the simplest search option when your Embed objects use simple text that is also displayed to the user.
This option allows searching within custom Embed objects using the node's raw data [Embeddable.data].
### SearchEmbedMode.plainText
This option is best for complex Embeds where the raw data contains text that is not visible to the user and/or contains textual data that is not suitable for searching.
For example, searching for '2024' would not be meaningful if the raw data is the full path of an image object (such as /user/temp/20240125/myimage.png).
In this case the image would be shown as a search hit but the user would not know why.
This option allows searching within custom Embed objects using an override to the [toPlainText] method.
```dart
class MyEmbedBuilder extends EmbedBuilder {
@override
String toPlainText(Embed node) {
/// Convert [node] to the text that can be searched.
/// For example: convert to MyEmbeddable and use the
/// properties to return the searchable text.
final m = MyEmbeddable(node.value.data);
return '${m.property1}\t${m.property2}';
}
...
```
If [toPlainText] is not overridden, the base class implementation returns [Embed.kObjectReplacementCharacter] which is not searchable.
### Strategy for mixed complex and simple Embed objects
Select option [SearchEmbedMode.plainText] and override [toPlainText] to provide the searchable text. For your simple Embed objects provide the following override:
```dart
class MySimpleEmbedBuilder extends EmbedBuilder {
@override
String toPlainText(Embed node) {
return node.value.data;
}
...
```

@ -98,10 +98,8 @@ Future<void> _addEditNote(BuildContext context, {Document? document}) async {
],
),
content: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
controller: quillEditorController,
readOnly: false,
),
controller: quillEditorController,
configurations: const QuillEditorConfigurations(),
),
),
);

@ -0,0 +1,252 @@
# What is Delta?
`Delta` is a structured format used to represent text editing operations consistently and efficiently. It is especially useful in collaborative editors where multiple users may be editing the same document simultaneously.
## How does Delta work?
`Delta` consists of a list of operations. Each operation describes a change in the document's content. The operations can be of three types: insertion (`insert`), deletion (`delete`), and retention (`retain`). These operations are combined to describe any change in the document's state.
You can import `Delta` and `Operation` class using:
```dart
import 'package:flutter_quill/dart_quill_delta.dart';
```
# What is a `Operation`?
Operations are the actions performed on the document to modify its content. Each operation can be an insertion, deletion, or retention, and is executed sequentially to transform the document's state.
## How Do `Operations` Work?
`Operations` are applied in the order they are defined in the `Delta`. Starting with the initial state of the `Document`, the operations are applied one by one, updating the document's state at each step.
Example of a `Operation` Code:
```dart
[
// Adds the text "Hello" to the editor's content
{ "insert": "Hello" },
// Retains the first 5 characters of the existing content,
// and applies the "bold" attribute to those characters.
{ "retain": 5, "attributes": { "bold": true } },
// Deletes 2 characters starting from the current position in the editor's content.
{ "delete": 2 }
]
```
# Types of Operations in Delta
## 1. Insertion (`Insert`)
An insertion adds new content to the document. The `Insert` operation contains the text or data being added.
Example of `Insert` operation:
```dart
import 'package:flutter_quill/dart_quill_delta.dart';
void main() {
// Create a Delta with a text insertion
final delta = Delta()
..insert('Hello, world!\n')
..insert('This is an example.\n', {'bold': true})
..delete(10); // Remove the first 10 characters
print(delta); // Output: [{insert: "Hello, world!\n"}, {insert: "This is an example.\n", attributes: {bold: true}}, {delete: 10}]
}
```
## 2. Deletion (`Delete`)
In Quill, operations are a way to represent changes to the editor's content. Each operation has a type and a set of properties that indicate what has changed and how.`Delete` operations are a specific type of operation that is used to remove content from the editor.
## Delete Operations
A Delete operation is used to remove a portion of the editor's content. The Delete operation has the following format:
```dart
Delta()
..retain(<number>)
..delete(<number>);
```
Where:
- **retain**: (Optional) The number of characters to retain before deletion is performed.
- **delete**: The number of characters to delete.
Basic example
Let's say you have the following content in the editor:
```Arduino
"Hello, world!"
```
And you want to remove the word "world". The corresponding Delete operation could be:
```dart
Delta()
..retain(6)
..delete(7);
```
Here the first **7** characters are being retained ("Hello, ") and then 6 characters are being removed ("world!").
### Behavior of Delete Operations
**Text Deletion**: The `Delete` operation removes text in the editor document. The characters removed are those that are in the range specified by the operation.
**Combination with retain**: The `Delete` operation is often combined with the retain operation to specify which part of the content should remain intact and which part should be removed. For example, if you want to delete a specific section of text, you can use retain to keep the text before and after the section to be deleted.
**Range Calculation**: When a `Delete` operation is applied, the range of text to be deleted is calculated based on the value of retain and delete. It is important to understand how retain and delete are combined to perform correct deletion.
Example of `Delete` operation using `QuillController`
```dart
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/dart_quill_delta.dart';
QuillController _quillController = QuillController(
document: Document.fromJson([{'insert': 'Hello, world!'}]),
selection: TextSelection.collapsed(offset: 0),
);
// Create a delta with the retain and delete operations
final delta = Delta()
..retain(6) // Retain "Hello, "
..delete(7); // Delete "world!"
// Apply the delta to update the content of the editor
_quillController.compose(delta, ChangeSource.local);
```
In this example, the current content of the editor is updated to reflect the removal of the word "world."
## 3. Retention (`Retain`)
`Retain` operations are particularly important because they allow you to apply attributes to specific parts of the content without modifying the content itself. A Retain operation consists of two parts:
- **Index**: The length of the content to retain unchanged.
- **Attributes**: An optional object containing the attributes to apply.
Example of a `Retain` Operation
Suppose we have the following content in an editor:
```arduino
"Hello world"
```
And we want to apply bold formatting to the word "world." The `Retain` operation would be represented in a `Delta` as follows:
```dart
[
{ "insert": "Hello, " },
{ "retain": 7 },
{ "retain": 5, "attributes": { "bold": true } }
]
```
This Delta is interpreted as follows:
- `{ "retain": 7 }`: Retains the first **7** characters ("Hello, ").
- `{ "retain": 5, "attributes": { "bold": true } }`: Retains the next **5** characters ("world") and applies the bold attribute.
### Applications of Retain
Retain operations are useful for various tasks in document editing, such as:
- **Text Formatting**: Applying styles (bold, italic, underline, etc.) to specific segments without altering the content.
- **Annotations**: Adding metadata or annotations to specific sections of text.
- **Content Preservation**: Ensuring that certain parts of the document remain unchanged during complex editing operations.
Using Directly `Delta` class:
```dart
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/dart_quill_delta.dart';
void main() {
// Create a Delta that retains 10 characters
QuillController _quillController = QuillController(
document: Document.fromJson([{'insert': 'Hello, world!'}]),
selection: TextSelection.collapsed(offset: 0),
);
// Create a delta with the retain and delete operations
final delta = Delta()
..retain(6) // Retain "Hello, "
// Apply the delta to update the content of the editor
_quillController.compose(delta, ChangeSource.local);
}
```
# Transformations
Transformations are used to combine two Deltas and produce a third Delta that represents the combination of both operations.
Example 1: Transformation with Deletions
Deltas to combine:
- **Delta A**: `[{insert: "Flutter"}, {retain: 3}, {insert: "Quill"}]`
- **Delta B**: `[{retain: 6}, {delete: 4}, {insert: "Editor"}]`
```dart
import 'package:flutter_quill/dart_quill_delta.dart' as quill;
void main() {
// Defining Delta A
final deltaA = quill.Delta()
..insert('Flutter')
..retain(3)
..insert('Quill');
// Defining Delta B
final deltaB = quill.Delta()
..retain(7) // retain: Flutter
..delete(5) // delete: Quill
..insert('Editor');
// applying transformation
final result = deltaA.transform(deltaB);
print(result.toJson()); // output: [{insert: "FlutterEditor"}]
}
```
Example 2: Complex Transformation
Deltas to combine:
- **Delta A**: `[{insert: "Hello World"}]`
- **Delta B**: `[{retain: 6}, {delete: 5}, {insert: "Flutter"}]`
```dart
import 'package:flutter_quill/dart_quill_delta.dart' as quill;
void main() {
// Defining Delta A
final deltaA = quill.Delta()
..insert('Hello World');
// Defining Delta B
final deltaB = quill.Delta()
..retain(6) // retain: 'Hello '
..delete(5) // delete: 'World'
..insert('Flutter');
// Applying transformations
final result = deltaA.transform(deltaB);
print(result.toJson()); // output: [{insert: "Hello Flutter"}]
}
```
# Why Use Delta Instead of Another Format?
Delta offers a structured and efficient way to represent changes in text documents, especially in collaborative environments. Its operation-based design allows for easy synchronization, transformation, and conflict handling, which is essential for real-time text editing applications. Other formats may not provide the same level of granularity and control over edits and transformations.

@ -0,0 +1,142 @@
## Rule
`Rule` in `flutter_quill` is a handler for specific operations within the editor. They define how to apply, modify, or delete content based on user actions. Each Rule corresponds to a type of operation that the editor can perform.
### RuleType
There are three main `RuleTypes` supported in `flutter_quill`, each serving a distinct purpose:
- **insert**: Handles operations related to inserting new content into the editor. This includes inserting text, images, or any other supported media.
- **delete**: Manages operations that involve deleting content from the editor. This can include deleting characters, lines, or entire blocks of content.
- **format**: Deals with operations that apply formatting changes to the content in the editor. This could involve applying styles such as bold, italic, underline, or changing text alignment, among others.
### How Rules Work
When a user interacts with the editor in `flutter_quill`, their actions are translated into one of the predefined `RuleType`. For instance:
- When the user types a new character, an **insert** Rule is triggered to handle the insertion of that character into the editor's content.
- When the user selects and deletes a block of text, a **delete** Rule is used to remove that selection from the editor.
- Applying formatting, such as making text bold or italic, triggers a **format** Rule to update the style of the selected text.
`Rule` is designed to be modular and configurable, allowing developers to extend or customize editor behavior as needed. By defining how each RuleType operates, `flutter_quill` ensures consistent and predictable behavior across different editing operations.
### Example of a custom `Rule`
In this case, we will use a simple example. We will create a `Rule` that is responsible for detecting any word that is surrounded by "*" just as any `Markdown` editor would do for italics.
In order for it to be detected while the user writes character by character, what we will do is extend the `InsertRule` class that is responsible for being called while the user writes a word character by character.
```dart
/// Applies italic format to text segment (which is surrounded by *)
/// when user inserts space character after it.
class AutoFormatItalicRule extends InsertRule {
const AutoFormatItalicRule();
static const _italicPattern = r'\*(.+)\*';
RegExp get italicRegExp => RegExp(
_italicPattern,
caseSensitive: false,
);
@override
Delta? applyRule(
Document document,
int index, {
int? len,
Object? data,
Attribute? attribute,
Object? extraData,
}) {
// Only format when inserting text.
if (data is! String) return null;
// Get current text.
final entireText = document.toPlainText();
// Get word before insertion.
final leftWordPart = entireText
// Keep all text before insertion.
.substring(0, index)
// Keep last paragraph.
.split('\n')
.last
// Keep last word.
.split(' ')
.last
.trimLeft();
// Get word after insertion.
final rightWordPart = entireText
// Keep all text after insertion.
.substring(index)
// Keep first paragraph.
.split('\n')
.first
// Keep first word.
.split(' ')
.first
.trimRight();
// Build the segment of affected words.
final affectedWords = '$leftWordPart$data$rightWordPart';
// Check for italic patterns.
final italicMatches = italicRegExp.allMatches(affectedWords);
// If there are no matches, do not apply any format.
if (italicMatches.isEmpty) return null;
// Build base delta.
// The base delta is a simple insertion delta.
final baseDelta = Delta()
..retain(index)
..insert(data);
// Get unchanged text length.
final unmodifiedLength = index - leftWordPart.length;
// Create formatter delta.
// The formatter delta will include italic formatting when needed.
final formatterDelta = Delta()..retain(unmodifiedLength);
var previousEndRelativeIndex = 0;
void retainWithAttributes(int start, int end, Map<String, dynamic> attributes) {
final separationLength = start - previousEndRelativeIndex;
final segment = affectedWords.substring(start, end);
formatterDelta
..retain(separationLength)
..retain(segment.length, attributes);
previousEndRelativeIndex = end;
}
for (final match in italicMatches) {
final matchStart = match.start;
final matchEnd = match.end;
retainWithAttributes(matchStart + 1, matchEnd - 1, const ItalicAttribute().toJson());
}
// Get remaining text length.
final remainingLength = affectedWords.length - previousEndRelativeIndex;
// Remove italic from remaining non-italic text.
formatterDelta.retain(remainingLength);
// Build resulting change delta.
return baseDelta.compose(formatterDelta);
}
}
```
To apply any custom `Rule` you can use `setCustomRules` that is exposed on `Document`
```dart
quillController.document.setCustomRules([const AutoFormatItalicRule()]);
```
You can see a example video [here](https://e.pcloud.link/publink/show?code=XZ2NzgZrb888sWjuxFjzWoBpe7HlLymKp3V)

@ -6,8 +6,8 @@ with:
```dart
QuillToolbar.simple(
controller: _controller,
configurations: QuillSimpleToolbarConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(
locale: Locale('de'),
),
@ -15,8 +15,8 @@ QuillToolbar.simple(
),
Expanded(
child: QuillEditor.basic(
controller: _controller,
configurations: QuillEditorConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(
locale: Locale('de'),
),
@ -27,9 +27,9 @@ Expanded(
## 🌐 Supported Locales
Currently, translations are available for these 40 locales:
Currently, translations are available for these 41 locales:
* `ar`, `bg`, `bn`, `cs`, `da`, `de`
* `ar`, `bg`, `bn`, `ca`, `cs`, `da`, `de`
* `en`, `en_US`, `es`, `fa`, `fr`, `he`
* `hi`, `id`, `it`, `ja`, `ko`, `ku`
* `ms`, `ne`, `nl`, `no`, `pl`, `pt`

@ -15,11 +15,22 @@ import '../../quill/samples/quill_videos_sample.dart';
import '../../settings/widgets/settings_screen.dart';
import 'example_item.dart';
class HomeScreen extends StatelessWidget {
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
static const routeName = '/home';
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void dispose() {
SpellCheckerServiceProvider.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(

@ -7,10 +7,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart'
show isAndroid, isDesktop, isIOS, isWeb;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/embeds/widgets/image.dart'
show getImageProviderByImageSource, imageFileExtensions;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter_quill_extensions/models/config/video/editor/youtube_video_support_mode.dart';
// ignore: implementation_imports
import 'package:flutter_quill_extensions/src/editor/image/widgets/image.dart'
show getImageProviderByImageSource, imageFileExtensions;
import 'package:path/path.dart' as path;
import '../../extensions/scaffold_messenger.dart';
@ -18,12 +18,14 @@ import 'embeds/timestamp_embed.dart';
class MyQuillEditor extends StatelessWidget {
const MyQuillEditor({
required this.controller,
required this.configurations,
required this.scrollController,
required this.focusNode,
super.key,
});
final QuillController controller;
final QuillEditorConfigurations configurations;
final ScrollController scrollController;
final FocusNode focusNode;
@ -34,6 +36,7 @@ class MyQuillEditor extends StatelessWidget {
return QuillEditor(
scrollController: scrollController,
focusNode: focusNode,
controller: controller,
configurations: configurations.copyWith(
elementOptions: const QuillEditorElementOptions(
codeBlock: QuillEditorCodeBlockElementOptions(
@ -51,8 +54,9 @@ class MyQuillEditor extends StatelessWidget {
height: 1.15,
fontWeight: FontWeight.w300,
),
HorizontalSpacing.zero,
const VerticalSpacing(16, 0),
const VerticalSpacing(0, 0),
VerticalSpacing.zero,
null,
),
sizeSmall: defaultTextStyle.style.copyWith(fontSize: 9),

@ -31,16 +31,16 @@ class MyQuillToolbar extends StatelessWidget {
) async {
final croppedFile = await ImageCropper().cropImage(
sourcePath: image,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Cropper',
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
@ -48,6 +48,13 @@ class MyQuillToolbar extends StatelessWidget {
),
IOSUiSettings(
title: 'Cropper',
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
),
WebUiSettings(
context: context,
@ -203,8 +210,12 @@ class MyQuillToolbar extends StatelessWidget {
);
}
return QuillToolbar.simple(
controller: controller,
/// configurations parameter:
/// Optional: if not provided will use the configuration set when the controller was instantiated.
/// Override: Provide parameter here to override the default configuration - useful if configuration will change.
configurations: QuillSimpleToolbarConfigurations(
controller: controller,
showAlignmentButtons: true,
multiRowsDisplay: true,
fontFamilyValues: {

@ -3,7 +3,10 @@ import 'dart:convert' show jsonEncode;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'
show FlutterQuillEmbeds, QuillSharedExtensionsConfigurations;
show
FlutterQuillEmbeds,
FlutterQuillExtensions,
QuillSharedExtensionsConfigurations;
import 'package:share_plus/share_plus.dart' show Share;
import '../../extensions/scaffold_messenger.dart';
@ -11,6 +14,8 @@ import '../shared/widgets/home_screen_button.dart';
import 'my_quill_editor.dart';
import 'my_quill_toolbar.dart';
var _isSpellcheckerActive = false;
@immutable
class QuillScreenArgs {
const QuillScreenArgs({required this.document});
@ -33,6 +38,7 @@ class QuillScreen extends StatefulWidget {
}
class _QuillScreenState extends State<QuillScreen> {
/// Instantiate the controller
final _controller = QuillController.basic();
final _editorFocusNode = FocusNode();
final _editorScrollController = ScrollController();
@ -55,10 +61,28 @@ class _QuillScreenState extends State<QuillScreen> {
@override
Widget build(BuildContext context) {
_controller.readOnly = _isReadOnly;
if (!_isSpellcheckerActive) {
_isSpellcheckerActive = true;
FlutterQuillExtensions.useSpellCheckerService(
Localizations.localeOf(context).languageCode);
}
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Quill'),
actions: [
IconButton(
tooltip: 'Spell-checker',
onPressed: () {
SpellCheckerServiceProvider.toggleState();
setState(() {});
},
icon: Icon(
Icons.document_scanner,
color: SpellCheckerServiceProvider.isServiceActive()
? Colors.red.withOpacity(0.5)
: null,
),
),
IconButton(
tooltip: 'Share',
onPressed: () {
@ -101,9 +125,12 @@ class _QuillScreenState extends State<QuillScreen> {
builder: (context) {
return Expanded(
child: MyQuillEditor(
controller: _controller,
configurations: QuillEditorConfigurations(
searchConfigurations: const QuillSearchConfigurations(
searchEmbedMode: SearchEmbedMode.plainText,
),
sharedConfigurations: _sharedConfigurations,
controller: _controller,
),
scrollController: _editorScrollController,
focusNode: _editorFocusNode,

@ -18,14 +18,14 @@ class _SimpleScreenState extends State<SimpleScreen> {
body: Column(
children: [
QuillToolbar.simple(
configurations:
QuillSimpleToolbarConfigurations(controller: _controller),
controller: _controller,
configurations: const QuillSimpleToolbarConfigurations(),
),
Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(
controller: _controller,
padding: const EdgeInsets.all(16),
controller: _controller,
configurations: const QuillEditorConfigurations(
padding: EdgeInsets.all(16),
),
),
),

@ -18,8 +18,6 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- printing (1.0.0):
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- sqflite (0.0.3):
@ -42,7 +40,6 @@ DEPENDENCIES:
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `Flutter/ephemeral/.symlinks/plugins/printing/macos`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
- super_native_extensions (from `Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos`)
@ -70,8 +67,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
printing:
:path: Flutter/ephemeral/.symlinks/plugins/printing/macos
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
sqflite:
@ -86,19 +81,18 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2
flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
printing: 1dd6a1fce2209ec240698e2439a4adbb9b427637
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
video_player_avfoundation: 2b4384f3b157206b5e150a0083cdc0c905d260d3
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
PODFILE CHECKSUM: 7159dd71cf9f57a5669bb2dee7a5030dbcc0483f

@ -1,7 +1,7 @@
import Cocoa
import FlutterMacOS
@NSApplicationMain
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true

@ -13,10 +13,10 @@ dependencies:
cupertino_icons: ^1.0.6
# Flutter Quill Packages
flutter_quill: ^9.3.4
dart_quill_delta: ^9.3.4
flutter_quill_extensions: ^9.3.4
flutter_quill_test: ^9.3.4
flutter_quill: ^10.0.0
dart_quill_delta: ^10.0.0
flutter_quill_extensions: ^10.0.0
flutter_quill_test: ^10.0.0
# Dart Packages
path: ^1.8.3
equatable: ^2.0.5
@ -35,7 +35,7 @@ dependencies:
json_annotation: ^4.8.1
# Plugins
image_cropper: ^5.0.1
image_cropper: ^8.0.1
path_provider: ^2.1.2
# For drag and drop feature
desktop_drop: ^0.4.4
@ -99,4 +99,4 @@ flutter:
fonts:
- asset: assets/fonts/RobotoMono-Regular.ttf
flutter_gen:
flutter_gen:

@ -4,6 +4,304 @@
All notable changes to this project will be documented in this file.
## 10.4.1
* Chore: improve Spell checker API to the example by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2133
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.4.0...v10.4.1
## 10.4.0
* Copy TapAndPanGestureRecognizer from TextField by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2128
* enhance stringToColor with a custom defined palette from `DefaultStyles` by @vishna in https://github.com/singerdmx/flutter-quill/pull/2095
* Feat: include spell checker for example app by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2127
## New Contributors
* @vishna made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2095
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.3...v10.4.0
## 10.3.2
* Fix: Loss of style when backspace by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2125
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.1...v10.3.2
## 10.3.1
* Chore: Move spellchecker service to extensions by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2120
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.0...v10.3.1
## 10.3.0
* Feat: Spellchecker for Flutter Quill by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2118
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.1...v10.3.0
## 10.2.1
* Fix: context menu is visible even when selection is collapsed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2116
* Fix: unsafe operation while getting overlayEntry in text_selection by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2117
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.0...v10.2.1
## 10.2.0
* refactor!: restructure project into modular architecture for flutter_quill_extensions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2106
* Fix: Link selection and editing by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2114
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.10...v10.2.0
## 10.1.10
* Fix(example): image_cropper outdated version by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2100
* Using dart.library.js_interop instead of dart.library.html by @h1376h in https://github.com/singerdmx/flutter-quill/pull/2103
## New Contributors
* @h1376h made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2103
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.9...v10.1.10
## 10.1.9
* restore ability to pass in key to QuillEditor by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2093
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.8...v10.1.9
## 10.1.8
* Enhancement: Search within Embed objects by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2090
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.7...v10.1.8
## 10.1.7
* Feature/allow shortcut override by @InstrinsicAutomations in https://github.com/singerdmx/flutter-quill/pull/2089
## New Contributors
* @InstrinsicAutomations made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2089
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.6...v10.1.7
## 10.1.6
* fixed #1295 Double click to select text sometimes doesn't work. by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2086
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.5...v10.1.6
## 10.1.5
* ref: add `VerticalSpacing.zero` and `HorizontalSpacing.zero` named constants by @adil192 in https://github.com/singerdmx/flutter-quill/pull/2083
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.4...v10.1.5
## 10.1.4
* Fix: collectStyles for lists and alignments by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2082
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.3...v10.1.4
## 10.1.3
* Move Controller outside of configurations data class by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2078
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.2...v10.1.3
## 10.1.2
* Fix Multiline paste with attributes and embeds by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2074
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.1...v10.1.2
## 10.1.1
* Toolbar dividers fixes + Docs updates by @troyanskiy in https://github.com/singerdmx/flutter-quill/pull/2071
## New Contributors
* @troyanskiy made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2071
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.0...v10.1.1
## 10.1.0
* Feat: support for customize copy and cut Embeddables to Clipboard by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2067
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.10...v10.1.0
## 10.0.10
* fix: Hide selection toolbar if editor loses focus by @huandu in https://github.com/singerdmx/flutter-quill/pull/2066
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.9...v10.0.10
## 10.0.9
* Fix: manual checking of directionality by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2063
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.8...v10.0.9
## 10.0.8
* feat: add callback to handle performAction by @huandu in https://github.com/singerdmx/flutter-quill/pull/2061
* fix: Invalid selection when tapping placeholder text by @huandu in https://github.com/singerdmx/flutter-quill/pull/2062
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.7...v10.0.8
## 10.0.7
* Fix: RTL issues by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2060
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.6...v10.0.7
## 10.0.6
* fix: textInputAction is not set when creating QuillRawEditorConfiguration by @huandu in https://github.com/singerdmx/flutter-quill/pull/2057
## New Contributors
* @huandu made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2057
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.5...v10.0.6
## 10.0.5
* Add tests for PreserveInlineStylesRule and fix link editing. Other minor fixes. by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2058
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.4...v10.0.5
## 10.0.4
* Add ability to set up horizontal spacing for block style by @dimkanovikov in https://github.com/singerdmx/flutter-quill/pull/2051
* add catalan language by @spilioio in https://github.com/singerdmx/flutter-quill/pull/2054
## New Contributors
* @dimkanovikov made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2051
* @spilioio made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2054
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.3...v10.0.4
## 10.0.3
* doc(Delta): more documentation about Delta by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2042
* doc(attribute): added documentation about Attribute class and how create one by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2048
* if magnifier removes toolbar, restore it when it is hidden by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2049
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.2...v10.0.3
## 10.0.2
* chore(scripts): migrate the scripts from sh to dart by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2036
* Have the ability to create custom rules, closes #1162 by @Guillergood in https://github.com/singerdmx/flutter-quill/pull/2040
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.1...v10.0.2
## 10.0.1
This release is identical to [10.0.0](https://github.com/singerdmx/flutter-quill/releases/tag/v10.0.0) with a fix that addresses issue #2034 by requiring `10.0.0` as the minimum version for quill related dependencies.
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.0...v10.0.1
## 10.0.0
* refactor: restructure project into modular architecture for flutter_quill by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2032
* chore: update GitHub PR template by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2033
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.6.0...v10.0.0
## 9.6.0
* [feature] : quill add magnifier by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2026
## New Contributors
* @demoYang made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2026
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.23...v9.6.0
## 9.5.23
* add untranslated Kurdish keys by @Xoshbin in https://github.com/singerdmx/flutter-quill/pull/2029
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.22...v9.5.23
## 9.5.22
* Fix outdated contributor guide link on PR template by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2027
* Fix(rule): PreserveInlineStyleRule assume the type of the operation data and throw stacktrace by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2028
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.21...v9.5.22
## 9.5.21
* Fix: Key actions not being handled by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2025
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.20...v9.5.21
## 9.5.20
* Remove useless delta_x_test by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2017
* Update flutter_quill_delta_from_html package on pubspec.yaml by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2018
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.19...v9.5.20
## 9.5.19
* fixed #1835 Embed Reloads on Cmd Key Press by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2013
## New Contributors
* @li8607 made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2013
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.18...v9.5.19
## 9.5.18
* Refactor: Moved core link button functions to link.dart by @Alspb in https://github.com/singerdmx/flutter-quill/pull/2008
* doc: more documentation about Rules by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2014
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.17...v9.5.18
## 9.5.17
* Feat(config): added option to disable automatic list conversion by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2011
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.16...v9.5.17
## 9.5.16
* chore: drop support for HTML, PDF, and Markdown converting functions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/1997
* docs(readme): update the extensions package to document the Rich Text Paste feature on web by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2001
* Fix(test): delta_x tests fail by wrong expected Delta for video embed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2010
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.15...v9.5.16
## 9.5.15
* Update delta_from_html to fix nested lists issues and more by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2000

@ -50,9 +50,10 @@ dependencies:
```yaml
dependencies:
flutter_quill_extensions:
git: https://github.com/singerdmx/flutter-quill.git
path: flutter_quill_extensions
ref: v<latest-version-here>
git:
url: https://github.com/singerdmx/flutter-quill.git
ref: v<latest-version-here>
path: flutter_quill_extensions
```
## 🛠 Platform Specific Configurations
@ -103,8 +104,8 @@ Set the `embedBuilders` and `embedToolbar` params in configurations of `QuillEdi
**Quill Toolbar**:
```dart
QuillToolbar(
configurations: QuillToolbarConfigurations(
QuillToolbar.simple(
configurations: QuillSimpleToolbarConfigurations(
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
),
),

@ -1,12 +0,0 @@
import 'package:cross_file/cross_file.dart' show XFile;
typedef MediaFileUrl = String;
typedef MediaFilePicker = Future<XFile?> Function(QuillMediaType mediaType);
typedef MediaPickedCallback = Future<MediaFileUrl> Function(XFile file);
enum QuillMediaType { image, video }
extension QuillMediaTypeX on QuillMediaType {
bool get isImage => this == QuillMediaType.image;
bool get isVideo => this == QuillMediaType.video;
}

@ -1,277 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' show QuillDialogTheme;
import 'package:flutter_quill/translations.dart';
import '../../utils/patterns.dart';
enum LinkType {
video,
image,
}
class TypeLinkDialog extends StatefulWidget {
const TypeLinkDialog({
required this.linkType,
this.dialogTheme,
this.link,
this.linkRegExp,
super.key,
});
final QuillDialogTheme? dialogTheme;
final String? link;
final RegExp? linkRegExp;
final LinkType linkType;
@override
TypeLinkDialogState createState() => TypeLinkDialogState();
}
class TypeLinkDialogState extends State<TypeLinkDialog> {
late String _link;
late TextEditingController _controller;
RegExp? _linkRegExp;
@override
void initState() {
super.initState();
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
_linkRegExp = widget.linkRegExp;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
content: TextField(
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
maxLines: null,
style: widget.dialogTheme?.inputTextStyle,
decoration: InputDecoration(
labelText: context.loc.pasteLink,
hintText: widget.linkType == LinkType.image
? context.loc.pleaseEnterAValidImageURL
: context.loc.pleaseEnterAValidVideoURL,
labelStyle: widget.dialogTheme?.labelTextStyle,
floatingLabelStyle: widget.dialogTheme?.labelTextStyle,
),
autofocus: true,
onChanged: _linkChanged,
controller: _controller,
onEditingComplete: () {
if (!_canPress()) {
return;
}
_applyLink();
},
),
actions: [
TextButton(
onPressed: _canPress() ? _applyLink : null,
child: Text(
context.loc.ok,
style: widget.dialogTheme?.labelTextStyle,
),
),
],
);
}
void _linkChanged(String value) {
setState(() {
_link = value;
});
}
void _applyLink() {
Navigator.pop(context, _link.trim());
}
RegExp get linkRegExp {
final customRegExp = _linkRegExp;
if (customRegExp != null) {
return customRegExp;
}
switch (widget.linkType) {
case LinkType.video:
if (youtubeRegExp.hasMatch(_link)) {
return youtubeRegExp;
}
return videoRegExp;
case LinkType.image:
return imageRegExp;
}
}
bool _canPress() {
if (_link.isEmpty) {
return false;
}
if (widget.linkType == LinkType.image) {}
return _link.isNotEmpty && linkRegExp.hasMatch(_link);
}
}
// @immutable
// class ImageVideoUtils {
// const ImageVideoUtils._();
// static Future<MediaPickSetting?> selectMediaPickSetting(
// BuildContext context,
// ) =>
// showDialog<MediaPickSetting>(
// context: context,
// builder: (ctx) => AlertDialog(
// contentPadding: EdgeInsets.zero,
// content: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// TextButton.icon(
// icon: const Icon(
// Icons.collections,
// color: Colors.orangeAccent,
// ),
// label: Text('Gallery'.i18n),
// onPressed: () => Navigator.pop(ctx,
// MediaPickSetting.gallery),
// ),
// TextButton.icon(
// icon: const Icon(
// Icons.link,
// color: Colors.cyanAccent,
// ),
// label: Text('Link'.i18n),
// onPressed: () => Navigator.pop(ctx, MediaPickSetting.link),
// )
// ],
// ),
// ),
// );
// /// For image picking logic
// static Future<void> handleImageButtonTap(
// BuildContext context,
// QuillController controller,
// ImageSource imageSource,
// OnImagePickCallback onImagePickCallback, {
// FilePickImpl? filePickImpl,
// WebImagePickImpl? webImagePickImpl,
// }) async {
// String? imageUrl;
// if (kIsWeb) {
// if (webImagePickImpl != null) {
// imageUrl = await webImagePickImpl(onImagePickCallback);
// return;
// }
// final file = await ImagePicker()
//.pickImage(source: ImageSource.gallery);
// imageUrl = file?.path;
// if (imageUrl == null) {
// return;
// }
// } else if (isMobile()) {
// imageUrl = await _pickImage(imageSource, onImagePickCallback);
// } else {
// assert(filePickImpl != null, 'Desktop must provide filePickImpl');
// imageUrl =
// await _pickImageDesktop
//(context, filePickImpl!, onImagePickCallback);
// }
// if (imageUrl == null) {
// return;
// }
// controller.insertImageBlock(
// imageUrl: imageUrl,
// );
// }
// static Future<String?> _pickImage(
// ImageSource source,
// OnImagePickCallback onImagePickCallback,
// ) async {
// final pickedFile = await ImagePicker().pickImage(source: source);
// if (pickedFile == null) {
// return null;
// }
// return onImagePickCallback(File(pickedFile.path));
// }
// static Future<String?> _pickImageDesktop(
// BuildContext context,
// FilePickImpl filePickImpl,
// OnImagePickCallback onImagePickCallback,
// ) async {
// final filePath = await filePickImpl(context);
// if (filePath == null || filePath.isEmpty) return null;
// final file = File(filePath);
// return onImagePickCallback(file);
// }
// /// For video picking logic
// static Future<void> handleVideoButtonTap(
// BuildContext context,
// QuillController controller,
// ImageSource videoSource,
// OnVideoPickCallback onVideoPickCallback, {
// FilePickImpl? filePickImpl,
// WebVideoPickImpl? webVideoPickImpl,
// }) async {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// String? videoUrl;
// if (kIsWeb) {
// assert(
// webVideoPickImpl != null,
// 'Please provide webVideoPickImpl for Web '
// 'in the options of this button',
// );
// videoUrl = await webVideoPickImpl!(onVideoPickCallback);
// } else if (isMobile()) {
// videoUrl = await _pickVideo(videoSource, onVideoPickCallback);
// } else {
// assert(filePickImpl != null, 'Desktop must provide filePickImpl');
// videoUrl =
// await _pickVideoDesktop(context, filePickImpl!,
// onVideoPickCallback);
// }
// if (videoUrl != null) {
// controller.replaceText(index, length, BlockEmbed.video(videoUrl),
// null);
// }
// }
// static Future<String?> _pickVideo(
// ImageSource source, OnVideoPickCallback onVideoPickCallback) async {
// final pickedFile = await ImagePicker().pickVideo(source: source);
// if (pickedFile == null) {
// return null;
// }
// return onVideoPickCallback(File(pickedFile.path));
// }
// static Future<String?> _pickVideoDesktop(
// BuildContext context,
// FilePickImpl filePickImpl,
// OnVideoPickCallback onVideoPickCallback) async {
// final filePath = await filePickImpl(context);
// if (filePath == null || filePath.isEmpty) return null;
// final file = File(filePath);
// return onVideoPickCallback(file);
// }
// }

@ -1,537 +0,0 @@
// // ignore_for_file: use_build_context_synchronously
// import 'dart:math' as math;
// import 'dart:ui';
// import 'package:flutter/foundation.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_quill/extensions.dart';
// import 'package:flutter_quill/flutter_quill.dart';
// import 'package:flutter_quill/translations.dart';
// import 'package:image_picker/image_picker.dart';
// import '../../../models/config/toolbar/buttons/media_button.dart';
// import '../../embed_types.dart';
// import '../utils/image_video_utils.dart';
// /// Widget which combines [ImageButton] and [VideButton] widgets. This widget
// /// has more customization and uses dialog similar to one which is used
// /// on [http://quilljs.com].
// class QuillToolbarMediaButton extends StatelessWidget {
// QuillToolbarMediaButton({
// required this.controller,
// this.options,
// super.key,
// }) : assert(options.type == QuillMediaType.image,
// 'Video selection is not supported yet');
// final QuillController controller;
// final QuillToolbarMediaButtonOptions options;
// double _iconSize(BuildContext context) {
// final baseFontSize = baseButtonExtraOptions(context).globalIconSize;
// final iconSize = options.iconSize;
// return iconSize ?? baseFontSize;
// }
// VoidCallback? _afterButtonPressed(BuildContext context) {
// return options.afterButtonPressed ??
// baseButtonExtraOptions(context).afterButtonPressed;
// }
// QuillIconTheme? _iconTheme(BuildContext context) {
// return options.iconTheme ?? baseButtonExtraOptions(context).iconTheme;
// }
// QuillToolbarBaseButtonOptions baseButtonExtraOptions(
//BuildContext context) {
// return context.requireQuillToolbarBaseButtonOptions;
// }
// (IconData, String) get _defaultData {
// switch (options.type) {
// case QuillMediaType.image:
// return (Icons.perm_media, 'Photo media button');
// case QuillMediaType.video:
// throw UnsupportedError('The video is not supported yet.');
// }
// }
// IconData _iconData(BuildContext context) {
// return options.iconData ??
// baseButtonExtraOptions(context).iconData ??
// _defaultData.$1;
// }
// String _tooltip(BuildContext context) {
// return options.tooltip ??
// baseButtonExtraOptions(context).tooltip ??
// _defaultData.$2;
// // ('Camera'.i18n);
// }
// void _sharedOnPressed(BuildContext context) {
// _onPressedHandler(context);
// _afterButtonPressed(context);
// }
// @override
// Widget build(BuildContext context) {
// final tooltip = _tooltip(context);
// final iconSize = _iconSize(context);
// final iconData = _iconData(context);
// final childBuilder =
// options.childBuilder ?? baseButtonExtraOptions(context).childBuilder;
// final iconTheme = _iconTheme(context);
// if (childBuilder != null) {
// return childBuilder(
// QuillToolbarMediaButtonOptions(
// type: options.type,
// onMediaPickedCallback: options.onMediaPickedCallback,
// onImagePickCallback: options.onImagePickCallback,
// onVideoPickCallback: options.onVideoPickCallback,
// iconData: iconData,
// afterButtonPressed: _afterButtonPressed(context),
// autovalidateMode: options.autovalidateMode,
// childrenSpacing: options.childrenSpacing,
// dialogBarrierColor: options.dialogBarrierColor,
// dialogTheme: options.dialogTheme,
// filePickImpl: options.filePickImpl,
// fillColor: options.fillColor,
// galleryButtonText: options.galleryButtonText,
// iconTheme: iconTheme,
// iconSize: iconSize,
// iconButtonFactor: iconButtonFactor,
// hintText: options.hintText,
// labelText: options.labelText,
// submitButtonSize: options.submitButtonSize,
// linkButtonText: options.linkButtonText,
// mediaFilePicker: options.mediaFilePicker,
// submitButtonText: options.submitButtonText,
// validationMessage: options.validationMessage,
// webImagePickImpl: options.webImagePickImpl,
// webVideoPickImpl: options.webVideoPickImpl,
// tooltip: options.tooltip,
// ),
// QuillToolbarMediaButtonExtraOptions(
// context: context,
// controller: controller,
// onPressed: () => _sharedOnPressed(context),
// ),
// );
// }
// final theme = Theme.of(context);
// final iconColor =
// options.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
// final iconFillColor = options.iconTheme?.iconUnselectedFillColor ??
// options.fillColor ??
// theme.canvasColor;
// return QuillToolbarIconButton(
// icon: Icon(iconData, size: iconSize, color: iconColor),
// tooltip: tooltip,
// highlightElevation: 0,
// hoverElevation: 0,
// size: iconSize * iconButtonFactor,
// fillColor: iconFillColor,
// borderRadius: iconTheme?.borderRadius ?? 2,
// onPressed: () => _sharedOnPressed(context),
// );
// }
// Future<void> _onPressedHandler(BuildContext context) async {
// if (options.onMediaPickedCallback == null) {
// _inputLink(context);
// return;
// }
// final mediaSource = await showDialog<MediaPickSetting>(
// context: context,
// builder: (_) => MediaSourceSelectorDialog(
// dialogTheme: options.dialogTheme,
// galleryButtonText: options.galleryButtonText,
// linkButtonText: options.linkButtonText,
// ),
// );
// if (mediaSource == null) {
// return;
// }
// switch (mediaSource) {
// case MediaPickSetting.gallery:
// await _pickImage();
// break;
// case MediaPickSetting.link:
// _inputLink(context);
// break;
// case MediaPickSetting.camera:
// await ImageVideoUtils.handleImageButtonTap(
// context,
// controller,
// ImageSource.camera,
// options.onImagePickCallback,
// filePickImpl: options.filePickImpl,
// webImagePickImpl: options.webImagePickImpl,
// );
// break;
// case MediaPickSetting.video:
// await ImageVideoUtils.handleVideoButtonTap(
// context,
// controller,
// ImageSource.camera,
// options.onVideoPickCallback,
// filePickImpl: options.filePickImpl,
// webVideoPickImpl: options.webVideoPickImpl,
// );
// break;
// }
// }
// Future<void> _pickImage() async {
// if (!(kIsWeb || isMobile() || isDesktop())) {
// throw UnsupportedError(
// 'Unsupported target platform: ${defaultTargetPlatform.name}',
// );
// }
// final mediaFileUrl = await _pickMediaFileUrl();
// if (mediaFileUrl != null) {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// controller.replaceText(
// index,
// length,
// BlockEmbed.image(mediaFileUrl),
// null,
// );
// }
// }
// Future<MediaFileUrl?> _pickMediaFileUrl() async {
// final mediaFile = await options.mediaFilePicker?.call(options.type);
// return mediaFile != null
// ? options.onMediaPickedCallback?.call(mediaFile)
// : null;
// }
// void _inputLink(BuildContext context) {
// showDialog<String>(
// context: context,
// builder: (_) => MediaLinkDialog(
// dialogTheme: options.dialogTheme,
// labelText: options.labelText,
// hintText: options.hintText,
// buttonText: options.submitButtonText,
// buttonSize: options.submitButtonSize,
// childrenSpacing: options.childrenSpacing,
// autovalidateMode: options.autovalidateMode,
// validationMessage: options.validationMessage,
// ),
// ).then(_linkSubmitted);
// }
// void _linkSubmitted(String? value) {
// if (value != null && value.isNotEmpty) {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// final data = options.type.isImage
// ? BlockEmbed.image(value)
// : BlockEmbed.video(value);
// controller.replaceText(index, length, data, null);
// }
// }
// }
// /// Provides a dialog for input link to media resource.
// class MediaLinkDialog extends StatefulWidget {
// const MediaLinkDialog({
// super.key,
// this.link,
// this.dialogTheme,
// this.childrenSpacing = 16.0,
// this.labelText,
// this.hintText,
// this.buttonText,
// this.buttonSize,
// this.autovalidateMode = AutovalidateMode.disabled,
// this.validationMessage,
// }) : assert(childrenSpacing > 0);
// final String? link;
// final QuillDialogTheme? dialogTheme;
// /// The margin between child widgets in the dialog.
// final double childrenSpacing;
// /// The text of label in link add mode.
// final String? labelText;
// /// The hint text for link [TextField].
// final String? hintText;
// /// The text of the submit button.
// final String? buttonText;
// /// The size of dialog buttons.
// final Size? buttonSize;
// final AutovalidateMode autovalidateMode;
// final String? validationMessage;
// @override
// State<MediaLinkDialog> createState() => _MediaLinkDialogState();
// }
// class _MediaLinkDialogState extends State<MediaLinkDialog> {
// final _linkFocus = FocusNode();
// final _linkController = TextEditingController();
// @override
// void dispose() {
// _linkFocus.dispose();
// _linkController.dispose();
// super.dispose();
// }
// @override
// Widget build(BuildContext context) {
// final constraints = widget.dialogTheme?.linkDialogConstraints ??
// () {
// final size = MediaQuery.sizeOf(context);
// final maxWidth = kIsWeb ? size.width / 4 : size.width - 80;
// return BoxConstraints(maxWidth: maxWidth, maxHeight: 80);
// }();
// final buttonStyle = widget.buttonSize != null
// ? Theme.of(context)
// .elevatedButtonTheme
// .style
// ?.copyWith(
//fixedSize: MaterialStatePropertyAll(widget.buttonSize))
// : widget.dialogTheme?.buttonStyle;
// final isWrappable = widget.dialogTheme?.isWrappable ?? false;
// final children = [
// Text(widget.labelText ?? 'Enter media'.i18n),
// UtilityWidgets.maybeWidget(
// enabled: !isWrappable,
// wrapper: (child) => Expanded(
// child: child,
// ),
// child: Padding(
// padding: EdgeInsets.symmetric(horizontal: widget.childrenSpacing),
// child: TextFormField(
// controller: _linkController,
// focusNode: _linkFocus,
// style: widget.dialogTheme?.inputTextStyle,
// keyboardType: TextInputType.url,
// textInputAction: TextInputAction.done,
// decoration: InputDecoration(
// labelStyle: widget.dialogTheme?.labelTextStyle,
// hintText: widget.hintText,
// ),
// autofocus: true,
// autovalidateMode: widget.autovalidateMode,
// validator: _validateLink,
// onChanged: _linkChanged,
// ),
// ),
// ),
// ElevatedButton(
// onPressed: _canPress() ? _submitLink : null,
// style: buttonStyle,
// child: Text(widget.buttonText ?? 'Ok'.i18n),
// ),
// ];
// return Dialog(
// backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
// shape: widget.dialogTheme?.shape ??
// DialogTheme.of(context).shape ??
// RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
// child: ConstrainedBox(
// constraints: constraints,
// child: Padding(
// padding:
// widget.dialogTheme?.linkDialogPadding ?? const
// EdgeInsets.all(16),
// child: Form(
// child: isWrappable
// ? Wrap(
// alignment: WrapAlignment.center,
// crossAxisAlignment: WrapCrossAlignment.center,
// runSpacing: widget.dialogTheme?.runSpacing ?? 0.0,
// children: children,
// )
// : Row(
// children: children,
// ),
// ),
// ),
// ),
// );
// }
// bool _canPress() => _validateLink(_linkController.text) == null;
// void _linkChanged(String value) {
// setState(() {
// _linkController.text = value;
// });
// }
// void _submitLink() => Navigator.pop(context, _linkController.text);
// String? _validateLink(String? value) {
// if ((value?.isEmpty ?? false) ||
// !AutoFormatMultipleLinksRule.oneLineLinkRegExp.hasMatch(value!)) {
// return widget.validationMessage ?? 'That is not a valid URL';
// }
// return null;
// }
// }
// /// Media souce selector.
// class MediaSourceSelectorDialog extends StatelessWidget {
// const MediaSourceSelectorDialog({
// super.key,
// this.dialogTheme,
// this.galleryButtonText,
// this.linkButtonText,
// });
// final QuillDialogTheme? dialogTheme;
// /// The text of the gallery button [MediaSourceSelectorDialog].
// final String? galleryButtonText;
// /// The text of the link button [MediaSourceSelectorDialog].
// final String? linkButtonText;
// @override
// Widget build(BuildContext context) {
// final constraints = dialogTheme?.mediaSelectorDialogConstraints ??
// () {
// final size = MediaQuery.sizeOf(context);
// double maxWidth, maxHeight;
// if (kIsWeb) {
// maxWidth = size.width / 7;
// maxHeight = size.height / 7;
// } else {
// maxWidth = size.width - 80;
// maxHeight = maxWidth / 2;
// }
// return BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight);
// }();
// final shape = dialogTheme?.shape ??
// DialogTheme.of(context).shape ??
// RoundedRectangleBorder(borderRadius: BorderRadius.circular(4));
// return Dialog(
// backgroundColor: dialogTheme?.dialogBackgroundColor,
// shape: shape,
// child: ConstrainedBox(
// constraints: constraints,
// child: Padding(
// padding: dialogTheme?.mediaSelectorDialogPadding ??
// const EdgeInsets.all(16),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(
// child: TextButtonWithIcon(
// icon: Icons.collections,
// label: galleryButtonText ?? 'Gallery'.i18n,
// onPressed: () =>
// Navigator.pop(context, MediaPickSetting.gallery),
// ),
// ),
// const SizedBox(width: 10),
// Expanded(
// child: TextButtonWithIcon(
// icon: Icons.link,
// label: linkButtonText ?? 'Link'.i18n,
// onPressed: () =>
// Navigator.pop(context, MediaPickSetting.link),
// ),
// )
// ],
// ),
// ),
// ),
// );
// }
// }
// class TextButtonWithIcon extends StatelessWidget {
// const TextButtonWithIcon({
// required this.label,
// required this.icon,
// required this.onPressed,
// this.textStyle,
// super.key,
// });
// final String label;
// final IconData icon;
// final VoidCallback onPressed;
// final TextStyle? textStyle;
// @override
// Widget build(BuildContext context) {
// final theme = Theme.of(context);
// final scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1;
// final gap = scale <= 1 ? 8.0 : lerpDouble(8, 4, math.min(scale - 1, 1))!;
// final buttonStyle = TextButtonTheme.of(context).style;
// final shape = buttonStyle?.shape?.resolve({}) ??
// const RoundedRectangleBorder(
// borderRadius: BorderRadius.all(
// Radius.circular(4),
// ),
// );
// return Material(
// shape: shape,
// textStyle: textStyle ??
// theme.textButtonTheme.style?.textStyle?.resolve({}) ??
// theme.textTheme.labelLarge,
// elevation: buttonStyle?.elevation?.resolve({}) ?? 0,
// child: InkWell(
// customBorder: shape,
// onTap: onPressed,
// child: Padding(
// padding: const EdgeInsets.all(16),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: <Widget>[
// Icon(icon),
// SizedBox(height: gap),
// Flexible(child: Text(label)),
// ],
// ),
// ),
// ),
// );
// }
// }
// /// Default file picker.
// // Future<QuillFile?> _defaultMediaPicker(QuillMediaType mediaType) async {
// // final pickedFile = mediaType.isImage
// // ? await ImagePicker().pickImage(source: ImageSource.gallery)
// // : await ImagePicker().pickVideo(source: ImageSource.gallery);
// // if (pickedFile != null) {
// // return QuillFile(
// // name: pickedFile.name,
// // path: pickedFile.path,
// // bytes: await pickedFile.readAsBytes(),
// // );
// // }
// // return null;
// // }

@ -1,19 +0,0 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_quill/flutter_quill.dart';
class QuillEditorUnknownEmbedBuilder extends EmbedBuilder {
@override
Widget build(
BuildContext context,
QuillController controller,
Embed node,
bool readOnly,
bool inline,
TextStyle textStyle,
) {
return const Text('Unknown embed builder');
}
@override
String get key => 'unknown';
}

@ -1,47 +1,67 @@
library flutter_quill_extensions;
// ignore: implementation_imports
import 'package:flutter_quill/src/services/clipboard/clipboard_service_provider.dart';
import 'package:flutter_quill/src/editor/spellchecker/spellchecker_service_provider.dart';
// ignore: implementation_imports
import 'package:flutter_quill/src/editor_toolbar_controller_shared/clipboard/clipboard_service_provider.dart';
import 'package:meta/meta.dart' show immutable;
import 'services/clipboard/super_clipboard_service.dart';
import 'src/editor/spell_checker/simple_spell_checker_service.dart';
import 'src/editor_toolbar_controller_shared/clipboard/super_clipboard_service.dart';
export 'embeds/embed_types.dart';
export 'embeds/formula/toolbar/formula_button.dart';
export 'embeds/image/editor/image_embed.dart';
export 'embeds/image/editor/image_embed_types.dart';
export 'embeds/image/editor/image_web_embed.dart';
export 'embeds/image/toolbar/image_button.dart';
export 'embeds/others/camera_button/camera_button.dart';
export 'embeds/others/media_button/media_button.dart';
export 'embeds/table/editor/table_cell_embed.dart';
export 'embeds/table/editor/table_embed.dart';
export 'embeds/table/editor/table_models.dart';
export 'embeds/table/toolbar/table_button.dart';
export 'embeds/unknown/editor/unknown_embed.dart';
export 'embeds/video/editor/video_embed.dart';
export 'embeds/video/editor/video_web_embed.dart';
export 'embeds/video/toolbar/video_button.dart';
export 'embeds/video/video.dart';
export 'extensions/controller_ext.dart';
export 'flutter_quill_embeds.dart';
export 'models/config/camera/camera_configurations.dart';
export 'models/config/formula/formula_configurations.dart';
export 'models/config/image/editor/image_configurations.dart';
export 'models/config/image/editor/image_web_configurations.dart';
export 'models/config/image/toolbar/image_configurations.dart';
export 'models/config/media/media_button_configurations.dart';
export 'models/config/shared_configurations.dart';
export 'models/config/table/table_configurations.dart';
export 'models/config/video/editor/video_configurations.dart';
export 'models/config/video/editor/video_web_configurations.dart';
export 'models/config/video/toolbar/video_configurations.dart';
export 'utils/utils.dart';
export 'src/common/extensions/controller_ext.dart';
export 'src/common/utils/utils.dart';
export 'src/editor/image/image_embed.dart';
export 'src/editor/image/image_embed_types.dart';
export 'src/editor/image/image_web_embed.dart';
export 'src/editor/image/models/image_configurations.dart';
export 'src/editor/image/models/image_web_configurations.dart';
export 'src/editor/spell_checker/simple_spell_checker_service.dart';
export 'src/editor/table/table_cell_embed.dart';
export 'src/editor/table/table_embed.dart';
export 'src/editor/table/table_models.dart';
export 'src/editor/video/models/video_configurations.dart';
export 'src/editor/video/models/video_web_configurations.dart';
export 'src/editor/video/models/youtube_video_support_mode.dart';
export 'src/editor/video/video_embed.dart';
export 'src/editor/video/video_web_embed.dart';
export 'src/editor_toolbar_shared/shared_configurations.dart';
export 'src/flutter_quill_embeds.dart';
export 'src/toolbar/camera/camera_button.dart';
export 'src/toolbar/camera/models/camera_configurations.dart';
export 'src/toolbar/formula/formula_button.dart';
export 'src/toolbar/formula/models/formula_configurations.dart';
export 'src/toolbar/image/image_button.dart';
export 'src/toolbar/image/models/image_configurations.dart';
export 'src/toolbar/table/models/table_configurations.dart';
export 'src/toolbar/table/table_button.dart';
export 'src/toolbar/video/models/video.dart';
export 'src/toolbar/video/models/video_configurations.dart';
export 'src/toolbar/video/video_button.dart';
@immutable
class FlutterQuillExtensions {
const FlutterQuillExtensions._();
/// override the default implementation of [SpellCheckerServiceProvider]
/// to allow a `flutter quill` support a better check spelling
///
/// # !WARNING
/// To avoid memory leaks, ensure to use [dispose()] method to
/// close stream controllers that used by this custom implementation
/// when them no longer needed
///
/// Example:
///
///```dart
///// set partial true if you only need to close the controllers
///SpellCheckerServiceProvider.dispose(onlyPartial: false);
///```
static void useSpellCheckerService(String language) {
SpellCheckerServiceProvider.setNewCheckerService(
SimpleSpellCheckerService(language: language));
}
/// Override default implementation of [ClipboardServiceProvider.instance]
/// to allow `flutter_quill` package to use `super_clipboard` plugin
/// to support rich text features, gif and images.

@ -1,71 +0,0 @@
import 'package:flutter/widgets.dart' show AutovalidateMode;
import 'package:flutter/widgets.dart' show Color, Size;
import 'package:flutter_quill/flutter_quill.dart';
import '../../../embeds/embed_types.dart';
class QuillToolbarMediaButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarMediaButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
});
}
class QuillToolbarMediaButtonOptions extends QuillToolbarBaseButtonOptions<
QuillToolbarMediaButtonOptions, QuillToolbarMediaButtonExtraOptions> {
const QuillToolbarMediaButtonOptions({
required this.type,
required this.onMediaPickedCallback,
// required this.onVideoPickCallback,
this.dialogBarrierColor,
this.mediaFilePicker,
this.childrenSpacing = 16.0,
this.autovalidateMode = AutovalidateMode.disabled,
super.iconSize,
this.dialogTheme,
this.labelText,
this.hintText,
this.submitButtonText,
this.submitButtonSize,
this.galleryButtonText,
this.linkButtonText,
this.validationMessage,
super.iconData,
super.afterButtonPressed,
super.tooltip,
super.iconTheme,
super.childBuilder,
});
final QuillMediaType type;
final QuillDialogTheme? dialogTheme;
final MediaFilePicker? mediaFilePicker;
final MediaPickedCallback? onMediaPickedCallback;
final Color? dialogBarrierColor;
/// The margin between child widgets in the dialog.
final double childrenSpacing;
/// The text of label in link add mode.
final String? labelText;
/// The hint text for link [TextField].
final String? hintText;
/// The text of the submit button.
final String? submitButtonText;
/// The size of dialog buttons.
final Size? submitButtonSize;
/// The text of the gallery button [MediaSourceSelectorDialog].
final String? galleryButtonText;
/// The text of the link button [MediaSourceSelectorDialog].
final String? linkButtonText;
final AutovalidateMode autovalidateMode;
final String? validationMessage;
}

@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' show QuillDialogTheme;
import 'package:flutter_quill/translations.dart';
import 'utils/patterns.dart';
enum LinkType {
video,
image,
}
class TypeLinkDialog extends StatefulWidget {
const TypeLinkDialog({
required this.linkType,
this.dialogTheme,
this.link,
this.linkRegExp,
super.key,
});
final QuillDialogTheme? dialogTheme;
final String? link;
final RegExp? linkRegExp;
final LinkType linkType;
@override
TypeLinkDialogState createState() => TypeLinkDialogState();
}
class TypeLinkDialogState extends State<TypeLinkDialog> {
late String _link;
late TextEditingController _controller;
RegExp? _linkRegExp;
@override
void initState() {
super.initState();
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
_linkRegExp = widget.linkRegExp;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
content: TextField(
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
maxLines: null,
style: widget.dialogTheme?.inputTextStyle,
decoration: InputDecoration(
labelText: context.loc.pasteLink,
hintText: widget.linkType == LinkType.image
? context.loc.pleaseEnterAValidImageURL
: context.loc.pleaseEnterAValidVideoURL,
labelStyle: widget.dialogTheme?.labelTextStyle,
floatingLabelStyle: widget.dialogTheme?.labelTextStyle,
),
autofocus: true,
onChanged: _linkChanged,
controller: _controller,
onEditingComplete: () {
if (!_canPress()) {
return;
}
_applyLink();
},
),
actions: [
TextButton(
onPressed: _canPress() ? _applyLink : null,
child: Text(
context.loc.ok,
style: widget.dialogTheme?.labelTextStyle,
),
),
],
);
}
void _linkChanged(String value) {
setState(() {
_link = value;
});
}
void _applyLink() {
Navigator.pop(context, _link.trim());
}
RegExp get linkRegExp {
final customRegExp = _linkRegExp;
if (customRegExp != null) {
return customRegExp;
}
switch (widget.linkType) {
case LinkType.video:
if (youtubeRegExp.hasMatch(_link)) {
return youtubeRegExp;
}
return videoRegExp;
case LinkType.image:
return imageRegExp;
}
}
bool _canPress() {
if (_link.isEmpty) {
return false;
}
if (widget.linkType == LinkType.image) {}
return _link.isNotEmpty && linkRegExp.hasMatch(_link);
}
}

@ -0,0 +1 @@
export 'dart:ui' if (dart.library.js_interop) 'dart:ui_web';

@ -4,8 +4,8 @@ import 'package:cross_file/cross_file.dart';
import 'package:flutter/foundation.dart' show Uint8List, immutable;
import 'package:http/http.dart' as http;
import '../embeds/widgets/image.dart';
import '../services/image_saver/s_image_saver.dart';
import '../../editor/image/widgets/image.dart';
import '../../editor_toolbar_shared/image_saver/s_image_saver.dart';
import 'patterns.dart';
bool isBase64(String str) {

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide OptionalSize;
import 'package:flutter_quill/translations.dart';
import '../../../models/config/image/editor/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../widgets/image.dart';
import '../../common/utils/element_utils/element_utils.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'image_menu.dart';
import 'models/image_configurations.dart';
import 'widgets/image.dart';
class QuillEditorImageEmbedBuilder extends EmbedBuilder {
QuillEditorImageEmbedBuilder({

@ -4,8 +4,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../extensions/controller_ext.dart';
import '../../../services/image_picker/s_image_picker.dart';
import '../../common/extensions/controller_ext.dart';
import '../../editor_toolbar_shared/image_picker/s_image_picker.dart';
/// When request picking an image, for example when the image button toolbar
/// clicked, it should be null in case the user didn't choose any image or

@ -7,14 +7,14 @@ import 'package:flutter_quill/flutter_quill.dart'
import 'package:flutter_quill/translations.dart';
import 'package:super_clipboard/super_clipboard.dart';
import '../../../models/config/image/editor/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_saver/s_image_saver.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../../utils/string.dart';
import '../../../utils/utils.dart';
import '../../widgets/image.dart' show ImageTapWrapper, getImageStyleString;
import '../../widgets/image_resizer.dart' show ImageResizer;
import '../../common/utils/element_utils/element_utils.dart';
import '../../common/utils/string.dart';
import '../../common/utils/utils.dart';
import '../../editor_toolbar_shared/image_saver/s_image_saver.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/image_configurations.dart';
import 'widgets/image.dart' show ImageTapWrapper, getImageStyleString;
import 'widgets/image_resizer.dart' show ImageResizer;
class ImageOptionsMenu extends StatelessWidget {
const ImageOptionsMenu({

@ -3,11 +3,12 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:universal_html/html.dart' as html;
import '../../../models/config/image/editor/image_web_configurations.dart';
import '../../../utils/dart_ui/dart_ui_fake.dart'
if (dart.library.html) '../../../utils/dart_ui/dart_ui_real.dart' as ui;
import '../../../utils/element_utils/element_web_utils.dart';
import '../../../utils/utils.dart';
import '../../common/utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../common/utils/dart_ui/dart_ui_real.dart'
as ui;
import '../../common/utils/element_utils/element_web_utils.dart';
import '../../common/utils/utils.dart';
import 'models/image_web_configurations.dart';
class QuillEditorWebImageEmbedBuilder extends EmbedBuilder {
const QuillEditorWebImageEmbedBuilder({

@ -3,7 +3,7 @@ import 'dart:io' show File;
import 'package:flutter_quill/extensions.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../../embeds/image/editor/image_embed_types.dart';
import '../image_embed_types.dart';
/// [QuillEditorImageEmbedConfigurations] for desktop, mobile and
/// other platforms

@ -6,9 +6,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:photo_view/photo_view.dart';
import '../../models/config/image/editor/image_configurations.dart';
import '../../utils/utils.dart';
import '../image/editor/image_embed_types.dart';
import '../../../common/utils/utils.dart';
import '../image_embed_types.dart';
import '../models/image_configurations.dart';
const List<String> imageFileExtensions = [
'.jpeg',

@ -0,0 +1,65 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:simple_spell_checker/simple_spell_checker.dart';
/// SimpleSpellChecker is a simple spell checker for get
/// all words divide on different objects if them are wrong or not
class SimpleSpellCheckerService
extends SpellCheckerService<LanguageIdentifier> {
SimpleSpellCheckerService({required super.language})
: checker = SimpleSpellChecker(
language: language,
safeDictionaryLoad: true,
);
/// [SimpleSpellChecker] comes from the package [simple_spell_checker]
/// that give us all necessary methods for get our spans with highlighting
/// where needed
final SimpleSpellChecker checker;
@override
List<TextSpan>? checkSpelling(
String text, {
LongPressGestureRecognizer Function(String word)?
customLongPressRecognizerOnWrongSpan,
}) {
return checker.check(
text,
customLongPressRecognizerOnWrongSpan:
customLongPressRecognizerOnWrongSpan,
);
}
@override
void toggleChecker() => checker.toggleChecker();
@override
bool isServiceActive() => checker.isCheckerActive();
@override
void dispose({bool onlyPartial = false}) {
if (onlyPartial) {
checker.disposeControllers();
return;
}
checker.dispose();
}
@override
void addCustomLanguage({required languageIdentifier}) {
checker
..registerLanguage(languageIdentifier.language)
..addCustomLanguage(languageIdentifier);
}
@override
void setNewLanguageState({required String language}) {
checker.setNewLanguageToState(language);
}
@override
void updateCustomLanguageIfExist({required languageIdentifier}) {
checker.updateCustomLanguageIfExist(languageIdentifier);
}
}

@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/quill_delta.dart';
import '../../../utils/quill_table_utils.dart';
import '../../common/utils/quill_table_utils.dart';
import 'table_cell_embed.dart';
import 'table_models.dart';

@ -2,11 +2,11 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import '../../../models/config/video/editor/video_configurations.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../../utils/utils.dart';
import '../../widgets/video_app.dart';
import '../../widgets/youtube_video_app.dart';
import '../../common/utils/element_utils/element_utils.dart';
import '../../common/utils/utils.dart';
import 'models/video_configurations.dart';
import 'widgets/video_app.dart';
import 'widgets/youtube_video_app.dart';
class QuillEditorVideoEmbedBuilder extends EmbedBuilder {
const QuillEditorVideoEmbedBuilder({

@ -4,11 +4,12 @@ import 'package:universal_html/html.dart' as html;
import 'package:youtube_player_flutter/youtube_player_flutter.dart'
show YoutubePlayer;
import '../../../models/config/video/editor/video_web_configurations.dart';
import '../../../utils/dart_ui/dart_ui_fake.dart'
if (dart.library.html) '../../../utils/dart_ui/dart_ui_real.dart' as ui;
import '../../../utils/element_utils/element_web_utils.dart';
import '../../../utils/utils.dart';
import '../../common/utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../common/utils/dart_ui/dart_ui_real.dart'
as ui;
import '../../common/utils/element_utils/element_web_utils.dart';
import '../../common/utils/utils.dart';
import 'models/video_web_configurations.dart';
class QuillEditorWebVideoEmbedBuilder extends EmbedBuilder {
const QuillEditorWebVideoEmbedBuilder({

@ -6,7 +6,7 @@ import 'package:flutter_quill/flutter_quill.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
import '../../flutter_quill_extensions.dart';
import '../../../../flutter_quill_extensions.dart';
/// Widget for playing back video
/// Refer to https://github.com/flutter/plugins/tree/master/packages/video_player/video_player

@ -5,7 +5,7 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import '../../models/config/video/editor/youtube_video_support_mode.dart';
import '../models/youtube_video_support_mode.dart';
import 'video_app.dart';
class YoutubeVideoApp extends StatefulWidget {

@ -3,7 +3,8 @@ import 'dart:convert' show utf8;
import 'package:flutter/foundation.dart';
// ignore: implementation_imports
import 'package:flutter_quill/src/services/clipboard/clipboard_service.dart';
import 'package:flutter_quill/src/editor_toolbar_controller_shared/clipboard/clipboard_service.dart';
import 'package:super_clipboard/super_clipboard.dart';
/// Implementation based on https://pub.dev/packages/super_clipboard

@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../services/image_picker/s_image_picker.dart';
import '../../services/image_saver/s_image_saver.dart';
import 'image_picker/s_image_picker.dart';
import 'image_saver/s_image_saver.dart';
/// Configurations for Flutter Editor Extensions
/// shared between toolbar and editor

@ -2,23 +2,21 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_quill/flutter_quill.dart' as fq;
import 'package:meta/meta.dart' show immutable;
import 'embeds/image/editor/image_embed.dart';
import 'embeds/image/editor/image_web_embed.dart';
import 'embeds/image/toolbar/image_button.dart';
import 'embeds/others/camera_button/camera_button.dart';
import 'embeds/table/editor/table_embed.dart';
import 'embeds/table/toolbar/table_button.dart';
import 'embeds/video/editor/video_embed.dart';
import 'embeds/video/editor/video_web_embed.dart';
import 'embeds/video/toolbar/video_button.dart';
import 'models/config/camera/camera_configurations.dart';
import 'models/config/image/editor/image_configurations.dart';
import 'models/config/image/toolbar/image_configurations.dart';
import 'models/config/media/media_button_configurations.dart';
import 'models/config/table/table_configurations.dart';
import 'models/config/video/editor/video_configurations.dart';
import 'models/config/video/editor/video_web_configurations.dart';
import 'models/config/video/toolbar/video_configurations.dart';
import 'editor/image/image_embed.dart';
import 'editor/image/models/image_configurations.dart';
import 'editor/table/table_embed.dart';
import 'editor/video/models/video_configurations.dart';
import 'editor/video/models/video_web_configurations.dart';
import 'editor/video/video_embed.dart';
import 'editor/video/video_web_embed.dart';
import 'toolbar/camera/camera_button.dart';
import 'toolbar/camera/models/camera_configurations.dart';
import 'toolbar/image/image_button.dart';
import 'toolbar/image/models/image_configurations.dart';
import 'toolbar/table/models/table_configurations.dart';
import 'toolbar/table/table_button.dart';
import 'toolbar/video/models/video_configurations.dart';
import 'toolbar/video/video_button.dart';
@immutable
class FlutterQuillEmbeds {
@ -122,10 +120,6 @@ class FlutterQuillEmbeds {
const QuillToolbarVideoButtonOptions(),
QuillToolbarCameraButtonOptions? cameraButtonOptions,
QuillToolbarTableButtonOptions? tableButtonOptions,
@Deprecated(
'Media button has been removed, the value of this parameter will be ignored',
)
QuillToolbarMediaButtonOptions? mediaButtonOptions,
}) =>
[
if (imageButtonOptions != null)

@ -10,10 +10,10 @@ import 'package:flutter_quill/flutter_quill.dart'
kDefaultIconButtonFactor;
import 'package:flutter_quill/translations.dart';
import '../../../models/config/camera/camera_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_picker/image_options.dart';
import '../../editor_toolbar_shared/image_picker/image_options.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'camera_types.dart';
import 'models/camera_configurations.dart';
import 'select_camera_action.dart';
class QuillToolbarCameraButton extends StatelessWidget {

@ -1,8 +1,8 @@
import 'package:flutter/widgets.dart' show BuildContext;
import 'package:meta/meta.dart' show immutable;
import '../../image/editor/image_embed_types.dart';
import '../../video/video.dart';
import '../../editor/image/image_embed_types.dart';
import '../video/models/video.dart';
enum CameraAction {
video,

@ -1,6 +1,6 @@
import 'package:flutter_quill/flutter_quill.dart';
import '../../../embeds/others/camera_button/camera_types.dart';
import '../camera_types.dart';
class QuillToolbarCameraButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import '../../../models/config/formula/formula_configurations.dart';
import 'models/formula_configurations.dart';
class QuillToolbarFormulaButton extends StatelessWidget {
const QuillToolbarFormulaButton({

@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/image/toolbar/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_picker/image_picker.dart';
import '../../others/image_video_utils.dart';
import '../editor/image_embed_types.dart';
import '../../common/image_video_utils.dart';
import '../../editor/image/image_embed_types.dart';
import '../../editor_toolbar_shared/image_picker/image_picker.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/image_configurations.dart';
import 'select_image_source.dart';
class QuillToolbarImageButton extends StatelessWidget {

@ -1,7 +1,7 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../../embeds/image/editor/image_embed_types.dart';
import '../../../editor/image/image_embed_types.dart';
class QuillToolbarImageButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/translations.dart';
import '../editor/image_embed_types.dart';
import '../../editor/image/image_embed_types.dart';
class SelectImageSourceDialog extends StatelessWidget {
const SelectImageSourceDialog({super.key});

@ -1,8 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/table/table_configurations.dart';
import '../../../utils/quill_table_utils.dart';
import '../../common/utils/quill_table_utils.dart';
import 'models/table_configurations.dart';
class QuillToolbarTableButton extends StatelessWidget {
const QuillToolbarTableButton({

@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../extensions/controller_ext.dart';
import '../../services/image_picker/s_image_picker.dart';
import '../../../common/extensions/controller_ext.dart';
import '../../../editor_toolbar_shared/image_picker/s_image_picker.dart';
/// When request picking an video, for example when the video button toolbar
/// clicked, it should be null in case the user didn't choose any video or

@ -1,6 +1,6 @@
import 'package:flutter_quill/flutter_quill.dart';
import '../../../../embeds/video/video.dart';
import 'video.dart';
class QuillToolbarVideoButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/translations.dart';
import '../video.dart';
import 'models/video.dart';
class SelectVideoSourceDialog extends StatelessWidget {
const SelectVideoSourceDialog({super.key});

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../models/config/video/toolbar/video_configurations.dart';
import '../../../services/image_picker/image_options.dart';
import '../../others/image_video_utils.dart';
import '../video.dart';
import '../../common/image_video_utils.dart';
import '../../editor_toolbar_shared/image_picker/image_options.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/video.dart';
import 'models/video_configurations.dart';
import 'select_video_source.dart';
// TODO: Add custom callback to validate the video link input

@ -1 +0,0 @@
export 'dart:ui' if (dart.library.html) 'dart:ui_web';

@ -1,6 +1,6 @@
name: flutter_quill_extensions
description: Embed extensions for flutter_quill including image, video, formula and etc.
version: 9.5.15
version: 10.4.1
homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions/
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/
@ -35,12 +35,13 @@ dependencies:
universal_html: ^2.2.4
cross_file: ^0.3.3+6
flutter_quill: ^9.5.1
flutter_quill: ^10.3.0
photo_view: ^0.15.0
youtube_explode_dart: ^2.2.1
# Plugins
video_player: ^2.8.1
simple_spell_checker: ^1.1.6
youtube_player_flutter: ^9.0.1
url_launcher: ^6.2.1
super_clipboard: ^0.8.15

@ -4,6 +4,304 @@
All notable changes to this project will be documented in this file.
## 10.4.1
* Chore: improve Spell checker API to the example by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2133
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.4.0...v10.4.1
## 10.4.0
* Copy TapAndPanGestureRecognizer from TextField by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2128
* enhance stringToColor with a custom defined palette from `DefaultStyles` by @vishna in https://github.com/singerdmx/flutter-quill/pull/2095
* Feat: include spell checker for example app by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2127
## New Contributors
* @vishna made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2095
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.3...v10.4.0
## 10.3.2
* Fix: Loss of style when backspace by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2125
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.1...v10.3.2
## 10.3.1
* Chore: Move spellchecker service to extensions by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2120
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.3.0...v10.3.1
## 10.3.0
* Feat: Spellchecker for Flutter Quill by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2118
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.1...v10.3.0
## 10.2.1
* Fix: context menu is visible even when selection is collapsed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2116
* Fix: unsafe operation while getting overlayEntry in text_selection by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2117
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.2.0...v10.2.1
## 10.2.0
* refactor!: restructure project into modular architecture for flutter_quill_extensions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2106
* Fix: Link selection and editing by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2114
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.10...v10.2.0
## 10.1.10
* Fix(example): image_cropper outdated version by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2100
* Using dart.library.js_interop instead of dart.library.html by @h1376h in https://github.com/singerdmx/flutter-quill/pull/2103
## New Contributors
* @h1376h made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2103
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.9...v10.1.10
## 10.1.9
* restore ability to pass in key to QuillEditor by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2093
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.8...v10.1.9
## 10.1.8
* Enhancement: Search within Embed objects by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2090
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.7...v10.1.8
## 10.1.7
* Feature/allow shortcut override by @InstrinsicAutomations in https://github.com/singerdmx/flutter-quill/pull/2089
## New Contributors
* @InstrinsicAutomations made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2089
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.6...v10.1.7
## 10.1.6
* fixed #1295 Double click to select text sometimes doesn't work. by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2086
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.5...v10.1.6
## 10.1.5
* ref: add `VerticalSpacing.zero` and `HorizontalSpacing.zero` named constants by @adil192 in https://github.com/singerdmx/flutter-quill/pull/2083
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.4...v10.1.5
## 10.1.4
* Fix: collectStyles for lists and alignments by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2082
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.3...v10.1.4
## 10.1.3
* Move Controller outside of configurations data class by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2078
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.2...v10.1.3
## 10.1.2
* Fix Multiline paste with attributes and embeds by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2074
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.1...v10.1.2
## 10.1.1
* Toolbar dividers fixes + Docs updates by @troyanskiy in https://github.com/singerdmx/flutter-quill/pull/2071
## New Contributors
* @troyanskiy made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2071
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.1.0...v10.1.1
## 10.1.0
* Feat: support for customize copy and cut Embeddables to Clipboard by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2067
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.10...v10.1.0
## 10.0.10
* fix: Hide selection toolbar if editor loses focus by @huandu in https://github.com/singerdmx/flutter-quill/pull/2066
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.9...v10.0.10
## 10.0.9
* Fix: manual checking of directionality by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2063
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.8...v10.0.9
## 10.0.8
* feat: add callback to handle performAction by @huandu in https://github.com/singerdmx/flutter-quill/pull/2061
* fix: Invalid selection when tapping placeholder text by @huandu in https://github.com/singerdmx/flutter-quill/pull/2062
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.7...v10.0.8
## 10.0.7
* Fix: RTL issues by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2060
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.6...v10.0.7
## 10.0.6
* fix: textInputAction is not set when creating QuillRawEditorConfiguration by @huandu in https://github.com/singerdmx/flutter-quill/pull/2057
## New Contributors
* @huandu made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2057
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.5...v10.0.6
## 10.0.5
* Add tests for PreserveInlineStylesRule and fix link editing. Other minor fixes. by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2058
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.4...v10.0.5
## 10.0.4
* Add ability to set up horizontal spacing for block style by @dimkanovikov in https://github.com/singerdmx/flutter-quill/pull/2051
* add catalan language by @spilioio in https://github.com/singerdmx/flutter-quill/pull/2054
## New Contributors
* @dimkanovikov made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2051
* @spilioio made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2054
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.3...v10.0.4
## 10.0.3
* doc(Delta): more documentation about Delta by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2042
* doc(attribute): added documentation about Attribute class and how create one by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2048
* if magnifier removes toolbar, restore it when it is hidden by @mtallenca in https://github.com/singerdmx/flutter-quill/pull/2049
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.2...v10.0.3
## 10.0.2
* chore(scripts): migrate the scripts from sh to dart by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2036
* Have the ability to create custom rules, closes #1162 by @Guillergood in https://github.com/singerdmx/flutter-quill/pull/2040
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.1...v10.0.2
## 10.0.1
This release is identical to [10.0.0](https://github.com/singerdmx/flutter-quill/releases/tag/v10.0.0) with a fix that addresses issue #2034 by requiring `10.0.0` as the minimum version for quill related dependencies.
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v10.0.0...v10.0.1
## 10.0.0
* refactor: restructure project into modular architecture for flutter_quill by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2032
* chore: update GitHub PR template by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2033
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.6.0...v10.0.0
## 9.6.0
* [feature] : quill add magnifier by @demoYang in https://github.com/singerdmx/flutter-quill/pull/2026
## New Contributors
* @demoYang made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2026
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.23...v9.6.0
## 9.5.23
* add untranslated Kurdish keys by @Xoshbin in https://github.com/singerdmx/flutter-quill/pull/2029
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.22...v9.5.23
## 9.5.22
* Fix outdated contributor guide link on PR template by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2027
* Fix(rule): PreserveInlineStyleRule assume the type of the operation data and throw stacktrace by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2028
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.21...v9.5.22
## 9.5.21
* Fix: Key actions not being handled by @AtlasAutocode in https://github.com/singerdmx/flutter-quill/pull/2025
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.20...v9.5.21
## 9.5.20
* Remove useless delta_x_test by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2017
* Update flutter_quill_delta_from_html package on pubspec.yaml by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2018
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.19...v9.5.20
## 9.5.19
* fixed #1835 Embed Reloads on Cmd Key Press by @li8607 in https://github.com/singerdmx/flutter-quill/pull/2013
## New Contributors
* @li8607 made their first contribution in https://github.com/singerdmx/flutter-quill/pull/2013
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.18...v9.5.19
## 9.5.18
* Refactor: Moved core link button functions to link.dart by @Alspb in https://github.com/singerdmx/flutter-quill/pull/2008
* doc: more documentation about Rules by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2014
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.17...v9.5.18
## 9.5.17
* Feat(config): added option to disable automatic list conversion by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2011
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.16...v9.5.17
## 9.5.16
* chore: drop support for HTML, PDF, and Markdown converting functions by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/1997
* docs(readme): update the extensions package to document the Rich Text Paste feature on web by @EchoEllet in https://github.com/singerdmx/flutter-quill/pull/2001
* Fix(test): delta_x tests fail by wrong expected Delta for video embed by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2010
**Full Changelog**: https://github.com/singerdmx/flutter-quill/compare/v9.5.15...v9.5.16
## 9.5.15
* Update delta_from_html to fix nested lists issues and more by @CatHood0 in https://github.com/singerdmx/flutter-quill/pull/2000

@ -1,6 +1,6 @@
name: flutter_quill_test
description: Test utilities for flutter_quill which includes methods to simplify interacting with the editor in test cases.
version: 9.5.15
version: 10.4.1
homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_test/
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_test/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/
@ -28,7 +28,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_quill: ^9.0.0-dev-6
flutter_quill: ^10.0.0
flutter_test:
sdk: flutter

@ -1,7 +1,10 @@
library flutter_quill.extensions;
export 'src/models/documents/nodes/leaf.dart';
export 'src/models/rules/insert.dart';
export 'src/utils/platform.dart';
export 'src/utils/string.dart';
export 'src/utils/widgets.dart';
export 'src/common/utils/platform.dart';
export 'src/common/utils/string.dart';
export 'src/common/utils/widgets.dart';
export 'src/document/nodes/leaf.dart';
export 'src/rules/delete.dart';
export 'src/rules/format.dart';
export 'src/rules/insert.dart';
export 'src/rules/rule.dart';

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save