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().find('Button')
+ button.simulate('click')
+
+ expect(onClick).not.toHaveBeenCalled()
+ })
+ })
})