wix-style-react
Version:
wix-style-react
237 lines (220 loc) • 7.34 kB
JavaScript
import s from './PageHeader.scss';
import React from 'react';
import PropTypes from 'prop-types';
import WixComponent from '../BaseComponents/WixComponent';
import classNames from 'classnames';
import ChevronLeft from 'wix-ui-icons-common/ChevronLeft';
import Breadcrumbs from '../Breadcrumbs';
import Text from '../Text';
import Heading from '../Heading';
import { Animator } from 'wix-animations';
import Button from '../Button';
const animateComponent = (show, useEnterDelay, content) => {
return useEnterDelay ? (
<Animator show={show} opacity timing="medium" delay={{ enter: 100 }}>
{content}
</Animator>
) : (
<Animator show={show} opacity timing="medium">
{content}
</Animator>
);
};
const isDarkTheme = (hasBackgroundImage, minimized) =>
!minimized && hasBackgroundImage;
const getBreadcrumbsTheme = (hasBackgroundImage, minimized) =>
isDarkTheme(hasBackgroundImage, minimized)
? 'onDarkBackground'
: 'onGrayBackground';
const getTitle = (title, minimized) =>
typeof title === 'function' ? title(minimized) : title;
const generateDefaultBreadcrumbs = (title, hasBackgroundImage, minimized) => (
<Breadcrumbs
items={[{ id: '1', value: getTitle(title, minimized) }]}
activeId="1"
size="medium"
theme={getBreadcrumbsTheme(hasBackgroundImage, minimized)}
onClick={() => {}}
/>
);
const generateThemedBreadcrumbs = (
breadcrumbs,
title,
hasBackgroundImage,
minimized,
) => {
if (breadcrumbs) {
return React.cloneElement(breadcrumbs, {
theme: getBreadcrumbsTheme(hasBackgroundImage, minimized),
});
}
return generateDefaultBreadcrumbs(title, hasBackgroundImage, minimized);
};
/**
* A header that sticks at the top of the container which minimizes on scroll
*/
export default class PageHeader extends WixComponent {
constructor(props) {
super(props);
const { breadcrumbs, title, hasBackgroundImage, minimized } = props;
this.state = {
themedBreadcrumbs: generateThemedBreadcrumbs(
breadcrumbs,
title,
hasBackgroundImage,
minimized,
),
};
}
componentWillReceiveProps(nextProps) {
const { breadcrumbs, title, hasBackgroundImage, minimized } = this.props;
const newBreadcrumbs = nextProps.breadcrumbs;
const newTitle = nextProps.title;
const newHasBackgroundImage = nextProps.hasBackgroundImage;
const newMinimized = nextProps.minimized;
if (
breadcrumbs !== newBreadcrumbs ||
title !== newTitle ||
hasBackgroundImage !== newHasBackgroundImage ||
minimized !== newMinimized
) {
const themedBreadcrumbs = generateThemedBreadcrumbs(
newBreadcrumbs,
newTitle,
newHasBackgroundImage,
newMinimized,
);
this.setState({ themedBreadcrumbs });
}
}
render() {
const {
breadcrumbs,
onBackClicked,
title,
subtitle,
minimized,
actionsBar,
showBackButton,
hasBackgroundImage,
className,
} = this.props;
const breadcrumbsExists = !!breadcrumbs;
const { themedBreadcrumbs } = this.state;
return (
<div className={classNames(s.headerContainer, className)}>
<div className={s.header}>
<div>
{animateComponent(
breadcrumbsExists || minimized,
!breadcrumbsExists,
<div
className={classNames(s.breadcrumbsContainer, {
[s.absolute]: !breadcrumbsExists,
[s.minimized]: minimized,
})}
data-hook="page-header-breadcrumbs"
>
{themedBreadcrumbs}
</div>,
)}
</div>
<div
className={classNames(s.titleContainer, {
[s.minimized]: minimized,
})}
>
{showBackButton &&
onBackClicked &&
animateComponent(
!minimized,
!breadcrumbsExists,
<div
className={classNames(s.backButton, {
[s.minimized]: minimized,
[s.darkTheme]: isDarkTheme(hasBackgroundImage, minimized),
})}
>
<Button
dataHook="page-header-backbutton"
onClick={onBackClicked}
theme="icon-white"
>
<ChevronLeft className={s.backButtonIcon} />
</Button>
</div>,
)}
<div className={s.titleColumn}>
{title &&
animateComponent(
!minimized,
!breadcrumbsExists,
<div
className={classNames(s.title, {
[s.minimized]: minimized,
})}
data-hook="page-header-title"
>
<Heading light={isDarkTheme(hasBackgroundImage, minimized)}>
{getTitle(title, minimized)}
</Heading>
</div>,
)}
{subtitle &&
animateComponent(
!minimized,
!breadcrumbsExists,
<div
className={classNames({ [s.minimized]: minimized })}
data-hook="page-header-subtitle"
>
<Text
light={isDarkTheme(hasBackgroundImage, minimized)}
secondary={!isDarkTheme(hasBackgroundImage, minimized)}
>
{subtitle}
</Text>
</div>,
)}
</div>
</div>
</div>
{actionsBar && (
<div
className={classNames(s.actionsBar, {
[s.minimized]: minimized,
[s.withBreadcrumbs]: breadcrumbsExists,
})}
data-hook="page-header-actionbar"
>
{React.cloneElement(actionsBar, { minimized, hasBackgroundImage })}
</div>
)}
</div>
);
}
}
PageHeader.displayName = 'Page.Header';
PageHeader.propTypes = {
/** This property is being supplied by the Page component, it's value changes by the state of the scrolled content */
minimized: PropTypes.bool,
/** This property is being supplied by the Page component, it's value reflects if the Page has a background image or not */
hasBackgroundImage: PropTypes.bool,
/** A css class to be applied to the component's root element */
className: PropTypes.string,
/** Wix-Style-React Breadcrumbs component */
breadcrumbs: PropTypes.node,
/** The main title text */
title: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
/** The subtitle text */
subtitle: PropTypes.node,
/** Should show a back button */
showBackButton: PropTypes.bool,
/** The callback when back button is clicked */
onBackClicked: PropTypes.func,
/** A placeholder for a component that can contain actions / anything else. It should be a React component that receives `minimized` and `hasBackgroundImage` props. */
actionsBar: PropTypes.node,
};
PageHeader.defaultProps = {
minimized: false,
};