diff --git a/e2e/__tests__/__image_snapshots__/radio-group-field-test-js-components-radio-button-1-snap.png b/e2e/__tests__/__image_snapshots__/radio-group-field-test-js-components-radio-button-1-snap.png new file mode 100644 index 00000000..e4414f6c Binary files /dev/null and b/e2e/__tests__/__image_snapshots__/radio-group-field-test-js-components-radio-button-1-snap.png differ diff --git a/e2e/__tests__/__image_snapshots__/radio-test-js-components-radio-group-field-button-1-snap.png b/e2e/__tests__/__image_snapshots__/radio-test-js-components-radio-group-field-button-1-snap.png new file mode 100644 index 00000000..6edd2c9b Binary files /dev/null and b/e2e/__tests__/__image_snapshots__/radio-test-js-components-radio-group-field-button-1-snap.png differ diff --git a/e2e/__tests__/radio-group-field.test.js b/e2e/__tests__/radio-group-field.test.js index c31f1806..1ac6f536 100644 --- a/e2e/__tests__/radio-group-field.test.js +++ b/e2e/__tests__/radio-group-field.test.js @@ -3,6 +3,7 @@ import { baisy } from '../setup/TestSuiter'; const SUITES = [ baisy.suite('Components/Radio', 'common'), + baisy.suite('Components/Radio', 'button'), baisy.suite('Components/Radio', 'with custom gap'), ]; diff --git a/e2e/__tests__/radio.test.js b/e2e/__tests__/radio.test.js index 31f46f3d..cdbdde09 100644 --- a/e2e/__tests__/radio.test.js +++ b/e2e/__tests__/radio.test.js @@ -3,6 +3,7 @@ import { baisy } from '../setup/TestSuiter'; const SUITES = [ baisy.suite('Components/RadioGroupField', 'default story'), + baisy.suite('Components/RadioGroupField', 'button'), baisy.suite('Components/RadioGroupField', 'disabled story'), baisy.suite('Components/RadioGroupField', 'with error'), ]; diff --git a/src/components/Radio/Radio.stories.js b/src/components/Radio/Radio.stories.js index 55714d3e..800121d2 100644 --- a/src/components/Radio/Radio.stories.js +++ b/src/components/Radio/Radio.stories.js @@ -32,6 +32,22 @@ common.story = { name: 'common', }; +export const button = () => ( + + { ({ value, changeValue }) => ( + + + + + + ) } + +); + +button.story = { + name: 'button', +}; + export const withCustomGap = () => ( diff --git a/src/components/Radio/Radio.theme.js b/src/components/Radio/Radio.theme.js index 9f14fc6b..f606617f 100644 --- a/src/components/Radio/Radio.theme.js +++ b/src/components/Radio/Radio.theme.js @@ -84,6 +84,27 @@ const [RadioWrapperTag, themeRadioWrapper] = createThemeTag(`${name}Wrapper`, { }, }); +const [RadioButtonTag, themeRadioButton] = createThemeTag(`${name}Button`, { + root: { + flex: 1, + + '&:first-child > *': { + borderRightStyle: 'unset', + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + }, + + '&:last-child > *': { + borderLeftStyle: 'unset', + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + }, + + '&:not(:first-child):not(:last-child) > *': { + borderRadius: 0, + }, + }, +}); const [RadioTag, themeRadio] = createThemeTag(name, { root: { @@ -98,6 +119,7 @@ const theme = { ...themeCircleInner, ...themeText, ...themeRadioWrapper, + ...themeRadioButton, ...themeRadio, }; @@ -108,5 +130,6 @@ export { RadioTag, RadioWrapperTag, RadioCircleInnerTag, + RadioButtonTag, RadioTextTag, }; diff --git a/src/components/Radio/RadioButton.js b/src/components/Radio/RadioButton.js new file mode 100644 index 00000000..0fd79d82 --- /dev/null +++ b/src/components/Radio/RadioButton.js @@ -0,0 +1,63 @@ +// @flow + +import React, { useCallback } from 'react'; +import { RadioTag, RadioButtonTag } from './Radio.theme'; + +import { Button } from '../Button'; + +type EqualsFuncArgument = { + selectedValue?: string | number, + value: string | number, +}; + +type RadioButtonClonedProps = { + /** private cloned props */ + name?: string, + /** private cloned props */ + onChange?: (string | number, SyntheticInputEvent) => void, + /** private cloned props */ + selectedValue?: string | number, + /** then true when show error styles */ + hasError?: boolean, +}; + +type RadioButtonProps = { + /** text of the label */ + label?: string, + /** radio value */ + value: string | number, + /** when true then disable radio */ + disabled?: boolean, + /** custom function to check the equals */ + equalsFunc?: (EqualsFuncArgument) => boolean, +}; + +const RadioButton = ({ + onChange, + value, + disabled, + selectedValue, + equalsFunc = ({ selectedValue, value }: EqualsFuncArgument) => selectedValue === value, + name, + label, + ...rest +}: RadioButtonProps & RadioButtonClonedProps) => { + const handleChange = useCallback((event) => { + if (typeof onChange === 'function' && !disabled) { + onChange(value, event); + } + }, [disabled, onChange, value]); + + const checked = value !== undefined && equalsFunc && equalsFunc({ selectedValue, value }); + + return ( + + + + ); +}; + +export { RadioButton }; diff --git a/src/components/Radio/RadioGroup.js b/src/components/Radio/RadioGroup.js index ba4f2721..ae59e267 100644 --- a/src/components/Radio/RadioGroup.js +++ b/src/components/Radio/RadioGroup.js @@ -23,6 +23,8 @@ type RadioProps = { options?: Array<({ value: any, label: string })>, /** disabled */ disabled?: boolean, + /** stretch */ + stretch?: boolean, } class RadioGroup extends PureComponent { @@ -57,10 +59,10 @@ class RadioGroup extends PureComponent { } render() { - const { children, value, direction, gap, onChange, hasError, disabled, ...rest } = this.props; + const { children, value, direction, gap, onChange, hasError, disabled, stretch, ...rest } = this.props; return ( - + { React.Children.map(this.renderChildren(), child => React.cloneElement(child, { diff --git a/src/components/Radio/index.js b/src/components/Radio/index.js index fd478d70..6afdec22 100644 --- a/src/components/Radio/index.js +++ b/src/components/Radio/index.js @@ -1,10 +1,12 @@ // @flow import { RadioItem } from './RadioItem'; +import { RadioButton } from './RadioButton'; import { RadioGroup } from './RadioGroup'; import { theme } from './Radio.theme'; const Radio = { + Button: RadioButton, Item: RadioItem, Group: RadioGroup, }; diff --git a/src/components/RadioGroupField/RadioGroupField.js b/src/components/RadioGroupField/RadioGroupField.js index 459314ae..e4c3922c 100644 --- a/src/components/RadioGroupField/RadioGroupField.js +++ b/src/components/RadioGroupField/RadioGroupField.js @@ -24,6 +24,8 @@ type RadioGroupFieldProps = { options?: Array<({ value: any, label: string })>, /** disabled */ disabled?: boolean, + /** stretch */ + stretch?: boolean, }; const RadioGroupField = ({ @@ -35,6 +37,7 @@ const RadioGroupField = ({ meta, options, disabled, + stretch, ...rest }: RadioGroupFieldProps) => { const { name, value, onChange } = input; @@ -52,6 +55,7 @@ const RadioGroupField = ({ options={ options } value={ value } disabled={ disabled } + stretch={ stretch } > { children } diff --git a/src/components/RadioGroupField/RadioGroupField.stories.js b/src/components/RadioGroupField/RadioGroupField.stories.js index 80404534..f0533d84 100644 --- a/src/components/RadioGroupField/RadioGroupField.stories.js +++ b/src/components/RadioGroupField/RadioGroupField.stories.js @@ -19,6 +19,18 @@ defaultStory.story = { name: 'default', }; +export const button = () => ( + + + + + +); + +button.story = { + name: 'button', +}; + export const disabledStory = () => (