dartlangeditorflutterflutter-appsflutter-examplesflutter-packageflutter-widgetquillquill-deltaquilljsreactquillrich-textrich-text-editorwysiwygwysiwyg-editor
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.1 KiB
143 lines
4.1 KiB
4 years ago
|
import 'package:flutter/cupertino.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:flutter_quill/widgets/controller.dart';
|
||
|
import 'package:flutter_quill/widgets/delegate.dart';
|
||
|
import 'package:flutter_quill/widgets/editor.dart';
|
||
|
|
||
|
class QuillField extends StatefulWidget {
|
||
|
final QuillController controller;
|
||
4 years ago
|
final FocusNode? focusNode;
|
||
|
final ScrollController? scrollController;
|
||
4 years ago
|
final bool scrollable;
|
||
|
final EdgeInsetsGeometry padding;
|
||
|
final bool autofocus;
|
||
|
final bool showCursor;
|
||
|
final bool readOnly;
|
||
|
final bool enableInteractiveSelection;
|
||
4 years ago
|
final double? minHeight;
|
||
|
final double? maxHeight;
|
||
4 years ago
|
final bool expands;
|
||
|
final TextCapitalization textCapitalization;
|
||
|
final Brightness keyboardAppearance;
|
||
4 years ago
|
final ScrollPhysics? scrollPhysics;
|
||
|
final ValueChanged<String>? onLaunchUrl;
|
||
|
final InputDecoration? decoration;
|
||
|
final Widget? toolbar;
|
||
|
final EmbedBuilder? embedBuilder;
|
||
4 years ago
|
|
||
|
QuillField({
|
||
4 years ago
|
Key? key,
|
||
|
required this.controller,
|
||
4 years ago
|
this.focusNode,
|
||
|
this.scrollController,
|
||
|
this.scrollable = true,
|
||
|
this.padding = EdgeInsets.zero,
|
||
|
this.autofocus = false,
|
||
|
this.showCursor = true,
|
||
|
this.readOnly = false,
|
||
|
this.enableInteractiveSelection = true,
|
||
|
this.minHeight,
|
||
|
this.maxHeight,
|
||
|
this.expands = false,
|
||
|
this.textCapitalization = TextCapitalization.sentences,
|
||
|
this.keyboardAppearance = Brightness.light,
|
||
|
this.scrollPhysics,
|
||
|
this.onLaunchUrl,
|
||
|
this.decoration,
|
||
|
this.toolbar,
|
||
|
this.embedBuilder,
|
||
|
}) : super(key: key);
|
||
|
|
||
|
@override
|
||
|
_QuillFieldState createState() => _QuillFieldState();
|
||
|
}
|
||
|
|
||
|
class _QuillFieldState extends State<QuillField> {
|
||
4 years ago
|
late bool _focused;
|
||
4 years ago
|
|
||
|
void _editorFocusChanged() {
|
||
|
setState(() {
|
||
4 years ago
|
_focused = widget.focusNode!.hasFocus;
|
||
4 years ago
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
4 years ago
|
_focused = widget.focusNode!.hasFocus;
|
||
|
widget.focusNode!.addListener(_editorFocusChanged);
|
||
4 years ago
|
}
|
||
|
|
||
|
@override
|
||
|
void didUpdateWidget(covariant QuillField oldWidget) {
|
||
|
super.didUpdateWidget(oldWidget);
|
||
|
if (widget.focusNode != oldWidget.focusNode) {
|
||
4 years ago
|
oldWidget.focusNode!.removeListener(_editorFocusChanged);
|
||
|
widget.focusNode!.addListener(_editorFocusChanged);
|
||
|
_focused = widget.focusNode!.hasFocus;
|
||
4 years ago
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
Widget child = QuillEditor(
|
||
4 years ago
|
controller: widget.controller,
|
||
4 years ago
|
focusNode: widget.focusNode!,
|
||
|
scrollController: widget.scrollController!,
|
||
4 years ago
|
scrollable: widget.scrollable,
|
||
|
padding: widget.padding,
|
||
|
autoFocus: widget.autofocus,
|
||
|
showCursor: widget.showCursor,
|
||
|
readOnly: widget.readOnly,
|
||
|
enableInteractiveSelection: widget.enableInteractiveSelection,
|
||
|
minHeight: widget.minHeight,
|
||
|
maxHeight: widget.maxHeight,
|
||
|
expands: widget.expands,
|
||
|
textCapitalization: widget.textCapitalization,
|
||
|
keyboardAppearance: widget.keyboardAppearance,
|
||
|
scrollPhysics: widget.scrollPhysics,
|
||
|
onLaunchUrl: widget.onLaunchUrl,
|
||
4 years ago
|
embedBuilder: widget.embedBuilder!,
|
||
4 years ago
|
);
|
||
|
|
||
|
if (widget.toolbar != null) {
|
||
|
child = Column(
|
||
|
children: [
|
||
|
child,
|
||
|
Visibility(
|
||
4 years ago
|
child: widget.toolbar!,
|
||
4 years ago
|
visible: _focused,
|
||
|
maintainSize: true,
|
||
|
maintainAnimation: true,
|
||
|
maintainState: true,
|
||
|
),
|
||
|
],
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return AnimatedBuilder(
|
||
|
animation:
|
||
4 years ago
|
Listenable.merge(<Listenable?>[widget.focusNode, widget.controller]),
|
||
|
builder: (BuildContext context, Widget? child) {
|
||
4 years ago
|
return InputDecorator(
|
||
|
decoration: _getEffectiveDecoration(),
|
||
4 years ago
|
isFocused: widget.focusNode!.hasFocus,
|
||
4 years ago
|
// TODO: Document should be considered empty of it has single empty line with no styles applied
|
||
|
isEmpty: widget.controller.document.length == 1,
|
||
|
child: child,
|
||
|
);
|
||
|
},
|
||
|
child: child,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
InputDecoration _getEffectiveDecoration() {
|
||
|
return (widget.decoration ?? const InputDecoration())
|
||
|
.applyDefaults(Theme.of(context).inputDecorationTheme)
|
||
|
.copyWith(
|
||
|
enabled: !widget.readOnly,
|
||
|
hintMaxLines: widget.decoration?.hintMaxLines,
|
||
|
);
|
||
|
}
|
||
|
}
|