Skip to content

RFC: Portal compatibility#21774

Merged
layershifter merged 2 commits into
microsoft:masterfrom
layershifter:rfc/compat-v8-v9
May 11, 2022
Merged

RFC: Portal compatibility#21774
layershifter merged 2 commits into
microsoft:masterfrom
layershifter:rfc/compat-v8-v9

Conversation

@layershifter

@layershifter layershifter commented Feb 16, 2022

Copy link
Copy Markdown
Member

Summary

This RFC proposes introduce compatibility between components in different Fluent UI versions that use ReactDOM.createPortal() via:

  • usage of same values for z-index
  • usage of separate React context to assign CSS class that handles CSS variables from Fluent UI React v9

Related Issue(s)

Provides solution for #21333.


Preview

@github-actions github-actions Bot added the Type: RFC Request for Feedback label Feb 16, 2022
@codesandbox-ci

codesandbox-ci Bot commented Feb 16, 2022

Copy link
Copy Markdown

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 b1a22f6:

Sandbox Source
@fluentui/react 8 starter Configuration
@fluentui/react-components 9 starter Configuration

@size-auditor

size-auditor Bot commented Feb 16, 2022

Copy link
Copy Markdown

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: 43f3fbf79244dfe2557322b1418f73d93bd1b054 (build)

@fabricteam

fabricteam commented Feb 16, 2022

Copy link
Copy Markdown
Collaborator

📊 Bundle size report

🤖 This report was generated against 319234c25f29defac6afc728dd109737fd1b803f

@fabricteam

fabricteam commented Feb 16, 2022

Copy link
Copy Markdown
Collaborator

Perf Analysis (@fluentui/react)

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 1059 1074 5000
BaseButton mount 1096 1075 5000
Breadcrumb mount 2887 2897 1000
ButtonNext mount 549 542 5000
Checkbox mount 1837 1940 5000
CheckboxBase mount 1629 1656 5000
ChoiceGroup mount 5634 5682 5000
ComboBox mount 1139 1166 1000
CommandBar mount 11601 11497 1000
ContextualMenu mount 9519 9479 1000
DefaultButton mount 1343 1321 5000
DetailsRow mount 4277 4343 5000
DetailsRowFast mount 4335 4344 5000
DetailsRowNoStyles mount 4037 4101 5000
Dialog mount 2474 2490 1000
DocumentCardTitle mount 210 221 1000
Dropdown mount 3691 3718 5000
FluentProviderNext mount 2009 2045 5000
FluentProviderWithTheme mount 183 188 10
FluentProviderWithTheme virtual-rerender 143 131 10
FluentProviderWithTheme virtual-rerender-with-unmount 219 227 10
FocusTrapZone mount 2080 2086 5000
FocusZone mount 1999 2051 5000
IconButton mount 2067 2086 5000
Label mount 421 429 5000
Layer mount 3462 3437 5000
Link mount 557 593 5000
MakeStyles mount 1811 1826 50000
MenuButton mount 1783 1793 5000
MessageBar mount 2299 2262 5000
Nav mount 3805 3801 1000
OverflowSet mount 1268 1279 5000
Panel mount 2422 2445 1000
Persona mount 995 984 1000
Pivot mount 1628 1640 1000
PrimaryButton mount 1479 1500 5000
Rating mount 9114 9085 5000
SearchBox mount 1576 1637 5000
Shimmer mount 2922 2970 5000
Slider mount 2495 2264 5000
SpinButton mount 5893 5695 5000
Spinner mount 509 526 5000
SplitButton mount 3648 3841 5000
Stack mount 637 661 5000
StackWithIntrinsicChildren mount 2770 2753 5000
StackWithTextChildren mount 6486 6466 5000
SwatchColorPicker mount 13462 13209 5000
TagPicker mount 3023 3212 5000
TeachingBubble mount 14611 14722 5000
Text mount 529 546 5000
TextField mount 1708 1651 5000
ThemeProvider mount 1380 1345 5000
ThemeProvider virtual-rerender 704 739 5000
ThemeProvider virtual-rerender-with-unmount 2165 2245 5000
Toggle mount 952 953 5000
buttonNative mount 172 176 5000

