Skip to content

Commit

Permalink
fix(Menu): List scroll not behaves
Browse files Browse the repository at this point in the history
  • Loading branch information
LexSwed committed Oct 8, 2020
1 parent e7cd3d5 commit 9f2dcef
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 191 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@
"eslint-plugin-react-hooks": "^4.1.2",
"husky": "^4.3.0",
"jest": "^26.5.2",
"next": "^9.5.3",
"next": "^9.5.4",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.2",
"pretty-quick": "^3.0.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-icons": "^3.11.0",
"rollup": "^2.28.2",
"rollup": "^2.29.0",
"rollup-plugin-peer-deps-external": "^2.2.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.27.3",
Expand Down
2 changes: 0 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ export default {
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-proposal-class-properties',
'transform-react-remove-prop-types',
],
exclude: 'node_modules/**',
babelHelpers: 'runtime',
Expand Down
1 change: 0 additions & 1 deletion src/lib/Menu/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const MenuItem = React.forwardRef<HTMLLIElement, Props>(({ act, ...props }, ref)
props.onPress,
useCallback(
(event) => {
console.log(act);
act && onAction?.(act);
if (event.defaultPrevented) return;
close();
Expand Down
48 changes: 11 additions & 37 deletions src/lib/Menu/MenuList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo } from 'react';
import Portal from '../Portal';
import { useMenu, useMenuControlState, useMenuOpenState } from './utils';
import { FocusManagerOptions, FocusScope, useFocusManager } from '@react-aria/focus';
import { useAllHandlers, useOnClickOutside, useForkRef, useKeyboardHandles, usePopper } from '../utils';
import { useAllHandlers, useOnClickOutside, useForkRef, useKeyboardHandles, usePopper, sameWidth } from '../utils';
import { styled } from '../stitches.config';
import type { Options } from '@popperjs/core';

Expand Down Expand Up @@ -52,30 +52,14 @@ const focusOptions: FocusManagerOptions = { wrap: true };
function useMenuProps({ placement = 'bottom-start', offset = 8, ...props }: Props): UlListProps {
const { triggerRef, popoverRef, seed, onAction } = useMenu();
const { close, stateRef } = useMenuControlState();
const focusManager = useFocusManager();
const { focusNext, focusPrevious } = useFocusManager();
const popperRef = usePopper(
triggerRef,
useMemo<Options>(
() => ({
placement,
strategy: 'fixed',
modifiers: [
{ name: 'offset', options: { offset: [0, offset] } },
{
name: 'minWidth',
enabled: true,
phase: 'beforeWrite',
requires: ['computeStyles'],
fn({ state }) {
const { width } = state.rects.reference;
state.styles.popper.minWidth = `${width}px`;
},
effect({ state }) {
const { width } = state.elements.reference.getBoundingClientRect();
state.elements.popper.style.minWidth = `${width}px`;
},
},
],
modifiers: [{ name: 'offset', options: { offset: [0, offset] } }, sameWidth],
}),
[placement, offset]
)
Expand All @@ -98,39 +82,29 @@ function useMenuProps({ placement = 'bottom-start', offset = 8, ...props }: Prop

useEffect(() => {
if (stateRef.current.lastKey === 'ArrowUp') {
focusManager.focusPrevious(focusOptions);
focusPrevious(focusOptions);
} else {
focusManager.focusNext(focusOptions);
focusNext(focusOptions);
}
}, [focusManager, popoverRef, stateRef]);
}, [focusNext, focusPrevious, popoverRef, stateRef]);

const handleKeyDown = useKeyboardHandles(
useMemo(
() => ({
'ArrowDown': () => focusManager.focusNext(focusOptions),
'ArrowUp': () => focusManager.focusPrevious(focusOptions),
'ArrowDown': () => focusNext(focusOptions),
'ArrowUp': () => focusPrevious(focusOptions),
'Enter': (event) => {
selectItem(event.target as HTMLLIElement);
if (event.defaultPrevented) return;
close();
},
' ': (event) => {
selectItem(event.target as HTMLLIElement);
if (event.defaultPrevented) return;
close();
},
'Escape': (event) => {
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
close();
},
'Tab': (event) => {
if (event.defaultPrevented) return;
close();
},
'Escape': close,
'Tab': close,
}),
[close, focusManager, selectItem]
[close, focusNext, focusPrevious, selectItem]
)
);

Expand Down
30 changes: 25 additions & 5 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createPopper, Instance, Options, VirtualElement } from '@popperjs/core';
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
import { createPopper, Instance, Modifier, Options, VirtualElement } from '@popperjs/core';

type PossibleRef<T> = React.Ref<T> | ((instance: T | null) => void) | null | undefined;

Expand Down Expand Up @@ -59,16 +59,23 @@ export function useAllHandlers<E extends React.SyntheticEvent<any, Event>>(
type KeyboardHandler = ((event: React.KeyboardEvent<any>) => void) | undefined;
type KeyboardHandlers = { [Key in React.KeyboardEvent<any>['key']]: KeyboardHandler };

export function useKeyboardHandles(handlers: KeyboardHandlers): KeyboardHandler {
export function useKeyboardHandles(handlers: KeyboardHandlers, preventDefault = true): KeyboardHandler {
const handlersRef = useRef(handlers);

useEffect(() => {
handlersRef.current = handlers;
}, [handlers]);

return useCallback<(event: React.KeyboardEvent<any>) => void>((event) => {
handlersRef.current[event.key]?.(event);
}, []);
return useCallback<(event: React.KeyboardEvent<any>) => void>(
(event) => {
if (preventDefault) {
event.preventDefault();
event.stopPropagation();
}
handlersRef.current[event.key]?.(event);
},
[preventDefault]
);
}

const MOUSEDOWN = 'mousedown';
Expand Down Expand Up @@ -143,3 +150,16 @@ export function usePopper(
};
}, [popoverRef, instantiatePopper]);
}

export const sameWidth: Modifier<'sameWidth', {}> = {
name: 'sameWidth',
enabled: true,
phase: 'beforeWrite',
requires: ['computeStyles'],
fn: ({ state }) => {
state.styles.popper.width = `${state.rects.reference.width}px`;
},
effect: ({ state }) => {
state.elements.popper.style.width = `${state.elements.reference.getBoundingClientRect().width}px`;
},
};
Loading

0 comments on commit 9f2dcef

Please sign in to comment.