@hyphen/hyphen-components 8.0.1 → 9.0.0-beta.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.
Files changed (60) hide show
  1. package/dist/css/utilities.css +1 -1
  2. package/dist/css/utilities.css.map +1 -1
  3. package/dist/hyphen-components.cjs.development.js +342 -311
  4. package/dist/hyphen-components.cjs.development.js.map +1 -1
  5. package/dist/hyphen-components.cjs.production.min.js +2 -2
  6. package/dist/hyphen-components.cjs.production.min.js.map +1 -1
  7. package/dist/hyphen-components.esm.js +346 -312
  8. package/dist/hyphen-components.esm.js.map +1 -1
  9. package/dist/index.d.ts +212 -202
  10. package/package.json +6 -5
  11. package/src/components/Alert/Alert.tsx +5 -6
  12. package/src/components/Badge/Badge.test.tsx +12 -0
  13. package/src/components/Badge/Badge.tsx +52 -20
  14. package/src/components/Box/Box.mdx +1 -1
  15. package/src/components/Box/Box.stories.tsx +1 -1
  16. package/src/components/Box/Box.test.tsx +24 -1
  17. package/src/components/Box/Box.tsx +108 -82
  18. package/src/components/Card/Card.tsx +5 -1
  19. package/src/components/Card/components/CardFooter/CardFooter.tsx +0 -4
  20. package/src/components/Card/components/CardHeader/CardHeader.tsx +4 -1
  21. package/src/components/Card/components/CardSection/CardSection.tsx +4 -5
  22. package/src/components/CheckboxInput/CheckboxInput.test.tsx +17 -0
  23. package/src/components/CheckboxInput/CheckboxInput.tsx +15 -4
  24. package/src/components/CheckboxInput/components/Checkbox.test.tsx +36 -0
  25. package/src/components/CheckboxInput/components/Checkbox.tsx +8 -2
  26. package/src/components/Details/Details.test.tsx +8 -0
  27. package/src/components/Details/Details.tsx +5 -2
  28. package/src/components/Details/DetailsSummary.tsx +4 -1
  29. package/src/components/Drawer/Drawer.test.tsx +8 -0
  30. package/src/components/Drawer/Drawer.tsx +1 -1
  31. package/src/components/FormLabel/FormLabel.tsx +6 -3
  32. package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.test.tsx +9 -0
  33. package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.tsx +1 -0
  34. package/src/components/Formik/FormikSelectInput/FormikSelectInput.tsx +21 -11
  35. package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.tsx +1 -1
  36. package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +1 -1
  37. package/src/components/Heading/Heading.tsx +5 -6
  38. package/src/components/Icon/Icon.test.tsx +8 -0
  39. package/src/components/Icon/Icon.tsx +6 -7
  40. package/src/components/Modal/Modal.test.tsx +31 -1
  41. package/src/components/Modal/Modal.tsx +13 -7
  42. package/src/components/Popover/Popover.test.tsx +3 -4
  43. package/src/components/RadioGroup/RadioGroup.tsx +11 -6
  44. package/src/components/RadioGroup/RadioInput/RadioInputIcon.tsx +0 -4
  45. package/src/components/SelectInput/SelectInput.test.tsx +18 -0
  46. package/src/components/SelectInput/SelectInput.tsx +47 -27
  47. package/src/components/SelectInputInset/SelectInputInset.tsx +8 -9
  48. package/src/components/SelectInputNative/SelectInputNative.test.tsx +24 -0
  49. package/src/components/SelectInputNative/SelectInputNative.tsx +79 -14
  50. package/src/components/Switch/Switch.tsx +1 -1
  51. package/src/components/Table/Table.mdx +1 -1
  52. package/src/components/Table/Table.stories.tsx +5 -1
  53. package/src/components/Table/common/TableRow/TableRow.test.tsx +16 -0
  54. package/src/components/Table/common/TableRow/TableRow.tsx +19 -1
  55. package/src/components/TextInput/TextInput.tsx +10 -8
  56. package/src/components/TextInputInset/TextInputInset.tsx +5 -6
  57. package/src/components/TextareaInput/TextareaInput.tsx +4 -5
  58. package/src/components/TextareaInputInset/TextareaInputInset.tsx +10 -17
  59. package/src/components/Toast/Toast.stories.tsx +5 -1
  60. package/src/types/index.ts +2 -3
