Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Infrastructure] Implement custom dropdown widget (Resolves #1527, Resolves #731, Resolves #689) #1538

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b9fbd90
Implement the dropdown widget
angelosilvestre Oct 20, 2023
9862741
PR updates
angelosilvestre Oct 21, 2023
7ecbeb5
Change dropdown alignment
angelosilvestre Oct 27, 2023
e0ebe87
Simplify animation
angelosilvestre Oct 27, 2023
d1b1376
Remove unused import
angelosilvestre Oct 27, 2023
e3f77b1
Rename the dropdown widget and update docs
angelosilvestre Nov 2, 2023
fb7fffc
PR Updates
angelosilvestre Nov 2, 2023
96eba09
Remove required boundaryKey
angelosilvestre Nov 2, 2023
39a5a55
Remove constrained box
angelosilvestre Nov 2, 2023
c20c1eb
Rebuild the toolbar when document changes
angelosilvestre Nov 2, 2023
bb1642a
Fix failing tests
angelosilvestre Nov 2, 2023
790533b
Make parentFocusNode optional
angelosilvestre Nov 2, 2023
652d762
Activate the selected item
angelosilvestre Nov 2, 2023
d40ac73
Rebuild fewer widgets when document changes
angelosilvestre Nov 3, 2023
7ee0510
Update API
angelosilvestre Nov 11, 2023
4389096
Implement autoscroll
angelosilvestre Nov 11, 2023
1522043
Update import
angelosilvestre Nov 11, 2023
d799dc4
API updates
angelosilvestre Nov 14, 2023
6edb852
Temporarily disable tests
angelosilvestre Nov 14, 2023
f217937
PR updates
angelosilvestre Nov 15, 2023
82be137
Replace _DelegateAligner with FunctionalAligner
angelosilvestre Nov 27, 2023
c0642f3
Update docs
angelosilvestre Nov 27, 2023
692a1b5
Update dependencies
angelosilvestre Dec 4, 2023
e8f023d
PR updates
angelosilvestre Dec 8, 2023
ef1f34e
PR updates
angelosilvestre Dec 8, 2023
e602f20
Rename dropdown to popover and add onTapOutSide configuration
angelosilvestre Dec 8, 2023
ad8eb10
Default popover tap outside
angelosilvestre Dec 8, 2023
3395d45
Split files
angelosilvestre Dec 8, 2023
4d22abf
PR updates
angelosilvestre Dec 8, 2023
bd4ed5d
Move focus sharing to the scaffold
angelosilvestre Dec 11, 2023
9d2a42f
Add tests
angelosilvestre Dec 13, 2023
6de054d
Test updates
angelosilvestre Dec 21, 2023
d986e6a
Split test files
angelosilvestre Dec 21, 2023
e306b88
Add tests for default popover geometry
angelosilvestre Dec 24, 2023
5bd8ff9
Fix popover size when using boundary key
angelosilvestre Dec 26, 2023
724dd1a
Update tests
angelosilvestre Dec 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 77 additions & 48 deletions super_editor/example/lib/demos/example_editor/_toolbar.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:math';

import 'package:example/demos/infrastructure/super_editor_item_selector.dart';
import 'package:example/logging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Expand Down Expand Up @@ -100,6 +101,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
_urlFocusNode.dispose();
_urlController!.dispose();
_popoverFocusNode.dispose();

super.dispose();
}

Expand Down Expand Up @@ -139,7 +141,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
} else if (selectedNode is ListItemNode) {
return selectedNode.type == ListItemType.ordered ? _TextType.orderedListItem : _TextType.unorderedListItem;
} else {
throw Exception('Invalid node type: $selectedNode');
throw Exception('Alignment does not apply to node of type: $selectedNode');
}
}

Expand All @@ -163,7 +165,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
return TextAlign.left;
}
} else {
throw Exception('Alignment does not apply to node of type: $selectedNode');
throw Exception('Invalid node type: $selectedNode');
}
}

Expand Down Expand Up @@ -469,6 +471,26 @@ class _EditorToolbarState extends State<EditorToolbar> {
}
}

