mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
Add in progress and ready states to the Button component
This commit is contained in:
parent
3d3509db8b
commit
861699b610
15 changed files with 174 additions and 23 deletions
|
|
@ -43,3 +43,43 @@
|
|||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.inProgress {
|
||||
padding: 0;
|
||||
|
||||
&:disabled {
|
||||
background-color: var(--marketplaceColor);
|
||||
}
|
||||
}
|
||||
|
||||
.primaryButton.inProgress:disabled {
|
||||
background-color: var(--successColor);
|
||||
}
|
||||
|
||||
.secondaryButton.inProgress:disabled {
|
||||
background-color: var(--matterColorLight);
|
||||
}
|
||||
|
||||
.ready {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
stroke: var(--matterColorLight);
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: var(--matterColorLight);
|
||||
}
|
||||
|
||||
.secondaryButton .spinner {
|
||||
stroke: var(--matterColorAnti);
|
||||
}
|
||||
|
||||
.secondaryButton .checkmark {
|
||||
stroke: var(--matterColorAnti);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,6 @@
|
|||
|
||||
.customButton {
|
||||
@apply --marketplaceButtonStyles;
|
||||
border-radius: 4px;
|
||||
padding: 12px 0;
|
||||
border-radius: 8px;
|
||||
height: 100px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,54 @@ const ButtonsComponent = () => {
|
|||
<h3>Default button disabled:</h3>
|
||||
<Button disabled>Click me</Button>
|
||||
|
||||
<h3>Default button in progress:</h3>
|
||||
<Button inProgress>Click me</Button>
|
||||
|
||||
<h3>Default button ready:</h3>
|
||||
<Button ready>Click me</Button>
|
||||
|
||||
<h3>Default button disabled and in progress:</h3>
|
||||
<Button disabled inProgress>Click me</Button>
|
||||
|
||||
<h3>Default button disabled and ready:</h3>
|
||||
<Button disabled ready>Click me</Button>
|
||||
|
||||
<h3>Primary button:</h3>
|
||||
<PrimaryButton>Click me</PrimaryButton>
|
||||
|
||||
<h3>Primary button disabled:</h3>
|
||||
<PrimaryButton disabled>Click me</PrimaryButton>
|
||||
|
||||
<h3>Primary button in progress:</h3>
|
||||
<PrimaryButton inProgress>Click me</PrimaryButton>
|
||||
|
||||
<h3>Primary button ready:</h3>
|
||||
<PrimaryButton ready>Click me</PrimaryButton>
|
||||
|
||||
<h3>Primary button disabled and in progress:</h3>
|
||||
<PrimaryButton disabled inProgress>Click me</PrimaryButton>
|
||||
|
||||
<h3>Primary button disabled ready:</h3>
|
||||
<PrimaryButton disabled ready>Click me</PrimaryButton>
|
||||
|
||||
<h3>Secondary button:</h3>
|
||||
<SecondaryButton>Click me</SecondaryButton>
|
||||
|
||||
<h3>Secondary button disabled:</h3>
|
||||
<SecondaryButton disabled>Click me</SecondaryButton>
|
||||
|
||||
<h3>Secondary button in progress:</h3>
|
||||
<SecondaryButton inProgress>Click me</SecondaryButton>
|
||||
|
||||
<h3>Secondary button ready:</h3>
|
||||
<SecondaryButton ready>Click me</SecondaryButton>
|
||||
|
||||
<h3>Secondary button disabled and in progress:</h3>
|
||||
<SecondaryButton disabled inProgress>Click me</SecondaryButton>
|
||||
|
||||
<h3>Secondary button disabled ready:</h3>
|
||||
<SecondaryButton disabled ready>Click me</SecondaryButton>
|
||||
|
||||
<h3>Inline text button:</h3>
|
||||
<p>
|
||||
Lorem ipsum <InlineTextButton>button that looks like link</InlineTextButton> dolor sit amet
|
||||
|
|
|
|||
|
|
@ -1,28 +1,48 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { IconSpinner, IconCheckmark } from '../../components';
|
||||
|
||||
import css from './Button.css';
|
||||
|
||||
const Button = props => {
|
||||
const { children, className, rootClassName, ...rest } = props;
|
||||
const { children, className, rootClassName, inProgress, ready, ...rest } = props;
|
||||
|
||||
const rootClass = rootClassName || css.root;
|
||||
const classes = classNames(rootClass, className);
|
||||
const classes = classNames(rootClass, className, {
|
||||
[css.ready]: ready,
|
||||
[css.inProgress]: inProgress,
|
||||
});
|
||||
|
||||
return <button className={classes} {...rest}>{children}</button>;
|
||||
let content;
|
||||
|
||||
if (inProgress) {
|
||||
content = <IconSpinner rootClassName={css.spinner} />;
|
||||
} else if (ready) {
|
||||
content = <IconCheckmark rootClassName={css.checkmark} />;
|
||||
} else {
|
||||
content = children;
|
||||
}
|
||||
|
||||
return <button className={classes} {...rest}>{content}</button>;
|
||||
};
|
||||
|
||||
const { node, string } = PropTypes;
|
||||
const { node, string, bool } = PropTypes;
|
||||
|
||||
Button.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
inProgress: false,
|
||||
ready: false,
|
||||
children: null,
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
|
||||
inProgress: bool,
|
||||
ready: bool,
|
||||
|
||||
children: node,
|
||||
};
|
||||
|
||||
|
|
|
|||
7
src/components/IconCheckmark/IconCheckMark.css
Normal file
7
src/components/IconCheckmark/IconCheckMark.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: var(--marketplaceColor);
|
||||
}
|
||||
7
src/components/IconCheckmark/IconCheckmark.example.js
Normal file
7
src/components/IconCheckmark/IconCheckmark.example.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import IconCheckmark from './IconCheckmark';
|
||||
|
||||
export const Icon = {
|
||||
component: IconCheckmark,
|
||||
props: {},
|
||||
group: 'icons',
|
||||
};
|
||||
30
src/components/IconCheckmark/IconCheckmark.js
Normal file
30
src/components/IconCheckmark/IconCheckmark.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import css from './IconCheckMark.css';
|
||||
|
||||
const IconCheckmark = props => {
|
||||
const { rootClassName, className } = props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
return (
|
||||
<svg className={classes} strokeWidth="2" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M22.6 1.2c-.4-.3-1-.2-1.3.2L7.8 19l-5.2-5c-.4-.4-1-.4-1.3 0-.4.3-.4.8 0 1l6 5.6.6.2s.2 0 .4-.4l14.3-18c.3-.5.2-1-.2-1"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
IconCheckmark.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
};
|
||||
|
||||
const { string } = PropTypes;
|
||||
|
||||
IconCheckmark.propTypes = {
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
};
|
||||
|
||||
export default IconCheckmark;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
stroke: var(--marketplaceColor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,35 +3,34 @@ import classNames from 'classnames';
|
|||
|
||||
import css from './IconSpinner.css';
|
||||
|
||||
// TODO: SVG needs to be changed so that it doesn't take 100x100 area,
|
||||
// but just a little bit more than what actual spinner takes (~26px)
|
||||
const IconSpinner = props => {
|
||||
const { rootClassName, className } = props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
return (
|
||||
<svg
|
||||
className={classes}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 100 100"
|
||||
viewBox="0 0 30 30"
|
||||
strokeWidth="3"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="50" cy="50" fill="none" r="10" strokeWidth="3" strokeLinecap="round">
|
||||
<circle cx="15" cy="15" r="12" fill="none" strokeLinecap="round">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
type="rotate"
|
||||
calcMode="linear"
|
||||
values="0 50 50;180 50 50;720 50 50"
|
||||
values="0 15 15;180 15 15;720 15 15"
|
||||
keyTimes="0;0.5;1"
|
||||
dur="1s"
|
||||
dur=".9"
|
||||
begin="0s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
<animate
|
||||
attributeName="stroke-dasharray"
|
||||
calcMode="linear"
|
||||
values="6 56;46 14;6 56"
|
||||
values="9 56;46 14;9 56"
|
||||
keyTimes="0;0.5;1"
|
||||
dur="1"
|
||||
dur=".9"
|
||||
begin="0s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import ExternalLink from './ExternalLink/ExternalLink';
|
|||
import FilterPanel from './FilterPanel/FilterPanel';
|
||||
import HeroSection from './HeroSection/HeroSection';
|
||||
import IconBannedUser from './IconBannedUser/IconBannedUser';
|
||||
import IconCheckmark from './IconCheckmark/IconCheckmark';
|
||||
import IconClose from './IconClose/IconClose';
|
||||
import IconEmailAttention from './IconEmailAttention/IconEmailAttention';
|
||||
import IconEmailSent from './IconEmailSent/IconEmailSent';
|
||||
|
|
@ -91,6 +92,7 @@ export {
|
|||
FilterPanel,
|
||||
HeroSection,
|
||||
IconBannedUser,
|
||||
IconCheckmark,
|
||||
IconClose,
|
||||
IconEmailAttention,
|
||||
IconEmailSent,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ exports[`EditListingLocationForm matches snapshot 1`] = `
|
|||
<Button
|
||||
className={null}
|
||||
disabled={false}
|
||||
inProgress={false}
|
||||
ready={false}
|
||||
rootClassName={null}
|
||||
type="submit">
|
||||
Save location
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ exports[`EditListingPhotosForm matches snapshot 1`] = `
|
|||
<Button
|
||||
className={null}
|
||||
disabled={false}
|
||||
inProgress={false}
|
||||
ready={false}
|
||||
rootClassName={null}
|
||||
type="submit">
|
||||
Save photos
|
||||
|
|
|
|||
|
|
@ -256,7 +256,9 @@ exports[`ListingPage matches snapshot 1`] = `
|
|||
</div>
|
||||
<Button
|
||||
className={null}
|
||||
inProgress={false}
|
||||
onClick={[Function]}
|
||||
ready={false}
|
||||
rootClassName={null}>
|
||||
ListingPage.ctaButtonMessage
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import * as DateRangeInputField from './components/DateRangeInputField/DateRange
|
|||
import * as EditListingWizard from './components/EditListingWizard/EditListingWizard.example';
|
||||
import * as ExpandingTextarea from './components/ExpandingTextarea/ExpandingTextarea.example';
|
||||
import * as IconBannedUser from './components/IconBannedUser/IconBannedUser.example';
|
||||
import * as IconCheckmark from './components/IconCheckmark/IconCheckmark.example';
|
||||
import * as IconClose from './components/IconClose/IconClose.example';
|
||||
import * as IconEmailAttention from './components/IconEmailAttention/IconEmailAttention.example';
|
||||
import * as IconEmailSent from './components/IconEmailSent/IconEmailSent.example';
|
||||
|
|
@ -79,6 +80,7 @@ export {
|
|||
EditListingWizard,
|
||||
ExpandingTextarea,
|
||||
IconBannedUser,
|
||||
IconCheckmark,
|
||||
IconClose,
|
||||
IconEmailAttention,
|
||||
IconEmailSent,
|
||||
|
|
|
|||
|
|
@ -150,10 +150,16 @@
|
|||
@apply --marketplaceButtonFontStyles;
|
||||
|
||||
/* Dimensions */
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
min-height: 65px;
|
||||
margin: 0;
|
||||
padding: 19px 0 22px 0;
|
||||
|
||||
/* Push the text up from center */
|
||||
padding-bottom: 2px;
|
||||
|
||||
/* Borders */
|
||||
border: none;
|
||||
|
|
@ -201,10 +207,6 @@
|
|||
--marketplaceButtonStylesSecondary {
|
||||
@apply --marketplaceButtonStyles;
|
||||
|
||||
/* We must reduce the padding since the border takes space from the
|
||||
full height that should match the default button height */
|
||||
padding: 16px 0 19px 0;
|
||||
|
||||
background-color: var(--matterColorLight);
|
||||
color: var(--matterColor);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue