From f7801874dc5b8777c8624709f99d62feb19b3563 Mon Sep 17 00:00:00 2001
From: bestguy <7zark7@gmail.com>
Date: Fri, 20 Aug 2021 20:53:22 -0700
Subject: [PATCH] feat(collapse): add horizontal collapse
---
docs/lib/Components/CollapsePage.js | 11 +++++++++
docs/lib/examples/CollapseHorizontal.js | 24 ++++++++++++++++++++
src/Collapse.js | 30 ++++++++++++++-----------
src/__tests__/Collapse.spec.js | 13 +++++++----
types/lib/Collapse.d.ts | 1 +
5 files changed, 62 insertions(+), 17 deletions(-)
create mode 100644 docs/lib/examples/CollapseHorizontal.js
diff --git a/docs/lib/Components/CollapsePage.js b/docs/lib/Components/CollapsePage.js
index 378719373..e4881292c 100644
--- a/docs/lib/Components/CollapsePage.js
+++ b/docs/lib/Components/CollapsePage.js
@@ -5,11 +5,13 @@ import PageTitle from '../UI/PageTitle';
import SectionTitle from '../UI/SectionTitle';
import CollapseExample from '../examples/Collapse';
+import CollapseHorizontalExample from '../examples/CollapseHorizontal';
import UncontrolledCollapseExample from '../examples/CollapseUncontrolled';
import CollapseEventsExample from '../examples/CollapseEvents';
const CollapseExampleSource = require('!!raw-loader!../examples/Collapse');
+const CollapseHorizontalExampleSource = require('!!raw-loader!../examples/CollapseHorizontal');
const CollapseEventsExampleSource = require('!!raw-loader!../examples/CollapseEvents');
const UncontrolledCollapseExampleSource = require('!!raw-loader!../examples/CollapseUncontrolled');
@@ -31,6 +33,7 @@ export default class CollapsePage extends React.Component {
{`Collapse.propTypes = {
...Transition.propTypes, // see note below
+ horizontal: PropTypes.bool,
isOpen: PropTypes.bool,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
@@ -51,6 +54,14 @@ export default class CollapsePage extends React.Component {
http://reactcommunity.org/react-transition-group/transition/.
+ Horizontal
+
+
+
+
+ {CollapseHorizontalExampleSource}
+
+
Events
Use the onEnter
, onEntering, onEntered, onExiting and onExited props for
diff --git a/docs/lib/examples/CollapseHorizontal.js b/docs/lib/examples/CollapseHorizontal.js
new file mode 100644
index 000000000..ed9508cfc
--- /dev/null
+++ b/docs/lib/examples/CollapseHorizontal.js
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import { Alert, Collapse, Button } from 'reactstrap';
+
+const Example = () => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const toggle = () => setIsOpen(!isOpen);
+
+ return (
+
+
Toggle
+
+
+ Anim pariatur cliche reprehenderit,
+ enim eiusmod high life accusamus terry richardson ad squid. Nihil
+ anim keffiyeh helvetica, craft beer labore wes anderson cred
+ nesciunt sapiente ea proident.
+
+
+
+ );
+}
+
+export default Example;
diff --git a/src/Collapse.js b/src/Collapse.js
index 9bac27e6d..b42efb1d9 100644
--- a/src/Collapse.js
+++ b/src/Collapse.js
@@ -6,6 +6,7 @@ import { mapToCssModules, omit, pick, TransitionTimeouts, TransitionPropTypeKeys
const propTypes = {
...Transition.propTypes,
+ horizontal: PropTypes.bool,
isOpen: PropTypes.bool,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
@@ -24,6 +25,7 @@ const propTypes = {
const defaultProps = {
...Transition.defaultProps,
+ horizontal: false,
isOpen: false,
appear: false,
enter: true,
@@ -43,16 +45,12 @@ function getTransitionClass(status) {
return transitionStatusToClassHash[status] || 'collapse';
}
-function getHeight(node) {
- return node.scrollHeight;
-}
-
class Collapse extends Component {
constructor(props) {
super(props);
this.state = {
- height: null
+ dimension: null
};
['onEntering', 'onEntered', 'onExit', 'onExiting', 'onExited'].forEach((name) => {
@@ -60,36 +58,41 @@ class Collapse extends Component {
});
}
+ getDimension(node) {
+ return this.props.horizontal ? node.scrollWidth : node.scrollHeight;
+ }
+
onEntering(node, isAppearing) {
- this.setState({ height: getHeight(node) });
+ this.setState({ dimension: this.getDimension(node) });
this.props.onEntering(node, isAppearing);
}
onEntered(node, isAppearing) {
- this.setState({ height: null });
+ this.setState({ dimension: null });
this.props.onEntered(node, isAppearing);
}
onExit(node) {
- this.setState({ height: getHeight(node) });
+ this.setState({ dimension: this.getDimension(node) });
this.props.onExit(node);
}
onExiting(node) {
// getting this variable triggers a reflow
- const _unused = node.offsetHeight; // eslint-disable-line no-unused-vars
- this.setState({ height: 0 });
+ const _unused = this.getDimension(node); // eslint-disable-line no-unused-vars
+ this.setState({ dimension: 0 });
this.props.onExiting(node);
}
onExited(node) {
- this.setState({ height: null });
+ this.setState({ dimension: null });
this.props.onExited(node);
}
render() {
const {
tag: Tag,
+ horizontal,
isOpen,
className,
navbar,
@@ -99,7 +102,7 @@ class Collapse extends Component {
...otherProps
} = this.props;
- const { height } = this.state;
+ const { dimension } = this.state;
const transitionProps = pick(otherProps, TransitionPropTypeKeys);
const childProps = omit(otherProps, TransitionPropTypeKeys);
@@ -117,10 +120,11 @@ class Collapse extends Component {
let collapseClass = getTransitionClass(status);
const classes = mapToCssModules(classNames(
className,
+ horizontal && 'collapse-horizontal',
collapseClass,
navbar && 'navbar-collapse'
), cssModule);
- const style = height === null ? null : { height };
+ const style = dimension === null ? null : { [horizontal ? 'width' : 'height']: dimension };
return (
{
expect(wrapper.find('div').hasClass('collapse')).toEqual(true);
});
+ it('should render with class "collapse-horizontal" if it has prop horizontal', () => {
+ wrapper = mount( );
+ expect(wrapper.find('div').hasClass('collapse-horizontal')).toEqual(true);
+ });
+
it('should render with class "navbar-collapse" if it has prop navbar', () => {
wrapper = mount( );
expect(wrapper.find('div').hasClass('navbar-collapse')).toEqual(true);
@@ -50,12 +55,12 @@ describe('Collapse', () => {
it('should set height to null when isOpen is true', () => {
wrapper = shallow( );
- expect(wrapper.state('height')).toBe(null);
+ expect(wrapper.state('dimension')).toBe(null);
});
it('should not set height when isOpen is false', () => {
wrapper = shallow( );
- expect(wrapper.state('height')).toBe(null);
+ expect(wrapper.state('dimension')).toBe(null);
});
it('should forward all styles', () => {
@@ -111,7 +116,7 @@ describe('Collapse', () => {
isOpen = true;
wrapper = mount( );
toggle();
- expect(wrapper.state('height')).toBe(0);
+ expect(wrapper.state('dimension')).toBe(0);
wrapper.unmount();
});
@@ -119,7 +124,7 @@ describe('Collapse', () => {
wrapper = mount( );
toggle();
jest.runTimersToTime(380);
- expect(wrapper.state('height')).toBe(null);
+ expect(wrapper.state('dimension')).toBe(null);
wrapper.unmount();
});
});
diff --git a/types/lib/Collapse.d.ts b/types/lib/Collapse.d.ts
index 2a4971543..a606db149 100644
--- a/types/lib/Collapse.d.ts
+++ b/types/lib/Collapse.d.ts
@@ -6,6 +6,7 @@ export interface CollapseProps extends React.HTMLAttributes {
isOpen?: boolean;
cssModule?: CSSModule;
tag?: React.ElementType;
+ horizontal?: boolean;
navbar?: boolean;
delay?: {
show: number;