Skip to content

Commit

Permalink
feat(TextInput): add rightContent props (#649)
Browse files Browse the repository at this point in the history
  • Loading branch information
korvin89 authored Apr 27, 2023
1 parent 11ff86a commit fd29127
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 18 deletions.
4 changes: 4 additions & 0 deletions src/components/TextInput/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export interface TextInputProps extends DOMProps, QAProps {
* Maximum number of rows in textarea when the hight is autogenerated.
*/
maxRows?: number;
/**
* User`s node rendered after input and clear button
*/
rightContent?: React.ReactNode;
onUpdate?: (value: string) => void;
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
Expand Down
23 changes: 13 additions & 10 deletions src/components/TextInput/TextInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ $block: '.#{variables.$ns}text-input';
}
}

&__additional-content {
display: flex;
align-items: center;
}

&_size {
&_s {
#{$block}__control {
Expand All @@ -139,7 +144,8 @@ $block: '.#{variables.$ns}text-input';
}

#{$block}__additional-content {
height: #{$sHeight};
height: #{$sHeight - $borderWidth * 2};
padding-right: 1px;
}

--yc-text-input-border-radius: var(--yc-border-radius-s);
Expand All @@ -155,7 +161,8 @@ $block: '.#{variables.$ns}text-input';
}

#{$block}__additional-content {
height: #{$mHeight};
height: #{$mHeight - $borderWidth * 2};
padding-right: 1px;
}

--yc-text-input-border-radius: var(--yc-border-radius-m);
Expand All @@ -171,7 +178,8 @@ $block: '.#{variables.$ns}text-input';
}

#{$block}__additional-content {
height: #{$lHeight};
height: #{$lHeight - $borderWidth * 2};
padding-right: 3px;
}

--yc-text-input-border-radius: var(--yc-border-radius-l);
Expand All @@ -187,7 +195,8 @@ $block: '.#{variables.$ns}text-input';
}

#{$block}__additional-content {
height: #{$xlHeight};
height: #{$xlHeight - $borderWidth * 2};
padding-right: 3px;
}

--yc-text-input-border-radius: var(--yc-border-radius-xl);
Expand Down Expand Up @@ -257,12 +266,6 @@ $block: '.#{variables.$ns}text-input';
}
}

&_has-left-content {
#{$block}__control {
padding-left: 2px;
}
}

