Skip to content
This repository was archived by the owner on May 20, 2023. It is now read-only.

Commit 042280b

Browse files
cissyshinshahan
authored andcommitted
Fix active item directive's scroll into view functionality in popups and modals.
PiperOrigin-RevId: 209880573
1 parent d14ee77 commit 042280b

File tree

1 file changed

+70
-15
lines changed

1 file changed

+70
-15
lines changed

lib/model/a11y/active_item_directive.dart

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:async';
56
import 'dart:html' as dom;
67

78
import 'package:angular/angular.dart';
89
import 'package:js/js_util.dart' as js_util;
10+
import 'package:angular_components/laminate/components/modal/modal.dart';
11+
import 'package:angular_components/laminate/popup/popup.dart';
912
import 'package:angular_components/utils/browser/dom_service/dom_service.dart';
1013

1114
/// Directive for elements able to be activated through mouse or keyboard, like
@@ -14,40 +17,92 @@ import 'package:angular_components/utils/browser/dom_service/dom_service.dart';
1417
/// Will scroll the item into view as long as it was made active when mouse is
1518
/// not hovering over it.
1619
@Directive(selector: '[itemActive]')
17-
class ActiveItemDirective {
20+
class ActiveItemDirective implements AfterViewInit, OnDestroy {
1821
/// Dom element of the item, that will be scrolled to view on activate.
19-
dom.HtmlElement _element;
22+
final dom.HtmlElement _element;
2023

2124
/// An instance of DomService, used to coordinate scrolling.
22-
DomService _domService;
25+
final DomService _domService;
26+
27+
/// Parent modal if any.
28+
final Modal _modal;
29+
30+
/// Parent popup if any.
31+
final PopupRef _popupRef;
2332

2433
bool _active = false;
2534

35+
bool _initialized = false;
36+
37+
StreamSubscription _visibilitySubscription;
38+
2639
/// Whether the element is active.
2740
@HostBinding('class.active')
2841
bool get active => _active;
2942

30-
ActiveItemDirective(this._element, this._domService);
43+
ActiveItemDirective(this._element, this._domService, @Optional() this._modal,
44+
@Optional() this._popupRef);
45+
46+
@override
47+
void ngOnDestroy() {
48+
_visibilitySubscription?.cancel();
49+
_visibilitySubscription = null;
50+
}
51+
52+
@override
53+
void ngAfterViewInit() {
54+
_initialized = true;
55+
_scrollIntoViewIfNecessary();
56+
}
3157

3258
/// Marks item as active from keyboard selection.
3359
@Input()
3460
set itemActive(bool value) {
3561
if (value == _active) return;
3662
_active = value;
37-
if (_active && !_hasHover) {
38-
_domService.scheduleWrite(() {
39-
try {
40-
var options = js_util.newObject();
41-
js_util.setProperty(options, 'block', 'nearest');
42-
js_util.setProperty(options, 'inline', 'nearest');
43-
js_util.callMethod(_element, 'scrollIntoView', [options]);
44-
} catch (_) {
45-
_element.scrollIntoView();
46-
}
47-
});
63+
_scrollIntoViewIfNecessary();
64+
}
65+
66+
bool get _shouldScrollIntoView => _initialized && _active && !_hasHover;
67+
68+
void _scrollIntoViewIfNecessary() {
69+
_visibilitySubscription?.cancel();
70+
71+
if (_shouldScrollIntoView) {
72+
var isVisible = _popupRef != null
73+
? _popupRef.isVisible
74+
: _modal != null ? _modal.visible : true;
75+
if (isVisible) {
76+
_scrollIntoView();
77+
} else {
78+
var onVisibleChanged = _popupRef != null
79+
? _popupRef.onVisibleChanged
80+
: _modal.onVisibleChanged;
81+
_visibilitySubscription = onVisibleChanged.listen((isVisible) {
82+
if (isVisible) {
83+
_visibilitySubscription?.cancel();
84+
if (_shouldScrollIntoView) {
85+
_scrollIntoView();
86+
}
87+
}
88+
});
89+
}
4890
}
4991
}
5092

93+
void _scrollIntoView() {
94+
_domService.scheduleWrite(() {
95+
try {
96+
var options = js_util.newObject();
97+
js_util.setProperty(options, 'block', 'nearest');
98+
js_util.setProperty(options, 'inline', 'nearest');
99+
js_util.callMethod(_element, 'scrollIntoView', [options]);
100+
} catch (_) {
101+
_element.scrollIntoView();
102+
}
103+
});
104+
}
105+
51106
/// Whether the element has hover.
52107
bool _hasHover = false;
53108

0 commit comments

Comments
 (0)