import { html, PropertyValueMap, unsafeCSS } from "lit";
import { property, query, state } from "lit/decorators.js";
import eleStyle from "./f-tab.scss?inline";
import globalStyle from "./f-tab-global.scss?inline";
import { FRoot } from "../../mixins/components/f-root/f-root";
import { FDiv } from "../f-div/f-div";
import { FTabNode } from "../f-tab-node/f-tab-node";
import { FIconButton } from "../f-icon-button/f-icon-button";
import { flowElement } from "./../../utils";
import { injectCss } from "@cldcvr/flow-core-config";
injectCss("f-tab", globalStyle);
export type FTabNodeWidthProp = "fill" | "hug-content" | `${number}`;
@flowElement("f-tab")
export class FTab extends FRoot {
/**
* css loaded from scss file
*/
static styles = [
unsafeCSS(eleStyle),
unsafeCSS(globalStyle),
...FDiv.styles,
...FIconButton.styles
];
/**
* id selecteor for f-tab-section
*/
@query("#f-tab-section")
tabSection!: FDiv;
/**
* local state for showing and vanishing scroll-icons
*/
@state()
showScrollIcons = false;
/**
* localState to check whether on overflow, scroll exists or not
*/
@state()
isOverflowing = false;
/**
* @attribute Variants are various representations of f-tab. f-tab can have filled tabs, or transparent tabs.
*/
@property({ type: String, reflect: true })
variant?: "fill" | "transparent" = "transparent";
/**
* @attribute Vertical tabs can be enabled using direction property. By default tabs are horizontal.
*/
@property({ type: String, reflect: true })
direction: "horizontal" | "vertical" = "horizontal";
/**
* @attribute The alignment property aligns a f-tab content with respect to the parent container.
For horizontal f-tab, content can align to left, center, or right.
For vertical f-tab, content can align to top, middle, or bottom.
*/
@property({ type: String, reflect: true })
alignment?: "left" | "right" | "center" | "top" | "bottom" | "middle" = "left";
/**
* @attribute width of `f-tab-node`
*/
@property({ type: String, reflect: true, attribute: "node-width" })
nodeWidth?: FTabNodeWidthProp = "hug-content";
/**
* return alignment of the tabs according to the scroll-bar and directions+alignment conditions.
*/
get tabsAlignment() {
if (!this.isOverflowing) {
if (this.direction === "horizontal") {
if (this.alignment === "right") {
return "top-right";
} else if (this.alignment === "center") {
return "top-center";
} else {
return "top-left";
}
} else {
if (this.alignment === "bottom") {
return "bottom-left";
} else if (this.alignment === "middle") {
return "middle-left";
} else {
return "top-left";
}
}
} else {
return "top-left";
}
}
/**
*
* @param e MouseEvtn
* @param position name of the position
* @param positionValue value of the position
*/
handleScroll(e: MouseEvent, position: "left" | "top", positionValue: number) {
e.stopPropagation();
this.tabSection.scrollBy({
[position]: positionValue,
behavior: "smooth"
});
}
/**
* @return return true/false according to the scroll present in the tab view or not.
*/
checkOverflowing() {
let isOverflowing;
if (this.direction === "vertical") {
isOverflowing = this.tabSection.clientHeight < this.tabSection.scrollHeight;
} else {
isOverflowing = this.tabSection.clientWidth < this.tabSection.scrollWidth;
}
return isOverflowing;
}
render() {
/**
* assign attribute direction to child `f-tab` components to align border-positioning accordingly.
*/
for (let i = 0; i < this.children.length; i++) {
this.children[i].setAttribute("direction", this.direction ?? "horizontal");
(this.children[i] as FTabNode).width = this.nodeWidth;
}
/**
* first scroll icon
*/
const firstScrollButton =
this.showScrollIcons && this.isOverflowing
? html`
${this.direction === "horizontal"
? html` this.handleScroll(e, "left", -150)}
>`
: html` this.handleScroll(e, "top", -150)}
>`}`
: "";
const lastScrollButton =
this.showScrollIcons && this.isOverflowing
? html`
${this.direction === "horizontal"
? html` this.handleScroll(e, "left", 150)}
>`
: html` this.handleScroll(e, "top", 150)}
>`}
`
: "";
/**
* Final html to render
*/
return html` (this.showScrollIcons = true)}
@mouseleave=${() => (this.showScrollIcons = false)}
overflow="hidden"
.height=${this.direction === "vertical" ? "100%" : "fill-container"}
>
${firstScrollButton}
${lastScrollButton}
`;
}
protected updated(changedProperties: PropertyValueMap | Map) {
super.updated(changedProperties);
/**
* on every update check if scroll is present or not
*/
this.isOverflowing = this.checkOverflowing();
}
}
/**
* Required for typescript
*/
declare global {
interface HTMLElementTagNameMap {
"f-tab": FTab;
}
}