@patternfly/react-core 4.242.8 → 4.243.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/esm/components/DatePicker/DatePicker.d.ts.map +1 -1
  3. package/dist/esm/components/DatePicker/DatePicker.js +4 -2
  4. package/dist/esm/components/DatePicker/DatePicker.js.map +1 -1
  5. package/dist/esm/components/TextArea/TextArea.d.ts +17 -11
  6. package/dist/esm/components/TextArea/TextArea.d.ts.map +1 -1
  7. package/dist/esm/components/TextArea/TextArea.js +8 -3
  8. package/dist/esm/components/TextArea/TextArea.js.map +1 -1
  9. package/dist/esm/components/TextInput/TextInput.d.ts +21 -16
  10. package/dist/esm/components/TextInput/TextInput.d.ts.map +1 -1
  11. package/dist/esm/components/TextInput/TextInput.js +7 -4
  12. package/dist/esm/components/TextInput/TextInput.js.map +1 -1
  13. package/dist/js/components/DatePicker/DatePicker.d.ts.map +1 -1
  14. package/dist/js/components/DatePicker/DatePicker.js +4 -2
  15. package/dist/js/components/DatePicker/DatePicker.js.map +1 -1
  16. package/dist/js/components/TextArea/TextArea.d.ts +17 -11
  17. package/dist/js/components/TextArea/TextArea.d.ts.map +1 -1
  18. package/dist/js/components/TextArea/TextArea.js +9 -4
  19. package/dist/js/components/TextArea/TextArea.js.map +1 -1
  20. package/dist/js/components/TextInput/TextInput.d.ts +21 -16
  21. package/dist/js/components/TextInput/TextInput.d.ts.map +1 -1
  22. package/dist/js/components/TextInput/TextInput.js +8 -5
  23. package/dist/js/components/TextInput/TextInput.js.map +1 -1
  24. package/dist/umd/react-core.min.css +1090 -1068
  25. package/dist/umd/react-core.min.js +3 -3
  26. package/package.json +6 -6
  27. package/src/components/DatePicker/DatePicker.tsx +4 -2
  28. package/src/components/DatePicker/__tests__/DatePicker.test.tsx +22 -1
  29. package/src/components/NumberInput/examples/NumberInput.md +9 -448
  30. package/src/components/NumberInput/examples/NumberInputCustomStep.tsx +29 -0
  31. package/src/components/NumberInput/examples/NumberInputCustomStepAndThreshold.tsx +52 -0
  32. package/src/components/NumberInput/examples/NumberInputDefault.tsx +34 -0
  33. package/src/components/NumberInput/examples/NumberInputDisabled.tsx +40 -0
  34. package/src/components/NumberInput/examples/NumberInputUnit.tsx +57 -0
  35. package/src/components/NumberInput/examples/NumberInputUnitThreshold.tsx +55 -0
  36. package/src/components/NumberInput/examples/NumberInputVaryingSizes.tsx +80 -0
  37. package/src/components/NumberInput/examples/{WithStatus.tsx → NumberInputWithStatus.tsx} +4 -3
  38. package/src/components/TextArea/TextArea.tsx +21 -13
  39. package/src/components/TextArea/__tests__/TextArea.test.tsx +20 -6
  40. package/src/components/TextArea/__tests__/__snapshots__/TextArea.test.tsx.snap +31 -5
  41. package/src/components/TextArea/examples/TextArea.md +30 -0
  42. package/src/components/TextInput/TextInput.tsx +26 -18
  43. package/src/components/TextInput/__tests__/TextInput.test.tsx +16 -2
  44. package/src/components/TextInput/__tests__/__snapshots__/TextInput.test.tsx.snap +36 -4
  45. package/src/components/TextInput/examples/TextInput.md +23 -2
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { NumberInput } from '@patternfly/react-core';
3
+
4
+ export const NumberInputDisabled: React.FunctionComponent = () => {
5
+ const [value, setValue] = React.useState(100);
6
+ const minValue = 0;
7
+ const maxValue = 100;
8
+
9
+ const onMinus = () => {
10
+ const newValue = value - 1;
11
+ setValue(newValue);
12
+ };
13
+
14
+ const onChange = (event: React.FormEvent<HTMLInputElement>) => {
15
+ const target = event.target as HTMLInputElement;
16
+ setValue(Number(target.value));
17
+ };
18
+
19
+ const onPlus = () => {
20
+ const newValue = value + 1;
21
+ setValue(newValue);
22
+ };
23
+
24
+ return (
25
+ <NumberInput
26
+ value={value}
27
+ min={minValue}
28
+ max={maxValue}
29
+ onMinus={onMinus}
30
+ onChange={onChange}
31
+ onPlus={onPlus}
32
+ inputName="input"
33
+ inputAriaLabel="number input"
34
+ minusBtnAriaLabel="minus"
35
+ plusBtnAriaLabel="plus"
36
+ unit="%"
37
+ isDisabled
38
+ />
39
+ );
40
+ };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { NumberInput } from '@patternfly/react-core';
3
+
4
+ export const NumberInputUnit: React.FunctionComponent = () => {
5
+ const [value1, setValue1] = React.useState(90);
6
+ const [value2, setValue2] = React.useState(Number((1.0).toFixed(2)));
7
+
8
+ const onMinus1 = () => setValue1(value1 - 1);
9
+ const onChange1 = (event: React.FormEvent<HTMLInputElement>) => {
10
+ const target = event.target as HTMLInputElement;
11
+ setValue1(Number(target.value));
12
+ };
13
+ const onPlus1 = () => setValue1(value1 + 1);
14
+
15
+ const onMinus2 = () => {
16
+ const newValue = Number((value2 - 0.01).toFixed(2));
17
+ setValue2(newValue);
18
+ };
19
+ const onChange2 = (event: React.FormEvent<HTMLInputElement>) => {
20
+ const target = event.target as HTMLInputElement;
21
+ setValue2(Number(target.value));
22
+ };
23
+ const onPlus2 = () => {
24
+ const newValue = Number((value2 + 0.01).toFixed(2));
25
+ setValue2(newValue);
26
+ };
27
+
28
+ return (
29
+ <React.Fragment>
30
+ <NumberInput
31
+ value={value1}
32
+ onMinus={onMinus1}
33
+ onChange={onChange1}
34
+ onPlus={onPlus1}
35
+ inputName="input 1"
36
+ inputAriaLabel="number input 1"
37
+ minusBtnAriaLabel="minus 1"
38
+ plusBtnAriaLabel="plus 1"
39
+ unit="%"
40
+ />
41
+ <br />
42
+ <br />
43
+ <NumberInput
44
+ value={value2}
45
+ onMinus={onMinus2}
46
+ onChange={onChange2}
47
+ onPlus={onPlus2}
48
+ inputName="input 2"
49
+ inputAriaLabel="number input 2"
50
+ minusBtnAriaLabel="minus 0.01"
51
+ plusBtnAriaLabel="plus 0.01"
52
+ unit="$"
53
+ unitPosition="before"
54
+ />
55
+ </React.Fragment>
56
+ );
57
+ };
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import { NumberInput } from '@patternfly/react-core';
3
+
4
+ export const NumberInputUnitThreshold: React.FunctionComponent = () => {
5
+ const [value, setValue] = React.useState(0);
6
+ const minValue = 0;
7
+ const maxValue = 10;
8
+
9
+ const normalizeBetween = (value, min, max) => {
10
+ if (min !== undefined && max !== undefined) {
11
+ return Math.max(Math.min(value, max), min);
12
+ } else if (value <= min) {
13
+ return min;
14
+ } else if (value >= max) {
15
+ return max;
16
+ }
17
+ return value;
18
+ };
19
+
20
+ const onMinus = () => {
21
+ const newValue = normalizeBetween(value - 1, minValue, maxValue);
22
+ setValue(newValue);
23
+ };
24
+
25
+ const onChange = (event: React.FormEvent<HTMLInputElement>) => {
26
+ const target = event.target as HTMLInputElement;
27
+ const newValue = normalizeBetween(isNaN(+target.value) ? 0 : Number(target.value), minValue, maxValue);
28
+ setValue(newValue);
29
+ };
30
+
31
+ const onPlus = () => {
32
+ const newValue = normalizeBetween(value + 1, minValue, maxValue);
33
+ setValue(newValue);
34
+ };
35
+
36
+ return (
37
+ <React.Fragment>
38
+ With a minimum value of 0 and maximum value of 10
39
+ <br />
40
+ <NumberInput
41
+ value={value}
42
+ min={minValue}
43
+ max={maxValue}
44
+ onMinus={onMinus}
45
+ onChange={onChange}
46
+ onPlus={onPlus}
47
+ inputName="input"
48
+ inputAriaLabel="number input"
49
+ minusBtnAriaLabel="minus"
50
+ plusBtnAriaLabel="plus"
51
+ unit="%"
52
+ />
53
+ </React.Fragment>
54
+ );
55
+ };
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import { NumberInput } from '@patternfly/react-core';
3
+
4
+ export const NumberInputVaryingSizes: React.FunctionComponent = () => {
5
+ const [input1Value, setInput1Value] = React.useState(1);
6
+ const [input2Value, setInput2Value] = React.useState(1234567890);
7
+ const [input3Value, setInput3Value] = React.useState(5);
8
+ const [input4Value, setInput4Value] = React.useState(12345);
9
+
10
+ const onChange = (
11
+ event: React.FormEvent<HTMLInputElement>,
12
+ updateFunction: React.Dispatch<React.SetStateAction<number>>
13
+ ) => {
14
+ const target = event.target as HTMLInputElement;
15
+ updateFunction(Number(target.value));
16
+ };
17
+
18
+ const onMinus = (value, updateFunction: React.Dispatch<React.SetStateAction<number>>) => {
19
+ updateFunction(value - 1);
20
+ };
21
+
22
+ const onPlus = (value, updateFunction: React.Dispatch<React.SetStateAction<number>>) => {
23
+ updateFunction(value + 1);
24
+ };
25
+
26
+ return (
27
+ <React.Fragment>
28
+ <NumberInput
29
+ value={input1Value}
30
+ onMinus={() => onMinus(input1Value, setInput1Value)}
31
+ onChange={event => onChange(event, setInput1Value)}
32
+ onPlus={() => onPlus(input1Value, setInput1Value)}
33
+ inputName="input1"
34
+ inputAriaLabel="number input 1"
35
+ minusBtnAriaLabel="input 2 minus"
36
+ plusBtnAriaLabel="input 2 plus"
37
+ widthChars={1}
38
+ />
39
+ <br />
40
+ <br />
41
+ <NumberInput
42
+ value={input2Value}
43
+ onMinus={() => onMinus(input2Value, setInput2Value)}
44
+ onChange={event => onChange(event, setInput2Value)}
45
+ onPlus={() => onPlus(input2Value, setInput2Value)}
46
+ inputName="input2"
47
+ inputAriaLabel="number input 2"
48
+ minusBtnAriaLabel="input 2 minus"
49
+ plusBtnAriaLabel="input 2 plus"
50
+ widthChars={10}
51
+ />
52
+ <br />
53
+ <br />
54
+ <NumberInput
55
+ value={input3Value}
56
+ onMinus={() => onMinus(input3Value, setInput3Value)}
57
+ onChange={event => onChange(event, setInput3Value)}
58
+ onPlus={() => onPlus(input3Value, setInput3Value)}
59
+ inputName="input3"
60
+ inputAriaLabel="number input 3"
61
+ minusBtnAriaLabel="input 3 minus"
62
+ plusBtnAriaLabel="input 3 plus"
63
+ widthChars={5}
64
+ />
65
+ <br />
66
+ <br />
67
+ <NumberInput
68
+ value={input4Value}
69
+ onMinus={() => onMinus(input4Value, setInput4Value)}
70
+ onChange={event => onChange(event, setInput4Value)}
71
+ onPlus={() => onPlus(input4Value, setInput4Value)}
72
+ inputName="input4"
73
+ inputAriaLabel="number input 4"
74
+ minusBtnAriaLabel="input 4 minus"
75
+ plusBtnAriaLabel="input 4 plus"
76
+ widthChars={5}
77
+ />
78
+ </React.Fragment>
79
+ );
80
+ };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { NumberInput, ValidatedOptions } from '@patternfly/react-core';
3
3
 
