UNPKG

@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.

151 lines (150 loc) 5.29 kB
"use strict"; 'use client'; Object.defineProperty(exports, "__esModule", { value: true }); exports.useAccordionRoot = useAccordionRoot; var React = _interopRequireWildcard(require("react")); var _mergeReactProps = require("../../utils/mergeReactProps"); var _useControlled = require("../../utils/useControlled"); var _composite = require("../../composite/composite"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const SUPPORTED_KEYS = [_composite.ARROW_DOWN, _composite.ARROW_UP, _composite.ARROW_RIGHT, _composite.ARROW_LEFT, 'Home', 'End']; function getActiveTriggers(accordionItemRefs) { const { current: accordionItemElements } = accordionItemRefs; const output = []; for (let i = 0; i < accordionItemElements.length; i += 1) { const section = accordionItemElements[i]; if (!isDisabled(section)) { const trigger = section?.querySelector('[type="button"]'); if (!isDisabled(trigger)) { output.push(trigger); } } } return output; } function isDisabled(element) { return element === null || element.hasAttribute('disabled') || element.getAttribute('data-disabled') === 'true'; } function useAccordionRoot(parameters) { const { disabled, direction, loop, onValueChange, orientation, openMultiple, value: valueParam, defaultValue } = parameters; const accordionItemRefs = React.useRef([]); const [value, setValue] = (0, _useControlled.useControlled)({ controlled: valueParam, default: defaultValue, name: 'Accordion', state: 'value' }); const handleValueChange = React.useCallback((newValue, nextOpen) => { if (!openMultiple) { const nextValue = value[0] === newValue ? [] : [newValue]; setValue(nextValue); onValueChange?.(nextValue); } else if (nextOpen) { const nextOpenValues = value.slice(); nextOpenValues.push(newValue); setValue(nextOpenValues); onValueChange?.(nextOpenValues); } else { const nextOpenValues = value.filter(v => v !== newValue); setValue(nextOpenValues); onValueChange?.(nextOpenValues); } }, [onValueChange, openMultiple, setValue, value]); const getRootProps = React.useCallback((externalProps = {}) => { const isRtl = direction === 'rtl'; const isHorizontal = orientation === 'horizontal'; return (0, _mergeReactProps.mergeReactProps)(externalProps, { dir: direction, role: 'region', onKeyDown(event) { if (!SUPPORTED_KEYS.includes(event.key)) { return; } event.preventDefault(); const triggers = getActiveTriggers(accordionItemRefs); const numOfEnabledTriggers = triggers.length; const lastIndex = numOfEnabledTriggers - 1; let nextIndex = -1; const thisIndex = triggers.indexOf(event.target); function toNext() { if (loop) { nextIndex = thisIndex + 1 > lastIndex ? 0 : thisIndex + 1; } else { nextIndex = Math.min(thisIndex + 1, lastIndex); } } function toPrev() { if (loop) { 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(); } } }); }, [direction, loop, orientation]); return React.useMemo(() => ({ getRootProps, accordionItemRefs, direction, disabled, handleValueChange, orientation, value }), [getRootProps, accordionItemRefs, direction, disabled, handleValueChange, orientation, value]); }