irisrad-ui
Version:
UI elements developered for IRIS R&D Group Inc
278 lines (258 loc) • 8.47 kB
JavaScript
/**
* IRIS R&D Group Inc. All rights reserved.
*
* Author: Lucien Chu
* Create Date: Apr 07, 2021
*
* Description: This is a wrapper of header
* A header should has the following components
* 1. the company logo
* provided as regular html img component
*
* 2. some some navigation links
* these component are optional, if they are given, they are positioned on the right hand side
* of the header
*
* 3. user name:
* logged in user's name, position next to the user icon buton
*
* 4. hidden links:
* some navigation links about the user, ie: profile, logout btn etc, the are not display until
* user click on the predefined user icon button
*
* 5. fade in element:
* elemets that would position below the header, a button would be posisiton on the header component
* which is used to toggle its fade in and fade out animation.
*/
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import { IrisMenuIcon } from "../irisIconButtons";
import "../../style/styles.css";
import { IrisDropDownMenu } from "../irisDropDownMenu/IrisDropDownMenu";
import { IrisButton } from "../irisButton/IrisButton";
const HEADER_VARIANTS = ["primary", "secondary"];
let timeoutFunction;
const toggleFadeInWrapper = (event) => {
// find header by its id
const toggleBtn = event.target;
const header = document.getElementById("iris-header");
if (header) {
// find the slide wrapper within the header
const slideDownOverlay = header.querySelector(".slide-down-overlay");
const slidDownContent = header.querySelector(".slide-down-wrapper");
if (slideDownOverlay && slidDownContent) {
const { classList: overlayClassList } = slideDownOverlay;
const { classList: contentClassList } = slidDownContent;
// const height = slidDownContent.scrollHeight;
if (timeoutFunction) {
clearTimeout(timeoutFunction);
timeoutFunction = null;
}
// content is currently shown
if (overlayClassList.contains("show")) {
// fade out content
contentClassList.toggle("fade-in");
header.classList.toggle("hide-shadow");
// document.body.style.overflow = "";
document.body.classList.remove("prevent-scroll");
// mark wrapper as display none
timeoutFunction = setTimeout(() => {
overlayClassList.toggle("show");
toggleBtn.classList.toggle(
"active",
overlayClassList.contains("show")
);
}, 300);
}
// content is not shown
else {
// display wrapper
overlayClassList.toggle("show");
// delay to fade in content
timeoutFunction = setTimeout(() => {
contentClassList.toggle("fade-in");
header.classList.toggle("hide-shadow");
// document.body.style.overflow = "hidden";
document.body.classList.add("prevent-scroll");
}, 100);
}
// highlight the toggle btn
toggleBtn.classList.toggle("active", overlayClassList.contains("show"));
}
}
};
export function IrisHeader({
className = "",
variant,
links,
logoComponent,
headerTitle,
actionButtons,
fadeInContent,
hiddenLinks,
menuBtnSize = "small",
userName = "",
...props
}) {
let headerStyle = "";
if (HEADER_VARIANTS.indexOf(variant) >= 0) {
headerStyle = `iris-header--${variant}`;
}
if (typeof className === "string" && className !== "") {
headerStyle += " " + className;
}
let hideenItems;
if (hiddenLinks) {
hideenItems = hiddenLinks.map((link) => (
<a href="#" onClick={link.onClick}>
{link.label}
</a>
));
}
useEffect(() => {
const ele = document.getElementById("iris-header");
const as = ele.querySelectorAll("a");
as.forEach((a) => {
a.onclick = () => {
as.forEach((a) => a.classList.remove("active"));
if (!a.classList.contains("active")) {
a.classList.add("active");
}
};
});
}, []);
// fade in content is provided
if (fadeInContent?.toggleBtnProps) {
const { btnTitle, size, iconProps } = fadeInContent.toggleBtnProps;
const toggleBtn = (
<IrisButton
onClick={toggleFadeInWrapper}
size={size}
iconProps={iconProps}
data-type="data-type"
>
{btnTitle}
</IrisButton>
);
// action buttons would be display on the header
// make the toggle button as the first element of
// the list so that it would be arranged on the
// left most position
if (actionButtons && Array.isArray(actionButtons)) {
actionButtons.unshift(toggleBtn);
} else {
actionButtons = [toggleBtn];
}
}
return (
<header id="iris-header" className={headerStyle} {...props}>
<nav className="iris-header-nav">
<div className="logo">{logoComponent}</div>
{/* header title */}
{headerTitle && <h2 className="header-title">{headerTitle}</h2>}
{/* action buttons */}
{actionButtons && (
<div className="action-btn-wrapper">
{actionButtons.map((Button, index) => (
<div key={index}>{Button}</div>
))}
</div>
)}
{links && (
<>
<label
htmlFor="iris-header-menu-toggle"
className="iris-header-menu-toggle-button"
>
<IrisMenuIcon size={menuBtnSize} />
</label>
<input type="checkbox" id="iris-header-menu-toggle" />
<ul className="nav-list">
{links.map((link) => (
<li key={link.label}>{link.node}</li>
))}
</ul>
</>
)}
<span
className="iris-header__user-name-wrapper"
style={{
marginLeft: "auto",
marginRight: "0.725rem",
fontSize: "1.375rem",
}}
>
{userName}
</span>
{hiddenLinks && (
<div className="hidden-content-wrapper">
<IrisDropDownMenu
menuItems={hideenItems}
style={{ color: "#737373" }}
menuProps={{
alignment: "right",
}}
/>
</div>
)}
</nav>
{/* element to be faded in and out */}
{fadeInContent?.element && (
<div
className="slide-down-overlay"
onClick={(event) => {
if (event.target === event.currentTarget) {
const header = document.getElementById("iris-header");
if (header) {
const toggleBtn = header.querySelector(
`[data-type="data-type"]`
);
if (toggleBtn) {
toggleBtn.click();
}
}
}
}}
>
<div className="slide-down-wrapper">
<div className="slide-down-content">{fadeInContent.element}</div>
</div>
</div>
)}
</header>
);
}
IrisHeader.propTypes = {
className: PropTypes.string,
variant: PropTypes.oneOf(HEADER_VARIANTS),
logoComponent: PropTypes.node, // html node that could represent company logo
headerTitle: PropTypes.string, // header title
actionButtons: PropTypes.arrayOf(PropTypes.node),
useName: PropTypes.string, // logged in user name
// navigation links
links: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
onClick: PropTypes.func,
})
),
// links hidden by defeault, togglable by clicking the user icon
hiddenLinks: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
onClick: PropTypes.func,
})
),
fadeInContent: PropTypes.shape({
toggleBtnProps: PropTypes.shape({
btnTitle: PropTypes.string.isRequired,
size: PropTypes.oneOf(["small", "medium", "large"]),
iconProps: PropTypes.shape({
variant: PropTypes.string,
size: PropTypes.string,
iconTitle: PropTypes.string.isRequired,
}),
}).isRequired,
element: PropTypes.node.isRequired,
}),
};