Skip to content

Commit

Permalink
feat(TextArea): add warning state (#13293)
Browse files Browse the repository at this point in the history
* feat(TextArea): add warning state

* chore: update snapshots

* fix: textarea error bottom border and default value in story

* chore: hide resize fluid textarea invalid and warn

---------

Co-authored-by: Andrea N. Cardona <cardona.n.andrea@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 13, 2023
1 parent 4886cb9 commit 242256a
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 11 deletions.
14 changes: 14 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7832,6 +7832,8 @@ Map {
"onClick": [Function],
"placeholder": "",
"rows": 4,
"warn": false,
"warnText": "",
},
"propTypes": Object {
"className": Object {
Expand Down Expand Up @@ -7910,6 +7912,12 @@ Map {
],
"type": "oneOfType",
},
"warn": Object {
"type": "bool",
},
"warnText": Object {
"type": "node",
},
},
"render": [Function],
},
Expand Down Expand Up @@ -9970,6 +9978,12 @@ Map {
],
"type": "oneOfType",
},
"warn": Object {
"type": "bool",
},
"warnText": Object {
"type": "node",
},
},
},
"unstable__FluidTextAreaSkeleton" => Object {
Expand Down
10 changes: 10 additions & 0 deletions packages/react/src/components/FluidTextArea/FluidTextArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ FluidTextArea.propTypes = {
* Provide the current value of the `<textarea>`
*/
value: 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 FluidTextArea;
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,16 @@ Playground.argTypes = {
},
defaultValue: '500',
},
warn: {
control: {
type: 'boolean',
},
defaultValue: false,
},
warnText: {
control: {
type: 'text',
},
defaultValue: 'This is a warning message.',
},
};
15 changes: 14 additions & 1 deletion packages/react/src/components/TextArea/TextArea.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ Playground.argTypes = {
control: {
type: 'text',
},
defaultValue: '',
defaultValue:
'Error message that is really long can wrap to more lines but should not be excessively long.',
},
labelText: {
control: {
Expand All @@ -140,6 +141,18 @@ Playground.argTypes = {
},
defaultValue: 4,
},
warn: {
control: {
type: 'boolean',
},
defaultValue: false,
},
warnText: {
control: {
type: 'text',
},
defaultValue: 'This is a warning message.',
},
};

Playground.args = {
Expand Down
49 changes: 47 additions & 2 deletions packages/react/src/components/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import PropTypes, { ReactNodeLike } from 'prop-types';
import React, { useState, useContext, useRef } from 'react';
import classNames from 'classnames';
import deprecate from '../../prop-types/deprecate';
import { WarningFilled } from '@carbon/icons-react';
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
import { useFeatureFlag } from '../FeatureFlags';
import { usePrefix } from '../../internal/usePrefix';
import { FormContext } from '../FluidForm';
Expand Down Expand Up @@ -123,6 +123,16 @@ export interface TextAreaProps
* Provide the current value of the `<textarea>`
*/
value?: string | number;

/**
* Specify whether the control is currently in warning state
*/
warn?: boolean;

/**
* Provide the text that is displayed when the control is in warning state
*/
warnText?: ReactNodeLike;
}

