UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

133 lines (124 loc) 4.71 kB
'use strict'; var React = require('react'); var octiconsReact = require('@primer/octicons-react'); var Divider = require('./ActionList/Divider.js'); var ActionListContainerContext = require('./ActionList/ActionListContainerContext.js'); var index = require('./Button/index.js'); var useId = require('./hooks/useId.js'); var useProvidedStateOrCreate = require('./hooks/useProvidedStateOrCreate.js'); var useProvidedRefOrCreate = require('./hooks/useProvidedRefOrCreate.js'); var useMenuKeyboardNavigation = require('./hooks/useMenuKeyboardNavigation.js'); var AnchoredOverlay = require('./AnchoredOverlay/AnchoredOverlay.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const MenuContext = /*#__PURE__*/React__default.default.createContext({ renderAnchor: null, open: false }); const Menu = ({ anchorRef: externalAnchorRef, open, onOpenChange, children }) => { const [combinedOpenState, setCombinedOpenState] = useProvidedStateOrCreate.useProvidedStateOrCreate(open, onOpenChange, false); const onOpen = React__default.default.useCallback(() => setCombinedOpenState(true), [setCombinedOpenState]); const onClose = React__default.default.useCallback(() => setCombinedOpenState(false), [setCombinedOpenState]); const anchorRef = useProvidedRefOrCreate.useProvidedRefOrCreate(externalAnchorRef); const anchorId = useId.useId(); let renderAnchor = null; // 🚨 Hack for good API! // we strip out Anchor from children and pass it to AnchoredOverlay to render // with additional props for accessibility const contents = React__default.default.Children.map(children, child => { if (child.type === MenuButton || child.type === Anchor) { renderAnchor = anchorProps => /*#__PURE__*/React__default.default.cloneElement(child, anchorProps); return null; } return child; }); return /*#__PURE__*/React__default.default.createElement(MenuContext.Provider, { value: { anchorRef, renderAnchor, anchorId, open: combinedOpenState, onOpen, onClose } }, contents); }; Menu.displayName = "Menu"; const Anchor = /*#__PURE__*/React__default.default.forwardRef(({ children, ...anchorProps }, anchorRef) => { return /*#__PURE__*/React__default.default.cloneElement(children, { ...anchorProps, ref: anchorRef }); }); /** this component is syntactical sugar 🍭 */ const MenuButton = /*#__PURE__*/React__default.default.forwardRef(({ ...props }, anchorRef) => { return /*#__PURE__*/React__default.default.createElement(Anchor, { ref: anchorRef }, /*#__PURE__*/React__default.default.createElement(index.Button, _extends({ type: "button", trailingAction: octiconsReact.TriangleDownIcon }, props))); }); const Overlay = ({ children, align = 'start', 'aria-labelledby': ariaLabelledby, ...overlayProps }) => { // we typecast anchorRef as required instead of optional // because we know that we're setting it in context in Menu const { anchorRef, renderAnchor, anchorId, open, onOpen, onClose } = React__default.default.useContext(MenuContext); const containerRef = React__default.default.useRef(null); useMenuKeyboardNavigation.useMenuKeyboardNavigation(open, onClose, containerRef, anchorRef); return /*#__PURE__*/React__default.default.createElement(AnchoredOverlay.AnchoredOverlay, { anchorRef: anchorRef, renderAnchor: renderAnchor, anchorId: anchorId, open: open, onOpen: onOpen, onClose: onClose, align: align, overlayProps: overlayProps, focusZoneSettings: { focusOutBehavior: 'wrap' } }, /*#__PURE__*/React__default.default.createElement("div", { ref: containerRef }, /*#__PURE__*/React__default.default.createElement(ActionListContainerContext.ActionListContainerContext.Provider, { value: { container: 'ActionMenu', listRole: 'menu', listLabelledBy: ariaLabelledby || anchorId, selectionAttribute: 'aria-checked', // Should this be here? afterSelect: onClose } }, children))); }; Overlay.displayName = "Overlay"; Menu.displayName = 'ActionMenu'; const ActionMenu = Object.assign(Menu, { Button: MenuButton, Anchor, Overlay, Divider: Divider.Divider }); exports.ActionMenu = ActionMenu;