@@ -7,7 +7,9 @@ import Select, {
7
7
  OptionsOrGroups,
8
8
  OnChangeValue,
9
9
  } from 'react-select';
10
- import AsyncCreatableSelect from 'react-select/async-creatable';
10
+ import AsyncCreatableSelect, {
11
+ AsyncCreatableProps,
12
+ } from 'react-select/async-creatable';
11
13
  import AsyncSelect from 'react-select/async';
12
14
  import CreatableSelect from 'react-select/creatable';
13
15
  import { ResponsiveProp } from '../../types';
@@ -42,7 +44,7 @@ export type TextInputSize =
42
44
  | 'lg'
43
45
  | ResponsiveProp<'sm' | 'md' | 'lg'>;
44
46
 
45
- export interface SelectInputProps {
47
+ interface SelectInputOwnProps {
46
48
  /**
47
49
  * The id attribute of the input.
48
50
  */
@@ -59,10 +61,6 @@ export interface SelectInputProps {
59
61
  * The value(s) of select.
60
62
  */
61
63
  value: any | any[]; // eslint-disable-line @typescript-eslint/no-explicit-any
62
- /**
63
- * Options for dropdown list.
64
- */
65
- options: SelectInputOptions | AsyncOptions;
66
64
  /**
67
65
  * Autofocus select input on render.
68
66
  */
@@ -84,10 +82,6 @@ export interface SelectInputProps {
84
82
  * Visually hide the label.
85
83
  */
86
84
  hideLabel?: boolean;
87
- /**
88
- * Load the input asynchronously.
89
- */
90
- isAsync?: boolean;
91
85
  /**
92
86
  * If the input value is clearable programmatically.
93
87
  */
@@ -137,18 +131,36 @@ export interface SelectInputProps {
137
131
  * The size of the text input.
138
132
  */
139
133
  size?: TextInputSize;
140
- /**
141
- * Additional props to be spread. These will be applied specifically to
142
- * the `react-select` component that powers the select. For full docs on
143
- * react-select props, [Click Here](https://react-select.com/props)
144
- */
145
- [x: string]: any; // eslint-disable-line
146
134
  }
147
135
 
136
+ type ReactSelectAsyncProps = AsyncCreatableProps<
137
+ SelectOption,
138
+ boolean,
139
+ SelectGroupOptions
140
+ >;
141
+
142
+ type ControlledReactSelectProps =
143
+ | 'aria-label'
144
+ | 'aria-labelledby'
145
+ | 'cacheOptions'
146
+ | 'classNamePrefix'
147
+ | 'components'
148
+ | 'defaultOptions'
149
+ | 'inputId'
150
+ | 'loadOptions'
151
+ | 'options'
152
+ | 'styles';
153
+
154
+ type SelectInputBaseProps = SelectInputOwnProps &
155
+ Omit<
156
+ ReactSelectAsyncProps,
157
+ keyof SelectInputOwnProps | ControlledReactSelectProps
158
+ >;
159
+
148
160
  type AsyncOptions = (
149
161
  inputValue: string
150
162
  ) => Promise<OptionsOrGroups<SelectOption, SelectGroupOptions>>;
151
- type AsyncSelectInputProps = SelectInputProps & {
163
+ export type AsyncSelectInputProps = SelectInputBaseProps & {
152
164
  /**
153
165
  * Load the input asynchronously.
154
166
  */
@@ -160,14 +172,14 @@ type AsyncSelectInputProps = SelectInputProps & {
160
172
  /**
161
173
  * If cacheOptions is passed, then the loaded data will be cached.
162
174
  */
163
- cacheOptions?: boolean;
175
+ cacheOptions?: ReactSelectAsyncProps['cacheOptions'];
164
176
  /**
165
177
  * The default set of options to show before the user starts searching.
166
178
  */
167
- defaultOptions?: boolean;
179
+ defaultOptions?: ReactSelectAsyncProps['defaultOptions'];
168
180
  };
169
181
 
170
- type SyncSelectInputProps = SelectInputProps & {
182
+ export type SyncSelectInputProps = SelectInputBaseProps & {
171
183
  /**
172
184
  * Load the input synchronously.
173
185
  */
@@ -176,10 +188,12 @@ type SyncSelectInputProps = SelectInputProps & {
176
188
  * Options for dropdown list.
177
189
  */
178
190
  options: SelectInputOptions;
191
+ cacheOptions?: never;
192
+ defaultOptions?: never;
179
193
  };
180
194
 
181
- export function SelectInput(props: AsyncSelectInputProps): JSX.Element;
182
- export function SelectInput(props: SyncSelectInputProps): JSX.Element;
195
+ export type SelectInputProps = AsyncSelectInputProps | SyncSelectInputProps;
196
+
183
197
  export function SelectInput(props: SelectInputProps): JSX.Element {
184
198
  const {
185
199
  id,
@@ -205,6 +219,8 @@ export function SelectInput(props: SelectInputProps): JSX.Element {
205
219
  placeholder = undefined,
206
220
  requiredIndicator = ' *',
207
221
  size = 'md',
222
+ cacheOptions,
223
+ defaultOptions,
208
224
  ...restProps
209
225
  } = props;
210
226
 
@@ -262,13 +278,17 @@ export function SelectInput(props: SelectInputProps): JSX.Element {
262
278
  isCreatable && isAsync
263
279
  ? AsyncCreatableSelect
264
280
  : isCreatable
265
- ? CreatableSelect
266
- : isAsync
267
- ? AsyncSelect
268
- : Select;
281
+ ? CreatableSelect
282
+ : isAsync
283
+ ? AsyncSelect
284
+ : Select;
269
285
 
270
286
  const selectOptions = isAsync
271
- ? ({ loadOptions: options } as { loadOptions: AsyncOptions })
287
+ ? {
288
+ loadOptions: options as AsyncOptions,
289
+ cacheOptions,
290
+ defaultOptions,
291
+ }
272
292
  : ({ options } as { options: SelectInputOptions });
273
293
 
274
294
  return (
@@ -6,7 +6,6 @@ import React, {
6
6
  FocusEvent,
7
7
  ForwardRefExoticComponent,
8
8
  ReactNode,
9
- HTMLProps,
10
9
  } from 'react';
11
10
  import classNames from 'classnames';
12
11
  import { ResponsiveProp } from '../../types';
@@ -36,11 +35,15 @@ export interface SelectInputInsetProps {
36
35
  /**
37
36
  * Callback function to call on change event.
38
37
  */
39
- onChange: (event: ChangeEvent<HTMLInputElement>) => void;
38
+ onChange: (event: ChangeEvent<HTMLSelectElement>) => void;
40
39
  /**
41
40
  * Value of selected option. Should match the value key in the option object.
42
41
  */
43
42
  value: string | number | null;
43
+ /**
44
+ * The select's autocomplete behavior.
45
+ */
46
+ autoComplete?: boolean | string;
44
47
  /**
45
48
  * Automatically focus the input when the page is loaded.
46
49
  */
@@ -61,7 +64,7 @@ export interface SelectInputInsetProps {
61
64
  /**
62
65
  * Props passed directly to the input element of the component
63
66
  */
64
- inputProps?: BoxProps & HTMLProps<HTMLInputElement>;
67
+ inputProps?: Omit<BoxProps<'select'>, 'as'>;
65
68
  /**
66
69
  * The input's disabled attribute
67
70
  */
@@ -77,7 +80,7 @@ export interface SelectInputInsetProps {
77
80
  /**
78
81
  * Callback function to call on blur event.
79
82
  */
80
- onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
83
+ onBlur?: (event: FocusEvent<HTMLSelectElement>) => void;
81
84
  /**
82
85
  * Callback function to call when input us cleared. When this is passed,
83
86
  * the input will display an icon on the right side, for triggering this callback.
@@ -88,7 +91,7 @@ export interface SelectInputInsetProps {
88
91
  /**
89
92
  * Callback function to call on focus event.
90
93
  */
91
- onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
94
+ onFocus?: (event: FocusEvent<HTMLSelectElement>) => void;
92
95
  /**
93
96
  * The input placeholder attribute.
94
97
  */
@@ -101,10 +104,6 @@ export interface SelectInputInsetProps {
101
104
  * The size of the text input.
102
105
  */
103
106
  size?: SelectInputInsetSize | ResponsiveProp<SelectInputInsetSize>;
104
- /**
105
- * Additional props to be spread to rendered element
106
- */
107
- [x: string]: any; // eslint-disable-line
108
107
  }
109
108
 
110
109
  export const SelectInputInset: ForwardRefExoticComponent<SelectInputInsetProps> =
@@ -102,6 +102,30 @@ describe('SelectInputNative', () => {
102
102
 
103
103
  expect(mockedHandleBlur).toBeCalledTimes(1);
104
104
  });
105
+
106
+ test('it forwards native select attributes to the select element', () => {
107
+ render(
108
+ <SelectInputNative
109
+ id="testId"
110
+ label="native attributes"
111
+ onChange={() => undefined}
112
+ options={selectOptions}
113
+ value={null}
114
+ form="settings-form"
115
+ disabled
116
+ required
117
+ data-testid="native-select"
118
+ inputProps={{ title: 'Select a flavor' }}
119
+ />
120
+ );
121
+
122
+ const select = screen.getByTestId('native-select');
123
+ expect(select).toHaveAttribute('form', 'settings-form');
124
+ expect(select).toHaveAttribute('title', 'Select a flavor');
125
+ expect(select).toBeDisabled();
126
+ expect(select).toBeRequired();
127
+ expect(select.parentElement).not.toHaveAttribute('form');
128
+ });
105
129
  });
106
130
 
107
131
  describe('States', () => {
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
4
4
  import { ResponsiveProp } from '../../types';
5
- import { Box, BoxProps } from '../Box/Box';
5
+ import { Box, BoxOwnProps, BoxProps, boxPropsKeys } from '../Box/Box';
6
6
  import { FormControl, FormControlProps } from '../FormControl/FormControl';
7
7
  import styles from './SelectInputNative.module.scss';
8
8
 
@@ -13,7 +13,7 @@ export interface SelectInputNativeOption {
13
13
  disabled?: boolean;
14
14
  }
15
15
 
16
- export interface SelectInputNativeProps extends BoxProps, FormControlProps {
16
+ interface SelectInputNativeOwnProps {
17
17
  /**
18
18
  * List of options for the select input.
19
19
  */
@@ -25,11 +25,36 @@ export interface SelectInputNativeProps extends BoxProps, FormControlProps {
25
25
  /**
26
26
  * Value of selected option. Should match the value key in the option object.
27
27
  */
28
- value: string | number | null;
28
+ value: React.ComponentPropsWithoutRef<'select'>['value'] | null;
29
+ /**
30
+ * Props passed directly to the select element of the component.
31
+ */
32
+ inputProps?: Omit<
33
+ BoxProps<'select'>,
34
+ | 'aria-label'
35
+ | 'aria-labelledby'
36
+ | 'aria-required'
37
+ | 'as'
38
+ | 'autoFocus'
39
+ | 'children'
40
+ | 'color'
41
+ | 'defaultValue'
42
+ | 'disabled'
43
+ | 'id'
44
+ | 'name'
45
+ | 'onChange'
46
+ | 'required'
47
+ | 'size'
48
+ | 'value'
49
+ >;
29
50
  /**
30
51
  * The input's 'name' attribute.
31
52
  */
32
53
  name?: string;
54
+ /**
55
+ * Placeholder option displayed before a value is selected.
56
+ */
57
+ placeholder?: string;
33
58
  /**
34
59
  * Visual indicator that the field is required, that gets appended to the label
35
60
  */
@@ -42,12 +67,38 @@ export interface SelectInputNativeProps extends BoxProps, FormControlProps {
42
67
  * Whether the input is autofocused on initial render.
43
68
  */
44
69
  autoFocus?: HTMLSelectElement['autofocus'];
45
- /**
46
- * Additional props to be spread.
47
- */
48
- [x: string]: any; // eslint-disable-line
49
70
  }
50
71
 
72
+ type SelectInputNativeFormControlProps = Pick<
73
+ FormControlProps,
74
+ | 'error'
75
+ | 'helpText'
76
+ | 'hideLabel'
77
+ | 'id'
78
+ | 'isDisabled'
79
+ | 'isRequired'
80
+ | 'label'
81
+ >;
82
+
83
+ type SelectInputNativeElementProps = Omit<
84
+ React.ComponentPropsWithoutRef<'select'>,
85
+ | keyof SelectInputNativeOwnProps
86
+ | keyof SelectInputNativeFormControlProps
87
+ | keyof BoxOwnProps
88
+ | 'aria-label'
89
+ | 'aria-labelledby'
90
+ | 'aria-required'
91
+ | 'children'
92
+ | 'dangerouslySetInnerHTML'
93
+ | 'defaultValue'
94
+ | 'size'
95
+ >;
96
+
97
+ export type SelectInputNativeProps = SelectInputNativeOwnProps &
98
+ SelectInputNativeFormControlProps &
99
+ Omit<BoxOwnProps, 'children'> &
100
+ SelectInputNativeElementProps;
101
+
51
102
  export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
52
103
  autoFocus = false,
53
104
  label,
@@ -55,6 +106,7 @@ export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
55
106
  helpText,
56
107
  error,
57
108
  id,
109
+ inputProps = {},
58
110
  isDisabled,
59
111
  isRequired,
60
112
  name,
@@ -66,6 +118,17 @@ export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
66
118
  size = 'md',
67
119
  ...restProps
68
120
  }) => {
121
+ const isBoxProp = (key: string) =>
122
+ boxPropsKeys.includes(key as keyof BoxOwnProps);
123
+ const formControlProps = Object.fromEntries(
124
+ Object.entries(restProps).filter(([key]) => isBoxProp(key))
125
+ ) as Omit<BoxOwnProps, 'children'>;
126
+ const selectProps = Object.fromEntries(
127
+ Object.entries(restProps).filter(([key]) => !isBoxProp(key))
128
+ ) as SelectInputNativeElementProps;
129
+ const selectIsDisabled = isDisabled || selectProps.disabled;
130
+ const selectIsRequired = isRequired || selectProps.required;
131
+
69
132
  const placeholderOption: SelectInputNativeOption = {
70
133
  value: '',
71
134
  label: placeholder,
@@ -83,7 +146,7 @@ export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
83
146
  styles['select-input-native-wrapper'],
84
147
  ...responsiveClasses.map((className) => styles[className]),
85
148
  {
86
- [styles.disabled]: isDisabled,
149
+ [styles.disabled]: selectIsDisabled,
87
150
  [styles.error]: error,
88
151
  }
89
152
  );
@@ -95,25 +158,27 @@ export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
95
158
  id={id}
96
159
  error={error}
97
160
  helpText={helpText}
98
- isDisabled={isDisabled}
99
- isRequired={isRequired}
161
+ isDisabled={selectIsDisabled}
162
+ isRequired={selectIsRequired}
100
163
  requiredIndicator={requiredIndicator}
101
- {...restProps}
164
+ {...formControlProps}
102
165
  >
103
166
  <Box className={selectWrapperClasses}>
104
167
  <Box
105
168
  as="select"
169
+ {...inputProps}
170
+ {...selectProps}
106
171
  aria-label={label}
107
172
  aria-labelledby={label && !hideLabel ? `${id}Label` : undefined}
108
- aria-required={isRequired}
173
+ aria-required={selectIsRequired}
109
174
  value={value ?? ''}
110
175
  onChange={onChange}
111
176
  color={!value ? 'disabled' : 'base'}
112
177
  autoFocus={autoFocus}
113
- disabled={isDisabled}
178
+ disabled={selectIsDisabled}
114
179
  name={name}
115
180
  id={id}
116
- required={isRequired}
181
+ required={selectIsRequired}
117
182
  >
118
183
  {optionsWithPlaceholder.map((option) => (
119
184
  <Box
@@ -139,7 +139,7 @@ export const Switch: FC<SwitchProps> = ({
139
139
  alignItems: helpText ? 'flex-start' : ('center' as BoxProps['alignItems']),
140
140
  isFieldRequired: isRequired,
141
141
  requiredIndicator,
142
- size,
142
+ ...(typeof size === 'string' && { size }),
143
143
  };
144
144
 
145
145
  return (
@@ -146,7 +146,7 @@ The `Column` object is equiped with a `render` method. When used, the cells will
146
146
 
147
147
  The render method also exposes data about the cell and row, namely:
148
148
 
149
- `cell: the content in the cell,`
149
+ `cell: the content in the cell, typed as Cell — narrow it before rendering,`
150
150
 
151
151
  `row: the entire row object,`
152
152
 
@@ -106,7 +106,11 @@ export const Column = () =>
106
106
  {
107
107
  heading: 'Type',
108
108
  dataKey: 'type',
109
- render: (cell: string) => <code style={codePreviewStyle}>{cell}</code>,
109
+ render: (cell?: Cell) => (
110
+ <code style={codePreviewStyle}>
111
+ {typeof cell === 'string' || typeof cell === 'number' ? cell : null}
112
+ </code>
113
+ ),
110
114
  },
111
115
  { heading: 'Description', dataKey: 'description' },
112
116
  ];
@@ -48,5 +48,21 @@ describe('TableRow', () => {
48
48
  const element = document.getElementsByClassName('string-class')[0];
49
49
  expect(element).toBeInTheDocument();
50
50
  });
51
+
52
+ test('renders a placeholder instead of a non-renderable row value', () => {
53
+ render(
54
+ <TableRow
55
+ row={{ metadata: { state: 'ready' }, action: <button>Open</button> }}
56
+ columns={[
57
+ { heading: 'Metadata', dataKey: 'metadata' },
58
+ { heading: 'Action', dataKey: 'action' },
59
+ ]}
60
+ emptyCellPlaceholder="--"
61
+ />
62
+ );
63
+
64
+ expect(screen.getByText('--')).toBeInTheDocument();
65
+ expect(screen.getByRole('button', { name: 'Open' })).toBeInTheDocument();
66
+ });
51
67
  });
52
68
  });
@@ -93,13 +93,31 @@ export const TableRow: FC<TableRowProps> = ({
93
93
  className
94
94
  );
95
95
 
96
+ const isRenderableCell = (value: unknown): value is ReactNode => {
97
+ if (value === null || value === undefined) return true;
98
+
99
+ const valueType = typeof value;
100
+ if (
101
+ valueType === 'string' ||
102
+ valueType === 'number' ||
103
+ valueType === 'boolean'
104
+ ) {
105
+ return true;
106
+ }
107
+
108
+ if (Array.isArray(value)) return value.every(isRenderableCell);
109
+
110
+ return React.isValidElement(value);
111
+ };
112
+
96
113
  const renderCellContent = (column: Column): ReactNode => {
97
114
  if (column.render) {
98
115
  const cellValue = column.dataKey && row ? row[column.dataKey] : undefined;
99
116
  return column.render(cellValue, row, rowIndex);
100
117
  }
101
118
 
102
- return column.dataKey && row ? row[column.dataKey] : null;
119
+ const cellValue = column.dataKey && row ? row[column.dataKey] : null;
120
+ return isRenderableCell(cellValue) ? cellValue : null;
103
121
  };
104
122
 
105
123
  const getCellClassName = (column: Column): string | undefined => {
@@ -3,7 +3,6 @@ import React, {
3
3
  ChangeEvent,
4
4
  FocusEvent,
5
5
  ForwardRefExoticComponent,
6
- HTMLProps,
7
6
  InputHTMLAttributes,
8
7
  KeyboardEvent,
9
8
  MouseEvent,
@@ -11,7 +10,7 @@ import React, {
11
10
  forwardRef,
12
11
  } from 'react';
13
12
 
14
- import { FormControl } from '../FormControl/FormControl';
13
+ import { FormControl, FormControlProps } from '../FormControl/FormControl';
15
14
  import { Icon } from '../Icon/Icon';
16
15
  import { ResponsiveProp } from '../../types';
17
16
  import classNames from 'classnames';
@@ -21,7 +20,7 @@ import { getAutoCompleteValue } from '../../lib/getAutoCompleteValue';
21
20
  import styles from './TextInput.module.scss';
22
21
 
23
22
  export type TextInputSizeType = 'sm' | 'md' | 'lg';
24
- export interface TextInputProps {
23
+ interface TextInputOwnProps {
25
24
  /**
26
25
  * The input's id attribute. Used to programmatically tie the input with its label.
27
26
  */
@@ -38,6 +37,10 @@ export interface TextInputProps {
38
37
  * The text value of the input. Required since our Input is a controlled component.
39
38
  */
40
39
  value: InputHTMLAttributes<HTMLInputElement>['value'];
40
+ /**
41
+ * The input's autocomplete behavior.
42
+ */
43
+ autoComplete?: boolean | string;
41
44
  /**
42
45
  * Automatically focus the input when the page is loaded.
43
46
  */
@@ -62,7 +65,7 @@ export interface TextInputProps {
62
65
  /**
63
66
  * Props passed directly to the input element of the component
64
67
  */
65
- inputProps?: BoxProps & HTMLProps<HTMLInputElement>;
68
+ inputProps?: Omit<BoxProps<'input'>, 'as'>;
66
69
  /**
67
70
  * The input's disabled attribute
68
71
  */
@@ -119,12 +122,11 @@ export interface TextInputProps {
119
122
  * The input 'type' value. Defaults to type 'text'.
120
123
  */
121
124
  type?: InputHTMLAttributes<HTMLInputElement>['type'];
122
- /**
123
- * Additional props to be spread to rendered element
124
- */
125
- [x: string]: any; // eslint-disable-line
126
125
  }
127
126
 
127
+ export type TextInputProps = TextInputOwnProps &
128
+ Omit<FormControlProps, keyof TextInputOwnProps>;
129
+
128
130
  export const TextInput: ForwardRefExoticComponent<TextInputProps> = forwardRef<
129
131
  HTMLDivElement,
130
132
  TextInputProps
@@ -6,7 +6,6 @@ import React, {
6
6
  FocusEvent,
7
7
  ForwardRefExoticComponent,
8
8
  ReactNode,
9
- HTMLProps,
10
9
  InputHTMLAttributes,
11
10
  } from 'react';
12
11
  import classNames from 'classnames';
@@ -38,6 +37,10 @@ export interface TextInputInsetProps {
38
37
  * The text value of the input. Required since our Input is a controlled component.
39
38
  */
40
39
  value: InputHTMLAttributes<HTMLInputElement>['value'];
40
+ /**
41
+ * The input's autocomplete behavior.
42
+ */
43
+ autoComplete?: boolean | string;
41
44
  /**
42
45
  * Automatically focus the input when the page is loaded.
43
46
  */
@@ -58,7 +61,7 @@ export interface TextInputInsetProps {
58
61
  /**
59
62
  * Props passed directly to the input element of the component
60
63
  */
61
- inputProps?: BoxProps & HTMLProps<HTMLInputElement>;
64
+ inputProps?: Omit<BoxProps<'input'>, 'as'>;
62
65
  /**
63
66
  * The input's disabled attribute
64
67
  */
@@ -115,10 +118,6 @@ export interface TextInputInsetProps {
115
118
  * The input 'type' value. Defaults to type 'text'.
116
119
  */
117
120
  type?: InputHTMLAttributes<HTMLInputElement>['type'];
118
- /**
119
- * Additional props to be spread to rendered element
120
- */
121
- [x: string]: any; // eslint-disable-line
122
121
  }
123
122
 
124
123
  export const TextInputInset: ForwardRefExoticComponent<TextInputInsetProps> =
@@ -9,7 +9,7 @@ import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
9
9
  import styles from './TextareaInput.module.scss';
10
10
 
11
11
  export type TextareaInputSize = 'sm' | 'md' | 'lg';
12
- export interface TextareaInputProps extends Omit<BoxProps, 'as' | 'width'> {
12
+ interface TextareaInputOwnProps {
13
13
  /**
14
14
  * The input's id attribute. Used to programmatically tie the input with its label.
15
15
  */
@@ -96,12 +96,11 @@ export interface TextareaInputProps extends Omit<BoxProps, 'as' | 'width'> {
96
96
  * The size of the text input.
97
97
  */
98
98
  size?: TextareaInputSize | ResponsiveProp<TextareaInputSize>;
99
- /**
100
- * Additional props to be spread to rendered element
101
- */
102
- [x: string]: any; // eslint-disable-line
103
99
  }
104
100
 
101
+ export type TextareaInputProps = TextareaInputOwnProps &
102
+ Omit<BoxProps<'div'>, keyof TextareaInputOwnProps | 'as' | 'width'>;
103
+
105
104
  export const TextareaInput: FC<TextareaInputProps> = ({
106
105
  id,
107
106
  label,