Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion src/components/controls/TextArea/TextArea.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ $block: '.#{variables.$ns}text-area';
}

&__clear {
position: absolute;
flex-shrink: 0;

&_size_s,
&_size_m {
Expand All @@ -92,6 +92,14 @@ $block: '.#{variables.$ns}text-area';
}
}

&__error-icon {
box-sizing: content-box;
color: var(--g-color-text-danger);
padding-block: var(--_--error-icon-padding-block);
padding-inline: var(--_--error-icon-padding-inline-start)
var(--_--error-icon-padding-inline-end);
}

&_size {
&_s {
#{$block}__control {
Expand All @@ -102,6 +110,10 @@ $block: '.#{variables.$ns}text-area';
padding-inline-end: 26px;
}

--_--error-icon-padding-block: 5px;
--_--error-icon-padding-inline-start: 0;
--_--error-icon-padding-inline-end: 5px;

--_--border-radius: var(--g-border-radius-s);
}

Expand All @@ -114,6 +126,10 @@ $block: '.#{variables.$ns}text-area';
padding-inline-end: 26px;
}

--_--error-icon-padding-block: 5px;
--_--error-icon-padding-inline-start: 0;
--_--error-icon-padding-inline-end: 5px;

--_--border-radius: var(--g-border-radius-m);
}

Expand All @@ -126,6 +142,10 @@ $block: '.#{variables.$ns}text-area';
padding-inline-end: 36px;
}

--_--error-icon-padding-block: 9px;
--_--error-icon-padding-inline-start: 0;
--_--error-icon-padding-inline-end: 9px;

--_--border-radius: var(--g-border-radius-l);
}

Expand All @@ -138,6 +158,10 @@ $block: '.#{variables.$ns}text-area';
padding-inline-end: 36px;
}

--_--error-icon-padding-block: 13px;
--_--error-icon-padding-inline-start: 0;
--_--error-icon-padding-inline-end: 13px;

--_--border-radius: var(--g-border-radius-xl);
}
}
Expand Down
34 changes: 30 additions & 4 deletions src/components/controls/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import * as React from 'react';

import {TriangleExclamation} from '@gravity-ui/icons';

import {useControlledState, useForkRef, useUniqId} from '../../../hooks';
import {useFormResetHandler} from '../../../hooks/private';
import {Icon} from '../../Icon';
import {Popover} from '../../legacy';
import {block} from '../../utils/cn';
import {ClearButton, mapTextInputSizeToButtonSize} from '../common';
import {OuterAdditionalContent} from '../common/OuterAdditionalContent/OuterAdditionalContent';
Expand All @@ -13,7 +17,12 @@ import type {
InputControlSize,
InputControlView,
} from '../types';
import {errorPropsMapper, getInputControlState, prepareAutoComplete} from '../utils';
import {
CONTROL_ERROR_ICON_QA,
errorPropsMapper,
getInputControlState,
prepareAutoComplete,
} from '../utils';

import {TextAreaControl} from './TextAreaControl';

Expand Down Expand Up @@ -51,6 +60,7 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
hasClear = false,
error,
errorMessage: errorMessageProp,
errorPlacement: errorPlacementProp = 'outside',
validationState: validationStateProp,
autoComplete,
id: idProp,
Expand All @@ -64,9 +74,10 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
onChange,
} = props;

const {errorMessage, validationState} = errorPropsMapper({
const {errorMessage, errorPlacement, validationState} = errorPropsMapper({
error,
errorMessage: errorMessageProp,
errorPlacement: errorPlacementProp,
validationState: validationStateProp,
});

Expand All @@ -78,7 +89,10 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
const state = getInputControlState(validationState);
const innerId = useUniqId();

const isErrorMsgVisible = validationState === 'invalid' && Boolean(errorMessage);
const isErrorMsgVisible =
validationState === 'invalid' && Boolean(errorMessage) && errorPlacement === 'outside';
const isErrorIconVisible =
validationState === 'invalid' && Boolean(errorMessage) && errorPlacement === 'inside';
const isClearControlVisible = Boolean(hasClear && !disabled && !readOnly && inputValue);
const id = idProp || innerId;

Expand Down Expand Up @@ -154,6 +168,7 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
state,
pin: view === 'clear' ? undefined : pin,
'has-clear': isClearControlVisible,
'has-error-icon': isErrorIconVisible,
'has-scrollbar': hasVerticalScrollbar,
},
className,
Expand All @@ -164,11 +179,22 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
<TextAreaControl {...props} {...commonProps} controlRef={handleRef} />
{isClearControlVisible && (
<ClearButton
className={b('clear', {size})}
size={mapTextInputSizeToButtonSize(size)}
onClick={handleClear}
className={b('clear', {size})}
/>
)}
{isErrorIconVisible && (
<Popover content={errorMessage}>
<span data-qa={CONTROL_ERROR_ICON_QA}>
<Icon
data={TriangleExclamation}
className={b('error-icon')}
size={size === 's' ? 12 : 16}
/>
</span>
</Popover>
)}
</span>
<OuterAdditionalContent
errorMessage={isErrorMsgVisible ? errorMessage : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@

await expectScreenshot({
themes: ['light'],
clip: {width: 522}

Check failure on line 85 in src/components/controls/TextArea/__tests__/TextArea.visual.test.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Insert `,`
});
});

Expand Down
Loading