@transferwise/components 0.0.0-experimental-c654bc3 → 0.0.0-experimental-a7e0e6f

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 (36) hide show
  1. package/build/index.esm.js +47 -141
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +47 -141
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +7 -5
  6. package/build/styles/dimmer/Dimmer.css +0 -3
  7. package/build/styles/drawer/Drawer.css +3 -0
  8. package/build/styles/main.css +7 -5
  9. package/build/styles/modal/Modal.css +4 -2
  10. package/build/types/index.d.ts +2 -1
  11. package/build/types/index.d.ts.map +1 -1
  12. package/build/types/typeahead/Typeahead.d.ts +98 -57
  13. package/build/types/typeahead/Typeahead.d.ts.map +1 -1
  14. package/build/types/typeahead/index.d.ts +3 -2
  15. package/build/types/typeahead/index.d.ts.map +1 -1
  16. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +23 -41
  17. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts.map +1 -1
  18. package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts +9 -17
  19. package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts.map +1 -1
  20. package/package.json +5 -2
  21. package/src/dimmer/Dimmer.css +0 -3
  22. package/src/dimmer/Dimmer.less +0 -4
  23. package/src/drawer/Drawer.css +3 -0
  24. package/src/drawer/Drawer.less +4 -0
  25. package/src/index.ts +2 -1
  26. package/src/main.css +7 -5
  27. package/src/modal/Modal.css +4 -2
  28. package/src/modal/Modal.less +5 -1
  29. package/src/modal/Modal.story.tsx +4 -2
  30. package/src/typeahead/Typeahead.spec.js +1 -1
  31. package/src/typeahead/{Typeahead.story.js → Typeahead.story.tsx} +8 -7
  32. package/src/typeahead/{Typeahead.js → Typeahead.tsx} +105 -106
  33. package/src/typeahead/index.ts +4 -0
  34. package/src/typeahead/typeaheadInput/{TypeaheadInput.js → TypeaheadInput.tsx} +43 -42
  35. package/src/typeahead/typeaheadOption/{TypeaheadOption.js → TypeaheadOption.tsx} +10 -20
  36. package/src/typeahead/index.js +0 -3
@@ -1,18 +1,19 @@
1
1
  import { select, boolean } from '@storybook/addon-knobs';
2
+ import { StoryContext } from '@storybook/react';
2
3
  import { userEvent, within } from '@storybook/test';
3
4
  import { Search as SearchIcon } from '@transferwise/icons';
4
5
  import { useState } from 'react';
5
6
 
6
7
  import { Sentiment } from '../common';
7
8
 
8
- import Typeahead from './Typeahead';
9
+ import { Typeahead, TypeaheadOption } from './Typeahead';
9
10
 
10
11
  export default {
11
12
  component: Typeahead,
12
13
  title: 'Forms/Typeahead',
13
14
  };
14
15
 
