Socket
Socket
Sign inDemoInstall

@paprika/dropdown-menu

Package Overview
Dependencies
111
Maintainers
3
Versions
79
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 2.0.1

lib/components/Confirmation/Confirmation.js

12

lib/components/Item/Item.js

@@ -40,2 +40,5 @@ "use strict";

/** Callback to be executed when key is pressed */
onKeyDown: func,
/** Callback to be executed when dropdown needs to be closed */

@@ -53,2 +56,3 @@ onClose: func,

onClick: function onClick() {},
onKeyDown: function onKeyDown() {},
onClose: function onClose() {},

@@ -71,6 +75,7 @@ onShowConfirmation: function onShowConfirmation() {},

renderConfirmation = props.renderConfirmation,
moreProps = (0, _objectWithoutProperties2["default"])(props, ["children", "isDestructive", "onClick", "onClose", "onShowConfirmation", "renderConfirmation"]);
onKeyDown = props.onKeyDown,
moreProps = (0, _objectWithoutProperties2["default"])(props, ["children", "isDestructive", "onClick", "onClose", "onShowConfirmation", "renderConfirmation", "onKeyDown"]);
var handleClickItem = function handleClickItem() {
onClick();
onClick(children);
onClose();

@@ -82,5 +87,8 @@ };

role: "menuitem",
"data-pka-anchor": "dropdown.item",
onKeyDown: onKeyDown,
isDestructive: isDestructive
};
return _react["default"].createElement(_StyledRawButton, (0, _extends2["default"])({
tabIndex: 0,
hasInsetFocusStyle: true

@@ -87,0 +95,0 @@ }, itemProps, moreProps), children);

@@ -25,2 +25,4 @@ "use strict";

var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/extends"));
var _defineProperty3 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));

@@ -36,2 +38,4 @@

var _useI18n = _interopRequireDefault(require("@paprika/l10n/lib/useI18n"));
var _Item = _interopRequireDefault(require("../../Item.styles"));

@@ -45,3 +49,4 @@

node = _propTypes["default"].node,
string = _propTypes["default"].string;
string = _propTypes["default"].string,
func = _propTypes["default"].func;
var propTypes = {

@@ -54,2 +59,5 @@ /** HTML for each LinkItem */

/** Callback to be executed when key is pressed */
onKeyDown: func,
/** Should the link open content in a new tab */

@@ -59,3 +67,4 @@ isExternal: bool

var defaultProps = {
isExternal: false
isExternal: false,
onKeyDown: function onKeyDown() {}
};

@@ -70,9 +79,13 @@

var children = props.children,
onKeyDown = props.onKeyDown,
isExternal = props.isExternal,
link = props.link,
moreProps = (0, _objectWithoutProperties2["default"])(props, ["children", "isExternal", "link"]);
moreProps = (0, _objectWithoutProperties2["default"])(props, ["children", "onKeyDown", "isExternal", "link"]);
var I18n = (0, _useI18n["default"])();
var linkItemProps = _objectSpread({
role: "menuitem",
href: link
"data-pka-anchor": "dropdown.item",
href: link,
onKeyDown: onKeyDown
}, moreProps);

@@ -85,3 +98,7 @@

return _react["default"].createElement(_StyledA, linkItemProps, children);
return _react["default"].createElement(_StyledA, (0, _extends2["default"])({
"aria-label": isExternal ? I18n.t("dropdownMenu.isExternal", {
link: children
}) : ""
}, linkItemProps), children);
};

@@ -88,0 +105,0 @@

@@ -80,3 +80,3 @@ "use strict";

