Web: Common: PageLayout: Fixed PageLayout for children logic

This commit is contained in:
Ilya Oleshko 2020-08-11 15:34:00 +03:00
parent fdb4f43028
commit d02afe646a
2 changed files with 223 additions and 145 deletions

View File

@ -6,27 +6,82 @@ import i18n from './i18n';
import { ARTICLE_PINNED_KEY } from "../../constants"; import { ARTICLE_PINNED_KEY } from "../../constants";
import Article from "./sub-components/article"; import Article from "./sub-components/article";
import ArticleHeader from "./sub-components/article-header"; import SubArticleHeader from "./sub-components/article-header";
import ArticleMainButton from "./sub-components/article-main-button"; import SubArticleMainButton from "./sub-components/article-main-button";
import ArticleBody from "./sub-components/article-body"; import SubArticleBody from "./sub-components/article-body";
import ArticlePinPanel from "./sub-components/article-pin-panel"; import ArticlePinPanel from "./sub-components/article-pin-panel";
import Section from "./sub-components/section"; import Section from "./sub-components/section";
import SectionHeader from "./sub-components/section-header"; import SubSectionHeader from "./sub-components/section-header";
import SectionFilter from "./sub-components/section-filter"; import SubSectionFilter from "./sub-components/section-filter";
import SectionBody from "./sub-components/section-body"; import SubSectionBody from "./sub-components/section-body";
import SectionPaging from "./sub-components/section-paging"; import SubSectionBodyContent from "./sub-components/section-body-content";
import SubSectionPaging from "./sub-components/section-paging";
import SectionToggler from "./sub-components/section-toggler"; import SectionToggler from "./sub-components/section-toggler";
import { changeLanguage } from '../../utils'; import { changeLanguage } from "../../utils";
function ArticleHeader() {
return null;
}
ArticleHeader.displayName = "ArticleHeader";
function ArticleMainButton() {
return null;
}
ArticleMainButton.displayName = "ArticleMainButton";
function ArticleBody() {
return null;
}
ArticleBody.displayName = "ArticleBody";
function SectionHeader() {
return null;
}
SectionHeader.displayName = "SectionHeader";
function SectionFilter() {
return null;
}
SectionFilter.displayName = "SectionFilter";
function SectionBody() {
return null;
}
SectionBody.displayName = "SectionBody";
function SectionPaging() {
return null;
}
SectionPaging.displayName = "SectionPaging";
class PageLayoutComponent extends React.Component {
static ArticleHeader = ArticleHeader;
static ArticleMainButton = ArticleMainButton;
static ArticleBody = ArticleBody;
static SectionHeader = SectionHeader;
static SectionFilter = SectionFilter;
static SectionBody = SectionBody;
static SectionPaging = SectionPaging;
class PageLayoutComponent extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = this.mapPropsToState(props);
const isArticleVisibleAndPinned = !!localStorage.getItem(
ARTICLE_PINNED_KEY
);
this.state = {
isBackdropVisible: false,
isArticleVisible: isArticleVisibleAndPinned,
isArticlePinned: isArticleVisibleAndPinned
};
} }
componentDidMount() { componentDidMount() {
window.addEventListener("orientationchange", this.orientationChangeHandler); window.addEventListener("orientationchange", this.orientationChangeHandler);
const articleElement = document.getElementsByTagName('article') && document.getElementsByTagName('article')[0]; const articleElement =
document.getElementsByTagName('article') &&
document.getElementsByTagName('article')[0];
articleElement && this.orientationChangeHandler(); articleElement && this.orientationChangeHandler();
} }
@ -39,7 +94,9 @@ class PageLayoutComponent extends React.PureComponent {
if (!articleElement) return; if (!articleElement) return;
const isOrientationVertical = !(screen.orientation ? screen.orientation.angle % 180 : window.matchMedia("(orientation: portrait)")); const isOrientationVertical = !(screen.orientation
? screen.orientation.angle % 180
: window.matchMedia("(orientation: portrait)"));
const isValueExist = !!localStorage.getItem(ARTICLE_PINNED_KEY); const isValueExist = !!localStorage.getItem(ARTICLE_PINNED_KEY);
const articleWidth = articleElement.offsetWidth; const articleWidth = articleElement.offsetWidth;
const isArticleWide = articleWidth > screen.availWidth - articleWidth; const isArticleWide = articleWidth > screen.availWidth - articleWidth;
@ -52,65 +109,6 @@ class PageLayoutComponent extends React.PureComponent {
} }
} }
componentDidUpdate(prevProps) {
if (this.hasChanges(this.props, prevProps)) {
this.setState(this.mapPropsToState(this.props));
}
}
hasChanges = (currentProps, prevProps) => {
return (
currentProps.articleHeaderContent != prevProps.articleHeaderContent ||
currentProps.articleMainButtonContent != prevProps.articleMainButtonContent ||
currentProps.articleBodyContent != prevProps.articleBodyContent ||
currentProps.sectionHeaderContent != prevProps.sectionHeaderContent ||
currentProps.sectionFilterContent != prevProps.sectionFilterContent ||
currentProps.sectionBodyContent != prevProps.sectionBodyContent ||
currentProps.sectionPagingContent != prevProps.sectionPagingContent
);
};
mapPropsToState = props => {
let isArticleHeaderAvailable = !!props.articleHeaderContent,
isArticleMainButtonAvailable = !!props.articleMainButtonContent,
isArticleBodyAvailable = !!props.articleBodyContent,
isArticleAvailable = isArticleHeaderAvailable || isArticleMainButtonAvailable || isArticleBodyAvailable,
isSectionHeaderAvailable = !!props.sectionHeaderContent,
isSectionFilterAvailable = !!props.sectionFilterContent,
isSectionPagingAvailable = !!props.sectionPagingContent,
isSectionBodyAvailable = !!props.sectionBodyContent || isSectionFilterAvailable || isSectionPagingAvailable,
isSectionAvailable = isSectionHeaderAvailable || isSectionFilterAvailable || isSectionBodyAvailable || isSectionPagingAvailable || isArticleAvailable,
isBackdropAvailable = isArticleAvailable,
isArticleVisibleAndPinned = !!localStorage.getItem(ARTICLE_PINNED_KEY);
let newState = {
isBackdropAvailable: isBackdropAvailable,
isArticleAvailable: isArticleAvailable,
isArticleHeaderAvailable: isArticleHeaderAvailable,
isArticleMainButtonAvailable: isArticleMainButtonAvailable,
isArticleBodyAvailable: isArticleBodyAvailable,
isSectionAvailable: isSectionAvailable,
isSectionHeaderAvailable: isSectionHeaderAvailable,
isSectionFilterAvailable: isSectionFilterAvailable,
isSectionBodyAvailable: isSectionBodyAvailable,
isSectionPagingAvailable: isSectionPagingAvailable,
isBackdropVisible: false,
isArticleVisible: isArticleVisibleAndPinned,
isArticlePinned: isArticleVisibleAndPinned,
articleHeaderContent: props.articleHeaderContent,
articleMainButtonContent: props.articleMainButtonContent,
articleBodyContent: props.articleBodyContent,
sectionHeaderContent: props.sectionHeaderContent,
sectionFilterContent: props.sectionFilterContent,
sectionBodyContent: props.sectionBodyContent,
sectionPagingContent: props.sectionPagingContent
};
return newState;
};
backdropClick = () => { backdropClick = () => {
this.setState({ this.setState({
isBackdropVisible: false, isBackdropVisible: false,
@ -148,56 +146,144 @@ class PageLayoutComponent extends React.PureComponent {
}; };
render() { render() {
const { showProgressBar, progressBarValue, progressBarDropDownContent, withBodyScroll, withBodyAutoFocus, progressBarLabel, onDrop, uploadFiles, setSelections, viewAs } = this.props; const {
onDrop,
progressBarDropDownContent,
progressBarLabel,
progressBarValue,
setSelections,
showProgressBar,
uploadFiles,
viewAs,
withBodyAutoFocus,
withBodyScroll,
children
} = this.props;
let articleHeaderContent = null;
let articleMainButtonContent = null;
let articleBodyContent = null;
let sectionHeaderContent = null;
let sectionFilterContent = null;
let sectionPagingContent = null;
let sectionBodyContent = null;
React.Children.forEach(children, child => {
const childType =
child && child.type && (child.type.displayName || child.type.name);
switch (childType) {
case ArticleHeader.displayName:
articleHeaderContent = child;
break;
case ArticleMainButton.displayName:
articleMainButtonContent = child;
break;
case ArticleBody.displayName:
articleBodyContent = child;
break;
case SectionHeader.displayName:
sectionHeaderContent = child;
break;
case SectionFilter.displayName:
sectionFilterContent = child;
break;
case SectionPaging.displayName:
sectionPagingContent = child;
break;
case SectionBody.displayName:
sectionBodyContent = child;
break;
default:
break;
}
});
const isArticleHeaderAvailable = !!articleHeaderContent,
isArticleMainButtonAvailable = !!articleMainButtonContent,
isArticleBodyAvailable = !!articleBodyContent,
isArticleAvailable =
isArticleHeaderAvailable ||
isArticleMainButtonAvailable ||
isArticleBodyAvailable,
isSectionHeaderAvailable = !!sectionHeaderContent,
isSectionFilterAvailable = !!sectionFilterContent,
isSectionPagingAvailable = !!sectionPagingContent,
isSectionBodyAvailable =
!!sectionBodyContent ||
isSectionFilterAvailable ||
isSectionPagingAvailable,
isSectionAvailable =
isSectionHeaderAvailable ||
isSectionFilterAvailable ||
isSectionBodyAvailable ||
isSectionPagingAvailable ||
isArticleAvailable,
isBackdropAvailable = isArticleAvailable;
return ( return (
<> <>
{this.state.isBackdropAvailable && ( {isBackdropAvailable && (
<Backdrop <Backdrop
zIndex={400} zIndex={400}
visible={this.state.isBackdropVisible} visible={this.state.isBackdropVisible}
onClick={this.backdropClick} onClick={this.backdropClick}
/> />
)} )}
{this.state.isArticleAvailable && ( {isArticleAvailable && (
<Article <Article
visible={this.state.isArticleVisible} visible={this.state.isArticleVisible}
pinned={this.state.isArticlePinned} pinned={this.state.isArticlePinned}
> >
{this.state.isArticleHeaderAvailable && ( {isArticleHeaderAvailable && (
<ArticleHeader> <SubArticleHeader>
{this.state.articleHeaderContent} {articleHeaderContent
</ArticleHeader> ? articleHeaderContent.props.children
: null}
</SubArticleHeader>
)} )}
{this.state.isArticleMainButtonAvailable && ( {isArticleMainButtonAvailable && (
<ArticleMainButton> <SubArticleMainButton>
{this.state.articleMainButtonContent} {articleMainButtonContent
</ArticleMainButton> ? articleMainButtonContent.props.children
: null}
</SubArticleMainButton>
)} )}
{this.state.isArticleBodyAvailable && ( {isArticleBodyAvailable && (
<ArticleBody>{this.state.articleBodyContent}</ArticleBody> <SubArticleBody>
{articleBodyContent ? articleBodyContent.props.children : null}
</SubArticleBody>
)} )}
{this.state.isArticleBodyAvailable && ( {isArticleBodyAvailable && (
<ArticlePinPanel <ArticlePinPanel
pinned={this.state.isArticlePinned} pinned={this.state.isArticlePinned}
pinText={this.props.t('Pin')} pinText={this.props.t("Pin")}
onPin={this.pinArticle} onPin={this.pinArticle}
unpinText={this.props.t('Unpin')} unpinText={this.props.t("Unpin")}
onUnpin={this.unpinArticle} onUnpin={this.unpinArticle}
/> />
)} )}
</Article> </Article>
)} )}
{this.state.isSectionAvailable && ( {isSectionAvailable && (
<Section> <Section>
{this.state.isSectionHeaderAvailable && ( {isSectionHeaderAvailable && (
<SectionHeader isArticlePinned={this.state.isArticlePinned}>{this.state.sectionHeaderContent}</SectionHeader> <SubSectionHeader isArticlePinned={this.state.isArticlePinned}>
{sectionHeaderContent
? sectionHeaderContent.props.children
: null}
</SubSectionHeader>
)} )}
{this.state.isSectionFilterAvailable && ( {isSectionFilterAvailable && (
<SectionFilter className="section-header_filter">{this.state.sectionFilterContent}</SectionFilter> <SubSectionFilter className="section-header_filter">
{sectionFilterContent
? sectionFilterContent.props.children
: null}
</SubSectionFilter>
)} )}
{this.state.isSectionBodyAvailable && ( {isSectionBodyAvailable && (
<> <>
<SectionBody <SubSectionBody
onDrop={onDrop} onDrop={onDrop}
uploadFiles={uploadFiles} uploadFiles={uploadFiles}
setSelections={setSelections} setSelections={setSelections}
@ -206,14 +292,26 @@ class PageLayoutComponent extends React.PureComponent {
pinned={this.state.isArticlePinned} pinned={this.state.isArticlePinned}
viewAs={viewAs} viewAs={viewAs}
> >
{this.state.isSectionFilterAvailable && ( {isSectionFilterAvailable && (
<SectionFilter className="section-body_filter">{this.state.sectionFilterContent}</SectionFilter> <SubSectionFilter className="section-body_filter">
)} {sectionFilterContent
{this.state.sectionBodyContent} ? sectionFilterContent.props.children
{this.state.isSectionPagingAvailable && ( : null}
<SectionPaging>{this.state.sectionPagingContent}</SectionPaging> </SubSectionFilter>
)} )}
</SectionBody> <SubSectionBodyContent>
{sectionBodyContent
? sectionBodyContent.props.children
: null}
</SubSectionBodyContent>
{isSectionPagingAvailable && (
<SubSectionPaging>
{sectionPagingContent
? sectionPagingContent.props.children
: null}
</SubSectionPaging>
)}
</SubSectionBody>
{showProgressBar && ( {showProgressBar && (
<ProgressBar <ProgressBar
className="layout-progress-bar" className="layout-progress-bar"
@ -225,7 +323,7 @@ class PageLayoutComponent extends React.PureComponent {
</> </>
)} )}
{this.state.isArticleAvailable && ( {isArticleAvailable && (
<SectionToggler <SectionToggler
visible={!this.state.isArticleVisible} visible={!this.state.isArticleVisible}
onClick={this.showArticle} onClick={this.showArticle}
@ -238,47 +336,8 @@ class PageLayoutComponent extends React.PureComponent {
} }
} }
const PageLayoutTranslated = withTranslation()(PageLayoutComponent);
const PageLayout = props => {
changeLanguage(i18n);
return <PageLayoutTranslated i18n={i18n} {...props} />
}
PageLayout.propTypes = {
language: PropTypes.string,
}
PageLayoutComponent.propTypes = { PageLayoutComponent.propTypes = {
articleHeaderContent: PropTypes.oneOfType([ children: PropTypes.any,
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
articleMainButtonContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
articleBodyContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
sectionHeaderContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
sectionFilterContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
sectionBodyContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
sectionPagingContent: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
withBodyScroll: PropTypes.bool, withBodyScroll: PropTypes.bool,
withBodyAutoFocus: PropTypes.bool, withBodyAutoFocus: PropTypes.bool,
t: PropTypes.func, t: PropTypes.func,
@ -289,8 +348,7 @@ PageLayoutComponent.propTypes = {
progressBarLabel: PropTypes.string, progressBarLabel: PropTypes.string,
onDrop: PropTypes.func, onDrop: PropTypes.func,
setSelections: PropTypes.func, setSelections: PropTypes.func,
uploadFiles: PropTypes.bool, uploadFiles: PropTypes.bool
viewAs: PropTypes.string
}; };
PageLayoutComponent.defaultProps = { PageLayoutComponent.defaultProps = {
@ -298,5 +356,25 @@ PageLayoutComponent.defaultProps = {
withBodyAutoFocus: false withBodyAutoFocus: false
}; };
const PageLayoutTranslated = withTranslation()(PageLayoutComponent);
const PageLayout = props => {
changeLanguage(i18n);
return <PageLayoutTranslated i18n={i18n} {...props} />
}
PageLayout.ArticleHeader = ArticleHeader;
PageLayout.ArticleMainButton = ArticleMainButton;
PageLayout.ArticleBody = ArticleBody;
PageLayout.SectionHeader = SectionHeader;
PageLayout.SectionFilter = SectionFilter;
PageLayout.SectionBody = SectionBody;
PageLayout.SectionPaging = SectionPaging;
PageLayout.propTypes = {
language: PropTypes.string,
children: PropTypes.any
}
export default PageLayout; export default PageLayout;

View File

@ -7,7 +7,7 @@ export { default as Headline } from "./Headline";
export { default as PeopleSelector } from "./PeopleSelector"; export { default as PeopleSelector } from "./PeopleSelector";
export { default as GroupSelector } from "./GroupSelector"; export { default as GroupSelector } from "./GroupSelector";
export { default as AdvancedSelector } from './AdvancedSelector'; export { default as AdvancedSelector } from './AdvancedSelector';
export { default as PageLayout } from './PageLayout'; export { default as PageLayout } from "./PageLayout";
export { default as Layout } from './Layout'; export { default as Layout } from './Layout';
export { default as ProfileMenu } from './ProfileMenu'; export { default as ProfileMenu } from './ProfileMenu';
export { default as ErrorContainer } from './ErrorContainer'; export { default as ErrorContainer } from './ErrorContainer';