Skip to content

Commit 028746a

Browse files
authored
feat(cdk-scrollable): add methods to normalize scrolling in RTL (#12607)
* feat(cdk-scrollable): add methods to normalize scrolling in RTL * address comments
1 parent 499458c commit 028746a

File tree

8 files changed

+510
-36
lines changed

8 files changed

+510
-36
lines changed

src/cdk/platform/features.ts renamed to src/cdk/platform/features/input-types.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
/** Cached result of whether the user's browser supports passive event listeners. */
10-
let supportsPassiveEvents: boolean;
11-
12-
/**
13-
* Checks whether the user's browser supports passive event listeners.
14-
* See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
15-
*/
16-
export function supportsPassiveEventListeners(): boolean {
17-
if (supportsPassiveEvents == null && typeof window !== 'undefined') {
18-
try {
19-
window.addEventListener('test', null!, Object.defineProperty({}, 'passive', {
20-
get: () => supportsPassiveEvents = true
21-
}));
22-
} finally {
23-
supportsPassiveEvents = supportsPassiveEvents || false;
24-
}
25-
}
26-
27-
return supportsPassiveEvents;
28-
}
29-
30-
/** Check whether the browser supports scroll behaviors. */
31-
export function supportsScrollBehavior(): boolean {
32-
return !!(document && document.documentElement && document.documentElement.style &&
33-
'scrollBehavior' in document.documentElement.style);
34-
}
35-
369
/** Cached result Set of input types support by the current browser. */
3710
let supportedInputTypes: Set<string>;
3811

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/** Cached result of whether the user's browser supports passive event listeners. */
10+
let supportsPassiveEvents: boolean;
11+
12+
/**
13+
* Checks whether the user's browser supports passive event listeners.
14+
* See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
15+
*/
16+
export function supportsPassiveEventListeners(): boolean {
17+
if (supportsPassiveEvents == null && typeof window !== 'undefined') {
18+
try {
19+
window.addEventListener('test', null!, Object.defineProperty({}, 'passive', {
20+
get: () => supportsPassiveEvents = true
21+
}));
22+
} finally {
23+
supportsPassiveEvents = supportsPassiveEvents || false;
24+
}
25+
}
26+
27+
return supportsPassiveEvents;
28+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/** The possible ways the browser may handle the horizontal scroll axis in RTL languages. */
10+
export enum RtlScrollAxisType {
11+
/**
12+
* scrollLeft is 0 when scrolled all the way left and (scrollWidth - clientWidth) when scrolled
13+
* all the way right.
14+
*/
15+
NORMAL,
16+
/**
17+
* scrollLeft is -(scrollWidth - clientWidth) when scrolled all the way left and 0 when scrolled
18+
* all the way right.
19+
*/
20+
NEGATED,
21+
/**
22+
* scrollLeft is (scrollWidth - clientWidth) when scrolled all the way left and 0 when scrolled
23+
* all the way right.
24+
*/
25+
INVERTED
26+
}
27+
28+
/** Cached result of the way the browser handles the horizontal scroll axis in RTL mode. */
29+
let rtlScrollAxisType: RtlScrollAxisType;
30+
31+
/** Check whether the browser supports scroll behaviors. */
32+
export function supportsScrollBehavior(): boolean {
33+
return !!(typeof document == 'object' && 'scrollBehavior' in document.documentElement.style);
34+
}
35+
36+
/**
37+
* Checks the type of RTL scroll axis used by this browser. As of time of writing, Chrome is NORMAL,
38+
* Firefox & Safari are NEGATED, and IE & Edge are INVERTED.
39+
*/
40+
export function getRtlScrollAxisType(): RtlScrollAxisType {
41+
// We can't check unless we're on the browser. Just assume 'normal' if we're not.
42+
if (typeof document !== 'object' || !document) {
43+
return RtlScrollAxisType.NORMAL;
44+
}
45+
46+
if (!rtlScrollAxisType) {
47+
// Create a 1px wide scrolling container and a 2px wide content element.
48+
const scrollContainer = document.createElement('div');
49+
const containerStyle = scrollContainer.style;
50+
scrollContainer.dir = 'rtl';
51+
containerStyle.height = '1px';
52+
containerStyle.width = '1px';
53+
containerStyle.overflow = 'auto';
54+
containerStyle.visibility = 'hidden';
55+
containerStyle.pointerEvents = 'none';
56+
containerStyle.position = 'absolute';
57+
58+
const content = document.createElement('div');
59+
const contentStyle = content.style;
60+
contentStyle.width = '2px';
61+
contentStyle.height = '1px';
62+
63+
scrollContainer.appendChild(content);
64+
document.body.appendChild(scrollContainer);
65+
66+
rtlScrollAxisType = RtlScrollAxisType.NORMAL;
67+
68+
// The viewport starts scrolled all the way to the right in RTL mode. If we are in a NORMAL
69+
// browser this would mean that the scrollLeft should be 1. If it's zero instead we know we're
70+
// dealing with one of the other two types of browsers.
71+
if (scrollContainer.scrollLeft === 0) {
72+
// In a NEGATED browser the scrollLeft is always somewhere in [-maxScrollAmount, 0]. For an
73+
// INVERTED browser it is always somewhere in [0, maxScrollAmount]. We can determine which by
74+
// setting to the scrollLeft to 1. This is past the max for a NEGATED browser, so it will
75+
// return 0 when we read it again.
76+
scrollContainer.scrollLeft = 1;
77+
rtlScrollAxisType =
78+
scrollContainer.scrollLeft === 0 ? RtlScrollAxisType.NEGATED : RtlScrollAxisType.INVERTED;
79+
}
80+
81+
scrollContainer.parentNode!.removeChild(scrollContainer);
82+
}
83+
return rtlScrollAxisType;
84+
}

src/cdk/platform/public-api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@
77
*/
88

99
export * from './platform';
10-
export * from './features';
1110
export * from './platform-module';
11+
export * from './features/input-types';
12+
export * from './features/passive-listeners';
13+
export * from './features/scrolling';

src/cdk/scrolling/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ng_module(
1010
module_name = "@angular/cdk/scrolling",
1111
assets = [":virtual-scroll-viewport.css"] + glob(["**/*.html"]),
1212
deps = [
13+
"//src/cdk/bidi",
1314
"//src/cdk/coercion",
1415
"//src/cdk/collections",
1516
"//src/cdk/platform",
@@ -29,6 +30,7 @@ ts_library(
2930
srcs = glob(["**/*.spec.ts"]),
3031
deps = [
3132
":scrolling",
33+
"//src/cdk/bidi",
3234
"//src/cdk/collections",
3335
"//src/cdk/testing",
3436
"@rxjs",

0 commit comments

Comments
 (0)