4
- export const WithStatus: React.FunctionComponent = () => {
4
+ export const NumberInputWithStatus: React.FunctionComponent = () => {
5
5
  const max = 10;
6
6
  const min = 0;
7
7
 
@@ -20,8 +20,9 @@ export const WithStatus: React.FunctionComponent = () => {
20
20
  validate(newVal);
21
21
  };
22
22
 
23
- const onChange = event => {
24
- const newVal = isNaN(event.target.value) ? 5 : Number(event.target.value);
23
+ const onChange = (event: React.FormEvent<HTMLInputElement>) => {
24
+ const target = event.target as HTMLInputElement;
25
+ const newVal = isNaN(+target.value) ? 5 : Number(target.value);
25
26
  setValue(newVal);
26
27
  validate(newVal);
27
28
  };
@@ -11,33 +11,40 @@ export enum TextAreResizeOrientation {
11
11
  both = 'both'
12
12
  }
13
13
 
14
+ export enum TextAreaReadOnlyVariant {
15
+ default = 'default',
16
+ plain = 'plain'
17
+ }
18
+
14
19
  export interface TextAreaProps extends Omit<HTMLProps<HTMLTextAreaElement>, 'onChange' | 'ref'> {
15
- /** Additional classes added to the TextArea. */
20
+ /** Additional classes added to the text area. */
16
21
  className?: string;
17
- /** Flag to show if the TextArea is required. */
22
+ /** Flag to show if the text area is required. */
18
23
  isRequired?: boolean;
19
- /** Flag to show if the TextArea is disabled. */
24
+ /** Flag to show if the text area is disabled. */
20
25
  isDisabled?: boolean;
21
- /** Flag to show if the TextArea is read only. */
26
+ /** @deprecated Use readOnlyVariant instead. Flag to show if the text area is read only. */
22
27
  isReadOnly?: boolean;
28
+ /** Read only variant. */
29
+ readOnlyVariant?: 'default' | 'plain';
23
30
  /** Use the external file instead of a data URI */
24
31
  isIconSprite?: boolean;
25
32
  /** Flag to modify height based on contents. */
26
33
  autoResize?: boolean;
27
- /** Value to indicate if the textarea is modified to show that validation state.
28
- * If set to success, textarea will be modified to indicate valid state.
29
- * If set to error, textarea will be modified to indicate error state.
34
+ /** Value to indicate if the text area is modified to show that validation state.
35
+ * If set to success, text area will be modified to indicate valid state.
36
+ * If set to error, text area will be modified to indicate error state.
30
37
  */
31
38
  validated?: 'success' | 'warning' | 'error' | 'default';
32
- /** Value of the TextArea. */
39
+ /** Value of the text area. */
33
40
  value?: string | number;
34
- /** A callback for when the TextArea value changes. */
41
+ /** A callback for when the text area value changes. */
35
42
  onChange?: (value: string, event: React.ChangeEvent<HTMLTextAreaElement>) => void;
36
43
  /** Sets the orientation to limit the resize to */
37
44
  resizeOrientation?: 'horizontal' | 'vertical' | 'both';
38
- /** Custom flag to show that the TextArea requires an associated id or aria-label. */
45
+ /** Custom flag to show that the text area requires an associated id or aria-label. */
39
46
  'aria-label'?: string;
40
- /** A reference object to attach to the textarea. */
47
+ /** A reference object to attach to the text area. */
41
48
  innerRef?: React.RefObject<any>;
42
49
  }
43
50
 
@@ -105,9 +112,9 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
105
112
  isDisabled,
106
113
  isIconSprite,
107
114
  isReadOnly,
115
+ readOnlyVariant,
108
116
  resizeOrientation,
109
117
  innerRef,
110
- readOnly,
111
118
  disabled,
112
119
  /* eslint-disable @typescript-eslint/no-unused-vars */
113
120
  autoResize,
@@ -121,6 +128,7 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
121
128
  className={css(
122
129
  styles.formControl,
123
130
  isIconSprite && styles.modifiers.iconSprite,
131
+ readOnlyVariant === 'plain' && styles.modifiers.plain,
124
132
  className,
125
133
  resizeOrientation !== TextAreResizeOrientation.both && styles.modifiers[orientation],
126
134
  validated === ValidatedOptions.success && styles.modifiers.success,
@@ -131,7 +139,7 @@ export class TextAreaBase extends React.Component<TextAreaProps> {
131
139
  aria-invalid={validated === ValidatedOptions.error}
132
140
  required={isRequired}
133
141
  disabled={isDisabled || disabled}
134
- readOnly={isReadOnly || readOnly}
142
+ readOnly={!!readOnlyVariant || isReadOnly}
135
143
  ref={innerRef || this.inputRef}
136
144
  {...props}
137
145
  />
@@ -12,7 +12,7 @@ const props = {
12
12
  };
13
13
 
14
14
  describe('TextArea', () => {
15
- test('textarea input passes value and event to onChange handler', async () => {
15
+ test('textarea passes value and event to onChange handler', async () => {
16
16
  const user = userEvent.setup();
17
17
 
18
18
  render(<TextAreaBase {...props} value="" aria-label="test textarea" />);
@@ -21,27 +21,41 @@ describe('TextArea', () => {
21
21
  expect(props.onChange).toHaveBeenCalledWith('a', expect.any(Object));
22
22
  });
23
23
 
24
- test('simple text input', () => {
24
+ test('simple text area', () => {
25
25
  const { asFragment } = render(<TextArea {...props} aria-label="simple textarea" />);
26
26
  expect(asFragment()).toMatchSnapshot();
27
27
  });
28
28
 
29
- test('disabled text input using isDisabled', () => {
29
+ test('disabled text area using isDisabled', () => {
30
30
  const { asFragment } = render(<TextArea {...props} aria-label="is disabled textarea" isDisabled />);
31
31
  expect(asFragment()).toMatchSnapshot();
32
32
  });
33
33
 
34
- test('disabled text input using disabled', () => {
34
+ test('disabled text area using disabled', () => {
35
35
  const { asFragment } = render(<TextArea {...props} aria-label="disabled textarea" disabled />);
36
36
  expect(asFragment()).toMatchSnapshot();
37
37
  });
38
38
 
39
- test('read only text input using isReadOnly', () => {
39
+ test('read only text area using isReadOnly', () => {
40
40
  const { asFragment } = render(<TextArea {...props} aria-label="is read only textarea" isReadOnly />);
41
41
  expect(asFragment()).toMatchSnapshot();
42
42
  });
43
43
 
44
- test('read only text input using readOnly', () => {
44
+ test('read only text area using default readOnlyVariant', () => {
45
+ const { asFragment } = render(
46
+ <TextArea {...props} aria-label="is default read only textarea" readOnlyVariant="default" />
47
+ );
48
+ expect(asFragment()).toMatchSnapshot();
49
+ });
50
+
51
+ test('read only text area using plain readOnlyVariant', () => {
52
+ const { asFragment } = render(
53
+ <TextArea {...props} aria-label="is plain read only textarea" readOnlyVariant="plain" />
54
+ );
55
+ expect(asFragment()).toMatchSnapshot();
56
+ });
57
+
58
+ test('read only text area using readOnly', () => {
45
59
  const { asFragment } = render(<TextArea {...props} aria-label="read only textarea" readOnly />);
46
60
  expect(asFragment()).toMatchSnapshot();
47
61
  });
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`TextArea disabled text input using disabled 1`] = `
3
+ exports[`TextArea disabled text area using disabled 1`] = `
4
4
  <DocumentFragment>
5
5
  <textarea
6
6
  aria-invalid="false"
@@ -13,7 +13,7 @@ exports[`TextArea disabled text input using disabled 1`] = `
13
13
  </DocumentFragment>
14
14
  `;
15
15
 
16
- exports[`TextArea disabled text input using isDisabled 1`] = `
16
+ exports[`TextArea disabled text area using isDisabled 1`] = `
17
17
  <DocumentFragment>
18
18
  <textarea
19
19
  aria-invalid="false"
@@ -39,7 +39,20 @@ exports[`TextArea horizontally resizable text area 1`] = `
39
39
  </DocumentFragment>
40
40
  `;
41
41
 
42
- exports[`TextArea read only text input using isReadOnly 1`] = `
42
+ exports[`TextArea read only text area using default readOnlyVariant 1`] = `
43
+ <DocumentFragment>
44
+ <textarea
45
+ aria-invalid="false"
46
+ aria-label="is default read only textarea"
47
+ class="pf-c-form-control"
48
+ readonly=""
49
+ >
50
+ test textarea
51
+ </textarea>
52
+ </DocumentFragment>
53
+ `;
54
+
55
+ exports[`TextArea read only text area using isReadOnly 1`] = `
43
56
  <DocumentFragment>
44
57
  <textarea
45
58
  aria-invalid="false"
@@ -52,7 +65,20 @@ exports[`TextArea read only text input using isReadOnly 1`] = `
52
65
  </DocumentFragment>
53
66
  `;
54
67
 
55
- exports[`TextArea read only text input using readOnly 1`] = `
68
+ exports[`TextArea read only text area using plain readOnlyVariant 1`] = `
69
+ <DocumentFragment>
70
+ <textarea
71
+ aria-invalid="false"
72
+ aria-label="is plain read only textarea"
73
+ class="pf-c-form-control pf-m-plain"
74
+ readonly=""
75
+ >
76
+ test textarea
77
+ </textarea>
78
+ </DocumentFragment>
79
+ `;
80
+
81
+ exports[`TextArea read only text area using readOnly 1`] = `
56
82
  <DocumentFragment>
57
83
  <textarea
58
84
  aria-invalid="false"
@@ -65,7 +91,7 @@ exports[`TextArea read only text input using readOnly 1`] = `
65
91
  </DocumentFragment>
66
92
  `;
67
93
 
68
- exports[`TextArea simple text input 1`] = `
94
+ exports[`TextArea simple text area 1`] = `
69
95
  <DocumentFragment>
70
96
  <textarea
71
97
  aria-invalid="false"
@@ -223,6 +223,36 @@ import { TextArea } from '@patternfly/react-core';
223
223
  <TextArea aria-label="disabled text area example" isDisabled />;
224
224
  ```
225
225
 
226
+ ### Read only
227
+
228
+ ```js
229
+ import React from 'react';
230
+ import { Checkbox, TextArea } from '@patternfly/react-core';
231
+
232
+ const ReadOnlyTextArea = () => {
233
+ const [isPlainChecked, setIsPlainChecked] = React.useState(false);
234
+
235
+ return (
236
+ <React.Fragment>
237
+ <div style={{ marginBottom: '12px' }}>
238
+ <Checkbox
239
+ id="isPlain"
240
+ key="isPlain"
241
+ label="Plain read only variant"
242
+ isChecked={isPlainChecked}
243
+ onChange={checked => setIsPlainChecked(checked)}
244
+ />
245
+ </div>
246
+ <TextArea
247
+ aria-label="read only text area example"
248
+ value="read only text area example"
249
+ readOnlyVariant={isPlainChecked ? 'plain' : 'default'}
250
+ />
251
+ </React.Fragment>
252
+ );
253
+ };
254
+ ```
255
+
226
256
  ### Auto resizing
227
257
 
228
258
  ```js
@@ -20,25 +20,31 @@ export enum TextInputTypes {
20
20
  url = 'url'
21
21
  }
22
22
 
23
+ export enum TextInputReadOnlyVariant {
24
+ default = 'default',
25
+ plain = 'plain'
26
+ }
27
+
23
28
  export interface TextInputProps
24
29
  extends Omit<React.HTMLProps<HTMLInputElement>, 'onChange' | 'onFocus' | 'onBlur' | 'disabled' | 'ref'>,
25
30
  OUIAProps {
26
- /** Additional classes added to the TextInput. */
31
+ /** Additional classes added to the text input. */
27
32
  className?: string;
28
- /** Flag to show if the input is disabled. */
33
+ /** Flag to show if the text input is disabled. */
29
34
  isDisabled?: boolean;
30
- /** Flag to show if the input is read only. */
35
+ /** @deprecated Use readOnlyVariant instead. Flag to show if the text input is read only. */
31
36
  isReadOnly?: boolean;
32
- /** Flag to show if the input is required. */
37
+ /** Read only variant. */
38
+ readOnlyVariant?: 'plain' | 'default';
33
39
  isRequired?: boolean;
34
- /** Value to indicate if the input is modified to show that validation state.
35
- * If set to success, input will be modified to indicate valid state.
36
- * If set to error, input will be modified to indicate error state.
40
+ /** Value to indicate if the text input is modified to show that validation state.
41
+ * If set to success, text input will be modified to indicate valid state.
42
+ * If set to error, text input will be modified to indicate error state.
37
43
  */
38
44
  validated?: 'success' | 'warning' | 'error' | 'default';
39
- /** A callback for when the input value changes. */
45
+ /** A callback for when the text input value changes. */
40
46
  onChange?: (value: string, event: React.FormEvent<HTMLInputElement>) => void;
41
- /** Type that the input accepts. */
47
+ /** Type that the text input accepts. */
42
48
  type?:
43
49
  | 'text'
44
50
  | 'date'
@@ -51,25 +57,25 @@ export interface TextInputProps
51
57
  | 'tel'
52
58
  | 'time'
53
59
  | 'url';
54
- /** Value of the input. */
60
+ /** Value of the text input. */
55
61
  value?: string | number;
56
- /** Aria-label. The input requires an associated id or aria-label. */
62
+ /** Aria-label. The text input requires an associated id or aria-label. */
57
63
  'aria-label'?: string;
58
- /** A reference object to attach to the input box. */
64
+ /** A reference object to attach to the text input box. */
59
65
  innerRef?: React.RefObject<any>;
60
66
  /** Trim text on left */
61
67
  isLeftTruncated?: boolean;
62
- /** Callback function when input is focused */
68
+ /** Callback function when text input is focused */
63
69
  onFocus?: (event?: any) => void;
64
- /** Callback function when input is blurred (focus leaves) */
70
+ /** Callback function when text input is blurred (focus leaves) */
65
71
  onBlur?: (event?: any) => void;
66
72
  /** icon variant */
67
73
  iconVariant?: 'calendar' | 'clock' | 'search';
68
74
  /** Use the external file instead of a data URI */
69
75
  isIconSprite?: boolean;
70
- /** Custom icon url to set as the input's background-image */
76
+ /** Custom icon url to set as the text input's background-image */
71
77
  customIconUrl?: string;
72
- /** Dimensions for the custom icon set as the input's background-size */
78
+ /** Dimensions for the custom icon set as the text input's background-size */
73
79
  customIconDimensions?: string;
74
80
  }
75
81
 
@@ -169,8 +175,9 @@ export class TextInputBase extends React.Component<TextInputProps, TextInputStat
169
175
  onFocus,
170
176
  onBlur,
171
177
  isLeftTruncated,
172
- /* eslint-enable @typescript-eslint/no-unused-vars */
173
178
  isReadOnly,
179
+ readOnly,
180
+ readOnlyVariant,
174
181
  isRequired,
175
182
  isDisabled,
176
183
  isIconSprite,
@@ -198,6 +205,7 @@ export class TextInputBase extends React.Component<TextInputProps, TextInputStat
198
205
  className={css(
199
206
  styles.formControl,
200
207
  isIconSprite && styles.modifiers.iconSprite,
208
+ readOnlyVariant === 'plain' && styles.modifiers.plain,
201
209
  validated === ValidatedOptions.success && styles.modifiers.success,
202
210
  validated === ValidatedOptions.warning && styles.modifiers.warning,
203
211
  ((iconVariant && iconVariant !== 'search') || customIconUrl) && styles.modifiers.icon,
@@ -210,7 +218,7 @@ export class TextInputBase extends React.Component<TextInputProps, TextInputStat
210
218
  aria-invalid={props['aria-invalid'] ? props['aria-invalid'] : validated === ValidatedOptions.error}
211
219
  required={isRequired}
212
220
  disabled={isDisabled}
213
- readOnly={isReadOnly}
221
+ readOnly={!!readOnlyVariant || isReadOnly || readOnly}
214
222
  ref={innerRef || this.inputRef}
215
223
  {...((customIconUrl || customIconDimensions) && { style: customIconStyle })}
216
224
  {...getOUIAProps(TextInput.displayName, ouiaId !== undefined ? ouiaId : this.state.ouiaStateId, ouiaSafe)}
@@ -31,8 +31,22 @@ describe('TextInput', () => {
31
31
  expect(asFragment()).toMatchSnapshot();
32
32
  });
33
33
 
34
- test('readonly text input', () => {
35
- const { asFragment } = render(<TextInput isReadOnly value="read only" aria-label="readonly text input" />);
34
+ test('read only text input using isReadOnly', () => {
35
+ const { asFragment } = render(<TextInput isReadOnly value="read only" aria-label="read only text input" />);
36
+ expect(asFragment()).toMatchSnapshot();
37
+ });
38
+
39
+ test('default read only text input', () => {
40
+ const { asFragment } = render(
41
+ <TextInput readOnlyVariant="default" value="read only default" aria-label="default read only text input" />
42
+ );
43
+ expect(asFragment()).toMatchSnapshot();
44
+ });
45
+
46
+ test('plain read only text input', () => {
47
+ const { asFragment } = render(
48
+ <TextInput readOnlyVariant="plain" value="read only plain" aria-label="plain read only text input" />
49
+ );
36
50
  expect(asFragment()).toMatchSnapshot();
37
51
  });
38
52