const TextArea = React.forwardRef((props: TextAreaProps, forwardRef) => {
Expand All @@ -140,6 +150,8 @@ const TextArea = React.forwardRef((props: TextAreaProps, forwardRef) => {
placeholder,
enableCounter,
maxCount,
warn = false,
warnText,
...other
} = props;
const prefix = usePrefix();
Expand Down Expand Up @@ -214,12 +226,24 @@ const TextArea = React.forwardRef((props: TextAreaProps, forwardRef) => {
</div>
) : null;

const warning = warn ? (
<div role="alert" className={`${prefix}--form-requirement`}>
{warnText}
{isFluid && (
<WarningAltFilled
className={`${prefix}--text-area__invalid-icon ${prefix}--text-area__invalid-icon--warning`}
/>
)}
</div>
) : null;

const textareaClasses = classNames(
`${prefix}--text-area`,
[enabled ? null : className],
{
[`${prefix}--text-area--light`]: light,
[`${prefix}--text-area--invalid`]: invalid,
[`${prefix}--text-area--warn`]: warn,
}
);

Expand Down Expand Up @@ -265,19 +289,28 @@ const TextArea = React.forwardRef((props: TextAreaProps, forwardRef) => {
<div
className={classNames(`${prefix}--text-area__wrapper`, {
[`${prefix}--text-area__wrapper--readonly`]: other.readOnly,
[`${prefix}--text-area__wrapper--warn`]: warn,
})}
data-invalid={invalid || null}>
{invalid && !isFluid && (
<WarningFilled className={`${prefix}--text-area__invalid-icon`} />
)}
{warn && !invalid && !isFluid && (
<WarningAltFilled
className={`${prefix}--text-area__invalid-icon ${prefix}--text-area__invalid-icon--warning`}
/>
)}
{input}
<span className={`${prefix}--text-area__counter-alert`} role="alert">
{ariaAnnouncement}
</span>
{isFluid && <hr className={`${prefix}--text-area__divider`} />}
{isFluid && invalid ? error : null}
{isFluid && warn && !invalid ? warning : null}
</div>
{invalid && !isFluid ? error : helper}
{!invalid && !warn && !isFluid ? helper : null}
{invalid && !isFluid ? error : null}
{warn && !invalid && !isFluid ? warning : null}
</div>
);
});
Expand Down Expand Up @@ -387,6 +420,16 @@ TextArea.propTypes = {
* Provide the current value of the `<textarea>`
*/
value: 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,
};

TextArea.defaultProps = {
Expand All @@ -400,6 +443,8 @@ TextArea.defaultProps = {
helperText: '',
enableCounter: false,
maxCount: undefined,
warn: false,
warnText: '',
};

export default TextArea;
Original file line number Diff line number Diff line change
Expand Up @@ -91,35 +91,62 @@
display: none;
}

.#{$prefix}--text-area--fluid .#{$prefix}--text-area--invalid,
.#{$prefix}--text-area--fluid .#{$prefix}--text-area--warn {
resize: none;
}

.#{$prefix}--text-area--fluid
.#{$prefix}--text-area__wrapper[data-invalid]
.#{$prefix}--text-area__divider,
.#{$prefix}--text-area--fluid
.#{$prefix}--text-area--invalid
+ .#{$prefix}--text-area__divider {
.#{$prefix}--text-area__wrapper--warn
.#{$prefix}--text-area__divider {
display: block;
border-style: solid;
border-color: $border-subtle;
border-bottom: none;
margin: 0 1rem;
}

// invalid error message container
// invalid & warning error message container
.#{$prefix}--text-area--fluid
.#{$prefix}--text-area--invalid
+ .#{$prefix}--text-area__divider
+ .#{$prefix}--form-requirement {
.#{$prefix}--text-area__wrapper[data-invalid]
.#{$prefix}--form-requirement.#{$prefix}--form-requirement,
.#{$prefix}--text-area--fluid
.#{$prefix}--text-area__wrapper--warn
.#{$prefix}--form-requirement.#{$prefix}--form-requirement {
position: relative;
display: block;
overflow: visible;
max-height: 12.5rem;
padding: 0.5rem 2.5rem 0.5rem 1rem;
margin: 0;
background: $field;
}

.#{$prefix}--text-area--fluid
.#{$prefix}--text-area__wrapper--warn
.#{$prefix}--form-requirement.#{$prefix}--form-requirement {
border-bottom: 1px solid $border-strong;
color: $text-primary;
}

.#{$prefix}--text-area--fluid
.#{$prefix}--text-area__wrapper[data-invalid]
.#{$prefix}--form-requirement.#{$prefix}--form-requirement {
border-bottom: none;
color: $text-error;
}

.#{$prefix}--text-area--fluid .#{$prefix}--text-area--warn {
border-bottom: none;
}

.#{$prefix}--modal
.#{$prefix}--text-area--fluid
.#{$prefix}--text-area--invalid
+ .#{$prefix}--text-area__divider
.#{$prefix}--text-area__wrapper[data-invalid]
.#{$prefix}--text-area__divider
+ .#{$prefix}--form-requirement {
background: $field-02;
}
Expand Down
1 change: 1 addition & 0 deletions packages/styles/scss/components/form/_form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ $input-label-weight: 400 !default;
.#{$prefix}--text-input__field-wrapper--warning,
.#{$prefix}--text-input__field-wrapper--warning > .#{$prefix}--text-input,
.#{$prefix}--text-area__wrapper[data-invalid],
.#{$prefix}--text-area__wrapper--warn,
.#{$prefix}--select-input__wrapper[data-invalid],
.#{$prefix}--select--warning .#{$prefix}--select-input__wrapper,
.#{$prefix}--time-picker[data-invalid],
Expand Down
10 changes: 10 additions & 0 deletions packages/styles/scss/components/text-area/_text-area.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

@use '../form';
@use '../../colors' as *;
@use '../../config' as *;
@use '../../motion' as *;
@use '../../spacing' as *;
Expand Down Expand Up @@ -71,6 +72,15 @@
fill: $support-error;
}

.#{$prefix}--text-area__invalid-icon--warning {
fill: $support-warning;
}

.#{$prefix}--text-area__invalid-icon--warning path[fill] {
fill: $black-100;
opacity: 1;
}

.#{$prefix}--text-area__counter-alert {
position: absolute;
overflow: hidden;
Expand Down

0 comments on commit 242256a

Please sign in to comment.