/// Called when the user selects a block type on the toolbar.
void _onBlockTypeSelected(SuperEditorDemoTextItem? selectedItem) {
if (selectedItem != null) {
setState(() {
_convertTextToNewType(_TextType.values //
.where((e) => e.name == selectedItem.id)
.first);
});
}
}

/// Called when the user selects an alignment on the toolbar.
void _onAlignmentSelected(SuperEditorDemoIconItem? selectedItem) {
if (selectedItem != null) {
setState(() {
_changeAlignment(TextAlign.values.firstWhere((e) => e.name == selectedItem.id));
});
}
}

@override
Widget build(BuildContext context) {
return BuildInOrder(
Expand Down Expand Up @@ -521,27 +543,7 @@ class _EditorToolbarState extends State<EditorToolbar> {
if (_isConvertibleNode()) ...[
Tooltip(
message: AppLocalizations.of(context)!.labelTextBlockType,
child: DropdownButton<_TextType>(
value: _getCurrentTextType(),
items: _TextType.values
.map((textType) => DropdownMenuItem<_TextType>(
value: textType,
child: Padding(
padding: const EdgeInsets.only(left: 16.0),
child: Text(_getTextTypeName(textType)),
),
))
.toList(),
icon: const Icon(Icons.arrow_drop_down),
style: const TextStyle(
color: Colors.black,
fontSize: 12,
),
underline: const SizedBox(),
elevation: 0,
itemHeight: 48,
onChanged: _convertTextToNewType,
),
child: _buildBlockTypeSelector(),
),
_buildVerticalDivider(),
],
Expand Down Expand Up @@ -580,33 +582,18 @@ class _EditorToolbarState extends State<EditorToolbar> {
),
// Only display alignment controls if the currently selected text
// node respects alignment. List items, for example, do not.
if (_isTextAlignable()) ...[
_buildVerticalDivider(),
Tooltip(
message: AppLocalizations.of(context)!.labelTextAlignment,
child: DropdownButton<TextAlign>(
value: _getCurrentTextAlignment(),
items: [TextAlign.left, TextAlign.center, TextAlign.right, TextAlign.justify]
.map((textAlign) => DropdownMenuItem<TextAlign>(
value: textAlign,
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Icon(_buildTextAlignIcon(textAlign)),
),
))
.toList(),
icon: const Icon(Icons.arrow_drop_down),
style: const TextStyle(
color: Colors.black,
fontSize: 12,
if (_isTextAlignable()) //
Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildVerticalDivider(),
Tooltip(
message: AppLocalizations.of(context)!.labelTextAlignment,
child: _buildAlignmentSelector(),
),
underline: const SizedBox(),
elevation: 0,
itemHeight: 48,
onChanged: _changeAlignment,
),
],
),
],

_buildVerticalDivider(),
Center(
child: IconButton(
Expand All @@ -623,6 +610,48 @@ class _EditorToolbarState extends State<EditorToolbar> {
);
}

Widget _buildAlignmentSelector() {
final alignment = _getCurrentTextAlignment();
return SuperEditorDemoIconItemSelector(
parentFocusNode: widget.editorFocusNode,
boundaryKey: widget.editorViewportKey,
value: SuperEditorDemoIconItem(
id: alignment.name,
icon: _buildTextAlignIcon(alignment),
),
items: TextAlign.values
.map(
(alignment) => SuperEditorDemoIconItem(
icon: _buildTextAlignIcon(alignment),
id: alignment.name,
),
)
.toList(),
onSelected: _onAlignmentSelected,
);
}

Widget _buildBlockTypeSelector() {
final currentBlockType = _getCurrentTextType();
return SuperEditorDemoTextItemSelector(
parentFocusNode: widget.editorFocusNode,
boundaryKey: widget.editorViewportKey,
id: SuperEditorDemoTextItem(
id: currentBlockType.name,
label: _getTextTypeName(currentBlockType),
),
items: _TextType.values
.map(
(blockType) => SuperEditorDemoTextItem(
id: blockType.name,
label: _getTextTypeName(blockType),
),
)
.toList(),
onSelected: _onBlockTypeSelected,
);
}

Widget _buildUrlField() {
return Material(
shape: const StadiumBorder(),
Expand Down
Loading
Loading