-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
feat(cdk-scrollable): add methods to normalize scrolling in RTL #12607
Conversation
cd90ac9
to
6b5485f
Compare
src/cdk/platform/features.ts
Outdated
@@ -8,6 +8,7 @@ | |||
|
|||
/** Cached result of whether the user's browser supports passive event listeners. */ | |||
let supportsPassiveEvents: boolean; | |||
let rtlScrollAxisType: 'normal' | 'negated' | 'inverted'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add description?
src/cdk/platform/features.ts
Outdated
* - inverted: scrollLeft is (scrollWidth - clientWidth) when scrolled all the way left and 0 when | ||
* scrolled all the way right. | ||
*/ | ||
export function getRtlScrollAxisType(): 'normal' | 'negated' | 'inverted' { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment somewhere in this file like "As of time of this writing, Chrome is ..., Firefox is ..."
src/cdk/platform/features.ts
Outdated
@@ -8,6 +8,7 @@ | |||
|
|||
/** Cached result of whether the user's browser supports passive event listeners. */ | |||
let supportsPassiveEvents: boolean; | |||
let rtlScrollAxisType: 'normal' | 'negated' | 'inverted'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be a good time to break features.ts
into separate files for different features
src/cdk/platform/features.ts
Outdated
@@ -8,6 +8,7 @@ | |||
|
|||
/** Cached result of whether the user's browser supports passive event listeners. */ | |||
let supportsPassiveEvents: boolean; | |||
let rtlScrollAxisType: 'normal' | 'negated' | 'inverted'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this use an enum
? In other places where we use string literal types, it's usually because the value can be provided in a template
src/cdk/platform/features.ts
Outdated
} | ||
|
||
if (!rtlScrollAxisType) { | ||
const viewport = document.createElement('div'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
viewport
-> scrollingContainer
? Since viewport
is often used to refer to the whole browser viewport.
src/cdk/scrolling/scrollable.spec.ts
Outdated
class ScrollableViewport { | ||
@Input() dir: Direction; | ||
@ViewChild(CdkScrollable) scrollable: CdkScrollable; | ||
@ViewChild('viewport') viewport: ElementRef<HTMLElement>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
viewport
-> scrollingContainer
?
src/cdk/scrolling/scrollable.ts
Outdated
*/ | ||
end?: number; | ||
/** A distance relative to the bottom edge of the viewport. */ | ||
bottom?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, you could capture the mutual exclusivity with TypeScript. The error message is a little wordy.
(idea stolen from microsoft/TypeScript#14094)
src/cdk/scrolling/scrollable.ts
Outdated
} | ||
|
||
getElementRef(): ElementRef { | ||
return this._elementRef; | ||
private _scrollTo(options: ScrollToOptions): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this have a different name than the public method that captures what it does differently / more?
src/cdk/scrolling/scrollable.ts
Outdated
* Measures the scroll offset relative to the specified edge of the viewport. | ||
* @param from The edge to measure from. | ||
*/ | ||
measureScrollOffset(from: 'top' | 'left' | 'right' | 'bottom' | 'start' | 'end'): number { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could the type for from
be an enum
, or does it come from something a user would put in a template?
If it can't be an enum, it might be good to alias it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one could appear in a template, I'll alias the values used more than once
src/cdk/scrolling/scrollable.ts
Outdated
from = isRtl ? 'left' : 'right'; | ||
} | ||
|
||
if (isRtl && getRtlScrollAxisType() == 'inverted') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would make this code more understandable if you had a brief comment like like
// normal:
// inverted:
// negated:
Even though that's already written in the feature detection function.
It would also be good to explicitly say in a comment which system you're normalizing to (I assume it's normal
).
*/ | ||
|
||
/** The possible ways the browser may handle the horizontal scroll axis in RTL languages. */ | ||
export enum RtlScrollAxisType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't we have something about not using enums @jelbourn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jelbourn actually requested this, since its not a value that a user would supply through a template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no memory about not wanting to use enums (for things that aren't used via templates). It is very possible I forgot something, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some memory about it messing some internal tooling (Closure maybe?), but I could be mixing things up.
|
||
/** Check whether the browser supports scroll behaviors. */ | ||
export function supportsScrollBehavior(): boolean { | ||
return !!(document && document.documentElement && document.documentElement.style && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will throw an error during server-side rendering. The check for document
should be typeof document !== 'undefined'
. Also you don't need checks for document.documentElement
and documentElement.style
since those are guaranteed to be there if we have a document
.
scrollContainer.style.overflow = 'auto'; | ||
scrollContainer.style.visibility = 'hidden'; | ||
scrollContainer.style.pointerEvents = 'none'; | ||
scrollContainer.style.position = 'absolute'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider having a variable for scrollContainer.style
so it doesn't have to be repeated as much. It should minify a bit better as well.
scrollContainer.scrollLeft == 0 ? RtlScrollAxisType.NEGATED : RtlScrollAxisType.INVERTED; | ||
} | ||
|
||
document.body.removeChild(scrollContainer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a little more future-proof as scrollContainer.parentNode.removeChild(scrollContainer)
. This would start failing if we started appending the element to something different from the body
.
// return 0 when we read it again. | ||
scrollContainer.scrollLeft = 1; | ||
rtlScrollAxisType = | ||
scrollContainer.scrollLeft == 0 ? RtlScrollAxisType.NEGATED : RtlScrollAxisType.INVERTED; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be triple equals.
src/cdk/scrolling/scrollable.spec.ts
Outdated
|
||
function checkIntersecting(r1: ClientRect, r2: ClientRect, expected = true) { | ||
const actual = | ||
r1.left < r2.right && r1.right > r2.left && r1.top < r2.bottom && r1.bottom > r2.top; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be <=
, >=
etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, elements that are side-by-side would be detected as overlapping if we did that
src/cdk/scrolling/scrollable.spec.ts
Outdated
checkIntersecting(testComponent.scrollContainer.nativeElement.getBoundingClientRect(), | ||
testComponent.lastRowEnd.nativeElement.getBoundingClientRect(), false); | ||
|
||
expect(testComponent.scrollable.measureScrollOffset('top')).toBe(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a bunch of long expressions like testComponent.scrollContainer.nativeElement
are being repeated a lot. Consider moving them into variables to reduce noise.
src/cdk/scrolling/scrollable.ts
Outdated
* start, and end properties. | ||
*/ | ||
export interface ExtendedScrollToOptions extends ScrollToOptions { | ||
/** A distance relative to the right edge of the viewport. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super tiny nit: the property description don't have to start with "a".
b4da004
to
e9c384b
Compare
PTAL, comments addressed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM aside from one nti
src/cdk/scrolling/scrollable.ts
Outdated
export type _Left = { left?: number }; | ||
export type _Right = { right?: number }; | ||
export type _Start = { start?: number }; | ||
export type _End = { end?: number }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omit spaces in braces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably make the new noImportSpacing
rule also cover the spacing inside of objects. Similar as the object-curly-spacing rule from ESlint. I'll have a quick look at some point.
e9c384b
to
8dee516
Compare
8dee516
to
7411d8c
Compare
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Technically a major change due to tightening the
ElementRef
toElementRef<HTMLElement>