import { HTMLWidget, Text, Widget } from "@hpcc-js/common";
import { select as d3Select } from "d3-selection";
import { Surface } from "./Surface.ts";
import "../src/Tabbed.css";
export class Tabbed extends HTMLWidget {
_tabContainer;
_contentContainer;
constructor() {
super();
this._tag = "div";
}
clearTabs() {
this.labels([]);
this.widgets([]);
return this;
}
addTab(widget, label, isActive?, callback?) {
const widgetSize = widget.size();
if (widgetSize.width === 0 && widgetSize.height === 0) {
widget.size({ width: "100%", height: "100%" });
}
const labels = this.labels();
const widgets = this.widgets();
if (isActive) {
this.activeTabIdx(this.widgets().length);
}
labels.push(label);
const surface = new Surface().widget(widget ? widget : new Text().text("No widget defined for tab"));
widgets.push(surface);
this.labels(labels);
this.widgets(widgets);
if (callback) {
callback(surface);
}
return this;
}
widgetSize(widgetDiv) {
const width = this.clientWidth();
let height = this.clientHeight();
const tcBox = this._tabContainer.node().getBoundingClientRect();
if (typeof (tcBox.height) !== "undefined") {
height -= tcBox.height;
}
return { width, height };
}
enter(domNode, element) {
super.enter(domNode, element);
this._tabContainer = element.append("div");
this._contentContainer = element.append("div");
}
update(domNode, element) {
super.update(domNode, element);
const context = this;
element.style("padding", this.surfacePadding_exists() ? this.surfacePadding() + "px" : null);
const tabs = this._tabContainer.selectAll(".tab-button.id" + this.id()).data(this.showTabs() ? this.labels() : [], function (d) { return d; });
tabs.enter().append("span")
.attr("class", "tab-button id" + this.id())
.style("cursor", "pointer")
.on("click", function (d, idx) {
context.click(context.widgets()[idx].widget(), d, idx);
context
.activeTabIdx(idx)
.render()
;
}).merge(tabs)
.classed("active", function (d, idx) { return context.activeTabIdx() === idx; })
.text(function (d) { return d; })
;
tabs.exit().remove();
const content = this._contentContainer.selectAll(".tab-content.id" + this.id()).data(this.widgets(), function (d) { return d.id(); });
content.enter().append("div")
.attr("class", "tab-content id" + this.id())
.each(function (widget, idx) {
widget.target(this);
}).merge(content)
.classed("active", function (d, idx) { return context.activeTabIdx() === idx; })
.style("display", function (d, idx) { return context.activeTabIdx() === idx ? "block" : "none"; })
.each(function (surface, idx) {
surface.visible(context.activeTabIdx() === idx);
if (context.activeTabIdx() === idx) {
const wSize = context.widgetSize(d3Select(this));
surface
.surfaceBorderWidth(context.showTabs() ? null : 0)
.surfacePadding(context.showTabs() ? null : 0)
.resize(wSize)
;
}
})
;
content.exit()
.each(function (widget, idx) {
widget
.target(null)
;
})
.remove();
switch (this.tabLocation()) {
case "bottom":
this._tabContainer
.attr("class", "on_bottom")
.style("top", (this._contentContainer.node().offsetHeight + this.surfacePadding()) + "px")
.style("position", "absolute")
;
this._contentContainer
.style("top", this.surfacePadding_exists() ? this.surfacePadding() + "px" : null)
.style("position", "absolute")
;
break;
default:
this._tabContainer
.attr("class", "on_top")
.style("top", null)
.style("position", "relative")
;
this._contentContainer
.style("top", (this._tabContainer.node().offsetHeight + this.surfacePadding()) + "px")
.style("position", "absolute")
;
break;
}
}
click(widget, column, idx) {
}
}
Tabbed.prototype._class += " layout_Tabbed";
export interface Tabbed {
showTabs(): boolean;
showTabs(_: boolean): this;
surfacePadding(): number;
surfacePadding(_: number): this;
surfacePadding_exists(): boolean;
activeTabIdx(): number;
activeTabIdx(_: number): this;
labels(): string[];
labels(_: string[]): this;
tabLocation(): "top" | "bottom";
tabLocation(_: "top" | "bottom"): this;
widgets(): any[];
widgets(_: any[]): this;
}
Tabbed.prototype.publish("showTabs", true, "boolean", "Show Tabs", null, {});
Tabbed.prototype.publish("surfacePadding", 4, "number", "Padding");
Tabbed.prototype.publish("activeTabIdx", 0, "number", "Index of active tab", null, {});
Tabbed.prototype.publish("labels", [], "array", "Array of tab labels sharing an index with ", null, { tags: ["Private"] });
Tabbed.prototype.publish("tabLocation", "top", "set", "Position the tabs at the bottom of the widget", ["top", "bottom"], { tags: ["Private"] });
Tabbed.prototype.publish("widgets", [], "widgetArray", "widgets", null, { tags: ["Private"] });