-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Fix overlay issues #276
Fix overlay issues #276
Conversation
top: $overlay-example-width / 2; | ||
left: calc(50% - #{$overlay-example-width / 2}); | ||
z-index: $pt-z-index-overlay + 1; | ||
width: $overlay-example-width; | ||
|
||
.pt-overlay-inline & { |
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.
Is this necessary? Looks like line 105 in _overlay.scss
does the same thing
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.
Yeah this is necessary. Line 105 applies this style to .pt-overlay-backdrop
; this .doc-overlay-example-transition
container is a sibling of .pt-overlay-backdrop
, and it needs to be styled separately.
This does bring up a broader annoyance that users will need to explicit;y style overlay content with position: absolute
if they want it to render properly inline. Maybe we should add a class (e.g. pt-overlay-content
) on all siblings of .pt-overlay-backdrop
that handles this position styling automatically?
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.
Indeed, users shouldn't have to explicitly style their overlay content, we should handle that automatically for them
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.
Done. 👍 See the updated PR description. I've introduced a .pt-overlay-content
class that we add to the overlay content container(s) automatically, to govern fixed
/absolute
position mode on behalf of Blueprint users.
@@ -84,6 +84,11 @@ export interface IBackdropProps { | |||
backdropProps?: React.HTMLProps<HTMLDivElement>; | |||
|
|||
/** | |||
* Whether underlying content should be scrollable while the backdrop is visible. | |||
*/ | |||
backgroundScrollingDisabled?: boolean; |
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.
Why is this configurable? Have you seen (or can you imagine) any use case where false
would make sense?
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.
Not off the top of my head, no. @giladgray said something in #183 about making this class prop-configurable. Not quite sure in what that meant - Gilad can you clarify? Happy to get rid of this if we want.
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.
For Overlay, I think it should be configurable because it is a low level component. I can imagine a sidebar created with Overlay which allows scrolling on the main content. It should be set to false
for Dialogs, 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 don't see a need for this prop. an overlay with a backdrop should always prevent scrolling. i can't see a case where you'd want a backdrop and the ability to scroll the document underneath.
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.
Hmm, I feel like we already have a prop for that: hasBackdrop
. If it's set to true
, you have a backdrop behind and you can't scroll. If it's false
, you don't have a background behind and you can scroll.
Enabling this extra backgroundScrollingDisabled
prop means that we think there's a use case for having a backdrop behind and being able to scroll what's beneath it. I'm skeptical about that but open to it.
What about canOutsideClickClose
found in Overlay
, and isModal
found in Popover
? I feel like there's a lot of repetition going on... Maybe isModal
is what we want instead of backgroundScrollingDisabled
.
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.
Killing this prop. 👍
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.
Done. FWIW we can easily add this back later if we observe a need for it.
EDIT: Relying on hasBackdrop
instead. If true
, disable document scrolling beneath the backdrop; if false
, don't.
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.
cool, you're right, this makes sense @giladgray @llorca
@@ -72,9 +72,14 @@ Styleguide components.overlay.scroll | |||
|
|||
$overlay-background-color: rgba($black, 0.7); | |||
|
|||
// restricts scrolling of underlying content while the overlay is open |
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 feels a little invasive. is it absolutely necessary?
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.
nvm, ignore me, I caught up on the linked thread
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.
Done (no changes made)
@@ -84,6 +84,11 @@ export interface IBackdropProps { | |||
backdropProps?: React.HTMLProps<HTMLDivElement>; | |||
|
|||
/** | |||
* Whether underlying content should be scrollable while the backdrop is visible. | |||
*/ | |||
backgroundScrollingDisabled?: boolean; |
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.
For Overlay, I think it should be configurable because it is a low level component. I can imagine a sidebar created with Overlay which allows scrolling on the main content. It should be set to false
for Dialogs, though.
// when rendered inline, we want the overlay to position itself relative to | ||
// its parent container, not relative to the whole window. | ||
.pt-overlay-inline & { | ||
@include position(absolute, 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.
position: absolute
should be enough.
this mixin generates five lines, four of which are the same as line 92.
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.
Done 👍
@@ -172,8 +178,14 @@ export class Overlay extends React.Component<IOverlayProps, IOverlayState> { | |||
</CSSTransitionGroup> | |||
); | |||
|
|||
const mergedClassName = classNames({ | |||
[Classes.OVERLAY]: true, |
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.
classNames(Classes.OVERLAY, { ... }, className)
no need to include it in the object if it's always true
.
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.
Yeah realized that after opening the PR but forgot to change it. Good catch. Done. 👍
@@ -19,6 +19,7 @@ describe("<Overlay>", () => { | |||
let wrapper: ReactWrapper<IOverlayProps, any>; | |||
|
|||
afterEach(() => { | |||
document.body.classList.remove(Classes.OVERLAY_OPEN); |
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.
why in the test? i'd expect the component to handle removing the class.
probably means you need to also be removing it in componentWillUnmount()
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.
Ah, yes, I noticed that when I was fixing other tests but didn't come back to omit it here. Done. 👍
@giladgray @adidahiya @llorca ready for re-review. See the updated PR description for an overview of the new scope of changes. |
// so that our class will override the position style of other classes that might | ||
// have set unnecessary position rules (note that CSS specificity plays a role here; | ||
// our class will only override an existing position rule if it has the same or | ||
// greater selector specificity). |
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.
If we proceed with this approach, might be worth mentioning in the docs that there's no need to explicitly set position
on your overlay content container, as we manage that ourselves.
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.
yes definitely worth mentioning
@@ -263,7 +263,6 @@ | |||
.docs-overlay-example-transition { | |||
$overlay-example-width: $pt-grid-size * 40; | |||
|
|||
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.
No longer necessary now that we manage the position mode internally (via .pt-overlay-content
).
|
||
.pt-overlay-backdrop { | ||
// fixed position so it won't scroll under the overlay | ||
position: fixed; |
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.
Deleted this rule (and therefore this .pt-overlay-backdrop
block), because the backdrop is set to position: fixed
by default now.
@@ -72,19 +72,14 @@ Styleguide components.overlay.scroll | |||
|
|||
$overlay-background-color: rgba($black, 0.7); | |||
|
|||
// scroll container for non-inline overlay | |||
.pt-overlay-scroll-container.pt-overlay-open { |
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.
Moved this down to the bottom of the file because it's a special case.
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.
mostly comments on comments 😄
} | ||
|
||
// fixed position so it won't scroll underneath the overlay content |
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.
not true... fixed position so it always covers the entire viewport (irrespective of page scroll position)
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 was a relic from line 81 in the old code. Will remove. 👍
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.
Done
|
||
// scroll container for non-inline overlay. it needs an explicit z-index to | ||
// ensure that the backdrop renders on top of any navbars. | ||
.pt-overlay-scroll-container.pt-overlay-open { |
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 wonder if we still need this class? but that's another issue, about scrolling dialogs 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.
Possibly not, can look into that more after this PR if that sounds good.
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.
Done (no change for now)
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.
yes not in this PR
@@ -159,6 +159,19 @@ export class Overlay extends React.Component<IOverlayProps, IOverlayState> { | |||
|
|||
const { children, className, inline, isOpen, transitionDuration, transitionName } = this.props; | |||
|
|||
// add a special class to each child that will automatically set the appropriate | |||
// CSS position mode under the hood. we add this class *after* the existing classes | |||
// so that our class will override the position style of other classes that might |
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 is not how CSS works, which you call out later... it's entirely about specificity. if the user sets position
in a selector with three classes it'll win out over ours every time.
i think you could safely remove all but the first sentence from this comment.
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.
Yeah this comment felt a little ham-handed. Will edit.
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.
Done
// so that our class will override the position style of other classes that might | ||
// have set unnecessary position rules (note that CSS specificity plays a role here; | ||
// our class will only override an existing position rule if it has the same or | ||
// greater selector specificity). |
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.
yes definitely worth mentioning
// our class will only override an existing position rule if it has the same or | ||
// greater selector specificity). | ||
const decoratedChildren = React.Children.map(children, (child: React.ReactChild) => { | ||
const childEl = child as React.ReactElement<any>; |
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 do this cast in the function signature? (child: React.ReactElement<any>) => {
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.
Sure thing.
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.
Done
assert.isFalse(isBodyScrollingDisabled()); | ||
}); | ||
|
||
function mountOverlay(inline?: boolean, hasBackdrop?: boolean) { |
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 need for ?
on either param, they're always specified
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.
Oh does TS not freak when I pass undefined
if a boolean
is expected?
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.
Done
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.
mm probably would. nvm then... inline?: boolean
=== inline: boolean | undefined
.pt-overlay-content { | ||
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.
this file looks great now! excellent refactor and comments.
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.
though it should end with a newline...
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.
Hmm, I thought my editor handled that. Will add.
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.
yeah that's why i asked about EditorConfig 😄
@@ -72,19 +72,14 @@ Styleguide components.overlay.scroll | |||
|
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.
the words "absolute positioning" are used a few times in these docs, please update accordingly.
see line 59 above
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.
Done
@giladgray is this too verbose, or does this look okay? |
|
remove the first sentence? and clarify that it's |
@giladgray v3 |
PR checklist
What changes did you make?
Introduce a
pt-overlay
class to serve as the top-level wrapper descriptor for the overlay component.As a consumer of Blueprint in the past, I was always much happier when everything had a clear CSS class attached to it. CSS rules downstream are much easier to grok and maintain when applied to meaningfully named elements, rather than opaque HTML tag names.
Introduce a
.pt-overlay-inline
class and apply it to the.pt-overlay
element iff the overlay is being rendered inline.This allows us to set
.pt-overlay-backdrop
and/or overlay content toposition: absolute
when the overlay is rendered inline, so that the overlay intuitively positions itself relative to its parent in that case.Introduce a
.pt-overlay-content
class that we apply under-the-hood to overlay content containers to manage CSS position mode on behalf of the developer.Otherwise, Blueprint users would have to explicitly set
position:fixed
for non-inline andposition:absolute
for inline rendering. That'd be brittle.Set
.pt-overlay-backdrop
toposition:fixed
if the overlay is not rendered inline.This is the crucial fix for Overlay doesn't stretch 100% height #183.
Disable document scrolling beneath the overlay backdrop when
hasBackdrop
istrue
.Reorganize CSS a bit to ensure that overflow-scrolling still works.
Tweaked unit tests:
.pt-overlay-open
to stay on thebody
after all the tests ran viagulp karma-unit-core
<Portal>
tests aren't properly detaching containers after they run. Fixed.Abandoned Changes:
Introduce abackgroundScrollingDisabled
prop onIBackdropProps
that, whentrue
, disables scrolling of content beneath the overlay backdrop. Underneath the hood, this adds a.pt-overlay-open
class to the documentbody
that setsoverflow: hidden
when applied.Is there anything you'd like reviewers to focus on?