Skip to content
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

[Popper] Convert code to typescript #34771

Merged
merged 15 commits into from Dec 20, 2022

Conversation

danhuynhdev
Copy link
Contributor

@danhuynhdev danhuynhdev commented Oct 15, 2022

Resolve #34718

@danhuynhdev
Copy link
Contributor Author

Resolve #34718

@mui-bot
Copy link

mui-bot commented Oct 15, 2022

Messages
📖 Netlify deploy preview: https://deploy-preview-34771--material-ui.netlify.app/

Details of bundle changes

Generated by 🚫 dangerJS against d6b14be

function resolveAnchorEl(anchorEl) {
function resolveAnchorEl(
anchorEl: VirtualElement | (() => VirtualElement)
): any {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure how to resolve this any. Seems like anchorEl has the type HTMLElement | VirtualElement | (() => HTMLElement | VirtualElement) but the current code treat it as HTMLElement | (() => HTMLElement)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

while the original signature put it as VirtualElement | (() => VirtualElement). Is there a potential bug here?

Copy link
Member

Choose a reason for hiding this comment

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

You can define the resolveAnchorEl as an overloaded function:

function resolveAnchorEl(anchorEl: VirtualElement | (() => VirtualElement)): VirtualElement;
function resolveAnchorEl(anchorEl: HTMLElement | (() => HTMLElement)): HTMLElement;
function resolveAnchorEl(anchorEl: VirtualElement | (() => VirtualElement) | HTMLElement | (() => HTMLElement)): HTMLElement | VirtualElement {
  return typeof anchorEl === 'function' ? anchorEl() : anchorEl;
}

and define a type guard checking if an element is a DOM element;

function isHTMLElement(element: HTMLElement | VirtualElement): element is HTMLElement {
  return (element as HTMLElement).nodeType !== undefined;
}

then, after resolving the anchorEl check if it's an HTMLElement:

-if (resolvedAnchorEl && resolvedAnchorEl.nodeType === 1) {
+if (resolvedAnchorEl && isHTMLElement(resolvedAnchorEl) && resolvedAnchorEl.nodeType === 1) {

Similarly, in PopperUnstyled body, where container is defined, check if we're dealing with HTMLElement or VirtualElement. You can pass in null to ownerDocument if anchorEl is a VirtualElement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I resolved this issue

@@ -106,6 +110,8 @@ export interface PopperUnstyledOwnProps {
* @default false
*/
transition?: boolean;

ownerState?: PopperUnstyledOwnerState;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added this to pass type check here https://github.com/danhuynhdev/material-ui/blob/2b0f1d9684abd308de1e3c05e8bec4aaa13993f5/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.tsx#L38
But then I still have to pass ownerState as any. Not sure how to properly handle this as I'm not familiar with ownerState. From other places, it seems like ownerState isn't passed in as a prop but constructed inside the component. But I do not see that in this component.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, something seems to be off here. You should not have ownerState as a prop. I'll try to correct the code in the separate PR and you'll be able to rebase on top of my fixes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have you taken a look a what's wrong here? Happy to fix that myself if I can understand the context here.

Copy link
Member

Choose a reason for hiding this comment

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

It turned out to be a bigger problem that affects several components, and we haven't figured out what would be the best solution here.
In short, we generally don't want to expose ownerState as a prop, because users of the components should not manually set it. However, in some cases, when an MUI Base component is used in a slot of another component, it will receive the ownerState (as all slot components do). The type of this ownerState is not PopperUnstyledOwnerState, though - it's a state of a component that owns the slots, so it's impossible to type this strongly.

For now, let's define ownerState?: object in PopperUnstyledOwnProps. When we decide how to solve the problem for good, we'll revisit this part. This should allow you to drop as any from tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the late response. I have updated the code but unfortunately, ownerState?: object isn't compatible with downstream type, as they expect a concrete interface. So I have to put it as any again, i guess it's the same as object here as we cannot guarantee typesafe-ness here.

@zannager zannager added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 17, 2022
@oliviertassinari oliviertassinari removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 17, 2022
@zannager zannager added component: Paper This is the name of the generic UI component, not the React module! component: Popper The React component. See <Popup> for the latest version. and removed component: Paper This is the name of the generic UI component, not the React module! labels Oct 18, 2022
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 19, 2022
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 23, 2022
> In short, we generally don't want to expose ownerState as a prop, because users of the components should not manually set it. However, in some cases, when an MUI Base component is used in a slot of another component, it will receive the ownerState (as all slot components do). The type of this ownerState is not PopperUnstyledOwnerState, though - it's a state of a component that owns the slots, so it's impossible to type this strongly.
@michaldudak
Copy link
Member

Thanks, this looks pretty good! There's a problem with the CI build, though. It needs the yarn docs:api to be run, but executing this script causes the description of the direction prop to be lost for some reason. Let me investigate it, and I'll do the final review when everything is fine.

@michaldudak michaldudak removed the request for review from mnajdova December 1, 2022 21:12
@michaldudak
Copy link
Member

The direction prop is correctly removed from the docs, as it's not a part of the Popper API, so all is good. Could you please run yarn docs:api and commit the changes?

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 12, 2022
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 20, 2022
@michaldudak
Copy link
Member

I corrected and simplified the code in a few places. I think it's good to go now. Thanks for your contribution, @danhuynhdev!

@michaldudak michaldudak merged commit 5b2583a into mui:master Dec 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: Popper The React component. See <Popup> for the latest version. typescript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Popper][base] Convert code to TypeScript
5 participants