diff --git a/packages/components/src/components/text-input/_text-input.scss b/packages/components/src/components/text-input/_text-input.scss index c39774fbb80e..a13132e7b89d 100644 --- a/packages/components/src/components/text-input/_text-input.scss +++ b/packages/components/src/components/text-input/_text-input.scss @@ -160,6 +160,11 @@ } } + .#{$prefix}--text-input__field-wrapper.#{$prefix}--password-input__field-wrapper + .#{$prefix}--text-input__invalid-icon { + right: $carbon--spacing-07; + } + .#{$prefix}--password-input-wrapper .#{$prefix}--text-input__invalid-icon { right: $carbon--spacing-08; } diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index fd036d934850..6b0a012feeba 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -5571,6 +5571,9 @@ Map { "isRequired": true, "type": "string", }, + "inline": Object { + "type": "bool", + }, "invalid": Object { "type": "bool", }, @@ -5633,6 +5636,12 @@ Map { ], "type": "oneOfType", }, + "warn": Object { + "type": "bool", + }, + "warnText": Object { + "type": "node", + }, }, "render": [Function], }, diff --git a/packages/react/src/components/TextInput/PasswordInput.js b/packages/react/src/components/TextInput/PasswordInput.js index 718e15df4585..92e696a6df12 100644 --- a/packages/react/src/components/TextInput/PasswordInput.js +++ b/packages/react/src/components/TextInput/PasswordInput.js @@ -1,9 +1,15 @@ -import React, { useState } from 'react'; +import React, { useContext, useState } from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; import { settings } from 'carbon-components'; -import { View16, ViewOff16, WarningFilled16 } from '@carbon/icons-react'; +import { + View16, + ViewOff16, + WarningAltFilled16, + WarningFilled16, +} from '@carbon/icons-react'; import { textInputProps } from './util'; +import { FormContext } from '../FluidForm'; const { prefix } = settings; @@ -17,6 +23,7 @@ const PasswordInput = React.forwardRef(function PasswordInput( onChange, onClick, hideLabel, + inline, invalid, invalidText, helperText, @@ -26,6 +33,8 @@ const PasswordInput = React.forwardRef(function PasswordInput( hidePasswordLabel = 'Hide password', showPasswordLabel = 'Show password', size, + warn, + warnText, ...other }, ref @@ -34,6 +43,7 @@ const PasswordInput = React.forwardRef(function PasswordInput( const togglePasswordVisibility = () => setInputType(inputType === 'password' ? 'text' : 'password'); const errorId = id + '-error-msg'; + const warnId = id + '-warn-msg'; const textInputClasses = classNames( `${prefix}--text-input`, `${prefix}--password-input`, @@ -62,23 +72,58 @@ const PasswordInput = React.forwardRef(function PasswordInput( ref, ...other, }; + const inputWrapperClasses = classNames( + `${prefix}--form-item`, + `${prefix}--text-input-wrapper`, + `${prefix}--password-input-wrapper`, + { + [`${prefix}--text-input-wrapper--light`]: light, + [`${prefix}--text-input-wrapper--inline`]: inline, + } + ); const labelClasses = classNames(`${prefix}--label`, { [`${prefix}--visually-hidden`]: hideLabel, [`${prefix}--label--disabled`]: disabled, + [`${prefix}--label--inline`]: inline, + [`${prefix}--label--inline--${size}`]: inline && !!size, }); const helperTextClasses = classNames(`${prefix}--form__helper-text`, { [`${prefix}--form__helper-text--disabled`]: disabled, + [`${prefix}--form__helper-text--inline`]: inline, }); + const fieldOuterWrapperClasses = classNames( + `${prefix}--text-input__field-outer-wrapper`, + { + [`${prefix}--text-input__field-outer-wrapper--inline`]: inline, + } + ); + const fieldWrapperClasses = classNames( + `${prefix}--text-input__field-wrapper`, + { + [`${prefix}--text-input__field-wrapper--warning`]: !invalid && warn, + } + ); const label = labelText ? ( ) : null; - const error = invalid ? ( -
- {invalidText} -
- ) : null; + + let error = null; + if (invalid) { + error = ( +
+ {invalidText} +
+ ); + } else if (warn) { + error = ( +
+ {warnText} +
+ ); + } + const passwordIsVisible = inputType === 'text'; const passwordVisibilityIcon = passwordIsVisible ? ( @@ -100,7 +145,13 @@ const PasswordInput = React.forwardRef(function PasswordInput( const input = ( <> @@ -122,19 +173,36 @@ const PasswordInput = React.forwardRef(function PasswordInput(
{helperText}
) : null; + const { isFluid } = useContext(FormContext); + return ( -
- {label} -
- {invalid && ( - - )} - {input} +
+ {!inline ? ( + label + ) : ( +
+ {label} + {!isFluid && helper} +
+ )} +
+
+ {invalid && ( + + )} + {!invalid && warn && ( + + )} + {input} + {isFluid && !inline && error} +
+ {!isFluid && error} + {!invalid && !warn && !isFluid && !inline && helper}
- {error ? error : helper}
); }); @@ -176,6 +244,11 @@ PasswordInput.propTypes = { */ id: PropTypes.string.isRequired, + /** + * `true` to use the inline version. + */ + inline: PropTypes.bool, + /** * Specify whether the control is currently invalid */ @@ -240,6 +313,16 @@ PasswordInput.propTypes = { * Provide the current value of the `` */ 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, }; PasswordInput.defaultProps = { diff --git a/packages/react/src/components/TextInput/TextInput.js b/packages/react/src/components/TextInput/TextInput.js index b2aa78d3b69f..4894245040dd 100644 --- a/packages/react/src/components/TextInput/TextInput.js +++ b/packages/react/src/components/TextInput/TextInput.js @@ -261,6 +261,7 @@ TextInput.propTypes = { * 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 */