@base-ui-components/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
170 lines (167 loc) • 5.32 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AccordionTrigger = void 0;
var React = _interopRequireWildcard(require("react"));
var _isElementDisabled = require("@base-ui-components/utils/isElementDisabled");
var _useIsoLayoutEffect = require("@base-ui-components/utils/useIsoLayoutEffect");
var _collapsibleOpenStateMapping = require("../../utils/collapsibleOpenStateMapping");
var _useButton = require("../../use-button");
var _CollapsibleRootContext = require("../../collapsible/root/CollapsibleRootContext");
var _composite = require("../../composite/composite");
var _AccordionRootContext = require("../root/AccordionRootContext");
var _AccordionItemContext = require("../item/AccordionItemContext");
var _useRenderElement = require("../../utils/useRenderElement");
const SUPPORTED_KEYS = new Set([_composite.ARROW_DOWN, _composite.ARROW_UP, _composite.ARROW_RIGHT, _composite.ARROW_LEFT, _composite.HOME, _composite.END]);
function getActiveTriggers(accordionItemRefs) {
const {
current: accordionItemElements
} = accordionItemRefs;
const output = [];
for (let i = 0; i < accordionItemElements.length; i += 1) {
const section = accordionItemElements[i];
if (!(0, _isElementDisabled.isElementDisabled)(section)) {
const trigger = section?.querySelector('[type="button"]');
if (!(0, _isElementDisabled.isElementDisabled)(trigger)) {
output.push(trigger);
}
}
}
return output;
}
/**
* A button that opens and closes the corresponding panel.
* Renders a `<button>` element.
*
* Documentation: [Base UI Accordion](https://base-ui.com/react/components/accordion)
*/
const AccordionTrigger = exports.AccordionTrigger = /*#__PURE__*/React.forwardRef(function AccordionTrigger(componentProps, forwardedRef) {
const {
disabled: disabledProp,
className,
id: idProp,
render,
nativeButton = true,
...elementProps
} = componentProps;
const {
panelId,
open,
handleTrigger,
disabled: contextDisabled
} = (0, _CollapsibleRootContext.useCollapsibleRootContext)();
const disabled = disabledProp ?? contextDisabled;
const {
getButtonProps,
buttonRef
} = (0, _useButton.useButton)({
disabled,
focusableWhenDisabled: true,
native: nativeButton
});
const {
accordionItemRefs,
direction,
loopFocus,
orientation
} = (0, _AccordionRootContext.useAccordionRootContext)();
const isRtl = direction === 'rtl';
const isHorizontal = orientation === 'horizontal';
const {
state,
setTriggerId,
triggerId: id
} = (0, _AccordionItemContext.useAccordionItemContext)();
(0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
if (idProp) {
setTriggerId(idProp);
}
return () => {
setTriggerId(undefined);
};
}, [idProp, setTriggerId]);
const props = React.useMemo(() => ({
'aria-controls': open ? panelId : undefined,
'aria-expanded': open,
disabled,
id,
onClick: handleTrigger,
onKeyDown(event) {
if (!SUPPORTED_KEYS.has(event.key)) {
return;
}
(0, _composite.stopEvent)(event);
const triggers = getActiveTriggers(accordionItemRefs);
const numOfEnabledTriggers = triggers.length;
const lastIndex = numOfEnabledTriggers - 1;
let nextIndex = -1;
const thisIndex = triggers.indexOf(event.target);
function toNext() {
if (loopFocus) {
nextIndex = thisIndex + 1 > lastIndex ? 0 : thisIndex + 1;
} else {
nextIndex = Math.min(thisIndex + 1, lastIndex);
}
}
function toPrev() {
if (loopFocus) {
nextIndex = thisIndex === 0 ? lastIndex : thisIndex - 1;
} else {
nextIndex = thisIndex - 1;
}
}
switch (event.key) {
case _composite.ARROW_DOWN:
if (!isHorizontal) {
toNext();
}
break;
case _composite.ARROW_UP:
if (!isHorizontal) {
toPrev();
}
break;
case _composite.ARROW_RIGHT:
if (isHorizontal) {
if (isRtl) {
toPrev();
} else {
toNext();
}
}
break;
case _composite.ARROW_LEFT:
if (isHorizontal) {
if (isRtl) {
toNext();
} else {
toPrev();
}
}
break;
case 'Home':
nextIndex = 0;
break;
case 'End':
nextIndex = lastIndex;
break;
default:
break;
}
if (nextIndex > -1) {
triggers[nextIndex].focus();
}
}
}), [accordionItemRefs, disabled, handleTrigger, id, isHorizontal, isRtl, loopFocus, open, panelId]);
const element = (0, _useRenderElement.useRenderElement)('button', componentProps, {
state,
ref: [forwardedRef, buttonRef],
props: [props, elementProps, getButtonProps],
stateAttributesMapping: _collapsibleOpenStateMapping.triggerOpenStateMapping
});
return element;
});
if (process.env.NODE_ENV !== "production") AccordionTrigger.displayName = "AccordionTrigger";