npm package diff
Package: @chakra-ui/react
Versions: 2.10.1 - 2.10.2
File: package/dist/cjs/menu/use-menu.cjs
Index: package/dist/cjs/menu/use-menu.cjs
===================================================================
--- package/dist/cjs/menu/use-menu.cjs
+++ package/dist/cjs/menu/use-menu.cjs
@@ -19,15 +19,8 @@
const [MenuProvider, useMenuContext] = utils.createContext({
strict: false,
name: "MenuContext"
});
-function useIds(idProp, ...prefixes) {
- const reactId = react.useId();
- const id = idProp || reactId;
- return react.useMemo(() => {
- return prefixes.map((prefix) => `${prefix}-${id}`);
- }, [id, prefixes]);
-}
function getOwnerDocument(node) {
return node?.ownerDocument ?? document;
}
function isActiveElement(element) {
@@ -53,8 +46,9 @@
...popperProps
} = props;
const menuRef = react.useRef(null);
const buttonRef = react.useRef(null);
+ const scrollIntoViewRef = react.useRef(true);
const descendants = useMenuDescendants();
const focusMenu = react.useCallback(() => {
requestAnimationFrame(() => {
menuRef.current?.focus({ preventScroll: false });
@@ -63,8 +57,10 @@
const focusFirstItem = react.useCallback(() => {
const id2 = setTimeout(() => {
if (initialFocusRef) {
initialFocusRef.current?.focus();
+ } else if (!descendants.count()) {
+ menuRef.current?.focus({ preventScroll: false });
} else {
const first = descendants.firstEnabled();
if (first)
setFocusedIndex(first.index);
@@ -73,11 +69,15 @@
timeoutIds.current.add(id2);
}, [descendants, initialFocusRef]);
const focusLastItem = react.useCallback(() => {
const id2 = setTimeout(() => {
- const last = descendants.lastEnabled();
- if (last)
- setFocusedIndex(last.index);
+ if (!descendants.count()) {
+ menuRef.current?.focus({ preventScroll: false });
+ } else {
+ const last = descendants.lastEnabled();
+ if (last)
+ setFocusedIndex(last.index);
+ }
});
timeoutIds.current.add(id2);
}, [descendants]);
const onOpenInternal = react.useCallback(() => {
@@ -110,20 +110,15 @@
placement,
direction
});
const [focusedIndex, setFocusedIndex] = react.useState(-1);
- hooks.useUpdateEffect(() => {
- if (!isOpen) {
- setFocusedIndex(-1);
- }
- }, [isOpen]);
hooks.useFocusOnHide(menuRef, {
focusRef: buttonRef,
visible: isOpen,
shouldFocus: true
});
const animationState = hooks.useAnimationState({ isOpen, ref: menuRef });
- const [buttonId, menuId] = useIds(id, `menu-button`, `menu-list`);
+ const [buttonId, menuId] = hooks.useIds(id, `menu-button`, `menu-list`);
const openAndFocusMenu = react.useCallback(() => {
onOpen();
focusMenu();
}, [onOpen, focusMenu]);
@@ -134,13 +129,33 @@
ids.forEach((id2) => clearTimeout(id2));
ids.clear();
};
}, []);
+ hooks.useUpdateEffect(() => {
+ if (isOpen)
+ return;
+ setFocusedIndex(-1);
+ menuRef.current?.scrollTo(0, 0);
+ }, [isOpen]);
+ hooks.useUpdateEffect(() => {
+ if (!isOpen)
+ return;
+ if (focusedIndex === -1) {
+ focusMenu();
+ }
+ }, [focusedIndex, isOpen]);
+ react.useEffect(() => {
+ if (!isOpen)
+ return;
+ const item = descendants.item(focusedIndex);
+ item?.node?.focus({ preventScroll: !scrollIntoViewRef.current });
+ }, [descendants, focusedIndex, isOpen]);
const openAndFocusFirstItem = react.useCallback(() => {
onOpen();
focusFirstItem();
}, [focusFirstItem, onOpen]);
const openAndFocusLastItem = react.useCallback(() => {
+ scrollIntoViewRef.current = true;
onOpen();
focusLastItem();
}, [onOpen, focusLastItem]);
const refocus = react.useCallback(() => {
@@ -149,11 +164,10 @@
const shouldRefocus = isOpen && !hasFocusWithin;
if (!shouldRefocus)
return;
const node = descendants.item(focusedIndex)?.node;
- node?.focus({ preventScroll: true });
+ node?.focus({ preventScroll: !scrollIntoViewRef.current });
}, [isOpen, focusedIndex, descendants]);
- const rafId = react.useRef(null);
return {
openAndFocusMenu,
openAndFocusFirstItem,
openAndFocusLastItem,
@@ -178,14 +192,20 @@
setFocusedIndex,
isLazy,
lazyBehavior,
initialFocusRef,
- rafId
+ scrollIntoViewRef
};
}
function useMenuButton(props = {}, externalRef = null) {
const menu = useMenuContext();
- const { onToggle, popper, openAndFocusFirstItem, openAndFocusLastItem } = menu;
+ const {
+ onToggle,
+ popper,
+ openAndFocusFirstItem,
+ openAndFocusLastItem,
+ scrollIntoViewRef
+ } = menu;
const onKeyDown = react.useCallback(
(event) => {
const eventKey = event.key;
const keyMap = {
@@ -194,14 +214,15 @@
ArrowUp: openAndFocusLastItem
};
const action = keyMap[eventKey];
if (action) {
+ scrollIntoViewRef.current = true;
event.preventDefault();
event.stopPropagation();
action(event);
}
},
- [openAndFocusFirstItem, openAndFocusLastItem]
+ [openAndFocusFirstItem, openAndFocusLastItem, scrollIntoViewRef]
);
return {
...props,
ref: hooks.mergeRefs(menu.buttonRef, externalRef, popper.referenceRef),
@@ -232,8 +253,9 @@
onClose,
menuId,
isLazy,
lazyBehavior,
+ scrollIntoViewRef,
unstable__animationState: animated
} = menu;
const descendants = useMenuDescendantsContext();
const createTypeaheadHandler = useShortcut.useShortcut({
@@ -250,14 +272,16 @@
event2.stopPropagation();
onClose();
},
ArrowDown: () => {
- const next = descendants.nextEnabled(focusedIndex);
+ scrollIntoViewRef.current = true;
+ const next = descendants.nextEnabled(focusedIndex) ?? descendants.firstEnabled();
if (next)
setFocusedIndex(next.index);
},
ArrowUp: () => {
- const prev = descendants.prevEnabled(focusedIndex);
+ scrollIntoViewRef.current = true;
+ const prev = descendants.prevEnabled(focusedIndex) ?? descendants.firstEnabled();
if (prev)
setFocusedIndex(prev.index);
}
};
@@ -287,9 +311,10 @@
descendants,
focusedIndex,
createTypeaheadHandler,
onClose,
- setFocusedIndex
+ setFocusedIndex,
+ scrollIntoViewRef
]
);
const hasBeenOpened = react.useRef(false);
if (isOpen) {
@@ -344,12 +369,10 @@
setFocusedIndex,
focusedIndex,
closeOnSelect: menuCloseOnSelect,
onClose,
- menuRef,
- isOpen,
menuId,
- rafId
+ scrollIntoViewRef
} = menu;
const ref = react.useRef(null);
const id = `${menuId}-menuitem-${react.useId()}`;
const { index, register } = useMenuDescendant({
@@ -359,11 +382,12 @@
(event) => {
onMouseEnterProp?.(event);
if (isDisabled)
return;
+ scrollIntoViewRef.current = false;
setFocusedIndex(index);
},
- [setFocusedIndex, index, isDisabled, onMouseEnterProp]
+ [setFocusedIndex, index, isDisabled, onMouseEnterProp, scrollIntoViewRef]
);
const onMouseMove = react.useCallback(
(event) => {
onMouseMoveProp?.(event);
@@ -400,29 +424,8 @@
},
[setFocusedIndex, onFocusProp, index]
);
const isFocused = index === focusedIndex;
- const trulyDisabled = isDisabled && !isFocusable;
- hooks.useUpdateEffect(() => {
- if (!isOpen)
- return;
- if (isFocused && !trulyDisabled && ref.current) {
- if (rafId.current) {
- cancelAnimationFrame(rafId.current);
- }
- rafId.current = requestAnimationFrame(() => {
- ref.current?.focus({ preventScroll: true });
- rafId.current = null;
- });
- } else if (menuRef.current && !isActiveElement(menuRef.current)) {
- menuRef.current.focus({ preventScroll: true });
- }
- return () => {
- if (rafId.current) {
- cancelAnimationFrame(rafId.current);
- }
- };
- }, [isFocused, trulyDisabled, menuRef, isOpen]);
const clickableProps = useClickable.useClickable({
onClick,
onFocus,
onMouseEnter,