-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat: add isIntersectingModifier to usePopper in v0 #21829
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { ScreenerTestsConfig } from '@fluentui/scripts/screener'; | ||
|
|
||
| const config: ScreenerTestsConfig = { | ||
| steps: [ | ||
| builder => | ||
| builder | ||
| .click('#message-1') | ||
| .snapshot('Opened a popup on second message') | ||
| .executeScript('document.querySelector("#scrollable-area").scrollTop = 50') | ||
| .snapshot('has "[data-popper-is-intersecting]" when the popover intersects boundaries') | ||
| .executeScript('document.querySelector("#scrollable-area").scrollTop = 80') | ||
| .snapshot(`has "[data-popper-escaped]" when the popper escapes the reference element's boundary`) | ||
| .executeScript('document.querySelector("#scrollable-area").scrollTop = 150') | ||
| .snapshot('has "[data-popper-reference-hidden]" when the reference is hidden'), | ||
| ], | ||
| }; | ||
|
|
||
| export default config; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import { Popup, popupContentSlotClassNames } from '@fluentui/react-northstar'; | ||
| import * as _ from 'lodash'; | ||
| import * as React from 'react'; | ||
|
|
||
| const PopperExampleVisibilityModifiers = () => ( | ||
| <> | ||
| <p style={{ marginTop: 50 }}> | ||
| This visual test asserts that visual styles are applied based on popper element's state: | ||
| </p> | ||
| <ul> | ||
| <li> | ||
| <b style={{ color: 'green' }}>green</b> when the popper element intersects boundaries | ||
| </li> | ||
| <li> | ||
| <b style={{ color: 'red' }}>red</b> when the reference is hidden | ||
| </li> | ||
| <li> | ||
| <b style={{ backgroundColor: 'yellow' }}>yellow</b> when the popper escapes the reference element's boundary | ||
| </li> | ||
| </ul> | ||
| <div | ||
| id="scrollable-area" | ||
| style={{ | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: 10, | ||
| border: '3px dotted purple', | ||
| height: 400, | ||
| width: 400, | ||
| overflow: 'scroll', | ||
| marginTop: 50, | ||
| marginLeft: 50, | ||
| }} | ||
| > | ||
| {_.times(20).map(i => ( | ||
| <Popup | ||
| align="center" | ||
| position="above" | ||
| key={i} | ||
| content={{ | ||
| styles: { | ||
| [`& .${popupContentSlotClassNames.content}`]: { | ||
| backgroundColor: '#ccc', | ||
| minHeight: '60px', | ||
| width: '200px', | ||
| }, | ||
| '[data-popper-reference-hidden]': { | ||
| [`& .${popupContentSlotClassNames.content}`]: { | ||
| outline: '5px solid red', | ||
| }, | ||
| }, | ||
| '[data-popper-escaped]': { | ||
| [`& .${popupContentSlotClassNames.content}`]: { | ||
| backgroundColor: 'yellow', | ||
| }, | ||
| }, | ||
| '[data-popper-is-intersecting]': { | ||
| [`& .${popupContentSlotClassNames.content}`]: { | ||
| outline: '5px solid green', | ||
| }, | ||
| }, | ||
| }, | ||
| }} | ||
| > | ||
| <div id={`message-${i}`} style={{ border: '2px solid grey', padding: 5, marginLeft: 10 }}> | ||
| <p>message: {i}</p> | ||
| </div> | ||
| </Popup> | ||
| ))} | ||
| </div> | ||
| </> | ||
| ); | ||
|
|
||
| export default PopperExampleVisibilityModifiers; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { detectOverflow, Modifier } from '@popperjs/core'; | ||
|
|
||
| export const isIntersectingModifier: IsIntersectingModifier = { | ||
| name: 'is-intersecting-modifier', | ||
| enabled: true, | ||
| phase: 'main', | ||
| requires: ['preventOverflow'], | ||
| fn: ({ state, name }) => { | ||
| const popperRect = state.rects.popper; | ||
| const popperAltOverflow = detectOverflow(state, { altBoundary: true }); | ||
|
|
||
| const isIntersectingTop = popperAltOverflow.top < popperRect.height && popperAltOverflow.top > 0; | ||
| const isIntersectingBottom = popperAltOverflow.bottom < popperRect.height && popperAltOverflow.bottom > 0; | ||
|
|
||
| const isIntersecting = isIntersectingTop || isIntersectingBottom; | ||
|
|
||
| state.modifiersData[name] = { | ||
| isIntersecting, | ||
| }; | ||
| state.attributes.popper = { | ||
| ...state.attributes.popper, | ||
| 'data-popper-is-intersecting': isIntersecting, | ||
| }; | ||
| }, | ||
| }; | ||
|
|
||
| type IsIntersectingModifier = Modifier<'is-intersecting-modifier', never>; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ import { getReactFiberFromNode } from '../getReactFiberFromNode'; | |
| import { isBrowser } from '../isBrowser'; | ||
| import { getBoundary } from './getBoundary'; | ||
| import { getScrollParent } from './getScrollParent'; | ||
| import { isIntersectingModifier } from './isIntersectingModifier'; | ||
| import { applyRtlToOffset, getPlacement } from './positioningHelper'; | ||
| import { PopperInstance, PopperOptions } from './types'; | ||
|
|
||
|
|
@@ -102,6 +103,8 @@ function usePopperOptions(options: PopperOptions, popperOriginalPositionRef: Rea | |
| : false; | ||
|
|
||
| const modifiers: PopperJs.Options['modifiers'] = [ | ||
| isIntersectingModifier, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want this on by default ? could it cause any issues with customers' tests ?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO yes. We have
May be, but as it adds only data attribute I don't see problems with it. |
||
|
|
||
| /** | ||
| * We are setting the position to `fixed` in the first effect to prevent scroll jumps in case of the content | ||
| * with managed focus. Modifier sets the position to `fixed` before all other modifier effects. Another part of | ||
|
|
||
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 it going to render
data-popper-is-intersecting="false"? or does thefalsenot render anything at all ?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.
falseis not added, https://github.com/floating-ui/floating-ui/blob/5c9600899717981dde1de2b908872413719dc7f8/src/modifiers/applyStyles.js#L28-L29