Break TabNavHorizontal into two components

This commit is contained in:
Hannu Lyytikainen 2017-12-15 10:19:53 +02:00
parent c0a8190a40
commit 4395e9ee6a
8 changed files with 114 additions and 111 deletions

View file

@ -1,30 +1,42 @@
import TabNavHorizontal from './TabNavHorizontal';
import { TAB_TYPE_BUTTON, TAB_TYPE_LINK } from './TabNavHorizontal';
import React from 'react';
import { LinkTabNavHorizontal, ButtonTabNavHorizontal } from './TabNavHorizontal';
const selfLinkProps = {
name: 'StyleguideComponent',
params: { component: 'TabNavHorizontal' },
};
export const LinkTabs = {
component: TabNavHorizontal,
props: {
tabs: [
{ text: 'Normal', linkProps: selfLinkProps },
{ text: 'Selected', linkProps: selfLinkProps, selected: true },
],
type: TAB_TYPE_LINK,
},
group: 'navigation',
};
const linkTabs = [
{ text: 'Normal', linkProps: selfLinkProps },
{ text: 'Selected', linkProps: selfLinkProps, selected: true },
];
const noop = () => null;
export const ButtonTabs = {
component: TabNavHorizontal,
props: {
tabs: [{ text: 'Normal', onClick: noop }, { text: 'Selected', onClick: noop, selected: true }],
type: TAB_TYPE_BUTTON,
},
const buttonTabs = [
{ text: 'Normal', onClick: noop },
{ text: 'Selected', onClick: noop, selected: true },
];
const TabNavHorizontalComponent = () => {
return (
<div>
<h3>Horizontal link tab navigation with light skin</h3>
<LinkTabNavHorizontal tabs={linkTabs} />
<h3>Horizontal link tab navigation with dark skin</h3>
<LinkTabNavHorizontal tabs={linkTabs} skin="dark" />
<h3>Horizontal button tab navigation with light skin</h3>
<ButtonTabNavHorizontal tabs={buttonTabs} />
<h3>Horizontal button tab navigation with dark skin</h3>
<ButtonTabNavHorizontal tabs={buttonTabs} skin="dark" />
</div>
);
};
export const TabNavHorizontal = {
component: TabNavHorizontalComponent,
group: 'navigation',
};

View file

@ -1,16 +1,3 @@
/**
* A horizontal tab bar.
*
* Tabs can be of links or buttons, denoted by the type param
* which accepts values 'link' and 'button'.
*
* The required tab params vary based on the main component type. For
* link tab bar linkProps is required for the tabs. For a button type
* of tab bar onClick function is required.
*
* By default the type of TabNavHorizontal is 'link'.
*/
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
@ -21,51 +8,10 @@ import css from './TabNavHorizontal.css';
export const LIGHT_SKIN = 'light';
export const DARK_SKIN = 'dark';
export const TAB_TYPE_LINK = 'link';
export const TAB_TYPE_BUTTON = 'button';
const { arrayOf, bool, func, node, object, oneOf, string, shape } = PropTypes;
const { arrayOf, bool, func, node, object, oneOf, string } = PropTypes;
const ButtonTab = props => {
const { className, disabled, text, selected, onClick, isDark } = props;
const darkSkinClasses = isDark
? classNames(css.tabContentDarkSkin, {
[css.selectedTabContentDarkSkin]: selected,
[css.disabledDarkSkin]: disabled,
})
: null;
const buttonClasses = classNames(
css.tabContent,
{
[css.selectedTabContent]: selected,
[css.disabled]: disabled,
},
darkSkinClasses
);
return (
<div className={className}>
<InlineTextButton className={buttonClasses} onClick={onClick}>
{text}
</InlineTextButton>
</div>
);
};
ButtonTab.defaultProps = { className: null, disabled: false, selected: false };
ButtonTab.propTypes = {
className: string,
text: node.isRequired,
disabled: bool,
selected: bool,
onClick: func.isRequired,
isDark: bool.isRequired,
};
const LinkTab = props => {
const { className, disabled, text, selected, linkProps, isDark } = props;
const Tab = props => {
const { className, disabled, text, selected, onClick, linkProps, isDark } = props;
const darkSkinClasses = isDark
? classNames(css.tabContentDarkSkin, {
[css.selectedTabContentDarkSkin]: selected,
@ -82,62 +28,114 @@ const LinkTab = props => {
darkSkinClasses
);
const buttonClasses = classNames(
css.tabContent,
css.button,
{
[css.selectedTabContent]: selected,
[css.disabled]: disabled,
},
darkSkinClasses
);
const isButton = !!onClick;
return (
<div className={className}>
<NamedLink className={linkClasses} {...linkProps}>
{text}
</NamedLink>
{isButton ? (
<InlineTextButton className={buttonClasses} onClick={onClick}>
{text}
</InlineTextButton>
) : (
<NamedLink className={linkClasses} {...linkProps}>
{text}
</NamedLink>
)}
</div>
);
};
LinkTab.defaultProps = { className: null, disabled: false, selected: false };
Tab.defaultProps = { className: null, disabled: false, selected: false };
LinkTab.propTypes = {
Tab.propTypes = {
className: string,
text: node.isRequired,
disabled: bool,
selected: bool,
linkProps: object.isRequired,
onClick: func,
linkProps: object,
isDark: bool.isRequired,
};
const TabNavHorizontal = props => {
const { className, rootClassName, tabRootClassName, tabs, skin, type } = props;
const { className, rootClassName, tabRootClassName, tabs, skin } = props;
const isDark = skin === DARK_SKIN;
const isButton = type === TAB_TYPE_BUTTON;
const classes = classNames(rootClassName || css.root, { [css.darkSkin]: isDark }, className);
const tabClasses = tabRootClassName || css.tab;
return (
<nav className={classes}>
{tabs.map((tab, index) => {
const key = typeof tab.text === 'string' ? tab.text : index;
return isButton ? (
<ButtonTab key={key} className={tabClasses} {...tab} isDark={isDark} />
) : (
<LinkTab key={key} className={tabClasses} {...tab} isDark={isDark} />
);
return <Tab key={key} className={tabClasses} {...tab} isDark={isDark} />;
})}
</nav>
);
};
TabNavHorizontal.defaultProps = {
/**
* A tab navigation element with buttons. Requires onClick
* function param for tab objects passed as parameter.
*/
export const ButtonTabNavHorizontal = props => <TabNavHorizontal {...props} />;
ButtonTabNavHorizontal.defaultProps = {
className: null,
rootClassName: null,
tabRootClassName: null,
tabClassName: null,
skin: LIGHT_SKIN,
type: TAB_TYPE_LINK,
};
TabNavHorizontal.propTypes = {
ButtonTabNavHorizontal.propTypes = {
className: string,
rootClassName: string,
tabRootClassName: string,
tabs: arrayOf(object).isRequired,
tabs: arrayOf(
shape({
text: node.isRequired,
disbaled: bool,
selected: bool,
onClick: func.isRequired,
})
).isRequired,
skin: oneOf([LIGHT_SKIN, DARK_SKIN]),
type: oneOf([TAB_TYPE_LINK, TAB_TYPE_BUTTON]),
};
export default TabNavHorizontal;
/**
* A tab navigation element with links. Requires linkProps
* object param for tab objects passed as parameter.
*/
export const LinkTabNavHorizontal = props => <TabNavHorizontal {...props} />;
LinkTabNavHorizontal.defaultProps = {
className: null,
rootClassName: null,
tabRootClassName: null,
tabClassName: null,
skin: LIGHT_SKIN,
};
LinkTabNavHorizontal.propTypes = {
className: string,
rootClassName: string,
tabRootClassName: string,
tabs: arrayOf(
shape({
text: node.isRequired,
disbaled: bool,
selected: bool,
linkProps: object.isRequired,
})
).isRequired,
skin: oneOf([LIGHT_SKIN, DARK_SKIN]),
};

View file

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { ACCOUNT_SETTINGS_PAGES } from '../../routeConfiguration';
import { TabNavHorizontal } from '../../components';
import { LinkTabNavHorizontal } from '../../components';
import css from './UserNav.css';
@ -38,7 +38,7 @@ const UserNav = props => {
];
return (
<TabNavHorizontal className={classes} tabRootClassName={css.tab} tabs={tabs} skin="dark" />
<LinkTabNavHorizontal className={classes} tabRootClassName={css.tab} tabs={tabs} skin="dark" />
);
};

View file

@ -99,7 +99,7 @@ export {
default as StripeBankAccountTokenInputField,
} from './StripeBankAccountTokenInputField/StripeBankAccountTokenInputField';
export { default as TabNav } from './TabNav/TabNav';
export { default as TabNavHorizontal } from './TabNavHorizontal/TabNavHorizontal';
export { LinkTabNavHorizontal, ButtonTabNavHorizontal } from './TabNavHorizontal/TabNavHorizontal';
export { default as Tabs } from './Tabs/Tabs';
export { default as TermsOfService } from './TermsOfService/TermsOfService';
export { default as TextInputField } from './TextInputField/TextInputField';

View file

@ -16,7 +16,7 @@ import {
Page,
NamedLink,
NamedRedirect,
TabNavHorizontal,
LinkTabNavHorizontal,
IconEmailSent,
InlineTextButton,
IconClose,
@ -131,7 +131,7 @@ export class AuthenticationPageComponent extends Component {
const formContent = (
<div className={css.content}>
<TabNavHorizontal className={css.tabs} tabs={tabs} />
<LinkTabNavHorizontal className={css.tabs} tabs={tabs} />
{loginOrSignupError}
{isLogin ? (
<LoginForm className={css.form} onSubmit={submitLogin} inProgress={authInProgress} />

View file

@ -30,7 +30,7 @@ exports[`AuthenticationPageComponent matches snapshot 1`] = `
>
<div>
<div>
<TabNavHorizontal
<Component
className={null}
rootClassName={null}
skin="light"
@ -74,7 +74,6 @@ exports[`AuthenticationPageComponent matches snapshot 1`] = `
},
]
}
type="link"
/>
<ReduxForm
inProgress={false}

View file

@ -21,9 +21,8 @@ import {
NamedLink,
ListingCard,
Reviews,
TabNavHorizontal,
ButtonTabNavHorizontal,
} from '../../components';
import { TAB_TYPE_BUTTON } from '../../components/TabNavHorizontal/TabNavHorizontal';
import { TopbarContainer } from '../../containers';
import { loadData } from './ProfilePage.duck';
import config from '../../config';
@ -169,11 +168,7 @@ export class ProfilePageComponent extends Component {
const desktopReviews = (
<div className={css.desktopReviews}>
<TabNavHorizontal
className={css.desktopReviewsTabNav}
tabs={desktopReviewTabs}
type={TAB_TYPE_BUTTON}
/>
<ButtonTabNavHorizontal className={css.desktopReviewsTabNav} tabs={desktopReviewTabs} />
{queryReviewsError ? reviewsError : null}

View file

@ -105,7 +105,7 @@ exports[`ProfilePage matches snapshot 1`] = `
/>
</div>
<div>
<TabNavHorizontal
<Component
className={null}
rootClassName={null}
skin="light"
@ -143,7 +143,6 @@ exports[`ProfilePage matches snapshot 1`] = `
},
]
}
type="button"
/>
<InjectIntl(ReviewsComponent)
reviews={Array []}