@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
327 lines (326 loc) • 14.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.AccordionContext = void 0;
var _react = require("motion/react");
var _react2 = _interopRequireWildcard(require("react"));
var _uuid = require("../../hooks/uuid");
var _useKeyboardFocusHighlighting = require("../../hooks/useKeyboardFocusHighlighting");
var _AreaContextProvider = require("../area-provider/AreaContextProvider");
var _ColorSchemeProvider = require("../color-scheme-provider/ColorSchemeProvider");
var _AccordionBody = _interopRequireDefault(require("./accordion-body/AccordionBody"));
var _AccordionGroup = require("./accordion-group/AccordionGroup");
var _AccordionHead = _interopRequireDefault(require("./accordion-head/AccordionHead"));
var _AccordionContextProvider = require("./accordion-provider/AccordionContextProvider");
var _Accordion = require("./Accordion.styles");
var _ref = require("../../hooks/ref");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const AccordionContext = exports.AccordionContext = /*#__PURE__*/_react2.default.createContext({
isWrapped: undefined
});
const Accordion = ({
bodyMaxHeight,
children,
icon,
isDefaultOpen = false,
isDisabled = false,
isFixed = false,
isOpened,
isTitleGreyed = false,
onBodyScroll,
onClose,
onHoverEnd,
onHoverStart,
onOpen,
onSearchChange,
rightElement,
searchPlaceholder,
searchValue,
shouldForceBackground = false,
shouldForceBottomLine = false,
shouldHideBackground = false,
shouldRenderClosed = false,
shouldRotateIcon = true,
shouldHideBottomLine = false,
title,
titleElement,
onTitleInputChange,
titleInputProps,
shouldSkipAnimation: shouldSkipAnimationProp = false,
colors,
shouldIndex = false,
onBodyAnimationComplete,
shouldEnableKeyboardHighlighting
}) => {
const {
isWrapped: groupIsWrapped,
openAccordionUuid,
accordionGroupUuid,
accordionUuids,
updateOpenAccordionUuid,
activeAccordionUuid,
updateActiveAccordionUuid,
registerAccordionUuid,
unregisterAccordionUuid
} = (0, _react2.useContext)(_AccordionGroup.AccordionGroupContext);
const {
isWrapped: isParentWrapped
} = (0, _react2.useContext)(AccordionContext);
const {
isWrapped: contextIsWrapped
} = (0, _react2.useContext)(_AccordionContextProvider.AccordionWrappedContext);
const colorScheme = (0, _ColorSchemeProvider.useColorScheme)();
const shouldEnableKeyboardHighlightingEffective = shouldEnableKeyboardHighlighting ?? (colorScheme === null || colorScheme === void 0 ? void 0 : colorScheme.shouldEnableKeyboardHighlighting) ?? false;
const isWrapped = (0, _react2.useMemo)(() => groupIsWrapped ?? contextIsWrapped, [contextIsWrapped, groupIsWrapped]);
const [isAccordionOpen, setIsAccordionOpen] = (0, _react2.useState)(isDefaultOpen ?? isOpened);
const [isGroupFocusWithin, setIsGroupFocusWithin] = (0, _react2.useState)(false);
const uuid = (0, _uuid.useUuid)();
const isInitialRenderRef = (0, _react2.useRef)(true);
const initialRenderSkipRef = (0, _ref.useInitialRenderRef)(true);
const shouldSkipAnimation = shouldSkipAnimationProp ?? (initialRenderSkipRef.current && isDefaultOpen);
const isInGroup = shouldSkipAnimation ? false : typeof updateOpenAccordionUuid === 'function';
const isOpen = isInGroup ? openAccordionUuid === uuid : isAccordionOpen;
const isOpenRef = (0, _react2.useRef)(isOpen);
const onCloseRef = (0, _react2.useRef)(onClose);
const onOpenRef = (0, _react2.useRef)(onOpen);
const shouldShowKeyboardHighlighting = (0, _useKeyboardFocusHighlighting.useKeyboardFocusHighlighting)(shouldEnableKeyboardHighlightingEffective);
const isKeyboardFocusable = !isDisabled && (shouldIndex || shouldEnableKeyboardHighlightingEffective);
const isInKeyboardNavigationGroup = isKeyboardFocusable && typeof updateActiveAccordionUuid === 'function' && typeof accordionGroupUuid === 'string';
(0, _react2.useEffect)(() => {
if (typeof accordionGroupUuid === 'string' && typeof registerAccordionUuid === 'function' && typeof unregisterAccordionUuid === 'function') {
registerAccordionUuid(uuid);
return () => {
unregisterAccordionUuid(uuid);
};
}
return undefined;
}, [accordionGroupUuid, registerAccordionUuid, unregisterAccordionUuid, uuid]);
const isLastAccordion = (0, _react2.useMemo)(() => accordionUuids ? accordionUuids[accordionUuids.length - 1] === uuid : false, [accordionUuids, uuid]);
(0, _react2.useEffect)(() => {
isOpenRef.current = isOpen;
onCloseRef.current = onClose;
onOpenRef.current = onOpen;
}, [isOpen, onClose, onOpen]);
const handleHeadClick = (0, _react2.useCallback)(() => {
if (isDisabled) {
return;
}
if (isKeyboardFocusable && typeof updateActiveAccordionUuid === 'function') {
updateActiveAccordionUuid(uuid);
}
if (typeof updateOpenAccordionUuid === 'function') {
updateOpenAccordionUuid(uuid);
}
setIsAccordionOpen(currentIsAccordionOpen => !currentIsAccordionOpen);
}, [isDisabled, isKeyboardFocusable, updateActiveAccordionUuid, updateOpenAccordionUuid, uuid]);
(0, _react2.useEffect)(() => {
if (isDisabled && isOpen) {
if (typeof updateOpenAccordionUuid === 'function') {
updateOpenAccordionUuid(uuid);
}
setIsAccordionOpen(currentIsAccordionOpen => !currentIsAccordionOpen);
}
}, [isDisabled, isOpen, updateOpenAccordionUuid, uuid]);
(0, _react2.useEffect)(() => {
if (isInitialRenderRef.current) {
isInitialRenderRef.current = false;
} else if (isOpen) {
if (typeof onOpenRef.current === 'function') {
onOpenRef.current();
}
} else if (typeof onCloseRef.current === 'function') {
onCloseRef.current();
}
}, [isOpen]);
(0, _react2.useEffect)(() => {
if (isDefaultOpen) {
if (typeof updateOpenAccordionUuid === 'function') {
updateOpenAccordionUuid(uuid, {
shouldOnlyOpen: true
});
} else {
setIsAccordionOpen(true);
}
}
}, [isDefaultOpen, updateOpenAccordionUuid, uuid]);
(0, _react2.useEffect)(() => {
if (typeof isOpened === 'boolean') {
if (typeof updateOpenAccordionUuid === 'function' && isOpened !== isOpenRef.current) {
updateOpenAccordionUuid(uuid);
} else {
setIsAccordionOpen(isOpened);
}
}
}, [isOpened, updateOpenAccordionUuid, uuid]);
const accordionContextProviderValue = (0, _react2.useMemo)(() => ({
isWrapped: isWrapped === true
}), [isWrapped]);
const areaContextProviderValue = (0, _react2.useMemo)(() => ({
shouldChangeColor: !shouldHideBackground
}), [shouldHideBackground]);
const accordionWrappedContextProviderValue = (0, _react2.useMemo)(() => ({
isWrapped: true
}), []);
const initialAnimation = (0, _react2.useMemo)(() => {
if (shouldSkipAnimation) {
return {
height: 'auto',
opacity: 1
};
}
return isOpen ? {
height: 'auto',
opacity: 1
} : {
height: 0,
opacity: 0
};
}, [isOpen, shouldSkipAnimation]);
const tabIndex = (0, _react2.useMemo)(() => isKeyboardFocusable ? 0 : -1, [isKeyboardFocusable]);
const handleKeyDown = (0, _react2.useCallback)(e => {
const isCurrentAccordionTarget = e.currentTarget === e.target;
if (isCurrentAccordionTarget && isInKeyboardNavigationGroup && accordionUuids !== null && accordionUuids !== void 0 && accordionUuids.length && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
const currentIndex = accordionUuids.indexOf(uuid);
if (currentIndex !== -1) {
const nextIndex = e.key === 'ArrowDown' ? (currentIndex + 1) % accordionUuids.length : (currentIndex - 1 + accordionUuids.length) % accordionUuids.length;
const nextAccordionUuid = accordionUuids[nextIndex];
if (nextAccordionUuid && nextAccordionUuid !== uuid) {
const nextAccordionElement = document.querySelector(`[data-uuid="${accordionGroupUuid}---${nextAccordionUuid}"]`);
if (nextAccordionElement) {
updateActiveAccordionUuid(nextAccordionUuid);
nextAccordionElement.focus();
return;
}
}
}
}
if (isCurrentAccordionTarget && (e.key === 'Enter' || e.key === ' ') && isKeyboardFocusable) {
handleHeadClick();
}
if (isCurrentAccordionTarget && e.key === 'ArrowRight' && isKeyboardFocusable && !isOpen) {
e.preventDefault();
handleHeadClick();
}
if (isCurrentAccordionTarget && (e.key === 'Escape' || e.key === 'ArrowLeft')) {
if (isOpen && isKeyboardFocusable) {
e.preventDefault();
handleHeadClick();
return;
}
if (isInKeyboardNavigationGroup && typeof updateActiveAccordionUuid === 'function') {
var _e$currentTarget$pare;
e.preventDefault();
updateActiveAccordionUuid(undefined);
let parentAccordion = (_e$currentTarget$pare = e.currentTarget.parentElement) === null || _e$currentTarget$pare === void 0 ? void 0 : _e$currentTarget$pare.closest('.beta-chayns-accordion');
while (parentAccordion) {
var _parentAccordion$getA, _parentAccordion$pare;
const parentGroupId = (_parentAccordion$getA = parentAccordion.getAttribute('data-uuid')) === null || _parentAccordion$getA === void 0 ? void 0 : _parentAccordion$getA.split('---')[0];
if (parentGroupId !== accordionGroupUuid) {
parentAccordion.focus();
break;
}
parentAccordion = (_parentAccordion$pare = parentAccordion.parentElement) === null || _parentAccordion$pare === void 0 ? void 0 : _parentAccordion$pare.closest('.beta-chayns-accordion');
}
}
}
}, [accordionGroupUuid, accordionUuids, handleHeadClick, isInKeyboardNavigationGroup, isKeyboardFocusable, isOpen, updateActiveAccordionUuid, uuid]);
const handleFocus = (0, _react2.useCallback)(e => {
if (e.currentTarget === e.target && isInKeyboardNavigationGroup && typeof updateActiveAccordionUuid === 'function') {
setIsGroupFocusWithin(true);
updateActiveAccordionUuid(uuid);
}
}, [isInKeyboardNavigationGroup, updateActiveAccordionUuid, uuid]);
const handleBlur = (0, _react2.useCallback)(e => {
if (isInKeyboardNavigationGroup && typeof updateActiveAccordionUuid === 'function' && typeof accordionGroupUuid === 'string') {
const nextFocusedElement = e.relatedTarget;
const currentGroupElement = e.currentTarget;
if (!nextFocusedElement || !currentGroupElement.contains(nextFocusedElement)) {
setIsGroupFocusWithin(false);
updateActiveAccordionUuid(undefined);
}
}
}, [accordionGroupUuid, isInKeyboardNavigationGroup, updateActiveAccordionUuid]);
(0, _react2.useEffect)(() => {
if (!isInKeyboardNavigationGroup) {
setIsGroupFocusWithin(false);
} else if (activeAccordionUuid == null && typeof updateActiveAccordionUuid === 'function' && (accordionUuids === null || accordionUuids === void 0 ? void 0 : accordionUuids[0]) === uuid) {
updateActiveAccordionUuid(uuid);
}
}, [accordionUuids, activeAccordionUuid, isInKeyboardNavigationGroup, updateActiveAccordionUuid, uuid]);
return /*#__PURE__*/_react2.default.createElement(_Accordion.StyledMotionAccordion, {
animate: {
height: 'auto',
opacity: 1
},
"data-uuid": `${accordionGroupUuid ?? ''}---${uuid}`,
className: "beta-chayns-accordion",
exit: {
height: 0,
opacity: 0
},
initial: initialAnimation,
$isOpen: isOpen,
tabIndex: tabIndex,
$shouldShowLines: !isLastAccordion || !isWrapped,
$isParentWrapped: isParentWrapped,
$isWrapped: isWrapped,
$shouldForceBackground: shouldForceBackground,
$shouldForceBottomLine: shouldForceBottomLine,
$shouldHideBackground: shouldHideBackground,
$shouldHideBottomLine: shouldHideBottomLine,
$bottomBorderColor: colors === null || colors === void 0 ? void 0 : colors.borderBottomColor,
$shouldEnableKeyboardHighlighting: shouldEnableKeyboardHighlightingEffective,
$shouldShowKeyboardHighlighting: shouldShowKeyboardHighlighting,
onKeyDown: handleKeyDown,
onFocus: handleFocus,
onBlur: handleBlur,
onMouseEnter: onHoverStart,
onMouseLeave: onHoverEnd,
transition: {
duration: shouldSkipAnimation ? 0 : 0.25
}
}, /*#__PURE__*/_react2.default.createElement(AccordionContext.Provider, {
value: accordionContextProviderValue
}, /*#__PURE__*/_react2.default.createElement(_react.MotionConfig, {
transition: {
type: 'tween'
}
}, /*#__PURE__*/_react2.default.createElement(_AccordionHead.default, {
uuid: uuid,
icon: icon,
isOpen: isOpen,
shouldSkipAnimation: shouldSkipAnimation,
isFixed: isFixed,
isTitleGreyed: isTitleGreyed || isDisabled,
isWrapped: isWrapped === true,
onClick: handleHeadClick,
onSearchChange: onSearchChange,
rightElement: rightElement,
searchPlaceholder: searchPlaceholder,
searchValue: searchValue,
shouldRotateIcon: shouldRotateIcon,
title: title,
titleElement: titleElement,
onTitleInputChange: onTitleInputChange,
titleInputProps: titleInputProps,
titleColor: colors === null || colors === void 0 ? void 0 : colors.titleColor,
shouldEnableKeyboardHighlighting: shouldEnableKeyboardHighlightingEffective
}), /*#__PURE__*/_react2.default.createElement(_react.AnimatePresence, {
initial: false
}, (isOpen || shouldRenderClosed) && /*#__PURE__*/_react2.default.createElement(_AccordionBody.default, {
shouldSkipAnimation: shouldSkipAnimation,
maxHeight: bodyMaxHeight,
onScroll: onBodyScroll,
onAnimationComplete: onBodyAnimationComplete,
shouldHideBody: shouldRenderClosed && !isOpen
}, /*#__PURE__*/_react2.default.createElement(_AccordionContextProvider.AccordionWrappedContext.Provider, {
value: accordionWrappedContextProviderValue
}, /*#__PURE__*/_react2.default.createElement(_AreaContextProvider.AreaContext.Provider, {
value: areaContextProviderValue
}, children)))))));
};
Accordion.displayName = 'Accordion';
var _default = exports.default = Accordion;
//# sourceMappingURL=Accordion.js.map