Perf Analysis (@fluentui/react-northstar)

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
ChatDuplicateMessagesPerf.default 371 337 1.1:1
PortalMinimalPerf.default 208 189 1.1:1
SkeletonMinimalPerf.default 444 409 1.09:1
FormMinimalPerf.default 512 475 1.08:1
RefMinimalPerf.default 272 253 1.08:1
AnimationMinimalPerf.default 658 617 1.07:1
AvatarMinimalPerf.default 240 224 1.07:1
DividerMinimalPerf.default 453 424 1.07:1
HeaderMinimalPerf.default 450 426 1.06:1
IconMinimalPerf.default 755 715 1.06:1
LayoutMinimalPerf.default 452 430 1.05:1
TableMinimalPerf.default 486 463 1.05:1
TextAreaMinimalPerf.default 635 606 1.05:1
TooltipMinimalPerf.default 1236 1179 1.05:1
ChatWithPopoverPerf.default 488 471 1.04:1
LoaderMinimalPerf.default 786 758 1.04:1
ReactionMinimalPerf.default 466 450 1.04:1
SliderMinimalPerf.default 1907 1827 1.04:1
HeaderSlotsPerf.default 923 895 1.03:1
ImageMinimalPerf.default 461 448 1.03:1
ItemLayoutMinimalPerf.default 1418 1375 1.03:1
StatusMinimalPerf.default 833 811 1.03:1
AccordionMinimalPerf.default 181 178 1.02:1
BoxMinimalPerf.default 412 405 1.02:1
ButtonOverridesMissPerf.default 1969 1939 1.02:1
ButtonSlotsPerf.default 668 654 1.02:1
DropdownManyItemsPerf.default 814 797 1.02:1
GridMinimalPerf.default 414 406 1.02:1
InputMinimalPerf.default 1475 1447 1.02:1
ListWith60ListItems.default 748 732 1.02:1
TableManyItemsPerf.default 2296 2242 1.02:1
VideoMinimalPerf.default 775 760 1.02:1
AlertMinimalPerf.default 344 341 1.01:1
CarouselMinimalPerf.default 581 575 1.01:1
CheckboxMinimalPerf.default 3085 3042 1.01:1
DatepickerMinimalPerf.default 6437 6399 1.01:1
DropdownMinimalPerf.default 3346 3311 1.01:1
EmbedMinimalPerf.default 4719 4654 1.01:1
FlexMinimalPerf.default 342 340 1.01:1
ListMinimalPerf.default 619 613 1.01:1
RosterPerf.default 1361 1342 1.01:1
ProviderMinimalPerf.default 1289 1271 1.01:1
CustomToolbarPrototype.default 4526 4481 1.01:1
ToolbarMinimalPerf.default 1101 1092 1.01:1
TreeMinimalPerf.default 962 950 1.01:1
ButtonMinimalPerf.default 219 219 1:1
DialogMinimalPerf.default 875 876 1:1
ListCommonPerf.default 766 763 1:1
MenuButtonMinimalPerf.default 1941 1942 1:1
RadioGroupMinimalPerf.default 559 558 1:1
SplitButtonMinimalPerf.default 4937 4958 1:1
TextMinimalPerf.default 402 404 1:1
AttachmentMinimalPerf.default 197 198 0.99:1
MenuMinimalPerf.default 1002 1017 0.99:1
ProviderMergeThemesPerf.default 1869 1888 0.99:1
ChatMinimalPerf.default 883 901 0.98:1
LabelMinimalPerf.default 467 475 0.98:1
PopupMinimalPerf.default 692 707 0.98:1
SegmentMinimalPerf.default 415 422 0.98:1
TreeWith60ListItems.default 219 224 0.98:1
AttachmentSlotsPerf.default 1257 1296 0.97:1
CardMinimalPerf.default 668 690 0.97:1
ListNestedPerf.default 644 670 0.96:1

@ling1726 ling1726 closed this Feb 17, 2022
@ling1726 ling1726 reopened this Feb 17, 2022
@layershifter layershifter marked this pull request as ready for review February 17, 2022 11:16
@layershifter layershifter requested a review from a team February 17, 2022 11:17
Comment thread rfcs/react-components/convergence/portal-compat.md Outdated

#### Pros and Cons

- 👎 `z-index=1000000` is ugly

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

another pro+con (combined) is that to solve the css vars, we need a context anyway, not storing an extra z-index in it doesn't change that fact


In the prototype the publisher component is called `CompatHostV9`:

