@@ -197,9 +197,10 @@ class FPopover extends StatefulWidget {
197
197
/// Controls the transfer of focus beyond the first and the last items in a popover. Defaults to
198
198
/// [TraversalEdgeBehavior.closedLoop] .
199
199
///
200
- /// Changing this field value has no immediate effect on the UI.
200
+ /// ## Contract
201
+ /// Throws [AssertionError] if both [focusNode] and [traversalEdgeBehavior] are not null.
201
202
/// {@endtemplate}
202
- final TraversalEdgeBehavior traversalEdgeBehavior;
203
+ final TraversalEdgeBehavior ? traversalEdgeBehavior;
203
204
204
205
/// {@template forui.widgets.FPopover.barrierSemanticsLabel}
205
206
/// The popover's barrier label used by accessibility frameworks.
@@ -257,7 +258,7 @@ class FPopover extends StatefulWidget {
257
258
this .autofocus,
258
259
this .focusNode,
259
260
this .onFocusChange,
260
- this .traversalEdgeBehavior = TraversalEdgeBehavior .closedLoop ,
261
+ this .traversalEdgeBehavior,
261
262
this .barrierSemanticsLabel,
262
263
this .barrierSemanticsDismissible = true ,
263
264
this .semanticsLabel,
@@ -271,6 +272,10 @@ class FPopover extends StatefulWidget {
271
272
groupId == null || hideOnTapOutside == FHidePopoverRegion .excludeTarget,
272
273
'groupId can only be used with FHidePopoverRegion.excludeTarget' ,
273
274
),
275
+ assert (
276
+ focusNode == null || traversalEdgeBehavior == null ,
277
+ 'focusNode and traversalEdgeBehavior cannot both be set.' ,
278
+ ),
274
279
assert (builder != _builder || child != null , 'Either builder or child must be provided.' ),
275
280
popoverAnchor = popoverAnchor ?? defaultPlatform.popover,
276
281
childAnchor = childAnchor ?? defaultPlatform.child;
@@ -314,6 +319,15 @@ class FPopover extends StatefulWidget {
314
319
class _State extends State <FPopover > with SingleTickerProviderStateMixin {
315
320
late Object ? _groupId = widget.groupId ?? UniqueKey ();
316
321
late FPopoverController _controller = widget.controller ?? FPopoverController (vsync: this );
322
+ FocusScopeNode ? _focusNode;
323
+
324
+ @override
325
+ void initState () {
326
+ super .initState ();
327
+ _focusNode =
328
+ widget.focusNode ??
329
+ FocusScopeNode (traversalEdgeBehavior: widget.traversalEdgeBehavior ?? TraversalEdgeBehavior .closedLoop);
330
+ }
317
331
318
332
@override
319
333
void didUpdateWidget (covariant FPopover old) {
@@ -322,6 +336,16 @@ class _State extends State<FPopover> with SingleTickerProviderStateMixin {
322
336
_groupId = widget.groupId ?? UniqueKey ();
323
337
}
324
338
339
+ if (widget.focusNode != old.focusNode || widget.traversalEdgeBehavior != old.traversalEdgeBehavior) {
340
+ if (old.focusNode == null ) {
341
+ _focusNode? .dispose ();
342
+ }
343
+
344
+ _focusNode =
345
+ widget.focusNode ??
346
+ FocusScopeNode (traversalEdgeBehavior: widget.traversalEdgeBehavior ?? TraversalEdgeBehavior .closedLoop);
347
+ }
348
+
325
349
if (widget.controller != old.controller) {
326
350
if (old.controller == null ) {
327
351
_controller.dispose ();
@@ -330,6 +354,18 @@ class _State extends State<FPopover> with SingleTickerProviderStateMixin {
330
354
}
331
355
}
332
356
357
+ @override
358
+ void dispose () {
359
+ if (widget.focusNode == null ) {
360
+ _focusNode? .dispose ();
361
+ }
362
+
363
+ if (widget.controller == null ) {
364
+ _controller.dispose ();
365
+ }
366
+ super .dispose ();
367
+ }
368
+
333
369
@override
334
370
Widget build (BuildContext context) {
335
371
final style = widget.style? .call (context.theme.popoverStyle) ?? context.theme.popoverStyle;
@@ -374,7 +410,7 @@ class _State extends State<FPopover> with SingleTickerProviderStateMixin {
374
410
container: true ,
375
411
child: FocusScope (
376
412
autofocus: widget.autofocus ?? (style.barrierFilter != null ),
377
- node: widget.focusNode ,
413
+ node: _focusNode ,
378
414
onFocusChange: widget.onFocusChange,
379
415
child: TapRegion (
380
416
groupId: _groupId,
@@ -423,14 +459,6 @@ class _State extends State<FPopover> with SingleTickerProviderStateMixin {
423
459
_controller.hide ();
424
460
}
425
461
}
426
-
427
- @override
428
- void dispose () {
429
- if (widget.controller == null ) {
430
- _controller.dispose ();
431
- }
432
- super .dispose ();
433
- }
434
462
}
435
463
436
464
/// A [FPopover] 's style.
0 commit comments