Skip to content

Commit

Permalink
feat(radio-button): add validation props (#13317)
Browse files Browse the repository at this point in the history
* feat(radio-button): add validation props

* chore(radiobutton): update spacing

* chore(radio-button): update snapshots

* chore(radio-button): fix css and argtypes

* chore(radio-button): update classnames

* Update RadioButtonGroup.js

* chore(radio-button): yarn format

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
aledavila and kodiakhq[bot] authored Mar 23, 2023
1 parent 33f683f commit d8afeeb
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 10 deletions.
15 changes: 15 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5924,6 +5924,15 @@ Map {
"disabled": Object {
"type": "bool",
},
"helperText": Object {
"type": "node",
},
"invalid": Object {
"type": "bool",
},
"invalidText": Object {
"type": "node",
},
"labelPosition": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -5968,6 +5977,12 @@ Map {
],
"type": "oneOfType",
},
"warn": Object {
"type": "bool",
},
"warnText": Object {
"type": "node",
},
},
"render": [Function],
},
Expand Down
61 changes: 52 additions & 9 deletions packages/react/src/components/RadioButton/RadioButton.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ export default {
page: mdx,
},
},
argTypes: {
readOnly: {
description: 'Specify whether the RadioButtonGroup is read-only',
control: {
type: 'boolean',
},
},
},
};

