@lumx/react 3.18.1 → 3.18.2-alpha.0
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.
- package/index.d.ts +13 -8
- package/index.js +217 -152
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/autocomplete/Autocomplete.tsx +5 -4
- package/src/components/autocomplete/AutocompleteMultiple.tsx +5 -3
- package/src/components/button/Button.stories.tsx +1 -0
- package/src/components/button/Button.test.tsx +41 -2
- package/src/components/button/ButtonRoot.tsx +10 -11
- package/src/components/checkbox/Checkbox.stories.tsx +13 -2
- package/src/components/checkbox/Checkbox.test.tsx +29 -0
- package/src/components/checkbox/Checkbox.tsx +8 -7
- package/src/components/chip/Chip.stories.tsx +17 -0
- package/src/components/chip/Chip.test.tsx +44 -0
- package/src/components/chip/Chip.tsx +10 -9
- package/src/components/date-picker/DatePickerField.stories.tsx +18 -0
- package/src/components/date-picker/DatePickerField.tsx +4 -4
- package/src/components/link/Link.stories.tsx +4 -1
- package/src/components/link/Link.test.tsx +45 -6
- package/src/components/link/Link.tsx +7 -6
- package/src/components/list/ListItem.stories.tsx +14 -48
- package/src/components/list/ListItem.test.tsx +78 -7
- package/src/components/list/ListItem.tsx +11 -9
- package/src/components/progress-tracker/ProgressTrackerStep.tsx +7 -7
- package/src/components/radio-button/RadioButton.stories.tsx +32 -0
- package/src/components/radio-button/RadioButton.test.tsx +30 -0
- package/src/components/radio-button/RadioButton.tsx +8 -7
- package/src/components/slider/Slider.tsx +6 -7
- package/src/components/switch/Switch.stories.tsx +11 -1
- package/src/components/switch/Switch.test.tsx +30 -0
- package/src/components/switch/Switch.tsx +8 -7
- package/src/components/table/TableRow.tsx +8 -6
- package/src/components/tabs/Tab.tsx +12 -9
- package/src/components/text-field/TextField.stories.tsx +22 -0
- package/src/components/text-field/TextField.test.tsx +56 -0
- package/src/components/text-field/TextField.tsx +12 -10
- package/src/utils/disabled/index.ts +1 -0
- package/src/utils/disabled/useDisableStateProps.tsx +34 -0
- package/src/utils/type/HasAriaDisabled.ts +6 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Alignment, Switch, SwitchProps } from '@lumx/react';
|
|
2
2
|
import { withValueOnChange } from '@lumx/react/stories/decorators/withValueOnChange';
|
|
3
3
|
import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
|
|
4
|
+
import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
title: 'LumX components/switch/Switch',
|
|
@@ -28,7 +29,16 @@ export const Default = {};
|
|
|
28
29
|
* Switch disabled
|
|
29
30
|
*/
|
|
30
31
|
export const Disabled = {
|
|
31
|
-
|
|
32
|
+
decorators: [
|
|
33
|
+
withCombinations({
|
|
34
|
+
combinations: {
|
|
35
|
+
rows: {
|
|
36
|
+
disabled: { isDisabled: true },
|
|
37
|
+
'aria-disabled': { 'aria-disabled': true },
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
32
42
|
};
|
|
33
43
|
|
|
34
44
|
/**
|
|
@@ -100,6 +100,36 @@ describe(`<${Switch.displayName}>`, () => {
|
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
+
describe('Disabled state', () => {
|
|
104
|
+
it('should be disabled with isDisabled', async () => {
|
|
105
|
+
const onChange = jest.fn();
|
|
106
|
+
const { switchWrapper, input } = setup({ isDisabled: true, onChange });
|
|
107
|
+
|
|
108
|
+
expect(switchWrapper).toHaveClass('lumx-switch--is-disabled');
|
|
109
|
+
expect(input).toBeDisabled();
|
|
110
|
+
expect(input).toHaveAttribute('readOnly');
|
|
111
|
+
|
|
112
|
+
// Should not trigger onChange.
|
|
113
|
+
await userEvent.click(input);
|
|
114
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should be disabled with aria-disabled', async () => {
|
|
118
|
+
const onChange = jest.fn();
|
|
119
|
+
const { switchWrapper, input } = setup({ 'aria-disabled': true, onChange });
|
|
120
|
+
|
|
121
|
+
expect(switchWrapper).toHaveClass('lumx-switch--is-disabled');
|
|
122
|
+
// Note: input is not disabled (so it can be focused) but it's readOnly.
|
|
123
|
+
expect(input).not.toBeDisabled();
|
|
124
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
125
|
+
expect(input).toHaveAttribute('readOnly');
|
|
126
|
+
|
|
127
|
+
// Should not trigger onChange.
|
|
128
|
+
await userEvent.click(input);
|
|
129
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
103
133
|
// Common tests suite.
|
|
104
134
|
commonTestsSuiteRTL(setup, {
|
|
105
135
|
baseClassName: CLASSNAME,
|
|
@@ -9,11 +9,13 @@ import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/classNam
|
|
|
9
9
|
import { useId } from '@lumx/react/hooks/useId';
|
|
10
10
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
11
11
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
12
|
+
import { useDisableStateProps } from '@lumx/react/utils/disabled/useDisableStateProps';
|
|
13
|
+
import { HasAriaDisabled } from '@lumx/react/utils/type/HasAriaDisabled';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Defines the props of the component.
|
|
15
17
|
*/
|
|
16
|
-
export interface SwitchProps extends GenericProps, HasTheme {
|
|
18
|
+
export interface SwitchProps extends GenericProps, HasTheme, HasAriaDisabled {
|
|
17
19
|
/** Helper text. */
|
|
18
20
|
helper?: string;
|
|
19
21
|
/** Whether it is checked or not. */
|
|
@@ -59,16 +61,15 @@ const DEFAULT_PROPS: Partial<SwitchProps> = {
|
|
|
59
61
|
* @return React element.
|
|
60
62
|
*/
|
|
61
63
|
export const Switch = forwardRef<SwitchProps, HTMLDivElement>((props, ref) => {
|
|
64
|
+
const { isAnyDisabled, disabledStateProps, otherProps } = useDisableStateProps(props);
|
|
62
65
|
const defaultTheme = useTheme() || Theme.light;
|
|
63
66
|
const {
|
|
64
67
|
checked,
|
|
65
68
|
children,
|
|
66
69
|
className,
|
|
67
|
-
disabled,
|
|
68
70
|
helper,
|
|
69
71
|
id,
|
|
70
72
|
isChecked = checked,
|
|
71
|
-
isDisabled = disabled,
|
|
72
73
|
name,
|
|
73
74
|
onChange,
|
|
74
75
|
position = DEFAULT_PROPS.position,
|
|
@@ -76,7 +77,7 @@ export const Switch = forwardRef<SwitchProps, HTMLDivElement>((props, ref) => {
|
|
|
76
77
|
value,
|
|
77
78
|
inputProps = {},
|
|
78
79
|
...forwardedProps
|
|
79
|
-
} =
|
|
80
|
+
} = otherProps;
|
|
80
81
|
const generatedInputId = useId();
|
|
81
82
|
const inputId = id || generatedInputId;
|
|
82
83
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
@@ -94,13 +95,12 @@ export const Switch = forwardRef<SwitchProps, HTMLDivElement>((props, ref) => {
|
|
|
94
95
|
handleBasicClasses({
|
|
95
96
|
prefix: CLASSNAME,
|
|
96
97
|
isChecked,
|
|
97
|
-
isDisabled,
|
|
98
|
+
isDisabled: isAnyDisabled,
|
|
98
99
|
position,
|
|
99
100
|
theme,
|
|
100
101
|
isUnchecked: !isChecked,
|
|
101
102
|
}),
|
|
102
103
|
)}
|
|
103
|
-
aria-disabled={isDisabled}
|
|
104
104
|
>
|
|
105
105
|
<div className={`${CLASSNAME}__input-wrapper`}>
|
|
106
106
|
<input
|
|
@@ -110,7 +110,8 @@ export const Switch = forwardRef<SwitchProps, HTMLDivElement>((props, ref) => {
|
|
|
110
110
|
className={`${CLASSNAME}__input-native`}
|
|
111
111
|
name={name}
|
|
112
112
|
value={value}
|
|
113
|
-
|
|
113
|
+
{...disabledStateProps}
|
|
114
|
+
readOnly={inputProps.readOnly || isAnyDisabled}
|
|
114
115
|
checked={isChecked}
|
|
115
116
|
aria-checked={Boolean(isChecked)}
|
|
116
117
|
onChange={handleChange}
|
|
@@ -5,6 +5,7 @@ import classNames from 'classnames';
|
|
|
5
5
|
import { GenericProps } from '@lumx/react/utils/type';
|
|
6
6
|
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
7
7
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
8
|
+
import { useDisableStateProps } from '@lumx/react/utils/disabled/useDisableStateProps';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Defines the props of the component.
|
|
@@ -43,23 +44,24 @@ const DEFAULT_PROPS: Partial<TableRowProps> = {};
|
|
|
43
44
|
* @return React element.
|
|
44
45
|
*/
|
|
45
46
|
export const TableRow = forwardRef<TableRowProps, HTMLTableRowElement>((props, ref) => {
|
|
46
|
-
const {
|
|
47
|
+
const { isAnyDisabled, disabledStateProps, otherProps } = useDisableStateProps(props);
|
|
48
|
+
const { children, className, isClickable, isSelected, ...forwardedProps } = otherProps;
|
|
47
49
|
|
|
48
50
|
return (
|
|
49
51
|
<tr
|
|
50
52
|
ref={ref}
|
|
51
|
-
tabIndex={isClickable && !
|
|
53
|
+
tabIndex={isClickable && !disabledStateProps.disabled ? 0 : -1}
|
|
52
54
|
{...forwardedProps}
|
|
53
55
|
className={classNames(
|
|
54
56
|
className,
|
|
55
57
|
handleBasicClasses({
|
|
56
|
-
isClickable: isClickable && !
|
|
57
|
-
isDisabled,
|
|
58
|
-
isSelected: isSelected && !
|
|
58
|
+
isClickable: isClickable && !isAnyDisabled,
|
|
59
|
+
isDisabled: isAnyDisabled,
|
|
60
|
+
isSelected: isSelected && !isAnyDisabled,
|
|
59
61
|
prefix: CLASSNAME,
|
|
60
62
|
}),
|
|
61
63
|
)}
|
|
62
|
-
aria-disabled={
|
|
64
|
+
aria-disabled={isAnyDisabled}
|
|
63
65
|
>
|
|
64
66
|
{children}
|
|
65
67
|
</tr>
|
|
@@ -8,6 +8,7 @@ import { GenericProps } from '@lumx/react/utils/type';
|
|
|
8
8
|
import { handleBasicClasses } from '@lumx/react/utils/className';
|
|
9
9
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
10
10
|
|
|
11
|
+
import { useDisableStateProps } from '@lumx/react/utils/disabled/useDisableStateProps';
|
|
11
12
|
import { useTabProviderContext } from './state';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -55,29 +56,28 @@ const DEFAULT_PROPS: Partial<TabProps> = {};
|
|
|
55
56
|
* @return React element.
|
|
56
57
|
*/
|
|
57
58
|
export const Tab = forwardRef<TabProps, HTMLButtonElement>((props, ref) => {
|
|
59
|
+
const { isAnyDisabled, otherProps } = useDisableStateProps(props);
|
|
58
60
|
const {
|
|
59
61
|
className,
|
|
60
|
-
disabled,
|
|
61
62
|
icon,
|
|
62
63
|
iconProps = {},
|
|
63
64
|
id,
|
|
64
65
|
isActive: propIsActive,
|
|
65
|
-
isDisabled = disabled,
|
|
66
66
|
label,
|
|
67
67
|
onFocus,
|
|
68
68
|
onKeyPress,
|
|
69
69
|
tabIndex = -1,
|
|
70
70
|
...forwardedProps
|
|
71
|
-
} =
|
|
71
|
+
} = otherProps;
|
|
72
72
|
const state = useTabProviderContext('tab', id);
|
|
73
73
|
const isActive = propIsActive || state?.isActive;
|
|
74
74
|
|
|
75
75
|
const changeToCurrentTab = useCallback(() => {
|
|
76
|
-
if (
|
|
76
|
+
if (isAnyDisabled) {
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
state?.changeToTab();
|
|
80
|
-
}, [
|
|
80
|
+
}, [isAnyDisabled, state]);
|
|
81
81
|
|
|
82
82
|
const handleFocus: FocusEventHandler = useCallback(
|
|
83
83
|
(event) => {
|
|
@@ -92,12 +92,12 @@ export const Tab = forwardRef<TabProps, HTMLButtonElement>((props, ref) => {
|
|
|
92
92
|
const handleKeyPress: KeyboardEventHandler = useCallback(
|
|
93
93
|
(event) => {
|
|
94
94
|
onKeyPress?.(event);
|
|
95
|
-
if (event.key !== 'Enter') {
|
|
95
|
+
if (event.key !== 'Enter' || isAnyDisabled) {
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
changeToCurrentTab();
|
|
99
99
|
},
|
|
100
|
-
[changeToCurrentTab, onKeyPress],
|
|
100
|
+
[changeToCurrentTab, isAnyDisabled, onKeyPress],
|
|
101
101
|
);
|
|
102
102
|
|
|
103
103
|
return (
|
|
@@ -106,13 +106,16 @@ export const Tab = forwardRef<TabProps, HTMLButtonElement>((props, ref) => {
|
|
|
106
106
|
{...forwardedProps}
|
|
107
107
|
type="button"
|
|
108
108
|
id={state?.tabId}
|
|
109
|
-
className={classNames(
|
|
109
|
+
className={classNames(
|
|
110
|
+
className,
|
|
111
|
+
handleBasicClasses({ prefix: CLASSNAME, isActive, isDisabled: isAnyDisabled }),
|
|
112
|
+
)}
|
|
110
113
|
onClick={changeToCurrentTab}
|
|
111
114
|
onKeyPress={handleKeyPress}
|
|
112
115
|
onFocus={handleFocus}
|
|
113
116
|
role="tab"
|
|
114
117
|
tabIndex={isActive ? 0 : tabIndex}
|
|
115
|
-
aria-disabled={
|
|
118
|
+
aria-disabled={isAnyDisabled}
|
|
116
119
|
aria-selected={isActive}
|
|
117
120
|
aria-controls={state?.tabPanelId}
|
|
118
121
|
>
|
|
@@ -3,6 +3,7 @@ import { mdiTranslate } from '@lumx/icons';
|
|
|
3
3
|
import { Chip, IconButton, TextField, Typography } from '@lumx/react';
|
|
4
4
|
import { withValueOnChange } from '@lumx/react/stories/decorators/withValueOnChange';
|
|
5
5
|
import { loremIpsum } from '@lumx/react/stories/utils/lorem';
|
|
6
|
+
import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
9
|
title: 'LumX components/text-field/TextField',
|
|
@@ -156,3 +157,24 @@ export const WithChips = {
|
|
|
156
157
|
),
|
|
157
158
|
},
|
|
158
159
|
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Disabled state
|
|
163
|
+
*/
|
|
164
|
+
export const Disabled = {
|
|
165
|
+
args: {
|
|
166
|
+
value: 'Some value',
|
|
167
|
+
label: 'Label',
|
|
168
|
+
helper: 'Helper',
|
|
169
|
+
},
|
|
170
|
+
decorators: [
|
|
171
|
+
withCombinations({
|
|
172
|
+
combinations: {
|
|
173
|
+
rows: {
|
|
174
|
+
disabled: { disabled: true },
|
|
175
|
+
'aria-disabled': { 'aria-disabled': true },
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
],
|
|
180
|
+
};
|
|
@@ -227,6 +227,62 @@ describe(`<${TextField.displayName}>`, () => {
|
|
|
227
227
|
});
|
|
228
228
|
});
|
|
229
229
|
|
|
230
|
+
describe('Disabled state', () => {
|
|
231
|
+
it('should render with "isDisabled"', async () => {
|
|
232
|
+
const onChange = jest.fn();
|
|
233
|
+
const { element, inputNative } = setup({
|
|
234
|
+
label: 'Label',
|
|
235
|
+
isDisabled: true,
|
|
236
|
+
value: 'test',
|
|
237
|
+
onChange,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
expect(element).toHaveClass('lumx-text-field--is-disabled');
|
|
241
|
+
expect(inputNative).toBeDisabled();
|
|
242
|
+
|
|
243
|
+
// Cannot type in disabled input.
|
|
244
|
+
await userEvent.type(inputNative, 'new value');
|
|
245
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should not render clear button when disabled', () => {
|
|
249
|
+
const { clearButton } = setup({
|
|
250
|
+
value: 'initial value',
|
|
251
|
+
clearButtonProps: { label: 'Clear' },
|
|
252
|
+
isDisabled: true,
|
|
253
|
+
});
|
|
254
|
+
expect(clearButton).not.toBeInTheDocument();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should render with "aria-disabled"', async () => {
|
|
258
|
+
const onChange = jest.fn();
|
|
259
|
+
const { element, inputNative } = setup({
|
|
260
|
+
label: 'Label',
|
|
261
|
+
'aria-disabled': true,
|
|
262
|
+
value: 'test',
|
|
263
|
+
onChange,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
expect(element).toHaveClass('lumx-text-field--is-disabled');
|
|
267
|
+
expect(inputNative).not.toBeDisabled();
|
|
268
|
+
expect(inputNative).toHaveAttribute('aria-disabled', 'true');
|
|
269
|
+
expect(inputNative).toHaveAttribute('readonly');
|
|
270
|
+
|
|
271
|
+
// Cannot type in readonly input.
|
|
272
|
+
await userEvent.type(inputNative, 'new value');
|
|
273
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should not render clear button when aria-disabled', () => {
|
|
277
|
+
const { clearButton } = setup({
|
|
278
|
+
value: 'initial value',
|
|
279
|
+
clearButtonProps: { label: 'Clear' },
|
|
280
|
+
'aria-disabled': true,
|
|
281
|
+
});
|
|
282
|
+
expect(clearButton).not.toBeInTheDocument();
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
230
286
|
// Common tests suite.
|
|
231
287
|
commonTestsSuiteRTL(setup, {
|
|
232
288
|
baseClassName: CLASSNAME,
|
|
@@ -22,11 +22,13 @@ import { mergeRefs } from '@lumx/react/utils/react/mergeRefs';
|
|
|
22
22
|
import { useId } from '@lumx/react/hooks/useId';
|
|
23
23
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
24
24
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
25
|
+
import { useDisableStateProps } from '@lumx/react/utils/disabled/useDisableStateProps';
|
|
26
|
+
import { HasAriaDisabled } from '@lumx/react/utils/type/HasAriaDisabled';
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Defines the props of the component.
|
|
28
30
|
*/
|
|
29
|
-
export interface TextFieldProps extends GenericProps, HasTheme {
|
|
31
|
+
export interface TextFieldProps extends GenericProps, HasTheme, HasAriaDisabled {
|
|
30
32
|
/** Chip Group to be rendered before the main text input. */
|
|
31
33
|
chips?: ReactNode;
|
|
32
34
|
/** Props to pass to the clear button (minus those already set by the TextField props). If not specified, the button won't be displayed. */
|
|
@@ -158,7 +160,9 @@ interface InputNativeProps {
|
|
|
158
160
|
id?: string;
|
|
159
161
|
inputRef?: TextFieldProps['inputRef'];
|
|
160
162
|
isDisabled?: boolean;
|
|
163
|
+
'aria-disabled'?: boolean;
|
|
161
164
|
isRequired?: boolean;
|
|
165
|
+
readOnly?: boolean;
|
|
162
166
|
multiline?: boolean;
|
|
163
167
|
maxLength?: number;
|
|
164
168
|
placeholder?: string;
|
|
@@ -178,7 +182,6 @@ interface InputNativeProps {
|
|
|
178
182
|
const renderInputNative: React.FC<InputNativeProps> = (props) => {
|
|
179
183
|
const {
|
|
180
184
|
id,
|
|
181
|
-
isDisabled,
|
|
182
185
|
isRequired,
|
|
183
186
|
placeholder,
|
|
184
187
|
multiline,
|
|
@@ -231,13 +234,13 @@ const renderInputNative: React.FC<InputNativeProps> = (props) => {
|
|
|
231
234
|
placeholder,
|
|
232
235
|
value,
|
|
233
236
|
name,
|
|
234
|
-
disabled: isDisabled,
|
|
235
237
|
required: isRequired,
|
|
236
238
|
onFocus: onTextFieldFocus,
|
|
237
239
|
onBlur: onTextFieldBlur,
|
|
238
240
|
onChange: handleChange,
|
|
239
241
|
'aria-invalid': hasError ? 'true' : undefined,
|
|
240
242
|
'aria-describedby': describedById,
|
|
243
|
+
readOnly: forwardedProps.readOnly || forwardedProps['aria-disabled'],
|
|
241
244
|
ref: mergeRefs(inputRef as any, ref) as any,
|
|
242
245
|
};
|
|
243
246
|
if (multiline) {
|
|
@@ -256,12 +259,12 @@ const renderInputNative: React.FC<InputNativeProps> = (props) => {
|
|
|
256
259
|
* @return React element.
|
|
257
260
|
*/
|
|
258
261
|
export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref) => {
|
|
262
|
+
const { isAnyDisabled, disabledStateProps, otherProps } = useDisableStateProps(props);
|
|
259
263
|
const defaultTheme = useTheme() || Theme.light;
|
|
260
264
|
const {
|
|
261
265
|
chips,
|
|
262
266
|
className,
|
|
263
267
|
clearButtonProps,
|
|
264
|
-
disabled,
|
|
265
268
|
error,
|
|
266
269
|
forceFocusStyle,
|
|
267
270
|
hasError,
|
|
@@ -269,7 +272,6 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
269
272
|
icon,
|
|
270
273
|
id,
|
|
271
274
|
inputRef: inputRefProps,
|
|
272
|
-
isDisabled = disabled,
|
|
273
275
|
isRequired,
|
|
274
276
|
isValid,
|
|
275
277
|
label,
|
|
@@ -289,7 +291,7 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
289
291
|
value,
|
|
290
292
|
afterElement,
|
|
291
293
|
...forwardedProps
|
|
292
|
-
} =
|
|
294
|
+
} = otherProps;
|
|
293
295
|
const generatedTextFieldId = useId();
|
|
294
296
|
const textFieldId = id || generatedTextFieldId;
|
|
295
297
|
/** Keep a clean local input ref to manage focus */
|
|
@@ -352,7 +354,7 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
352
354
|
hasPlaceholder: Boolean(placeholder),
|
|
353
355
|
hasTextarea: multiline,
|
|
354
356
|
hasValue: Boolean(value),
|
|
355
|
-
isDisabled,
|
|
357
|
+
isDisabled: isAnyDisabled,
|
|
356
358
|
isFocus: isFocus || forceFocusStyle,
|
|
357
359
|
isValid,
|
|
358
360
|
prefix: CLASSNAME,
|
|
@@ -400,7 +402,7 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
400
402
|
{renderInputNative({
|
|
401
403
|
id: textFieldId,
|
|
402
404
|
inputRef,
|
|
403
|
-
|
|
405
|
+
...disabledStateProps,
|
|
404
406
|
isRequired,
|
|
405
407
|
maxLength,
|
|
406
408
|
multiline,
|
|
@@ -426,7 +428,7 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
426
428
|
{renderInputNative({
|
|
427
429
|
id: textFieldId,
|
|
428
430
|
inputRef,
|
|
429
|
-
|
|
431
|
+
...disabledStateProps,
|
|
430
432
|
isRequired,
|
|
431
433
|
maxLength,
|
|
432
434
|
multiline,
|
|
@@ -456,7 +458,7 @@ export const TextField = forwardRef<TextFieldProps, HTMLDivElement>((props, ref)
|
|
|
456
458
|
/>
|
|
457
459
|
)}
|
|
458
460
|
|
|
459
|
-
{clearButtonProps && isNotEmpty && (
|
|
461
|
+
{clearButtonProps && isNotEmpty && !isAnyDisabled && (
|
|
460
462
|
<IconButton
|
|
461
463
|
{...clearButtonProps}
|
|
462
464
|
className={`${CLASSNAME}__input-clear`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useDisableStateProps } from './useDisableStateProps';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type GenericProps = {
|
|
2
|
+
disabled?: boolean;
|
|
3
|
+
isDisabled?: boolean;
|
|
4
|
+
'aria-disabled'?: boolean | 'true' | 'false';
|
|
5
|
+
onClick?: any;
|
|
6
|
+
onChange?: any;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
interface Output<TProps extends GenericProps> {
|
|
10
|
+
/** Is disabled or aria-disabled */
|
|
11
|
+
isAnyDisabled?: boolean;
|
|
12
|
+
disabledStateProps: { disabled?: boolean; 'aria-disabled'?: boolean };
|
|
13
|
+
otherProps: TProps & { disabled: never; 'aria-disabled': never; isDisabled: never };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve disabled state from props.
|
|
18
|
+
* (handles `disabled`, `isDisabled` and `aria-disabled`)
|
|
19
|
+
*
|
|
20
|
+
* @params component props
|
|
21
|
+
*/
|
|
22
|
+
export function useDisableStateProps<TProps extends GenericProps>(props: TProps): Output<TProps> {
|
|
23
|
+
const { disabled, isDisabled = disabled, 'aria-disabled': ariaDisabled, onClick, onChange, ...otherProps } = props;
|
|
24
|
+
const disabledStateProps = {
|
|
25
|
+
disabled: isDisabled,
|
|
26
|
+
'aria-disabled': ariaDisabled === true || ariaDisabled === 'true',
|
|
27
|
+
};
|
|
28
|
+
const isAnyDisabled = disabledStateProps['aria-disabled'] || disabledStateProps.disabled;
|
|
29
|
+
if (!isAnyDisabled) {
|
|
30
|
+
(otherProps as any).onClick = onClick;
|
|
31
|
+
(otherProps as any).onChange = onChange;
|
|
32
|
+
}
|
|
33
|
+
return { disabledStateProps, otherProps: otherProps as Output<TProps>['otherProps'], isAnyDisabled };
|
|
34
|
+
}
|