@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
150 lines (149 loc) • 4.87 kB
JavaScript
"use client";
var _span;
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import clsx from 'clsx';
import IconPrimary from "../IconPrimary.js";
import HeightAnimation from "../height-animation/HeightAnimation.js";
import { MenuContext, useMenuContext } from "./MenuContext.js";
import MenuItemContent from "./MenuItemContent.js";
import useMenuItemRegistration from "./useMenuItemRegistration.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
export default function MenuAccordion(props) {
const {
id,
className,
children,
icon,
text,
disabled = false,
onOpenChange,
...rest
} = props;
const parentContext = useMenuContext();
const level = parentContext ? parentContext.level + 1 : 1;
const [isOpen, setIsOpenState] = useState(false);
const setIsOpen = useCallback(next => {
setIsOpenState(prev => {
const value = typeof next === 'function' ? next(prev) : next;
if (value !== prev) {
onOpenChange === null || onOpenChange === void 0 || onOpenChange(value);
}
return value;
});
}, [onOpenChange]);
const parentIsOpen = parentContext === null || parentContext === void 0 ? void 0 : parentContext.isOpen;
useEffect(() => {
if (!parentIsOpen) {
setIsOpen(false);
}
}, [parentIsOpen, setIsOpen]);
const triggerRef = useRef(null);
const {
isActive
} = useMenuItemRegistration(triggerRef);
const contentRef = useRef(null);
const closeAll = useCallback(() => {
setIsOpen(false);
parentContext === null || parentContext === void 0 || parentContext.closeAll();
}, [parentContext, setIsOpen]);
const closeSelf = useCallback(() => {
var _triggerRef$current;
setIsOpen(false);
(_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
preventScroll: true
});
}, [setIsOpen]);
const childContextValue = useMemo(() => {
if (!parentContext) {
return null;
}
return {
...parentContext,
level,
closeAll,
closeSelf
};
}, [parentContext, level, closeAll, closeSelf]);
const handleClick = useCallback(() => {
if (disabled) {
return;
}
setIsOpen(prev => !prev);
}, [disabled, setIsOpen]);
const focusFirstChild = useCallback(() => {
var _contentRef$current;
const firstChild = (_contentRef$current = contentRef.current) === null || _contentRef$current === void 0 ? void 0 : _contentRef$current.querySelector('[role="menuitem"]:not([aria-disabled="true"])');
if (firstChild && parentContext) {
firstChild.focus({
preventScroll: true
});
const refIndex = parentContext.itemRefs.current.findIndex(r => (r === null || r === void 0 ? void 0 : r.current) === firstChild);
if (refIndex !== -1) {
parentContext.setActiveIndex(refIndex);
}
}
}, [parentContext]);
const handleKeyDown = useCallback(event => {
if (disabled) {
return;
}
if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowRight') {
event.preventDefault();
event.stopPropagation();
if (!isOpen) {
setIsOpen(true);
requestAnimationFrame(() => {
focusFirstChild();
});
} else if (event.key === 'ArrowRight') {
focusFirstChild();
} else {
setIsOpen(false);
}
}
if (event.key === 'ArrowLeft') {
event.preventDefault();
event.stopPropagation();
setIsOpen(false);
}
}, [disabled, isOpen, setIsOpen, focusFirstChild]);
return _jsxs("li", {
role: "none",
className: clsx('dnb-menu__accordion', className, isOpen && 'dnb-menu__accordion--open', disabled && 'dnb-menu__accordion--disabled'),
children: [_jsxs("div", {
id: id,
ref: triggerRef,
role: "menuitem",
"aria-expanded": isOpen,
"aria-haspopup": "menu",
"aria-disabled": disabled || undefined,
tabIndex: isActive ? 0 : -1,
className: "dnb-menu__action dnb-menu__accordion__trigger",
onClick: handleClick,
onKeyDown: handleKeyDown,
...rest,
children: [_jsx(MenuItemContent, {
icon: icon,
text: text
}), _span || (_span = _jsx("span", {
className: "dnb-menu__accordion__indicator",
children: _jsx(IconPrimary, {
icon: "chevron_right"
})
}))]
}), _jsx(HeightAnimation, {
open: isOpen,
children: childContextValue && _jsx(MenuContext, {
value: childContextValue,
children: _jsx("ul", {
ref: contentRef,
role: "group",
"aria-label": typeof text === 'string' ? text : undefined,
className: "dnb-menu__list",
children: children
})
})
})]
});
}
//# sourceMappingURL=MenuAccordion.js.map