UNPKG

8.89 kBJavaScriptView Raw
1/*
2 * Copyright 2015 Palantir Technologies, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { __decorate, __extends } from "tslib";
17import classNames from "classnames";
18import * as React from "react";
19import { polyfill } from "react-lifecycles-compat";
20import { AbstractPureComponent2, Classes } from "../../common";
21import { DISPLAYNAME_PREFIX } from "../../common/props";
22/**
23 * `Collapse` can be in one of six states, enumerated here.
24 * When changing the `isOpen` prop, the following happens to the states:
25 * isOpen={true} : CLOSED -> OPEN_START -> OPENING -> OPEN
26 * isOpen={false} : OPEN -> CLOSING_START -> CLOSING -> CLOSED
27 */
28export var AnimationStates;
29(function (AnimationStates) {
30 /**
31 * The body is re-rendered, height is set to the measured body height and
32 * the body Y is set to 0.
33 */
34 AnimationStates[AnimationStates["OPEN_START"] = 0] = "OPEN_START";
35 /**
36 * Animation begins, height is set to auto. This is all animated, and on
37 * complete, the state changes to OPEN.
38 */
39 AnimationStates[AnimationStates["OPENING"] = 1] = "OPENING";
40 /**
41 * The collapse height is set to auto, and the body Y is set to 0 (so the
42 * element can be seen as normal).
43 */
44 AnimationStates[AnimationStates["OPEN"] = 2] = "OPEN";
45 /**
46 * Height has been changed from auto to the measured height of the body to
47 * prepare for the closing animation in CLOSING.
48 */
49 AnimationStates[AnimationStates["CLOSING_START"] = 3] = "CLOSING_START";
50 /**
51 * Height is set to 0 and the body Y is at -height. Both of these properties
52 * are transformed, and then after the animation is complete, the state
53 * changes to CLOSED.
54 */
55 AnimationStates[AnimationStates["CLOSING"] = 4] = "CLOSING";
56 /**
57 * The contents of the collapse is not rendered, the collapse height is 0,
58 * and the body Y is at -height (so that the bottom of the body is at Y=0).
59 */
60 AnimationStates[AnimationStates["CLOSED"] = 5] = "CLOSED";
61})(AnimationStates || (AnimationStates = {}));
62var Collapse = /** @class */ (function (_super) {
63 __extends(Collapse, _super);
64 function Collapse() {
65 var _this = _super !== null && _super.apply(this, arguments) || this;
66 _this.state = {
67 animationState: _this.props.isOpen ? AnimationStates.OPEN : AnimationStates.CLOSED,
68 height: undefined,
69 heightWhenOpen: undefined,
70 };
71 // The element containing the contents of the collapse.
72 _this.contents = null;
73 _this.contentsRefHandler = function (el) {
74 _this.contents = el;
75 if (_this.contents != null) {
76 var height = _this.contents.clientHeight;
77 _this.setState({
78 animationState: _this.props.isOpen ? AnimationStates.OPEN : AnimationStates.CLOSED,
79 height: height === 0 ? undefined : height + "px",
80 heightWhenOpen: height === 0 ? undefined : height,
81 });
82 }
83 };
84 return _this;
85 }
86 Collapse.getDerivedStateFromProps = function (props, state) {
87 var isOpen = props.isOpen;
88 var animationState = state.animationState;
89 if (isOpen) {
90 switch (animationState) {
91 case AnimationStates.OPEN:
92 // no-op
93 break;
94 case AnimationStates.OPENING:
95 // allow Collapse#onDelayedStateChange() to handle the transition here
96 break;
97 default:
98 return { animationState: AnimationStates.OPEN_START };
99 }
100 }
101 else {
102 switch (animationState) {
103 case AnimationStates.CLOSED:
104 // no-op
105 break;
106 case AnimationStates.CLOSING:
107 // allow Collapse#onDelayedStateChange() to handle the transition here
108 break;
109 default:
110 // need to set an explicit height so that transition can work
111 return {
112 animationState: AnimationStates.CLOSING_START,
113 height: state.heightWhenOpen + "px",
114 };
115 }
116 }
117 return null;
118 };
119 Collapse.prototype.render = function () {
120 var isContentVisible = this.state.animationState !== AnimationStates.CLOSED;
121 var shouldRenderChildren = isContentVisible || this.props.keepChildrenMounted;
122 var displayWithTransform = isContentVisible && this.state.animationState !== AnimationStates.CLOSING;
123 var isAutoHeight = this.state.height === "auto";
124 var containerStyle = {
125 height: isContentVisible ? this.state.height : undefined,
126 overflowY: isAutoHeight ? "visible" : undefined,
127 // transitions don't work with height: auto
128 transition: isAutoHeight ? "none" : undefined,
129 };
130 var contentsStyle = {
131 // only use heightWhenOpen while closing
132 transform: displayWithTransform ? "translateY(0)" : "translateY(-" + this.state.heightWhenOpen + "px)",
133 // transitions don't work with height: auto
134 transition: isAutoHeight ? "none" : undefined,
135 };
136 return React.createElement(this.props.component, {
137 className: classNames(Classes.COLLAPSE, this.props.className),
138 style: containerStyle,
139 }, React.createElement("div", { className: Classes.COLLAPSE_BODY, ref: this.contentsRefHandler, style: contentsStyle, "aria-hidden": !isContentVisible && this.props.keepChildrenMounted }, shouldRenderChildren ? this.props.children : null));
140 };
141 Collapse.prototype.componentDidMount = function () {
142 this.forceUpdate();
143 // HACKHACK: this should probably be done in getSnapshotBeforeUpdate
144 /* eslint-disable react/no-did-mount-set-state */
145 if (this.props.isOpen) {
146 this.setState({ animationState: AnimationStates.OPEN, height: "auto" });
147 }
148 else {
149 this.setState({ animationState: AnimationStates.CLOSED, height: "0px" });
150 }
151 /* eslint-disable react/no-did-mount-set-state */
152 };
153 Collapse.prototype.componentDidUpdate = function () {
154 var _this = this;
155 if (this.contents == null) {
156 return;
157 }
158 var transitionDuration = this.props.transitionDuration;
159 var animationState = this.state.animationState;
160 if (animationState === AnimationStates.OPEN_START) {
161 var clientHeight = this.contents.clientHeight;
162 this.setState({
163 animationState: AnimationStates.OPENING,
164 height: clientHeight + "px",
165 heightWhenOpen: clientHeight,
166 });
167 this.setTimeout(function () { return _this.onDelayedStateChange(); }, transitionDuration);
168 }
169 else if (animationState === AnimationStates.CLOSING_START) {
170 var clientHeight_1 = this.contents.clientHeight;
171 this.setTimeout(function () {
172 return _this.setState({
173 animationState: AnimationStates.CLOSING,
174 height: "0px",
175 heightWhenOpen: clientHeight_1,
176 });
177 });
178 this.setTimeout(function () { return _this.onDelayedStateChange(); }, transitionDuration);
179 }
180 };
181 Collapse.prototype.onDelayedStateChange = function () {
182 switch (this.state.animationState) {
183 case AnimationStates.OPENING:
184 this.setState({ animationState: AnimationStates.OPEN, height: "auto" });
185 break;
186 case AnimationStates.CLOSING:
187 this.setState({ animationState: AnimationStates.CLOSED });
188 break;
189 default:
190 break;
191 }
192 };
193 Collapse.displayName = DISPLAYNAME_PREFIX + ".Collapse";
194 Collapse.defaultProps = {
195 component: "div",
196 isOpen: false,
197 keepChildrenMounted: false,
198 transitionDuration: 200,
199 };
200 Collapse = __decorate([
201 polyfill
202 ], Collapse);
203 return Collapse;
204}(AbstractPureComponent2));
205export { Collapse };
206//# sourceMappingURL=collapse.js.map
\No newline at end of file