Skip to content

Commit c95df9a

Browse files
authored
fix: More ariakit upgrade fixes (#817)
* Remove hack to hide tooltips when clicking to dismiss a button popover * Simplify Menu's onItemSelect handling internally * Hide menus when they lose focus
1 parent bb396b9 commit c95df9a

File tree

5 files changed

+20
-57
lines changed

5 files changed

+20
-57
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Reactist follows [semantic versioning](https://semver.org/) and doesn't introduce breaking changes (API-wise) in minor or patch releases. However, the appearance of a component might change in a minor or patch release so keep an eye on redesigns and make sure your app still looks and feels like you expect it.
44

5+
# v24.1.1-beta
6+
7+
- [Fix] It was possible to leave a tooltip in a state in which it remained visible all the time. This release fixes the issue.
8+
- [Fix] Auto-close menus when they lose focus to elements other than their own content or their sub-menus.
9+
510
# v24.1.0-beta
611

712
- [Feat] Include changes from [v23.2.0](#v2320) in the beta release

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"email": "henning@doist.com",
77
"url": "http://doist.com"
88
},
9-
"version": "24.1.0-beta",
9+
"version": "24.1.1-beta",
1010
"license": "MIT",
1111
"homepage": "https://github.com/Doist/reactist#readme",
1212
"repository": {

src/menu/menu.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type NativeProps<E extends HTMLElement> = React.DetailedHTMLProps<React.HTMLAttr
3232

3333
type MenuContextState = {
3434
menuStore: MenuStore
35-
handleItemSelect: (value: string | null | undefined) => void
35+
handleItemSelect?: (value: string | null | undefined) => void
3636
getAnchorRect: (() => { x: number; y: number }) | null
3737
setAnchorRect: (rect: { x: number; y: number } | null) => void
3838
}
@@ -76,16 +76,9 @@ function Menu({ children, onItemSelect, ...props }: MenuProps) {
7676
const getAnchorRect = React.useMemo(() => (anchorRect ? () => anchorRect : null), [anchorRect])
7777
const menuStore = useMenuStore({ focusLoop: true, ...props })
7878

79-
const handleItemSelect = React.useCallback(
80-
function handleItemSelect(value: string | null | undefined) {
81-
onItemSelect?.(value)
82-
},
83-
[onItemSelect],
84-
)
85-
8679
const value: MenuContextState = React.useMemo(
87-
() => ({ menuStore, handleItemSelect, getAnchorRect, setAnchorRect }),
88-
[menuStore, handleItemSelect, getAnchorRect, setAnchorRect],
80+
() => ({ menuStore, handleItemSelect: onItemSelect, getAnchorRect, setAnchorRect }),
81+
[menuStore, onItemSelect, getAnchorRect, setAnchorRect],
8982
)
9083

9184
return <MenuContext.Provider value={value}>{children}</MenuContext.Provider>
@@ -163,6 +156,12 @@ const MenuList = polymorphicComponent<'div', MenuListProps>(function MenuList(
163156
className={classNames('reactist_menulist', exceptionallySetClassName)}
164157
getAnchorRect={getAnchorRect ?? undefined}
165158
modal={modal}
159+
onBlur={(event) => {
160+
if (!event.relatedTarget) return
161+
if (event.currentTarget.contains(event.relatedTarget)) return
162+
if (event.relatedTarget?.closest('[role^="menu"]')) return
163+
menuStore.hide()
164+
}}
166165
/>
167166
</Portal>
168167
) : null
@@ -249,7 +248,7 @@ const MenuItem = polymorphicComponent<'button', MenuItemProps>(function MenuItem
249248
const onSelectResult: unknown =
250249
onSelect && !event.defaultPrevented ? onSelect() : undefined
251250
const shouldClose = onSelectResult !== false && hideOnSelect
252-
handleItemSelect(value)
251+
handleItemSelect?.(value)
253252
if (shouldClose) hide()
254253
},
255254
[onSelect, onClick, handleItemSelect, hideOnSelect, hide, value],
@@ -307,7 +306,7 @@ const SubMenu = React.forwardRef<HTMLDivElement, SubMenuProps>(function SubMenu(
307306
const handleSubItemSelect = React.useCallback(
308307
function handleSubItemSelect(value: string | null | undefined) {
309308
if (onItemSelect) onItemSelect(value)
310-
parentMenuItemSelect(value)
309+
parentMenuItemSelect?.(value)
311310
parentMenuHide()
312311
},
313312
[parentMenuHide, parentMenuItemSelect, onItemSelect],

src/tooltip/tooltip.tsx

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -95,50 +95,9 @@ function Tooltip({
9595
throw new Error('Tooltip: String refs cannot be used as they cannot be forwarded')
9696
}
9797

98-
/**
99-
* Prevents the tooltip from automatically firing on focus all the time. This is to prevent
100-
* tooltips from showing when the trigger element is focused back after a popover or dialog that
101-
* it opened was closed. See link below for more details.
102-
* @see https://github.com/ariakit/ariakit/discussions/749
103-
*/
104-
function handleFocus(event: React.FocusEvent<HTMLDivElement>) {
105-
// If focus is not followed by a key up event, does it mean that it's not an intentional
106-
// keyboard focus? Not sure but it seems to work.
107-
// This may be resolved soon in an upcoming version of ariakit:
108-
// https://github.com/ariakit/ariakit/issues/750
109-
function handleKeyUp(event: Event) {
110-
const eventKey = (event as KeyboardEvent).key
111-
if (eventKey !== 'Escape' && eventKey !== 'Enter' && eventKey !== 'Space') {
112-
tooltip.show()
113-
}
114-
}
115-
event.currentTarget.addEventListener('keyup', handleKeyUp, { once: true })
116-
event.preventDefault() // Prevent tooltip.show from being called by TooltipReference
117-
child?.props?.onFocus?.(event)
118-
}
119-
120-
function handleBlur(event: React.FocusEvent<HTMLDivElement>) {
121-
tooltip.hide()
122-
child?.props?.onBlur?.(event)
123-
}
124-
12598
return (
12699
<>
127-
<TooltipAnchor
128-
render={(anchorProps) => {
129-
// Let child props override anchor props so user can specify attributes like tabIndex
130-
// Also, do not apply the child's props to TooltipAnchor as props like `as` can create problems
131-
// by applying the replacement component/element twice
132-
return React.cloneElement(child, {
133-
...child.props,
134-
...anchorProps,
135-
onFocus: handleFocus,
136-
onBlur: handleBlur,
137-
})
138-
}}
139-
store={tooltip}
140-
ref={child.ref}
141-
/>
100+
<TooltipAnchor render={child} store={tooltip} ref={child.ref} />
142101
{isOpen && content ? (
143102
<Box
144103
as={AriakitTooltip}

0 commit comments

Comments
 (0)