- it reads current classes from `useThemeClassName()`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

apps could also just create their own class name instead of useThemeClassName (i.e. use useThemeStyleTag instead.

Maybe we should include that as an option and also list pros/cons

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am not sure that it's a realistic case... useThemeClassName() and matching context are still required to be used to make Fluent components working otherwise heavy recomposition of every component that uses Portal will be required.

For custom components I still see sense to use our Portal instead of custom ones (it handles SSR). IMO if customers are creating custom portals and do not use useThemeClassName() to get classes with CSS variables they have bigger problem than compatibility 🐱

Comment thread rfcs/react-components/convergence/portal-compat.md
Comment thread rfcs/react-components/convergence/portal-compat.md
@layershifter layershifter requested review from a team February 21, 2022 15:14
@theerebuss theerebuss self-requested a review February 22, 2022 13:09

@theerebuss theerebuss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm pro introducing the compat Context because:

  • Cleanest solution (no "deps" on older code)
  • We don't double down on values that will become harder to change in the future

My only two concerns are communication on this and cleanup in the future.

Is it the user's concern to remove the compat context once no longer needed?


#### Pros and Cons

- 👎 (_out of scope?_) possible singleton issues due multiple versions that could be present in an app

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if this will happen applications will break. if we decide to go with this appraoch this package should never major bump

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's true and I think that it's a valid requirement.

@dzearing dzearing May 4, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It would be great to start marking singleton packages with singleton: true in the package.json. We've run into situations where this metadata would be beneficial elsewhere. For example, we could detect dupe singletons in an app graph and fail the build on detection.

@Hotell Hotell May 4, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@dzearing can you pls point us to existing tooling that is capable to check such a scenario ? I'd rather avoid adding some undocumented magic which is not part of standard package.json json schema. If we can document/automate I'm ok with that.

Comment thread rfcs/react-components/convergence/portal-compat.md

@Hotell Hotell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, lets wait for agreement from redmond folks.

@layershifter

Copy link
Copy Markdown
Member Author

@microsoft/cxe-red & @microsoft/cxe-coastal can you please review?

@khmakoto khmakoto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Took another look after yesterday's discussion and it LGTM.

@micahgodbolt

Copy link
Copy Markdown
Member

ping @GeoffCox as he's working on v8 transition tools and docs

@layershifter

Copy link
Copy Markdown
Member Author

We have an offline sync about this RFC few weeks ago (17th March) with @khmakoto, @levithomason, @ling1726, @miroslavstastny & @GeoffCox.

The summary:

  • zIndex
    • To check if these values (1000000) can be changed via props in v8
    • Trace in history when these zIndex values appeared
    • Prototype layer manager to increase zIndex based on parent (DOM or JSX??)
  • Context approach
    • Agreed to proceed, no comments ✅

@layershifter

Copy link
Copy Markdown
Member Author

My only two concerns are communication on this and cleanup in the future.

Is it the user's concern to remove the compat context once no longer needed?

Yes, it user's concern. But I think it that it's okay, once customers will stop to use @fluentui/react@8 or @fluentui/react-northstar they will need to perform cleanup anyway (remove providers, entries in package.json files, etc.).

@layershifter

Copy link
Copy Markdown
Member Author

zIndex

  • To check if these values (1000000) can be changed via props in v8

No, styles are hardcoded:

isNotHost && [
classNames.rootNoHost,
{
position: 'fixed',
zIndex: ZIndexes.Layer,
top: 0,
left: 0,
bottom: 0,
right: 0,
visibility: 'hidden',
},
],

These styles will be always added when a layer is not using LayerHost, https://developer.microsoft.com/en-us/fluentui#/controls/web/layer.

  • Trace in history when these zIndex values appeared
  • Prototype layer manager to increase zIndex based on parent (DOM or JSX??)

@GeoffCox AFAIR it was yours proposal. Can you please share ideas and goals behind it?

For example, elements with equal values zIndex will be handled by DOM order i.e. a component that will be later mounted - wins.

Another issue, that any smart handling might be a huge breaking change for customers (see the history, these values were there for ages). But without changes in v8/v0 I don't see a way how it could be integrated as we can't rely on DOM order:

<!-- Elements are not nested, they are siblings -->
<div class="ms-Layer"></div>
<div class="fui-Popup"></div>

Increasing zIndex based on a value of sibling does not sound like a great approach. For example, a change in DOM structure and it's broken:

<div>
  <div class="ms-Layer"></div> <!-- ⬅️ z-index is there ->
</div>
<div class="fui-Popup"></div>

This might not be a case for v8, but it's true for v0.

@ling1726

Copy link
Copy Markdown
Contributor

zIndex

@layershifter The problem we are trying to solve is that portals are stacked on top of each other when nested right ?

<V8Portal>
  <v9Portal />
<v8Portal>

In this case we should make sure that the v9 portal renders over the v8 portal.

V8 already has a mechanism to modify z-index for layers (Link to docs)

<Callout layerProps={{ className: overrideZIndex }}  />

In this case I propose 2 ways of going forward

portalProps (naming not binding) for components

Our components that use portals should expose a similar portalProps prop that is typed consistently across all the components that will render portals

<Popover portalProps={{ className: overrideZIndex }} />
<Tooltip portalProps={{ className: overrideZIndex }} />
<Menu portalProps={{ className: overrideZIndex }} />

Compatware for v9

We can continue the idea of compat context for v9 to set zindex

<V9PortalCompat zIndex={1000000}>
   <V9Portal />
<v9PortalCompat />

@GeoffCoxMSFT GeoffCoxMSFT removed the request for review from a team May 2, 2022 19:14
@Hotell

Hotell commented May 4, 2022

Copy link
Copy Markdown
Contributor

Probably out of topic of this particular RFC, but regarding z-indexes on root elements:

It should be avoided at all cost . instead we can leverage isolation. That would mitigate those z-indexes battles in a convenient way.

No z-index, no problem:
image
image

Not sure that adding another property to our components API to basically "hack/workaround" things is the proper way forward.

@layershifter

Copy link
Copy Markdown
Member Author

Probably out of topic of this particular RFC, but regarding z-indexes on root elements:

It should be avoided at all cost . instead we can leverage isolation. That would mitigate those z-indexes battles in a convenient way.

No z-index, no problem: image image

Not sure that adding another property to our components API to basically "hack/workaround" things is the proper way forward.

Sorry, but I didn't get how isolation could help with existing zIndex values in @fluentui/react@8. Can you please clarify?

@Hotell

Hotell commented May 4, 2022

Copy link
Copy Markdown
Contributor

Sorry, but I didn't get how isolation could help with existing zIndex values in @fluentui/react@8. Can you please clarify?

right, as I mentioned this is probably Out of topic for this RFC, but as you started convo regarding z-indexes I wanted to add my POV on the topic. this solution would "help" I guess only if we changed the css definition in v8, but I guess that's a no go.

hope it's clear now

@layershifter

Copy link
Copy Markdown
Member Author

@layershifter The problem we are trying to solve is that portals are stacked on top of each other when nested right ?

Correct, effectively it's this case (modified CodeSandbox). I don't see any other solution than applying the same zIndex for v9 Portals.

@layershifter

Copy link
Copy Markdown
Member Author

Summary

  • There are no concerns about React Context part and it's being implemented in feat: add portal compat implementation to v8 & v0 #22541
  • There are no other solution as apply the same zIndex for v9 Portal as in Layer from v8. This is a legacy part that is impossible to change. Ability to customise zIndex (RFC: Portal compatibility #21774 (comment)) is also a valid requirement, but it's out of scope of this RFC. I will create a separate one to standardise the approach (similarly to positioning prop).

This RFC has enough approvals and if there will be no additional input I am going to merge it on Wednesday. Cheers 🍻

@layershifter layershifter merged commit 36a89f2 into microsoft:master May 11, 2022
@layershifter layershifter deleted the rfc/compat-v8-v9 branch May 11, 2022 08:28
rohitpagariya pushed a commit to rohitpagariya/fluentui that referenced this pull request May 12, 2022
* RFC: Portal compatibility

* Update rfcs/react-components/convergence/portal-compat.md

Co-authored-by: ling1726 <[email protected]>

Co-authored-by: ling1726 <[email protected]>
marwan38 pushed a commit to marwan38/fluentui that referenced this pull request Jun 13, 2022
* RFC: Portal compatibility

* Update rfcs/react-components/convergence/portal-compat.md

Co-authored-by: ling1726 <[email protected]>

Co-authored-by: ling1726 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: RFC Request for Feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.