Feat: Line height support (#1972)

* Support for Line height

* fix(translations): line-height translation empty

* chore: dart fixes

* fix(test): blockSelectionStyle doesn't find line-height attribute

* fix: increased _expectedTranslationKeysLength value for new line height translation

* fix: restore h1 configurations on DefaultStyles

* fix: better organization for line height attribute

* fix: select_line_height_dropdown_button doesn't find LineHeightAttribute constants

* chore: dart fixes

* fix(test): controller_test doesn't find LineHeightAttribute

* fix: changed MenuAnchor to showMenu method since this MenuAnchor  appears below keyboard

* added docs comments

* set showLineHeightButton to false

* added warnings about line height attribute could cause conflicts with original Quill API

* chore: dart fixes

---------

Co-authored-by: CatHood0 <santiagowmar@gmail.com>
pull/1976/head^2 v9.5.4
Cat 9 months ago committed by GitHub
parent 151e629ee3
commit 6598f3d74d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      doc/custom_toolbar.md
  2. 4
      example/lib/screens/quill/my_quill_toolbar.dart
  3. 6
      lib/src/l10n/generated/quill_localizations.dart
  4. 3
      lib/src/l10n/generated/quill_localizations_ar.dart
  5. 3
      lib/src/l10n/generated/quill_localizations_bg.dart
  6. 3
      lib/src/l10n/generated/quill_localizations_bn.dart
  7. 3
      lib/src/l10n/generated/quill_localizations_cs.dart
  8. 3
      lib/src/l10n/generated/quill_localizations_da.dart
  9. 3
      lib/src/l10n/generated/quill_localizations_de.dart
  10. 6
      lib/src/l10n/generated/quill_localizations_en.dart
  11. 3
      lib/src/l10n/generated/quill_localizations_es.dart
  12. 3
      lib/src/l10n/generated/quill_localizations_fa.dart
  13. 3
      lib/src/l10n/generated/quill_localizations_fr.dart
  14. 3
      lib/src/l10n/generated/quill_localizations_he.dart
  15. 3
      lib/src/l10n/generated/quill_localizations_hi.dart
  16. 3
      lib/src/l10n/generated/quill_localizations_id.dart
  17. 3
      lib/src/l10n/generated/quill_localizations_it.dart
  18. 3
      lib/src/l10n/generated/quill_localizations_ja.dart
  19. 3
      lib/src/l10n/generated/quill_localizations_ko.dart
  20. 6
      lib/src/l10n/generated/quill_localizations_ku.dart
  21. 3
      lib/src/l10n/generated/quill_localizations_ms.dart
  22. 3
      lib/src/l10n/generated/quill_localizations_ne.dart
  23. 3
      lib/src/l10n/generated/quill_localizations_nl.dart
  24. 3
      lib/src/l10n/generated/quill_localizations_no.dart
  25. 3
      lib/src/l10n/generated/quill_localizations_pl.dart
  26. 6
      lib/src/l10n/generated/quill_localizations_pt.dart
  27. 6
      lib/src/l10n/generated/quill_localizations_ro.dart
  28. 3
      lib/src/l10n/generated/quill_localizations_ru.dart
  29. 3
      lib/src/l10n/generated/quill_localizations_sk.dart
  30. 3
      lib/src/l10n/generated/quill_localizations_sr.dart
  31. 3
      lib/src/l10n/generated/quill_localizations_sv.dart
  32. 3
      lib/src/l10n/generated/quill_localizations_sw.dart
  33. 3
      lib/src/l10n/generated/quill_localizations_tk.dart
  34. 3
      lib/src/l10n/generated/quill_localizations_tr.dart
  35. 3
      lib/src/l10n/generated/quill_localizations_uk.dart
  36. 3
      lib/src/l10n/generated/quill_localizations_ur.dart
  37. 3
      lib/src/l10n/generated/quill_localizations_vi.dart
  38. 9
      lib/src/l10n/generated/quill_localizations_zh.dart
  39. 3
      lib/src/l10n/quill_ar.arb
  40. 3
      lib/src/l10n/quill_bg.arb
  41. 3
      lib/src/l10n/quill_bn.arb
  42. 3
      lib/src/l10n/quill_cs.arb
  43. 3
      lib/src/l10n/quill_da.arb
  44. 3
      lib/src/l10n/quill_de.arb
  45. 3
      lib/src/l10n/quill_en.arb
  46. 1
      lib/src/l10n/quill_en_US.arb
  47. 3
      lib/src/l10n/quill_es.arb
  48. 3
      lib/src/l10n/quill_fa.arb
  49. 1
      lib/src/l10n/quill_fr.arb
  50. 3
      lib/src/l10n/quill_he.arb
  51. 3
      lib/src/l10n/quill_hi.arb
  52. 3
      lib/src/l10n/quill_id.arb
  53. 3
      lib/src/l10n/quill_it.arb
  54. 3
      lib/src/l10n/quill_ja.arb
  55. 1
      lib/src/l10n/quill_ko.arb
  56. 1
      lib/src/l10n/quill_ku.arb
  57. 1
      lib/src/l10n/quill_ku_CKB.arb
  58. 3
      lib/src/l10n/quill_ms.arb
  59. 3
      lib/src/l10n/quill_ne.arb
  60. 3
      lib/src/l10n/quill_nl.arb
  61. 3
      lib/src/l10n/quill_no.arb
  62. 3
      lib/src/l10n/quill_pl.arb
  63. 3
      lib/src/l10n/quill_pt.arb
  64. 3
      lib/src/l10n/quill_pt_br.arb
  65. 1
      lib/src/l10n/quill_ro.arb
  66. 1
      lib/src/l10n/quill_ro_RO.arb
  67. 1
      lib/src/l10n/quill_ru.arb
  68. 3
      lib/src/l10n/quill_sk.arb
  69. 3
      lib/src/l10n/quill_sr.arb
  70. 3
      lib/src/l10n/quill_sv.arb
  71. 3
      lib/src/l10n/quill_sw.arb
  72. 3
      lib/src/l10n/quill_tk.arb
  73. 3
      lib/src/l10n/quill_tr.arb
  74. 3
      lib/src/l10n/quill_uk.arb
  75. 3
      lib/src/l10n/quill_ur.arb
  76. 3
      lib/src/l10n/quill_vi.arb
  77. 3
      lib/src/l10n/quill_zh.arb
  78. 3
      lib/src/l10n/quill_zh_CN.arb
  79. 3
      lib/src/l10n/quill_zh_HK.arb
  80. 78
      lib/src/models/config/toolbar/buttons/select_line_height_style_dropdown_button_configurations.dart
  81. 6
      lib/src/models/config/toolbar/simple_toolbar_button_options.dart
  82. 5
      lib/src/models/config/toolbar/simple_toolbar_configurations.dart
  83. 26
      lib/src/models/documents/attribute.dart
  84. 347
      lib/src/widgets/others/default_styles.dart
  85. 28
      lib/src/widgets/quill/text_line.dart
  86. 1
      lib/src/widgets/toolbar/base_toolbar.dart
  87. 234
      lib/src/widgets/toolbar/buttons/select_line_height_dropdown_button.dart
  88. 7
      lib/src/widgets/toolbar/simple_toolbar.dart
  89. 2
      scripts/ensure_translations_correct.dart
  90. 1
      test/widgets/controller_test.dart

@ -73,6 +73,14 @@ QuillToolbar.simple(
isBackground: true,
),
const VerticalDivider(),
// This is an implementation that only is used on
// flutter_quill and it's not originally
// implemented in Quill JS API, so it could cause conflicts
// with the original Quill Delta format
QuillToolbarSelectLineHeightStyleDropdownButton(
controller: globalController,
),
const VerticalDivider(),
QuillToolbarSelectHeaderStyleButton(
controller: controller,
),

@ -164,6 +164,10 @@ class MyQuillToolbar extends StatelessWidget {
controller: controller,
),
const VerticalDivider(),
QuillToolbarSelectLineHeightStyleDropdownButton(
controller: controller,
),
const VerticalDivider(),
QuillToolbarToggleCheckListButton(
controller: controller,
),

@ -577,6 +577,12 @@ abstract class FlutterQuillLocalizations {
/// **'Color'**
String get color;
/// No description provided for @lineheight.
///
/// In en, this message translates to:
/// **'Line height'**
String get lineheight;
/// No description provided for @findText.
///
/// In en, this message translates to:

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsAr extends FlutterQuillLocalizations {
@override
String get color => 'اللون';
@override
String get lineheight => 'ارتفاع خط';
@override
String get findText => 'بحث عن نص';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsBg extends FlutterQuillLocalizations {
@override
String get color => 'Цвят';
@override
String get lineheight => 'височина на линията';
@override
String get findText => 'Намери текст';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsBn extends FlutterQuillLocalizations {
@override
String get color => '';
@override
String get lineheight => 'ইনর উচচত';
@override
String get findText => 'য খ';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsCs extends FlutterQuillLocalizations {
@override
String get color => 'Barva';
@override
String get lineheight => 'Výška čáry';
@override
String get findText => 'Najít text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsDa extends FlutterQuillLocalizations {
@override
String get color => 'Farve';
@override
String get lineheight => 'altezza della linea';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsDe extends FlutterQuillLocalizations {
@override
String get color => 'Farbe';
@override
String get lineheight => 'Zeilenhöhe';
@override
String get findText => 'Text suchen';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsEn extends FlutterQuillLocalizations {
@override
String get color => 'Color';
@override
String get lineheight => 'Line height';
@override
String get findText => 'Find text';
@ -482,6 +485,9 @@ class FlutterQuillLocalizationsEnUs extends FlutterQuillLocalizationsEn {
@override
String get color => 'Color';
@override
String get lineheight => 'Line height';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsEs extends FlutterQuillLocalizations {
@override
String get color => 'Color';
@override
String get lineheight => 'Interlineado';
@override
String get findText => 'Buscar texto';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsFa extends FlutterQuillLocalizations {
@override
String get color => 'رنگ';
@override
String get lineheight => 'ارتفاع خط';
@override
String get findText => 'جستجوی متن';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsFr extends FlutterQuillLocalizations {
@override
String get color => 'Couleur';
@override
String get lineheight => 'Hauteur de la ligne';
@override
String get findText => 'Rechercher du texte';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsHe extends FlutterQuillLocalizations {
@override
String get color => 'צבע';
@override
String get lineheight => 'גובה קו';
@override
String get findText => 'מצא טקסט';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsHi extends FlutterQuillLocalizations {
@override
String get color => '';
@override
String get lineheight => 'ईन';
@override
String get findText => 'मद क';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsId extends FlutterQuillLocalizations {
@override
String get color => 'Warna';
@override
String get lineheight => 'Tinggi garis';
@override
String get findText => 'Temukan Teks';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsIt extends FlutterQuillLocalizations {
@override
String get color => 'Colore';
@override
String get lineheight => 'Altezza della linea';
@override
String get findText => 'Trova testo';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsJa extends FlutterQuillLocalizations {
@override
String get color => 'Color';
@override
String get lineheight => '行の高さ';
@override
String get findText => '検索テキスト';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsKo extends FlutterQuillLocalizations {
@override
String get color => '색상';
@override
String get lineheight => '선 높이';
@override
String get findText => '찾기';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsKu extends FlutterQuillLocalizations {
@override
String get color => 'ڕەنگ';
@override
String get lineheight => 'بەرزی هێڵ';
@override
String get findText => 'دۆزینەوەی نوسین';
@ -504,6 +507,9 @@ class FlutterQuillLocalizationsKuCkb extends FlutterQuillLocalizationsKu {
@override
String get color => 'ڕەنگ';
@override
String get lineheight => 'بەرزی هێڵ';
@override
String get findText => 'دۆزینەوەی نوسین';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsMs extends FlutterQuillLocalizations {
@override
String get color => 'Warna';
@override
String get lineheight => 'Ketinggian garisan';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsNe extends FlutterQuillLocalizations {
@override
String get color => 'रङ';
@override
String get lineheight => '-उच';
@override
String get findText => 'ट फ';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsNl extends FlutterQuillLocalizations {
@override
String get color => 'Kleur';
@override
String get lineheight => 'Lijnhoogte';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsNo extends FlutterQuillLocalizations {
@override
String get color => 'Farge';
@override
String get lineheight => 'Linjehøyde';
@override
String get findText => 'Finn tekst';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsPl extends FlutterQuillLocalizations {
@override
String get color => 'Kolor';
@override
String get lineheight => 'Wysokość linii';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsPt extends FlutterQuillLocalizations {
@override
String get color => 'Cor';
@override
String get lineheight => 'Altura da linha';
@override
String get findText => 'Find text';
@ -482,6 +485,9 @@ class FlutterQuillLocalizationsPtBr extends FlutterQuillLocalizationsPt {
@override
String get color => 'Cor';
@override
String get lineheight => 'Altura da linha';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsRo extends FlutterQuillLocalizations {
@override
String get color => 'Culoare';
@override
String get lineheight => 'Inaltimea liniei';
@override
String get findText => 'Găsește text';
@ -506,6 +509,9 @@ class FlutterQuillLocalizationsRoRo extends FlutterQuillLocalizationsRo {
@override
String get color => 'Culoare';
@override
String get lineheight => 'Inaltimea liniei';
@override
String get findText => 'Găsește text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsRu extends FlutterQuillLocalizations {
@override
String get color => 'Цвет';
@override
String get lineheight => 'Высота линии';
@override
String get findText => 'Найти текст';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsSk extends FlutterQuillLocalizations {
@override
String get color => 'Farba';
@override
String get lineheight => 'Výška riadku';
@override
String get findText => 'Nájsť text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsSr extends FlutterQuillLocalizations {
@override
String get color => 'Boja';
@override
String get lineheight => 'Visina linije';
@override
String get findText => 'Nađi tekst';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsSv extends FlutterQuillLocalizations {
@override
String get color => 'Färg';
@override
String get lineheight => 'Radavstånd';
@override
String get findText => 'Hitta text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsSw extends FlutterQuillLocalizations {
@override
String get color => 'Rangi';
@override
String get lineheight => 'Urefu wa mstari';
@override
String get findText => 'Pata Maandishi';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsTk extends FlutterQuillLocalizations {
@override
String get color => 'Reňk';
@override
String get lineheight => 'Çyzyk beýikligi';
@override
String get findText => 'Tekst tapyň';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsTr extends FlutterQuillLocalizations {
@override
String get color => 'Renk';
@override
String get lineheight => 'Satır yüksekliği';
@override
String get findText => 'Find text';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsUk extends FlutterQuillLocalizations {
@override
String get color => 'Колір';
@override
String get lineheight => 'Висота лінії';
@override
String get findText => 'Знайти текст';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsUr extends FlutterQuillLocalizations {
@override
String get color => 'رنگ';
@override
String get lineheight => 'لکیر کی اونچائی';
@override
String get findText => 'متن تلاش کریں';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsVi extends FlutterQuillLocalizations {
@override
String get color => 'Màu';
@override
String get lineheight => 'Chiều cao giữa các dòng';
@override
String get findText => 'Tìm văn bản';

@ -208,6 +208,9 @@ class FlutterQuillLocalizationsZh extends FlutterQuillLocalizations {
@override
String get color => '颜色';
@override
String get lineheight => '行高';
@override
String get findText => '搜索文本';
@ -500,6 +503,9 @@ class FlutterQuillLocalizationsZhCn extends FlutterQuillLocalizationsZh {
@override
String get color => '颜色';
@override
String get lineheight => '行高';
@override
String get findText => '搜索文本';
@ -745,6 +751,9 @@ class FlutterQuillLocalizationsZhHk extends FlutterQuillLocalizationsZh {
@override
String get color => '顏色';
@override
String get lineheight => '行高';
@override
String get findText => '搜尋文本';

@ -60,6 +60,7 @@
"hex": "Hex",
"material": "Material",
"color": "اللون",
"lineheight": "ارتفاع خط",
"findText": "بحث عن نص",
"moveToPreviousOccurrence": "الانتقال إلى الحدث السابق",
"moveToNextOccurrence": "الانتقال إلى الحدث التالي",
@ -88,4 +89,4 @@
"recordAVideoUsingYourCamera": "تسجيل فيديو باستخدام الكاميرا",
"pasteAVideoUsingALink": "لصق فيديو باستخدام رابط"
}

@ -60,6 +60,7 @@
"hex": "Hex",
"material": "Material",
"color": "Цвят",
"lineheight": "височина на линията",
"findText": "Намери текст",
"moveToPreviousOccurrence": "Премести към предишното съвпадение",
"moveToNextOccurrence": "Премести към следващото съвпадение",
@ -76,4 +77,4 @@
"caseSensitivityAndWholeWordSearch": "Чувствителност на кутията и търсене на цялата дума",
"insertImage": "Вмъкване на изображение"
}

@ -60,6 +60,7 @@
"hex": "হস",
"material": "মিল",
"color": "কর",
"lineheight": "লইনর উচচত",
"findText": "পয খন",
"moveToPreviousOccurrence": "পববর ঘটন চলন",
"moveToNextOccurrence": "পরবর ঘটন চলন",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "কস সিিিি এবণ শবদ অনসনন",
"insertImage": "চির সনিশ"
}

@ -60,6 +60,7 @@
"hex": "Hex",
"material": "Material",
"color": "Barva",
"lineheight": "Výška čáry",
"findText": "Najít text",
"moveToPreviousOccurrence": "Přesunout na předchozí výskyt",
"moveToNextOccurrence": "Přesunout na následující výskyt",
@ -102,4 +103,4 @@
"recordAVideoUsingYourCamera": "Natočit video pomocí kamery",
"pasteAVideoUsingALink": "Vložit video pomocí odkazu"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Materiale",
"color": "Farve",
"lineheight": "altezza della linea",
"pleaseEnterAValidVideoURL": "Angiv en gyldig video-URL",
"photo": "Foto",
"image": "Billede",
"caseSensitivityAndWholeWordSearch": "Stor- og småbogstavsfølsomhed samt helordsøgning",
"insertImage": "Indsæt billede"
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Material",
"color": "Farbe",
"lineheight": "Zeilenhöhe",
"pleaseEnterAValidVideoURL": "Bitte geben Sie eine gültige Video-URL ein",
"photo": "Foto",
"image": "Bild",
@ -79,4 +80,4 @@
"pasteAPhotoUsingALink": "Fügen Sie ein Foto über einen Link ein",
"pickAVideoFromYourGallery": "Wählen Sie ein Video aus Ihrer Galerie",
"recordAVideoUsingYourCamera": "Nehmen Sie ein Video mit Ihrer Kamera auf"
}
}

@ -71,6 +71,7 @@
"hex": "Hex",
"material": "Material",
"color": "Color",
"lineheight": "Line height",
"findText": "Find text",
"moveToPreviousOccurrence": "Move to previous occurrence",
"moveToNextOccurrence": "Move to next occurrence",
@ -108,4 +109,4 @@
"cut": "Cut",
"paste": "Paste",
"insertTable": "Insert table"
}
}

@ -60,6 +60,7 @@
"hex": "Hex",
"material": "Material",
"color": "Color",
"lineheight": "Line height",
"findText": "Find text",
"moveToPreviousOccurrence": "Move to previous occurrence",
"moveToNextOccurrence": "Move to next occurrence",

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Material",
"color": "Color",
"lineheight": "Interlineado",
"pleaseEnterAValidVideoURL": "Por favor, ingrese una URL de video válida",
"photo": "Foto",
"image": "Imagen",
@ -79,4 +80,4 @@
"pasteAPhotoUsingALink": "Pega una foto usando un enlace",
"pickAVideoFromYourGallery": "Elige un video de tu galería",
"recordAVideoUsingYourCamera": "Graba un video con tu cámara"
}
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "مواد",
"color": "رنگ",
"lineheight": "ارتفاع خط",
"savedUsingTheNetwork": "با استفاده از شبکه ذخیره شده است",
"pleaseEnterTextForYourLink": "لطفاً متن لینک خود را وارد کنید (مثال: 'بیشتر بدانید')",
"pleaseEnterTheLinkURL": "لطفاً URL لینک را وارد کنید (مثال: 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "حساسیت به کوچکی و بزرگی حروف و جستجوی کلمه کامل",
"insertImage": "وارد کردن تصویر"
}

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Matériel",
"color": "Couleur",
"lineheight": "Hauteur de la ligne",
"findText": "Rechercher du texte",
"moveToPreviousOccurrence": "Aller à l'occurrence précédente",
"moveToNextOccurrence": "Aller à l'occurrence suivante",

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "חומר",
"color": "צבע",
"lineheight": "גובה קו",
"savedUsingTheNetwork": "נשמר באמצעות הרשת",
"pleaseEnterTextForYourLink": "אנא הזן טקסט לקישור שלך (לדוגמה, 'מידע נוסף')",
"pleaseEnterTheLinkURL": "אנא הזן את כתובת ה-URL של הקישור (לדוגמה, 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "רגישות לאותות רישיות וחיפוש לפי מילה שלמה",
"insertImage": "הכנס תמונה"
}

@ -69,6 +69,7 @@
"hex": "हस",
"material": "समग",
"color": "रग",
"lineheight": "ऊईन",
"savedUsingTheNetwork": "नटवरक क उपयग करक सह गय",
"pleaseEnterTextForYourLink": "कपय अपनिक किए एक पठ दरज कर (उदहरण: 'और अधिक ज')",
"pleaseEnterTheLinkURL": "कपयिक URL दरज कर (उदहरण: 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "कस सििि और प शबद कज",
"insertImage": "छवि"
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Material",
"color": "Warna",
"lineheight": "Tinggi garis",
"savedUsingTheNetwork": "Tersimpan menggunakan jaringan",
"pleaseEnterTextForYourLink": "Harap masukkan teks untuk tautan Anda (contoh: 'Pelajari lebih lanjut')",
"pleaseEnterTheLinkURL": "Harap masukkan URL tautan (contoh: 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Sensitivitas huruf besar dan kecil dan pencarian kata utuh",
"insertImage": "Sisipkan Gambar"
}

@ -60,6 +60,7 @@
"hex": "Esadecimale",
"material": "Materiale",
"color": "Colore",
"lineheight": "Altezza della linea",
"findText": "Trova testo",
"moveToPreviousOccurrence": "Vai all'occorrenza precedente",
"moveToNextOccurrence": "Vai all'occorrenza successiva",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Sensibilità maiuscole/minuscole e ricerca di parole intere",
"insertImage": "Inserisci immagine"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Material",
"color": "Color",
"lineheight": "行の高さ",
"pleaseEnterAValidVideoURL": "有効なビデオURLを入力してください",
"photo": "写真",
"image": "画像",
"caseSensitivityAndWholeWordSearch": "大文字と小文字の区別と完全一致検索",
"insertImage": "画像を挿入"
}

@ -67,6 +67,7 @@
"hex": "Hex 값",
"material": "Material 색상",
"color": "색상",
"lineheight": "선 높이",
"findText": "찾기",
"moveToPreviousOccurrence": "이전 위치로 이동",
"moveToNextOccurrence": "다음 위치로 이동",

@ -67,6 +67,7 @@
"hex": "هێکس",
"material": "بابەت",
"color": "ڕەنگ",
"lineheight": "بەرزی هێڵ",
"findText": "دۆزینەوەی نوسین",
"moveToPreviousOccurrence": "بچۆ بۆ ڕووداوی پێشوو",
"moveToNextOccurrence": "بڕۆ بۆ ڕووداوی داهاتوو",

@ -67,6 +67,7 @@
"hex": "هێکس",
"material": "بابەت",
"color": "ڕەنگ",
"lineheight": "بەرزی هێڵ",
"findText": "دۆزینەوەی نوسین",
"moveToPreviousOccurrence": "بچۆ بۆ ڕووداوی پێشوو",
"moveToNextOccurrence": "بڕۆ بۆ ڕووداوی داهاتوو",

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Bahan",
"color": "Warna",
"lineheight": "Ketinggian garisan",
"savedUsingTheNetwork": "Disimpan menggunakan rangkaian",
"pleaseEnterTextForYourLink": "Sila masukkan teks untuk pautan anda (contoh, 'Ketahui lebih lanjut')",
"pleaseEnterTheLinkURL": "Sila masukkan URL pautan (contoh, 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Sensitiviti huruf besar dan kecil dan carian penuh perkataan",
"insertImage": "Masukkan imej"
}

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Material",
"color": "रङ",
"lineheight": "र-उचइ",
"findText": "टट फ",
"moveToPreviousOccurrence": "अघि घटन",
"moveToNextOccurrence": "अर घटन",
@ -97,4 +98,4 @@
"pickAVideoFromYourGallery": "आफलरट भिि",
"recordAVideoUsingYourCamera": "आफरयग गरर भििकरड गर",
"pasteAVideoUsingALink": "लिक परयग गरर भिि"
}
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Materiaal",
"color": "Kleur",
"lineheight": "Lijnhoogte",
"savedUsingTheNetwork": "Opgeslagen via het netwerk",
"pleaseEnterTextForYourLink": "Voer tekst in voor uw link (bijvoorbeeld 'Meer weten')",
"pleaseEnterTheLinkURL": "Voer de URL van de link in (bijvoorbeeld 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Hoofdlettergevoeligheid en volledig woord zoeken",
"insertImage": "Afbeelding invoegen"
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Materiale",
"color": "Farge",
"lineheight": "Linjehøyde",
"savedUsingTheNetwork": "Lagret ved hjelp av nettverket",
"pleaseEnterTextForYourLink": "Vennligst skriv inn tekst for lenken din (for eksempel 'Lær mer')",
"pleaseEnterTheLinkURL": "Vennligst skriv inn lenkens URL (for eksempel 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Stor/liten bokstavfølsomhet og helordsøk",
"insertImage": "Sett inn bilde"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Materiał",
"color": "Kolor",
"lineheight": "Wysokość linii",
"pleaseEnterAValidVideoURL": "Proszę wprowadzić poprawny adres URL wideo",
"photo": "Zdjęcie",
"image": "Obraz",
"caseSensitivityAndWholeWordSearch": "Czułość na wielkość liter i wyszukiwanie całego słowa",
"insertImage": "Wstaw obraz"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Material",
"color": "Cor",
"lineheight": "Altura da linha",
"pleaseEnterAValidVideoURL": "Por favor, insira uma URL de vídeo válida",
"photo": "Foto",
"image": "Imagem",
"caseSensitivityAndWholeWordSearch": "Sensibilidade a maiúsculas e minúsculas e pesquisa de palavras inteiras",
"insertImage": "Inserir imagem"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Material",
"color": "Cor",
"lineheight": "Altura da linha",
"pleaseEnterAValidVideoURL": "Por favor, insira uma URL de vídeo válida",
"photo": "Foto",
"image": "Imagem",
"caseSensitivityAndWholeWordSearch": "Sensibilidade a maiúsculas e minúsculas e pesquisa de palavras inteiras",
"insertImage": "Inserir imagem"
}

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Material",
"color": "Culoare",
"lineheight": "Inaltimea liniei",
"findText": "Găsește text",
"moveToPreviousOccurrence": "Mutați la apariția anterioară",
"moveToNextOccurrence": "Mutați la apariția următoare",

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Material",
"color": "Culoare",
"lineheight": "Inaltimea liniei",
"findText": "Găsește text",
"moveToPreviousOccurrence": "Mutați la apariția anterioară",
"moveToNextOccurrence": "Mutați la apariția următoare",

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Материал",
"color": "Цвет",
"lineheight": "Высота линии",
"pleaseEnterAValidVideoURL": "Пожалуйста, введите действительный URL-адрес видео",
"photo": "Фото",
"image": "Изображение",

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Materiál",
"color": "Farba",
"lineheight": "Výška riadku",
"findText": "Nájsť text",
"moveToPreviousOccurrence": "Prejsť na predchádzajúce výskyty",
"moveToNextOccurrence": "Prejsť na ďalší výskyt",
@ -97,4 +98,4 @@
"pickAVideoFromYourGallery": "Vyberte video z vašej galérie",
"recordAVideoUsingYourCamera": "Natočiť video pomocou vašej kamery",
"pasteAVideoUsingALink": "Vložiť video pomocou odkazu"
}
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Materijal",
"color": "Boja",
"lineheight": "Visina linije",
"savedUsingTheNetwork": "Sačuvano korišćenjem mreže",
"pleaseEnterTextForYourLink": "Unesite tekst za svoj link (na primer, 'Saznajte više')",
"pleaseEnterTheLinkURL": "Unesite URL linka (na primer, 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Osetljivost na velika i mala slova i potraga za celom rečju",
"insertImage": "Umetni sliku"
}

@ -67,6 +67,7 @@
"hex": "Hex",
"material": "Material",
"color": "Färg",
"lineheight": "Radavstånd",
"findText": "Hitta text",
"moveToPreviousOccurrence": "Gå till föregående förekomst",
"moveToNextOccurrence": "Gå till nästa förekomst",
@ -87,4 +88,4 @@
"pickAVideoFromYourGallery": "Välj en video från ditt galleri",
"recordAVideoUsingYourCamera": "Spela in en video med din kamera",
"pasteAVideoUsingALink": "Klistra in en video med en länk"
}
}

@ -60,6 +60,7 @@
"hex": "Hexi",
"material": "Nyenzo",
"color": "Rangi",
"lineheight": "Urefu wa mstari",
"findText": "Pata Maandishi",
"moveToPreviousOccurrence": "Nenda Kwenye Tukio la Awali",
"moveToNextOccurrence": "Nenda kwa Tukio linalofuata",
@ -76,4 +77,4 @@
"caseSensitivityAndWholeWordSearch": "Uwiano wa herufi kubwa na ndogo na utafutaji wa neno zima",
"insertImage": "Weka Picha"
}

@ -60,6 +60,7 @@
"hex": "Hex",
"material": "Material",
"color": "Reňk",
"lineheight": "Çyzyk beýikligi",
"findText": "Tekst tapyň",
"moveToPreviousOccurrence": "Öňki hadysa geçiň",
"moveToNextOccurrence": "Indiki hadysa geçiň",
@ -76,4 +77,4 @@
"caseSensitivityAndWholeWordSearch": "Iňkisar we iň oňg söz gözleýinç",
"insertImage": "Surat goş"
}

@ -69,10 +69,11 @@
"hex": "Hex",
"material": "Malzeme",
"color": "Renk",
"lineheight": "Satır yüksekliği",
"pleaseEnterAValidVideoURL": "Lütfen geçerli bir video URL'si girin",
"photo": "Fotoğraf",
"image": "Görüntü",
"caseSensitivityAndWholeWordSearch": "Büyük/küçük harf hassasiyeti ve tam kelime arama",
"insertImage": "Görüntü ekle"
}

@ -14,6 +14,7 @@
"hex": "Hex",
"material": "Матеріал",
"color": "Колір",
"lineheight": "Висота лінії",
"pleaseEnterAValidVideoURL": "Будь ласка, введіть дійсну URL-адресу відео",
"photo": "Фото",
"image": "Зображення",
@ -88,4 +89,4 @@
"heading5": "Заголовок 5",
"heading6": "Заголовок 6"
}

@ -69,6 +69,7 @@
"hex": "ہیکس",
"material": "مواد",
"color": "رنگ",
"lineheight": "لکیر کی اونچائی",
"savedUsingTheNetwork": "نیٹ ورک کا استعمال کر کے محفوظ ہوا",
"pleaseEnterTextForYourLink": "براہ کرم اپنے لنک کے لیے متن درج کریں (مثال کے طور پر، 'مزید جانیں')",
"pleaseEnterTheLinkURL": "براہ کرم لنک کا URL درج کریں (مثال کے طور پر، 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "معاملے کی حساسیت اور پورے الفاظ کی تلاش",
"insertImage": "تصویر داخل کریں"
}

@ -69,6 +69,7 @@
"hex": "Hex",
"material": "Chất liệu",
"color": "Màu",
"lineheight": "Chiều cao giữa các dòng",
"savedUsingTheNetwork": "Đã lưu bằng cách sử dụng mạng",
"pleaseEnterTextForYourLink": "Vui lòng nhập văn bản cho liên kết của bạn (ví dụ: 'Tìm hiểu thêm')",
"pleaseEnterTheLinkURL": "Vui lòng nhập URL của liên kết (ví dụ: 'https://example.com')",
@ -79,4 +80,4 @@
"caseSensitivityAndWholeWordSearch": "Độ nhạy cảm chữ hoa/chữ thường và tìm kiếm toàn bộ từ",
"insertImage": "Chèn hình ảnh"
}

@ -67,6 +67,7 @@
"hex": "十六进制",
"material": "Material 设计",
"color": "颜色",
"lineheight": "行高",
"findText": "搜索文本",
"moveToPreviousOccurrence": "上一个匹配项",
"moveToNextOccurrence": "下一个匹配项",
@ -87,4 +88,4 @@
"pickAVideoFromYourGallery": "从相册选取视频",
"recordAVideoUsingYourCamera": "使用相机录制",
"pasteAVideoUsingALink": "从链接获取视频"
}
}

@ -67,6 +67,7 @@
"hex": "十六进制",
"material": "Material 设计",
"color": "颜色",
"lineheight": "行高",
"findText": "搜索文本",
"moveToPreviousOccurrence": "上一个匹配项",
"moveToNextOccurrence": "下一个匹配项",
@ -87,4 +88,4 @@
"pickAVideoFromYourGallery": "从相册选取视频",
"recordAVideoUsingYourCamera": "使用相机录制",
"pasteAVideoUsingALink": "从链接获取视频"
}
}

@ -69,10 +69,11 @@
"hex": "十六進制",
"material": "物料",
"color": "顏色",
"lineheight": "行高",
"pleaseEnterAValidVideoURL": "請輸入有效的視頻URL",
"photo": "照片",
"image": "圖像",
"caseSensitivityAndWholeWordSearch": "區分大小寫和整詞搜索",
"insertImage": "插入圖像"
}

@ -0,0 +1,78 @@
import 'package:flutter/widgets.dart'
show IconData, TextStyle, ValueChanged, VoidCallback;
import '../../../../widgets/toolbar/base_toolbar.dart';
import '../../../documents/attribute.dart';
import '../../../themes/quill_icon_theme.dart';
class QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
required this.currentValue,
});
final Attribute currentValue;
}
class QuillToolbarSelectLineHeightStyleDropdownButtonOptions
extends QuillToolbarBaseButtonOptions<
QuillToolbarSelectLineHeightStyleDropdownButtonOptions,
QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions> {
const QuillToolbarSelectLineHeightStyleDropdownButtonOptions({
super.afterButtonPressed,
super.childBuilder,
super.iconTheme,
super.tooltip,
super.iconSize,
super.iconButtonFactor,
this.textStyle,
super.iconData,
this.attributes,
this.defaultDisplayText,
this.width,
});
final TextStyle? textStyle;
/// Line-height attributes, defaults to:
/// ```dart
/// [
/// Attribute.lineHeightNormal,
/// Attribute.lineHeightTight,
/// Attribute.lineHeightOneAndHalf,
/// Attribute.lineHeightDouble,
/// ]
/// ```
final List<Attribute<double?>>? attributes;
final double? width;
final String? defaultDisplayText;
QuillToolbarSelectLineHeightStyleDropdownButtonOptions copyWith({
ValueChanged<String>? onSelected,
List<Attribute<double>>? attributes,
TextStyle? style,
double? iconSize,
double? iconButtonFactor,
IconData? iconData,
VoidCallback? afterButtonPressed,
String? tooltip,
QuillIconTheme? iconTheme,
String? defaultDisplayText,
double? width,
}) {
return QuillToolbarSelectLineHeightStyleDropdownButtonOptions(
attributes: attributes ?? this.attributes,
iconData: iconData ?? this.iconData,
afterButtonPressed: afterButtonPressed ?? this.afterButtonPressed,
tooltip: tooltip ?? this.tooltip,
iconTheme: iconTheme ?? this.iconTheme,
iconSize: iconSize ?? this.iconSize,
iconButtonFactor: iconButtonFactor ?? this.iconButtonFactor,
defaultDisplayText: defaultDisplayText ?? this.defaultDisplayText,
width: width ?? this.width,
);
}
}

@ -16,6 +16,7 @@ import 'buttons/search_configurations.dart';
import 'buttons/select_alignment_configurations.dart';
import 'buttons/select_header_style_buttons_configurations.dart';
import 'buttons/select_header_style_dropdown_button_configurations.dart';
import 'buttons/select_line_height_style_dropdown_button_configurations.dart';
import 'buttons/toggle_check_list_configurations.dart';
import 'buttons/toggle_style_configurations.dart';
@ -72,6 +73,8 @@ class QuillSimpleToolbarButtonOptions extends Equatable {
const QuillToolbarSelectHeaderStyleButtonsOptions(),
this.selectHeaderStyleDropdownButton =
const QuillToolbarSelectHeaderStyleDropdownButtonOptions(),
this.selectLineHeightStyleDropdownButton =
const QuillToolbarSelectLineHeightStyleDropdownButtonOptions(),
this.linkStyle = const QuillToolbarLinkStyleButtonOptions(),
this.linkStyle2 = const QuillToolbarLinkStyleButton2Options(),
this.customButtons = const QuillToolbarCustomButtonOptions(),
@ -131,6 +134,9 @@ class QuillSimpleToolbarButtonOptions extends Equatable {
final QuillToolbarSelectHeaderStyleDropdownButtonOptions
selectHeaderStyleDropdownButton;
final QuillToolbarSelectLineHeightStyleDropdownButtonOptions
selectLineHeightStyleDropdownButton;
final QuillToolbarLinkStyleButtonOptions linkStyle;
final QuillToolbarLinkStyleButton2Options linkStyle2;

@ -97,6 +97,7 @@ class QuillSimpleToolbarConfigurations extends QuillSharedToolbarProperties {
this.showItalicButton = true,
this.showSmallButton = false,
this.showUnderLineButton = true,
this.showLineHeightButton = false,
this.showStrikeThrough = true,
this.showInlineCode = true,
this.showColorButton = true,
@ -217,6 +218,10 @@ class QuillSimpleToolbarConfigurations extends QuillSharedToolbarProperties {
final bool showClipboardCopy;
final bool showClipboardPaste;
/// This activates a functionality that is only implemented in [flutter_quill] and is NOT originally
/// used in the [Quill Js API]. So it could cause conflicts if you use this attribute with the original Delta format of Quill Js
final bool showLineHeightButton;
/// Toolbar items to display for controls of embed blocks
final List<EmbedButtonBuilder>? embedButtons;

@ -40,6 +40,7 @@ class Attribute<T> extends Equatable {
Attribute.background.key: Attribute.background,
Attribute.placeholder.key: Attribute.placeholder,
Attribute.header.key: Attribute.header,
Attribute.lineHeight.key: Attribute.lineHeight,
Attribute.align.key: Attribute.align,
Attribute.direction.key: Attribute.direction,
Attribute.list.key: Attribute.list,
@ -87,6 +88,8 @@ class Attribute<T> extends Equatable {
static const HeaderAttribute header = HeaderAttribute();
static const LineHeightAttribute lineHeight = LineHeightAttribute();
static const IndentAttribute indent = IndentAttribute();
static const AlignAttribute align = AlignAttribute(null);
@ -135,6 +138,7 @@ class Attribute<T> extends Equatable {
Attribute.blockQuote.key,
Attribute.indent.key,
Attribute.direction.key,
Attribute.lineHeight.key,
});
static final Set<String> blockKeysExceptHeader = LinkedHashSet.of({
@ -142,6 +146,7 @@ class Attribute<T> extends Equatable {
Attribute.align.key,
Attribute.codeBlock.key,
Attribute.blockQuote.key,
Attribute.lineHeight.key,
Attribute.indent.key,
Attribute.direction.key,
});
@ -337,6 +342,27 @@ class HeaderAttribute extends Attribute<int?> {
: super('header', AttributeScope.block, level);
}
/// This attribute represents the space between text lines. The line height can be
/// adjusted using predefined constants or custom values
///
/// The attribute at the json looks like: "attributes":{"line-height": 1.5 }
class LineHeightAttribute extends Attribute<double?> {
const LineHeightAttribute({double? lineHeight})
: super('line-height', AttributeScope.block, lineHeight);
static const Attribute<double?> lineHeightNormal =
LineHeightAttribute(lineHeight: 1);
static const Attribute<double?> lineHeightTight =
LineHeightAttribute(lineHeight: 1.15);
static const Attribute<double?> lineHeightOneAndHalf =
LineHeightAttribute(lineHeight: 1.5);
static const Attribute<double?> lineHeightDouble =
LineHeightAttribute(lineHeight: 2);
}
class IndentAttribute extends Attribute<int?> {
const IndentAttribute({int? level})
: super('indent', AttributeScope.block, level);

@ -170,6 +170,10 @@ class DefaultStyles {
this.h5,
this.h6,
this.paragraph,
this.lineHeightNormal,
this.lineHeightTight,
this.lineHeightOneAndHalf,
this.lineHeightDouble,
this.bold,
this.subscript,
this.superscript,
@ -199,6 +203,10 @@ class DefaultStyles {
final DefaultTextBlockStyle? h5;
final DefaultTextBlockStyle? h6;
final DefaultTextBlockStyle? paragraph;
final DefaultTextBlockStyle? lineHeightNormal;
final DefaultTextBlockStyle? lineHeightTight;
final DefaultTextBlockStyle? lineHeightOneAndHalf;
final DefaultTextBlockStyle? lineHeightDouble;
final TextStyle? bold;
final TextStyle? subscript;
final TextStyle? superscript;
@ -227,7 +235,7 @@ class DefaultStyles {
final defaultTextStyle = DefaultTextStyle.of(context);
final baseStyle = defaultTextStyle.style.copyWith(
fontSize: 16,
height: 1.3,
height: 1.15,
decoration: TextDecoration.none,
);
const baseSpacing = VerticalSpacing(6, 0);
@ -245,186 +253,211 @@ class DefaultStyles {
);
return DefaultStyles(
h1: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 34,
color: defaultTextStyle.style.color,
letterSpacing: -1,
height: 1,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(16, 0),
const VerticalSpacing(0, 0),
null),
h2: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 30,
color: defaultTextStyle.style.color,
letterSpacing: -0.8,
height: 1.067,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(8, 0),
const VerticalSpacing(0, 0),
null),
h3: DefaultTextBlockStyle(
h1: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 24,
fontSize: 34,
color: defaultTextStyle.style.color,
letterSpacing: -0.5,
height: 1.083,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(8, 0),
const VerticalSpacing(0, 0),
null,
),
h4: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
color: defaultTextStyle.style.color,
letterSpacing: -0.4,
height: 1.1,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(6, 0),
const VerticalSpacing(16, 0),
const VerticalSpacing(0, 0),
null,
),
h5: DefaultTextBlockStyle(
null),
h2: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 18,
fontSize: 30,
color: defaultTextStyle.style.color,
letterSpacing: -0.2,
height: 1.11,
letterSpacing: -0.8,
height: 1.067,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(6, 0),
const VerticalSpacing(0, 0),
null,
),
h6: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 16,
color: defaultTextStyle.style.color,
letterSpacing: -0.1,
height: 1.125,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
const VerticalSpacing(4, 0),
const VerticalSpacing(8, 0),
const VerticalSpacing(0, 0),
null,
null),
h3: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 24,
color: defaultTextStyle.style.color,
letterSpacing: -0.5,
height: 1.083,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
paragraph: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
const VerticalSpacing(8, 0),
const VerticalSpacing(0, 0),
null,
),
h4: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
color: defaultTextStyle.style.color,
letterSpacing: -0.4,
height: 1.1,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
bold: const TextStyle(fontWeight: FontWeight.bold),
subscript: const TextStyle(
fontFeatures: [
FontFeature.liningFigures(),
FontFeature.subscripts(),
],
const VerticalSpacing(6, 0),
const VerticalSpacing(0, 0),
null,
),
h5: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 18,
color: defaultTextStyle.style.color,
letterSpacing: -0.2,
height: 1.11,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
superscript: const TextStyle(
fontFeatures: [
FontFeature.liningFigures(),
FontFeature.superscripts(),
],
const VerticalSpacing(6, 0),
const VerticalSpacing(0, 0),
null,
),
h6: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 16,
color: defaultTextStyle.style.color,
letterSpacing: -0.1,
height: 1.125,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
),
italic: const TextStyle(fontStyle: FontStyle.italic),
small: const TextStyle(fontSize: 12),
underline: const TextStyle(decoration: TextDecoration.underline),
strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough),
inlineCode: InlineCodeStyle(
backgroundColor: Colors.grey.shade100,
radius: const Radius.circular(3),
style: inlineCodeStyle,
header1: inlineCodeStyle.copyWith(
fontSize: 32,
fontWeight: FontWeight.w500,
),
header2: inlineCodeStyle.copyWith(
fontSize: 22,
fontWeight: FontWeight.w500,
),
header3: inlineCodeStyle.copyWith(
fontSize: 18,
fontWeight: FontWeight.w500,
),
const VerticalSpacing(4, 0),
const VerticalSpacing(0, 0),
null,
),
lineHeightNormal: DefaultTextBlockStyle(
baseStyle.copyWith(height: 1.15),
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
lineHeightTight: DefaultTextBlockStyle(
baseStyle.copyWith(height: 1.30),
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
lineHeightOneAndHalf: DefaultTextBlockStyle(
baseStyle.copyWith(height: 1.55),
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
lineHeightDouble: DefaultTextBlockStyle(
baseStyle.copyWith(height: 2),
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
paragraph: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
bold: const TextStyle(fontWeight: FontWeight.bold),
subscript: const TextStyle(
fontFeatures: [
FontFeature.liningFigures(),
FontFeature.subscripts(),
],
),
superscript: const TextStyle(
fontFeatures: [
FontFeature.liningFigures(),
FontFeature.superscripts(),
],
),
italic: const TextStyle(fontStyle: FontStyle.italic),
small: const TextStyle(fontSize: 12),
underline: const TextStyle(decoration: TextDecoration.underline),
strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough),
inlineCode: InlineCodeStyle(
backgroundColor: Colors.grey.shade100,
radius: const Radius.circular(3),
style: inlineCodeStyle,
header1: inlineCodeStyle.copyWith(
fontSize: 32,
fontWeight: FontWeight.w500,
),
link: TextStyle(
color: themeData.colorScheme.secondary,
decoration: TextDecoration.underline,
header2: inlineCodeStyle.copyWith(
fontSize: 22,
fontWeight: FontWeight.w500,
),
placeHolder: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
height: 1.5,
color: Colors.grey.withOpacity(0.6),
),
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null),
lists: DefaultListBlockStyle(
baseStyle,
baseSpacing,
const VerticalSpacing(0, 6),
null,
null,
header3: inlineCodeStyle.copyWith(
fontSize: 18,
fontWeight: FontWeight.w500,
),
quote: DefaultTextBlockStyle(
TextStyle(color: baseStyle.color!.withOpacity(0.6)),
baseSpacing,
const VerticalSpacing(6, 2),
BoxDecoration(
border: Border(
left: BorderSide(width: 4, color: Colors.grey.shade300),
),
),
link: TextStyle(
color: themeData.colorScheme.secondary,
decoration: TextDecoration.underline,
),
placeHolder: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
height: 1.5,
color: Colors.grey.withOpacity(0.6),
),
),
code: DefaultTextBlockStyle(
TextStyle(
color: Colors.blue.shade900.withOpacity(0.9),
fontFamily: fontFamily,
fontSize: 13,
height: 1.15,
),
baseSpacing,
const VerticalSpacing(0, 0),
BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(2),
)),
indent: DefaultTextBlockStyle(
baseStyle,
baseSpacing,
const VerticalSpacing(0, 6),
null,
),
align: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
null),
lists: DefaultListBlockStyle(
baseStyle,
baseSpacing,
const VerticalSpacing(0, 6),
null,
null,
),
quote: DefaultTextBlockStyle(
TextStyle(color: baseStyle.color!.withOpacity(0.6)),
baseSpacing,
const VerticalSpacing(6, 2),
BoxDecoration(
border: Border(
left: BorderSide(width: 4, color: Colors.grey.shade300),
),
),
leading: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
),
code: DefaultTextBlockStyle(
TextStyle(
color: Colors.blue.shade900.withOpacity(0.9),
fontFamily: fontFamily,
fontSize: 13,
height: 1.15,
),
baseSpacing,
const VerticalSpacing(0, 0),
null,
),
sizeSmall: const TextStyle(fontSize: 10),
sizeLarge: const TextStyle(fontSize: 18),
sizeHuge: const TextStyle(fontSize: 22));
BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(2),
)),
indent: DefaultTextBlockStyle(
baseStyle,
baseSpacing,
const VerticalSpacing(0, 6),
null,
),
align: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
leading: DefaultTextBlockStyle(
baseStyle,
const VerticalSpacing(0, 0),
const VerticalSpacing(0, 0),
null,
),
sizeSmall: const TextStyle(fontSize: 10),
sizeLarge: const TextStyle(fontSize: 18),
sizeHuge: const TextStyle(fontSize: 22),
);
}
DefaultStyles merge(DefaultStyles other) {
@ -447,6 +480,10 @@ class DefaultStyles {
link: other.link ?? link,
color: other.color ?? color,
placeHolder: other.placeHolder ?? placeHolder,
lineHeightNormal: other.lineHeightNormal ?? lineHeightNormal,
lineHeightTight: other.lineHeightTight ?? lineHeightTight,
lineHeightOneAndHalf: other.lineHeightOneAndHalf ?? lineHeightOneAndHalf,
lineHeightDouble: other.lineHeightDouble ?? lineHeightDouble,
lists: other.lists ?? lists,
quote: other.quote ?? quote,
code: other.code ?? code,

@ -8,27 +8,18 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../models/documents/attribute.dart';
import '../../../flutter_quill.dart';
import '../../models/documents/nodes/container.dart' as container_node;
import '../../models/documents/nodes/embeddable.dart';
import '../../models/documents/nodes/leaf.dart' as leaf;
import '../../models/documents/nodes/leaf.dart';
import '../../models/documents/nodes/line.dart';
import '../../models/documents/nodes/node.dart';
import '../../models/documents/style.dart';
import '../../models/structs/vertical_spacing.dart';
import '../../utils/color.dart';
import '../../utils/font.dart';
import '../../utils/platform.dart';
import '../others/box.dart';
import '../others/cursor.dart';
import '../others/default_styles.dart';
import '../others/delegate.dart';
import '../others/keyboard_listener.dart';
import '../others/link.dart';
import '../others/proxy.dart';
import '../others/text_selection.dart';
import 'quill_controller.dart';
class TextLine extends StatefulWidget {
const TextLine({
@ -301,6 +292,23 @@ class _TextLineState extends State<TextLine> {
}
textStyle = textStyle.merge(toMerge);
final lineHeight = widget.line.style.attributes[Attribute.lineHeight.key];
final x = <Attribute, TextStyle>{
LineHeightAttribute.lineHeightNormal:
defaultStyles.lineHeightNormal!.style,
LineHeightAttribute.lineHeightTight: defaultStyles.lineHeightTight!.style,
LineHeightAttribute.lineHeightOneAndHalf:
defaultStyles.lineHeightOneAndHalf!.style,
LineHeightAttribute.lineHeightDouble:
defaultStyles.lineHeightDouble!.style,
};
// If the lineHeight attribute isn't null, then get just the height param instead whole TextStyle
// to avoid modify the current style of the text line
textStyle =
textStyle.merge(textStyle.copyWith(height: x[lineHeight]?.height));
textStyle = _applyCustomAttributes(textStyle, widget.line.style.attributes);
return textStyle;

@ -24,6 +24,7 @@ export 'buttons/link_style_button.dart';
export 'buttons/quill_icon_button.dart';
export 'buttons/search/legacy/legacy_search_button.dart';
export 'buttons/search/search_button.dart';
export 'buttons/select_line_height_dropdown_button.dart';
export 'buttons/toggle_check_list_button.dart';
export 'buttons/toggle_style_button.dart';

@ -0,0 +1,234 @@
import 'package:flutter/material.dart';
import '../../../../translations.dart';
import '../../../extensions/quill_configurations_ext.dart';
import '../../../models/config/toolbar/buttons/select_line_height_style_dropdown_button_configurations.dart';
import '../../../models/documents/attribute.dart';
import '../../../models/themes/quill_icon_theme.dart';
import '../base_button/base_value_button.dart';
import '../base_toolbar.dart';
typedef QuillToolbarSelectLineHeightStyleDropdownBaseButton
= QuillToolbarBaseButton<
QuillToolbarSelectLineHeightStyleDropdownButtonOptions,
QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions>;
typedef QuillToolbarSelectLineHeightStyleDropdownBaseButtonsState<
W extends QuillToolbarSelectLineHeightStyleDropdownButton>
= QuillToolbarCommonButtonState<
W,
QuillToolbarSelectLineHeightStyleDropdownButtonOptions,
QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions>;
class QuillToolbarSelectLineHeightStyleDropdownButton
extends QuillToolbarSelectLineHeightStyleDropdownBaseButton {
const QuillToolbarSelectLineHeightStyleDropdownButton({
required super.controller,
super.options =
const QuillToolbarSelectLineHeightStyleDropdownButtonOptions(),
super.key,
});
@override
QuillToolbarSelectLineHeightStyleDropdownBaseButtonsState createState() =>
_QuillToolbarSelectLineHeightStyleDropdownButtonState();
}
class _QuillToolbarSelectLineHeightStyleDropdownButtonState
extends QuillToolbarSelectLineHeightStyleDropdownBaseButtonsState {
@override
String get defaultTooltip => context.loc.lineheight;
@override
IconData get defaultIconData => Icons.question_mark_outlined;
Attribute<dynamic> _selectedItem = Attribute.lineHeight;
@override
void initState() {
super.initState();
widget.controller.addListener(_didChangeEditingValue);
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
@override
void didUpdateWidget(
covariant QuillToolbarSelectLineHeightStyleDropdownButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller == widget.controller) {
return;
}
widget.controller
..removeListener(_didChangeEditingValue)
..addListener(_didChangeEditingValue);
}
void _didChangeEditingValue() {
final newSelectedItem = _getLineHeightValue();
if (newSelectedItem == _selectedItem) {
return;
}
setState(() {
_selectedItem = newSelectedItem;
});
}
Attribute<dynamic> _getLineHeightValue() {
final attr =
widget.controller.toolbarButtonToggler[Attribute.lineHeight.key];
if (attr != null) {
widget.controller.toolbarButtonToggler.remove(Attribute.lineHeight.key);
return attr;
}
return widget.controller
.getSelectionStyle()
.attributes[Attribute.lineHeight.key] ??
Attribute.lineHeight;
}
String _label(Attribute<dynamic> attribute) {
var label = LineHeightAttribute.lineHeightNormal.value.toString();
if (attribute.value != null) {
label = attribute.value.toString();
}
return label;
}
List<Attribute<dynamic>> get lineHeightAttributes {
return widget.options.attributes ??
[
LineHeightAttribute.lineHeightNormal,
LineHeightAttribute.lineHeightTight,
LineHeightAttribute.lineHeightOneAndHalf,
LineHeightAttribute.lineHeightDouble,
];
}
void _onPressed(Attribute<dynamic> e) {
setState(() => _selectedItem = e);
widget.controller.formatSelection(_selectedItem);
}
@override
Widget build(BuildContext context) {
final baseButtonConfigurations = context.quillToolbarBaseButtonOptions;
final childBuilder =
widget.options.childBuilder ?? baseButtonConfigurations?.childBuilder;
if (childBuilder != null) {
return childBuilder(
widget.options,
QuillToolbarSelectLineHeightStyleDropdownButtonExtraOptions(
currentValue: _selectedItem,
context: context,
controller: widget.controller,
onPressed: () {
throw UnimplementedError('Not implemented yet.');
},
),
);
}
return Builder(
builder: (context) {
final isMaterial3 = Theme.of(context).useMaterial3;
final child = Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_label(_selectedItem),
style: widget.options.textStyle ??
TextStyle(
fontSize: iconSize / 1.15,
),
),
Icon(
Icons.arrow_drop_down,
size: iconSize * iconButtonFactor,
),
],
);
if (!isMaterial3) {
return RawMaterialButton(
onPressed: () => _onDropdownButtonPressed(context),
child: child,
);
}
return _QuillToolbarLineHeightIcon(
iconTheme: iconTheme,
tooltip: tooltip,
onPressed: _onDropdownButtonPressed,
child: child,
);
},
);
}
Future<void> _onDropdownButtonPressed(BuildContext context) async {
final position = _renderPosition(context);
await showMenu<Attribute<dynamic>>(
context: context,
position: position,
items: lineHeightAttributes
.map(
(e) => PopupMenuItem(
value: e,
child: Text(_label(e)),
),
)
.toList())
.then<void>(
(value) {
if (value != null) {
_onPressed(value);
}
},
);
}
RelativeRect _renderPosition(BuildContext context) {
final size = MediaQuery.sizeOf(context);
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
final button = context.findRenderObject() as RenderBox;
final position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(const Offset(0, -65), ancestor: overlay),
button.localToGlobal(
button.size.bottomRight(Offset.zero) + const Offset(-50, 0),
ancestor: overlay),
),
Offset.zero & size * 0.40,
);
return position;
}
}
class _QuillToolbarLineHeightIcon extends StatelessWidget {
const _QuillToolbarLineHeightIcon({
required this.tooltip,
required this.iconTheme,
required this.onPressed,
required this.child,
});
final Row child;
final void Function(BuildContext) onPressed;
final QuillIconTheme? iconTheme;
final String tooltip;
@override
Widget build(BuildContext context) {
return QuillToolbarIconButton(
icon: child,
isSelected: false,
iconTheme: iconTheme,
tooltip: tooltip,
onPressed: () => onPressed(context),
);
}
}

@ -31,6 +31,7 @@ class QuillSimpleToolbar extends StatelessWidget
configurations.showItalicButton ||
configurations.showSmallButton ||
configurations.showUnderLineButton ||
configurations.showLineHeightButton ||
configurations.showStrikeThrough ||
configurations.showInlineCode ||
configurations.showColorButton ||
@ -195,6 +196,12 @@ class QuillSimpleToolbar extends StatelessWidget
isButtonGroupShown[4] ||
isButtonGroupShown[5]))
divider,
if (configurations.showLineHeightButton)
QuillToolbarSelectLineHeightStyleDropdownButton(
controller: globalController,
options: toolbarConfigurations
.buttonOptions.selectLineHeightStyleDropdownButton,
),
if (configurations.showHeaderStyle) ...[
if (configurations.headerStyleType.isOriginal)
QuillToolbarSelectHeaderStyleDropdownButton(

@ -18,7 +18,7 @@ import 'package:yaml/yaml.dart';
// This must be updated once add or remove some translation keys
// if you update existing keys, no need to update it
const _expectedTranslationKeysLength = 99;
const _expectedTranslationKeysLength = 100;
Future<void> main(List<String> args) async {
final l10nYamlText = await File('l10n.yaml').readAsString();

@ -372,6 +372,7 @@ void main() {
'blockquote' => Attribute.blockQuote,
'indent' => Attribute.indentL2,
'direction' => Attribute.rtl,
'line-height' => LineHeightAttribute.lineHeightNormal,
String() => throw UnimplementedError(key)
};

Loading…
Cancel
Save