stem-core
Version:
Frontend and core-library framework
213 lines (172 loc) • 5.91 kB
JSX
import {UI} from "../UIBase";
import {Switcher} from "../Switcher";
import {Link} from "../UIPrimitives";
import {SingleActiveElementDispatcher} from "../../base/Dispatcher";
import {registerStyle} from "../style/Theme";
import {DefaultTabAreaStyle} from "./Style";
import {unwrapArray} from "../../base/Utils";
class BasicTabTitle extends Link {
extraNodeAttributes(attr) {
attr.addClass(this.styleSheet.tab);
if (this.options.active) {
attr.addClass(this.styleSheet.activeTab);
}
}
getDefaultOptions() {
return {
newTab: false,
}
}
canOverwrite(existingElement) {
// Disable reusing with different panels, since we want to attach listeners to the panel
return super.canOverwrite(existingElement) && this.options.panel === existingElement.options.panel;
}
setActive(active) {
this.options.active = active;
this.redraw();
if (active) {
this.options.activeTabDispatcher.setActive(this.getPanel(), () => {
this.setActive(false);
});
}
}
getPanel() {
return this.options.panel;
}
getTitle() {
if (this.options.title) {
return this.options.title;
}
let panel = this.getPanel();
if (typeof panel.getTitle === "function") {
return panel.getTitle();
}
return panel.options.title;
}
render() {
return [this.getTitle()];
}
onMount() {
super.onMount();
if (this.options.active) {
this.setActive(true);
}
this.addClickListener(() => {
this.setActive(true);
});
if (this.options.panel && this.options.panel.addListener) {
this.attachListener(this.options.panel, "show", () => {
this.setActive(true);
});
}
}
}
class TabTitleArea extends UI.Element {
}
class TabArea extends UI.Element {
activeTabDispatcher = new SingleActiveElementDispatcher();
getDefaultOptions() {
return {
autoActive: true, // means the first Tab will be automatically selected
// lazyRender: true, // TODO: should be true by default
panelClass: null, // Custom css class can be added to panels
titleAreaClass: null, // Custom css class can be added to title area
}
}
extraNodeAttributes(attr) {
attr.addClass(this.styleSheet.tabArea);
}
createTabPanel(panel) {
let tab = <BasicTabTitle panel={panel} activeTabDispatcher={this.activeTabDispatcher}
active={panel.options.active} href={panel.options.tabHref}
styleSheet={this.styleSheet} />;
return [tab, panel];
}
appendChild(panel, doMount) {
let [tabTitle, tabPanel] = this.createTabPanel(panel);
this.options.children.push(panel);
this.titleArea.appendChild(tabTitle);
this.switcherArea.appendChild(tabPanel, doMount || !this.options.lazyRender);
};
getTitleArea(tabTitles) {
let titleAreaClass = this.styleSheet.nav;
if (this.options.titleAreaClass) {
titleAreaClass += " " + this.options.titleAreaClass;
}
return <TabTitleArea ref="titleArea" className={titleAreaClass}>
{tabTitles}
</TabTitleArea>;
}
getSwitcher(tabPanels) {
let switcherClass = this.styleSheet.switcher;
if (this.options.panelClass) {
switcherClass += " " + this.options.panelClass;
}
return <Switcher className={switcherClass} ref="switcherArea" lazyRender={this.options.lazyRender}>
{tabPanels}
</Switcher>;
}
getChildrenToRender() {
let tabTitles = [];
let tabPanels = [];
let activeTab;
for (const panel of unwrapArray(this.render())) {
let [tabTitle, tabPanel] = this.createTabPanel(panel);
if (this.activePanel === tabPanel) {
activeTab = tabTitle;
}
tabTitles.push(tabTitle);
tabPanels.push(tabPanel);
}
if (!activeTab) {
for (const tabTitle of tabTitles) {
if (tabTitle.options.active) {
activeTab = tabTitle;
}
}
} else {
for (let i = 0; i < tabPanels.length; i += 1) {
const tabTitle = tabTitles[i];
const tabPanel = tabPanels[i];
if (tabTitle.options.active) {
tabTitle.options.active = false;
}
if (tabPanels.options.active) {
tabPanels.options.active = false;
}
if (activeTab === tabTitle) {
tabPanel.options.active = true;
tabTitle.options.active = true;
}
}
}
if (this.options.autoActive && !activeTab && tabTitles.length > 0) {
tabTitles[0].options.active = true;
}
return [
this.getTitleArea(tabTitles),
this.getSwitcher(tabPanels),
];
};
setActive(panel) {
this.activeTabDispatcher.setActive(panel);
}
getActive() {
return this.activeTabDispatcher.getActive();
}
onSetActive(panel) {
this.switcherArea.setActive(panel);
this.activePanel = panel;
}
onMount() {
this.attachListener(this.activeTabDispatcher, (panel) => {
this.onSetActive(panel);
});
this.addListener("resize", () => {
this.switcherArea.dispatch("resize");
});
}
}
export * from "./Style";
export {TabTitleArea, BasicTabTitle, TabArea};