import { HTMLWidget } from "@hpcc-js/common"; import { select as d3Select } from "d3-selection"; import "../src/FlexGrid.css"; export class FlexGrid extends HTMLWidget { constructor() { super(); } enter(domNode, element) { super.enter(domNode, element); d3Select(domNode.parentNode) .style("height", "100%") .style("width", "100%") ; } update(domNode, element) { super.update(domNode, element); const context = this; const cachedSizes = []; this.updateFlexParent(element); const listItems = element.selectAll(".FlexGrid-list-item").data(this.widgets(), w => w.id()); listItems.enter() .append("div") .classed("FlexGrid-list-item", true) .each(function (w) { w.target(this); }) .merge(listItems) .style("min-height", this.itemMinHeight() + "px") .style("min-width", this.itemMinWidth() + "px") .style("flex-basis", (n, i) => { const flexBasis = this.widgetsFlexBasis()[i]; return typeof flexBasis !== "undefined" ? flexBasis : this.flexBasis(); }) .style("flex-grow", (n, i) => { const flexGrow = this.widgetsFlexGrow()[i]; return typeof flexGrow !== "undefined" ? flexGrow : this.flexGrow(); }) .style("border-width", this.borderWidth() + "px") .style("border-color", this.itemBorderColor()) .each(function () { this.firstChild.style.display = "none"; }) .each(function () { const rect = this.getBoundingClientRect(); cachedSizes.push([ rect.width, rect.height ]); }) .each(function (w, i) { this.firstChild.style.display = "block"; w.resize({ width: cachedSizes[i][0] - (2 * context.borderWidth()), height: cachedSizes[i][1] - (2 * context.borderWidth()) }); }) ; listItems.exit().remove(); } exit(domNode, element) { super.exit(domNode, element); } updateFlexParent(element) { element .style("height", "100%") .style("flex-direction", this.orientation() === "horizontal" ? "row" : "column") .style("flex-wrap", this.flexWrap()) .style("align-items", this.alignItems()) .style("align-content", this.alignContent()) .style("overflow-x", () => { if (this.forceXScroll() || (this.orientation() === "horizontal" && this.flexWrap() === "nowrap" && !this.disableScroll())) { return "scroll"; } return "hidden"; }) .style("overflow-y", () => { if (this.forceYScroll() || (this.orientation() === "vertical" && this.flexWrap() === "nowrap" && !this.disableScroll())) { return "scroll"; } return "hidden"; }) ; } } FlexGrid.prototype._class += " layout_FlexGrid"; export interface FlexGrid { widgets(): any; widgets(_: any): this; orientation(): "horizontal" | "vertical"; orientation(_: "horizontal" | "vertical"): this; flexWrap(): "nowrap" | "wrap" | "wrap-reverse"; flexWrap(_: "nowrap" | "wrap" | "wrap-reverse"): this; itemMinHeight(): number; itemMinHeight(_: number): this; itemMinWidth(): number; itemMinWidth(_: number): this; alignItems(): "flex-start" | "center" | "flex-end" | "stretch"; alignItems(_: "flex-start" | "center" | "flex-end" | "stretch"): this; alignContent(): "flex-start" | "center" | "flex-end" | "stretch" | "space-between" | "space-around"; alignContent(_: "flex-start" | "center" | "flex-end" | "stretch" | "space-between" | "space-around"): this; itemBorderColor(): string; itemBorderColor(_: string): this; borderWidth(): number; borderWidth(_: number): this; flexGrow(): number; flexGrow(_: number): this; widgetsFlexGrow(): number[]; widgetsFlexGrow(_: number[]): this; flexBasis(): string; flexBasis(_: string): this; widgetsFlexBasis(): string[]; widgetsFlexBasis(_: string[]): this; disableScroll(): boolean; disableScroll(_: boolean): this; forceXScroll(): boolean; forceXScroll(_: boolean): this; forceYScroll(): boolean; forceYScroll(_: boolean): this; } FlexGrid.prototype.publish("itemBorderColor", "transparent", "html-color", "Color of list item borders"); FlexGrid.prototype.publish("borderWidth", 0, "number", "Width of list item borders (pixels)"); FlexGrid.prototype.publish("orientation", "horizontal", "set", "Controls the flex-direction of the list items", ["horizontal", "vertical"]); FlexGrid.prototype.publish("flexWrap", "wrap", "set", "Controls the line wrap when overflow occurs", ["nowrap", "wrap", "wrap-reverse"]); FlexGrid.prototype.publish("disableScroll", false, "boolean", "If false, scrollbar will show (when flexWrap is set to 'nowrap')", null, { disable: (w: any) => w.flexWrap() !== "nowrap" }); FlexGrid.prototype.publish("forceXScroll", false, "boolean", "If true, horzontal scrollbar will show"); FlexGrid.prototype.publish("forceYScroll", false, "boolean", "If true, vertical scrollbar will show"); FlexGrid.prototype.publish("itemMinHeight", 64, "number", "Minimum height of a list item (pixels)"); FlexGrid.prototype.publish("itemMinWidth", 64, "number", "Minimum width of a list item (pixels)"); FlexGrid.prototype.publish("alignItems", "stretch", "set", "Controls normal alignment of items", ["flex-start", "center", "flex-end", "stretch"]); FlexGrid.prototype.publish("alignContent", "stretch", "set", "Controls normal alignment of item rows", ["flex-start", "center", "flex-end", "stretch", "space-between", "space-around"]); FlexGrid.prototype.publish("flexGrow", 1, "number", "Default flex-grow style for all list items"); FlexGrid.prototype.publish("flexBasis", "10%", "string", "Default flex-basis style for all list items"); FlexGrid.prototype.publish("widgetsFlexGrow", [], "array", "Array of flex-grow values keyed on the widgets array"); FlexGrid.prototype.publish("widgetsFlexBasis", [], "array", "Array of flex-basis values keyed on the widgets array"); FlexGrid.prototype.publish("widgets", [], "widgetArray", "Array of widgets to be rendered as list items");