Skip to content

Commit 4fb26e9

Browse files
committed
added keyboard shortcuts, bold and italic
1 parent f0414be commit 4fb26e9

File tree

7 files changed

+179
-92
lines changed

7 files changed

+179
-92
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.13 - 10-July-2022
2+
* Added shortcut Ctrl+B: Bold text
3+
* Added shortcut Ctrl+I: Italic text
4+
15
## 0.2.12 - 30-June-2022
26
* Added clear and reset buttons in toolbar
37
* Added readOnly option in Split Markdown Field

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ packages:
115115
path: ".."
116116
relative: true
117117
source: path
118-
version: "0.2.12"
118+
version: "0.2.13"
119119
matcher:
120120
dependency: transitive
121121
description:

lib/src/constants.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import 'package:flutter/material.dart';
2+
3+
class BoldTextIntent extends Intent {}
4+
5+
class ItalicTextIntent extends Intent {}

lib/widgets/markdown_auto_preview.dart

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
23
import 'package:flutter_markdown/flutter_markdown.dart';
4+
import '../src/constants.dart';
35
import '../src/emoji_input_formatter.dart';
6+
import '../src/toolbar.dart';
47
import 'markdown_toolbar.dart';
58

69
class MarkdownAutoPreview extends StatefulWidget {
@@ -186,19 +189,60 @@ class _MarkdownAutoPreviewState extends State<MarkdownAutoPreview> {
186189
final FocusNode _textFieldFocusNode =
187190
FocusNode(debugLabel: '_textFieldFocusNode');
188191

192+
late Toolbar _toolbar;
193+
189194
bool _focused = false;
190195

191196
@override
192197
void initState() {
193198
_internalController = widget.controller ?? TextEditingController();
194199

200+
_toolbar = Toolbar(
201+
controller: _internalController,
202+
bringEditorToFocus: () {
203+
if (!_textFieldFocusNode.hasFocus) {
204+
setState(() {
205+
_focused = true;
206+
});
207+
208+
_textFieldFocusNode.requestFocus();
209+
}
210+
},
211+
);
212+
195213
super.initState();
196214
}
197215

198216
@override
199217
Widget build(BuildContext context) {
200-
return FocusScope(
201-
debugLabel: 'Markdown-Form-Field-FocusNode',
218+
return FocusableActionDetector(
219+
shortcuts: {
220+
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyB):
221+
BoldTextIntent(),
222+
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyI):
223+
ItalicTextIntent(),
224+
},
225+
actions: {
226+
BoldTextIntent: CallbackAction<BoldTextIntent>(
227+
onInvoke: (intent) {
228+
_toolbar.action("**", "**");
229+
230+
// onActionCompleted
231+
// setState(() {});
232+
return null;
233+
},
234+
),
235+
ItalicTextIntent: CallbackAction<ItalicTextIntent>(
236+
onInvoke: (intent) {
237+
_toolbar.action("_", "_");
238+
239+
// onActionCompleted
240+
// setState(() {});
241+
return null;
242+
},
243+
),
244+
},
245+
202246
onFocusChange: (focus) {
203247
setState(() {
204248
_focused = focus;
@@ -207,7 +251,7 @@ class _MarkdownAutoPreviewState extends State<MarkdownAutoPreview> {
207251
if (_focused) _internalFocus.requestFocus(_textFieldFocusNode);
208252
},
209253
// canRequestFocus: false,
210-
node: _internalFocus,
254+
focusNode: _internalFocus,
211255
child: _focused
212256
? _editorOnFocused()
213257
: GestureDetector(
@@ -218,7 +262,7 @@ class _MarkdownAutoPreviewState extends State<MarkdownAutoPreview> {
218262
});
219263

220264
// Then request for focus when widget is built
221-
_internalFocus.requestFocus(_textFieldFocusNode);
265+
_textFieldFocusNode.requestFocus();
222266
},
223267
child: Align(
224268
alignment: Alignment.centerLeft,
@@ -249,15 +293,7 @@ class _MarkdownAutoPreviewState extends State<MarkdownAutoPreview> {
249293
// key: const ValueKey<String>("zmarkdowntoolbar"),
250294
controller: _internalController,
251295
autoCloseAfterSelectEmoji: widget.autoCloseAfterSelectEmoji,
252-
bringEditorToFocus: () {
253-
if (!_textFieldFocusNode.hasFocus) {
254-
setState(() {
255-
_focused = true;
256-
});
257-
258-
_textFieldFocusNode.requestFocus();
259-
}
260-
},
296+
toolbar: _toolbar,
261297
onPreviewChanged: () {
262298
// Remove focus first
263299
_internalFocus.unfocus();

lib/widgets/markdown_toolbar.dart

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,26 @@ class MarkdownToolbar extends StatelessWidget {
1515
final Toolbar toolbar;
1616
final Color? toolbarBackground;
1717
final Color? expandableBackground;
18-
final VoidCallback? bringEditorToFocus;
1918
final bool showPreviewButton;
2019
final bool showEmojiSelection;
2120
final VoidCallback? onActionCompleted;
2221
final String? markdownSyntax;
2322

24-
MarkdownToolbar({
23+
const MarkdownToolbar({
2524
Key? key,
2625
this.onPreviewChanged,
2726
this.markdownSyntax,
2827
required this.controller,
2928
this.emojiConvert = true,
3029
this.unfocus,
31-
this.bringEditorToFocus,
30+
required this.toolbar,
3231
this.autoCloseAfterSelectEmoji = true,
3332
this.toolbarBackground,
3433
this.expandableBackground,
3534
this.onActionCompleted,
3635
this.showPreviewButton = true,
3736
this.showEmojiSelection = true,
38-
}) : toolbar = Toolbar(
39-
controller: controller,
40-
bringEditorToFocus: bringEditorToFocus,
41-
),
42-
super(key: key);
37+
}) : super(key: key);
4338

4439
@override
4540
Widget build(BuildContext context) {
@@ -159,6 +154,16 @@ class MarkdownToolbar extends StatelessWidget {
159154
onActionCompleted?.call();
160155
},
161156
),
157+
ToolbarItem(
158+
key: const ValueKey<String>("h4"),
159+
icon: "H4",
160+
tooltip: 'Insert Heading 4',
161+
onPressedButton: () {
162+
toolbar.action("#### ", "");
163+
onActionCompleted?.call();
164+
},
165+
),
166+
// Heading 5 onwards has same font
162167
],
163168
),
164169
// unorder list

lib/widgets/splitted_markdown_form_field.dart

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
23
import 'package:flutter_markdown/flutter_markdown.dart';
4+
import 'package:markdown_editor_plus/src/toolbar.dart';
5+
import '../src/constants.dart';
36
import '../src/emoji_input_formatter.dart';
47
import 'markdown_toolbar.dart';
58

@@ -202,87 +205,121 @@ class _SplittedMarkdownFormFieldState extends State<SplittedMarkdownFormField> {
202205
// Internal parameter
203206
late TextEditingController _internalController;
204207
final FocusNode _focusNode = FocusNode();
208+
late Toolbar _toolbar;
205209

206210
@override
207211
void initState() {
208212
_internalController = widget.controller ?? TextEditingController();
209213

214+
_toolbar = Toolbar(
215+
controller: _internalController,
216+
bringEditorToFocus: () {
217+
_focusNode.requestFocus();
218+
},
219+
);
220+
210221
super.initState();
211222
}
212223

213224
@override
214225
Widget build(BuildContext context) {
215-
return LayoutBuilder(
216-
builder: (context, constraints) {
217-
return Column(
218-
mainAxisAlignment: MainAxisAlignment.start,
219-
crossAxisAlignment: CrossAxisAlignment.center,
220-
mainAxisSize: MainAxisSize.min,
221-
children: [
222-
Row(
223-
children: [
224-
Expanded(
225-
child: TextFormField(
226-
readOnly: widget.readOnly,
227-
controller: _internalController,
228-
cursorColor: widget.cursorColor,
229-
focusNode: _focusNode,
230-
inputFormatters: [
231-
if (widget.emojiConvert) EmojiInputFormatter(),
232-
],
233-
onChanged: (value) {
234-
setState(() {});
235-
widget.onChanged?.call(value);
236-
},
237-
onTap: widget.onTap,
238-
scrollController: widget.scrollController,
239-
style: widget.style,
240-
textCapitalization: widget.textCapitalization,
241-
maxLines: widget.maxLines,
242-
minLines: widget.minLines,
243-
expands: widget.expands,
244-
decoration: widget.decoration,
245-
validator: widget.validator,
246-
autovalidateMode: widget.autovalidateMode,
247-
onSaved: widget.onSaved,
226+
return FocusableActionDetector(
227+
shortcuts: {
228+
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyB):
229+
BoldTextIntent(),
230+
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyI):
231+
ItalicTextIntent(),
232+
},
233+
actions: {
234+
BoldTextIntent: CallbackAction<BoldTextIntent>(
235+
onInvoke: (intent) {
236+
_toolbar.action("**", "**");
237+
238+
// onActionCompleted
239+
setState(() {});
240+
return null;
241+
},
242+
),
243+
ItalicTextIntent: CallbackAction<ItalicTextIntent>(
244+
onInvoke: (intent) {
245+
_toolbar.action("_", "_");
246+
247+
// onActionCompleted
248+
setState(() {});
249+
return null;
250+
},
251+
),
252+
},
253+
child: LayoutBuilder(
254+
builder: (context, constraints) {
255+
return Column(
256+
mainAxisAlignment: MainAxisAlignment.start,
257+
crossAxisAlignment: CrossAxisAlignment.center,
258+
mainAxisSize: MainAxisSize.min,
259+
children: [
260+
Row(
261+
children: [
262+
Expanded(
263+
child: TextFormField(
264+
readOnly: widget.readOnly,
265+
controller: _internalController,
266+
cursorColor: widget.cursorColor,
267+
focusNode: _focusNode,
268+
inputFormatters: [
269+
if (widget.emojiConvert) EmojiInputFormatter(),
270+
],
271+
onChanged: (value) {
272+
setState(() {});
273+
widget.onChanged?.call(value);
274+
},
275+
onTap: widget.onTap,
276+
scrollController: widget.scrollController,
277+
style: widget.style,
278+
textCapitalization: widget.textCapitalization,
279+
maxLines: widget.maxLines,
280+
minLines: widget.minLines,
281+
expands: widget.expands,
282+
decoration: widget.decoration,
283+
validator: widget.validator,
284+
autovalidateMode: widget.autovalidateMode,
285+
onSaved: widget.onSaved,
286+
),
248287
),
249-
),
250-
// Some padding
251-
const SizedBox(width: 8.0),
252-
Expanded(
253-
child: MarkdownBody(
254-
// key: const ValueKey<String>("zmarkdown-parse-body"),
255-
data: _internalController.text == ""
256-
? "_Markdown text_"
257-
: _internalController.text,
258-
selectable: true,
288+
// Some padding
289+
const SizedBox(width: 8.0),
290+
Expanded(
291+
child: MarkdownBody(
292+
// key: const ValueKey<String>("zmarkdown-parse-body"),
293+
data: _internalController.text == ""
294+
? "_Markdown text_"
295+
: _internalController.text,
296+
selectable: true,
297+
),
259298
),
260-
),
261-
],
262-
),
263-
264-
// show toolbar
265-
if (widget.enableToolBar)
266-
MarkdownToolbar(
267-
markdownSyntax: widget.markdownSyntax,
268-
showPreviewButton: false,
269-
// key: const ValueKey<String>("zmarkdowntoolbar"),
270-
controller: _internalController,
271-
autoCloseAfterSelectEmoji: widget.autoCloseAfterSelectEmoji,
272-
emojiConvert: widget.emojiConvert,
273-
toolbarBackground: widget.toolbarBackground,
274-
expandableBackground: widget.expandableBackground,
275-
bringEditorToFocus: () {
276-
_focusNode.requestFocus();
277-
},
278-
onActionCompleted: () {
279-
setState(() {});
280-
},
281-
showEmojiSelection: widget.showEmojiSelection,
282-
)
283-
],
284-
);
285-
},
299+
],
300+
),
301+
302+
// show toolbar
303+
if (widget.enableToolBar)
304+
MarkdownToolbar(
305+
markdownSyntax: widget.markdownSyntax,
306+
showPreviewButton: false,
307+
// key: const ValueKey<String>("zmarkdowntoolbar"),
308+
controller: _internalController,
309+
autoCloseAfterSelectEmoji: widget.autoCloseAfterSelectEmoji,
310+
emojiConvert: widget.emojiConvert,
311+
toolbarBackground: widget.toolbarBackground,
312+
expandableBackground: widget.expandableBackground,
313+
toolbar: _toolbar,
314+
onActionCompleted: () {
315+
setState(() {});
316+
},
317+
showEmojiSelection: widget.showEmojiSelection,
318+
)
319+
],
320+
);
321+
},
322+
),
286323
);
287324
}
288325
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: markdown_editor_plus
22
description: A TextField Widget that allow you to convert easily what's in the
33
TextField to Markdown with custom toolbar support.
44

5-
version: 0.2.12
5+
version: 0.2.13
66
homepage: https://github.com/OmkarDabade/markdown_editor_plus
77
repository: https://github.com/OmkarDabade/markdown_editor_plus
88

0 commit comments

Comments
 (0)