-
Notifications
You must be signed in to change notification settings - Fork 981
[Dialog][AlertDialog] Add portal part #936
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
Conversation
4929a13
to
b1f1361
Compare
b1f1361
to
171a975
Compare
/> | ||
</RemoveScroll> | ||
</Portal> | ||
<RemoveScroll as={Slot} allowPinchZoom={allowPinchZoom}> |
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.
Realised we could as={Slot}
this to reduce the number of div
s rendered. I tested this on desktop and iOS and scroll is still prevented fine. The allowPinchZoom
story also still works.
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 neat too.
|
||
type UnstablePortalElement = React.ElementRef<typeof Primitive.div>; | ||
interface UnstablePortalProps extends PrimitiveDivProps { | ||
container?: HTMLElement | null; |
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've made this expect the node instead of a ref because if we expect a ref
we have to build in assumptions that mightn't be correct.
You'll see in the old Portal
implementation that we assume the element exists on the page and that the ref
will be available when we force a re-render which might not be the case... Perhaps the node they want to portal into is mounted at the same time as the Dialog.Content
(if they're controlling it) 🤷♂️
This approach means we will get the correct container whenever it becomes available.
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'm a bit unsure about this because I remember that when we rejigged the portal implementation, we did try this but it broke some of our Portal chromatic stories around custom containers.
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'll add a story for this new UnstablePortal
to test this theory. I would expect this version to work the same in Chromatic
because our previous Portal
was forcing a re-render for it to work and this approach will be doing the same.
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, tested and it does behave differently... that's super strange, they're both forcing a re-render 🤔 Gonna look into this some more.
Oh no wait, I'm being a muppet... it obviously looked different cos the styles are removed haha. I've moved positioning into story and looks fine so let's see what Chromatic does when it finishes building.
UPDATE: both look the same here
|
||
const UnstablePortal: React.FC<UnstablePortalProps> = (props) => { | ||
const { container = globalThis?.document?.body, children } = props; | ||
return container ? ReactDOM.createPortal(<>{children}</>, container) : null; |
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.
Portal
wouldn't render a div
anymore. This removes the confusion of applying zIndex
to Dialog.Content
and having the wrong stacking. Consumers can apply all layering CSS to Dialog.Content
and Dialog.Overlay
directly where they add their position: fixed
styles and get the expected result.
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 like the simplicity of this, but I think we've lost a big part of the overall solution though with regards to the layering. In my mind, I thought we would open up to provide a way to override our defaults, but right now it seems we just don't offer defaults anymore with this approach so the layering can very easily be wrong out of the box.
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 thought we would open up to provide a way to override our defaults, but right now it seems we just don't offer defaults anymore with this approach so the layering can very easily be wrong out of the box.
It seemed to me that we needed to offer defaults for this that "worked out of the box" because people couldn't access this part to style it. We created a problem for ourselves by closing over the part that required default styles to solve, but this change removes that problem.
so the layering can very easily be wrong out of the box.
Now that the portal doesn't render anything, all of their position: fixed; zIndex: 100
styles that they apply to Dialog.Content
(which is the more natural place to apply them) will work as intended.
We don't provide position: fixed
styles for Dialog.Content
so not sure why we would hard-code positioning and layering into portal either, especially when portals don't have to be on top of things.
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've had a chat with @jjenzz about this and I think I'm aligned with this now. @colmtuite might want to take a look at some point as this is a slight difference to what we were doing before though.
764ea49
to
43edbe7
Compare
43edbe7
to
7c858d2
Compare
|
||
type UnstablePortalElement = React.ElementRef<typeof Primitive.div>; | ||
interface UnstablePortalProps extends PrimitiveDivProps { | ||
container?: HTMLElement | null; |
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'm a bit unsure about this because I remember that when we rejigged the portal implementation, we did try this but it broke some of our Portal chromatic stories around custom containers.
|
||
const UnstablePortal: React.FC<UnstablePortalProps> = (props) => { | ||
const { container = globalThis?.document?.body, children } = props; | ||
return container ? ReactDOM.createPortal(<>{children}</>, container) : null; |
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 like the simplicity of this, but I think we've lost a big part of the overall solution though with regards to the layering. In my mind, I thought we would open up to provide a way to override our defaults, but right now it seems we just don't offer defaults anymore with this approach so the layering can very easily be wrong out of the box.
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 like the changes, this is definitely the right direction to go with all primitives I think.
Also, Dialog is a good one to have people try as it was probably the one with the most requests around this subject, so I'm looking forward to hear from users if we've addressed their concerns/issues.
return container ? ReactDOM.createPortal(<>{children}</>, container) : null; | ||
}; | ||
|
||
Portal.displayName = UNSTABLE_PORTAL_NAME; |
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.
UnstablePortal.displayName = UNSTABLE_PORTAL_NAME;
😄
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.
😅 good spot! Fancy creating a new PR?
Easier to review with hidden whitespace changes
First instalment for #760
Vlad is struggling with the inability to portal dialogs into a custom container on the new primitives website. This should unblock him while we find time to roll this out to other primitives.
Notes for docs
Portal
parts forDialog
andAlertDialog
z-index
toOverlay
andContent
container
prop which must beHTMLElement
so document example of this