-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
AccordionButton.tsx
104 lines (91 loc) · 2.91 KB
/
AccordionButton.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as React from 'react';
import { useContext } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import AccordionContext, {
isAccordionItemSelected,
AccordionEventKey,
} from './AccordionContext';
import AccordionItemContext from './AccordionItemContext';
import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';
import { useBootstrapPrefix } from './ThemeProvider';
type EventHandler = React.EventHandler<React.SyntheticEvent>;
export interface AccordionButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
BsPrefixProps {}
const propTypes = {
/** Set a custom element for this component */
as: PropTypes.elementType,
/** @default 'accordion-button' */
bsPrefix: PropTypes.string,
/** A callback function for when this component is clicked */
onClick: PropTypes.func,
};
export function useAccordionButton(
eventKey: string,
onClick?: EventHandler,
): EventHandler {
const { activeEventKey, onSelect, alwaysOpen } = useContext(AccordionContext);
return (e) => {
/*
Compare the event key in context with the given event key.
If they are the same, then collapse the component.
*/
let eventKeyPassed: AccordionEventKey =
eventKey === activeEventKey ? null : eventKey;
if (alwaysOpen) {
if (Array.isArray(activeEventKey)) {
if (activeEventKey.includes(eventKey)) {
eventKeyPassed = activeEventKey.filter((k) => k !== eventKey);
} else {
eventKeyPassed = [...activeEventKey, eventKey];
}
} else {
// activeEventKey is undefined.
eventKeyPassed = [eventKey];
}
}
onSelect?.(eventKeyPassed, e);
onClick?.(e);
};
}
const AccordionButton: BsPrefixRefForwardingComponent<
'div',
AccordionButtonProps
> = React.forwardRef<HTMLButtonElement, AccordionButtonProps>(
(
{
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'button',
bsPrefix,
className,
onClick,
...props
},
ref,
) => {
bsPrefix = useBootstrapPrefix(bsPrefix, 'accordion-button');
const { eventKey } = useContext(AccordionItemContext);
const accordionOnClick = useAccordionButton(eventKey, onClick);
const { activeEventKey } = useContext(AccordionContext);
if (Component === 'button') {
props.type = 'button';
}
return (
<Component
ref={ref}
onClick={accordionOnClick}
{...props}
aria-expanded={eventKey === activeEventKey}
className={classNames(
className,
bsPrefix,
!isAccordionItemSelected(activeEventKey, eventKey) && 'collapsed',
)}
/>
);
},
);
AccordionButton.propTypes = propTypes;
AccordionButton.displayName = 'AccordionButton';
export default AccordionButton;