UNPKG

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