@nex-ui/react
Version:
🎉 A beautiful, modern, and reliable React component library.
279 lines (273 loc) • 9.14 kB
JavaScript
"use client";
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var m = require('motion/react-m');
var hooks = require('@nex-ui/hooks');
var icons = require('@nex-ui/icons');
var react$1 = require('motion/react');
var styled = require('@nex-ui/styled');
var utils = require('@nex-ui/utils');
var react = require('react');
var AccordionContext = require('./AccordionContext.cjs');
var useDefaultProps = require('../utils/useDefaultProps.cjs');
var useStyles = require('../utils/useStyles.cjs');
var useSlotProps = require('../utils/useSlotProps.cjs');
var Context = require('../provider/Context.cjs');
var composeClasses = require('../utils/composeClasses.cjs');
var accordion = require('../../theme/recipes/accordion.cjs');
var getUtilityClass = require('../utils/getUtilityClass.cjs');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var m__namespace = /*#__PURE__*/_interopNamespace(m);
const contentMotionVariants = {
expanded: {
opacity: 1,
height: 'auto',
transition: {
opacity: {
delay: 0.1
},
ease: 'easeInOut',
duration: 0.2
}
},
unexpanded: {
opacity: 0,
height: 0,
overflow: 'hidden',
transition: {
ease: 'easeInOut',
duration: 0.2
}
}
};
const indicatorMotionVariants = {
expanded: {
rotate: 180,
transition: {
duration: 0.2
}
},
unexpanded: {
rotate: 0,
transition: {
duration: 0.2
}
}
};
const useSlotClasses = (ownerState)=>{
const { prefix } = Context.useNexUI();
const accordionItemRoot = `${prefix}-accordion-item`;
const { hideIndicator, keepMounted, disabled, classes } = ownerState;
const slots = {
root: [
'root',
hideIndicator && 'hide-indicator',
keepMounted && 'keep-mounted',
disabled && 'disabled'
],
heading: [
'heading'
],
trigger: [
'trigger'
],
content: [
'content'
],
indicator: [
'indicator'
]
};
const composedClasses = composeClasses.composeClasses(slots, getUtilityClass.getUtilityClass(accordionItemRoot), classes);
return composedClasses;
};
const useSlotAriaProps = (ownerState)=>{
const { itemKey, disabled, expanded, slotProps } = ownerState;
const triggerProps = slotProps?.trigger || {};
const triggerId = react.useId();
const contentId = `panel-${itemKey}-content`;
let trigger = {
type: 'button',
disabled,
id: triggerId,
tabIndex: disabled ? -1 : 0,
'aria-expanded': expanded,
'aria-controls': contentId,
'aria-disabled': disabled || undefined
};
if (triggerProps.as && triggerProps.as !== 'button') {
trigger = {
...trigger,
role: 'button'
};
}
const content = {
role: 'region',
'aria-labelledby': triggerId,
id: contentId
};
return {
trigger,
content
};
};
const AccordionItem = (inProps)=>{
const defaultKey = react.useId();
const firstRender = react.useRef(true);
const triggerRef = react.useRef(null);
const props = useDefaultProps.useDefaultProps({
name: 'AccordionItem',
props: inProps
});
const { variant, toggleExpandedKey, expandedKeys, disabledKeys, disabled: defaultDisabled, indicator: defaultIndicator, motionProps: defaultMotionProps, keepMounted: defaultKeepMounted, hideIndicator: defaultHideIndicator, indicatorMotionProps: defaultIndicatorMotionProps } = AccordionContext.useAccordionGroup();
const { ref, children, title, slotProps, as = 'div', indicatorMotionProps = defaultIndicatorMotionProps, motionProps = defaultMotionProps, hideIndicator = defaultHideIndicator, keepMounted = defaultKeepMounted, indicator = defaultIndicator, itemKey = defaultKey, disabled = disabledKeys.includes(itemKey) || defaultDisabled, ...remainingProps } = props;
const expanded = expandedKeys.includes(itemKey);
const [focusVisible] = hooks.useFocusVisible({
ref: triggerRef
});
const ownerState = {
...props,
variant,
itemKey,
expanded,
indicator,
keepMounted,
hideIndicator,
disabled,
motionProps
};
const styles = useStyles.useStyles({
name: 'AccordionItem',
ownerState,
recipe: accordion.accordionItemRecipe
});
const onClick = hooks.useEvent(()=>{
toggleExpandedKey(itemKey);
});
const onKeyUp = hooks.useEvent((event)=>{
// Keyboard accessibility for non interactive elements
if (focusVisible && slotProps?.trigger?.as && slotProps?.trigger?.as !== 'button' && (event.code === 'Space' || event.code === 'Enter')) {
event.currentTarget.click();
}
});
const classes = useSlotClasses(ownerState);
const slotAriaProps = useSlotAriaProps(ownerState);
const animate = expanded ? 'expanded' : 'unexpanded';
const contentMotionProps = keepMounted ? {
animate,
initial: firstRender.current && animate,
variants: contentMotionVariants
} : {
variants: contentMotionVariants,
initial: firstRender.current && animate,
animate: 'expanded',
exit: 'unexpanded'
};
const rootProps = useSlotProps.useSlotProps({
ownerState,
externalForwardedProps: remainingProps,
sx: styles.root,
classNames: classes.root,
additionalProps: {
ref,
as
}
});
const headingProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: slotProps?.heading,
sx: styles.heading,
classNames: classes.heading
});
const triggerProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: {
...slotProps?.trigger,
ref: utils.mergeRefs(triggerRef, slotProps?.trigger?.ref)
},
sx: styles.trigger,
classNames: classes.trigger,
additionalProps: {
onClick,
onKeyUp,
...slotAriaProps.trigger
}
});
const contentProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: slotProps?.content,
sx: styles.content,
classNames: classes.content,
additionalProps: slotAriaProps.content
});
const indicatorProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: slotProps?.indicator,
sx: styles.indicator,
classNames: classes.indicator,
additionalProps: {
size: 'sm',
as: m__namespace.span,
animate,
variants: indicatorMotionVariants,
...indicatorMotionProps
}
});
react.useEffect(()=>{
if (firstRender.current) {
firstRender.current = false;
}
}, []);
return /*#__PURE__*/ jsxRuntime.jsx(react$1.LazyMotion, {
features: react$1.domAnimation,
children: /*#__PURE__*/ jsxRuntime.jsxs(styled.nex.div, {
...rootProps,
children: [
/*#__PURE__*/ jsxRuntime.jsx(styled.nex.h3, {
...headingProps,
children: /*#__PURE__*/ jsxRuntime.jsxs(styled.nex.button, {
...triggerProps,
children: [
/*#__PURE__*/ jsxRuntime.jsx("span", {
children: title
}),
!hideIndicator && /*#__PURE__*/ jsxRuntime.jsx(styled.nex.span, {
...indicatorProps,
children: indicator ?? /*#__PURE__*/ jsxRuntime.jsx(icons.ChevronDownOutlined, {})
})
]
})
}),
/*#__PURE__*/ jsxRuntime.jsx(react$1.AnimatePresence, {
children: (keepMounted || expanded) && // @ts-ignore
/*#__PURE__*/ jsxRuntime.jsx(m__namespace.div, {
...contentMotionProps,
...motionProps,
children: /*#__PURE__*/ jsxRuntime.jsx(styled.nex.div, {
...contentProps,
children: children
})
})
})
]
})
});
};
AccordionItem.displayName = 'AccordionItem';
exports.AccordionItem = AccordionItem;