Skip to content

Commit

Permalink
feat(TextInput, TextArea): add readOnly property (#1747)
Browse files Browse the repository at this point in the history
  • Loading branch information
polikashina authored Aug 22, 2024
1 parent c4a9d97 commit 1c95f75
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/components/controls/TextArea/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ LANDING_BLOCK-->
| pin | The control's border view | `string` | `"round-round"` |
| placeholder | Text that appears in the control when no value is set | `string` | |
| qa | Test id attribute (`data-qa`) | `string` | |
| readOnly | Indicates that the user cannot change control's value | `boolean` | `false` |
| rows | The number of visible text lines for the control. If unspecified, the hight will be calculated automatically based on the content | `number` | |
| size | The control's size | `"s"` `"m"` `"l"` `"xl"` | `"m"` |
| tabIndex | The control's `tabindex` attribute | `string` | |
Expand Down
11 changes: 7 additions & 4 deletions src/components/controls/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
name,
value,
defaultValue,
disabled = false,
disabled: disabledProp,
readOnly: readOnlyProp,
hasClear = false,
error,
errorMessage: errorMessageProp,
validationState: validationStateProp,
autoComplete,
id: originalId,
id: idProp,
tabIndex,
style,
className,
Expand All @@ -63,6 +64,8 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
onUpdate,
onChange,
} = props;
const disabled = disabledProp ?? controlProps?.disabled;
const readOnly = readOnlyProp ?? controlProps?.readOnly;