var DropdownMenu = function DropdownMenu(props) {
function DropdownMenu(props) {
var align = props.align,

@@ -102,2 +102,7 @@ children = props.children,

var _React$useState7 = _react["default"].useState(0),
_React$useState8 = (0, _slicedToArray2["default"])(_React$useState7, 2),
currentFocusIndex = _React$useState8[0],
setFocusIndex = _React$useState8[1];
var triggerRef = _react["default"].useRef(null);

@@ -109,2 +114,9 @@

var dropdownListRef = _react["default"].useRef(null);
function focusAndSetIndex(index) {
if (dropdownListRef && dropdownListRef.current && index !== undefined) dropdownListRef.current.querySelectorAll('[data-pka-anchor="dropdown.item"]')[index].focus();
setFocusIndex(index);
}
var handleCloseMenu = function handleCloseMenu() {

@@ -122,7 +134,33 @@ setIsOpen(false);

var handleOpenMenu = function handleOpenMenu() {
setIsOpen(true);
setIsOpen(true); // https://github.com/acl-services/paprika/issues/316
// Todo Should focus the first item via an onAfterOpen event callback in popover
setTimeout(function () {
focusAndSetIndex(0);
}, 250);
};
var extractedChildren = (0, _extractChildren["default"])(children, ["DropdownMenu.Trigger"]);
var dropdownLastItemIndex = _react["default"].Children.toArray(extractedChildren.children.filter(function (child) {
return child.type && (child.type.displayName === "DropdownMenu.Item" || child.type.displayName === "DropdownMenu.LinkItem");
})).length - 1;
var _onKeyDown = function onKeyDown(event, currentIndex) {
if (event.key === "ArrowDown") {
var indexToFocus = currentIndex === dropdownLastItemIndex ? 0 : currentIndex + 1;
focusAndSetIndex(indexToFocus);
} else if (event.key === "ArrowUp") {
var _indexToFocus = currentIndex === 0 ? dropdownLastItemIndex : currentIndex - 1;
focusAndSetIndex(_indexToFocus);
} else if (event.key === "Home") {
focusAndSetIndex(0);
} else if (event.key === "End") {
focusAndSetIndex(dropdownLastItemIndex);
} else if (event.key === "Enter" || event.key === " ") {// do nothing
} else {
handleCloseMenu();
}
};
var handleShowConfirmation = function handleShowConfirmation(renderConfirmation) {

@@ -153,2 +191,11 @@ return function () {

var getClonedChild = function getClonedChild(child, childKey) {
var additionalProps = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
return _react["default"].cloneElement(child, _objectSpread({
onKeyDown: function onKeyDown(e) {
return _onKeyDown(e, currentFocusIndex);
}
}, childKey, {}, additionalProps));
};
var renderContent = function renderContent() {

@@ -169,20 +216,22 @@ if (isConfirming) {

return _react["default"].createElement(_StyledDiv, null, extractedChildren.children.map(function (child, index) {
return _react["default"].createElement(_StyledDiv, {
ref: dropdownListRef
}, extractedChildren.children.map(function (child, index) {
var childKey = {
key: "DropdownMenuItem".concat(index)
};
if (child && child.type && child.type.displayName === "DropdownMenu.Item") {
var childKey = {
key: "DropdownMenuItem".concat(index)
};
if (child.props.renderConfirmation) {
return _react["default"].cloneElement(child, _objectSpread({
return getClonedChild(child, childKey, {
onShowConfirmation: handleShowConfirmation(child.props.renderConfirmation)
}, childKey));
});
}
return _react["default"].cloneElement(child, _objectSpread({
return getClonedChild(child, childKey, {
onClose: handleCloseMenu
}, childKey));
});
}
return child;
return getClonedChild(child, childKey);
}));

@@ -203,3 +252,3 @@ };

}, isOpen && _react["default"].createElement(_popover["default"].Card, null, renderContent())));
};
}

@@ -206,0 +255,0 @@ DropdownMenu.displayName = "DropdownMenu";

16

package.json
{
"name": "@paprika/dropdown-menu",
"version": "2.0.0",
"version": "2.0.1",
"description": "DropdownMenu component",

@@ -17,9 +17,9 @@ "author": "@paprika",

"@babel/runtime-corejs2": "^7.3.1",
"@paprika/button": "^0.2.4",
"@paprika/confirmation": "^0.2.6",
"@paprika/button": "^0.2.5",
"@paprika/confirmation": "^0.2.7",
"@paprika/helpers": "^0.2.5",
"@paprika/popover": "^0.3.5",
"@paprika/raw-button": "^0.2.2",
"@paprika/stylers": "^0.2.2",
"@paprika/tokens": "^0.1.9",
"@paprika/popover": "^0.3.6",
"@paprika/raw-button": "^0.2.3",
"@paprika/stylers": "^0.2.3",
"@paprika/tokens": "^0.1.10",
"prop-types": "^15.7.2",

@@ -34,3 +34,3 @@ "uuid": "^3.3.2"

},
"gitHead": "011ea581cd21a8ae84e49197a52230b4d5131a5e"
"gitHead": "02878656cf2acd9c62af07d4123dced3ab4455eb"
}

@@ -18,2 +18,5 @@ import React from "react";

/** Callback to be executed when key is pressed */
onKeyDown: func,
/** Callback to be executed when dropdown needs to be closed */

@@ -32,2 +35,3 @@ onClose: func,

onClick: () => {},
onKeyDown: () => {},
onClose: () => {},

@@ -39,6 +43,15 @@ onShowConfirmation: () => {},

const Item = props => {
const { children, isDestructive, onClick, onClose, onShowConfirmation, renderConfirmation, ...moreProps } = props;
const {
children,
isDestructive,
onClick,
onClose,
onShowConfirmation,
renderConfirmation,
onKeyDown,
...moreProps
} = props;
const handleClickItem = () => {
onClick();
onClick(children);
onClose();

@@ -50,2 +63,4 @@ };

role: "menuitem",
"data-pka-anchor": "dropdown.item",
onKeyDown,
isDestructive,

@@ -55,3 +70,3 @@ };

return (
<RawButton hasInsetFocusStyle css={ItemStyles} {...itemProps} {...moreProps}>
<RawButton tabIndex={0} hasInsetFocusStyle css={ItemStyles} {...itemProps} {...moreProps}>
{children}

@@ -58,0 +73,0 @@ </RawButton>

import React from "react";
import PropTypes from "prop-types";
import useI18n from "@paprika/l10n/lib/useI18n";
import linkItemStyles from "../../Item.styles";
const { bool, node, string } = PropTypes;
const { bool, node, string, func } = PropTypes;

@@ -12,2 +13,4 @@ const propTypes = {

link: string.isRequired,
/** Callback to be executed when key is pressed */
onKeyDown: func,
/** Should the link open content in a new tab */

@@ -19,10 +22,14 @@ isExternal: bool,

isExternal: false,
onKeyDown: () => {},
};
const LinkItem = props => {
const { children, isExternal, link, ...moreProps } = props;
const { children, onKeyDown, isExternal, link, ...moreProps } = props;
const I18n = useI18n();
const linkItemProps = {
role: "menuitem",
"data-pka-anchor": "dropdown.item",
href: link,
onKeyDown,
...moreProps,

@@ -37,3 +44,7 @@ };

return (
<a css={linkItemStyles} {...linkItemProps}>
<a
aria-label={isExternal ? I18n.t("dropdownMenu.isExternal", { link: children }) : ""}
css={linkItemStyles}
{...linkItemProps}
>
{children}

@@ -40,0 +51,0 @@ </a>

@@ -30,3 +30,3 @@ import React from "react";

const DropdownMenu = props => {
function DropdownMenu(props) {
const { align, children, edge, ...moreProps } = props;

@@ -36,2 +36,3 @@ const [isOpen, setIsOpen] = React.useState(false);

const [renderConfirmation, setRenderConfirmation] = React.useState(null);
const [currentFocusIndex, setFocusIndex] = React.useState(0);
const triggerRef = React.useRef(null);

@@ -41,2 +42,10 @@ const menuId = React.useRef(uuid());

const dropdownListRef = React.useRef(null);
function focusAndSetIndex(index) {
if (dropdownListRef && dropdownListRef.current && index !== undefined)
dropdownListRef.current.querySelectorAll('[data-pka-anchor="dropdown.item"]')[index].focus();
setFocusIndex(index);
}
const handleCloseMenu = () => {

@@ -55,2 +64,7 @@ setIsOpen(false);

setIsOpen(true);
// https://github.com/acl-services/paprika/issues/316
// Todo Should focus the first item via an onAfterOpen event callback in popover
setTimeout(() => {
focusAndSetIndex(0);
}, 250);
};

@@ -60,2 +74,29 @@

const dropdownLastItemIndex =
React.Children.toArray(
extractedChildren.children.filter(
child =>
child.type &&
(child.type.displayName === "DropdownMenu.Item" || child.type.displayName === "DropdownMenu.LinkItem")
)
).length - 1;
const onKeyDown = (event, currentIndex) => {
if (event.key === "ArrowDown") {
const indexToFocus = currentIndex === dropdownLastItemIndex ? 0 : currentIndex + 1;
focusAndSetIndex(indexToFocus);
} else if (event.key === "ArrowUp") {
const indexToFocus = currentIndex === 0 ? dropdownLastItemIndex : currentIndex - 1;
focusAndSetIndex(indexToFocus);
} else if (event.key === "Home") {
focusAndSetIndex(0);
} else if (event.key === "End") {
focusAndSetIndex(dropdownLastItemIndex);
} else if (event.key === "Enter" || event.key === " ") {
// do nothing
} else {
handleCloseMenu();
}
};
const handleShowConfirmation = renderConfirmation => () => {

@@ -79,2 +120,9 @@ setIsConfirming(prevIsConfirmingState => !prevIsConfirmingState);

const getClonedChild = (child, childKey, additionalProps = {}) =>
React.cloneElement(child, {
onKeyDown: e => onKeyDown(e, currentFocusIndex),
...childKey,
...additionalProps,
});
const renderContent = () => {

@@ -94,18 +142,16 @@ if (isConfirming) {

return (
<div css={contentStyles}>
<div css={contentStyles} ref={dropdownListRef}>
{extractedChildren.children.map((child, index) => {
const childKey = { key: `DropdownMenuItem${index}` };
if (child && child.type && child.type.displayName === "DropdownMenu.Item") {
const childKey = { key: `DropdownMenuItem${index}` };
if (child.props.renderConfirmation) {
return React.cloneElement(child, {
return getClonedChild(child, childKey, {
onShowConfirmation: handleShowConfirmation(child.props.renderConfirmation),
...childKey,
});
}
return React.cloneElement(child, {
return getClonedChild(child, childKey, {
onClose: handleCloseMenu,
...childKey,
});
}
return child;
return getClonedChild(child, childKey);
})}

@@ -133,3 +179,3 @@ </div>

);
};
}

@@ -136,0 +182,0 @@ DropdownMenu.displayName = "DropdownMenu";

import React from "react";
import { Rule, Tagline } from "storybook/assets/styles/common.styles";
import { select, text } from "@storybook/addon-knobs";
import { action } from "@storybook/addon-actions";
import { AlignTypes } from "@paprika/helpers/lib/customPropTypes";

@@ -33,2 +34,6 @@ import L10n from "@paprika/l10n";

const handleItemClick = val => {
action("Clicked a item")(val);
};
const ExampleStory = () => (

@@ -48,11 +53,11 @@ <DropdownMenuStory>

<DropdownMenu.Trigger>{dropdownComponentProps().triggerContent}</DropdownMenu.Trigger>
<DropdownMenu.Item onClick={() => {}}>Edit</DropdownMenu.Item>
<DropdownMenu.Item onClick={() => {}}>Duplicate</DropdownMenu.Item>
<DropdownMenu.Item isDestructive isDisabled onClick={() => {}}>
<DropdownMenu.Item onClick={handleItemClick}>Edit</DropdownMenu.Item>
<DropdownMenu.Item onClick={handleItemClick}>Duplicate</DropdownMenu.Item>
<DropdownMenu.Item isDestructive isDisabled onClick={handleItemClick}>
Galvanize item
</DropdownMenu.Item>
<DropdownMenu.Item isDisabled onClick={() => {}}>
<DropdownMenu.Item isDisabled onClick={handleItemClick}>
Galvanize item
</DropdownMenu.Item>
<DropdownMenu.LinkItem link="http://www.wegalvanize.com">
<DropdownMenu.LinkItem isExternal link="http://www.wegalvanize.com">
{dropdownComponentProps().itemContent}

@@ -63,3 +68,3 @@ </DropdownMenu.LinkItem>

</DropdownMenu.LinkItem>
<DropdownMenu.Item isDisabled onClick={() => {}}>
<DropdownMenu.Item isDisabled onClick={handleItemClick}>
Galvanize

@@ -66,0 +71,0 @@ </DropdownMenu.Item>

@@ -9,3 +9,3 @@ describe("<DropdownMenu />", () => {

cy.getByTestId("popover.content").should("be.visible");
cy.wait(100).then(() => {
cy.wait(250).then(() => {
cy.getByTestId("dropdown-menu__trigger").click();

@@ -18,3 +18,3 @@ cy.getByTestId("popover.content").should("not.be.visible");

cy.getByTestId("dropdown-menu__trigger").click();
cy.wait(100).then(() => {
cy.wait(250).then(() => {
cy.getByTestId("dropdown-menu__trigger").click();

@@ -21,0 +21,0 @@ cy.getByTestId("dropdown-menu__trigger").then(triggerElement => {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc