Skip to content

Commit 8e46a5e

Browse files
committed
Text input Update (bdlukaa#179)
2 parents de1fff1 + 1c00bde commit 8e46a5e

10 files changed

Lines changed: 460 additions & 118 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
Date format: DD/MM/YYYY
22

3+
## [unreleased] - Input Update
4+
5+
- `TextBox` updates: ([#179](https://github.com/bdlukaa/fluent_ui/pull/179))
6+
- Correctly apply the `style` property
7+
- Correctly apply `decoration` to the background
8+
- Added `foregroundDecoration` and `highlightColor` property. They can not be specified at the same time
9+
- **BREAKING** replaced `maxLengthEnforeced` with `maxLengthEnforcement`
10+
- Expose more propertied to `TextFormBox`
11+
- `AutoSuggestBox` updates:
12+
- Improved fidelity of the suggestions overlay
13+
- When a suggestion is picked, the overlay is automatically closed and the text box is unfocused
14+
- Clear button now only shows when the text box is focused
15+
316
## [3.9.0] - Fidelity - [10/02/2022]
417

518
- **BREAKING** Renamed `standartCurve` to `standardCurve`

example/lib/screens/forms.dart

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ class _FormsState extends State<Forms> {
3535

3636
DateTime date = DateTime.now();
3737

38+
@override
39+
void initState() {
40+
super.initState();
41+
_clearController.addListener(() {
42+
if (_clearController.text.length == 1 && mounted) setState(() {});
43+
});
44+
}
45+
46+
@override
47+
void dispose() {
48+
_clearController.dispose();
49+
super.dispose();
50+
}
51+
3852
@override
3953
Widget build(BuildContext context) {
4054
return ScaffoldPage.scrollable(
@@ -57,10 +71,11 @@ class _FormsState extends State<Forms> {
5771
),
5872
const SizedBox(height: 20),
5973
Row(children: [
60-
const Expanded(
74+
Expanded(
6175
child: TextBox(
6276
readOnly: true,
6377
placeholder: 'Read only text box',
78+
highlightColor: Colors.magenta,
6479
),
6580
),
6681
const SizedBox(width: 10),
@@ -93,12 +108,14 @@ class _FormsState extends State<Forms> {
93108
controller: _clearController,
94109
suffixMode: OverlayVisibilityMode.always,
95110
minHeight: 100,
96-
suffix: IconButton(
97-
icon: const Icon(FluentIcons.chrome_close),
98-
onPressed: () {
99-
_clearController.clear();
100-
},
101-
),
111+
suffix: _clearController.text.isEmpty
112+
? null
113+
: IconButton(
114+
icon: const Icon(FluentIcons.chrome_close),
115+
onPressed: () {
116+
_clearController.clear();
117+
},
118+
),
102119
placeholder: 'Text box with clear button',
103120
),
104121
const SizedBox(height: 20),

example/pubspec.lock

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,6 @@ packages:
205205
url: "https://pub.dartlang.org"
206206
source: hosted
207207
version: "0.12.11"
208-
material_color_utilities:
209-
dependency: transitive
210-
description:
211-
name: material_color_utilities
212-
url: "https://pub.dartlang.org"
213-
source: hosted
214-
version: "0.1.3"
215208
meta:
216209
dependency: transitive
217210
description:
@@ -328,7 +321,7 @@ packages:
328321
name: test_api
329322
url: "https://pub.dartlang.org"
330323
source: hosted
331-
version: "0.4.8"
324+
version: "0.4.3"
332325
typed_data:
333326
dependency: transitive
334327
description:

lib/src/controls/form/auto_suggest_box.dart

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class _AutoSuggestBoxState<T> extends State<AutoSuggestBox> {
109109

110110
late TextEditingController controller;
111111

112+
final FocusScopeNode overlayNode = FocusScopeNode();
113+
112114
@override
113115
void initState() {
114116
super.initState();
@@ -153,6 +155,7 @@ class _AutoSuggestBoxState<T> extends State<AutoSuggestBox> {
153155
child: SizedBox(
154156
width: box.size.width,
155157
child: _AutoSuggestBoxOverlay(
158+
node: overlayNode,
156159
controller: controller,
157160
items: widget.items,
158161
onSelected: (String item) {
@@ -162,6 +165,11 @@ class _AutoSuggestBoxState<T> extends State<AutoSuggestBox> {
162165
offset: item.length,
163166
);
164167
widget.onChanged?.call(item, TextChangedReason.userInput);
168+
169+
// After selected, the overlay is dismissed and the text box is
170+
// unfocused
171+
_dismissOverlay();
172+
focusNode.unfocus();
165173
},
166174
),
167175
),
@@ -195,59 +203,77 @@ class _AutoSuggestBoxState<T> extends State<AutoSuggestBox> {
195203

196204
return CompositedTransformTarget(
197205
link: _layerLink,
198-
child: TextBox(
199-
key: _textBoxKey,
200-
controller: controller,
201-
focusNode: focusNode,
202-
placeholder: widget.placeholder,
203-
placeholderStyle: widget.placeholderStyle,
204-
clipBehavior: _entry != null ? Clip.none : Clip.antiAliasWithSaveLayer,
205-
suffix: Row(children: [
206-
if (widget.trailingIcon != null) widget.trailingIcon!,
207-
if (widget.clearButtonEnabled && controller.text.isNotEmpty)
208-
Padding(
209-
padding: const EdgeInsets.only(left: 2.0),
210-
child: IconButton(
211-
icon: const Icon(FluentIcons.chrome_close),
212-
onPressed: () {
213-
controller.clear();
214-
focusNode.unfocus();
215-
},
216-
),
217-
),
218-
]),
219-
suffixMode: OverlayVisibilityMode.always,
220-
onChanged: (text) {
221-
widget.onChanged?.call(text, TextChangedReason.userInput);
222-
_showOverlay();
206+
child: Actions(
207+
actions: {
208+
DirectionalFocusIntent: _DirectionalFocusAction(),
223209
},
210+
child: TextBox(
211+
key: _textBoxKey,
212+
controller: controller,
213+
focusNode: focusNode,
214+
placeholder: widget.placeholder,
215+
placeholderStyle: widget.placeholderStyle,
216+
clipBehavior:
217+
_entry != null ? Clip.none : Clip.antiAliasWithSaveLayer,
218+
suffix: Row(children: [
219+
if (widget.trailingIcon != null) widget.trailingIcon!,
220+
if (widget.clearButtonEnabled &&
221+
controller.text.isNotEmpty &&
222+
focusNode.hasFocus)
223+
Padding(
224+
padding: const EdgeInsets.only(left: 2.0),
225+
child: IconButton(
226+
icon: const Icon(FluentIcons.chrome_close),
227+
onPressed: () {
228+
controller.clear();
229+
focusNode.unfocus();
230+
},
231+
),
232+
),
233+
]),
234+
suffixMode: OverlayVisibilityMode.always,
235+
onChanged: (text) {
236+
widget.onChanged?.call(text, TextChangedReason.userInput);
237+
_showOverlay();
238+
},
239+
),
224240
),
225241
);
226242
}
227243
}
228244

245+
class _DirectionalFocusAction extends DirectionalFocusAction {
246+
@override
247+
void invoke(covariant DirectionalFocusIntent intent) {
248+
// if (!intent.ignoreTextFields || !_isForTextField) {
249+
// primaryFocus!.focusInDirection(intent.direction);
250+
// }
251+
debugPrint(intent.direction.toString());
252+
}
253+
}
254+
229255
class _AutoSuggestBoxOverlay extends StatelessWidget {
230256
const _AutoSuggestBoxOverlay({
231257
Key? key,
232258
required this.items,
233259
required this.controller,
234260
required this.onSelected,
261+
required this.node,
235262
}) : super(key: key);
236263

237264
final List items;
238265
final TextEditingController controller;
239266
final ValueChanged<String> onSelected;
267+
final FocusScopeNode node;
240268

241269
@override
242270
Widget build(BuildContext context) {
243271
final theme = FluentTheme.of(context);
244272
final localizations = FluentLocalizations.of(context);
245273
return FocusScope(
246-
autofocus: true,
274+
node: node,
247275
child: Container(
248-
constraints: const BoxConstraints(
249-
maxHeight: 385,
250-
),
276+
constraints: const BoxConstraints(maxHeight: 380),
251277
decoration: ShapeDecoration(
252278
shape: RoundedRectangleBorder(
253279
borderRadius: const BorderRadius.vertical(
@@ -281,9 +307,7 @@ class _AutoSuggestBoxOverlay extends StatelessWidget {
281307
final item = items[index];
282308
return _AutoSuggestBoxOverlayTile(
283309
text: '$item',
284-
onSelected: () {
285-
onSelected(item);
286-
},
310+
onSelected: () => onSelected(item),
287311
);
288312
}),
289313
);
@@ -314,6 +338,7 @@ class _AutoSuggestBoxOverlayTile extends StatefulWidget {
314338
class __AutoSuggestBoxOverlayTileState extends State<_AutoSuggestBoxOverlayTile>
315339
with SingleTickerProviderStateMixin {
316340
late AnimationController controller;
341+
final node = FocusNode();
317342

318343
@override
319344
void initState() {
@@ -328,19 +353,21 @@ class __AutoSuggestBoxOverlayTileState extends State<_AutoSuggestBoxOverlayTile>
328353
@override
329354
void dispose() {
330355
controller.dispose();
356+
node.dispose();
331357
super.dispose();
332358
}
333359

334360
@override
335361
Widget build(BuildContext context) {
336362
final theme = FluentTheme.of(context);
337363
return HoverButton(
364+
focusNode: node,
338365
onPressed: widget.onSelected,
339366
margin: const EdgeInsets.only(top: 4.0, left: 4.0, right: 4.0),
340367
builder: (context, states) => Stack(
341368
children: [
342369
Container(
343-
height: 40.0,
370+
height: 36.0,
344371
padding: const EdgeInsets.symmetric(horizontal: 10.0),
345372
decoration: BoxDecoration(
346373
borderRadius: BorderRadius.circular(6.0),

lib/src/controls/form/form_row.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class FormRow extends StatelessWidget {
4242
),
4343
),
4444
if (error != null)
45-
Align(
45+
Container(
46+
margin: const EdgeInsets.only(top: 2.0),
4647
alignment: AlignmentDirectional.centerStart,
4748
child: DefaultTextStyle(
4849
style: const TextStyle(

0 commit comments

Comments
 (0)