15
- const validateChip = (option) => {
16
+ const validateChip = (option: TypeaheadOption) => {
16
17
  // eslint-disable-next-line unicorn/no-unsafe-regex
17
18
  return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
18
19
  option.label,
@@ -43,7 +44,7 @@ export const createable = () => {
43
44
  );
44
45
  };
45
46
 
46
- createable.play = async ({ canvasElement }) => {
47
+ createable.play = async ({ canvasElement }: StoryContext) => {
47
48
  const canvas = within(canvasElement);
48
49
  await userEvent.type(canvas.getByRole('combobox'), 'chip{Enter}chip2{Enter}');
49
50
  };
@@ -76,7 +77,7 @@ export const Basic = () => {
76
77
  ]);
77
78
 
78
79
  const validateChipWhenMultiple = () => {
79
- return multiple && allowNew ? (option) => validateChip(option) : undefined;
80
+ return multiple && allowNew ? (option: TypeaheadOption) => validateChip(option) : undefined;
80
81
  };
81
82
 
82
83
  const multiple = boolean('multiple', false);
@@ -101,8 +102,8 @@ export const Basic = () => {
101
102
  showNewEntry={showNewEntry}
102
103
  placeholder="placeholder"
103
104
  chipSeparators={[',', ' ']}
104
- validateChip={validateChipWhenMultiple}
105
- alert={showAlert && { message: `Couldn't add item`, type: alertType }}
105
+ validateChip={validateChipWhenMultiple()}
106
+ alert={showAlert ? { message: `Couldn't add item`, type: alertType } : undefined}
106
107
  addon={<SearchIcon size={24} />}
107
108
  options={options}
108
109
  inputAutoComplete="off"
@@ -115,7 +116,7 @@ export const Basic = () => {
115
116
  );
116
117
  };
117
118
 
118
- Basic.play = async ({ canvasElement }) => {
119
+ Basic.play = async ({ canvasElement }: StoryContext) => {
119
120
  const canvas = within(canvasElement);
120
121
  await userEvent.type(canvas.getByRole('combobox'), 'abc{ArrowDown}');
121
122
  };
@@ -4,18 +4,20 @@
4
4
 
5
5
  import { Cross as CrossIcon } from '@transferwise/icons';
6
6
  import classNames from 'classnames';
7
+ import { DebouncedFunc } from 'lodash';
7
8
  import clamp from 'lodash.clamp';
8
9
  import debounce from 'lodash.debounce';
9
- import PropTypes from 'prop-types';
10
- import { Component } from 'react';
10
+ import { Component, ReactNode } from 'react';
11
11
 
12
12
  import Chip from '../chips/Chip';
13
- import { Size, Sentiment } from '../common';
13
+ import { Size, Sentiment, SizeMedium, SizeLarge } from '../common';
14
14
  import {
15
15
  addClickClassToDocumentOnIos,
16
16
  removeClickClassFromDocumentOnIos,
17
+ stopPropagation,
17
18
  } from '../common/domHelpers';
18
19
  import InlineAlert from '../inlineAlert';
20
+ import { InlineAlertProps } from '../inlineAlert/InlineAlert';
19
21
 
20
22
  import TypeaheadInput from './typeaheadInput/TypeaheadInput';
21
23
  import TypeaheadOption from './typeaheadOption/TypeaheadOption';
@@ -23,8 +25,81 @@ import TypeaheadOption from './typeaheadOption/TypeaheadOption';
23
25
  const DEFAULT_MIN_QUERY_LENGTH = 3;
24
26
  const SEARCH_DELAY = 200;
25
27
 
26
- export default class Typeahead extends Component {
27
- constructor(props) {
28
+ export type TypeaheadOption<T = string> = {
29
+ label: string;
30
+ note?: string;
31
+ secondary?: string;
32
+ value?: T;
33
+ };
34
+
35
+ export interface TypeaheadProps<T> {
36
+ id: string;
37
+ name: string;
38
+ addon: ReactNode;
39
+ alert?: {
40
+ message: InlineAlertProps['children'];
41
+ type: InlineAlertProps['type'];
42
+ };
43
+ allowNew: boolean;
44
+ autoFillOnBlur?: boolean;
45
+ autoFocus: boolean;
46
+ chipSeparators?: string[];
47
+ clearable: boolean;
48
+ footer: ReactNode;
49
+ initialValue: TypeaheadOption<T>[];
50
+ inputAutoComplete?: string;
51
+ maxHeight: number;
52
+ minQueryLength: number;
53
+ placeholder?: string;
54
+ multiple: boolean;
55
+ options: TypeaheadOption<T>[];
56
+ searchDelay: number;
57
+ showSuggestions: boolean;
58
+ showNewEntry: boolean;
59
+ size?: SizeMedium | SizeLarge;
60
+
61
+ onBlur?: () => void;
62
+ onChange: (options: TypeaheadOption<T>[]) => void;
63
+ onFocus?: () => void;
64
+ onInputChange?: (query: string) => void;
65
+ onSearch?: (query: string) => void;
66
+ validateChip?: (chip: TypeaheadOption<T>) => boolean;
67
+ }
68
+
69
+ type TypeaheadState<T> = {
70
+ selected: TypeaheadOption<T>[];
71
+ keyboardFocusedOptionIndex: number | null;
72
+ errorState: boolean;
73
+ query: string;
74
+ optionsShown?: boolean;
75
+ isFocused?: boolean;
76
+ };
77
+
78
+ export class Typeahead<T> extends Component<TypeaheadProps<T>, TypeaheadState<T>> {
79
+ declare props: TypeaheadProps<T> &
80
+ Required<Pick<TypeaheadProps<T>, keyof typeof Typeahead.defaultProps>>;
81
+
82
+ static defaultProps = {
83
+ addon: null,
84
+ allowNew: false,
85
+ autoFillOnBlur: true,
86
+ autoFocus: false,
87
+ chipSeparators: [],
88
+ clearable: true,
89
+ footer: null,
90
+ initialValue: [],
91
+ inputAutoComplete: 'new-password',
92
+ maxHeight: null,
93
+ minQueryLength: DEFAULT_MIN_QUERY_LENGTH,
94
+ multiple: false,
95
+ searchDelay: SEARCH_DELAY,
96
+ showSuggestions: true,
97
+ showNewEntry: true,
98
+ size: Size.MEDIUM,
99
+ validateChip: () => true,
100
+ };
101
+
102
+ constructor(props: TypeaheadProps<T>) {
28
103
  super(props);
29
104
  const { searchDelay, initialValue, multiple } = props;
30
105
  this.handleSearchDebounced = debounce(this.handleSearch, searchDelay);
@@ -37,7 +112,9 @@ export default class Typeahead extends Component {
37
112
  };
38
113
  }
39
114
 
40
- UNSAFE_componentWillReceiveProps(nextProps) {
115
+ handleSearchDebounced: DebouncedFunc<(query: string) => void>;
116
+
117
+ UNSAFE_componentWillReceiveProps(nextProps: TypeaheadProps<T>) {
41
118
  if (nextProps.multiple !== this.props.multiple) {
42
119
  this.setState((previousState) => {
43
120
  const { selected } = previousState;
@@ -49,6 +126,7 @@ export default class Typeahead extends Component {
49
126
  }
50
127
  return {
51
128
  query: '',
129
+ selected: previousState.selected,
52
130
  };
53
131
  });
54
132
  }
@@ -59,20 +137,16 @@ export default class Typeahead extends Component {
59
137
  }
60
138
 
61
139
  handleOnFocus = () => {
62
- const { onFocus } = this.props;
63
140
  this.showMenu();
64
-
65
- if (onFocus) {
66
- this.props.onFocus();
67
- }
141
+ this.props.onFocus?.();
68
142
  };
69
143
 
70
- onOptionSelected = (event, item) => {
144
+ onOptionSelected = (event: React.MouseEvent, item: TypeaheadOption<T>) => {
71
145
  event.preventDefault();
72
146
  this.selectItem(item);
73
147
  };
74
148
 
75
- handleOnChange = (event) => {
149
+ handleOnChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
76
150
  const { optionsShown, selected } = this.state;
77
151
  const { multiple, onInputChange } = this.props;
78
152
 
@@ -94,7 +168,7 @@ export default class Typeahead extends Component {
94
168
  });
95
169
  };
96
170
 
97
- handleOnPaste = (event) => {
171
+ handleOnPaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {
98
172
  const { allowNew, multiple, chipSeparators } = this.props;
99
173
  const { selected } = this.state;
100
174
 
@@ -113,7 +187,7 @@ export default class Typeahead extends Component {
113
187
  }
114
188
  };
115
189
 
116
- handleOnKeyDown = (event) => {
190
+ handleOnKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
117
191
  const { showSuggestions, allowNew, multiple, chipSeparators, options } = this.props;
118
192
  const { keyboardFocusedOptionIndex, query, selected } = this.state;
119
193
  const chipsMode = !showSuggestions && allowNew && multiple;
@@ -133,7 +207,7 @@ export default class Typeahead extends Component {
133
207
  break;
134
208
  case 'Enter':
135
209
  event.preventDefault();
136
- if (options[keyboardFocusedOptionIndex]) {
210
+ if (keyboardFocusedOptionIndex && options[keyboardFocusedOptionIndex]) {
137
211
  this.selectItem(options[keyboardFocusedOptionIndex]);
138
212
  } else if (allowNew && query.trim()) {
139
213
  this.selectItem({ label: query });
@@ -150,7 +224,7 @@ export default class Typeahead extends Component {
150
224
  }
151
225
  };
152
226
 
153
- moveFocusedOption(offset) {
227
+ moveFocusedOption(offset: number) {
154
228
  this.setState((previousState) => {
155
229
  const { keyboardFocusedOptionIndex } = previousState;
156
230
  const { options } = this.props;
@@ -164,7 +238,7 @@ export default class Typeahead extends Component {
164
238
  });
165
239
  }
166
240
 
167
- selectItem = (item) => {
241
+ selectItem = (item: TypeaheadOption<T>) => {
168
242
  const { multiple } = this.props;
169
243
  let selected = [...this.state.selected];
170
244
  let query;
@@ -183,15 +257,7 @@ export default class Typeahead extends Component {
183
257
  });
184
258
  };
185
259
 
186
- stopPropagation = (event) => {
187
- event.stopPropagation();
188
- event.preventDefault();
189
- if (event.nativeEvent && event.nativeEvent.stopImmediatePropagation) {
190
- event.nativeEvent.stopImmediatePropagation();
191
- }
192
- };
193
-
194
- handleSearch = (query) => {
260
+ handleSearch = (query: string) => {
195
261
  const { onSearch } = this.props;
196
262
  if (onSearch) {
197
263
  onSearch(query);
@@ -246,7 +312,7 @@ export default class Typeahead extends Component {
246
312
  );
247
313
  };
248
314
 
249
- updateSelectedValue = (selected) => {
315
+ updateSelectedValue = (selected: TypeaheadOption<T>[]) => {
250
316
  const { onChange, validateChip } = this.props;
251
317
 
252
318
  const errorState = selected.some((chip) => !validateChip(chip));
@@ -255,7 +321,7 @@ export default class Typeahead extends Component {
255
321
  });
256
322
  };
257
323
 
258
- clear = (event) => {
324
+ clear = (event: React.MouseEvent<HTMLButtonElement>) => {
259
325
  event.preventDefault();
260
326
  if (this.state.selected.length > 0) {
261
327
  this.updateSelectedValue([]);
@@ -266,7 +332,7 @@ export default class Typeahead extends Component {
266
332
  });
267
333
  };
268
334
 
269
- removeChip = (option) => {
335
+ removeChip = (option: TypeaheadOption<T>) => {
270
336
  const { selected } = this.state;
271
337
 
272
338
  if (selected.length > 0) {
@@ -274,8 +340,8 @@ export default class Typeahead extends Component {
274
340
  }
275
341
  };
276
342
 
277
- renderChip = (option, idx) => {
278
- const valid = this.props.validateChip(option);
343
+ renderChip = (option: TypeaheadOption<T>, idx: number): ReactNode => {
344
+ const valid = this.props.validateChip?.(option);
279
345
 
280
346
  return (
281
347
  <Chip
@@ -299,7 +365,10 @@ export default class Typeahead extends Component {
299
365
  allowNew,
300
366
  showNewEntry,
301
367
  dropdownOpen,
302
- }) => {
368
+ }: Pick<TypeaheadProps<T>, 'footer' | 'options' | 'id' | 'allowNew' | 'showNewEntry'> &
369
+ Pick<TypeaheadState<T>, 'keyboardFocusedOptionIndex' | 'query'> & {
370
+ dropdownOpen?: boolean;
371
+ }) => {
303
372
  const optionsToRender = [...options];
304
373
  if (
305
374
  allowNew &&
@@ -364,6 +433,7 @@ export default class Typeahead extends Component {
364
433
  const menu = this.renderMenu({
365
434
  footer,
366
435
  options,
436
+ id,
367
437
  keyboardFocusedOptionIndex,
368
438
  query,
369
439
  allowNew,
@@ -384,7 +454,7 @@ export default class Typeahead extends Component {
384
454
  'typeahead--multiple': multiple,
385
455
  open: dropdownOpen,
386
456
  })}
387
- onClick={this.stopPropagation}
457
+ onClick={stopPropagation}
388
458
  >
389
459
  <div
390
460
  className={classNames('form-group', {
@@ -409,6 +479,7 @@ export default class Typeahead extends Component {
409
479
  selected,
410
480
  maxHeight,
411
481
  }}
482
+ id={id}
412
483
  name={name}
413
484
  value={query}
414
485
  typeaheadId={id}
@@ -435,75 +506,3 @@ export default class Typeahead extends Component {
435
506
  );
436
507
  }
437
508
  }
438
-
439
- Typeahead.propTypes = {
440
- id: PropTypes.string.isRequired,
441
- name: PropTypes.string.isRequired,
442
- options: PropTypes.arrayOf(
443
- PropTypes.shape({
444
- label: PropTypes.string.isRequired,
445
- note: PropTypes.string,
446
- secondary: PropTypes.string,
447
- value: PropTypes.object,
448
- }),
449
- ).isRequired,
450
- initialValue: PropTypes.arrayOf(
451
- PropTypes.shape({
452
- label: PropTypes.string.isRequired,
453
- note: PropTypes.string,
454
- secondary: PropTypes.string,
455
- }),
456
- ),
457
- onChange: PropTypes.func.isRequired,
458
- allowNew: PropTypes.bool,
459
- autoFocus: PropTypes.bool,
460
- clearable: PropTypes.bool,
461
- multiple: PropTypes.bool,
462
- showSuggestions: PropTypes.bool,
463
- showNewEntry: PropTypes.bool,
464
- searchDelay: PropTypes.number,
465
- maxHeight: PropTypes.number,
466
- minQueryLength: PropTypes.number,
467
- addon: PropTypes.node,
468
- placeholder: PropTypes.string,
469
- alert: PropTypes.shape({
470
- message: PropTypes.string.isRequired,
471
- type: PropTypes.oneOf(['error', 'warning', 'neutral']).isRequired,
472
- }),
473
- footer: PropTypes.node,
474
- validateChip: PropTypes.func,
475
- onSearch: PropTypes.func,
476
- onBlur: PropTypes.func,
477
- onInputChange: PropTypes.func,
478
- onFocus: PropTypes.func,
479
- chipSeparators: PropTypes.arrayOf(PropTypes.string),
480
- size: PropTypes.oneOf(['md', 'lg']),
481
- inputAutoComplete: PropTypes.string,
482
- autoFillOnBlur: PropTypes.bool,
483
- };
484
-
485
- Typeahead.defaultProps = {
486
- allowNew: false,
487
- autoFocus: false,
488
- clearable: true,
489
- multiple: false,
490
- maxHeight: null,
491
- showSuggestions: true,
492
- showNewEntry: true,
493
- searchDelay: SEARCH_DELAY,
494
- minQueryLength: DEFAULT_MIN_QUERY_LENGTH,
495
- addon: null,
496
- placeholder: null,
497
- alert: null,
498
- footer: null,
499
- size: Size.MEDIUM,
500
- chipSeparators: [],
501
- initialValue: [],
502
- onSearch: null,
503
- onBlur: null,
504
- onInputChange: null,
505
- onFocus: null,
506
- validateChip: () => true,
507
- inputAutoComplete: 'new-password',
508
- autoFillOnBlur: true,
509
- };
@@ -0,0 +1,4 @@
1
+ import { Typeahead, type TypeaheadProps } from './Typeahead';
2
+ import type { TypeaheadOption } from './Typeahead';
3
+
4
+ export { Typeahead, TypeaheadOption, TypeaheadProps };
@@ -2,16 +2,42 @@
2
2
  /* eslint-disable jsx-a11y/click-events-have-key-events */
3
3
  /* eslint-disable jsx-a11y/no-static-element-interactions */
4
4
  import classnames from 'classnames';
5
- import PropTypes from 'prop-types';
6
- import { Component } from 'react';
5
+ import { Component, ReactNode } from 'react';
7
6
 
8
7
  import { Input } from '../../inputs/Input';
8
+ import { TypeaheadOption, TypeaheadProps } from '../Typeahead';
9
9
 
10
10
  const DEFAULT_INPUT_MIN_WIDTH = 10;
11
11
 
12
- export default class TypeaheadInput extends Component {
13
- constructor() {
14
- super();
12
+ export type TypeaheadInputProps<T> = {
13
+ typeaheadId: string;
14
+ value: string;
15
+ selected: TypeaheadOption<T>[];
16
+ optionsShown?: boolean;
17
+ autoComplete: string;
18
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
19
+ onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
20
+ onFocus: () => void;
21
+ onPaste: React.ClipboardEventHandler<HTMLInputElement>;
22
+ renderChip: (chip: TypeaheadOption<T>, index: number) => ReactNode;
23
+ } & Pick<
24
+ TypeaheadProps<T>,
25
+ 'id' | 'name' | 'autoFocus' | 'multiple' | 'placeholder' | 'maxHeight' | 'onFocus'
26
+ >;
27
+
28
+ type TypeaheadInputState = {
29
+ inputWidth: number;
30
+ };
31
+
32
+ export default class TypeaheadInput<T> extends Component<
33
+ TypeaheadInputProps<T>,
34
+ TypeaheadInputState
35
+ > {
36
+ inputRef: HTMLInputElement | null = null;
37
+ sizerRef: HTMLDivElement | null = null;
38
+
39
+ constructor(props: TypeaheadInputProps<T>) {
40
+ super(props);
15
41
  this.state = {
16
42
  inputWidth: DEFAULT_INPUT_MIN_WIDTH,
17
43
  };
@@ -20,11 +46,11 @@ export default class TypeaheadInput extends Component {
20
46
  componentDidMount() {
21
47
  const { autoFocus } = this.props;
22
48
  if (autoFocus) {
23
- this.inputRef.focus();
49
+ this.inputRef?.focus();
24
50
  }
25
51
  }
26
52
 
27
- componentDidUpdate(previousProps) {
53
+ componentDidUpdate(previousProps: TypeaheadInputProps<T>) {
28
54
  if (previousProps.value !== this.props.value && this.props.multiple) {
29
55
  this.recalculateWidth();
30
56
  }
@@ -33,7 +59,9 @@ export default class TypeaheadInput extends Component {
33
59
  recalculateWidth = () => {
34
60
  requestAnimationFrame(() => {
35
61
  this.setState({
36
- inputWidth: Math.max(DEFAULT_INPUT_MIN_WIDTH, this.sizerRef.scrollWidth + 10),
62
+ inputWidth: this.sizerRef
63
+ ? Math.max(DEFAULT_INPUT_MIN_WIDTH, this.sizerRef.scrollWidth + 10)
64
+ : DEFAULT_INPUT_MIN_WIDTH,
37
65
  });
38
66
  });
39
67
  };
@@ -41,12 +69,12 @@ export default class TypeaheadInput extends Component {
41
69
  renderInput = () => {
42
70
  const {
43
71
  typeaheadId,
44
- autoFocus,
72
+ autoFocus = false,
45
73
  multiple,
46
74
  name,
47
- optionsShown,
48
- placeholder,
49
- selected,
75
+ optionsShown = false,
76
+ placeholder = '',
77
+ selected = [],
50
78
  value,
51
79
  onChange,
52
80
  onKeyDown,
@@ -85,14 +113,14 @@ export default class TypeaheadInput extends Component {
85
113
  };
86
114
 
87
115
  render() {
88
- const { multiple, selected, value, maxHeight, renderChip } = this.props;
116
+ const { multiple, selected = [], value, maxHeight = null, renderChip } = this.props;
89
117
 
90
118
  return multiple ? (
91
119
  <div
92
120
  className="form-control typeahead__input-container"
93
- style={maxHeight && { maxHeight }}
121
+ style={{ maxHeight: maxHeight ?? undefined }}
94
122
  onClick={() => {
95
- this.inputRef.focus();
123
+ this.inputRef?.focus();
96
124
  }}
97
125
  >
98
126
  <div className="typeahead__input-wrapper">
@@ -115,30 +143,3 @@ export default class TypeaheadInput extends Component {
115
143
  );
116
144
  }
117
145
  }
118
-
119
- TypeaheadInput.propTypes = {
120
- typeaheadId: PropTypes.string.isRequired,
121
- name: PropTypes.string.isRequired,
122
- autoFocus: PropTypes.bool,
123
- multiple: PropTypes.bool.isRequired,
124
- value: PropTypes.string.isRequired,
125
- selected: PropTypes.arrayOf(PropTypes.object),
126
- placeholder: PropTypes.string,
127
- optionsShown: PropTypes.bool,
128
- maxHeight: PropTypes.number,
129
- autoComplete: PropTypes.string.isRequired,
130
-
131
- onChange: PropTypes.func.isRequired,
132
- renderChip: PropTypes.func.isRequired,
133
- onKeyDown: PropTypes.func.isRequired,
134
- onFocus: PropTypes.func.isRequired,
135
- onPaste: PropTypes.func.isRequired,
136
- };
137
-
138
- TypeaheadInput.defaultProps = {
139
- autoFocus: false,
140
- maxHeight: null,
141
- placeholder: '',
142
- optionsShown: false,
143
- selected: [],
144
- };
@@ -1,11 +1,18 @@
1
1
  /* eslint-disable jsx-a11y/anchor-is-valid */
2
2
  import classNames from 'classnames';
3
- import PropTypes from 'prop-types';
4
3
 
4
+ import { TypeaheadOption } from '../Typeahead';
5
5
  import highlight from '../util/highlight';
6
6
 
7
- const Option = (props) => {
8
- const { option, selected, onClick, query } = props;
7
+ export type TypeaheadOptionProps<T> = {
8
+ option: TypeaheadOption<T>;
9
+ selected?: boolean;
10
+ onClick?: React.MouseEventHandler;
11
+ query?: string;
12
+ };
13
+
14
+ const Option = <T,>(props: TypeaheadOptionProps<T>) => {
15
+ const { option, selected = false, onClick = () => {}, query = '' } = props;
9
16
  const { label, note, secondary } = option;
10
17
 
11
18
  return (
@@ -27,21 +34,4 @@ const Option = (props) => {
27
34
  );
28
35
  };
29
36
 
30
- Option.propTypes = {
31
- option: PropTypes.shape({
32
- label: PropTypes.string.isRequired,
33
- note: PropTypes.string,
34
- secondary: PropTypes.string,
35
- }).isRequired,
36
- query: PropTypes.string,
37
- selected: PropTypes.bool,
38
- onClick: PropTypes.func,
39
- };
40
-
41
- Option.defaultProps = {
42
- selected: false,
43
- query: '',
44
- onClick: () => {},
45
- };
46
-
47
37
  export default Option;
@@ -1,3 +0,0 @@
1
- import Typeahead from './Typeahead';
2
-
3
- export default Typeahead;