Skip to content

feat(Popover): Support nesting #18148

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

Merged
merged 28 commits into from
May 18, 2021
Merged

Conversation

ling1726
Copy link
Member

@ling1726 ling1726 commented May 11, 2021

Pull request checklist

  • Addresses an existing issue: Fixes #0000
  • Include a change request file using $ yarn change

Description of changes

Introduces virtual-parents to react-portal. Portal will always be rendered with a hidden span so that elementContains will work for all Portals in the same React tree

The virtual parent feature will allow Popovers, Menus and Tooltips to be nested so that:

  • click outside works for the entire out of order stack
  • clicking in parent out of order component will close nested out of order component

Focus areas to test

(optional)

ling1726 added 2 commits May 11, 2021 14:43
Introduces `@fluentui/react-virtual-parents` as a utility library to set
virtual parents. Integrates it as an optional feature in `usePopper`.

The virtual parent feature will allow `Popovers` to be nested so that:
* click outside works for the entire `Popover` stack
* clicking in parent `Popovers` will close nested `Popovers`
@ling1726 ling1726 requested review from layershifter and a team May 11, 2021 16:20
@codesandbox-ci
Copy link

codesandbox-ci bot commented May 11, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit aae1997:

Sandbox Source
Fluent UI Button Configuration
codesandbox-react-template Configuration
codesandbox-react-northstar-template Configuration

@ling1726 ling1726 marked this pull request as draft May 11, 2021 17:27
@ling1726
Copy link
Member Author

Marking as draft again, to extend the solution to Portal

@ling1726 ling1726 marked this pull request as ready for review May 12, 2021 07:57
@ling1726 ling1726 added the Type: Spec Component spec PR label May 12, 2021
Copy link
Member

@layershifter layershifter left a comment

Choose a reason for hiding this comment

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

Can you please also port some unit tests for virtualParent?

@size-auditor
Copy link

size-auditor bot commented May 12, 2021

Asset size changes

Project Bundle Baseline Size New Size Difference
office-ui-fabric-react fluentui-react-components-Menu 99.497 kB 99.876 kB ExceedsBaseline     379 bytes
office-ui-fabric-react fluentui-react-components-Portal 2.211 kB 2.553 kB ExceedsBaseline     342 bytes
office-ui-fabric-react fluentui-react-components-Tooltip 39.083 kB 39.425 kB ExceedsBaseline     342 bytes

ExceedsTolerance Over Tolerance (1024 B) ExceedsBaseline Over Baseline BelowBaseline Below Baseline New New Deleted  Removed 1 kB = 1000 B

Baseline commit: 644df65321367dd615548b2877293d5268595c2b (build)

@fabricteam
Copy link
Collaborator

fabricteam commented May 12, 2021

