-
Notifications
You must be signed in to change notification settings - Fork 21
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
feat(react): support react 17 #1680
base: develop
Are you sure you want to change the base?
Conversation
ff1b1e5
to
84b23af
Compare
This pull request is automatically being deployed by Amplify Hosting (learn more). |
@@ -545,6 +548,9 @@ test('should not prevent default with enter keypress and closed listbox', () => | |||
// rtl doesn't let us mock preventDefault | |||
// see: https://github.com/testing-library/react-testing-library/issues/572 | |||
event.preventDefault = preventDefault; | |||
if (type === 'focus') { |
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.
From Jason:
The changes here I suspect are related to testing-library/user-event#592, but we're not using user-event but are calling fireEvent due to specific limitations with testing library.
expect(outsideButton).toBeTruthy(); | ||
await user.click(outsideButton); | ||
render(<Wrapper tooltipProps={{ onClose }} />); | ||
await user.click(document.body); |
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.
We don't need to add any other elements to test clicking outside. We can click on the body
element instead.
buttonProps = {}, | ||
tooltipProps = {} | ||
}: { | ||
interface PopoverProps { |
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.
Small cleanup since these types were repeated.
f6fe383
to
ab1f0c2
Compare
469811e
to
9b75a9c
Compare
991f913
to
aaa242c
Compare
fcb43d8
to
cda2956
Compare
bb33c6f
to
098a995
Compare
@@ -277,7 +276,7 @@ test('should have no axe violations for prompt variant', async () => { | |||
expect(await axe(baseElement)).toHaveNoViolations(); | |||
}); | |||
|
|||
test('aria-labelleddby should exist for variant="custom"', async () => { | |||
test('aria-labelledby should exist for variant="custom"', async () => { |
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.
Typo!
@@ -286,7 +285,7 @@ test('aria-labelleddby should exist for variant="custom"', async () => { | |||
expect(ariaLabelledById).toBeTruthy(); | |||
}); | |||
|
|||
test('aria-labelleddby should not exist if aria-label provided for variant="prompt"', async () => { | |||
test('aria-labelledby should not exist if aria-label provided for variant="prompt"', async () => { |
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.
Same typo as above.
6e50a3a
to
ede47b8
Compare
ad1a367
to
250db1f
Compare
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.
These changes are recommended here https://legacy.reactjs.org/blog/2020/08/10/react-v17-rc.html#fixing-potential-issues
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.
We'll want to be sure we call this out in the release, might be good to tag folks in the slack channel. I don't think anyone should be relying on the capture vs bubble phase but you never know...
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.
Everything looks pretty good, but I do think we need to address the breaking change here.
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.
We'll want to be sure we call this out in the release, might be good to tag folks in the slack channel. I don't think anyone should be relying on the capture vs bubble phase but you never know...
export interface OptionsMenuListProps | ||
extends Omit<OptionsMenuProps, 'trigger'> { | ||
className?: string; | ||
triggerRef: React.RefObject<HTMLButtonElement>; | ||
} |
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.
Unfortunately, this appears to be a breaking change. Does this change still need to be made even when we're checking the event in the capture phase?
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.
This change is needed because the trigger button is outside of the ClickOutsideListener
component which caused the menu to not be able to close after it was opened. If the menu was open and you clicked on the trigger button to close it, it would call handleClickOutside
in OptionsMenuList
and then toggleMenu
in the OptionsMenu
would be called to keep it open again. That's why I do the check below to not call onClose
within handeClickOutside
if we click on the trigger element:
const handleClickOutside = (e: MouseEvent | TouchEvent) => {
const target = e.target as Node;
const triggerElement = triggerRef.current;
if (target === triggerElement || triggerElement?.contains(target)) {
return;
}
Let me know if you think there's a better way to go about this.
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.
I pulled down your PR, and I have a few thoughts about this.
One way we could handle this in a non-breaking manner, is to check for event.defaultPrevented
here:
cauldron/packages/react/src/components/OptionsMenu/OptionsMenu.tsx
Lines 48 to 50 in 9df13e6
const toggleMenu = () => { | |
setShow(!show); | |
}; |
Within the click outside callback we could then set event.preventDefault
if the menu list is currently shown. This does come with the downside of it would prevent immediate clicks on elements outside of the menu while the list is open so not the best solution, but also non-breaking.
Aside from that, we need to consider these components could also be constructed piecemeal so we need to accommodate for that scenario as well. Instead of explicitly trying to set the ref on a component (and not all components correctly implement the ref
property) we might want to consider capturing the element that triggered the open state:
const triggerRef = useRef<HTMLElement>()
const toggleMenu = (event) => {
if (!show) {
triggerRef.current = document.activeElement
} else {
triggerRef.current = null
}
setShow(!show);
};
OptionsMenuList could optionally accept the ref (to be non breaking):
export interface OptionsMenuListProps
extends Omit<OptionsMenuProps, 'trigger'> {
className?: string;
triggerRef?: React.RefObject<HTMLElement>
}
...
const handleClickOutside = (e: MouseEvent | TouchEvent) => {
if (triggerRef && triggerRef.current) {
// use existing checks
}
}
IMO it makes it slightly more robust without there needing to be a breaking change. Thoughts?
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.
In the long run, we're on the path to create a brand new component that will replace this one and deprecate usage of this component. It has a lot odd patterns that do not support some of the mechanisms we're trying to achieve and any changes we would make would need to be breaking. A brand new component to move away from some of these patterns without breaking immediate usage is the path of least resistance.
closes #1473
This PR does a few things:
OptionsMenu
andPopover
component, when a user opens them, clicking on the trigger buttons will now close them instead of triggering the click outsideclose()
methodOptionsMenu
components to function componentsTopBar
docs so that theOptionsMenu
now has a trigger to referenceVerification Steps
OptionsMenu
componentOptionsMenu
OptionsMenu
will close theOptionsMenu
Popover
componentPopover
Popover
will close thePopover
TopBar
with menu componentOptionsMenu
inside theTopBar
OptionsMenu
will close theOptionsMenu