export const Default = () => {
Expand Down Expand Up @@ -65,7 +57,7 @@ export const Skeleton = () => {

export const Playground = (args) => {
return (
<RadioButtonGroup labelText="Radio Button group" {...args}>
<RadioButtonGroup legendText="Radio Button group" {...args}>
<RadioButton
labelText="Radio button label"
value="radio-1"
Expand All @@ -84,3 +76,54 @@ export const Playground = (args) => {
</RadioButtonGroup>
);
};

Playground.argTypes = {
readOnly: {
description: 'Specify whether the RadioButtonGroup is read-only',
control: {
type: 'boolean',
},
},
helperText: {
description:
'Provide text that is used alongside the control label for additional help',
control: {
type: 'text',
},
defaultValue: 'Helper text',
},
invalid: {
description: 'Specify whether the RadioButtonGroup is invalid',
control: {
type: 'boolean',
},
},
invalidText: {
description:
'Provide the text that is displayed when the control is in an invalid state',
control: {
type: 'text',
},
defaultValue: 'Invalid selection',
},
orientation: {
description: 'Provide how radio buttons should be displayed',
control: 'select',
options: ['horizontal', 'vertical'],
},
warn: {
description: 'Specify whether the control is currently in warning state',
control: {
type: 'boolean',
},
defaultValue: false,
},
warnText: {
description:
'Provide the text that is displayed when the control is in warning state',
control: {
type: 'text',
},
defaultValue: 'Please notice the warning',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React, { createContext, useState } from 'react';
import classNames from 'classnames';
import { Legend } from '../Text';
import { usePrefix } from '../../internal/usePrefix';
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';

export const RadioButtonGroupContext = createContext();

Expand All @@ -19,13 +20,18 @@ const RadioButtonGroup = React.forwardRef(function RadioButtonGroup(
className,
defaultSelected,
disabled,
helperText,
invalid = false,
invalidText,
labelPosition = 'right',
legendText,
name,
onChange = () => {},
orientation = 'horizontal',
readOnly,
valueSelected,
warn = false,
warnText,
...rest
},
ref
Expand Down Expand Up @@ -75,27 +81,60 @@ const RadioButtonGroup = React.forwardRef(function RadioButtonGroup(
}
}

const showWarning = !readOnly && !invalid && warn;
const showHelper = !invalid && !disabled && !warn;

const wrapperClasses = classNames(`${prefix}--form-item`, className);

const fieldsetClasses = classNames(`${prefix}--radio-button-group`, {
[`${prefix}--radio-button-group--${orientation}`]:
orientation === 'vertical',
[`${prefix}--radio-button-group--label-${labelPosition}`]: labelPosition,
[`${prefix}--radio-button-group--readonly`]: readOnly,
[`${prefix}--radio-button-group--invalid`]: !readOnly && invalid,
[`${prefix}--radio-button-group--warning`]: showWarning,
});

const wrapperClasses = classNames(`${prefix}--form-item`, className);
const helperClasses = classNames(`${prefix}--form__helper-text`, {
[`${prefix}--form__helper-text--disabled`]: disabled,
});

const helper = helperText ? (
<div className={helperClasses}>{helperText}</div>
) : null;

return (
<div className={wrapperClasses} ref={ref}>
<fieldset
className={fieldsetClasses}
disabled={disabled}
data-invalid={invalid ? true : undefined}
aria-readonly={readOnly}
{...rest}>
{legendText && (
<Legend className={`${prefix}--label`}>{legendText}</Legend>
)}
{getRadioButtons()}
</fieldset>
<div className={`${prefix}--radio-button__validation-msg`}>
{!readOnly && invalid && (
<>
<WarningFilled
className={`${prefix}--radio-button__invalid-icon`}
/>
<div className={`${prefix}--form-requirement`}>{invalidText}</div>
</>
)}
{showWarning && (
<>
<WarningAltFilled
className={`${prefix}--radio-button__invalid-icon ${prefix}--radio-button__invalid-icon--warning`}
/>
<div className={`${prefix}--form-requirement`}>{warnText}</div>
</>
)}
{showHelper && helper}
</div>
</div>
);
});
Expand All @@ -121,6 +160,21 @@ RadioButtonGroup.propTypes = {
*/
disabled: PropTypes.bool,

/**
* Provide text that is used alongside the control label for additional help
*/
helperText: PropTypes.node,

/**
* Specify whether the control is currently invalid
*/
invalid: PropTypes.bool,

/**
* Provide the text that is displayed when the control is in an invalid state
*/
invalidText: PropTypes.node,

/**
* Provide where label text should be placed
*/
Expand Down Expand Up @@ -157,6 +211,16 @@ RadioButtonGroup.propTypes = {
* Specify the value that is currently selected in the group
*/
valueSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

/**
* Specify whether the control is currently in warning state
*/
warn: PropTypes.bool,

/**
* Provide the text that is displayed when the control is in warning state
*/
warnText: PropTypes.node,
};

export default RadioButtonGroup;
57 changes: 57 additions & 0 deletions packages/styles/scss/components/radio-button/_radio-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,63 @@ $radio-border-width: 1px !default;
user-select: text;
}

// invalid + warn
.#{$prefix}--radio-button-group--invalid
.#{$prefix}--radio-button
+ .#{$prefix}--radio-button__label
.#{$prefix}--radio-button__appearance {
border-color: $support-error;
}

.#{$prefix}--radio-button__validation-msg {
display: none;
align-items: flex-end;
margin-top: $spacing-03;
}

.#{$prefix}--radio-button__invalid-icon {
margin: 0 rem(1px) 0 rem(3px);
fill: $support-error;
}

.#{$prefix}--radio-button__invalid-icon--warning {
fill: $support-warning;
}

.#{$prefix}--radio-button__invalid-icon--warning path:first-of-type {
fill: #000000;
}

.#{$prefix}--radio-button__validation-msg .#{$prefix}--form__helper-text {
margin-top: 0;
}

.#{$prefix}--radio-button-group--invalid
+ .#{$prefix}--radio-button__validation-msg,
.#{$prefix}--radio-button-group--warning
+ .#{$prefix}--radio-button__validation-msg {
display: flex;
}

.#{$prefix}--radio-button-group--invalid
+ .#{$prefix}--radio-button__validation-msg
.#{$prefix}--form-requirement,
.#{$prefix}--radio-button-group--warning
+ .#{$prefix}--radio-button__validation-msg
.#{$prefix}--form-requirement {
display: block;
overflow: visible;
max-height: 100%;
margin-top: 0;
margin-left: $spacing-03;
}

.#{$prefix}--radio-button-group--invalid
+ .#{$prefix}--radio-button__validation-msg
.#{$prefix}--form-requirement {
color: $text-error;
}

// Focus

.#{$prefix}--radio-button:focus
Expand Down

0 comments on commit d8afeeb

Please sign in to comment.