Perf Analysis (@fluentui/react)

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 946 942 5000
BaseButton mount 1025 1050 5000
Breadcrumb mount 2816 2859 1000
ButtonNext mount 561 563 5000
Checkbox mount 1793 1773 5000
CheckboxBase mount 1482 1511 5000
ChoiceGroup mount 5352 5428 5000
ComboBox mount 1168 1107 1000
CommandBar mount 11099 11048 1000
ContextualMenu mount 6839 6785 1000
DefaultButton mount 1291 1300 5000
DetailsRow mount 4081 4156 5000
DetailsRowFast mount 4210 4160 5000
DetailsRowNoStyles mount 3895 3912 5000
Dialog mount 2310 2329 1000
DocumentCardTitle mount 163 158 1000
Dropdown mount 3622 3576 5000
FocusTrapZone mount 1928 2020 5000
FocusZone mount 1938 1989 5000
IconButton mount 1948 2005 5000
Label mount 387 380 5000
Layer mount 1991 2018 5000
Link mount 517 515 5000
MakeStyles mount 1927 2045 50000
MenuButton mount 1648 1673 5000
MessageBar mount 2199 2220 5000
Nav mount 3695 3597 1000
OverflowSet mount 1160 1126 5000
Panel mount 2286 2236 1000
Persona mount 897 900 1000
Pivot mount 1578 1585 1000
PrimaryButton mount 1406 1435 5000
Rating mount 8583 8745 5000
SearchBox mount 1513 1512 5000
Shimmer mount 2844 2989 5000
Slider mount 2198 2184 5000
SpinButton mount 5558 5500 5000
Spinner mount 478 450 5000
SplitButton mount 3502 3482 5000
Stack mount 552 565 5000
StackWithIntrinsicChildren mount 1699 1694 5000
StackWithTextChildren mount 5192 5128 5000
SwatchColorPicker mount 11239 11232 5000
Tabs mount 1573 1533 1000
TagPicker mount 2817 2775 5000
TeachingBubble mount 12908 12886 5000
Text mount 484 500 5000
TextField mount 1576 1559 5000
ThemeProvider mount 1328 1300 5000
ThemeProvider virtual-rerender 658 667 5000
ThemeProviderNext mount 7075 7023 5000
Toggle mount 906 886 5000
buttonNative mount 116 133 5000

Perf Analysis (@fluentui/react-northstar)

⚠️ 1 potential perf regressions detected

Potential regressions comparing to master

Scenario Current PR Ticks Baseline Ticks Ratio Regression Analysis
AvatarMinimalPerf.default 218 222 0.98:1 analysis
Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
ButtonMinimalPerf.default 215 190 1.13:1
AttachmentMinimalPerf.default 198 177 1.12:1
SkeletonMinimalPerf.default 441 401 1.1:1
CarouselMinimalPerf.default 546 502 1.09:1
HeaderMinimalPerf.default 444 413 1.08:1
LabelMinimalPerf.default 462 430 1.07:1
ReactionMinimalPerf.default 454 424 1.07:1
TableMinimalPerf.default 481 451 1.07:1
TextMinimalPerf.default 421 394 1.07:1
MenuMinimalPerf.default 997 940 1.06:1
SegmentMinimalPerf.default 410 385 1.06:1
VideoMinimalPerf.default 734 692 1.06:1
AccordionMinimalPerf.default 183 175 1.05:1
TooltipMinimalPerf.default 1116 1067 1.05:1
CardMinimalPerf.default 643 617 1.04:1
DropdownManyItemsPerf.default 791 764 1.04:1
ItemLayoutMinimalPerf.default 1495 1438 1.04:1
LayoutMinimalPerf.default 426 411 1.04:1
ListCommonPerf.default 745 715 1.04:1
PortalMinimalPerf.default 174 167 1.04:1
RadioGroupMinimalPerf.default 512 491 1.04:1
IconMinimalPerf.default 721 691 1.04:1
ToolbarMinimalPerf.default 1112 1072 1.04:1
DatepickerMinimalPerf.default 6224 6043 1.03:1
DividerMinimalPerf.default 427 414 1.03:1
FlexMinimalPerf.default 328 318 1.03:1
GridMinimalPerf.default 396 384 1.03:1
ProviderMinimalPerf.default 1114 1084 1.03:1
StatusMinimalPerf.default 804 783 1.03:1
TreeMinimalPerf.default 908 878 1.03:1
AnimationMinimalPerf.default 477 467 1.02:1
BoxMinimalPerf.default 397 388 1.02:1
ChatDuplicateMessagesPerf.default 328 323 1.02:1
CheckboxMinimalPerf.default 3059 2997 1.02:1
MenuButtonMinimalPerf.default 1803 1768 1.02:1
CustomToolbarPrototype.default 4123 4059 1.02:1
AttachmentSlotsPerf.default 1268 1257 1.01:1
DialogMinimalPerf.default 827 821 1.01:1
DropdownMinimalPerf.default 3386 3343 1.01:1
InputMinimalPerf.default 1376 1368 1.01:1
ListMinimalPerf.default 571 564 1.01:1
SliderMinimalPerf.default 1698 1683 1.01:1
SplitButtonMinimalPerf.default 4206 4168 1.01:1
TableManyItemsPerf.default 2207 2180 1.01:1
TextAreaMinimalPerf.default 599 593 1.01:1
TreeWith60ListItems.default 188 187 1.01:1
ButtonOverridesMissPerf.default 1851 1859 1:1
ButtonSlotsPerf.default 620 621 1:1
ChatMinimalPerf.default 708 709 1:1
EmbedMinimalPerf.default 4537 4537 1:1
ImageMinimalPerf.default 435 437 1:1
LoaderMinimalPerf.default 758 760 1:1
AlertMinimalPerf.default 319 322 0.99:1
HeaderSlotsPerf.default 881 892 0.99:1
FormMinimalPerf.default 466 477 0.98:1
ListWith60ListItems.default 720 738 0.98:1
ProviderMergeThemesPerf.default 1743 1770 0.98:1
PopupMinimalPerf.default 620 639 0.97:1
RefMinimalPerf.default 256 264 0.97:1
ChatWithPopoverPerf.default 394 416 0.95:1
ListNestedPerf.default 618 655 0.94:1
RosterPerf.default 1250 1351 0.93:1

