From c7b762195ae9d2c58e889ab6996565a6cbed826a Mon Sep 17 00:00:00 2001 From: Alexandru Buliga Date: Tue, 31 Jul 2018 16:00:25 +0200 Subject: [PATCH] feat(button): adding disabled prop to Button (#14) --- CHANGELOG.md | 1 + .../ButtonExampleDisabled.shorthand.tsx | 17 +++++++++ .../Button/States/ButtonExampleDisabled.tsx | 28 ++++++++++++++ .../components/Button/States/index.tsx | 15 ++++++++ docs/src/examples/components/Button/index.tsx | 2 + src/components/Button/Button.tsx | 38 +++++++++++++++++-- src/components/Button/buttonRules.ts | 29 ++++++++++---- src/components/Button/buttonVariables.ts | 2 +- test/specs/components/Button/Button-test.tsx | 12 +++++- 9 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 docs/src/examples/components/Button/States/ButtonExampleDisabled.shorthand.tsx create mode 100644 docs/src/examples/components/Button/States/ButtonExampleDisabled.tsx create mode 100644 docs/src/examples/components/Button/States/index.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index e8bf47d465..912b4411cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Features - Add Icon `xSpacing` prop @Bugaa92 ([#22](https://github.com/stardust-ui/react/pull/22)) - Add Button `icon` prop and Text `truncated` prop @Bugaa92 ([#13](https://github.com/stardust-ui/react/pull/13)) +- Add Button `disabled` prop @Bugaa92 ([#14](https://github.com/stardust-ui/react/pull/14)) ## [v0.2.3](https://github.com/stardust-ui/react/tree/v0.2.3) (2018-07-24) diff --git a/docs/src/examples/components/Button/States/ButtonExampleDisabled.shorthand.tsx b/docs/src/examples/components/Button/States/ButtonExampleDisabled.shorthand.tsx new file mode 100644 index 0000000000..4478806faa --- /dev/null +++ b/docs/src/examples/components/Button/States/ButtonExampleDisabled.shorthand.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { Button } from '@stardust-ui/react' + +const ButtonExampleDisabled = () => ( +
+
+) + +export default ButtonExampleDisabled diff --git a/docs/src/examples/components/Button/States/ButtonExampleDisabled.tsx b/docs/src/examples/components/Button/States/ButtonExampleDisabled.tsx new file mode 100644 index 0000000000..af895ff118 --- /dev/null +++ b/docs/src/examples/components/Button/States/ButtonExampleDisabled.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { Button, Icon, Text } from '@stardust-ui/react' + +const ButtonExampleDisabled = () => ( +
+ + + + + +
+
+ +
+) + +export default ButtonExampleDisabled diff --git a/docs/src/examples/components/Button/States/index.tsx b/docs/src/examples/components/Button/States/index.tsx new file mode 100644 index 0000000000..a505470c8b --- /dev/null +++ b/docs/src/examples/components/Button/States/index.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample' +import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection' + +const States = () => ( + + + +) + +export default States diff --git a/docs/src/examples/components/Button/index.tsx b/docs/src/examples/components/Button/index.tsx index a0c60ea521..e28853e499 100644 --- a/docs/src/examples/components/Button/index.tsx +++ b/docs/src/examples/components/Button/index.tsx @@ -1,10 +1,12 @@ import React from 'react' import Types from './Types' import Variations from './Variations' +import States from './States' const ButtonExamples = () => (
+
) diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 62453edc07..7c32d4ac55 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,5 +1,5 @@ import PropTypes from 'prop-types' -import React, { ReactNode, CSSProperties } from 'react' +import React, { ReactNode, CSSProperties, SyntheticEvent } from 'react' import { UIComponent, childrenExist, customPropTypes, IRenderResultConfig } from '../../lib' import buttonRules from './buttonRules' @@ -16,9 +16,11 @@ export interface IButtonProps { circular?: boolean className?: string content?: ReactNode + disabled?: boolean fluid?: boolean icon?: boolean | string iconPosition?: IconPosition + onClick?: (e: SyntheticEvent, props: IButtonProps) => void style?: CSSProperties type?: ButtonType } @@ -50,6 +52,9 @@ class Button extends UIComponent { /** Additional classes. */ className: PropTypes.string, + /** A button can show it is currently unable to be interacted with. */ + disabled: PropTypes.bool, + /** Shorthand for primary content. */ content: customPropTypes.contentShorthand, @@ -62,6 +67,13 @@ class Button extends UIComponent { /** An icon button can format an Icon to appear before or after the button */ iconPosition: PropTypes.oneOf(['before', 'after']), + /** + * Called after user's click. + * @param {SyntheticEvent} event - React's original SyntheticEvent. + * @param {object} data - All props. + */ + onClick: PropTypes.func, + /** A button can be formatted to show different levels of emphasis. */ type: PropTypes.oneOf(['primary', 'secondary']), } @@ -72,9 +84,11 @@ class Button extends UIComponent { 'circular', 'className', 'content', + 'disabled', 'fluid', 'icon', 'iconPosition', + 'onClick', 'type', ] @@ -87,7 +101,7 @@ class Button extends UIComponent { classes, rest, }: IRenderResultConfig): ReactNode { - const { children, content, icon, iconPosition, type } = this.props + const { children, content, disabled, icon, iconPosition, type } = this.props const primary = type === 'primary' const getContent = (): ReactNode => { @@ -113,11 +127,29 @@ class Button extends UIComponent { } return ( - + {getContent()} ) } + + private handleClick = (e: SyntheticEvent) => { + const { onClick, disabled } = this.props + + if (disabled) { + e.preventDefault() + return + } + + if (onClick) { + onClick(e, this.props) + } + } } export default Button diff --git a/src/components/Button/buttonRules.ts b/src/components/Button/buttonRules.ts index b990aba4c3..f16e985677 100644 --- a/src/components/Button/buttonRules.ts +++ b/src/components/Button/buttonRules.ts @@ -1,11 +1,11 @@ import { pxToRem } from '../../lib' -import { truncateStyle } from '../../styles/customCSS' +import { disabledStyle, truncateStyle } from '../../styles/customCSS' import { IButtonVariables } from './buttonVariables' import { IButtonProps } from './Button' export default { root: ({ props, variables }: { props: IButtonProps; variables: IButtonVariables }) => { - const { circular, fluid, icon, iconPosition, type } = props + const { circular, disabled, fluid, icon, iconPosition, type } = props const primary = type === 'primary' const secondary = type === 'secondary' @@ -27,7 +27,7 @@ export default { typeSecondaryBorderColor, } = variables - return { + const rules = { height, minWidth, maxWidth, @@ -37,12 +37,8 @@ export default { padding: `0 ${pxToRem(paddingLeftRightValue)}`, margin: `0 ${pxToRem(8)} 0 0`, verticalAlign: 'middle', - cursor: 'pointer', - borderWidth: `${secondary ? (circular ? 1 : 2) : 0}px`, borderRadius: pxToRem(2), - ':hover': { - backgroundColor: backgroundColorHover, - }, + borderWidth: 0, ...truncateStyle, @@ -67,6 +63,23 @@ export default { width: '100%', maxWidth: '100%', }), + } + + if (disabled) { + return { + ...rules, + ...disabledStyle, + } + } + + return { + ...rules, + + borderWidth: `${secondary ? (circular ? 1 : 2) : 0}px`, + cursor: 'pointer', + ':hover': { + backgroundColor: backgroundColorHover, + }, ...(primary && { color: typePrimaryColor, diff --git a/src/components/Button/buttonVariables.ts b/src/components/Button/buttonVariables.ts index a8894a4031..3676345504 100644 --- a/src/components/Button/buttonVariables.ts +++ b/src/components/Button/buttonVariables.ts @@ -25,8 +25,8 @@ export default (siteVars: any): IButtonVariables => { maxWidth: pxToRem(280), backgroundColor: siteVars.gray08, backgroundColorHover: siteVars.gray06, - paddingLeftRightValue: 20, circularRadius: pxToRem(999), + paddingLeftRightValue: 20, typePrimaryColor: siteVars.white, typePrimaryBackgroundColor: siteVars.brand, typePrimaryBackgroundColorHover: siteVars.brand04, diff --git a/test/specs/components/Button/Button-test.tsx b/test/specs/components/Button/Button-test.tsx index 342485a754..c894013ef0 100644 --- a/test/specs/components/Button/Button-test.tsx +++ b/test/specs/components/Button/Button-test.tsx @@ -1,7 +1,7 @@ import React from 'react' import { isConformant } from 'test/specs/commonTests' -import { getTestingRenderedComponent } from 'test/utils' +import { getTestingRenderedComponent, mountWithProvider } from 'test/utils' import Button from 'src/components/Button/Button' @@ -47,4 +47,14 @@ describe('Button', () => { expect(btnCircular).toEqual(true) }) }) + + describe('onClick', () => { + it('does not call onClick when the button is disabled', () => { + const onClick = jest.fn() + const button = mountWithProvider(