&_has-right-content {
#{$block}__control {
padding-right: 2px;
Expand Down
8 changes: 6 additions & 2 deletions src/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {useUniqId} from '../utils/useUniqId';
import {InputControl} from './InputControl/InputControl';
import {TextAreaControl} from './TextAreaControl/TextAreaControl';
import {ClearAction} from './ClearAction/ClearAction';
import {AdditionalContent} from './AdditionalContent/AdditionalContent';
import {TextInputProps, TextInputView, TextInputSize, TextInputPin, TextInputState} from './types';

import './TextInput.scss';
Expand Down Expand Up @@ -56,6 +57,7 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(funct
className,
qa,
controlProps: originalControlProps,
rightContent,
} = props;
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? '');
const innerControlRef = React.useRef<HTMLTextAreaElement | HTMLInputElement>(null);
Expand Down Expand Up @@ -118,6 +120,7 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(funct

const isErrorMsgVisible = typeof error === 'string';
const isClearControlVisible = Boolean(hasClear && !disabled && inputValue);
const isRightContentVisible = Boolean(rightContent && !multiline);

const controlProps: TextInputProps['controlProps'] = {
...originalControlProps,
Expand Down Expand Up @@ -158,8 +161,8 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(funct
disabled,
state,
pin: view === 'clear' ? undefined : pin,
'has-left-content': isLabelVisible,
'has-right-content': isClearControlVisible && !multiline,
'has-right-content':
(isClearControlVisible || isRightContentVisible) && !multiline,
'has-scrollbar': hasVerticalScrollbar,
},
className,
Expand All @@ -184,6 +187,7 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(funct
onClick={handleClear}
/>
)}
{isRightContentVisible && <AdditionalContent>{rightContent}</AdditionalContent>}
</span>
{isErrorMsgVisible && <div className={b('error')}>{error}</div>}
</span>
Expand Down
6 changes: 0 additions & 6 deletions src/components/TextInput/__stories__/TextInputShowcase.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
.text-input-showcase {
display: grid;
grid-template:
'text-input' auto
'text-input-label' auto
'text-area' auto / auto;

&__text-input-examples {
grid-area: text-input;
display: grid;
Expand Down
90 changes: 90 additions & 0 deletions src/components/TextInput/__stories__/TextInputShowcase.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from 'react';
import block from 'bem-cn-lite';
import {Checkbox} from '../../Checkbox';
import {Button} from '../../Button';
import {Icon} from '../../Icon';
import {GearIcon} from '../../icons';
import {TextInput} from '../TextInput';
import {TextInputProps} from '../types';
import './TextInputShowcase.scss';
Expand All @@ -10,6 +13,25 @@ const b = block('text-input-showcase');
const LABEL = 'Label:';
const LONG_LABEL = 'Very very long label is limited by 50% width of the input control size';

const RightContent = (props: {size: TextInputProps['size']; disabled?: boolean}) => {
const {size, disabled} = props;
const [selected, setSelected] = React.useState(false);

const handleClick = () => setSelected(!selected);

return (
<Button
view={selected ? 'normal' : 'flat'}
size={size}
selected={selected}
disabled={disabled}
onClick={handleClick}
>
<Icon data={GearIcon} size={18} />
</Button>
);
};

export const TextInputShowcase: React.FC = () => {
const [value, setValue] = React.useState('');
const [isErrorMessageVisible, setErrorMessageVisibility] = React.useState(false);
Expand Down Expand Up @@ -112,6 +134,74 @@ export const TextInputShowcase: React.FC = () => {
</div>
</div>

<div className={b('text-input-examples')}>
<h2 className={b('title')}>TextInput (with right content)</h2>

<div className={'size-examples'}>
<h3 className={b('section-header')}>Sizes:</h3>

<TextInput
{...textInputProps}
size="s"
placeholder="s"
rightContent={<RightContent size="s" />}
/>
<TextInput
{...textInputProps}
placeholder="m"
rightContent={<RightContent size="s" />}
/>
<TextInput
{...textInputProps}
size="l"
placeholder="l"
rightContent={<RightContent size="m" />}
/>
<TextInput
{...textInputProps}
size="xl"
placeholder="xl"
rightContent={<RightContent size="l" />}
/>
</div>

<div className={b('state-examples')}>
<h3 className={b('section-header')}>States:</h3>

<div className={b('row')}>
<TextInput
{...textInputProps}
placeholder="error with message"
error={isErrorMessageVisible ? 'It happened a validation error' : true}
rightContent={<RightContent size="s" />}
/>
<Checkbox
onUpdate={setErrorMessageVisibility}
checked={isErrorMessageVisible}
/>
</div>
<TextInput
{...textInputProps}
placeholder="disabled"
rightContent={<RightContent size="s" disabled />}
disabled
/>
<TextInput
{...textInputProps}
placeholder="clear"
rightContent={<RightContent size="s" />}
hasClear
/>
<TextInput
{...textInputProps}
placeholder="default value"
value={undefined}
defaultValue="defaultValue"
rightContent={<RightContent size="s" />}
/>
</div>
</div>

<div className={b('text-area-examples')}>
<h2 className={b('title')}>TextInput (multiline)</h2>

Expand Down
4 changes: 4 additions & 0 deletions src/components/TextInput/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ export interface TextInputProps extends DOMProps, QAProps {
* Maximum number of rows in textarea when the hight is autogenerated.
*/
maxRows?: number;
/**
* User`s node rendered after input and clear button
*/
rightContent?: React.ReactNode;
onUpdate?: (value: string) => void;
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
Expand Down

0 comments on commit fd29127

Please sign in to comment.