UNPKG

stem-core

Version:

Frontend and core-library framework

193 lines (164 loc) 6.31 kB
import {UI} from "../UIBase"; import {registerStyle} from "../style/Theme"; import {getComputedStyle} from "../Utils"; import {unwrapArray} from "../../base/Utils"; import {Device} from "../../base/Device"; import {AccordionStyle} from "./Style"; import {FACollapseIcon} from "../../ui/FontAwesome"; import {Divider} from "./Divider"; @registerStyle(AccordionStyle) class AccordionDivider extends Divider { dragMousedown(event) { document.body.classList.add(this.styleSheet.noTextSelection); this.addClass(this.styleSheet.grabbing); } dragMouseup(event) { document.body.classList.remove(this.styleSheet.noTextSelection); this.removeClass(this.styleSheet.grabbing); } extraNodeAttributes(attr) { super.extraNodeAttributes(attr); attr.addClass(this.styleSheet.grab); } render() { return [<FACollapseIcon ref="collapseIcon" collapsed={false} className={this.styleSheet.collapseIcon}/>, this.options.children]; } setCollapsed(value) { this.collapseIcon.setCollapsed(value); } onMount() { super.onMount(); this.addListener("togglePanel", () => {this.collapseIcon.toggleCollapsed();}); } } @registerStyle(AccordionStyle) class Accordion extends UI.Element { extraNodeAttributes(attr) { attr.addClass(this.styleSheet.accordion); } getChildrenToRender() { let children = []; this.dividers = []; this.panels = []; for (let child of unwrapArray(this.render())) { let title = (child.getTitle ? child.getTitle() : (child.options.title ? child.options.title : "")); let divider = <AccordionDivider>{title}</AccordionDivider>; this.dividers.push(divider); this.panels.push(child); children.push(divider); children.push(child); } return children; } getNextVisibleChild(index) { for (let i = index; i < this.panels.length; i += 1) { if (!this.panels[i].hasClass("hidden")) { return this.panels[i]; } } return null; } getPreviousVisibleChild(index) { for (let i = index - 1; i >= 0; i -= 1) { if (!this.panels[i].hasClass("hidden")) { return this.panels[i]; } } return null; } dividerMousedownFunction(dividerEvent) { let dragTriggered, panelsHeight, totalFlex; let previousEvent = dividerEvent.domEvent; let index = this.dividers.indexOf(dividerEvent.divider); let previousPanel = this.getPreviousVisibleChild(index); let nextPanel = this.getNextVisibleChild(index); panelsHeight = this.getHeight(); for (let divider of this.dividers) { panelsHeight -= divider.getHeight(); } totalFlex = 0; for (let panel of this.panels) { if (!panel.hasClass("hidden")) { totalFlex += parseFloat(getComputedStyle(panel.node, "flex")); } } let mouseMoveListener = this.addListener("dividerMousemove", (event) => { dragTriggered = true; if (index != -1 && nextPanel && previousPanel) { // Calculate the height to transfer from one panel to another let delta = (Device.getEventY(event) - Device.getEventY(previousEvent)) * totalFlex / panelsHeight; let nextSize = parseFloat(getComputedStyle(nextPanel.node, "flex")); let previousSize = parseFloat(getComputedStyle(previousPanel.node, "flex")); // Cap the delta value, to at most zero our panels delta = Math.sign(delta) * Math.min(Math.abs(delta), (delta > 0 ? nextSize : previousSize)); nextPanel.setStyle("flex", nextSize - delta); previousPanel.setStyle("flex", previousSize + delta); previousEvent = event; this.dispatch("dragging"); } }); let mouseUpListener = this.addListener("dividerMouseup", () => { if (!dragTriggered) { dividerEvent.divider.dispatch("togglePanel"); this.toggleChild(this.panels[index]); } mouseMoveListener.remove(); mouseUpListener.remove(); this.dispatch("childrenStatusChange"); }); } toggleChild(child) { let totalFlex = 0; for (let panel of this.panels) { if (!panel.hasClass("hidden")) { totalFlex += parseFloat(getComputedStyle(panel.node, "flex")); } } let sign = child.hasClass("hidden") ? 1 : -1; totalFlex += sign * parseFloat(getComputedStyle(child, "flex")); child.toggleClass("hidden"); if (totalFlex < 1) { for (let panel of this.panels) { if (!panel.hasClass("hidden") && parseFloat(getComputedStyle(panel.node, "flex")) < 1) { panel.setStyle("flex", 1); } } } } getChildrenStatus() { let childrenStatus = []; for (let panel of this.panels) { childrenStatus.push({ flex: getComputedStyle(panel.node, "flex"), collapsed: panel.hasClass("hidden") }); } return childrenStatus; } getDefaultChildrenStatus() { let childrenStatus = []; for (let panel of this.panels) { childrenStatus.push({ flex: 1, collapsed: false }) } return childrenStatus; } setChildrenStatus(childrenStatus) { for (let i = 0; i < childrenStatus.length; i += 1) { this.panels[i].setStyle("flex", childrenStatus[i].flex); let collapsed = childrenStatus[i].collapsed; if (collapsed) { this.panels[i].addClass("hidden"); } else { this.panels[i].removeClass("hidden"); } this.dividers[i].setCollapsed(collapsed); } } onMount() { this.addListener("dividerMousedown", (dividerEvent) => this.dividerMousedownFunction(dividerEvent)); } } export {Accordion};