@douyinfe/semi-ui
Version:
A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.
185 lines (184 loc) • 6.97 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _pick2 = _interopRequireDefault(require("lodash/pick"));
var _isEqual2 = _interopRequireDefault(require("lodash/isEqual"));
var _react = _interopRequireDefault(require("react"));
var _foundation = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/collapsible/foundation"));
var _baseComponent = _interopRequireDefault(require("../_base/baseComponent"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _constants = require("@douyinfe/semi-foundation/lib/cjs/collapsible/constants");
require("@douyinfe/semi-foundation/lib/cjs/collapsible/collapsible.css");
var _utils = require("../_utils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
class Collapsible extends _baseComponent.default {
constructor(props) {
super(props);
this.domRef = /*#__PURE__*/_react.default.createRef();
this.hasBeenRendered = false;
this.handleResize = entryList => {
const entry = entryList[0];
if (entry) {
const entryInfo = Collapsible.getEntryInfo(entry);
this.foundation.updateDOMHeight(entryInfo.height);
this.foundation.updateDOMInRenderTree(entryInfo.isShown);
}
};
this.isChildrenInRenderTree = () => {
if (this.domRef.current) {
return this.domRef.current.offsetHeight > 0;
}
return false;
};
this.state = {
domInRenderTree: false,
domHeight: 0,
visible: this.props.isOpen,
isTransitioning: false
};
this.foundation = new _foundation.default(this.adapter);
}
get adapter() {
return Object.assign(Object.assign({}, super.adapter), {
setDOMInRenderTree: domInRenderTree => {
if (this.state.domInRenderTree !== domInRenderTree) {
this.setState({
domInRenderTree
});
}
},
setDOMHeight: domHeight => {
if (this.state.domHeight !== domHeight) {
this.setState({
domHeight
});
}
},
setVisible: visible => {
if (this.state.visible !== visible) {
this.setState({
visible
});
}
},
setIsTransitioning: isTransitioning => {
if (this.state.isTransitioning !== isTransitioning) {
this.setState({
isTransitioning
});
}
}
});
}
componentDidMount() {
super.componentDidMount();
this.resizeObserver = new ResizeObserver(this.handleResize);
this.resizeObserver.observe(this.domRef.current);
const domInRenderTree = this.isChildrenInRenderTree();
this.foundation.updateDOMInRenderTree(domInRenderTree);
if (domInRenderTree) {
this.foundation.updateDOMHeight(this.domRef.current.scrollHeight);
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
const changedPropKeys = Object.keys((0, _pick2.default)(this.props, ['reCalcKey', "isOpen"])).filter(key => !(0, _isEqual2.default)(this.props[key], prevProps[key]));
const changedStateKeys = Object.keys((0, _pick2.default)(this.state, ['domInRenderTree'])).filter(key => !(0, _isEqual2.default)(this.state[key], prevState[key]));
if (changedPropKeys.includes("reCalcKey")) {
this.foundation.updateDOMHeight(this.domRef.current.scrollHeight);
}
if (changedStateKeys.includes("domInRenderTree") && this.state.domInRenderTree) {
this.foundation.updateDOMHeight(this.domRef.current.scrollHeight);
}
if (changedPropKeys.includes("isOpen")) {
if (this.props.isOpen || !this.props.motion) {
this.foundation.updateVisible(this.props.isOpen);
}
}
if (this.props.motion && prevProps.isOpen !== this.props.isOpen) {
this.foundation.updateIsTransitioning(true);
}
}
componentWillUnmount() {
super.componentWillUnmount();
this.resizeObserver.disconnect();
}
render() {
const wrapperStyle = Object.assign({
overflow: 'hidden',
height: this.props.isOpen ? this.state.domHeight : this.props.collapseHeight,
opacity: this.props.isOpen || !this.props.fade || this.props.collapseHeight !== 0 ? 1 : 0,
transitionDuration: `${this.props.motion && this.state.isTransitioning ? this.props.duration : 0}ms`
}, this.props.style);
const wrapperCls = (0, _classnames.default)(`${_constants.cssClasses.PREFIX}-wrapper`, {
[`${_constants.cssClasses.PREFIX}-transition`]: this.props.motion && this.state.isTransitioning
}, this.props.className);
const shouldRender = this.props.keepDOM && (this.props.lazyRender ? this.hasBeenRendered : true) || this.props.collapseHeight !== 0 || this.state.visible || this.props.isOpen;
if (shouldRender && !this.hasBeenRendered) {
this.hasBeenRendered = true;
}
return /*#__PURE__*/_react.default.createElement("div", Object.assign({
className: wrapperCls,
style: wrapperStyle,
onTransitionEnd: () => {
var _a, _b;
if (!this.props.isOpen) {
this.foundation.updateVisible(false);
}
this.foundation.updateIsTransitioning(false);
(_b = (_a = this.props).onMotionEnd) === null || _b === void 0 ? void 0 : _b.call(_a);
}
}, this.getDataAttr(this.props)), /*#__PURE__*/_react.default.createElement("div", {
"x-semi-prop": "children",
ref: this.domRef,
style: {
overflow: 'hidden'
},
id: this.props.id
}, shouldRender && this.props.children));
}
}
Collapsible.__SemiComponentName__ = "Collapsible";
Collapsible.defaultProps = (0, _utils.getDefaultPropsFromGlobalConfig)(Collapsible.__SemiComponentName__, {
isOpen: false,
duration: 250,
motion: true,
keepDOM: false,
lazyRender: false,
collapseHeight: 0,
fade: false
});
Collapsible.getEntryInfo = entry => {
//judge whether parent or self display none
let inRenderTree;
if (entry.borderBoxSize) {
inRenderTree = !(entry.borderBoxSize[0].blockSize === 0 && entry.borderBoxSize[0].inlineSize === 0);
} else {
inRenderTree = !(entry.contentRect.height === 0 && entry.contentRect.width === 0);
}
let height = 0;
if (entry.borderBoxSize) {
height = Math.ceil(entry.borderBoxSize[0].blockSize);
} else {
const target = entry.target;
height = target.clientHeight;
}
return {
isShown: inRenderTree,
height
};
};
Collapsible.propTypes = {
motion: _propTypes.default.bool,
children: _propTypes.default.node,
isOpen: _propTypes.default.bool,
duration: _propTypes.default.number,
keepDOM: _propTypes.default.bool,
collapseHeight: _propTypes.default.number,
style: _propTypes.default.object,
className: _propTypes.default.string,
reCalcKey: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])
};
var _default = exports.default = Collapsible;