const {errorMessage, validationState} = errorPropsMapper({
error,
Expand All @@ -79,8 +82,8 @@ export const TextArea = React.forwardRef<HTMLSpanElement, TextAreaProps>(
const innerId = useUniqId();

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

const errorMessageId = useUniqId();
const noteId = useUniqId();
Expand Down
2 changes: 2 additions & 0 deletions src/components/controls/TextArea/TextAreaControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function TextAreaControl(props: Props) {
maxRows,
autoFocus,
disabled,
readOnly,
onChange,
onFocus,
onBlur,
Expand Down Expand Up @@ -112,6 +113,7 @@ export function TextAreaControl(props: Props) {
onKeyUp={onKeyUp}
onKeyPress={onKeyPress}
disabled={disabled ?? controlProps.disabled}
readOnly={readOnly ?? controlProps.readOnly}
/>
);
}
21 changes: 21 additions & 0 deletions src/components/controls/TextArea/__stories__/TextAreaShowcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ export function TextAreaShowcase() {
/>
</div>
<TextArea {...textAreaProps} placeholder="disabled" disabled rows={2} />
<TextArea
{...textAreaProps}
placeholder="readonly"
value="readonly value"
readOnly
rows={2}
/>
<TextArea {...textAreaProps} placeholder="rows = 4 & clear" hasClear rows={4} />
<TextArea
{...textAreaProps}
Expand Down Expand Up @@ -113,6 +120,13 @@ value`.trim()}
<TextArea {...textAreaProps} />
<TextArea {...textAreaProps} value={undefined} defaultValue="has clear" hasClear />
<TextArea {...textAreaProps} disabled />
<TextArea
{...textAreaProps}
placeholder="readonly"
value="readonly value"
readOnly
rows={2}
/>
<TextArea {...textAreaProps} error="Error message" />
</div>
<div className={b('custom-theme')}>
Expand All @@ -127,6 +141,13 @@ value`.trim()}
<TextArea {...textAreaProps} />
<TextArea {...textAreaProps} value={undefined} defaultValue="has clear" hasClear />
<TextArea {...textAreaProps} disabled />
<TextArea
{...textAreaProps}
placeholder="readonly"
value="readonly value"
readOnly
rows={2}
/>
<TextArea {...textAreaProps} error="Error message" />
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/controls/TextInput/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ LANDING_BLOCK-->
| onUpdate | Fires when the input’s value is changed by the user. Provides new value as an callback's argument | `function` | |
| pin | The control's border view | `string` | `'round-round'` |
| placeholder | Text that appears in the control when it has no value set | `string` | |
| qa | Test ID attribute (`data-qa`) | `string` | |
| qa | Test ID attribute (`data-qa`) | `string` |
| readOnly | Indicates that the user cannot change control's value | `boolean` | `false` |
| rightContent | User`s node rendered after the input node and clear button | `React.ReactNode` | |
| size | The size of the control | `"s"` `"m"` `"l"` `"xl"` | `"m"` |
| tabIndex | The `tabindex` attribute of the control | `string` | |
Expand Down
21 changes: 12 additions & 9 deletions src/components/controls/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,20 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(
value,
defaultValue,
label,
disabled = false,
disabled: disabledProp,
readOnly: readOnlyProp,
hasClear = false,
error,
errorMessage: errorMessageProp,
errorPlacement: errorPlacementProp = 'outside',
validationState: validationStateProp,
autoComplete,
id: originalId,
id: idProp,
tabIndex,
style,
className,
qa,
controlProps: originalControlProps,
controlProps: controlPropsProp,
leftContent,
rightContent,
startContent = leftContent,
Expand All @@ -89,6 +90,8 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(
onUpdate,
onChange,
} = props;
const disabled = disabledProp ?? controlPropsProp?.disabled;
const readOnly = readOnlyProp ?? controlPropsProp?.readOnly;

const {errorMessage, errorPlacement, validationState} = errorPropsMapper({
error,
Expand All @@ -110,14 +113,14 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(
validationState === 'invalid' && Boolean(errorMessage) && errorPlacement === 'outside';
const isErrorIconVisible =
validationState === 'invalid' && Boolean(errorMessage) && errorPlacement === 'inside';
const isClearControlVisible = Boolean(hasClear && !disabled && inputValue);
const isClearControlVisible = Boolean(hasClear && !disabled && !readOnly && inputValue);
const isStartContentVisible = Boolean(startContent);
const isEndContentVisible = Boolean(endContent);
const isAutoCompleteOff =
isLabelVisible && !originalId && !name && typeof autoComplete === 'undefined';
isLabelVisible && !idProp && !name && typeof autoComplete === 'undefined';

const innerId = useUniqId();
const id = isLabelVisible ? originalId || innerId : originalId;
const id = isLabelVisible ? idProp || innerId : idProp;

const labelSize = useElementSize(isLabelVisible ? labelRef : null, size);
const startContentSize = useElementSize(
Expand All @@ -128,17 +131,17 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(
const errorMessageId = useUniqId();
const noteId = useUniqId();
const ariaDescribedBy = [
originalControlProps?.['aria-describedby'],
controlPropsProp?.['aria-describedby'],
note ? noteId : undefined,
isErrorMsgVisible ? errorMessageId : undefined,
]
.filter(Boolean)
.join(' ');

const controlProps: TextInputProps['controlProps'] = {
...originalControlProps,
...controlPropsProp,
style: {
...originalControlProps?.style,
...controlPropsProp?.style,
...(isLabelVisible && labelSize.width
? {paddingInlineStart: `${labelSize.width}px`}
: {}),
Expand Down
2 changes: 2 additions & 0 deletions src/components/controls/TextInput/TextInputControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function TextInputControl(props: Props) {
defaultValue,
autoFocus,
disabled,
readOnly,
onChange,
onFocus,
onBlur,
Expand Down Expand Up @@ -54,6 +55,7 @@ export function TextInputControl(props: Props) {
onKeyUp={onKeyUp}
onKeyPress={onKeyPress}
disabled={disabled ?? controlProps.disabled}
readOnly={readOnly ?? controlProps.readOnly}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ export const CustomThemeShowcase = () => {
errorPlacement="inside"
/>
<TextInput {...textInputProps} placeholder="disabled" disabled />
<TextInput
{...textInputProps}
placeholder="disabled"
value="readonlyValue"
readOnly
/>
<TextInput {...textInputProps} placeholder="clear" hasClear />
<TextInput
{...textInputProps}
Expand Down Expand Up @@ -82,6 +88,12 @@ export const CustomThemeShowcase = () => {
errorPlacement="inside"
/>
<TextInput {...textInputProps} placeholder="disabled" disabled />
<TextInput
{...textInputProps}
placeholder="disabled"
value="readonlyValue"
readOnly
/>
<TextInput {...textInputProps} placeholder="clear" hasClear />
<TextInput
{...textInputProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ export function TextInputShowcase() {
/>
</div>
<TextInput {...textInputProps} placeholder="disabled" disabled />
<TextInput
{...textInputProps}
placeholder="readonly"
value="readonlyValue"
readOnly
/>
<TextInput {...textInputProps} placeholder="clear" hasClear />
<TextInput
{...textInputProps}
Expand Down Expand Up @@ -128,6 +134,13 @@ export function TextInputShowcase() {
/>
</div>
<TextInput {...textInputProps} placeholder="disabled" label={LABEL} disabled />
<TextInput
{...textInputProps}
placeholder="readonly"
value="readonlyValue"
label={LABEL}
readOnly
/>
<TextInput {...textInputProps} placeholder="clear" label={LABEL} hasClear />
<TextInput
{...textInputProps}
Expand Down Expand Up @@ -234,6 +247,17 @@ export function TextInputShowcase() {
}
disabled
/>
<TextInput
{...textInputProps}
placeholder="readonly"
type={additionalContentExmpleInputType}
value="readonlyValue"
leftContent={<Icon data={Key} />}
rightContent={
<EyeButton opened={hideValue} onClick={handleEyeButtonClick} />
}
readOnly
/>
<TextInput
{...textInputProps}
placeholder="clear"
Expand Down
2 changes: 2 additions & 0 deletions src/components/controls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export type BaseInputControlProps<T = Element> = DOMProps &
pin?: InputControlPin;
/** Text that appears in the control when it has no value set */
placeholder?: string;
/** Indicates that the user cannot change control's value */
readOnly?: boolean;
/** The control's size. `'m'` by default */
size?: InputControlSize;
/** The control's `tabindex` attribute */
Expand Down

0 comments on commit 1c95f75

Please sign in to comment.