@ling1726 ling1726 requested a review from a team as a code owner May 12, 2021 10:19
@ling1726 ling1726 enabled auto-merge (squash) May 12, 2021 11:31
ling1726 added 3 commits May 12, 2021 14:59
Introduces `@fluentui/react-virtual-parents` as a utility library to set
virtual parents. Integrates it as an optional feature in `usePopper`.

The virtual parent feature will allow `Popovers` to be nested so that:
* click outside works for the entire `Popover` stack
* clicking in parent `Popovers` will close nested `Popovers`
@ling1726 ling1726 requested a review from a team May 12, 2021 14:06
@ling1726 ling1726 disabled auto-merge May 12, 2021 14:06
@ling1726
Copy link
Member Author

@behowell can you take a look at the tooltip snapshot updates ? It's caused by Portal rendering a span for virtual parents

*/
export function getVirtualParent(child: HTMLElement): HTMLElement | undefined {
let parent: HTMLElement | undefined;
if (child && isVirtualElement(child)) {
Copy link
Member

Choose a reason for hiding this comment

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

Do you need to check child here?
It is HTMLElement and it's isVirtualElement's responsibility to check it's truthy

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right, it's unnecessary

Comment on lines +25 to +29
React.useEffect(() => {
if (state.virtualParentRootRef.current && state.mountNode) {
setVirtualParent(state.mountNode, state.virtualParentRootRef.current);
}
}, [state.virtualParentRootRef, state.mountNode]);
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't re-run if virtualParentRootRef.current changes. You might be able to make it work by making virtualParentRootRef a function that gets called whenever the ref is set... but then you'd also want to update the virtual parent whenever mountNode changes.

That said, presumably setVirtualParent is cheap right? Maybe it's simpler to make this effect run after every render (remove the deps).

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not entirely sure if virtualParentRootRef.current would ever change, since it is always set internally into that span that users will never have access to.

That inacessible slot always renders even during server render in SSR or in the client when the Portal can't be rendered.

@ling1726 ling1726 enabled auto-merge (squash) May 18, 2021 06:48
@ling1726 ling1726 merged commit 90cd8ca into microsoft:master May 18, 2021
@msft-fluent-ui-bot
Copy link
Collaborator

🎉@fluentui/[email protected] has been released which incorporates this pull request.:tada:

Handy links:

@msft-fluent-ui-bot
Copy link
Collaborator

🎉@fluentui/[email protected] has been released which incorporates this pull request.:tada:

Handy links:

@msft-fluent-ui-bot
Copy link
Collaborator

🎉@fluentui/[email protected] has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants