Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/fluentui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Features
- Add new Popup prop `closeOnScroll` to close popup when scroll happens outside of the popover element @yuanboxue-amber ([#21453](https://github.com/microsoft/fluentui/pull/21453))
- Add new `isIntersectingModifier` modifier to `usePopper` @layershifter ([#21829](https://github.com/microsoft/fluentui/pull/21829))

<!--------------------------------[ v0.60.1 ]------------------------------- -->
## [v0.60.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-northstar_v0.60.1) (2022-01-17)
Expand Down
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
Expand Up @@ -9,6 +9,7 @@ const Visual = () => (
<ComponentExample examplePath="components/Popup/Visual/PopupExamplePointerMargin" />
<ComponentExample examplePath="components/Popup/Visual/PopupExampleContainerTransformed" />
<ComponentExample examplePath="components/Popup/Visual/PopupScrollExample" />
<ComponentExample examplePath="components/Popup/Visual/PopperExampleVisibilityModifiers" />
</NonPublicSection>
);

Expand Down
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,
Copy link
Contributor

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 the false not render anything at all ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};
},
};

type IsIntersectingModifier = Modifier<'is-intersecting-modifier', never>;
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -102,6 +103,8 @@ function usePopperOptions(options: PopperOptions, popperOriginalPositionRef: Rea
: false;

const modifiers: PopperJs.Options['modifiers'] = [
isIntersectingModifier,
Copy link
Contributor

Choose a reason for hiding this comment

The 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 ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO yes. We have hide modifier enabled, this modifier acts in the same scope so it's reasonable to enable.

could it cause any issues with customers' tests ?

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
Expand Down