UNPKG

8.75 kBJavaScriptView Raw
1import { __rest } from "tslib";
2import * as React from 'react';
3import styles from '@patternfly/react-styles/css/components/Menu/menu';
4import { css } from '@patternfly/react-styles';
5import { getOUIAProps, getDefaultOUIAId } from '../../helpers';
6import { MenuContext } from './MenuContext';
7import { canUseDOM } from '../../helpers/util';
8import { KeyboardHandler } from '../../helpers';
9class MenuBase extends React.Component {
10 constructor(props) {
11 super(props);
12 this.menuRef = React.createRef();
13 this.activeMenu = null;
14 this.state = {
15 ouiaStateId: getDefaultOUIAId(Menu.displayName),
16 searchInputValue: '',
17 transitionMoveTarget: null,
18 flyoutRef: null,
19 disableHover: false
20 };
21 this.handleDrilldownTransition = (event) => {
22 const current = this.menuRef.current;
23 if (!current ||
24 (current !== event.target.closest('.pf-c-menu') &&
25 !Array.from(current.getElementsByClassName('pf-c-menu')).includes(event.target.closest('.pf-c-menu')))) {
26 return;
27 }
28 if (this.state.transitionMoveTarget) {
29 this.state.transitionMoveTarget.focus();
30 this.setState({ transitionMoveTarget: null });
31 }
32 else {
33 const nextMenu = current.querySelector('#' + this.props.activeMenu) || current || null;
34 const nextTarget = Array.from(nextMenu.getElementsByTagName('UL')[0].children).filter(el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider')))[0].firstChild;
35 nextTarget.focus();
36 nextTarget.tabIndex = 0;
37 }
38 };
39 this.handleExtraKeys = (event) => {
40 const isDrilldown = this.props.containsDrilldown;
41 const activeElement = document.activeElement;
42 if (event.target.closest('.pf-c-menu') !== this.activeMenu &&
43 !event.target.classList.contains('pf-c-breadcrumb__link')) {
44 this.activeMenu = event.target.closest('.pf-c-menu');
45 this.setState({ disableHover: true });
46 }
47 if (event.target.tagName === 'INPUT') {
48 return;
49 }
50 const parentMenu = this.activeMenu;
51 const key = event.key;
52 const isFromBreadcrumb = activeElement.classList.contains('pf-c-breadcrumb__link') ||
53 activeElement.classList.contains('pf-c-dropdown__toggle');
54 if (key === ' ' || key === 'Enter') {
55 event.preventDefault();
56 if (isDrilldown && !isFromBreadcrumb) {
57 const isDrillingOut = activeElement.closest('li').classList.contains('pf-m-current-path');
58 if (isDrillingOut && parentMenu.parentElement.tagName === 'LI') {
59 activeElement.tabIndex = -1;
60 parentMenu.parentElement.firstChild.tabIndex = 0;
61 this.setState({ transitionMoveTarget: parentMenu.parentElement.firstChild });
62 }
63 else {
64 if (activeElement.nextElementSibling && activeElement.nextElementSibling.classList.contains('pf-c-menu')) {
65 const childItems = Array.from(activeElement.nextElementSibling.getElementsByTagName('UL')[0].children).filter(el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider')));
66 activeElement.tabIndex = -1;
67 childItems[0].firstChild.tabIndex = 0;
68 this.setState({ transitionMoveTarget: childItems[0].firstChild });
69 }
70 }
71 }
72 document.activeElement.click();
73 }
74 };
75 this.createNavigableElements = () => {
76 const isDrilldown = this.props.containsDrilldown;
77 return isDrilldown
78 ? Array.from(this.activeMenu.getElementsByTagName('UL')[0].children).filter(el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider')))
79 : Array.from(this.menuRef.current.getElementsByTagName('LI')).filter(el => !(el.classList.contains('pf-m-disabled') || el.classList.contains('pf-c-divider')));
80 };
81 if (props.innerRef) {
82 this.menuRef = props.innerRef;
83 }
84 }
85 allowTabFirstItem() {
86 // Allow tabbing to first menu item
87 const current = this.menuRef.current;
88 if (current) {
89 const first = current.querySelector('ul button, ul a');
90 if (first) {
91 first.tabIndex = 0;
92 }
93 }
94 }
95 componentDidMount() {
96 if (this.context) {
97 this.setState({ disableHover: this.context.disableHover });
98 }
99 if (canUseDOM) {
100 window.addEventListener('transitionend', this.props.isRootMenu ? this.handleDrilldownTransition : null);
101 }
102 this.allowTabFirstItem();
103 }
104 componentWillUnmount() {
105 if (canUseDOM) {
106 window.removeEventListener('transitionend', this.handleDrilldownTransition);
107 }
108 }
109 componentDidUpdate(prevProps) {
110 if (prevProps.children !== this.props.children) {
111 this.allowTabFirstItem();
112 }
113 }
114 render() {
115 const _a = this.props, { 'aria-label': ariaLabel, id, children, className, onSelect, selected = null, onActionClick, ouiaId, ouiaSafe, containsFlyout, isNavFlyout, containsDrilldown, isMenuDrilledIn, isPlain, isScrollable, drilldownItemPath, drilledInMenus, onDrillIn, onDrillOut, onGetMenuHeight, parentMenu = null, activeItemId = null,
116 /* eslint-disable @typescript-eslint/no-unused-vars */
117 innerRef, isRootMenu, activeMenu } = _a,
118 /* eslint-enable @typescript-eslint/no-unused-vars */
119 props = __rest(_a, ['aria-label', "id", "children", "className", "onSelect", "selected", "onActionClick", "ouiaId", "ouiaSafe", "containsFlyout", "isNavFlyout", "containsDrilldown", "isMenuDrilledIn", "isPlain", "isScrollable", "drilldownItemPath", "drilledInMenus", "onDrillIn", "onDrillOut", "onGetMenuHeight", "parentMenu", "activeItemId", "innerRef", "isRootMenu", "activeMenu"]);
120 const _isMenuDrilledIn = isMenuDrilledIn || (drilledInMenus && drilledInMenus.includes(id)) || false;
121 return (React.createElement(MenuContext.Provider, { value: {
122 menuId: id,
123 parentMenu: parentMenu || id,
124 onSelect,
125 onActionClick,
126 activeItemId,
127 selected,
128 drilledInMenus,
129 drilldownItemPath,
130 onDrillIn,
131 onDrillOut,
132 onGetMenuHeight,
133 flyoutRef: this.state.flyoutRef,
134 setFlyoutRef: flyoutRef => this.setState({ flyoutRef }),
135 disableHover: this.state.disableHover
136 } },
137 isRootMenu && (React.createElement(KeyboardHandler, { containerRef: this.menuRef || null, additionalKeyHandler: this.handleExtraKeys, createNavigableElements: this.createNavigableElements, isActiveElement: (element) => document.activeElement.parentElement === element ||
138 (document.activeElement.closest('ol') && document.activeElement.closest('ol').firstChild === element), getFocusableElement: (navigableElement) => navigableElement.firstChild, noHorizontalArrowHandling: document.activeElement &&
139 (document.activeElement.classList.contains('pf-c-breadcrumb__link') ||
140 document.activeElement.classList.contains('pf-c-dropdown__toggle')), noEnterHandling: true, noSpaceHandling: true })),
141 React.createElement("div", Object.assign({ id: id, className: css(styles.menu, isPlain && styles.modifiers.plain, isScrollable && styles.modifiers.scrollable, containsFlyout && styles.modifiers.flyout, isNavFlyout && styles.modifiers.nav, containsDrilldown && styles.modifiers.drilldown, _isMenuDrilledIn && styles.modifiers.drilledIn, className), "aria-label": ariaLabel, ref: this.menuRef }, getOUIAProps(Menu.displayName, ouiaId !== undefined ? ouiaId : this.state.ouiaStateId, ouiaSafe), props), children)));
142 }
143}
144MenuBase.displayName = 'Menu';
145MenuBase.contextType = MenuContext;
146MenuBase.defaultProps = {
147 ouiaSafe: true,
148 isRootMenu: true,
149 isPlain: false,
150 isScrollable: false
151};
152export const Menu = React.forwardRef((props, ref) => (React.createElement(MenuBase, Object.assign({}, props, { innerRef: ref }))));
153Menu.displayName = 'Menu';
154//# sourceMappingURL=Menu.js.map
\No newline at end of file