From fc461a15dfad003a549c01f216166221215175f3 Mon Sep 17 00:00:00 2001 From: Zheng Song <41896553+szhsin@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:42:07 +1100 Subject: [PATCH] Add offset props that set offset distance between menu and its anchor element --- package.json | 2 +- src/components/ControlledMenu.js | 10 +++++++- src/components/Menu.js | 10 +++++++- src/components/MenuList.js | 13 ++++++---- src/components/SubMenu.js | 10 +++++++- src/utils/constants.js | 33 ------------------------ src/utils/index.js | 1 + src/utils/propTypes.js | 43 ++++++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 42 deletions(-) create mode 100644 src/utils/propTypes.js diff --git a/package.json b/package.json index f390aadb..316f6db3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@szhsin/react-menu", - "version": "0.10.3", + "version": "0.10.4", "description": "React menu components", "author": "Zheng Song", "license": "MIT", diff --git a/src/components/ControlledMenu.js b/src/components/ControlledMenu.js index d6f91e47..9c7354aa 100644 --- a/src/components/ControlledMenu.js +++ b/src/components/ControlledMenu.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import { menuPropTypesBase, menuDefaultPropsBase, + offsetPropTypes, + offsetDefaultProps, FocusPositions } from '../utils'; import { useMenuList } from './useMenuList'; @@ -22,6 +24,8 @@ export const ControlledMenu = React.memo(function ControlledMenu({ isOpen, isMounted, menuItemFocus, + offsetX, + offsetY, children, onClick, onClose, @@ -39,7 +43,9 @@ export const ControlledMenu = React.memo(function ControlledMenu({ direction, isOpen, isMounted, - menuItemFocus + menuItemFocus, + offsetX, + offsetY }, id, animation, @@ -51,6 +57,7 @@ export const ControlledMenu = React.memo(function ControlledMenu({ ControlledMenu.propTypes = { ...menuPropTypesBase, + ...offsetPropTypes, anchorPoint: PropTypes.exact({ x: PropTypes.number, y: PropTypes.number @@ -66,6 +73,7 @@ ControlledMenu.propTypes = { ControlledMenu.defaultProps = { ...menuDefaultPropsBase, + ...offsetDefaultProps, isMounted: true, menuItemFocus: { position: FocusPositions.INITIAL } }; diff --git a/src/components/Menu.js b/src/components/Menu.js index 55ad4c09..61f4c714 100644 --- a/src/components/Menu.js +++ b/src/components/Menu.js @@ -4,6 +4,8 @@ import { safeCall, menuPropTypesBase, menuDefaultPropsBase, + offsetPropTypes, + offsetDefaultProps, Keys, FocusPositions, useMenuChange, @@ -23,6 +25,8 @@ export const Menu = React.memo(function Menu({ align, direction, menuButton, + offsetX, + offsetY, children, onClick, onChange }) { @@ -97,7 +101,9 @@ export const Menu = React.memo(function Menu({ direction, isOpen, isMounted, - menuItemFocus + menuItemFocus, + offsetX, + offsetY }, id, animation, @@ -117,6 +123,7 @@ export const Menu = React.memo(function Menu({ Menu.propTypes = { ...menuPropTypesBase, + ...offsetPropTypes, keepMounted: PropTypes.bool, menuButton: PropTypes.oneOfType([ PropTypes.element, @@ -127,5 +134,6 @@ Menu.propTypes = { Menu.defaultProps = { ...menuDefaultPropsBase, + ...offsetDefaultProps, keepMounted: true }; diff --git a/src/components/MenuList.js b/src/components/MenuList.js index 94897a5e..813a9fb6 100644 --- a/src/components/MenuList.js +++ b/src/components/MenuList.js @@ -36,6 +36,8 @@ export const MenuList = defineName(React.memo(function MenuList({ isMounted, isDisabled, menuItemFocus, + offsetX, + offsetY, children, onKeyDown, onAnimationEnd, @@ -286,12 +288,12 @@ export const MenuList = defineName(React.memo(function MenuList({ } = positionHelpers(); const anchorRect = anchorRef.current.getBoundingClientRect(); - const placeLeftX = anchorRect.left - containerRect.left - menuRect.width; - const placeRightX = anchorRect.right - containerRect.left; - const placeLeftorRightY = anchorRect.top - containerRect.top; + const placeLeftX = anchorRect.left - containerRect.left - menuRect.width - offsetX; + const placeRightX = anchorRect.right - containerRect.left + offsetX; + const placeLeftorRightY = anchorRect.top - containerRect.top + offsetY; - const placeTopY = anchorRect.top - containerRect.top - menuRect.height; - const placeBottomY = anchorRect.bottom - containerRect.top; + const placeTopY = anchorRect.top - containerRect.top - menuRect.height - offsetY; + const placeBottomY = anchorRect.bottom - containerRect.top + offsetY; let placeToporBottomX; if (align === 'end') { placeToporBottomX = anchorRect.right - containerRect.left - menuRect.width; @@ -301,6 +303,7 @@ export const MenuList = defineName(React.memo(function MenuList({ } else { placeToporBottomX = anchorRect.left - containerRect.left; } + placeToporBottomX += offsetX; let newPosition, x, y; let computedDirection = direction; diff --git a/src/components/SubMenu.js b/src/components/SubMenu.js index 734c5fd7..29ac6e65 100644 --- a/src/components/SubMenu.js +++ b/src/components/SubMenu.js @@ -6,6 +6,8 @@ import { bem, flatStyles, stylePropTypes, + offsetPropTypes, + offsetDefaultProps, menuClass, subMenuClass, menuItemClass, @@ -31,6 +33,8 @@ export const SubMenu = defineName(React.memo(function SubMenu({ keepMounted, label, index, + offsetX, + offsetY, children, onChange }) { @@ -175,7 +179,9 @@ export const SubMenu = defineName(React.memo(function SubMenu({ isOpen={isOpen} isMounted={isMounted} isDisabled={isDisabled} - menuItemFocus={menuItemFocus}> + menuItemFocus={menuItemFocus} + offsetX={offsetX} + offsetY={offsetY}> {children} @@ -184,6 +190,7 @@ export const SubMenu = defineName(React.memo(function SubMenu({ SubMenu.propTypes = { ...stylePropTypes, + ...offsetPropTypes, 'aria-label': PropTypes.string, menuClassName: PropTypes.oneOfType([ PropTypes.string, @@ -204,5 +211,6 @@ SubMenu.propTypes = { }; SubMenu.defaultProps = { + ...offsetDefaultProps, keepMounted: true }; diff --git a/src/utils/constants.js b/src/utils/constants.js index a4dd5c82..3583670b 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; export const menuContainerClass = 'rc-menu-container'; export const menuClass = 'rc-menu'; @@ -43,35 +42,3 @@ export const CloseReason = Object.freeze({ 'CANCEL': 'cancel', 'BLUR': 'blur' }); - -export const stylePropTypes = { - className: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.func - ]), - styles: PropTypes.oneOfType([ - PropTypes.object, - PropTypes.func - ]), -}; - -export const menuPropTypesBase = { - ...stylePropTypes, - 'aria-label': PropTypes.string, - id: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number - ]), - animation: PropTypes.bool, - debugging: PropTypes.bool, - align: PropTypes.oneOf(['start', 'center', 'end']), - direction: PropTypes.oneOf(['left', 'right', 'top', 'bottom']), - children: PropTypes.node.isRequired, - onClick: PropTypes.func -}; - -export const menuDefaultPropsBase = { - animation: true, - align: 'start', - direction: 'bottom' -}; diff --git a/src/utils/index.js b/src/utils/index.js index 242e65b4..ac3f58b6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,4 +1,5 @@ export * from './constants'; +export * from './propTypes'; export * from './utils'; export * from './useActiveState'; export * from './useItemState'; diff --git a/src/utils/propTypes.js b/src/utils/propTypes.js new file mode 100644 index 00000000..571535b1 --- /dev/null +++ b/src/utils/propTypes.js @@ -0,0 +1,43 @@ +import PropTypes from 'prop-types'; + +export const stylePropTypes = { + className: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.func + ]), + styles: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.func + ]), +}; + +export const menuPropTypesBase = { + ...stylePropTypes, + 'aria-label': PropTypes.string, + id: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), + animation: PropTypes.bool, + debugging: PropTypes.bool, + align: PropTypes.oneOf(['start', 'center', 'end']), + direction: PropTypes.oneOf(['left', 'right', 'top', 'bottom']), + children: PropTypes.node.isRequired, + onClick: PropTypes.func +}; + +export const menuDefaultPropsBase = { + animation: true, + align: 'start', + direction: 'bottom' +}; + +export const offsetPropTypes = { + offsetX: PropTypes.number, + offsetY: PropTypes.number +} + +export const offsetDefaultProps = { + offsetX: 0, + offsetY: 0 +}