suomifi-ui-components
Version:
Suomi.fi UI component library
305 lines (302 loc) • 10.1 kB
JavaScript
import { __rest, __assign, __makeTemplateObject, __spreadArray } from 'tslib';
import React, { useState, useRef, useEffect } from 'react';
import { styled } from 'styled-components';
import { usePopper } from 'react-popper';
import classnames from 'classnames';
import { useEnhancedEffect } from '../../../utils/common/common.js';
import { SuomifiThemeConsumer } from '../../theme/SuomifiThemeProvider/SuomifiThemeProvider.js';
import '../../theme/SuomifiTheme/SuomifiTheme.js';
import '../../theme/SpacingProvider/SpacingProvider.js';
import '../../../reset/HtmlA/HtmlA.js';
import '../../../reset/HtmlButton/HtmlButton.js';
import { HtmlDivWithRef } from '../../../reset/HtmlDiv/HtmlDiv.js';
import '../../../reset/HtmlFieldSet/HtmlFieldSet.js';
import '../../../reset/HtmlH/HtmlH.js';
import '../../../reset/HtmlInput/HtmlInput.js';
import '../../../reset/HtmlLabel/HtmlLabel.js';
import '../../../reset/HtmlLegend/HtmlLegend.js';
import '../../../reset/HtmlLi/HtmlLi.js';
import '../../../reset/HtmlNav/HtmlNav.js';
import '../../../reset/HtmlOl/HtmlOl.js';
import '../../../reset/HtmlSpan/HtmlSpan.js';
import '../../../reset/HtmlTextarea/HtmlTextarea.js';
import '../../../reset/HtmlUl/HtmlUl.js';
import '../../../reset/HtmlTable/HtmlTable.js';
import '../../../reset/HtmlTable/HtmlTableCaption.js';
import '../../../reset/HtmlTable/HtmlTableHeader.js';
import '../../../reset/HtmlTable/HtmlTableRow.js';
import '../../../reset/HtmlTable/HtmlTableBody.js';
import '../../../reset/HtmlTable/HtmlTableHeaderCell.js';
import '../../../reset/HtmlTable/HtmlTableCell.js';
import { getLogger } from '../../../utils/log/logger.js';
import { baseStyles } from './ActionMenuPopover.baseStyles.js';
var baseClassName = 'fi-action-menu-popover';
var actionMenuClassNames = {
baseClassName: baseClassName,
hidden: "".concat(baseClassName, "--hidden"),
list: "".concat(baseClassName, "_list"),
popperArrow: "".concat(baseClassName, "_popper-arrow")
};
var defaultProviderValue = {
onItemClick: function onItemClick() {
return null;
},
onItemMouseOver: function onItemMouseOver() {
return null;
},
activeDescendantIndex: -1,
parentId: ''
};
var _a = /*#__PURE__*/React.createContext(defaultProviderValue),
ActionMenuProvider = _a.Provider,
ActionMenuConsumer = _a.Consumer;
var sameWidth = {
name: 'sameWidth',
enabled: true,
phase: 'beforeWrite',
requires: ['computeStyles'],
fn: function fn(_a) {
var state = _a.state;
state.styles.popper.width = "".concat(state.rects.reference.width, "px");
},
effect: function effect(_a) {
var state = _a.state;
state.elements.popper.style.width = "".concat(state.elements.reference.offsetWidth, "px");
}
};
var BaseActionMenuPopover = function BaseActionMenuPopover(props) {
var _a;
var _b;
var openButtonRef = props.openButtonRef,
onClose = props.onClose,
className = props.className,
children = props.children,
menuId = props.menuId,
buttonId = props.buttonId,
initialActiveDescendant = props.initialActiveDescendant,
fullWidth = props.fullWidth,
isOpen = props.isOpen;
var _c = useState(null),
mountNode = _c[0],
setMountNode = _c[1];
var _d = useState(null),
dialogElement = _d[0],
setDialogElement = _d[1];
var _e = useState(-1),
activeChild = _e[0],
setActiveChild = _e[1];
var divRef = useRef(null);
useEnhancedEffect(function () {
setMountNode(window.document.body);
}, []);
useEffect(function () {
if (isOpen) {
document.addEventListener('keydown', globalKeyDownHandler, {
capture: true
});
return function () {
document.removeEventListener('keydown', globalKeyDownHandler, {
capture: true
});
};
}
}, [isOpen]);
useEffect(function () {
if (isOpen) {
document.addEventListener('click', globalClickHandler, {
capture: true
});
return function () {
document.removeEventListener('click', globalClickHandler, {
capture: true
});
};
}
}, [isOpen]);
useEffect(function () {
var isSubscribed = true;
setTimeout(function () {
if (isSubscribed) {
if (initialActiveDescendant === 'first') {
setActiveChild(0);
} else if (initialActiveDescendant === 'last') {
setActiveChild(React.Children.count(children) - 1);
}
}
}, 0);
return function () {
setActiveChild(-1);
isSubscribed = false;
};
}, [isOpen]);
var globalClickHandler = function globalClickHandler(nativeEvent) {
var _a, _b;
if (!((_a = divRef.current) === null || _a === void 0 ? void 0 : _a.contains(nativeEvent.target)) && !((_b = openButtonRef.current) === null || _b === void 0 ? void 0 : _b.contains(nativeEvent.target))) {
handleClose(false);
}
};
var isActivable = function isActivable(child) {
var _a;
return ((_a = child === null || child === void 0 ? void 0 : child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'ActionMenuItem';
};
var nextActivable = function nextActivable(current) {
var nextActivableIndex = -1;
var firstActivableIndex = -1;
var startFrom = 0;
if (current) {
startFrom = current;
}
React.Children.forEach(children, function (child, index) {
if (isActivable(child) && firstActivableIndex === -1) {
firstActivableIndex = index;
}
if (index > startFrom && isActivable(child) && nextActivableIndex === -1) {
nextActivableIndex = index;
}
});
if (nextActivableIndex !== -1) {
return nextActivableIndex;
}
return firstActivableIndex;
};
var previousActivable = function previousActivable(current) {
var result = -1;
var lastActivable = -1;
React.Children.forEach(children, function (child, index) {
if (isActivable(child)) {
lastActivable = index;
}
if (index < current && isActivable(child)) {
result = index;
}
});
if (result !== -1) {
return result;
}
return lastActivable;
};
var globalKeyDownHandler = function globalKeyDownHandler(event) {
if (event.key === 'Escape') {
handleClose(true);
event.preventDefault();
}
if (event.key === 'Tab') {
handleClose(true);
}
if (event.key === 'ArrowDown') {
event.preventDefault();
setActiveChild(function (previous) {
return nextActivable(previous);
});
}
if (event.key === 'ArrowUp') {
event.preventDefault();
setActiveChild(function (previous) {
return previousActivable(previous);
});
}
};
var defaultModifiers = [{
name: 'eventListeners',
enabled: isOpen
}, {
name: 'offset',
options: {
offset: [0, 10]
}
}, {
name: 'flip',
options: {
fallbackPlacements: ['top-end']
}
}, {
name: 'preventOverflow',
options: {
padding: 5
}
}];
var _f = usePopper(openButtonRef.current, dialogElement, {
strategy: 'fixed',
modifiers: fullWidth ? __spreadArray(__spreadArray([], defaultModifiers, true), [sameWidth], false) : defaultModifiers,
placement: 'bottom-end'
}),
styles = _f.styles,
attributes = _f.attributes;
var handleClose = function handleClose(moveFocus) {
onClose(moveFocus);
};
if (React.Children.count(children) < 1) {
getLogger().warn("Action Menu does not contain items");
return null;
}
var menuItems = function menuItems(childs) {
return React.Children.map(childs, function (child, index) {
if ( /*#__PURE__*/React.isValidElement(child) && isActivable(child)) {
return /*#__PURE__*/React.cloneElement(child, {
itemIndex: index
});
}
return child;
});
};
var itemMouseOver = function itemMouseOver(value) {
setActiveChild(value);
};
if (!mountNode) {
return null;
}
return /*#__PURE__*/React.createElement(HtmlDivWithRef, {
className: classnames(className, baseClassName, (_a = {}, _a[actionMenuClassNames.hidden] = !isOpen, _a)),
style: styles.popper,
forwardedRef: setDialogElement,
tabIndex: -1,
role: "none"
}, /*#__PURE__*/React.createElement(ActionMenuProvider, {
value: {
onItemClick: function onItemClick() {
return handleClose(true);
},
onItemMouseOver: function onItemMouseOver(itemIndex) {
itemMouseOver(itemIndex);
},
activeDescendantIndex: activeChild,
parentId: menuId
}
}, /*#__PURE__*/React.createElement(HtmlDivWithRef, {
role: "menu",
forwardedRef: divRef,
id: menuId,
"aria-labelledby": buttonId,
tabIndex: -1,
className: actionMenuClassNames.list
}, menuItems(children))), /*#__PURE__*/React.createElement("div", {
className: actionMenuClassNames.popperArrow,
style: styles.arrow,
"aria-hidden": true,
tabIndex: -1,
"data-popper-arrow": true,
"data-popper-placement": (_b = attributes.popper) === null || _b === void 0 ? void 0 : _b['data-popper-placement']
}));
};
var StyledActionMenuPopover = styled(function (_a) {
_a.theme;
var passProps = __rest(_a, ["theme"]);
return /*#__PURE__*/React.createElement(BaseActionMenuPopover, __assign({}, passProps));
}).withConfig({
componentId: "sc-1cahlko-0"
})(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (_a) {
var theme = _a.theme;
return baseStyles(theme);
});
var ActionMenuPopover = function ActionMenuPopover(props) {
return /*#__PURE__*/React.createElement(SuomifiThemeConsumer, null, function (_a) {
var suomifiTheme = _a.suomifiTheme;
return /*#__PURE__*/React.createElement(StyledActionMenuPopover, __assign({
theme: suomifiTheme
}, props));
});
};
ActionMenuPopover.displayName = 'ActionMenuPopover';
var templateObject_1;
export { ActionMenuConsumer, ActionMenuPopover, ActionMenuProvider, BaseActionMenuPopover, actionMenuClassNames };
//# sourceMappingURL=ActionMenuPopover.js.map