jcore-ui
Version:
jcore-ui - components for building an interface
192 lines (155 loc) • 4.7 kB
text/typescript
import Component, {
IComponent,
IComponentOn,
IComponentOptions,
IComponentSelector,
} from "../core/Component";
import config from "../../config";
import { $, JDom } from "../core/JDom";
const selectors = {
element: `.${config.prefix}-collapse`,
wrapper: `.${config.prefix}-collapse-wrapper`,
button: `.${config.prefix}-collapse-button`,
};
interface ICollapseSelector extends IComponentSelector {
wrapper?: string;
button?: string;
}
interface ICollapseOptions extends IComponentOptions {
height?: number;
duration?: number;
}
interface ICollapseOn extends IComponentOn {
toggle?: (ctx?: Component) => void;
}
interface ICollapse extends IComponent {
selectors?: ICollapseSelector;
options?: ICollapseOptions;
on?: ICollapseOn;
}
interface Collapse {
selectors: ICollapseSelector;
$wrapper: JDom;
$button: JDom;
options: ICollapseOptions;
isActive: boolean;
scrollHeight: number;
on: ICollapseOn;
}
class Collapse extends Component {
constructor(props: ICollapse = {}) {
super({
...props,
Component: Collapse,
selectors: Object.assign(selectors, props.selectors || {}),
});
if (this.options && this.options.mount) {
this.mount();
}
}
mount() {
if (!this.$element || this._mount || this.$element.attr("data-mount")) {
return;
}
super.mount();
this.options = Object.assign(
{
height: this.$element.dataset.height || 0,
duration: this.$element.dataset.duration || 300,
},
this.options
);
this.handlers = {
toggle: this.toggle.bind(this),
resize: this.resize.bind(this),
};
this.on = Object.assign(
{
toggle: () => {},
},
this.on
);
this.$wrapper = $(this.$element).find(this.selectors.wrapper);
this.$button = $(this.$element).find(this.selectors.button);
this.isActive = false;
this.scrollHeight = this.$wrapper.scrollHeight;
this.addEvents();
this.on.mount(this);
this.emitter.emit("mount", this);
}
addEvents() {
this.$wrapper.style.setProperty(
"max-height",
`${this.options.height}px`
);
this.$wrapper.style.setProperty(
"transition",
`all ease-in-out ${this.options.duration}ms`
);
this.$button.on("click", this.handlers.toggle);
window.addEventListener("resize", this.handlers.resize);
this.initButtonByHeight();
}
unmount() {
super.unmount();
this.$button.off("click", this.handlers.toggle, null);
window.removeEventListener("resize", this.handlers.resize);
this.$button.attr("data-mount", null);
this.on.unmount(this);
this.emitter.emit("unmount", this);
}
toggle() {
this.scrollHeight = this.$wrapper.scrollHeight;
if (this.isActive) {
this.close();
} else {
this.open();
}
this.emitter.emit("toggle", this);
this.on.toggle(this);
}
open() {
this.$button.attr("data-active", "");
this.$element.attr("data-active", "");
this.$wrapper.attr("data-active", "");
this.$wrapper.style.setProperty("max-height", `${this.scrollHeight}px`);
this.isActive = true;
}
close() {
this.$button.attr("data-active", null);
this.$element.attr("data-active", null);
this.$wrapper.attr("data-active", null);
this.$wrapper.style.setProperty(
"max-height",
`${this.options.height}px`
);
this.isActive = false;
}
resize() {
if (this.$wrapper) {
this.scrollHeight = this.$wrapper.scrollHeight;
if (this.isActive) {
this.$wrapper.style.setProperty(
"max-height",
`${this.scrollHeight}px`
);
} else {
this.$wrapper.style.setProperty(
"max-height",
`${this.options.height}px`
);
}
}
this.initButtonByHeight();
}
initButtonByHeight() {
if (this.$button) {
if (this.scrollHeight < this.options.height) {
this.$button.attr("data-mount", null);
} else {
this.$button.attr("data-mount", "");
}
}
}
}
export default Collapse;