@lote-design-system/marketing-blocks
Version:
522 lines (485 loc) • 17.4 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled, { css, keyframes } from 'styled-components';
import { rem } from 'polished';
import { LogoDefault } from '../svg';
import { Icon } from '@lote-design-system/icons';
import { Container, Button, useWindowSize } from '@lote-design-system/core'; // => Dependent styled-components
// Our main component depends upon the following styled-components
const NavBar = styled.nav.withConfig({
displayName: "NavBar2__NavBar",
componentId: "fv1p0z-0"
})(["padding:", " 0;", ";", ";", ";"], rem(16), ({
fixed
}) => {
if (fixed === 'top') {
return css(["position:fixed;top:0;right:0;left:0;z-index:1030;"]);
} else if (fixed === 'bottom') {
return css(["position:fixed;right:0;bottom:0;left:0;z-index:1030;"]);
} else {
return css([""]);
}
}, ({
sticky
}) => {
if (sticky) {
return css(["@supports ((position:-webkit-sticky) or (position:sticky)){position:sticky;top:0;z-index:1020;}"]);
} else {
return css([""]);
}
}, ({
styled
}) => {
if (styled) {
return css(["&{", ";}"], styled);
}
}); // This container is very important component for the Nav aligning
const ContainerModify = styled(Container).withConfig({
displayName: "NavBar2__ContainerModify",
componentId: "fv1p0z-1"
})(["position:relative;display:flex;flex-wrap:wrap;align-items:center;", " justify-content:space-between;max-width:", ";"], ''
/* Remember this is a very important property if you remove it your NavBarStart, NavBarEnd and BurgerButton
will not display left of even right side of the bar. */
, ({
theme
}) => theme.maxContainerWidth);
const NavBarBrand = styled.a.withConfig({
displayName: "NavBar2__NavBarBrand",
componentId: "fv1p0z-2"
})(["display:inline-flex;align-items:center;padding:", " 0;white-space:nowrap;margin-right:", ";> svg,> img{width:56px;height:56px;}}}"], rem(4), rem(64));
const NavBarButtonToggler = styled(Button).withConfig({
displayName: "NavBar2__NavBarButtonToggler",
componentId: "fv1p0z-3"
})(["width:48px;height:48px;padding:", " ", ";display:inline-flex;justify-content:center;align-items:center;", "{display:none;}"], rem(4), rem(12), ({
theme
}) => theme.mediaQueries.lg);
const navbarOverlayOpacity = keyframes(["0%{opacity:0;}100%{opacity:1;}"]);
const NavBarPlate = styled.div.withConfig({
displayName: "NavBar2__NavBarPlate",
componentId: "fv1p0z-4"
})(["", " display:none;", " ", "{display:flex;align-items:center;flex-grow:1;}@media (max-width:991px){display:block;position:fixed;z-index:", ";width:0;height:100%;transition:transform 0.4s linear,height 0s ease 0.4s,width 0s ease 0.4s;top:0;", " ", "}"], ''
/* Default NavBarPlate will be disabled on Mobile devices. */
, ''
/* NavBarPlate will be enabled on Desktop devices. */
, ({
theme
}) => theme.mediaQueries.lg, ({
zIndex
}) => zIndex, props => {
if (props.placement === 'left') {
return {
left: 0
};
} else if (props.placement === 'right') {
return {
right: 0
};
}
}, props => props.visible && css(["width:100%;transition:transform 0.4s linear;", "{height:100%;opacity:1;transition:none;animation:", " 0.4s linear;}", "{visibility:visible;", "}"], NavBarOverlay, navbarOverlayOpacity, NavBarMenu, props => {
if (props.placement === 'left') {
return {
transform: 'translateX(100%)'
};
} else if (props.placement === 'right') {
return {
transform: 'translateX(-100%)'
};
}
}));
const NavBarOverlay = styled.div.withConfig({
displayName: "NavBar2__NavBarOverlay",
componentId: "fv1p0z-5"
})(["@media (max-width:991px){position:fixed;top:0;left:0;width:100%;height:0;opacity:0;transition:opacity 0.4s linear,height 0s ease 0.4s;background-color:rgba(0,0,0,0.7);}"]); // NavBarMenu is important component because all placement of links depend upon this.
const NavBarMenu = styled.div.withConfig({
displayName: "NavBar2__NavBarMenu",
componentId: "fv1p0z-6"
})(["", " ", "{display:flex;align-items:center;flex-grow:1;}@media (max-width:991px){", ";position:fixed;", ";height:100%;background-color:#ffffff;overflow-y:auto;visibility:hidden;transition:transform 0.2s linear,visibility 0.2s linear;}"], ''
/* Styling for the NavBarMenu will be disabled on Desktop devices. */
, ({
theme
}) => theme.mediaQueries.lg, ({
theme,
placement
}) => {
if (placement === 'left') {
return {
boxShadow: theme.shadowSide.right,
right: '100%'
};
} else if (placement === 'right') {
return {
boxShadow: theme.shadowSide.left,
left: '100%'
};
}
}, ({
w
}) => {
if (typeof w === 'number') {
return css(["width:", "px;"], w);
} else if (typeof w === 'string') {
return css(["width:", ";"], w);
} else {
return css(["width:", "px;"], w);
}
});
const NavBarHeader = styled.div.withConfig({
displayName: "NavBar2__NavBarHeader",
componentId: "fv1p0z-7"
})(["display:none;@media (max-width:991px){display:flex;flex-wrap:wrap;align-items:center;border-bottom:1px solid #f8f8f8;", ""], ({
hasTitle,
hasClosable
}) => {
if (hasTitle && hasClosable) {
return css(["justify-content:space-between;padding:", " ", ";"], rem(8), rem(18));
} else if (hasTitle && !hasClosable) {
return css(["padding:", ";"], rem(18));
} else if (!hasTitle && hasClosable) {
return css(["justify-content:flex-end;padding:", " ", ";"], rem(8), rem(18));
}
});
const NavBarText = styled.span.withConfig({
displayName: "NavBar2__NavBarText",
componentId: "fv1p0z-8"
})(["font-size:", ";font-weight:500;color:", ";"], rem(16), ({
theme: {
colors
}
}) => colors.text.title);
const NavBarCloseButton = styled(Button).withConfig({
displayName: "NavBar2__NavBarCloseButton",
componentId: "fv1p0z-9"
})(["width:46px;height:46px;padding:", ";font-size:", ";"], rem(4), rem(18)); // NavBarStart Section i.e. unordered list display on the left side
// =================================================================
// Anchor
const NavBarStartLink = styled.a.withConfig({
displayName: "NavBar2__NavBarStartLink",
componentId: "fv1p0z-10"
})(["font-size:", ";color:", ";display:block;font-weight:500;padding:", " ", ";transition:color 0.4s linear;&:hover{color:", ";}"], rem(14), ({
theme: {
colors
}
}) => colors.text.primary, rem(8), rem(16), ({
theme: {
colors
}
}) => colors.primary); // ListItem
const NavBarStartItem = styled.li.withConfig({
displayName: "NavBar2__NavBarStartItem",
componentId: "fv1p0z-11"
})(["", ";"], props => props.active && css(["> ", "{color:", ";}"], NavBarStartLink, ({
theme: {
colors
}
}) => colors.primary)); // Unordered List
const NavBarStart = styled.ul.withConfig({
displayName: "NavBar2__NavBarStart",
componentId: "fv1p0z-12"
})(["", " ", " padding:", ";margin-bottom:0;list-style:none;", "{display:flex;align-items:center;padding:0;margin-right:auto;}"], ''
/* These styles will appear on both Desktop & Mobile devices. */
, ''
/* But the bottom padding property will be only applied on Mobile Devices.
Basically, It will add the padding on the list container. */
, rem(14), ({
theme
}) => theme.mediaQueries.lg); // End =================================
// NavBarEnd Section i.e. unordered list display on the right side
// =================================================================
// Unordered List
const NavBarEnd = styled.div.withConfig({
displayName: "NavBar2__NavBarEnd",
componentId: "fv1p0z-13"
})(["", " ", " padding:", ";", "{display:flex;align-items:center;padding:0;margin-left:auto;}"], ''
/* These styles will appear on both Desktop & Mobile devices. */
, ''
/* But the bottom padding property will only apply on the Mobile Devices.
Basically, It will add the padding on the list container. */
, rem(14), ({
theme
}) => theme.mediaQueries.lg); // Button
const NavBarEndLinkButton = styled(Button).withConfig({
displayName: "NavBar2__NavBarEndLinkButton",
componentId: "fv1p0z-14"
})(["font-weight:500;margin:", ";@media (max-width:991px){display:block;}"], rem(8)); // End =================================
// <= End Dependent styled-components
const leftLinkShape = {
id: PropTypes.number.isRequired,
href: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
active: PropTypes.bool
};
const variationShape = {
drawerVariation: PropTypes.string.isRequired,
normal: PropTypes.string.isRequired
};
const rightLinkShape = {
id: PropTypes.number.isRequired,
href: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
variation: PropTypes.oneOfType([PropTypes.string, PropTypes.shape(variationShape)]).isRequired,
color: PropTypes.string
};
const leftLinkSchema = [{
id: 1,
href: '/',
text: 'Home',
active: true
}, {
id: 2,
href: '/',
text: 'Features'
}, {
id: 3,
href: '/',
text: 'Pricing'
}, {
id: 4,
href: '/',
text: 'Services'
}, {
id: 5,
href: '/',
text: 'About Us'
}];
const rightLinkSchema = [{
id: 1,
href: '/',
text: 'Login',
variation: {
drawerVariation: 'light',
normal: 'transparent'
},
color: 'primary'
}, {
id: 2,
href: '/',
text: 'Get Started',
variation: 'fill',
color: 'primary'
}];
const propTypes = {
/** Render new styles on the NavBar Container. */
styledCSS: PropTypes.string,
/** Position an element at the top/bottom of the viewport, from edge to edge. Fixed NavBars use
position: fixed, meaning they’re pulled from the normal flow of the DOM and may require
custom CSS (e.g., padding-top on the <body>) to prevent overlap with other elements. */
fixed: PropTypes.oneOf(['top', 'bottom']),
/** Position an element at the top of the viewport, from edge to edge, but only after you scroll past it. */
sticky: PropTypes.bool,
/** Whether a close (X) button is visible on top right of the Drawer dialog or not. */
closable: PropTypes.bool,
/** Whether to show mask or not. */
mask: PropTypes.bool,
/** Clicking on the mask (area outside the Drawer) to close the Drawer or not. */
maskClosable: PropTypes.bool,
/** The title of the Drawer. */
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Width of the Drawer dialog. */
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** The z-index of the Drawer. */
zIndex: PropTypes.number,
/** The placement of the Drawer. */
placement: PropTypes.oneOf(['right', 'left']),
/** The logo appear on the NavBar, default it will be ui-kit logo. */
logo: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Links appear on the left side of the NavBar, same links also render on the Drawer. */
leftLinks: PropTypes.arrayOf(PropTypes.shape(leftLinkShape)).isRequired,
/** Links appear on the right side of the NavBar, same links also render on the Drawer. */
rightLinks: PropTypes.arrayOf(PropTypes.shape(rightLinkShape)).isRequired
};
const defaultProps = {
closable: true,
mask: true,
maskClosable: true,
width: 256,
zIndex: 1000,
placement: 'right',
logo: /*#__PURE__*/React.createElement(LogoDefault, {
fill: "#01a1ff"
}),
leftLinks: leftLinkSchema,
rightLinks: rightLinkSchema
};
/**
* Returns the JSX or null for the logo.
* @param logo {*} - The logo will React.element or a path
* @return {null|*} - Returns the JSX or null
*/
const renderLogo = logo => {
if (React.isValidElement(logo)) {
return logo;
} else if (typeof logo === 'string' && logo.length > 0) {
return /*#__PURE__*/React.createElement("img", {
src: logo,
alt: "Brand Logo"
});
} else {
return null;
}
};
/**
* Render overlay mask on the back of the Drawer.
* @param state {boolean} - Updated value of the state
* @param mask {boolean} - Whether to show mask or not
* @param maskClosable {boolean} - Clicking on the mask to close the Drawer or not
* @param onClose {function} - A function that will be called when a user clicks mask
* @return {null|*} - Returns the JSX or null
*/
const renderMask = (state, mask, maskClosable, onClose) => {
if (mask) {
if (state) {
document.body.style.position = 'relative';
document.body.style.overflow = 'hidden';
document.body.style.width = `calc(${100}% - ${17}px)`;
} else {
document.body.style.position = '';
document.body.style.overflow = '';
document.body.style.width = '';
}
if (maskClosable) {
return /*#__PURE__*/React.createElement(NavBarOverlay, {
onClick: onClose
});
} else {
return /*#__PURE__*/React.createElement(NavBarOverlay, null);
}
} else {
return null;
}
};
/**
* Render header on the Drawer
* @param title {*|string} - The title of the Drawer
* @param closable {boolean} - Whether a close (X) button is visible on top right of the Drawer dialog or not
* @param onClose {function} - A function that will be called when a user clicks the close button
* @return {null|*} - Returns the JSX or null
*/
const renderHeader = (title, closable, onClose) => {
// If title is undefined & closeable is undefined then render nothing, else render deterministic elements
if (!title && !closable) {
return null;
} else {
return /*#__PURE__*/React.createElement(NavBarHeader, {
hasTitle: !!title,
hasClosable: !!closable
}, title && /*#__PURE__*/React.createElement(NavBarText, null, title), closable && /*#__PURE__*/React.createElement(NavBarCloseButton, {
type: "button",
basic: true,
variation: "lightTransparent",
onClick: onClose
}, /*#__PURE__*/React.createElement(Icon, {
name: "x"
})));
}
};
/**
* Render schema for the NavBar
* @param leftData {Array} - Left side schema for the NavBar
* @param rightData {Array} - Right side schema for the NavBar
* @param windowSize {Number} - Size of the browser window
* @return {null|*}
*/
const renderBody = (leftData, rightData, windowSize) => {
if (Array.isArray(leftData) && leftData.length > 0 && Array.isArray(rightData) && rightData.length > 0) {
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(NavBarStart, null, leftData.map(({
id,
href,
text,
active
}) => /*#__PURE__*/React.createElement(NavBarStartItem, {
key: id,
active: active
}, /*#__PURE__*/React.createElement(NavBarStartLink, {
href: href
}, text)))), /*#__PURE__*/React.createElement(NavBarEnd, null, rightData.map(({
id,
href,
text,
variation,
color
}) => {
// Check if variation is an object type then it means user want to use the breakpoints
if (variation != null && (typeof variation === 'object' || typeof variation === 'function')) {
return /*#__PURE__*/React.createElement(NavBarEndLinkButton, {
key: id,
href: href,
variation: windowSize < 992 ? variation.drawerVariation : variation.normal,
color: color
}, text);
} else {
return /*#__PURE__*/React.createElement(NavBarEndLinkButton, {
key: id,
href: href,
variation: variation,
color: color
}, text);
}
})));
} else {
return null;
}
};
export const NavBar2 = props => {
const {
innerWidth
} = useWindowSize();
const {
styledCSS,
fixed,
sticky,
closable,
mask,
maskClosable,
title,
width,
zIndex,
logo: Logo,
leftLinks,
rightLinks,
placement
} = props,
attributes = _objectWithoutProperties(props, ["styledCSS", "fixed", "sticky", "closable", "mask", "maskClosable", "title", "width", "zIndex", "logo", "leftLinks", "rightLinks", "placement"]);
const [visibleDrawer, setVisibleDrawer] = useState(false);
const showDrawer = () => {
setVisibleDrawer(!visibleDrawer);
}; // This will be used inside the Drawer header, close button & MaskOverlay
const onClose = () => {
setVisibleDrawer(false);
}; // Always make sure the Drawer don't show up on the big screen size,
// so the state will always be false.
useEffect(() => {
if (innerWidth > 991) {
setVisibleDrawer(false);
}
}, [innerWidth]);
return /*#__PURE__*/React.createElement(NavBar, _extends({
styled: styledCSS,
fixed: fixed,
sticky: sticky
}, attributes), /*#__PURE__*/React.createElement(ContainerModify, {
fluid: true
}, /*#__PURE__*/React.createElement(NavBarBrand, {
href: "/"
}, renderLogo(Logo)), /*#__PURE__*/React.createElement(NavBarButtonToggler, {
basic: true,
variation: "fill",
color: "primary",
active: visibleDrawer,
onClick: showDrawer
}, visibleDrawer ? /*#__PURE__*/React.createElement(Icon, {
name: "x"
}) : /*#__PURE__*/React.createElement(Icon, {
name: "menu"
})), /*#__PURE__*/React.createElement(NavBarPlate, {
visible: visibleDrawer,
placement: placement,
zIndex: zIndex
}, renderMask(visibleDrawer, mask, maskClosable, onClose), /*#__PURE__*/React.createElement(NavBarMenu, {
w: width,
placement: placement
}, renderHeader(title, closable, onClose), renderBody(leftLinks, rightLinks, innerWidth)))));
};
NavBar2.propTypes = propTypes;
NavBar2.defaultProps = defaultProps;