Skip to content
This repository was archived by the owner on Apr 21, 2026. It is now read-only.

Commit e3418bf

Browse files
J12934SirDany
andcommitted
Use collapsible component directly instead of vendoring it
Co-authored-by: Daniel Patanin <44839597+dpatanin@users.noreply.github.com>
1 parent e039460 commit e3418bf

5 files changed

Lines changed: 44 additions & 348 deletions

File tree

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"lodash": "^4.17.20",
3232
"react": "^16.13.1",
3333
"react-burger-menu": "^2.7.0",
34+
"react-collapsible": "^2.8.0",
3435
"react-dom": "^16.13.1",
3536
"react-helmet": "^6.1.0",
3637
"react-icons": "^3.11.0",

src/components/Collapsible.js

Lines changed: 17 additions & 345 deletions
Original file line numberDiff line numberDiff line change
@@ -1,346 +1,18 @@
1-
import React, { Component } from 'react';
2-
import PropTypes from 'prop-types';
3-
import { IoIosArrowDown, IoIosArrowForward } from 'react-icons/io';
4-
5-
/**
6-
* This Component was adapted from https://www.npmjs.com/package/react-collapsible.
7-
*/
8-
class Collapsible extends Component {
9-
constructor(props) {
10-
super(props);
11-
12-
this.timeout = undefined;
13-
14-
// Bind class methods
15-
this.handleTriggerClick = this.handleTriggerClick.bind(this);
16-
this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
17-
this.continueOpenCollapsible = this.continueOpenCollapsible.bind(this);
18-
this.setInnerRef = this.setInnerRef.bind(this);
19-
20-
// Defaults the dropdown to be closed
21-
if (props.open) {
22-
this.state = {
23-
isClosed: false,
24-
shouldSwitchAutoOnNextCycle: false,
25-
height: 'auto',
26-
transition: 'none',
27-
hasBeenOpened: true,
28-
overflow: props.overflowWhenOpen,
29-
inTransition: false,
30-
};
31-
} else {
32-
this.state = {
33-
isClosed: true,
34-
shouldSwitchAutoOnNextCycle: false,
35-
height: 0,
36-
transition: `height ${props.transitionTime}ms ${props.easing}`,
37-
hasBeenOpened: false,
38-
overflow: 'hidden',
39-
inTransition: false,
40-
};
41-
}
42-
}
43-
44-
componentDidUpdate(prevProps, prevState) {
45-
if (this.state.shouldOpenOnNextCycle) {
46-
this.continueOpenCollapsible();
47-
}
48-
49-
if (
50-
prevState.height === 'auto' &&
51-
this.state.shouldSwitchAutoOnNextCycle === true
52-
) {
53-
window.clearTimeout(this.timeout);
54-
this.timeout = window.setTimeout(() => {
55-
// Set small timeout to ensure a true re-render
56-
this.setState({
57-
height: 0,
58-
overflow: 'hidden',
59-
isClosed: true,
60-
shouldSwitchAutoOnNextCycle: false,
61-
});
62-
}, 50);
63-
}
64-
65-
// If there has been a change in the open prop (controlled by accordion)
66-
if (prevProps.open !== this.props.open) {
67-
if (this.props.open === true) {
68-
this.openCollapsible();
69-
this.props.onOpening();
70-
} else {
71-
this.closeCollapsible();
72-
this.props.onClosing();
73-
}
74-
}
75-
}
76-
77-
componentWillUnmount() {
78-
window.clearTimeout(this.timeout);
79-
}
80-
81-
closeCollapsible() {
82-
this.setState({
83-
shouldSwitchAutoOnNextCycle: true,
84-
height: this.innerRef.scrollHeight,
85-
transition: `height ${
86-
this.props.transitionCloseTime
87-
? this.props.transitionCloseTime
88-
: this.props.transitionTime
89-
}ms ${this.props.easing}`,
90-
inTransition: true,
91-
});
92-
}
93-
94-
openCollapsible() {
95-
this.setState({
96-
inTransition: true,
97-
shouldOpenOnNextCycle: true,
98-
});
99-
}
100-
101-
continueOpenCollapsible() {
102-
this.setState({
103-
height: this.innerRef.scrollHeight,
104-
transition: `height ${this.props.transitionTime}ms ${this.props.easing}`,
105-
isClosed: false,
106-
hasBeenOpened: true,
107-
inTransition: true,
108-
shouldOpenOnNextCycle: false,
109-
});
110-
}
111-
112-
handleTriggerClick(event) {
113-
if (this.props.triggerDisabled || this.state.inTransition) {
114-
return;
115-
}
116-
117-
event.preventDefault();
118-
119-
if (this.props.handleTriggerClick) {
120-
this.props.handleTriggerClick(this.props.accordionPosition);
121-
} else {
122-
if (this.state.isClosed === true) {
123-
this.openCollapsible();
124-
this.props.onOpening();
125-
this.props.onTriggerOpening();
126-
} else {
127-
this.closeCollapsible();
128-
this.props.onClosing();
129-
this.props.onTriggerClosing();
130-
}
131-
}
132-
}
133-
134-
renderNonClickableTriggerElement() {
135-
if (
136-
this.props.triggerSibling &&
137-
typeof this.props.triggerSibling === 'string'
138-
) {
139-
return (
140-
<span className={`${this.props.classParentString}__trigger-sibling`}>
141-
{this.props.triggerSibling}
142-
</span>
143-
);
144-
} else if (
145-
this.props.triggerSibling &&
146-
typeof this.props.triggerSibling === 'function'
147-
) {
148-
return this.props.triggerSibling();
149-
} else if (this.props.triggerSibling) {
150-
return <this.props.triggerSibling />;
151-
}
152-
153-
return null;
154-
}
155-
156-
handleTransitionEnd(e) {
157-
// only handle transitions that origin from the container of this component
158-
if (e.target !== this.innerRef) {
159-
return;
160-
}
161-
// Switch to height auto to make the container responsive
162-
if (!this.state.isClosed) {
163-
this.setState({
164-
height: 'auto',
165-
overflow: this.props.overflowWhenOpen,
166-
inTransition: false,
167-
});
168-
this.props.onOpen();
169-
} else {
170-
this.setState({ inTransition: false });
171-
this.props.onClose();
172-
}
173-
}
174-
175-
setInnerRef(ref) {
176-
this.innerRef = ref;
177-
}
178-
179-
render() {
180-
const dropdownStyle = {
181-
height: this.state.height,
182-
WebkitTransition: this.state.transition,
183-
msTransition: this.state.transition,
184-
transition: this.state.transition,
185-
overflow: this.state.overflow,
186-
};
187-
188-
var openClass = this.state.isClosed ? 'is-closed' : 'is-open';
189-
var disabledClass = this.props.triggerDisabled ? 'is-disabled' : '';
190-
191-
//If user wants different text when tray is open
192-
var trigger =
193-
this.state.isClosed === false && this.props.triggerWhenOpen !== undefined
194-
? this.props.triggerWhenOpen
195-
: this.props.trigger;
196-
197-
const ContentContainerElement = this.props.contentContainerTagName;
198-
199-
// If user wants a trigger wrapping element different than 'span'
200-
const TriggerElement = this.props.triggerTagName;
201-
202-
// Don't render children until the first opening of the Collapsible if lazy rendering is enabled
203-
var children =
204-
this.props.lazyRender &&
205-
!this.state.hasBeenOpened &&
206-
this.state.isClosed &&
207-
!this.state.inTransition
208-
? null
209-
: this.props.children;
210-
211-
// Construct CSS classes strings
212-
const triggerClassString = `${
213-
this.props.classParentString
214-
}__trigger ${openClass} ${disabledClass} ${
215-
this.state.isClosed
216-
? this.props.triggerClassName
217-
: this.props.triggerOpenedClassName
218-
}`;
219-
const parentClassString = `${this.props.classParentString} ${
220-
this.state.isClosed ? this.props.className : this.props.openedClassName
221-
}`;
222-
const outerClassString = `${this.props.classParentString}__contentOuter ${this.props.contentOuterClassName}`;
223-
const innerClassString = `${this.props.classParentString}__contentInner ${this.props.contentInnerClassName}`;
224-
225-
return (
226-
<ContentContainerElement
227-
className={parentClassString.trim()}
228-
{...this.props.containerElementProps}
229-
>
230-
<TriggerElement
231-
className={triggerClassString.trim()}
232-
onClick={this.handleTriggerClick}
233-
style={this.props.triggerStyle && this.props.triggerStyle}
234-
onKeyPress={(event) => {
235-
const { key } = event;
236-
if (
237-
(key === ' ' &&
238-
this.props.triggerTagName.toLowerCase() !== 'button') ||
239-
key === 'Enter'
240-
) {
241-
this.handleTriggerClick(event);
242-
}
243-
}}
244-
tabIndex={this.props.tabIndex && this.props.tabIndex}
245-
{...this.props.triggerElementProps}
246-
>
247-
<div className="collapsible-header">
248-
{trigger}
249-
<IoIosArrowDown
250-
style={{
251-
display: this.state.isClosed ? 'none' : 'block',
252-
}}
253-
/>
254-
<IoIosArrowForward
255-
style={{
256-
display: this.state.isClosed ? 'block' : 'none',
257-
}}
258-
/>
259-
</div>
260-
</TriggerElement>
261-
262-
{this.renderNonClickableTriggerElement()}
263-
264-
<div
265-
className={outerClassString.trim()}
266-
style={dropdownStyle}
267-
onTransitionEnd={this.handleTransitionEnd}
268-
ref={this.setInnerRef}
269-
>
270-
<div className={innerClassString.trim()}>{children}</div>
271-
</div>
272-
</ContentContainerElement>
273-
);
274-
}
1+
import React, { Fragment } from "react";
2+
import Collapsible from "react-collapsible";
3+
import { IoIosArrowDown, IoIosArrowForward } from "react-icons/io";
4+
5+
export default function CollapsibleWrapper({ trigger, children, ...props }) {
6+
const triggerComponent = (
7+
<Fragment>
8+
{trigger}
9+
<IoIosArrowDown className="arrow-down" />
10+
<IoIosArrowForward className="arrow-up" />
11+
</Fragment>
12+
);
13+
return (
14+
<Collapsible trigger={triggerComponent} {...props}>
15+
{children}
16+
</Collapsible>
17+
);
27518
}
276-
277-
Collapsible.propTypes = {
278-
transitionTime: PropTypes.number,
279-
transitionCloseTime: PropTypes.number,
280-
triggerTagName: PropTypes.string,
281-
easing: PropTypes.string,
282-
open: PropTypes.bool,
283-
containerElementProps: PropTypes.object,
284-
triggerElementProps: PropTypes.object,
285-
classParentString: PropTypes.string,
286-
openedClassName: PropTypes.string,
287-
triggerStyle: PropTypes.object,
288-
triggerClassName: PropTypes.string,
289-
triggerOpenedClassName: PropTypes.string,
290-
contentOuterClassName: PropTypes.string,
291-
contentInnerClassName: PropTypes.string,
292-
accordionPosition: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
293-
handleTriggerClick: PropTypes.func,
294-
onOpen: PropTypes.func,
295-
onClose: PropTypes.func,
296-
onOpening: PropTypes.func,
297-
onClosing: PropTypes.func,
298-
onTriggerOpening: PropTypes.func,
299-
onTriggerClosing: PropTypes.func,
300-
trigger: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
301-
triggerWhenOpen: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
302-
triggerDisabled: PropTypes.bool,
303-
lazyRender: PropTypes.bool,
304-
overflowWhenOpen: PropTypes.oneOf([
305-
'hidden',
306-
'visible',
307-
'auto',
308-
'scroll',
309-
'inherit',
310-
'initial',
311-
'unset',
312-
]),
313-
triggerSibling: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
314-
tabIndex: PropTypes.number,
315-
contentContainerTagName: PropTypes.string,
316-
};
317-
318-
Collapsible.defaultProps = {
319-
transitionTime: 400,
320-
transitionCloseTime: null,
321-
triggerTagName: 'span',
322-
easing: 'linear',
323-
open: false,
324-
classParentString: 'Collapsible',
325-
triggerDisabled: false,
326-
lazyRender: false,
327-
overflowWhenOpen: 'hidden',
328-
openedClassName: '',
329-
triggerStyle: null,
330-
triggerClassName: '',
331-
triggerOpenedClassName: '',
332-
contentOuterClassName: '',
333-
contentInnerClassName: '',
334-
className: '',
335-
triggerSibling: null,
336-
onOpen: () => {},
337-
onClose: () => {},
338-
onOpening: () => {},
339-
onClosing: () => {},
340-
onTriggerOpening: () => {},
341-
onTriggerClosing: () => {},
342-
tabIndex: null,
343-
contentContainerTagName: 'div',
344-
};
345-
346-
export default Collapsible;

0 commit comments

Comments
 (0)